2 * Copyright (C) 2023 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.
9 package eu
.etaxonomy
.cdm
.api
.service
.geo
;
11 import java
.awt
.Color
;
12 import java
.io
.IOException
;
13 import java
.io
.Reader
;
14 import java
.util
.ArrayList
;
15 import java
.util
.Arrays
;
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
;
23 import java
.util
.stream
.Collectors
;
25 import javax
.persistence
.EntityNotFoundException
;
27 import org
.apache
.logging
.log4j
.LogManager
;
28 import org
.apache
.logging
.log4j
.Logger
;
29 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
30 import org
.springframework
.stereotype
.Service
;
31 import org
.springframework
.transaction
.annotation
.Transactional
;
33 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.DistributionInfoDto
;
34 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.DistributionInfoDto
.InfoPart
;
35 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.config
.CondensedDistribution
;
36 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.config
.CondensedDistributionConfiguration
;
37 import eu
.etaxonomy
.cdm
.api
.dto
.portal
.config
.DistributionInfoConfiguration
;
38 import eu
.etaxonomy
.cdm
.api
.service
.ICommonService
;
39 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
40 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
41 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
42 import eu
.etaxonomy
.cdm
.model
.common
.MarkerType
;
43 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
44 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
45 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
46 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTerm
;
47 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
48 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
49 import eu
.etaxonomy
.cdm
.model
.term
.DefinedTermBase
;
50 import eu
.etaxonomy
.cdm
.model
.term
.TermTree
;
51 import eu
.etaxonomy
.cdm
.model
.term
.TermVocabulary
;
52 import eu
.etaxonomy
.cdm
.persistence
.dao
.description
.IDescriptionDao
;
53 import eu
.etaxonomy
.cdm
.persistence
.dao
.term
.IDefinedTermDao
;
54 import eu
.etaxonomy
.cdm
.persistence
.dao
.term
.ITermVocabularyDao
;
61 @Transactional(readOnly
= true)
62 public class DistributionServiceImpl
implements IDistributionService
{
64 @SuppressWarnings("unused")
65 private static final Logger logger
= LogManager
.getLogger();
68 private IDescriptionDao dao
;
71 private ICommonService commonService
;
74 private IDefinedTermDao termDao
;
77 private ITermVocabularyDao vocabDao
;
80 private IGeoServiceAreaMapping areaMapping
;
83 public DistributionInfoDto
composeDistributionInfoFor(DistributionInfoConfiguration config
,
85 Map
<UUID
,Color
> distributionStatusColorMap
,
86 List
<Language
> languages
,
87 List
<String
> propertyPaths
){
89 Set
<UUID
> featureUuids
= config
.getFeatures();
90 Set
<Feature
> features
= null;
91 if (!CdmUtils
.isNullSafeEmpty(featureUuids
)) {
92 features
= termDao
.list(featureUuids
, null, null, null, null)
93 .stream().filter(t
->t
.isInstanceOf(Feature
.class)).map(t
->(Feature
)t
).collect(Collectors
.toSet());
96 if (propertyPaths
== null){
97 propertyPaths
= Arrays
.asList(new String
[]{});
99 // Adding default initStrategies to improve the performance of this method
100 // adding 'status' and 'area' has a good positive effect:
101 // filterDistributions() only takes 21% of the total method time (before it was 46%)
102 // at the same time the cost of the getDescriptionElementForTaxon is not increased at all!
104 // adding 'markers.markerType' is not improving the performance since it only
105 // moved the load from the filter method to the getDescriptionElementForTaxon()
107 // overall improvement by this means is by 42% (from 77,711 ms to 44,868 ms)
108 ArrayList
<String
> initStrategy
= new ArrayList
<>(propertyPaths
);
109 if(!initStrategy
.contains("status")) {
110 initStrategy
.add("status");
112 if(!initStrategy
.contains("area")) {
113 initStrategy
.add("area");
115 if(!initStrategy
.contains("markers.markerType")) {
116 initStrategy
.add("markers.markerType");
119 List
<Distribution
> distributions
= dao
.getDescriptionElementForTaxon(
120 taxonUUID
, features
, Distribution
.class, config
.isIncludeUnpublished(), null, null, initStrategy
);
122 TermTree
<NamedArea
> areaTree
= null;
123 TermTree
<PresenceAbsenceTerm
> statusTree
= null;
124 return new DistributionInfoBuilder(languages
, commonService
).build(
125 config
, distributions
, areaTree
, statusTree
,
126 distributionStatusColorMap
, areaMapping
);
130 public CondensedDistribution
getCondensedDistribution(Set
<Distribution
> distributions
,
131 TermTree
<NamedArea
> areaTree
,
132 TermTree
<PresenceAbsenceTerm
> statusTree
,
133 boolean statusOrderPreference
,
134 Set
<MarkerType
> fallbackAreaMarkerTypes
,
135 CondensedDistributionConfiguration config
,
136 List
<Language
> langs
) {
138 DistributionInfoConfiguration diConfig
= new DistributionInfoConfiguration();
139 diConfig
.setCondensedDistributionConfiguration(config
);
140 diConfig
.setFallbackAreaMarkerTypes(fallbackAreaMarkerTypes
);
141 diConfig
.setStatusOrderPreference(statusOrderPreference
);
142 diConfig
.setInfoParts(EnumSet
.of(InfoPart
.condensedDistribution
));
143 DistributionInfoDto distInfo
= new DistributionInfoBuilder(langs
, commonService
).build(diConfig
, distributions
, areaTree
, statusTree
, null, areaMapping
);
144 return distInfo
.getCondensedDistribution();
146 // Collection<DistributionTmpDto> filteredDistributions = DistributionServiceUtilities.filterDistributions(
147 // distributions, areaTree, statusTree, fallbackAreaMarkerTypes, false, statusOrderPreference,
148 // false, false, -99);
150 // //TODO exclude "undefined" status as long as status tree is not yet
151 // areaTree = areaTree == null ? DistributionServiceUtilities.getAreaTree(distributions, fallbackAreaMarkerTypes) : areaTree;
152 // SetMap<NamedArea,TermNode<NamedArea>> parentNodeMap = areaTree.getTerm2ParentNodeMap();
154 // CondensedDistribution condensedDistribution = DistributionServiceUtilities.getCondensedDistribution(
155 // filteredDistributions,
159 // return condensedDistribution;
163 public void setMapping(NamedArea area
, GeoServiceArea geoServiceArea
) {
164 areaMapping
.set(area
, geoServiceArea
);
168 public String
getDistributionServiceRequestParameterString(List
<TaxonDescription
> taxonDescriptions
,
169 boolean subAreaPreference
,
170 boolean statusOrderPreference
,
171 Set
<MarkerType
> hideMarkedAreas
,
172 Map
<UUID
, Color
> presenceAbsenceTermColors
,
173 List
<Language
> langs
,
174 boolean includeUnpublished
) {
176 Set
<Feature
> features
= new HashSet
<>();
177 features
.add(Feature
.DISTRIBUTION()); //for now only this one
178 Set
<Distribution
> distributions
= getDistributionsOf(taxonDescriptions
, features
, includeUnpublished
);
180 String uriParams
= getDistributionServiceRequestParameterString(distributions
,
182 statusOrderPreference
,
184 presenceAbsenceTermColors
,
190 private Set
<Distribution
> getDistributionsOf(List
<TaxonDescription
> taxonDescriptions
, Set
<Feature
> features
, boolean includeUnpublished
) {
191 Set
<Distribution
> result
= new HashSet
<>();
193 for (TaxonDescription taxonDescription
: taxonDescriptions
) {
194 List
<Distribution
> distributions
;
195 if (taxonDescription
.getId() > 0){
196 distributions
= dao
.getDescriptionElements(taxonDescription
,
197 null, features
, Distribution
.class, includeUnpublished
, null, null, null);
199 distributions
= new ArrayList
<>();
200 for (DescriptionElementBase deb
: taxonDescription
.getElements()){
201 if (deb
.isInstanceOf(Distribution
.class)){
202 if (features
== null || features
.isEmpty()
203 || features
.contains(deb
.getFeature())) {
204 distributions
.add(CdmBase
.deproxy(deb
, Distribution
.class));
209 result
.addAll(distributions
);
216 public String
getDistributionServiceRequestParameterString(
217 Set
<Distribution
> distributions
,
218 boolean preferSubareas
,
219 boolean statusOrderPreference
,
220 Set
<MarkerType
> fallbackAreaMarkerTypes
,
221 Map
<UUID
, Color
> presenceAbsenceTermColors
,
222 List
<Language
> langs
) {
224 TermTree
<NamedArea
> areaTree
= null;
225 TermTree
<PresenceAbsenceTerm
> statusTree
= null;
227 DistributionInfoConfiguration diConfig
= new DistributionInfoConfiguration();
228 diConfig
.setFallbackAreaMarkerTypes(fallbackAreaMarkerTypes
);
229 diConfig
.setStatusOrderPreference(statusOrderPreference
);
230 diConfig
.setPreferSubAreas(preferSubareas
);
231 diConfig
.setInfoParts(EnumSet
.of(InfoPart
.mapUriParams
));
232 DistributionInfoDto distInfo
= new DistributionInfoBuilder(langs
, commonService
)
233 .build(null, distributions
, areaTree
, statusTree
,
234 presenceAbsenceTermColors
, areaMapping
);
235 return distInfo
.getMapUriParams();
238 // TermTree<NamedArea> areaTree = null;
239 // TermTree<PresenceAbsenceTerm> statusTree = null;
240 // boolean keepFallbackOnlyIfNoSubareaDataExists = true;
241 // Collection<DistributionDto> filteredDistributions = DistributionServiceUtilities.filterDistributions(
242 // distributions, areaTree, statusTree,
243 // hideMarkedAreas, false, statusOrderPreference,
244 // subAreaPreference, keepFallbackOnlyIfNoSubareaDataExists);
246 // String uriParams = DistributionServiceUtilities.getDistributionServiceRequestParameterString(
247 // filteredDistributions,
249 // presenceAbsenceTermColors,
255 @Transactional(readOnly
=false)
256 public Map
<NamedArea
, String
> mapShapeFileToNamedAreas(Reader csvReader
,
257 List
<String
> idSearchFields
, String wmsLayerName
, UUID areaVocabularyUuid
,
258 Set
<UUID
> namedAreaUuids
) throws IOException
{
260 Set
<NamedArea
> areas
= new HashSet
<>();
262 if(areaVocabularyUuid
!= null){
263 @SuppressWarnings("unchecked")
264 TermVocabulary
<NamedArea
> areaVocabulary
= vocabDao
.load(areaVocabularyUuid
);
265 if(areaVocabulary
== null){
266 throw new EntityNotFoundException("No Vocabulary found for uuid " + areaVocabularyUuid
);
268 areas
.addAll(areaVocabulary
.getTerms());
270 if(namedAreaUuids
!= null && !namedAreaUuids
.isEmpty()){
271 for(DefinedTermBase
<?
> dtb
: termDao
.list(namedAreaUuids
, null, null, null, null)){
272 areas
.add((NamedArea
)CdmBase
.deproxy(dtb
));
276 ShpAttributesToNamedAreaMapper mapper
= new ShpAttributesToNamedAreaMapper(areas
, areaMapping
);
277 Map
<NamedArea
, String
> resultMap
= mapper
.readCsv(csvReader
, idSearchFields
, wmsLayerName
);
278 termDao
.saveOrUpdateAll((Collection
)areas
);