3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
11 package eu
.etaxonomy
.cdm
.ext
.geo
;
13 import java
.awt
.Color
;
14 import java
.io
.UnsupportedEncodingException
;
15 import java
.net
.URLEncoder
;
16 import java
.util
.ArrayList
;
17 import java
.util
.Collection
;
18 import java
.util
.Collections
;
19 import java
.util
.HashMap
;
20 import java
.util
.HashSet
;
21 import java
.util
.List
;
24 import java
.util
.UUID
;
26 import javax
.persistence
.Transient
;
28 import org
.apache
.commons
.lang
.StringUtils
;
29 import org
.apache
.log4j
.Logger
;
31 import eu
.etaxonomy
.cdm
.api
.utility
.DescriptionUtility
;
32 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
33 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
34 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTermBase
;
35 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
36 import eu
.etaxonomy
.cdm
.model
.common
.Representation
;
37 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
38 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
39 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTermBase
;
40 import eu
.etaxonomy
.cdm
.model
.description
.PresenceTerm
;
41 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
42 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
43 import eu
.etaxonomy
.cdm
.model
.location
.Point
;
44 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationType
;
45 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IDefinedTermDao
;
48 * Class implementing the business logic for creating the map service string for
49 * a given set of distributions. See {@link EditGeoService} as API for the given functionality.
56 public class EditGeoServiceUtilities
{
57 private static final Logger logger
= Logger
.getLogger(EditGeoServiceUtilities
.class);
59 private static PresenceAbsenceTermBase
<?
> defaultStatus
= PresenceTerm
.PRESENT();
61 private static IDefinedTermDao termDao
;
68 public static void setTermDao(IDefinedTermDao termDao
) {
69 EditGeoServiceUtilities
.termDao
= termDao
;
72 private static HashMap
<SpecimenOrObservationType
, Color
> defaultSpecimenOrObservationTypeColors
= null;
74 private static HashMap
<SpecimenOrObservationType
, Color
> getDefaultSpecimenOrObservationTypeColors() {
75 if(defaultSpecimenOrObservationTypeColors
== null){
76 defaultSpecimenOrObservationTypeColors
= new HashMap
<SpecimenOrObservationType
, Color
>();
77 defaultSpecimenOrObservationTypeColors
.put(SpecimenOrObservationType
.FieldUnit
, Color
.ORANGE
);
78 defaultSpecimenOrObservationTypeColors
.put(SpecimenOrObservationType
.DerivedUnit
, Color
.RED
);
79 defaultSpecimenOrObservationTypeColors
.put(SpecimenOrObservationType
.LivingSpecimen
, Color
.GREEN
);
80 defaultSpecimenOrObservationTypeColors
.put(SpecimenOrObservationType
.Observation
, Color
.ORANGE
);
81 defaultSpecimenOrObservationTypeColors
.put(SpecimenOrObservationType
.PreservedSpecimen
, Color
.GRAY
);
82 defaultSpecimenOrObservationTypeColors
.put(SpecimenOrObservationType
.Media
, Color
.BLUE
);
84 return defaultSpecimenOrObservationTypeColors
;
88 private static HashMap
<PresenceAbsenceTermBase
<?
>, Color
> defaultPresenceAbsenceTermBaseColors
= null;
90 private static HashMap
<PresenceAbsenceTermBase
<?
>, Color
> getDefaultPresenceAbsenceTermBaseColors() {
91 if(defaultPresenceAbsenceTermBaseColors
== null){
92 defaultPresenceAbsenceTermBaseColors
= new HashMap
<PresenceAbsenceTermBase
<?
>, Color
>();
93 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.PRESENT(), Color
.decode("0x4daf4a"));
94 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.NATIVE(), Color
.decode("0x4daf4a"));
95 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.NATIVE_DOUBTFULLY_NATIVE(), Color
.decode("0x377eb8"));
96 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.CULTIVATED(), Color
.decode("0x984ea3"));
97 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.INTRODUCED(), Color
.decode("0xff7f00"));
98 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.INTRODUCED_ADVENTITIOUS(), Color
.decode("0xffff33"));
99 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.INTRODUCED_CULTIVATED(), Color
.decode("0xa65628"));
100 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.INTRODUCED_NATURALIZED(), Color
.decode("0xf781bf"));
103 * and now something very hacky ...
104 * ONLY-A-TEST is set by the Test class EditGeoServiceTest
106 * TODO remove according line from
107 * EditGeoServiceTest.setUp() when the hardcoded colors for flora of
108 * cyprus are no further needed !!
110 String onlyTest
= System
.getProperty("ONLY-A-TEST"); //
111 if(onlyTest
!= null && onlyTest
.equals("TRUE")){
112 return defaultPresenceAbsenceTermBaseColors
;
114 //special colors for flora of cyprus !!! see HACK above !!!
115 UUID indigenousUuid
= UUID
.fromString("b325859b-504b-45e0-9ef0-d5c1602fcc0f");
116 UUID indigenousQUuid
= UUID
.fromString("17bc601f-53eb-4997-a4bc-c03ce5bfd1d3");
118 UUID cultivatedQUuid
= UUID
.fromString("4f31bfc8-3058-4d83-aea5-3a1fe9773f9f");
120 UUID casualUuid
= UUID
.fromString("5e81353c-38a3-4ca6-b979-0d9abc93b877");
121 UUID casualQUuid
= UUID
.fromString("73f75493-1185-4a3e-af1e-9a1f2e8dadb7");
123 UUID naturalizedNonInvasiveUuid
= UUID
.fromString("1b025e8b-901a-42e8-9739-119b410c6f03");
124 UUID naturalizedNonInvasiveQUuid
= UUID
.fromString("11f56e2f-c16c-4b3d-a870-bb5d3b20e624");
126 UUID naturalizedInvasiveUuid
= UUID
.fromString("faf2d271-868a-4bf7-b0b8-a1c5ab309de2");
127 UUID naturalizedInvasiveQUuid
= UUID
.fromString("ac429d5f-e8ad-49ae-a41c-e4779b58b96a");
129 UUID questionablelUuid
= UUID
.fromString("4b48f675-a6cf-49f3-a5ba-77e2c2979eb3");
130 UUID questionableQUuid
= UUID
.fromString("914e7393-1314-4632-bc45-5eff3dc1e424");
132 UUID reportedInErrorUuid
= UUID
.fromString("38604788-cf05-4607-b155-86db456f7680");
134 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(indigenousUuid
), Color
.decode("0x339966"));
135 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(indigenousQUuid
), Color
.decode("0x339966"));
137 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(cultivatedQUuid
), Color
.decode("0xbdb76b"));
139 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(casualUuid
), Color
.decode("0xffff00"));
140 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(casualQUuid
), Color
.decode("0xffff00"));
142 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(naturalizedNonInvasiveUuid
), Color
.decode("0xff9900"));
143 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(naturalizedNonInvasiveQUuid
), Color
.decode("0xff9900"));
145 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(naturalizedInvasiveUuid
), Color
.decode("0xff0000"));
146 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(naturalizedInvasiveQUuid
), Color
.decode("0xff0000"));
148 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(questionablelUuid
), Color
.decode("0x00ccff"));
149 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(questionableQUuid
), Color
.decode("0x00ccff"));
151 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(reportedInErrorUuid
), Color
.decode("0xcccccc"));
154 return defaultPresenceAbsenceTermBaseColors
;
159 private static final String SUBENTRY_DELIMITER
= ",";
160 private static final String ENTRY_DELIMITER
= ";";
161 static final String ID_FROM_VALUES_SEPARATOR
= ":";
162 static final String VALUE_LIST_ENTRY_SEPARATOR
= "|";
163 static final String VALUE_SUPER_LIST_ENTRY_SEPARATOR
= "||";
167 //preliminary implementation for TDWG areas
169 * Returns the parameter String for the EDIT geo webservice to create a
172 * @param distributions
173 * A set of distributions that should be shown on the map
174 * @param presenceAbsenceTermColors
175 * A map that defines the colors of PresenceAbsenceTerms. The
176 * PresenceAbsenceTerms are defined by their uuid. If a
177 * PresenceAbsenceTerm is not included in this map, it's default
178 * color is taken instead. If the map == null all terms are
179 * colored by their default color.
185 * The maps bounding box (e.g. "-180,-90,180,90" for the whole
187 * @param projectToLayer
188 * name of a layer which is representing a specific
189 * {@link NamedAreaLevel} Supply this parameter if you to project
190 * all other distribution area levels to this layer.
192 * The layer that is responsible for background borders and
193 * colors. Use the name for the layer. If null 'earth' is taken
195 * @return the parameter string or an empty string if the
196 * <code>distributions</code> set was null or empty.
199 public static String
getDistributionServiceRequestParameterString(
200 Set
<Distribution
> distributions
,
201 IGeoServiceAreaMapping mapping
,
202 Map
<PresenceAbsenceTermBase
<?
>,Color
> presenceAbsenceTermColors
,
206 String baseLayerName
,
207 String projectToLayer
,
208 List
<Language
> languages
){
212 * generateMultipleAreaDataParameters switches between the two possible styles:
213 * 1. ad=layername1:area-data||layername2:area-data
214 * 2. ad=layername1:area-data&ad=layername2:area-data
216 boolean generateMultipleAreaDataParameters
= false;
219 * doNotReuseStyles is a workaround for a problem in the EDIT MapService,
220 * see https://dev.e-taxonomy.eu/trac/ticket/2707#comment:24
222 boolean doNotReuseStyles
= true;
224 List
<String
> perLayerAreaData
= new ArrayList
<String
>();
225 Map
<Integer
, String
> areaStyles
= new HashMap
<Integer
, String
>();
226 List
<String
> legendLabels
= new ArrayList
<String
>();
229 String borderWidth
= "0.1";
230 String borderColorRgb
= "";
231 String borderDashingPattern
= "";
235 if(distributions
== null || distributions
.size() == 0){
239 Collection
<Distribution
> filteredDistributions
= DescriptionUtility
.filterDistributions(distributions
);
241 Map
<String
, Map
<Integer
, Set
<Distribution
>>> layerMap
= new HashMap
<String
, Map
<Integer
, Set
<Distribution
>>>();
242 List
<PresenceAbsenceTermBase
<?
>> statusList
= new ArrayList
<PresenceAbsenceTermBase
<?
>>();
244 // TODO this step seems to be taking too much time
245 groupStylesAndLayers(filteredDistributions
, layerMap
, statusList
, mapping
);
247 presenceAbsenceTermColors
= mergeMaps(getDefaultPresenceAbsenceTermBaseColors(), presenceAbsenceTermColors
);
249 Map
<String
, String
> parameters
= new HashMap
<String
, String
>();
253 parameters
.put("bbox", bbox
);
256 String ms
= compileMapSizeParameterValue(width
, height
);
258 parameters
.put("ms", ms
);
261 // if (StringUtils.isBlank(baseLayerName)){
262 // baseLayerName = "earth";
264 if (!StringUtils
.isBlank(baseLayerName
)){
265 parameters
.put("l", baseLayerName
);
269 int styleCounter
= 0;
270 for (PresenceAbsenceTermBase
<?
> status
: statusList
){
272 char styleCode
= getStyleAbbrev(styleCounter
);
274 //getting the area title
275 if (languages
== null){
276 languages
= new ArrayList
<Language
>();
278 if (languages
.size() == 0){
279 languages
.add(Language
.DEFAULT());
281 Representation representation
= status
.getPreferredRepresentation(languages
);
282 String statusLabel
= representation
.getLabel();
283 //statusLabel.replace('introduced: ', '');
284 statusLabel
= statusLabel
.replace("introduced: ", "introduced, ");
285 statusLabel
= statusLabel
.replace("native: ", "native, ");
287 //getting the area color
288 Color statusColor
= presenceAbsenceTermColors
.get(status
);
290 if (statusColor
!= null){
291 fillColorRgb
= Integer
.toHexString(statusColor
.getRGB()).substring(2);
294 fillColorRgb
= status
.getDefaultColor(); //TODO
296 fillColorRgb
= defaultStatus
.getDefaultColor();
299 String styleValues
= StringUtils
.join(new String
[]{fillColorRgb
, borderColorRgb
, borderWidth
, borderDashingPattern
}, ',');
301 areaStyles
.put(styleCounter
, styleValues
);
302 legendLabels
.add(styleCode
+ ID_FROM_VALUES_SEPARATOR
+ encode(statusLabel
));
307 List
<String
> styledAreasPerLayer
;
308 List
<String
> areasPerStyle
;
310 * Used to avoid reusing styles in multiple layers
313 * value: the count of how often the style has been used for different layers, starts with 0 for first time use
315 Map
<Integer
, Integer
> styleUsage
= new HashMap
<Integer
, Integer
>();
317 for (String layerString
: layerMap
.keySet()){
319 styledAreasPerLayer
= new ArrayList
<String
>();
320 Map
<Integer
, Set
<Distribution
>> styleMap
= layerMap
.get(layerString
);
321 for (int style
: styleMap
.keySet()){
323 if(doNotReuseStyles
) {
324 if(!styleUsage
.containsKey(style
)){
325 styleUsage
.put(style
, 0);
328 styleUsage
.put(style
, styleUsage
.get(style
) + 1);
330 Integer styleIncrement
= styleUsage
.get(style
);
331 if(styleIncrement
> 0){
332 // style code has been used before!
333 styleChar
= getStyleAbbrev(style
+ styleIncrement
+ styleCounter
);
334 areaStyles
.put(style
+ styleIncrement
+ styleCounter
, areaStyles
.get(style
));
336 styleChar
= getStyleAbbrev(style
);
339 styleChar
= getStyleAbbrev(style
);
341 Set
<Distribution
> distributionSet
= styleMap
.get(style
);
342 areasPerStyle
= new ArrayList
<String
>();
343 for (Distribution distribution
: distributionSet
){
345 areasPerStyle
.add(encode(getAreaCode(distribution
, mapping
)));
347 styledAreasPerLayer
.add(styleChar
+ ID_FROM_VALUES_SEPARATOR
+ StringUtils
.join(areasPerStyle
.iterator(), SUBENTRY_DELIMITER
));
349 perLayerAreaData
.add(encode(layerString
) + ID_FROM_VALUES_SEPARATOR
+ StringUtils
.join(styledAreasPerLayer
.iterator(), VALUE_LIST_ENTRY_SEPARATOR
));
352 if(areaStyles
.size() > 0){
353 ArrayList
<Integer
> styleIds
= new ArrayList
<Integer
>(areaStyles
.size());
354 styleIds
.addAll(areaStyles
.keySet());
355 Collections
.sort(styleIds
);
356 StringBuilder db
= new StringBuilder();
357 for(Integer sid
: styleIds
){
359 db
.append(VALUE_LIST_ENTRY_SEPARATOR
);
361 db
.append( getStyleAbbrev(sid
)).append(ID_FROM_VALUES_SEPARATOR
).append(areaStyles
.get(sid
));
363 parameters
.put("as", db
.toString());
365 if(legendLabels
.size() > 0){
366 parameters
.put("title", StringUtils
.join(legendLabels
.iterator(), VALUE_LIST_ENTRY_SEPARATOR
));
370 if(generateMultipleAreaDataParameters
){
371 // not generically possible since parameters can not contain duplicate keys with value "ad"
373 parameters
.put("ad", StringUtils
.join(perLayerAreaData
.iterator(), VALUE_SUPER_LIST_ENTRY_SEPARATOR
));
376 String queryString
= makeQueryString(parameters
);
377 logger
.debug("getDistributionServiceRequestParameterString(): " + queryString
);
384 * Fills the layerMap and the statusList
386 * @param distributions
387 * @param layerMap see {@link #addAreaToLayerMap(Map, List, Distribution, NamedArea, IGeoServiceAreaMapping)}
390 private static void groupStylesAndLayers(Collection
<Distribution
> distributions
,
391 Map
<String
, Map
<Integer
,Set
<Distribution
>>> layerMap
,
392 List
<PresenceAbsenceTermBase
<?
>> statusList
,
393 IGeoServiceAreaMapping mapping
) {
396 //iterate through distributions and group styles and layers
397 //and collect necessary information
398 for (Distribution distribution
: distributions
){
400 PresenceAbsenceTermBase
<?
> status
= distribution
.getStatus();
402 status
= defaultStatus
;
404 if (! statusList
.contains(status
)){
405 statusList
.add(status
);
407 //group areas by layers and styles
408 NamedArea area
= distribution
.getArea();
410 addAreaToLayerMap(layerMap
, statusList
, distribution
, area
, mapping
);
415 * A layer map holds the following information:
418 * <li><b>String</b>: the WMSLayerName which matches the level of the
419 * contained distributions areas</li>
420 * <li><b>StyleMap</b>:</li>
422 * <li><b>Integer</b>: the index of the status in the
423 * <code>statusList</code></li>
424 * <li><b>Set{@code<Distribution>}</b>: the set of distributions having the
425 * same Status, the status list is populated in {@link #groupStylesAndLayers(Set, Map, List, IGeoServiceAreaMapping)}</li>
431 * @param distribution
434 private static void addAreaToLayerMap(Map
<String
, Map
<Integer
,
435 Set
<Distribution
>>> layerMap
,
436 List
<PresenceAbsenceTermBase
<?
>> statusList
,
437 Distribution distribution
,
439 IGeoServiceAreaMapping mapping
) {
442 String geoLayerString
= getWMSLayerName(area
, mapping
);
444 if(geoLayerString
== null){
446 // if no layer is mapped this area descend into sub areas in order to project
447 // the distribution to those
448 for(DefinedTermBase
<?
> dtb
: area
.getIncludes()){
449 NamedArea subArea
= HibernateProxyHelper
.deproxy(dtb
, NamedArea
.class);
450 addAreaToLayerMap(layerMap
, statusList
, distribution
, subArea
, mapping
);
455 Map
<Integer
, Set
<Distribution
>> styleMap
= layerMap
.get(geoLayerString
);
456 if (styleMap
== null) {
457 styleMap
= new HashMap
<Integer
, Set
<Distribution
>>();
458 layerMap
.put(geoLayerString
, styleMap
);
460 addDistributionToStyleMap(distribution
, styleMap
, statusList
);
467 private static String
compileMapSizeParameterValue(int width
, int height
) {
469 String widthStr
= "";
470 String heightStr
= "";
473 widthStr
= "" + width
;
476 heightStr
= SUBENTRY_DELIMITER
+ height
;
478 String ms
= widthStr
+ heightStr
;
479 if(ms
.length() == 0){
486 * URI encode the given String
490 private static String
encode(String string
) {
491 String encoded
= string
;
493 encoded
= URLEncoder
.encode(string
, "UTF-8");
494 } catch (UnsupportedEncodingException e
) {
501 * combine parameter into a URI query string fragment. The values will be
505 * @return a URI query string fragment
507 private static String
makeQueryString(Map
<String
, String
> parameters
){
508 StringBuilder queryString
= new StringBuilder();
509 for (String key
: parameters
.keySet()) {
510 if(queryString
.length() > 0){
511 queryString
.append('&');
513 if(key
.equals("od") || key
.equals("os") || key
.equals("ms") || key
.equals("ad") || key
.equals("as") || key
.equals("title") || key
.equals("bbox")){
514 queryString
.append(key
).append('=').append(parameters
.get(key
));
516 queryString
.append(key
).append('=').append(encode(parameters
.get(key
)));
519 return queryString
.toString();
522 private static String
getAreaCode(Distribution distribution
, IGeoServiceAreaMapping mapping
){
523 NamedArea area
= distribution
.getArea();
524 TermVocabulary
<NamedArea
> voc
= area
.getVocabulary();
525 String result
= null;
527 if (voc
!= null && voc
.getUuid().equals(NamedArea
.uuidTdwgAreaVocabulary
)
528 || voc
.getUuid().equals(uuidCyprusDivisionsVocabulary
)) {
530 result
= area
.getIdInVocabulary();
531 if (area
.getLevel() != null && area
.getLevel().equals(NamedAreaLevel
.TDWG_LEVEL4())) {
532 result
= result
.replace("-", "");
535 // use generic GeoServiceArea data stored in technical annotations
538 GeoServiceArea areas
= mapping
.valueOf(area
);
539 if ((areas
!= null) && areas
.size() > 0) {
540 // FIXME multiple layers
541 List
<String
> values
= areas
.getAreasMap().values().iterator().next().values().iterator().next();
542 for (String value
: values
) {
543 result
= CdmUtils
.concat(SUBENTRY_DELIMITER
, result
, value
);
548 return CdmUtils
.Nz(result
, "-");
554 //Preliminary as long as user defined areas are not fully implemented
555 public static final UUID uuidCyprusDivisionsVocabulary
= UUID
.fromString("2119f610-1f93-4d87-af28-40aeefaca100");
557 private static List
<String
> projectToWMSSubLayer(NamedArea area
){
559 List
<String
> layerNames
= new ArrayList
<String
>();
560 String matchedLayerName
= null;
561 TermVocabulary
<NamedArea
> voc
= area
.getVocabulary();
563 if (voc
.getUuid().equals(NamedArea
.uuidTdwgAreaVocabulary
)){
564 NamedAreaLevel level
= area
.getLevel();
566 //TODO integrate into CDM
567 if (level
.equals(NamedAreaLevel
.TDWG_LEVEL1())) {
568 matchedLayerName
= "tdwg1" ;
569 } else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL2())) {
570 matchedLayerName
= "tdwg2";
571 }else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL3())) {
572 matchedLayerName
= "tdwg3";
573 }else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL4())) {
574 matchedLayerName
= "tdwg4";
577 //unrecognized tdwg area
580 //TODO hardcoded for cyprus (as long as user defined areas are not fully implemented). Remove afterwards.
581 if (voc
.getUuid().equals(uuidCyprusDivisionsVocabulary
)){
582 matchedLayerName
= "cyprusdivs:bdcode";
585 // check if the matched layer equals the layer to project to
586 // if not: recurse into the sub-level in order to find the specified one.
587 String
[] matchedLayerNameTokens
= StringUtils
.split(matchedLayerName
, ':');
588 // if(matchedLayerNameTokens.length > 0 && matchedLayerNameTokens[0] != projectToLayer){
589 // for (NamedArea subArea : area.getIncludes()){
599 private static String
getWMSLayerName(NamedArea area
, IGeoServiceAreaMapping mapping
){
600 TermVocabulary
<NamedArea
> voc
= area
.getVocabulary();
602 if (voc
.getUuid().equals(NamedArea
.uuidTdwgAreaVocabulary
)){
603 NamedAreaLevel level
= area
.getLevel();
605 //TODO integrate into CDM
606 if (level
.equals(NamedAreaLevel
.TDWG_LEVEL1())) {
608 } else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL2())) {
610 }else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL3())) {
612 }else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL4())) {
616 //unrecognized tdwg area
620 //hardcoded for cyprus (as long as user defined areas are not fully implemented). Remove afterwards.
621 if (voc
.getUuid().equals(uuidCyprusDivisionsVocabulary
)){
622 return "cyprusdivs:bdcode";
625 GeoServiceArea areas
= mapping
.valueOf(area
);
626 if (areas
!= null && areas
.getAreasMap().size() > 0){
627 //FIXME multiple layers
628 String layer
= areas
.getAreasMap().keySet().iterator().next();
629 Map
<String
, List
<String
>> fields
= areas
.getAreasMap().get(layer
);
630 String field
= fields
.keySet().iterator().next();
631 String layerString
= layer
+ ":" + field
;
632 return layerString
.toLowerCase();
639 private static void addDistributionToStyleMap(Distribution distribution
, Map
<Integer
, Set
<Distribution
>> styleMap
,
640 List
<PresenceAbsenceTermBase
<?
>> statusList
) {
641 PresenceAbsenceTermBase
<?
> status
= distribution
.getStatus();
642 if (status
== null) {
643 status
= defaultStatus
;
645 int style
= statusList
.indexOf(status
);
646 Set
<Distribution
> distributionSet
= styleMap
.get(style
);
647 if (distributionSet
== null) {
648 distributionSet
= new HashSet
<Distribution
>();
649 styleMap
.put(style
, distributionSet
);
651 distributionSet
.add(distribution
);
655 * @param fieldUnitPoints
656 * @param derivedUnitPoints
657 * @param specimenOrObservationTypeColors
658 * @param doReturnImage TODO
671 * &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
672 * &os=1%3Ac%2FFFD700%2F10%2FAporrectodea caliginosa
674 public static String
getOccurrenceServiceRequestParameterString(
675 List
<Point
> fieldUnitPoints
,
676 List
<Point
> derivedUnitPoints
,
677 Map
<SpecimenOrObservationType
, Color
> specimenOrObservationTypeColors
,
678 Boolean doReturnImage
, Integer width
, Integer height
, String bbox
, String backLayer
) {
680 specimenOrObservationTypeColors
= mergeMaps(getDefaultSpecimenOrObservationTypeColors(), specimenOrObservationTypeColors
);
682 Map
<String
, String
> parameters
= new HashMap
<String
, String
>();
683 parameters
.put("legend", "0");
684 parameters
.put("image", doReturnImage
!= null && doReturnImage ?
"true" : "false");
685 parameters
.put("recalculate", "false"); // TODO add parameter to method
687 parameters
.put("bbox", bbox
);
689 if(width
!= null || height
!= null){
690 parameters
.put("ms", compileMapSizeParameterValue(width
, height
));
693 Map
<String
, String
> styleAndData
= new HashMap
<String
, String
>();
695 addToStyleAndData(fieldUnitPoints
, SpecimenOrObservationType
.FieldUnit
, specimenOrObservationTypeColors
, styleAndData
);
696 addToStyleAndData(derivedUnitPoints
, SpecimenOrObservationType
.DerivedUnit
, specimenOrObservationTypeColors
, styleAndData
);
698 parameters
.put("os", StringUtils
.join(styleAndData
.keySet().iterator(), "||"));
699 parameters
.put("od", StringUtils
.join(styleAndData
.values().iterator(), "||"));
701 String queryString
= makeQueryString(parameters
);
703 logger
.info(queryString
);
715 private static <T
, S
> Map
<T
, S
> mergeMaps(Map
<T
, S
> defaultMap
, Map
<T
, S
> overrideMap
) {
716 Map
<T
, S
> tmpMap
= new HashMap
<T
, S
>();
717 tmpMap
.putAll(defaultMap
);
718 if(overrideMap
!= null){
719 tmpMap
.putAll(overrideMap
);
724 private static void addToStyleAndData(
726 SpecimenOrObservationType specimenOrObservationType
,
727 Map
<SpecimenOrObservationType
, Color
> specimenOrObservationTypeColors
, Map
<String
, String
> styleAndData
) {
729 //TODO add markerShape and size and Label to specimenOrObservationTypeColors -> Map<Class<SpecimenOrObservationBase<?>>, MapStyle>
731 if(points
!= null && points
.size()>0){
732 String style
= "c/" + Integer
.toHexString(specimenOrObservationTypeColors
.get(specimenOrObservationType
).getRGB()).substring(2) + "/10/noLabel";
733 StringBuilder data
= new StringBuilder();
734 for(Point point
: points
){
735 if(data
.length() > 0){
738 data
.append(point
.getLatitude() + "," + point
.getLongitude());
740 int index
= styleAndData
.size() + 1;
741 styleAndData
.put(index
+ ":" +style
, index
+ ":" +data
.toString());
747 * transform an integer (style counter) into a valid character representing a style.
750 * i not in {0,...,51} is undefined
754 private static char getStyleAbbrev(int i
){