All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.belladati.sdk.impl.BellaDatiServiceImpl Maven / Gradle / Ivy

package com.belladati.sdk.impl;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.Field;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import com.belladati.httpclientandroidlib.client.utils.URIBuilder;
import com.belladati.httpclientandroidlib.message.BasicNameValuePair;
import com.belladati.sdk.BellaDatiService;
import com.belladati.sdk.dashboard.Dashboard;
import com.belladati.sdk.dashboard.DashboardInfo;
import com.belladati.sdk.exception.InternalConfigurationException;
import com.belladati.sdk.filter.Filter;
import com.belladati.sdk.impl.AttributeValueImpl.InvalidAttributeValueException;
import com.belladati.sdk.impl.TableViewImpl.TableImpl;
import com.belladati.sdk.report.AttributeValue;
import com.belladati.sdk.report.Comment;
import com.belladati.sdk.report.Report;
import com.belladati.sdk.report.ReportInfo;
import com.belladati.sdk.user.User;
import com.belladati.sdk.util.CachedList;
import com.belladati.sdk.util.PaginatedIdList;
import com.belladati.sdk.util.PaginatedList;
import com.belladati.sdk.view.ViewType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

class BellaDatiServiceImpl implements BellaDatiService {

	/** The serialVersionUID */
	private static final long serialVersionUID = 9054278401541000710L;

	final BellaDatiClient client;
	final TokenHolder tokenHolder;

	private final transient PaginatedIdList dashboardList = new DashboardList();

	private final transient PaginatedIdList reportList = new ReportList();

	private final transient Map> commentLists = Collections
		.synchronizedMap(new HashMap>());

	private final transient Map>> reportAttributeValues = new HashMap>>();

	BellaDatiServiceImpl(BellaDatiClient client, TokenHolder tokenHolder) {
		this.client = client;
		this.tokenHolder = tokenHolder;
	}

	@Override
	public PaginatedIdList getDashboardInfo() {
		return dashboardList;
	}

	@Override
	public Dashboard loadDashboard(String id) {
		return new DashboardImpl(this, loadJson("api/dashboards/" + id));
	}

	@Override
	public Object loadDashboardThumbnail(String id) throws IOException {
		return loadImage("api/dashboards/" + id + "/thumbnail");
	}

	@Override
	public PaginatedIdList getReportInfo() {
		return reportList;
	}

	@Override
	public Report loadReport(String id) {
		return new ReportImpl(this, loadJson("api/reports/" + id));
	}

	@Override
	public Object loadReportThumbnail(String reportId) throws IOException {
		return loadImage("api/reports/" + reportId + "/thumbnail");
	}

	/**
	 * Convenience method for other parts of the implementation to easily load
	 * data through the API.
	 * 
	 * @param uri URI to contact
	 * @return the resulting JSON response
	 */
	JsonNode loadJson(String uri) {
		return client.getJson(uri, tokenHolder);
	}

	/**
	 * Loads an image from the given URI.
	 * 
	 * @param relativeUrl the URI to load from
	 * @return the image from the server
	 * @throws IOException if the image cannot be loaded
	 */
	private Object loadImage(String relativeUrl) throws IOException {
		ByteArrayInputStream bais = new ByteArrayInputStream(client.get(relativeUrl, tokenHolder));
		try {
			Bitmap image = BitmapFactory.decodeStream(bais);
			if (image == null) {
				throw new IOException("Could not load image");
			}
			return image;
		} finally {
			bais.close();
		}
	}

	@Override
	public PaginatedList getReportComments(String reportId) {
		PaginatedList existing = commentLists.get(reportId);
		if (existing != null) {
			return existing;
		} else {
			synchronized (commentLists) {
				existing = commentLists.get(reportId);
				if (existing != null) {
					return existing;
				} else {
					PaginatedList newList = new PaginatedListImpl(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 Object loadViewContent(String viewId, ViewType viewType, Filter... filters) {
		return loadViewContent(viewId, viewType, Arrays.asList(filters));
	}

	@Override
	public Object loadViewContent(String viewId, ViewType viewType, Collection> filters) {
		try {
			URIBuilder builder = new URIBuilder("api/reports/views/" + viewId + "/" + viewType.getUri());
			JsonNode json = loadJson(appendFilter(builder, filters).build().toString());
			if (viewType == ViewType.TABLE) {
				return new TableImpl(this, viewId, json, filters);
			}
			return json;
		} catch (URISyntaxException e) {
			throw new InternalConfigurationException(e);
		}
	}

	/**
	 * 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
	 */
	URIBuilder appendFilter(URIBuilder builder, Collection> 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;
	}

	@Override
	public synchronized CachedList getAttributeValues(String reportId, String attributeCode) {
		if (!reportAttributeValues.containsKey(reportId)) {
			// we don't have any values for this report yet, insert new map
			reportAttributeValues.put(reportId, new HashMap>());
		}

		Map> attributeValues = reportAttributeValues.get(reportId);

		CachedListImpl values = attributeValues.get(attributeCode);
		if (values == null) {
			// we don't have this attribute in our cache yet
			values = new CachedListImpl(this, "api/reports/" + reportId
				+ "/filter/drilldownAttributeValues?code=" + attributeCode, "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 User loadUser(String userId) {
		return new UserImpl(loadJson("api/users/" + userId));
	}

	@Override
	public Object loadUserImage(String userId) throws IOException {
		return loadImage("api/users/" + userId + "/image");
	}

	@Override
	public String toString() {
		return "BellaDati Service(server: " + client.getBaseUrl() + ", key: " + tokenHolder.getConsumerKey() + ", token: "
			+ tokenHolder.getToken() + ")";
	}

	/** Deserialization. Sets up the element lists and maps as empty objects. */
	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
		in.defaultReadObject();
		try {
			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 commentLists = getClass().getDeclaredField("commentLists");
			commentLists.setAccessible(true);
			commentLists.set(this, Collections.synchronizedMap(new HashMap>()));

			Field reportAttributeValues = getClass().getDeclaredField("reportAttributeValues");
			reportAttributeValues.setAccessible(true);
			reportAttributeValues.set(this, new HashMap>>());
		} 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);
		}
	}

	/** Paginated list class for dashboards. */
	private class DashboardList extends PaginatedIdListImpl {
		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 {
		public ReportList() {
			super(BellaDatiServiceImpl.this, "api/reports", "reports");
		}

		@Override
		protected ReportInfo parse(BellaDatiServiceImpl service, JsonNode node) {
			return new ReportInfoImpl(service, node);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy