package org.activityinfo.server.endpoint.rest; import com.bedatadriven.rebar.time.calendar.LocalDate; import com.google.common.base.Strings; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.activityinfo.legacy.shared.command.*; import org.activityinfo.legacy.shared.command.result.MonthlyReportResult; import org.activityinfo.legacy.shared.model.*; import org.activityinfo.server.command.DispatcherSync; import org.codehaus.jackson.JsonGenerator; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.IOException; import java.io.StringWriter; import java.util.List; import java.util.Map; import java.util.Set; public class SitesResources { private final DispatcherSync dispatcher; public SitesResources(DispatcherSync dispatcher) { this.dispatcher = dispatcher; } @GET @Produces(MediaType.APPLICATION_JSON) public String query(@QueryParam("activity") List<Integer> activityIds, @QueryParam("database") List<Integer> databaseIds, @QueryParam("indicator") List<Integer> indicatorIds, @QueryParam("partner") List<Integer> partnerIds, @QueryParam("attribute") List<Integer> attributeIds, @QueryParam("location") List<Integer> locationIds, @QueryParam("format") String format) throws IOException { Filter filter = new Filter(); filter.addRestriction(DimensionType.Activity, activityIds); filter.addRestriction(DimensionType.Database, databaseIds); filter.addRestriction(DimensionType.Indicator, indicatorIds); filter.addRestriction(DimensionType.Partner, partnerIds); filter.addRestriction(DimensionType.Attribute, attributeIds); filter.addRestriction(DimensionType.Location, locationIds); List<SiteDTO> sites = dispatcher.execute(new GetSites(filter)).getData(); StringWriter writer = new StringWriter(); JsonGenerator json = Jackson.createJsonFactory(writer); writeJson(sites, json); return writer.toString(); } @GET @Path("/points") public Response queryPoints(@QueryParam("activity") List<Integer> activityIds, @QueryParam("database") List<Integer> databaseIds, @QueryParam("callback") String callback) throws IOException { Filter filter = new Filter(); filter.addRestriction(DimensionType.Activity, activityIds); filter.addRestriction(DimensionType.Database, databaseIds); List<SiteDTO> sites = dispatcher.execute(new GetSites(filter)).getData(); StringWriter writer = new StringWriter(); JsonGenerator json = Jackson.createJsonFactory(writer); writeGeoJson(sites, json); if (Strings.isNullOrEmpty(callback)) { return Response.ok(writer.toString()).type("application/json; charset=UTF-8").build(); } else { return Response.ok(callback + "(" + writer.toString() + ");") .type("application/javascript; charset=UTF-8") .build(); } } private void writeJson(List<SiteDTO> sites, JsonGenerator json) throws IOException { json.writeStartArray(); for (SiteDTO site : sites) { json.writeStartObject(); json.writeNumberField("id", site.getId()); json.writeNumberField("activity", site.getActivityId()); json.writeNumberField("timestamp", site.getTimeEdited()); // write start / end date if applicable if (site.getDate1() != null && site.getDate2() != null) { json.writeStringField("startDate", site.getDate1().toString()); json.writeStringField("endDate", site.getDate2().toString()); } // write the location as a separate object json.writeObjectFieldStart("location"); json.writeNumberField("id", site.getLocationId()); json.writeStringField("name", site.getLocationName()); if (site.hasLatLong()) { json.writeFieldName("latitude"); json.writeNumber(site.getLatitude()); json.writeFieldName("longitude"); json.writeNumber(site.getLongitude()); } json.writeEndObject(); json.writeObjectFieldStart("partner"); json.writeNumberField("id", site.getPartnerId()); json.writeStringField("name", site.getPartnerName()); json.writeEndObject(); if (site.getProject() != null) { json.writeNumberField("projectId", site.getProject().getId()); } // write attributes as a series of ids Set<Integer> attributes = getAttributeIds(site); if (!attributes.isEmpty()) { json.writeFieldName("attributes"); json.writeStartArray(); for (Integer attributeId : attributes) { json.writeNumber(attributeId); } json.writeEndArray(); } // write indicators Set<Integer> indicatorIds = getIndicatorIds(site); if (!indicatorIds.isEmpty()) { json.writeObjectFieldStart("indicatorValues"); for (Integer indicatorId : indicatorIds) { Object indicatorValue = site.getIndicatorValue(indicatorId); if (indicatorValue instanceof Double) { json.writeNumberField(Integer.toString(indicatorId), (Double) indicatorValue); } else if (indicatorValue instanceof String) { json.writeStringField(Integer.toString(indicatorId), (String) indicatorValue); } else if (indicatorValue instanceof LocalDate) { json.writeStringField(Integer.toString(indicatorId), ((LocalDate) indicatorValue).toString()); } else if (indicatorValue instanceof Boolean) { json.writeStringField(Integer.toString(indicatorId), ((Boolean) indicatorValue).toString()); } } json.writeEndObject(); } // comments if (!Strings.isNullOrEmpty(site.getComments())) { json.writeFieldName("comments"); json.writeString(site.getComments()); } json.writeEndObject(); } json.writeEndArray(); json.close(); } private void writeGeoJson(List<SiteDTO> sites, JsonGenerator json) throws IOException { json.writeStartObject(); json.writeStringField("type", "FeatureCollection"); json.writeArrayFieldStart("features"); Map<Integer, ActivityFormDTO> forms = Maps.newHashMap(); for (SiteDTO site : sites) { if (site.hasLatLong()) { json.writeStartObject(); json.writeStringField("type", "Feature"); json.writeNumberField("id", site.getId()); // json.writeNumberField("timestamp", site.getTimeEdited()); ActivityFormDTO form = forms.get(site.getActivityId()); if(form == null) { form = dispatcher.execute(new GetActivityForm(site.getActivityId())); forms.put(form.getId(), form); } // write out the properties object json.writeObjectFieldStart("properties"); json.writeStringField("locationName", site.getLocationName()); json.writeStringField("partnerName", site.getPartnerName()); if (!Strings.isNullOrEmpty(site.getComments())) { json.writeStringField("comments", site.getComments()); } json.writeNumberField("activity", site.getActivityId()); if (!Strings.isNullOrEmpty(form.getCategory())) { json.writeStringField("activityCategory", form.getCategory()); } json.writeStringField("activityName", form.getName()); // write start / end date if applicable if (site.getDate1() != null && site.getDate2() != null) { json.writeStringField("startDate", site.getDate1().toString()); json.writeStringField("endDate", site.getDate2().toString()); } final Map<String, Object> indicatorsMap = Maps.newHashMap(); final Map<AttributeGroupDTO, Map<String, Object>> attributesGroupMap = Maps.newHashMap(); // write indicators and attributes for (String propertyName : site.getPropertyNames()) { if (propertyName.startsWith(IndicatorDTO.PROPERTY_PREFIX)) { Object value = site.get(propertyName); final int indicatorId = IndicatorDTO.indicatorIdForPropertyName(propertyName); final IndicatorDTO dto = form.getIndicatorById(indicatorId); if (value instanceof Number) { final double doubleValue = ((Number) value).doubleValue(); indicatorsMap.put(dto.getName(), doubleValue); } else if (value instanceof String || value instanceof LocalDate) { indicatorsMap.put(dto.getName(), value); } else if (value instanceof Boolean) { indicatorsMap.put(dto.getName(), value); } } else if (propertyName.startsWith(AttributeDTO.PROPERTY_PREFIX)) { Object value = site.get(propertyName); final int attributeId = AttributeDTO.idForPropertyName(propertyName); for (AttributeGroupDTO attributeGroupDTO : form.getAttributeGroups()) { final AttributeDTO attributeDTO = attributeGroupDTO.getAttributeById(attributeId); if (attributeDTO != null) { if (attributesGroupMap.containsKey(attributeGroupDTO)) { final Map<String, Object> map = attributesGroupMap.get(attributeGroupDTO); map.put(attributeDTO.getName(), value == Boolean.TRUE); } else { final Map<String, Object> map = Maps.newHashMap(); map.put(attributeDTO.getName(), value == Boolean.TRUE); attributesGroupMap.put(attributeGroupDTO, map); } break; } } } } // write indicators inside properties Jackson.writeMap(json, "indicators", indicatorsMap); // write attribute groups for (Map.Entry<AttributeGroupDTO, Map<String, Object>> entry : attributesGroupMap.entrySet()) { Jackson.writeMap(json, entry.getKey().getName(), entry.getValue()); } json.writeEndObject(); // write out the geometry object json.writeObjectFieldStart("geometry"); json.writeStringField("type", "Point"); json.writeArrayFieldStart("coordinates"); json.writeNumber(site.getX()); json.writeNumber(site.getY()); json.writeEndArray(); json.writeEndObject(); json.writeEndObject(); } } json.writeEndArray(); json.writeEndObject(); json.close(); } private Set<Integer> getIndicatorIds(SiteDTO site) { Set<Integer> ids = Sets.newHashSet(); for (String propertyName : site.getPropertyNames()) { if (propertyName.startsWith(IndicatorDTO.PROPERTY_PREFIX) && site.get(propertyName) != null) { ids.add(IndicatorDTO.indicatorIdForPropertyName(propertyName)); } } return ids; } private Set<Integer> getAttributeIds(SiteDTO site) { Set<Integer> ids = Sets.newHashSet(); for (String propertyName : site.getPropertyNames()) { if (propertyName.startsWith(AttributeDTO.PROPERTY_PREFIX)) { int attributeId = AttributeDTO.idForPropertyName(propertyName); boolean value = site.get(propertyName, false); if (value) { ids.add(attributeId); } } } return ids; } @GET @Path("{id}/monthlyReports") @Produces("application/json") public String queryMonthlyReports(@PathParam("id") int siteId) throws IOException { GetMonthlyReports command = new GetMonthlyReports(siteId, new Month(0,1), new Month(Integer.MAX_VALUE, 12)); MonthlyReportResult result = dispatcher.execute(command); // list all months Set<String> monthNames = Sets.newHashSet(); for(IndicatorRowDTO row : result.getData()) { for(String propertyName : row.getPropertyNames()) { if(propertyName.startsWith("M")) { monthNames.add(propertyName); } } } // write out results per month StringWriter writer = new StringWriter(); JsonGenerator json = Jackson.createJsonFactory(writer); json.writeStartObject(); for(String monthName : monthNames) { json.writeArrayFieldStart(formatMonth(monthName)); for(IndicatorRowDTO row : result.getData()) { if(row.get(monthName) instanceof Number) { json.writeStartObject(); Number value = row.get(monthName); json.writeNumberField("indicatorId", row.getIndicatorId()); json.writeStringField("indicatorName", row.getIndicatorName()); json.writeNumberField("value", value.doubleValue()); json.writeEndObject(); } } json.writeEndArray(); } json.writeEndObject(); json.close(); return writer.toString(); } @Path("/cube") public CubeResource getCube() { return new CubeResource(dispatcher); } private String formatMonth(String propertyName) { Month month = Month.parseMonth(propertyName.substring(1)); String monthName = month.getYear() + "-"; if(month.getMonth() < 10) { monthName += "0"; } monthName += month.getMonth(); return monthName; } }