package com.belladati.sdk.impl; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.ObjectInputStream; import java.lang.reflect.Field; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import org.apache.http.NameValuePair; import org.apache.http.client.utils.URIBuilder; import org.apache.http.message.BasicNameValuePair; import com.belladati.sdk.BellaDatiService; import com.belladati.sdk.dashboard.Dashboard; import com.belladati.sdk.dashboard.DashboardInfo; import com.belladati.sdk.dashboard.impl.DashboardImpl; import com.belladati.sdk.dashboard.impl.DashboardInfoImpl; import com.belladati.sdk.dataset.AttributeValue; import com.belladati.sdk.dataset.DataSet; import com.belladati.sdk.dataset.DataSetInfo; import com.belladati.sdk.dataset.data.DataColumn; import com.belladati.sdk.dataset.data.DataRow; import com.belladati.sdk.dataset.data.DataTable; import com.belladati.sdk.dataset.impl.AttributeValueImpl; import com.belladati.sdk.dataset.impl.DataSetImpl; import com.belladati.sdk.dataset.impl.DataSetInfoImpl; import com.belladati.sdk.dataset.source.DataSource; import com.belladati.sdk.dataset.source.DataSourceImport; import com.belladati.sdk.dataset.source.DataSourcePendingImport; import com.belladati.sdk.dataset.source.impl.DataSourceImpl; import com.belladati.sdk.dataset.source.impl.DataSourceImportImpl; import com.belladati.sdk.dataset.source.impl.DataSourcePendingImportImpl; import com.belladati.sdk.domain.Domain; import com.belladati.sdk.domain.DomainCreateBuilder; import com.belladati.sdk.domain.DomainEditBuilder; import com.belladati.sdk.domain.DomainInfo; import com.belladati.sdk.domain.impl.DomainCreateBuilderImpl; import com.belladati.sdk.domain.impl.DomainEditBuilderImpl; import com.belladati.sdk.domain.impl.DomainImpl; import com.belladati.sdk.domain.impl.DomainInfoImpl; import com.belladati.sdk.exception.InternalConfigurationException; import com.belladati.sdk.exception.dataset.data.UnknownServerColumnException; import com.belladati.sdk.exception.impl.InvalidAttributeValueException; import com.belladati.sdk.exception.impl.InvalidDataSourceImportException; import com.belladati.sdk.exception.server.InvalidJsonException; import com.belladati.sdk.exception.server.InvalidStreamException; import com.belladati.sdk.exception.server.NotFoundException; import com.belladati.sdk.exception.server.UnexpectedResponseException; import com.belladati.sdk.filter.Filter; import com.belladati.sdk.form.Form; import com.belladati.sdk.form.FormDataPostBuilder; import com.belladati.sdk.form.impl.FormDataPostBuilderImpl; import com.belladati.sdk.form.impl.FormImpl; import com.belladati.sdk.intervals.DateUnit; import com.belladati.sdk.intervals.Interval; import com.belladati.sdk.intervals.TimeUnit; import com.belladati.sdk.report.Comment; import com.belladati.sdk.report.Report; import com.belladati.sdk.report.ReportInfo; import com.belladati.sdk.report.impl.CommentImpl; import com.belladati.sdk.report.impl.ReportImpl; import com.belladati.sdk.report.impl.ReportInfoImpl; import com.belladati.sdk.user.User; import com.belladati.sdk.user.UserCreateBuilder; import com.belladati.sdk.user.UserEditBuilder; import com.belladati.sdk.user.UserGroup; import com.belladati.sdk.user.UserGroupCreateBuilder; import com.belladati.sdk.user.UserRequestType; import com.belladati.sdk.user.impl.UserCreateBuilderImpl; import com.belladati.sdk.user.impl.UserEditBuilderImpl; import com.belladati.sdk.user.impl.UserGroupCreateBuilderImpl; import com.belladati.sdk.user.impl.UserGroupImpl; import com.belladati.sdk.user.impl.UserImpl; import com.belladati.sdk.util.CachedList; import com.belladati.sdk.util.MultipartPiece; import com.belladati.sdk.util.PaginatedIdList; import com.belladati.sdk.util.PaginatedList; import com.belladati.sdk.util.impl.BellaDatiSdkUtils; import com.belladati.sdk.util.impl.CachedListImpl; import com.belladati.sdk.util.impl.MultipartFileImpl; import com.belladati.sdk.util.impl.MultipartTextImpl; import com.belladati.sdk.util.impl.PaginatedIdListImpl; import com.belladati.sdk.util.impl.PaginatedListImpl; import com.belladati.sdk.view.ViewLoader; import com.belladati.sdk.view.ViewType; import com.belladati.sdk.view.export.ViewExporter; import com.belladati.sdk.view.impl.ViewExporterImpl; import com.belladati.sdk.view.impl.ViewLoaderImpl; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; public class BellaDatiServiceImpl implements BellaDatiService { /** The serialVersionUID */ private static final long serialVersionUID = 9054278401541000710L; public static final String DATE_TIME_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz"; private final BellaDatiClient client; private final TokenHolder tokenHolder; private final transient CachedList<DomainInfo> domainList = new DomainList(); private final transient Map<String, CachedList<User>> users = Collections .synchronizedMap(new HashMap<String, CachedList<User>>()); private final transient Map<String, CachedList<UserGroup>> userGroups = Collections .synchronizedMap(new HashMap<String, CachedList<UserGroup>>()); private final transient PaginatedIdList<DashboardInfo> dashboardList = new DashboardList(); private final transient PaginatedIdList<ReportInfo> reportList = new ReportList(); private final transient PaginatedIdList<DataSetInfo> dataSetList = new DataSetList(); private final transient Map<String, PaginatedList<Comment>> commentLists = Collections .synchronizedMap(new HashMap<String, PaginatedList<Comment>>()); private final transient Map<String, Map<String, CachedList<AttributeValue>>> dataSetAttributeValues = new HashMap<String, Map<String, CachedList<AttributeValue>>>(); private final transient Map<String, CachedList<DataSource>> dataSourceList = new HashMap<String, CachedList<DataSource>>(); private final transient Map<String, CachedList<DataSourceImport>> dataSourceImportList = new HashMap<String, CachedList<DataSourceImport>>(); private final transient Map<String, PaginatedIdList<DataRow>> dataSetData = Collections .synchronizedMap(new HashMap<String, PaginatedIdList<DataRow>>()); private final transient CachedList<Form> importFormList = new ImportFormList(); public BellaDatiServiceImpl(BellaDatiClient client, TokenHolder tokenHolder) { this.client = client; this.tokenHolder = tokenHolder; } public BellaDatiClient getClient() { return client; } public TokenHolder getTokenHolder() { return tokenHolder; } @Override public CachedList<DomainInfo> getDomainInfo() { return domainList; } @Override public Domain loadDomain(String id) throws NotFoundException { return new DomainImpl(this, getAsJson("api/domains/" + id)); } @Override public CachedList<User> getDomainUsers(String domainId, String userGroupId) { final String cacheKey = domainId + "-" + userGroupId; CachedList<User> existing = users.get(cacheKey); if (existing != null) { return existing; } else { synchronized (users) { existing = users.get(cacheKey); if (existing != null) { return existing; } else { String params = userGroupId != null && !userGroupId.isEmpty() ? "?userGroup_id=" + userGroupId : ""; String endpoint = "api/domains/" + domainId + "/users" + params; CachedList<User> newList = new CachedListImpl<User>(this, endpoint, "users") { @Override protected User parse(BellaDatiServiceImpl service, JsonNode node) { return new UserImpl(service, node); } }; users.put(cacheKey, newList); return newList; } } } } @Override public CachedList<UserGroup> getDomainUserGroups(String domainId) { CachedList<UserGroup> existing = userGroups.get(domainId); if (existing != null) { return existing; } else { synchronized (userGroups) { existing = userGroups.get(domainId); if (existing != null) { return existing; } else { CachedList<UserGroup> newList = new CachedListImpl<UserGroup>(this, "api/domains/" + domainId + "/userGroups", "userGroups") { @Override protected UserGroup parse(BellaDatiServiceImpl service, JsonNode node) { return new UserGroupImpl(node); } }; userGroups.put(domainId, newList); return newList; } } } } @Override public DomainCreateBuilder setupDomainCreateBuilder() { return new DomainCreateBuilderImpl(this); } @Override public DomainEditBuilder setupDomainEditBuilder(String domainId) { return new DomainEditBuilderImpl(this, domainId); } @Override public UserGroupCreateBuilder setupUserGroupCreateBuilder(String domainId) { return new UserGroupCreateBuilderImpl(this, domainId); } @Override public UserCreateBuilder setupUserCreateBuilder(String domainId) { return new UserCreateBuilderImpl(this, domainId); } @Override public UserEditBuilder setupUserEditBuilder(String userId) { return new UserEditBuilderImpl(this, userId); } @Override public PaginatedIdList<DashboardInfo> getDashboardInfo() { return dashboardList; } @Override public Dashboard loadDashboard(String id) { return new DashboardImpl(this, getAsJson("api/dashboards/" + id)); } @Override public Object loadDashboardThumbnail(String id) { return getAsImage("api/dashboards/" + id + "/thumbnail"); } @Override public PaginatedIdList<ReportInfo> getReportInfo() { return reportList; } @Override public Report loadReport(String id) { return new ReportImpl(this, getAsJson("api/reports/" + id)); } @Override public Object loadReportThumbnail(String reportId) { return getAsImage("api/reports/" + reportId + "/thumbnail"); } @Override public PaginatedList<Comment> getReportComments(String reportId) { PaginatedList<Comment> existing = commentLists.get(reportId); if (existing != null) { return existing; } else { synchronized (commentLists) { existing = commentLists.get(reportId); if (existing != null) { return existing; } else { PaginatedList<Comment> newList = new PaginatedListImpl<Comment>(this, "api/reports/" + reportId + "/comments", "comments") { @Override protected Comment parse(BellaDatiServiceImpl service, JsonNode node) { return new CommentImpl(service, node); } }; commentLists.put(reportId, newList); return newList; } } } } @Override public void postComment(String reportId, String text) { client.post("api/reports/" + reportId + "/comments", tokenHolder, Collections.singletonList(new BasicNameValuePair("text", text))); } @Override public void deleteComment(String commentId) throws NotFoundException { client.delete("api/reports/comments/" + commentId, tokenHolder); } @Override public Object loadViewContent(String viewId, ViewType viewType, Filter<?>... filters) { return loadViewContent(viewId, viewType, Arrays.asList(filters)); } @Override public Object loadViewContent(String viewId, ViewType viewType, Collection<Filter<?>> filters) { return setupViewLoader(viewId, viewType).addFilters(filters).loadContent(); } @Override public ViewLoader setupViewLoader(String viewId, ViewType viewType) { return new ViewLoaderImpl(this, viewId, viewType); } @Override public ViewExporter setupViewExporter(String viewId) { return new ViewExporterImpl(this, viewId); } @Override public CachedList<DataSource> getDataSources(String id) throws NotFoundException { CachedList<DataSource> list = dataSourceList.get(id); if (list == null) { // we don't have this data set's sources in our cache yet list = new CachedListImpl<DataSource>(this, "api/dataSets/" + id + "/dataSources", "dataSources") { @Override protected DataSource parse(BellaDatiServiceImpl service, JsonNode node) throws ParseException { return new DataSourceImpl(service, node); } }; dataSourceList.put(id, list); } return list; } @Override public CachedList<DataSourceImport> getDataSourceImports(String id) throws NotFoundException { CachedList<DataSourceImport> list = dataSourceImportList.get(id); if (list == null) { // we don't have this data set's sources in our cache yet list = new CachedListImpl<DataSourceImport>(this, "api/dataSets/dataSources/" + id + "/executions", "executions") { @Override protected DataSourceImport parse(BellaDatiServiceImpl service, JsonNode node) throws ParseException { try { return new DataSourceImportImpl(node); } catch (InvalidDataSourceImportException e) { throw new ParseException(node, e); } } }; dataSourceImportList.put(id, list); } return list; } @Override public DataSourcePendingImport setupDataSourceImport(String id, Date date) { return new DataSourcePendingImportImpl(this, id, date); } /** * Appends a filter parameter from the given filters to the URI builder. * Won't do anything if the filter collection is empty. * * @param builder the builder to append to * @param filters filters to append * @return the same builder, for chaining */ public URIBuilder appendFilter(URIBuilder builder, Collection<Filter<?>> filters) { if (filters.size() > 0) { ObjectNode filterNode = new ObjectMapper().createObjectNode(); for (Filter<?> filter : filters) { filterNode.setAll(filter.toJson()); } ObjectNode drilldownNode = new ObjectMapper().createObjectNode(); drilldownNode.put("drilldown", filterNode); builder.addParameter("filter", drilldownNode.toString()); } return builder; } /** * Appends a date/time definition parameter to the URI builder. Won't do * anything if both intervals are <tt>null</tt>. * * @param builder the builder to append to * @param dateInterval date interval to append, or <tt>null</tt> * @param timeInterval time interval to append, or <tt>null</tt> * @return the same builder, for chaining */ public URIBuilder appendDateTime(URIBuilder builder, Interval<DateUnit> dateInterval, Interval<TimeUnit> timeInterval) { if (dateInterval != null || timeInterval != null) { ObjectNode dateTimeNode = new ObjectMapper().createObjectNode(); if (dateInterval != null) { dateTimeNode.setAll(dateInterval.toJson()); } if (timeInterval != null) { dateTimeNode.setAll(timeInterval.toJson()); } builder.addParameter("dateTimeDefinition", dateTimeNode.toString()); } return builder; } /** * Appends a locale language parameter to the URI builder. Won't do anything * if the locale is <tt>null</tt>. * * @param builder the builder to append to * @param locale the locale to append * @return the same builder, for chaining */ public URIBuilder appendLocale(URIBuilder builder, Locale locale) { if (locale != null) { builder.addParameter("lang", locale.getLanguage()); } return builder; } @Override public synchronized CachedList<AttributeValue> getAttributeValues(String dataSetId, String attributeCode) { if (!dataSetAttributeValues.containsKey(dataSetId)) { // we don't have any values for this report yet, insert new map dataSetAttributeValues.put(dataSetId, new HashMap<String, CachedList<AttributeValue>>()); } Map<String, CachedList<AttributeValue>> attributeValues = dataSetAttributeValues.get(dataSetId); CachedList<AttributeValue> values = attributeValues.get(attributeCode); if (values == null) { // we don't have this attribute in our cache yet values = new CachedListImpl<AttributeValue>(this, "api/dataSets/" + dataSetId + "/attributes/" + attributeCode + "/values", "values") { @Override protected AttributeValue parse(BellaDatiServiceImpl service, JsonNode node) throws ParseException { try { return new AttributeValueImpl(node); } catch (InvalidAttributeValueException e) { throw new ParseException(node, e); } } }; attributeValues.put(attributeCode, values); } return values; } @Override public void postAttributeValueImage(String dataSetId, String attributeCode, String attributeValue, File image) throws URISyntaxException { URIBuilder builder = new URIBuilder(); builder.setPath("api/dataSets/" + dataSetId + "/attributes/" + attributeCode + "/" + attributeValue + "/image"); String relativeUri = builder.build().toString(); List<MultipartPiece<?>> multipart = new ArrayList<>(); multipart.add(new MultipartFileImpl("file", image)); postMultipart(relativeUri, multipart); } @Override public User loadUser(String userId) { return new UserImpl(this, getAsJson("api/users/" + userId)); } @Override public User loadUserByUsername(String username) { return new UserImpl(this, getAsJson("api/users/username/" + username)); } @Override public Object loadUserImage(String userId) { return getAsImage("api/users/" + userId + "/image"); } @Override public String loadUserStatus(String userId) throws NotFoundException { return new String(client.get("api/users/" + userId + "/status", tokenHolder)); } @Override public void postUserStatus(String userId, String status) throws NotFoundException { client.post("api/users/" + userId + "/status", tokenHolder, Collections.singletonList(new BasicNameValuePair("status", status))); } @Override public String toString() { return "BellaDati Service(server: " + client.getBaseUrl() + ", key: " + tokenHolder.getConsumerKey() + ", token: " + tokenHolder.getToken() + ")"; } @Override public PaginatedIdList<DataSetInfo> getDataSetInfo() { return dataSetList; } @Override public DataSet loadDataSet(String id) throws NotFoundException { return new DataSetImpl(this, getAsJson("api/dataSets/" + id)); } @Override public void uploadData(String id, DataTable data) { List<DataRow> rows = data.getRows(); if (rows.size() == 0) { // if we don't have data, do nothing return; } try { client.postUpload("api/import/" + id, tokenHolder, data.toJson().toString()); } catch (UnexpectedResponseException e) { if (e.getResponseCode() == 400) { Pattern codePattern = Pattern.compile(".*?'(.*?)'.*"); Matcher codeMatcher = codePattern.matcher(e.getResponseContent()); if (codeMatcher.matches()) { throw new UnknownServerColumnException(id, codeMatcher.group(1)); } } throw new UnexpectedResponseException(e.getResponseCode(), e.getResponseContent(), e); } } @Override public void uploadImage(File image, String name) { List<MultipartPiece<?>> multipart = new ArrayList<>(); multipart.add(new MultipartFileImpl("file", image)); if (name != null) { multipart.add(new MultipartTextImpl("name", name)); } postMultipart("api/import/media/image", multipart); } /** Deserialization. Sets up the element lists and maps as empty objects. */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); try { Field domainList = getClass().getDeclaredField("domainList"); domainList.setAccessible(true); domainList.set(this, new DomainList()); Field dashboardList = getClass().getDeclaredField("dashboardList"); dashboardList.setAccessible(true); dashboardList.set(this, new DashboardList()); Field reportList = getClass().getDeclaredField("reportList"); reportList.setAccessible(true); reportList.set(this, new ReportList()); Field dataSetList = getClass().getDeclaredField("dataSetList"); dataSetList.setAccessible(true); dataSetList.set(this, new DataSetList()); Field commentLists = getClass().getDeclaredField("commentLists"); commentLists.setAccessible(true); commentLists.set(this, Collections.synchronizedMap(new HashMap<String, PaginatedList<Comment>>())); Field reportAttributeValues = getClass().getDeclaredField("dataSetAttributeValues"); reportAttributeValues.setAccessible(true); reportAttributeValues.set(this, new HashMap<String, Map<String, CachedListImpl<AttributeValue>>>()); Field dataSourceList = getClass().getDeclaredField("dataSourceList"); dataSourceList.setAccessible(true); dataSourceList.set(this, new HashMap<String, CachedListImpl<DataSource>>()); Field importFormList = getClass().getDeclaredField("importFormList"); importFormList.setAccessible(true); importFormList.set(this, new ImportFormList()); Field dataSourceImportList = getClass().getDeclaredField("dataSourceImportList"); dataSourceImportList.setAccessible(true); dataSourceImportList.set(this, new HashMap<String, CachedListImpl<DataSourceImport>>()); } catch (NoSuchFieldException e) { throw new InternalConfigurationException("Failed to set service fields", e); } catch (IllegalAccessException e) { throw new InternalConfigurationException("Failed to set service fields", e); } catch (SecurityException e) { throw new InternalConfigurationException("Failed to set service fields", e); } catch (IllegalArgumentException e) { throw new InternalConfigurationException("Failed to set service fields", e); } } /** Cached list class for domains. */ private class DomainList extends CachedListImpl<DomainInfo> { public DomainList() { super(BellaDatiServiceImpl.this, "api/domains", "domains"); } @Override protected DomainInfo parse(BellaDatiServiceImpl service, JsonNode node) { return new DomainInfoImpl(service, node); } } /** Paginated list class for dashboards. */ private class DashboardList extends PaginatedIdListImpl<DashboardInfo> { public DashboardList() { super(BellaDatiServiceImpl.this, "api/dashboards", "dashboards"); } @Override protected DashboardInfo parse(BellaDatiServiceImpl service, JsonNode node) { return new DashboardInfoImpl(service, node); } } /** Paginated list class for reports. */ private class ReportList extends PaginatedIdListImpl<ReportInfo> { public ReportList() { super(BellaDatiServiceImpl.this, "api/reports", "reports"); } @Override protected ReportInfo parse(BellaDatiServiceImpl service, JsonNode node) { return new ReportInfoImpl(service, node); } } /** Paginated list class for data sets. */ private class DataSetList extends PaginatedIdListImpl<DataSetInfo> { public DataSetList() { super(BellaDatiServiceImpl.this, "api/dataSets", "dataSets"); } @Override protected DataSetInfo parse(BellaDatiServiceImpl service, JsonNode node) { return new DataSetInfoImpl(service, node); } } /** Cached list class for import forms. */ private class ImportFormList extends CachedListImpl<Form> { public ImportFormList() { super(BellaDatiServiceImpl.this, "api/import/forms", "importForms"); } @Override protected Form parse(BellaDatiServiceImpl service, JsonNode node) { return new FormImpl(node); } } @Override public byte[] post(String uri) throws URISyntaxException { return post(uri, Collections.<String, String> emptyMap()); } @Override public byte[] post(String uri, Map<String, String> uriParameters) throws URISyntaxException { return postForm(uri, uriParameters, Collections.<String, String> emptyMap()); } @Override public byte[] post(String uri, byte[] content) throws URISyntaxException { return post(uri, Collections.<String, String> emptyMap(), content); } @Override public byte[] post(String uri, Map<String, String> uriParameters, byte[] content) throws URISyntaxException { URIBuilder builder = new URIBuilder(uri); for (Entry<String, String> entry : uriParameters.entrySet()) { builder.addParameter(entry.getKey(), entry.getValue()); } return client.postData(builder.build().toString(), tokenHolder, content); } @Override public byte[] postMultipart(String relativeUrl, List<? extends MultipartPiece<?>> multipart) { return client.postMultipart(relativeUrl, tokenHolder, multipart); } @Override public byte[] postForm(String uri, Map<String, String> formParameters) throws URISyntaxException { return postForm(uri, Collections.<String, String> emptyMap(), formParameters); } @Override public byte[] postForm(String uri, Map<String, String> uriParameters, Map<String, String> formParameters) throws URISyntaxException { URIBuilder builder = new URIBuilder(uri); for (Entry<String, String> entry : uriParameters.entrySet()) { builder.addParameter(entry.getKey(), entry.getValue()); } List<NameValuePair> formParams = new ArrayList<NameValuePair>(); for (Entry<String, String> entry : formParameters.entrySet()) { formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } return client.post(builder.build().toString(), tokenHolder, formParams); } @Override public byte[] get(String uri) throws URISyntaxException { return get(uri, Collections.<String, String> emptyMap()); } @Override public byte[] get(String uri, Map<String, String> uriParameters) throws URISyntaxException { URIBuilder builder = new URIBuilder(uri); for (Entry<String, String> entry : uriParameters.entrySet()) { builder.addParameter(entry.getKey(), entry.getValue()); } return client.get(builder.build().toString(), tokenHolder); } /** * Helper method to invoke GET operation on the specified relative URI and to read result as {@link JsonNode}. * * @param relativeUri the relative URI to load JSON from * @return the JsonNode parsed from the response * @throws InvalidJsonException if response cannot be parsed into JSON */ public JsonNode getAsJson(String relativeUri) throws InvalidJsonException { return client.getAsJson(relativeUri, tokenHolder); } /** * Helper method to invoke GET operation on the specified relative URI and to read result as {@link BufferedImage}. * * @param relativeUri the relative URI to load image from * @return the BufferedImage parsed from the response * @throws InvalidStreamException if response cannot be parsed into image */ public BufferedImage getAsImage(String relativeUri) throws InvalidStreamException { return client.getAsImage(relativeUri, tokenHolder); } /** * Helper method to invoke GET operation on the specified relative URI and to read result as {@link ByteArrayInputStream}. * * @param relativeUri the relative URI to load stream from * @return the ByteArrayInputStream parsed from the response */ public ByteArrayInputStream getAsStream(String relativeUri) { return client.getAsStream(relativeUri, tokenHolder); } @Override public CachedList<Form> getImportForms() { return importFormList; } @Override public Form loadImportForm(String id) throws NotFoundException { return new FormImpl(getAsJson("api/import/forms/" + id)); } @Override public FormDataPostBuilder setupFormDataPostBuilder(String formId) { return new FormDataPostBuilderImpl(this, formId); } @Override public String createImageView(String reportId, String viewName, File image, Integer width, Integer height) { Map<String, String> uriParams = new HashMap<>(); if (width != null) { uriParams.put("width", width.toString()); } if (height != null) { uriParams.put("height", height.toString()); } String relativeUri = BellaDatiSdkUtils.joinUriWithParams("api/reports/" + reportId + "/images", uriParams); List<MultipartPiece<?>> multipart = new ArrayList<>(); multipart.add(new MultipartTextImpl("name", viewName)); multipart.add(new MultipartFileImpl("file", image)); byte[] response = postMultipart(relativeUri, multipart); return new String(response); } @Override public void editImageView(String viewId, File image) { List<MultipartPiece<?>> multipart = new ArrayList<>(); multipart.add(new MultipartFileImpl("file", image)); String relativeUri = "api/reports/views/" + viewId + "/image"; postMultipart(relativeUri, multipart); } @Override public Object loadFile(String absolutePath) throws URISyntaxException { URIBuilder builder = new URIBuilder(); builder.setPath("api/utils/file/" + absolutePath); return getAsStream(builder.build().toString()); } @Override public Object mergePdfFiles(List<String> paths) throws URISyntaxException { String joinedPaths = StringUtils.join(paths, ";"); URIBuilder builder = new URIBuilder(); builder.setPath("api/utils/mergePdfFiles/" + joinedPaths); return getAsStream(builder.build().toString()); } @Override public String createUserRequest(String username, UserRequestType requestType) { List<NameValuePair> formParams = new ArrayList<NameValuePair>(); formParams.add(new BasicNameValuePair("request_type", requestType.name())); byte[] response = client.post("api/users/" + username + "/requests", tokenHolder, formParams); return new String(response); } @Override public String createAccessToken(String username, Integer validity, String domainId) { List<NameValuePair> formParams = new ArrayList<NameValuePair>(); if (validity != null) { formParams.add(new BasicNameValuePair("validity", validity.toString())); } if (domainId != null) { formParams.add(new BasicNameValuePair("domain_id", domainId)); } byte[] response = client.post("api/users/" + username + "/accessToken", tokenHolder, formParams); return new String(response); } @Override public PaginatedIdList<DataRow> getDataSetData(String dataSetId) { PaginatedIdList<DataRow> existing = dataSetData.get(dataSetId); if (existing != null) { return existing; } else { synchronized (dataSetData) { existing = dataSetData.get(dataSetId); if (existing != null) { return existing; } else { DataRowList newList = new DataRowList(dataSetId); dataSetData.put(dataSetId, newList); return newList; } } } } @Override public void postDataSetData(String dataSetId, DataRow row) throws NotFoundException { client.post("api/dataSets/" + dataSetId + "/data", tokenHolder, Collections.singletonList(new BasicNameValuePair("dataRow", row.toJsonObject().toString()))); } /** Paginated list class for data rows. */ private class DataRowList extends PaginatedIdListImpl<DataRow> { public DataRowList(String dataSetId) { super(BellaDatiServiceImpl.this, "api/dataSets/" + dataSetId + "/data", "data"); } @Override protected DataRow parse(BellaDatiServiceImpl service, JsonNode node) { String rowId = node.hasNonNull("UID") ? node.get("UID").asText() : null; List<DataColumn> columns = new ArrayList<>(); Iterator<String> fieldNames = node.fieldNames(); while (fieldNames.hasNext()) { String fieldName = fieldNames.next(); if (!fieldName.equalsIgnoreCase("UID")) { columns.add(new DataColumn(fieldName)); } } DataRow row = new DataRow(rowId, columns); List<String> values = new ArrayList<>(); for (DataColumn column : columns) { values.add(node.get(column.getCode()).asText()); } row.setAll(values.toArray(new String[values.size()])); return row; } } }