3 * Copyright (C) 2009 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.
10 package eu
.etaxonomy
.cdm
.ext
.geo
;
12 import java
.awt
.Color
;
13 import java
.io
.IOException
;
14 import java
.io
.Reader
;
15 import java
.util
.ArrayList
;
16 import java
.util
.Collection
;
17 import java
.util
.EnumSet
;
18 import java
.util
.HashSet
;
19 import java
.util
.List
;
22 import java
.util
.UUID
;
24 import javax
.persistence
.EntityNotFoundException
;
26 import org
.apache
.log4j
.Logger
;
27 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
28 import org
.springframework
.stereotype
.Service
;
29 import org
.springframework
.transaction
.annotation
.Transactional
;
31 import eu
.etaxonomy
.cdm
.api
.service
.IDescriptionService
;
32 import eu
.etaxonomy
.cdm
.api
.service
.dto
.CondensedDistribution
;
33 import eu
.etaxonomy
.cdm
.api
.service
.dto
.DistributionInfoDTO
;
34 import eu
.etaxonomy
.cdm
.api
.service
.dto
.DistributionInfoDTO
.InfoPart
;
35 import eu
.etaxonomy
.cdm
.api
.utility
.DescriptionUtility
;
36 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTermBase
;
37 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
38 import eu
.etaxonomy
.cdm
.model
.common
.MarkerType
;
39 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
40 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
41 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
42 import eu
.etaxonomy
.cdm
.model
.description
.IndividualsAssociation
;
43 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTerm
;
44 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
45 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
46 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
47 import eu
.etaxonomy
.cdm
.model
.location
.Point
;
48 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
49 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldUnit
;
50 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
51 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationType
;
52 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IDefinedTermDao
;
53 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ITermVocabularyDao
;
54 import eu
.etaxonomy
.cdm
.persistence
.dao
.description
.IDescriptionDao
;
55 import eu
.etaxonomy
.cdm
.persistence
.dao
.occurrence
.IOccurrenceDao
;
58 * @author a.kohlbecker
63 @Transactional(readOnly
= true)
64 public class EditGeoService
implements IEditGeoService
{
65 public static final Logger logger
= Logger
.getLogger(EditGeoService
.class);
68 private IDescriptionDao dao
;
71 private IGeoServiceAreaMapping areaMapping
;
74 private IDescriptionService descriptionService
;
77 private ITermVocabularyDao vocabDao
;
79 private IDefinedTermDao termDao
;
81 public void setTermDao(IDefinedTermDao termDao
) {
82 this.termDao
= termDao
;
83 EditGeoServiceUtilities
.setTermDao(termDao
);
87 private IOccurrenceDao occurrenceDao
;
89 private Set
<Feature
> getDistributionFeatures() {
90 Set
<Feature
> distributionFeature
= new HashSet
<Feature
>();
91 Feature feature
= (Feature
) termDao
.findByUuid(Feature
.DISTRIBUTION().getUuid());
92 distributionFeature
.add(feature
);
93 return distributionFeature
;
97 * @param taxonDescriptions
100 private Set
<Distribution
> getDistributionsOf(List
<TaxonDescription
> taxonDescriptions
) {
101 Set
<Distribution
> distributions
= new HashSet
<Distribution
>();
102 for (TaxonDescription taxonDescription
: taxonDescriptions
) {
103 List
<Distribution
> result
= (List
) dao
.getDescriptionElements(
106 getDistributionFeatures(),
111 distributions
.addAll(result
);
113 return distributions
;
120 public String
getDistributionServiceRequestParameterString(List
<TaxonDescription
> taxonDescriptions
,
121 boolean subAreaPreference
,
122 boolean statusOrderPreference
,
123 Set
<MarkerType
> hideMarkedAreas
,
124 Map
<PresenceAbsenceTerm
, Color
> presenceAbsenceTermColors
,
125 List
<Language
> langs
) {
127 Set
<Distribution
> distributions
= getDistributionsOf(taxonDescriptions
);
129 String uriParams
= getDistributionServiceRequestParameterString(distributions
,
131 statusOrderPreference
,
133 presenceAbsenceTermColors
,
143 public String
getDistributionServiceRequestParameterString(
144 Set
<Distribution
> distributions
,
145 boolean subAreaPreference
,
146 boolean statusOrderPreference
,
147 Set
<MarkerType
> hideMarkedAreas
,
148 Map
<PresenceAbsenceTerm
, Color
> presenceAbsenceTermColors
,
149 List
<Language
> langs
) {
151 Collection
<Distribution
> filteredDistributions
= DescriptionUtility
.filterDistributions(distributions
,
152 hideMarkedAreas
, true, statusOrderPreference
, subAreaPreference
);
155 String uriParams
= EditGeoServiceUtilities
.getDistributionServiceRequestParameterString(
156 filteredDistributions
,
158 presenceAbsenceTermColors
,
168 public String
getDistributionServiceRequestParameterString(TaxonDescription taxonDescription
,
169 boolean subAreaPreference
,
170 boolean statusOrderPreference
,
171 Set
<MarkerType
> hideMarkedAreas
,
172 Map
<PresenceAbsenceTerm
, Color
> presenceAbsenceTermColors
,
173 List
<Language
> langs
) {
175 List
<TaxonDescription
> taxonDescriptions
= new ArrayList
<TaxonDescription
>();
176 taxonDescriptions
.add(taxonDescription
);
178 return getDistributionServiceRequestParameterString(taxonDescriptions
,
180 statusOrderPreference
,
182 presenceAbsenceTermColors
,
190 public OccurrenceServiceRequestParameterDto
getOccurrenceServiceRequestParameterString(List
<SpecimenOrObservationBase
> specimensOrObersvations
,
191 Map
<SpecimenOrObservationType
, Color
> specimenOrObservationTypeColors
) {
193 List
<Point
> fieldUnitPoints
= new ArrayList
<Point
>();
194 List
<Point
> derivedUnitPoints
= new ArrayList
<Point
>();
196 IndividualsAssociation individualsAssociation
;
197 DerivedUnit derivedUnit
;
199 for (SpecimenOrObservationBase specimenOrObservationBase
: specimensOrObersvations
) {
200 SpecimenOrObservationBase
<?
> specimenOrObservation
= occurrenceDao
201 .load(specimenOrObservationBase
.getUuid());
203 if (specimenOrObservation
instanceof FieldUnit
) {
204 fieldUnitPoints
.add(((FieldUnit
) specimenOrObservation
).getGatheringEvent()
205 .getExactLocation());
207 if (specimenOrObservation
instanceof DerivedUnit
) {
208 registerDerivedUnitLocations((DerivedUnit
) specimenOrObservation
, derivedUnitPoints
);
212 return EditGeoServiceUtilities
.getOccurrenceServiceRequestParameterString(fieldUnitPoints
,
213 derivedUnitPoints
, specimenOrObservationTypeColors
);
217 public CondensedDistribution
getCondensedDistribution(List
<TaxonDescription
> taxonDescriptions
,
218 boolean statusOrderPreference
,
219 Set
<MarkerType
> hideMarkedAreas
,
220 MarkerType fallbackAreaMarkerType
,
221 CondensedDistributionRecipe recipe
,
222 List
<Language
> langs
) {
223 Set
<Distribution
> distributions
= getDistributionsOf(taxonDescriptions
);
224 return getCondensedDistribution(distributions
, statusOrderPreference
,
225 hideMarkedAreas
, fallbackAreaMarkerType
, recipe
, langs
);
228 public CondensedDistribution
getCondensedDistribution(Set
<Distribution
> distributions
,
229 boolean statusOrderPreference
,
230 Set
<MarkerType
> hideMarkedAreas
,
231 MarkerType fallbackAreaMarkerType
,
232 CondensedDistributionRecipe recipe
,
233 List
<Language
> langs
) {
235 Collection
<Distribution
> filteredDistributions
= DescriptionUtility
.filterDistributions(
236 distributions
, hideMarkedAreas
, true, statusOrderPreference
, false);
240 CondensedDistribution condensedDistribution
= EditGeoServiceUtilities
.getCondensedDistribution(
241 filteredDistributions
,
245 return condensedDistribution
;
250 * @param derivedUnitPoints
252 private void registerDerivedUnitLocations(DerivedUnit derivedUnit
, List
<Point
> derivedUnitPoints
) {
254 Set
<SpecimenOrObservationBase
> originals
= derivedUnit
.getOriginals();
255 if (originals
!= null) {
256 for (SpecimenOrObservationBase original
: originals
) {
257 if (original
instanceof FieldUnit
) {
258 if (((FieldUnit
) original
).getGatheringEvent() != null) {
259 Point point
= ((FieldUnit
) original
).getGatheringEvent().getExactLocation();
261 // points with no longitude or latitude should not exist
262 // see #4173 ([Rule] Longitude and Latitude in Point must not be null)
263 if (point
.getLatitude() == null || point
.getLongitude() == null){
266 // FIXME: remove next statement after
267 // DerivedUnitFacade or ABCD import is fixed
269 if(point
.getLatitude() == 0.0 || point
.getLongitude() == 0.0) {
272 derivedUnitPoints
.add(point
);
276 registerDerivedUnitLocations((DerivedUnit
) original
, derivedUnitPoints
);
288 public void setMapping(NamedArea area
, GeoServiceArea geoServiceArea
) {
289 areaMapping
.set(area
, geoServiceArea
);
297 @Transactional(readOnly
=false)
298 public Map
<NamedArea
, String
> mapShapeFileToNamedAreas(Reader csvReader
,
299 List
<String
> idSearchFields
, String wmsLayerName
, UUID areaVocabularyUuid
,
300 Set
<UUID
> namedAreaUuids
) throws IOException
{
302 Set
<NamedArea
> areas
= new HashSet
<NamedArea
>();
304 if(areaVocabularyUuid
!= null){
305 TermVocabulary
<NamedArea
> areaVocabulary
= vocabDao
.load(areaVocabularyUuid
);
306 if(areaVocabulary
== null){
307 throw new EntityNotFoundException("No Vocabulary found for uuid " + areaVocabularyUuid
);
309 areas
.addAll(areaVocabulary
.getTerms());
311 if(namedAreaUuids
!= null && !namedAreaUuids
.isEmpty()){
312 for(DefinedTermBase dtb
: termDao
.list(namedAreaUuids
, null, null, null, null)){
313 areas
.add((NamedArea
)dtb
);
317 ShpAttributesToNamedAreaMapper mapper
= new ShpAttributesToNamedAreaMapper(areas
, areaMapping
);
318 Map
<NamedArea
, String
> resultMap
= mapper
.readCsv(csvReader
, idSearchFields
, wmsLayerName
);
319 termDao
.saveOrUpdateAll((Collection
)areas
);
327 public DistributionInfoDTO
composeDistributionInfoFor(EnumSet
<DistributionInfoDTO
.InfoPart
> parts
, UUID taxonUUID
,
328 boolean subAreaPreference
, boolean statusOrderPreference
, Set
<MarkerType
> hiddenAreaMarkerTypes
,
329 Set
<NamedAreaLevel
> omitLevels
, Map
<PresenceAbsenceTerm
, Color
> presenceAbsenceTermColors
,
330 List
<Language
> languages
, List
<String
> propertyPaths
, CondensedDistributionRecipe recipe
){
332 DistributionInfoDTO dto
= new DistributionInfoDTO();
334 // Adding default initStrategies to improve the performance of this method
335 // adding 'status' and 'area' has a good positive effect:
336 // filterDistributions() only takes 21% of the total method time (before it was 46%)
337 // at the same time the cost of the getDescriptionElementForTaxon is not increased at all!
339 // adding 'markers.markerType' is not improving the performance since it only
340 // moved the load from the filter method to the getDescriptionElementForTaxon()
342 // overall improvement by this means is by 42% (from 77,711 ms to 44,868 ms)
343 ArrayList
<String
> initStrategy
= new ArrayList
<String
>(propertyPaths
);
344 if(!initStrategy
.contains("status")) {
345 initStrategy
.add("status");
347 if(!initStrategy
.contains("area")) {
348 initStrategy
.add("area");
350 if(!initStrategy
.contains("markers.markerType")) {
351 initStrategy
.add("markers.markerType");
353 if(omitLevels
== null) {
354 omitLevels
= new HashSet
<NamedAreaLevel
>(0);
357 List
<Distribution
> distributions
= dao
.getDescriptionElementForTaxon(taxonUUID
, null, Distribution
.class, null, null, initStrategy
);
359 // Apply the rules statusOrderPreference and hideMarkedAreas for textual distribution info
360 Set
<Distribution
> filteredDistributions
= DescriptionUtility
.filterDistributions(distributions
, hiddenAreaMarkerTypes
,
361 true, statusOrderPreference
, false);
363 if(parts
.contains(InfoPart
.elements
)) {
364 dto
.setElements(filteredDistributions
);
367 if(parts
.contains(InfoPart
.tree
)) {
368 dto
.setTree(DescriptionUtility
.orderDistributions(termDao
, omitLevels
, filteredDistributions
, hiddenAreaMarkerTypes
));
371 if(parts
.contains(InfoPart
.condensedDistribution
)) {
372 dto
.setCondensedDistribution(EditGeoServiceUtilities
.getCondensedDistribution(filteredDistributions
, recipe
, languages
));
375 if (parts
.contains(InfoPart
.mapUriParams
)) {
376 // only apply the subAreaPreference rule for the maps
377 Set
<Distribution
> filteredMapDistributions
= DescriptionUtility
.filterDistributions(filteredDistributions
, null, false, false, subAreaPreference
);
379 dto
.setMapUriParams(EditGeoServiceUtilities
.getDistributionServiceRequestParameterString(filteredMapDistributions
,
381 presenceAbsenceTermColors
,