Project

General

Profile

Download (15.4 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2009 EDIT
3
 * European Distributed Institute of Taxonomy
4
 * http://www.e-taxonomy.eu
5
 *
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.
8
 */
9
package eu.etaxonomy.cdm.ext.geo;
10

    
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;
20
import java.util.Map;
21
import java.util.Set;
22
import java.util.UUID;
23

    
24
import javax.persistence.EntityNotFoundException;
25

    
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;
30

    
31
import eu.etaxonomy.cdm.api.service.DistributionTree;
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.api.utility.DistributionOrder;
37
import eu.etaxonomy.cdm.model.common.CdmBase;
38
import eu.etaxonomy.cdm.model.common.Language;
39
import eu.etaxonomy.cdm.model.common.MarkerType;
40
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
41
import eu.etaxonomy.cdm.model.description.Distribution;
42
import eu.etaxonomy.cdm.model.description.Feature;
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.GatheringEvent;
51
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
52
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
53
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
54
import eu.etaxonomy.cdm.model.term.TermVocabulary;
55
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
56
import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
57
import eu.etaxonomy.cdm.persistence.dao.term.IDefinedTermDao;
58
import eu.etaxonomy.cdm.persistence.dao.term.ITermVocabularyDao;
59

    
60
/**
61
 * @author a.kohlbecker
62
 * @since 18.06.2009
63
 */
64
@Service
65
@Transactional(readOnly = true)
66
public class EditGeoService implements IEditGeoService {
67

    
68
    public static final Logger logger = Logger.getLogger(EditGeoService.class);
69

    
70
    @Autowired
71
    private IDescriptionDao dao;
72

    
73
    @Autowired
74
    private IGeoServiceAreaMapping areaMapping;
75

    
76
    @Autowired
77
    private ITermVocabularyDao vocabDao;
78

    
79
    @Autowired
80
    private IDefinedTermDao termDao;
81

    
82
    @Autowired
83
    private IOccurrenceDao occurrenceDao;
84

    
85
    private Set<Feature> getDistributionFeatures() {
86
        Set<Feature> distributionFeature = new HashSet<>();
87
        Feature feature = (Feature) termDao.findByUuid(Feature.DISTRIBUTION().getUuid());
88
        distributionFeature.add(feature);
89
        return distributionFeature;
90
    }
91

    
92
    private Set<Distribution> getDistributionsOf(List<TaxonDescription> taxonDescriptions) {
93
        Set<Distribution> result = new HashSet<>();
94

    
95
        Set<Feature> features = getDistributionFeatures();
96
        for (TaxonDescription taxonDescription : taxonDescriptions) {
97
            List<Distribution> distributions;
98
            if (taxonDescription.getId() > 0){
99
                distributions = dao.getDescriptionElements(
100
                        taxonDescription,
101
                        null,
102
                        null /*features*/,
103
                        Distribution.class,
104
                        null,
105
                        null,
106
                        null);
107
            }else{
108
                distributions = new ArrayList<Distribution>();
109
                for (DescriptionElementBase deb : taxonDescription.getElements()){
110
                    if (deb.isInstanceOf(Distribution.class)){
111
                        if (features == null || features.isEmpty()
112
                                || features.contains(deb.getFeature())) {
113
                            distributions.add(CdmBase.deproxy(deb, Distribution.class));
114
                        }
115
                    }
116
                }
117
            }
118
            result.addAll(distributions);
119
        }
120
        return result;
121
    }
122

    
123
    @Override
124
    public String getDistributionServiceRequestParameterString(List<TaxonDescription> taxonDescriptions,
125
            boolean subAreaPreference,
126
            boolean statusOrderPreference,
127
            Set<MarkerType> hideMarkedAreas,
128
            Map<PresenceAbsenceTerm, Color> presenceAbsenceTermColors,
129
            List<Language> langs) {
130

    
131
        Set<Distribution> distributions = getDistributionsOf(taxonDescriptions);
132

    
133
        String uriParams = getDistributionServiceRequestParameterString(distributions,
134
                subAreaPreference,
135
                statusOrderPreference,
136
                hideMarkedAreas,
137
                presenceAbsenceTermColors,
138
                langs);
139

    
140
        return uriParams;
141
    }
142

    
143
    @Override
144
    public String getDistributionServiceRequestParameterString(
145
            Set<Distribution> distributions,
146
            boolean subAreaPreference,
147
            boolean statusOrderPreference,
148
            Set<MarkerType> hideMarkedAreas,
149
            Map<PresenceAbsenceTerm, Color> presenceAbsenceTermColors,
150
            List<Language> langs) {
151

    
152
        Collection<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(distributions,
153
                hideMarkedAreas, true, statusOrderPreference, subAreaPreference);
154

    
155
        String uriParams = EditGeoServiceUtilities.getDistributionServiceRequestParameterString(
156
                filteredDistributions,
157
                areaMapping,
158
                presenceAbsenceTermColors,
159
                null, langs);
160
        return uriParams;
161
    }
162

    
163
    @Override
164
    @Deprecated
165
    public String getDistributionServiceRequestParameterString(TaxonDescription taxonDescription,
166
            boolean subAreaPreference,
167
            boolean statusOrderPreference,
168
            Set<MarkerType> hideMarkedAreas,
169
            Map<PresenceAbsenceTerm, Color> presenceAbsenceTermColors,
170
            List<Language> langs) {
171

    
172
        List<TaxonDescription> taxonDescriptions = new ArrayList<>();
173
        taxonDescriptions.add(taxonDescription);
174

    
175
        return getDistributionServiceRequestParameterString(taxonDescriptions,
176
                subAreaPreference,
177
                statusOrderPreference,
178
                hideMarkedAreas,
179
                presenceAbsenceTermColors,
180
                langs);
181
    }
182

    
183
    @Override
184
    public OccurrenceServiceRequestParameterDto getOccurrenceServiceRequestParameterString(
185
            List<SpecimenOrObservationBase> specimensOrObersvations,
186
            Map<SpecimenOrObservationType, Color> specimenOrObservationTypeColors) {
187

    
188
        List<Point> fieldUnitPoints = new ArrayList<>();
189
        List<Point> derivedUnitPoints = new ArrayList<>();
190

    
191
        for (SpecimenOrObservationBase<?> specimenOrObservationBase : specimensOrObersvations) {
192
            SpecimenOrObservationBase<?> specimenOrObservation = occurrenceDao
193
                    .load(specimenOrObservationBase.getUuid());
194

    
195
            if (specimenOrObservation instanceof FieldUnit) {
196
                GatheringEvent gatherEvent = ((FieldUnit) specimenOrObservation).getGatheringEvent();
197
                if (gatherEvent != null && gatherEvent.getExactLocation() != null){
198
                    fieldUnitPoints.add(gatherEvent.getExactLocation());
199
                }
200
            }
201
            if (specimenOrObservation instanceof DerivedUnit) {
202
                registerDerivedUnitLocations((DerivedUnit) specimenOrObservation, derivedUnitPoints);
203
            }
204
        }
205

    
206
        return EditGeoServiceUtilities.getOccurrenceServiceRequestParameterString(fieldUnitPoints,
207
                derivedUnitPoints, specimenOrObservationTypeColors);
208
    }
209

    
210
    public CondensedDistribution getCondensedDistribution(List<TaxonDescription> taxonDescriptions,
211
            boolean statusOrderPreference,
212
            Set<MarkerType> hideMarkedAreas,
213
            MarkerType fallbackAreaMarkerType,
214
            CondensedDistributionRecipe recipe,
215
            List<Language> langs) {
216
        Set<Distribution> distributions = getDistributionsOf(taxonDescriptions);
217
        return getCondensedDistribution(distributions, statusOrderPreference,
218
                hideMarkedAreas, fallbackAreaMarkerType, recipe, langs);
219
    }
220

    
221
    @Override
222
    public CondensedDistribution getCondensedDistribution(Set<Distribution> distributions,
223
            boolean statusOrderPreference,
224
            Set<MarkerType> hideMarkedAreas,
225
            MarkerType fallbackAreaMarkerType,
226
            CondensedDistributionRecipe recipe,
227
            List<Language> langs) {
228

    
229
        Collection<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(
230
                distributions, hideMarkedAreas, true, statusOrderPreference, false);
231
        CondensedDistribution condensedDistribution = EditGeoServiceUtilities.getCondensedDistribution(
232
                filteredDistributions,
233
                recipe,
234
                langs);
235
        return condensedDistribution;
236
    }
237

    
238
    private void registerDerivedUnitLocations(DerivedUnit derivedUnit, List<Point> derivedUnitPoints) {
239

    
240
        Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals();
241
        if (originals != null) {
242
            for (SpecimenOrObservationBase<?> original : originals) {
243
                if (original instanceof FieldUnit) {
244
                    if (((FieldUnit) original).getGatheringEvent() != null) {
245
                        Point point = ((FieldUnit) original).getGatheringEvent().getExactLocation();
246
                        if (point != null) {
247
                            // points with no longitude or latitude should not exist
248
                            // see  #4173 ([Rule] Longitude and Latitude in Point must not be null)
249
                            if (point.getLatitude() == null || point.getLongitude() == null){
250
                                continue;
251
                            }
252
                            // FIXME: remove next statement after
253
                            // DerivedUnitFacade or ABCD import is fixed
254
                            //
255
                            if(point.getLatitude() == 0.0 || point.getLongitude() == 0.0) {
256
                                continue;
257
                            }
258
                            derivedUnitPoints.add(point);
259
                        }
260
                    }
261
                } else {
262
                    registerDerivedUnitLocations((DerivedUnit) original, derivedUnitPoints);
263
                }
264
            }
265
        }
266
    }
267

    
268
    @Override
269
    public void setMapping(NamedArea area, GeoServiceArea geoServiceArea) {
270
        areaMapping.set(area, geoServiceArea);
271
    }
272

    
273
    @Override
274
    @Transactional(readOnly=false)
275
    public Map<NamedArea, String> mapShapeFileToNamedAreas(Reader csvReader,
276
            List<String> idSearchFields, String wmsLayerName, UUID areaVocabularyUuid,
277
            Set<UUID> namedAreaUuids) throws IOException {
278

    
279
        Set<NamedArea> areas = new HashSet<>();
280

    
281
        if(areaVocabularyUuid != null){
282
            TermVocabulary<NamedArea> areaVocabulary = vocabDao.load(areaVocabularyUuid);
283
            if(areaVocabulary == null){
284
                throw new EntityNotFoundException("No Vocabulary found for uuid " + areaVocabularyUuid);
285
            }
286
            areas.addAll(areaVocabulary.getTerms());
287
        }
288
        if(namedAreaUuids != null && !namedAreaUuids.isEmpty()){
289
            for(DefinedTermBase<?> dtb : termDao.list(namedAreaUuids, null, null, null, null)){
290
                areas.add((NamedArea)CdmBase.deproxy(dtb));
291
            }
292
        }
293

    
294
        ShpAttributesToNamedAreaMapper mapper = new ShpAttributesToNamedAreaMapper(areas, areaMapping);
295
        Map<NamedArea, String> resultMap = mapper.readCsv(csvReader, idSearchFields, wmsLayerName);
296
        termDao.saveOrUpdateAll((Collection)areas);
297
        return resultMap;
298
    }
299

    
300
    @Override
301
    public DistributionInfoDTO composeDistributionInfoFor(EnumSet<DistributionInfoDTO.InfoPart> parts, UUID taxonUUID,
302
            boolean subAreaPreference, boolean statusOrderPreference, Set<MarkerType> hiddenAreaMarkerTypes,
303
            Set<NamedAreaLevel> omitLevels, Map<PresenceAbsenceTerm, Color> presenceAbsenceTermColors,
304
            List<Language> languages,  List<String> propertyPaths, CondensedDistributionRecipe recipe,
305
            DistributionOrder distributionOrder){
306

    
307
        DistributionInfoDTO dto = new DistributionInfoDTO();
308

    
309
        if (propertyPaths == null){
310
            propertyPaths = Arrays.asList(new String []{});
311
        }
312
        // Adding default initStrategies to improve the performance of this method
313
        // adding 'status' and 'area' has a good positive effect:
314
        // filterDistributions() only takes 21% of the total method time (before it was 46%)
315
        // at the same time the cost of the getDescriptionElementForTaxon is not increased at all!
316
        //
317
        // adding 'markers.markerType' is not improving the performance since it only
318
        // moved the load from the filter method to the getDescriptionElementForTaxon()
319
        // method.
320
        // overall improvement by this means is by 42% (from 77,711 ms to 44,868 ms)
321
        ArrayList<String> initStrategy = new ArrayList<>(propertyPaths);
322
        if(!initStrategy.contains("status")) {
323
            initStrategy.add("status");
324
        }
325
        if(!initStrategy.contains("area")) {
326
            initStrategy.add("area");
327
        }
328
        if(!initStrategy.contains("markers.markerType")) {
329
            initStrategy.add("markers.markerType");
330
        }
331
        if(omitLevels == null) {
332
            omitLevels = new HashSet<>(0);
333
        }
334

    
335
        List<Distribution> distributions = dao.getDescriptionElementForTaxon(taxonUUID, null, Distribution.class, null, null, initStrategy);
336

    
337
        // Apply the rules statusOrderPreference and hideMarkedAreas for textual distribution info
338
        Set<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(distributions, hiddenAreaMarkerTypes,
339
                true, statusOrderPreference, false);
340

    
341
        if(parts.contains(InfoPart.elements)) {
342
            dto.setElements(filteredDistributions);
343
        }
344

    
345
        if(parts.contains(InfoPart.tree)) {
346
            DistributionTree tree = DescriptionUtility.orderDistributions(termDao, omitLevels,
347
                    filteredDistributions, hiddenAreaMarkerTypes,distributionOrder);
348
            dto.setTree(tree);
349
        }
350

    
351
        if(parts.contains(InfoPart.condensedDistribution)) {
352
            dto.setCondensedDistribution(EditGeoServiceUtilities.getCondensedDistribution(
353
                    filteredDistributions, recipe, languages));
354
        }
355

    
356
        if (parts.contains(InfoPart.mapUriParams)) {
357
            // only apply the subAreaPreference rule for the maps
358
            Set<Distribution> filteredMapDistributions = DescriptionUtility.filterDistributions(
359
                    filteredDistributions, null, false, false, subAreaPreference);
360

    
361
            dto.setMapUriParams(EditGeoServiceUtilities.getDistributionServiceRequestParameterString(filteredMapDistributions,
362
                    areaMapping,
363
                    presenceAbsenceTermColors,
364
                    null, languages));
365
        }
366

    
367
        return dto;
368
    }
369
}
(3-3/14)