2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.model
.description
;
12 import java
.util
.ArrayList
;
13 import java
.util
.HashMap
;
14 import java
.util
.HashSet
;
15 import java
.util
.List
;
19 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
20 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
21 import eu
.etaxonomy
.cdm
.model
.common
.Representation
;
22 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
23 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
24 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
26 import org
.apache
.log4j
.Logger
;
27 import org
.hibernate
.annotations
.Cascade
;
28 import org
.hibernate
.annotations
.CascadeType
;
29 import javax
.persistence
.*;
30 import javax
.xml
.bind
.annotation
.XmlAccessType
;
31 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
32 import javax
.xml
.bind
.annotation
.XmlElement
;
33 import javax
.xml
.bind
.annotation
.XmlIDREF
;
34 import javax
.xml
.bind
.annotation
.XmlRootElement
;
35 import javax
.xml
.bind
.annotation
.XmlSchemaType
;
36 import javax
.xml
.bind
.annotation
.XmlType
;
39 * This class represents elementary distribution data for a {@link Taxon taxon}.
40 * Only {@link TaxonDescription taxon descriptions} may contain distributions.
41 * A distribution instance consist of a {@link NamedArea named area} and of a {@link PresenceAbsenceTermBase status}
42 * describing the absence or the presence of a taxon (like "extinct"
43 * or "introduced") in this named area.
45 * This class corresponds partially to: <ul>
46 * <li> CodedDescriptionType according to the the SDD schema
47 * <li> Distribution according to the TDWG ontology
52 * @created 08-Nov-2007 13:06:21
54 @XmlAccessorType(XmlAccessType
.FIELD
)
55 @XmlType(name
= "Distribution", propOrder
= {
59 @XmlRootElement(name
= "Distribution")
61 public class Distribution
extends DescriptionElementBase
{
62 static Logger logger
= Logger
.getLogger(Distribution
.class);
64 @XmlElement(name
= "NamedArea")
66 @XmlSchemaType(name
= "IDREF")
67 private NamedArea area
;
69 @XmlElement(name
= "PresenceAbsenceStatus")
70 private PresenceAbsenceTermBase
<?
> status
;
74 * Class constructor: creates a new empty distribution instance.
75 * The corresponding {@link Feature feature} is set to {@link Feature#DISTRIBUTION() DISTRIBUTION}.
77 protected Distribution(){
78 super(Feature
.DISTRIBUTION());
83 * Creates an empty distribution instance. The corresponding {@link Feature feature}
84 * is set to {@link Feature#DISTRIBUTION() DISTRIBUTION}.
86 * @see #NewInstance(NamedArea, PresenceAbsenceTermBase)
88 public static Distribution
NewInstance(){
89 Distribution result
= new Distribution();
94 * Creates a distribution instance with the given {@link NamedArea named area} and {@link PresenceAbsenceTermBase status}.
95 * The corresponding {@link Feature feature} is set to {@link Feature#DISTRIBUTION() DISTRIBUTION}.
97 * @param area the named area for the new distribution
98 * @param status the presence or absence term for the new distribution
101 public static Distribution
NewInstance(NamedArea area
, PresenceAbsenceTermBase
<?
> status
){
102 Distribution result
= new Distribution();
103 result
.setArea(area
);
104 result
.setStatus(status
);
112 * Deprecated because {@link Feature feature} should always be {@link Feature#DISTRIBUTION() DISTRIBUTION}
113 * for all distribution instances.
116 * @see eu.etaxonomy.cdm.model.description.DescriptionElementBase#setFeature(eu.etaxonomy.cdm.model.description.Feature)
120 public void setFeature(Feature feature
) {
121 super.setFeature(feature
);
125 * Returns the {@link NamedArea named area} <i>this</i> distribution applies to.
128 @Cascade({CascadeType
.SAVE_UPDATE
})
129 public NamedArea
getArea(){
135 public void setArea(NamedArea area
){
140 * Returns the {@link PresenceAbsenceTermBase presence or absence term} for <i>this</i> distribution.
143 public PresenceAbsenceTermBase
<?
> getStatus(){
149 public void setStatus(PresenceAbsenceTermBase
<?
> status
){
150 this.status
= status
;
153 //preliminary implementation for TDWG areas
155 //TODO move to an other place -> e.g. service layer
156 public static String
getWebServiceUrl(Set
<Distribution
> distributions
, String webServiceUrl
, int width
, int height
, String bbox
){
159 String areaData
= "";
160 String areaStyle
= "";
161 String widthStr
= null;
162 String heightStr
= null;
163 String adLayerSeperator
= "/";
165 if (webServiceUrl
== null){
166 logger
.warn("No WebServiceURL defined");
169 //List<String> layerStrings = new ArrayList<String>();
170 Map
<String
, Map
<Integer
, Set
<Distribution
>>> layerMap
= new HashMap
<String
, Map
<Integer
, Set
<Distribution
>>>();
171 List
<PresenceAbsenceTermBase
<?
>> statusList
= new ArrayList
<PresenceAbsenceTermBase
<?
>>();
175 widthStr
= "w=" + width
;
178 heightStr
= "h=" + height
;
181 //iterate through distributions and group styles and layers
182 for (Distribution distribution
:distributions
){
184 PresenceAbsenceTermBase
<?
> status
= distribution
.getStatus();
185 if (! statusList
.contains(status
)){
186 statusList
.add(status
);
188 //group by layers and styles
189 NamedArea area
= distribution
.getArea();
191 NamedAreaLevel level
= area
.getLevel();
192 String geoLayerString
= getGeoServiceLayer(level
);
193 //Set<Distribution> layerDistributionSet;
194 //int index = layerStrings.indexOf(geoLayerString);
195 Map
<Integer
, Set
<Distribution
>> styleMap
= layerMap
.get(geoLayerString
);
196 if (styleMap
== null){
197 styleMap
= new HashMap
<Integer
, Set
<Distribution
>>();
198 layerMap
.put(geoLayerString
, styleMap
);
200 addDistributionToMap(distribution
, styleMap
, statusList
);
206 for (String layerString
: layerMap
.keySet()){
207 layer
+= "|" + layerString
;
209 layer
= "l=" + layer
.substring(1); //remove first |
214 Map
<PresenceAbsenceTermBase
<?
>, Character
> styleCharMap
= new HashMap
<PresenceAbsenceTermBase
<?
>, Character
>();
216 for (PresenceAbsenceTermBase
<?
> status
: statusList
){
217 char style
= getStyleAbbrev(i
);
218 String color
= status
.getDefaultColor();//"00FFAA"; //TODO
219 areaStyle
+= "|" + style
+ ":" + color
;
220 styleCharMap
.put(status
, style
);
224 String styleWorkaround
= "|z:FFFFFF";
225 areaStyle
= "as=" + areaStyle
.substring(1) + styleWorkaround
; //remove first |
229 boolean isFirstLayer
= true;
230 for (String layerString
: layerMap
.keySet()){
231 //Set<Distribution> layerDistributions = layerData.get(layerIndex);
232 //int distributionListIndex = 1;
233 areaData
+= (isFirstLayer?
"" : "||") + layerString
+ adLayerSeperator
;
234 Map
<Integer
, Set
<Distribution
>> styleMap
= layerMap
.get(layerString
);
235 boolean isFirstStyle
= true;
236 for (int style
: styleMap
.keySet()){
237 char styleChar
= getStyleAbbrev(style
);
238 areaData
+= (isFirstStyle?
"" : "|") + styleChar
+ ":";
239 Set
<Distribution
> distributionSet
= styleMap
.get(style
);
240 boolean isFirstDistribution
= true;
241 for (Distribution distribution
: distributionSet
){
242 String areaAbbrev
= getAreaAbbrev(distribution
);
243 areaData
+= (isFirstDistribution ?
"" : ",") + areaAbbrev
;
244 isFirstDistribution
= false;
246 isFirstStyle
= false;
248 isFirstLayer
= false;
251 String workaround
= "tdwg2/z:Subarctic%20America,Australia||";
252 areaData
= "ad=" + workaround
+ areaData
.substring(0); //remove first |
255 result
= webServiceUrl
+ "?";
256 result
+= CdmUtils
.concat("&", new String
[] {layer
, areaData
, areaStyle
, bbox
, widthStr
, heightStr
});
260 private static String
getAreaAbbrev(Distribution distribution
){
261 NamedArea area
= distribution
.getArea();
262 Representation representation
= area
.getRepresentation(Language
.DEFAULT());
263 String areaAbbrev
= representation
.getAbbreviatedLabel();
267 private static void addDistributionToMap(Distribution distribution
, Map
<Integer
, Set
<Distribution
>> styleMap
, List
<PresenceAbsenceTermBase
<?
>> statusList
){
268 int style
= statusList
.indexOf(distribution
.getStatus());
269 Set
<Distribution
> distributionSet
= styleMap
.get(style
);
270 if (distributionSet
== null){
271 distributionSet
= new HashSet
<Distribution
>();
272 styleMap
.put(style
, distributionSet
);
274 distributionSet
.add(distribution
);
279 * transform an integer (style counter) into a valid character representing a style.
282 * i not in {0,...,51} is undefined
286 private static char getStyleAbbrev(int i
){
295 private static String
getGeoServiceLayer(NamedAreaLevel level
){
296 //TODO integrate into CDM
297 if (level
.equals(NamedAreaLevel
.TDWG_LEVEL1())){
299 }else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL2())){
301 }if (level
.equals(NamedAreaLevel
.TDWG_LEVEL3())){
303 }if (level
.equals(NamedAreaLevel
.TDWG_LEVEL4())){