X-Git-Url: https://dev.e-taxonomy.eu/gitweb/cdmlib.git/blobdiff_plain/41ac3198866c1696c7e10beddd705d145fd7ecac..c59da2646103ea436e37f25b35288c6b0042e361:/cdmlib-ext/src/main/java/eu/etaxonomy/cdm/ext/geo/EditGeoServiceUtilities.java?ds=sidebyside diff --git a/cdmlib-ext/src/main/java/eu/etaxonomy/cdm/ext/geo/EditGeoServiceUtilities.java b/cdmlib-ext/src/main/java/eu/etaxonomy/cdm/ext/geo/EditGeoServiceUtilities.java index 2546bc4b0f..47d01471c7 100644 --- a/cdmlib-ext/src/main/java/eu/etaxonomy/cdm/ext/geo/EditGeoServiceUtilities.java +++ b/cdmlib-ext/src/main/java/eu/etaxonomy/cdm/ext/geo/EditGeoServiceUtilities.java @@ -11,6 +11,7 @@ package eu.etaxonomy.cdm.ext.geo; import java.awt.Color; +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; @@ -25,19 +26,26 @@ import java.util.UUID; import javax.persistence.Transient; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.Transformer; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; - +import org.codehaus.jackson.JsonParseException; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.type.MapType; +import org.codehaus.jackson.map.type.TypeFactory; + +import eu.etaxonomy.cdm.api.service.ITermService; +import eu.etaxonomy.cdm.api.service.dto.CondensedDistribution; import eu.etaxonomy.cdm.api.utility.DescriptionUtility; import eu.etaxonomy.cdm.common.CdmUtils; -import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper; -import eu.etaxonomy.cdm.model.common.DefinedTermBase; import eu.etaxonomy.cdm.model.common.Language; import eu.etaxonomy.cdm.model.common.Representation; import eu.etaxonomy.cdm.model.common.TermVocabulary; import eu.etaxonomy.cdm.model.description.Distribution; -import eu.etaxonomy.cdm.model.description.PresenceAbsenceTermBase; -import eu.etaxonomy.cdm.model.description.PresenceTerm; +import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm; +import eu.etaxonomy.cdm.model.location.Country; import eu.etaxonomy.cdm.model.location.NamedArea; import eu.etaxonomy.cdm.model.location.NamedAreaLevel; import eu.etaxonomy.cdm.model.location.Point; @@ -56,7 +64,9 @@ import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao; public class EditGeoServiceUtilities { private static final Logger logger = Logger.getLogger(EditGeoServiceUtilities.class); - private static PresenceAbsenceTermBase defaultStatus = PresenceTerm.PRESENT(); + private static final int INT_MAX_LENGTH = String.valueOf(Integer.MAX_VALUE).length(); + + private static PresenceAbsenceTerm defaultStatus = PresenceAbsenceTerm.PRESENT(); private static IDefinedTermDao termDao; @@ -69,6 +79,7 @@ public class EditGeoServiceUtilities { EditGeoServiceUtilities.termDao= termDao; } + private static HashMap defaultSpecimenOrObservationTypeColors = null; private static HashMap getDefaultSpecimenOrObservationTypeColors() { @@ -85,27 +96,27 @@ public class EditGeoServiceUtilities { } - private static HashMap, Color> defaultPresenceAbsenceTermBaseColors = null; + private static HashMap defaultPresenceAbsenceTermBaseColors = null; - private static HashMap, Color> getDefaultPresenceAbsenceTermBaseColors() { + private static HashMap getDefaultPresenceAbsenceTermBaseColors() { if(defaultPresenceAbsenceTermBaseColors == null){ - defaultPresenceAbsenceTermBaseColors = new HashMap, Color>(); - defaultPresenceAbsenceTermBaseColors.put(PresenceTerm.PRESENT(), Color.decode("0x4daf4a")); - defaultPresenceAbsenceTermBaseColors.put(PresenceTerm.NATIVE(), Color.decode("0x4daf4a")); - defaultPresenceAbsenceTermBaseColors.put(PresenceTerm.NATIVE_DOUBTFULLY_NATIVE(), Color.decode("0x377eb8")); - defaultPresenceAbsenceTermBaseColors.put(PresenceTerm.CULTIVATED(), Color.decode("0x984ea3")); - defaultPresenceAbsenceTermBaseColors.put(PresenceTerm.INTRODUCED(), Color.decode("0xff7f00")); - defaultPresenceAbsenceTermBaseColors.put(PresenceTerm.INTRODUCED_ADVENTITIOUS(), Color.decode("0xffff33")); - defaultPresenceAbsenceTermBaseColors.put(PresenceTerm.INTRODUCED_CULTIVATED(), Color.decode("0xa65628")); - defaultPresenceAbsenceTermBaseColors.put(PresenceTerm.INTRODUCED_NATURALIZED(), Color.decode("0xf781bf")); + defaultPresenceAbsenceTermBaseColors = new HashMap(); + defaultPresenceAbsenceTermBaseColors.put(PresenceAbsenceTerm.PRESENT(), Color.decode("0x4daf4a")); + defaultPresenceAbsenceTermBaseColors.put(PresenceAbsenceTerm.NATIVE(), Color.decode("0x4daf4a")); + defaultPresenceAbsenceTermBaseColors.put(PresenceAbsenceTerm.NATIVE_DOUBTFULLY_NATIVE(), Color.decode("0x377eb8")); + defaultPresenceAbsenceTermBaseColors.put(PresenceAbsenceTerm.CULTIVATED(), Color.decode("0x984ea3")); + defaultPresenceAbsenceTermBaseColors.put(PresenceAbsenceTerm.INTRODUCED(), Color.decode("0xff7f00")); + defaultPresenceAbsenceTermBaseColors.put(PresenceAbsenceTerm.INTRODUCED_ADVENTITIOUS(), Color.decode("0xffff33")); + defaultPresenceAbsenceTermBaseColors.put(PresenceAbsenceTerm.INTRODUCED_CULTIVATED(), Color.decode("0xa65628")); + defaultPresenceAbsenceTermBaseColors.put(PresenceAbsenceTerm.INTRODUCED_NATURALIZED(), Color.decode("0xf781bf")); /* * and now something very hacky ... * ONLY-A-TEST is set by the Test class EditGeoServiceTest * - * TODO remove according line from - * EditGeoServiceTest.setUp() when the hardcoded colors for flora of - * cyprus are no further needed !! + * FIXME remove according line from + * EditGeoServiceTest.setUp() since the hardcoded colors for flora of + * cyprus should no longer be needed : #4268 (allow defining custom presence and absence term colors for EditGeoServiceUtilities) */ String onlyTest = System.getProperty("ONLY-A-TEST"); // if(onlyTest != null && onlyTest.equals("TRUE")){ @@ -131,24 +142,24 @@ public class EditGeoServiceUtilities { UUID reportedInErrorUuid = UUID.fromString("38604788-cf05-4607-b155-86db456f7680"); - defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTermBase) termDao.load(indigenousUuid), Color.decode("0x339966")); - defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTermBase) termDao.load(indigenousQUuid), Color.decode("0x339966")); + defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTerm) termDao.load(indigenousUuid), Color.decode("0x339966")); + defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTerm) termDao.load(indigenousQUuid), Color.decode("0x339966")); - defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTermBase) termDao.load(cultivatedQUuid), Color.decode("0xbdb76b")); + defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTerm) termDao.load(cultivatedQUuid), Color.decode("0xbdb76b")); - defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTermBase) termDao.load(casualUuid), Color.decode("0xffff00")); - defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTermBase) termDao.load(casualQUuid), Color.decode("0xffff00")); + defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTerm) termDao.load(casualUuid), Color.decode("0xffff00")); + defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTerm) termDao.load(casualQUuid), Color.decode("0xffff00")); - defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTermBase) termDao.load(naturalizedNonInvasiveUuid), Color.decode("0xff9900")); - defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTermBase) termDao.load(naturalizedNonInvasiveQUuid), Color.decode("0xff9900")); + defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTerm) termDao.load(naturalizedNonInvasiveUuid), Color.decode("0xff9900")); + defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTerm) termDao.load(naturalizedNonInvasiveQUuid), Color.decode("0xff9900")); - defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTermBase) termDao.load(naturalizedInvasiveUuid), Color.decode("0xff0000")); - defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTermBase) termDao.load(naturalizedInvasiveQUuid), Color.decode("0xff0000")); + defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTerm) termDao.load(naturalizedInvasiveUuid), Color.decode("0xff0000")); + defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTerm) termDao.load(naturalizedInvasiveQUuid), Color.decode("0xff0000")); - defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTermBase) termDao.load(questionablelUuid), Color.decode("0x00ccff")); - defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTermBase) termDao.load(questionableQUuid), Color.decode("0x00ccff")); + defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTerm) termDao.load(questionablelUuid), Color.decode("0x00ccff")); + defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTerm) termDao.load(questionableQUuid), Color.decode("0x00ccff")); - defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTermBase) termDao.load(reportedInErrorUuid), Color.decode("0xcccccc")); + defaultPresenceAbsenceTermBaseColors.put((PresenceAbsenceTerm) termDao.load(reportedInErrorUuid), Color.decode("0xcccccc")); } return defaultPresenceAbsenceTermBaseColors; @@ -163,68 +174,66 @@ public class EditGeoServiceUtilities { static final String VALUE_SUPER_LIST_ENTRY_SEPARATOR = "||"; - - //preliminary implementation for TDWG areas /** * Returns the parameter String for the EDIT geo webservice to create a - * dsitribution map. + * distribution map. * * @param distributions * A set of distributions that should be shown on the map + * The {@link DescriptionUtility} class provides a method for + * filtering a set of Distributions : + * + * {@code + * Collection filteredDistributions = + * DescriptionUtility.filterDistributions(distributions, + * subAreaPreference, statusOrderPreference, hideMarkedAreas); + * } + * @param mapping + * Data regarding the mapping of NamedAreas to shape file + * attribute tables * @param presenceAbsenceTermColors * A map that defines the colors of PresenceAbsenceTerms. The * PresenceAbsenceTerms are defined by their uuid. If a * PresenceAbsenceTerm is not included in this map, it's default * color is taken instead. If the map == null all terms are * colored by their default color. - * @param width - * The maps width - * @param height - * The maps height - * @param bbox - * The maps bounding box (e.g. "-180,-90,180,90" for the whole - * world) * @param projectToLayer * name of a layer which is representing a specific * {@link NamedAreaLevel} Supply this parameter if you to project * all other distribution area levels to this layer. - * @param layer - * The layer that is responsible for background borders and - * colors. Use the name for the layer. If null 'earth' is taken - * as default. + * @param languages + * * @return the parameter string or an empty string if the * distributions set was null or empty. */ @Transient public static String getDistributionServiceRequestParameterString( - Set distributions, + Collection filteredDistributions, IGeoServiceAreaMapping mapping, - Map,Color> presenceAbsenceTermColors, - int width, - int height, - String bbox, - String baseLayerName, + Map presenceAbsenceTermColors, String projectToLayer, List languages){ - /** + /* * generateMultipleAreaDataParameters switches between the two possible styles: * 1. ad=layername1:area-data||layername2:area-data * 2. ad=layername1:area-data&ad=layername2:area-data */ boolean generateMultipleAreaDataParameters = false; - /** + /* * doNotReuseStyles is a workaround for a problem in the EDIT MapService, * see https://dev.e-taxonomy.eu/trac/ticket/2707#comment:24 + * + * a.kohlbecker 2014-07-02 :This bug in the map service has been + * fixed now so reusing styles is now possible setting this flag to false. */ - boolean doNotReuseStyles = true; + boolean doNotReuseStyles = false; List perLayerAreaData = new ArrayList(); - Map areaStyles = new HashMap(); - List legendLabels = new ArrayList(); - + Map areaStyles = new HashMap(); + List legendSortList = new ArrayList(); String borderWidth = "0.1"; String borderColorRgb = ""; @@ -232,42 +241,22 @@ public class EditGeoServiceUtilities { //handle empty set - if(distributions == null || distributions.size() == 0){ + if(filteredDistributions == null || filteredDistributions.size() == 0){ return ""; } - Collection filteredDistributions = DescriptionUtility.filterDistributions(distributions); + presenceAbsenceTermColors = mergeMaps(getDefaultPresenceAbsenceTermBaseColors(), presenceAbsenceTermColors); Map>> layerMap = new HashMap>>(); - List> statusList = new ArrayList>(); + List statusList = new ArrayList(); - // TODO this step seems to be taking too much time groupStylesAndLayers(filteredDistributions, layerMap, statusList, mapping); - presenceAbsenceTermColors = mergeMaps(getDefaultPresenceAbsenceTermBaseColors(), presenceAbsenceTermColors); - Map parameters = new HashMap(); - //bbox - if (bbox != null){ - parameters.put("bbox", bbox); - } - // map size - String ms = compileMapSizeParameterValue(width, height); - if(ms != null){ - parameters.put("ms", ms); - } - //layer -// if (StringUtils.isBlank(baseLayerName)){ -// baseLayerName = "earth"; -// } - if (!StringUtils.isBlank(baseLayerName)){ - parameters.put("l", baseLayerName); - } - //style int styleCounter = 0; - for (PresenceAbsenceTermBase status: statusList){ + for (PresenceAbsenceTerm status: statusList){ char styleCode = getStyleAbbrev(styleCounter); @@ -278,11 +267,7 @@ public class EditGeoServiceUtilities { if (languages.size() == 0){ languages.add(Language.DEFAULT()); } - Representation representation = status.getPreferredRepresentation(languages); - String statusLabel = representation.getLabel(); - //statusLabel.replace('introduced: ', ''); - statusLabel = statusLabel.replace("introduced: ", "introduced, "); - statusLabel = statusLabel.replace("native: ", "native, "); + Representation statusRepresentation = status.getPreferredRepresentation(languages); //getting the area color Color statusColor = presenceAbsenceTermColors.get(status); @@ -299,7 +284,9 @@ public class EditGeoServiceUtilities { String styleValues = StringUtils.join(new String[]{fillColorRgb, borderColorRgb, borderWidth, borderDashingPattern}, ','); areaStyles.put(styleCounter, styleValues); - legendLabels.add(styleCode + ID_FROM_VALUES_SEPARATOR + encode(statusLabel)); + + String legendEntry = styleCode + ID_FROM_VALUES_SEPARATOR + encode(statusRepresentation.getLabel()); + legendSortList.add(StringUtils.leftPad(String.valueOf(status.getOrderIndex()), INT_MAX_LENGTH, '0') + legendEntry ); styleCounter++; } @@ -307,12 +294,15 @@ public class EditGeoServiceUtilities { List styledAreasPerLayer; List areasPerStyle; /** + * Map styleUsage + * * Used to avoid reusing styles in multiple layers * * key: the style id * value: the count of how often the style has been used for different layers, starts with 0 for first time use */ Map styleUsage = new HashMap(); + char styleChar; for (String layerString : layerMap.keySet()){ // each layer @@ -331,6 +321,8 @@ public class EditGeoServiceUtilities { if(styleIncrement > 0){ // style code has been used before! styleChar = getStyleAbbrev(style + styleIncrement + styleCounter); + //for debugging sometimes failing test #3831 + logger.warn("style: " + style + ", styleIncrement: " + styleIncrement + ", styleCounter: " + styleCounter); areaStyles.put(style + styleIncrement + styleCounter, areaStyles.get(style)); } else { styleChar = getStyleAbbrev(style); @@ -352,7 +344,7 @@ public class EditGeoServiceUtilities { if(areaStyles.size() > 0){ ArrayList styleIds = new ArrayList(areaStyles.size()); styleIds.addAll(areaStyles.keySet()); - Collections.sort(styleIds); + Collections.sort(styleIds); // why is it necessary to sort here? StringBuilder db = new StringBuilder(); for(Integer sid : styleIds){ if(db.length() > 0){ @@ -362,10 +354,27 @@ public class EditGeoServiceUtilities { } parameters.put("as", db.toString()); } - if(legendLabels.size() > 0){ - parameters.put("title", StringUtils.join(legendLabels.iterator(), VALUE_LIST_ENTRY_SEPARATOR)); - } + if(legendSortList.size() > 0){ + // sort the label entries after the status terms + Collections.sort(legendSortList); + // since the status terms are have an inverse natural order + // (as all other ordered term, see OrderedTermBase.performCompareTo(T orderedTerm, boolean skipVocabularyCheck) + // the sorted list must be reverted +// Collections.reverse(legendSortList); + // remove the prepended order index (like 000000000000001 ) from the legend entries + @SuppressWarnings("unchecked") + Collection legendEntries = CollectionUtils.collect(legendSortList, new Transformer() + { + @Override + public String transform(Object o) + { + String s = ((String) o); + return s.substring(INT_MAX_LENGTH, s.length()); + } + }); + parameters.put("title", StringUtils.join(legendEntries.iterator(), VALUE_LIST_ENTRY_SEPARATOR)); + } if(generateMultipleAreaDataParameters){ // not generically possible since parameters can not contain duplicate keys with value "ad" @@ -389,7 +398,7 @@ public class EditGeoServiceUtilities { */ private static void groupStylesAndLayers(Collection distributions, Map>> layerMap, - List> statusList, + List statusList, IGeoServiceAreaMapping mapping) { @@ -397,7 +406,7 @@ public class EditGeoServiceUtilities { //and collect necessary information for (Distribution distribution : distributions){ //collect status - PresenceAbsenceTermBase status = distribution.getStatus(); + PresenceAbsenceTerm status = distribution.getStatus(); if(status == null){ status = defaultStatus; } @@ -412,6 +421,9 @@ public class EditGeoServiceUtilities { } /** + * Adds the areas to the layer map. Areas which do not have layer information + * mapped to them are ignored. + *

* A layer map holds the following information: * *

    @@ -433,60 +445,28 @@ public class EditGeoServiceUtilities { */ private static void addAreaToLayerMap(Map>> layerMap, - List> statusList, + List statusList, Distribution distribution, NamedArea area, IGeoServiceAreaMapping mapping) { if (area != null){ - String geoLayerString = getWMSLayerName(area, mapping); - - if(geoLayerString == null){ - - // if no layer is mapped this area descend into sub areas in order to project - // the distribution to those - /** - * FIXME ClassCaseException!!! - * getIncludes(): Hibernate returns this as a collection of CGLibProxy$$DefinedTermBase objects - * which can't be cast to instances of T - can we explicitly initialize these terms using - * Hibernate.initialize(), does this imply a distinct load, and find methods in the dao? - */ - for(DefinedTermBase dtb : area.getIncludes()){ - NamedArea subArea = HibernateProxyHelper.deproxy(dtb, NamedArea.class); - addAreaToLayerMap(layerMap, statusList, distribution, subArea, mapping); - } + String geoLayerName = getWMSLayerName(area, mapping); + if(geoLayerName == null){ + /* IGNORE areas for which no layer is mapped */ } else { - - Map> styleMap = layerMap.get(geoLayerString); + Map> styleMap = layerMap.get(geoLayerName); if (styleMap == null) { styleMap = new HashMap>(); - layerMap.put(geoLayerString, styleMap); + layerMap.put(geoLayerName, styleMap); } addDistributionToStyleMap(distribution, styleMap, statusList); - } } } - private static String compileMapSizeParameterValue(int width, int height) { - - String widthStr = ""; - String heightStr = ""; - - if (width > 0) { - widthStr = "" + width; - } - if (height > 0) { - heightStr = SUBENTRY_DELIMITER + height; - } - String ms = widthStr + heightStr; - if(ms.length() == 0){ - ms = null; - } - return ms; - } /** * URI encode the given String @@ -530,9 +510,8 @@ public class EditGeoServiceUtilities { TermVocabulary voc = area.getVocabulary(); String result = null; - if (voc != null && voc.getUuid().equals(NamedArea.uuidTdwgAreaVocabulary) - || voc.getUuid().equals(uuidCyprusDivisionsVocabulary)) { - // TDWG or Cyprus + if (voc != null && voc.getUuid().equals(NamedArea.uuidTdwgAreaVocabulary) || voc.getUuid().equals(Country.uuidCountryVocabulary)) { + // TDWG or Country result = area.getIdInVocabulary(); if (area.getLevel() != null && area.getLevel().equals(NamedAreaLevel.TDWG_LEVEL4())) { result = result.replace("-", ""); @@ -555,11 +534,6 @@ public class EditGeoServiceUtilities { } - - - //Preliminary as long as user defined areas are not fully implemented - public static final UUID uuidCyprusDivisionsVocabulary = UUID.fromString("2119f610-1f93-4d87-af28-40aeefaca100"); - private static List projectToWMSSubLayer(NamedArea area){ List layerNames = new ArrayList(); @@ -583,10 +557,7 @@ public class EditGeoServiceUtilities { //unrecognized tdwg area } - //TODO hardcoded for cyprus (as long as user defined areas are not fully implemented). Remove afterwards. - if (voc.getUuid().equals(uuidCyprusDivisionsVocabulary)){ - matchedLayerName = "cyprusdivs:bdcode"; - } + //TODO countries // check if the matched layer equals the layer to project to // if not: recurse into the sub-level in order to find the specified one. @@ -622,10 +593,8 @@ public class EditGeoServiceUtilities { //unrecognized tdwg area return null; - } - //hardcoded for cyprus (as long as user defined areas are not fully implemented). Remove afterwards. - if (voc.getUuid().equals(uuidCyprusDivisionsVocabulary)){ - return "cyprusdivs:bdcode"; + }else if (voc.getUuid().equals(Country.uuidCountryVocabulary)){ + return "country_earth:gmi_cntry"; } GeoServiceArea areas = mapping.valueOf(area); @@ -643,8 +612,8 @@ public class EditGeoServiceUtilities { private static void addDistributionToStyleMap(Distribution distribution, Map> styleMap, - List> statusList) { - PresenceAbsenceTermBase status = distribution.getStatus(); + List statusList) { + PresenceAbsenceTerm status = distribution.getStatus(); if (status == null) { status = defaultStatus; } @@ -661,7 +630,6 @@ public class EditGeoServiceUtilities { * @param fieldUnitPoints * @param derivedUnitPoints * @param specimenOrObservationTypeColors - * @param doReturnImage TODO * @param width * @param height * @param bbox @@ -677,38 +645,35 @@ public class EditGeoServiceUtilities { * &od=1%3A44.29481%2C6.82161|44.29252%2C6.822873|44.29247%2C6.82346|44.29279%2C6.823678|44.29269%2C6.82394|44.28482%2C6.887252|44.11469%2C7.287144|44.11468%2C7.289168 * &os=1%3Ac%2FFFD700%2F10%2FAporrectodea caliginosa */ - public static String getOccurrenceServiceRequestParameterString( - List fieldUnitPoints, - List derivedUnitPoints, - Map specimenOrObservationTypeColors, - Boolean doReturnImage, Integer width, Integer height, String bbox, String backLayer) { - - specimenOrObservationTypeColors = mergeMaps(getDefaultSpecimenOrObservationTypeColors(), specimenOrObservationTypeColors); - - Map parameters = new HashMap(); - parameters.put("legend", "0"); - parameters.put("image", doReturnImage != null && doReturnImage ? "true" : "false"); - parameters.put("recalculate", "false"); // TODO add parameter to method - if(bbox != null){ - parameters.put("bbox", bbox); - } - if(width != null || height != null){ - parameters.put("ms", compileMapSizeParameterValue(width, height)); - } + public static OccurrenceServiceRequestParameterDto getOccurrenceServiceRequestParameterString( + List fieldUnitPoints, + List derivedUnitPoints, + Map specimenOrObservationTypeColors) { + OccurrenceServiceRequestParameterDto dto = new OccurrenceServiceRequestParameterDto(); - Map styleAndData = new HashMap(); - addToStyleAndData(fieldUnitPoints, SpecimenOrObservationType.FieldUnit, specimenOrObservationTypeColors, styleAndData); - addToStyleAndData(derivedUnitPoints, SpecimenOrObservationType.DerivedUnit, specimenOrObservationTypeColors, styleAndData); + specimenOrObservationTypeColors = mergeMaps(getDefaultSpecimenOrObservationTypeColors(), specimenOrObservationTypeColors); - parameters.put("os", StringUtils.join(styleAndData.keySet().iterator(), "||")); - parameters.put("od", StringUtils.join(styleAndData.values().iterator(), "||")); + Map parameters = new HashMap(); + parameters.put("legend", "0"); - String queryString = makeQueryString(parameters); + Map styleAndData = new HashMap(); - logger.info(queryString); + addToStyleAndData(fieldUnitPoints, SpecimenOrObservationType.FieldUnit, specimenOrObservationTypeColors, styleAndData); + addToStyleAndData(derivedUnitPoints, SpecimenOrObservationType.DerivedUnit, specimenOrObservationTypeColors, styleAndData); - return queryString; + parameters.put("os", StringUtils.join(styleAndData.keySet().iterator(), "||")); + parameters.put("od", StringUtils.join(styleAndData.values().iterator(), "||")); + + String queryString = makeQueryString(parameters); + + dto.setFieldUnitPoints(fieldUnitPoints); + dto.setDerivedUnitPoints(derivedUnitPoints); + dto.setOccurrenceQuery(queryString); + + logger.info(queryString); + + return dto; } /** @@ -766,4 +731,68 @@ public class EditGeoServiceUtilities { return (char)ascii; } + /** + * @param statusColorJson for example: {@code {"n":"#ff0000","p":"#ffff00"}} + * @return + * @throws IOException + * @throws JsonParseException + * @throws JsonMappingException + */ + public static Map buildStatusColorMap(String statusColorJson, ITermService termService) throws IOException, JsonParseException, + JsonMappingException { + + Map presenceAbsenceTermColors = null; + if(StringUtils.isNotEmpty(statusColorJson)){ + + ObjectMapper mapper = new ObjectMapper(); + // TODO cache the color maps to speed this up? + + TypeFactory typeFactory = mapper.getTypeFactory(); + MapType mapType = typeFactory.constructMapType(HashMap.class, String.class, String.class); + + Map statusColorMap = mapper.readValue(statusColorJson, mapType); + UUID presenceTermVocabUuid = PresenceAbsenceTerm.NATIVE().getVocabulary().getUuid(); + presenceAbsenceTermColors = new HashMap(); + PresenceAbsenceTerm paTerm = null; + for(String statusId : statusColorMap.keySet()){ + try { + Color color = Color.decode(statusColorMap.get(statusId)); + paTerm = termService.findByIdInVocabulary(statusId, presenceTermVocabUuid, PresenceAbsenceTerm.class); + if(paTerm != null){ + presenceAbsenceTermColors.put(paTerm, color); + } + } catch (NumberFormatException e){ + logger.error("Cannot decode color", e); + } + } + } + return presenceAbsenceTermColors; + } + + + /** + * @param filteredDistributions + * @param recipe + * @param hideMarkedAreas + * @param langs + * @return + */ + public static CondensedDistribution getCondensedDistribution(Collection filteredDistributions, + CondensedDistributionRecipe recipe, List langs) { + ICondensedDistributionComposer composer; + if(recipe == null) { + throw new NullPointerException("parameter recipe must not be null"); + } + try { + composer = recipe.newCondensedDistributionComposerInstance(); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + CondensedDistribution condensedDistribution = composer.createCondensedDistribution( + filteredDistributions, langs); + return condensedDistribution; + } + }