Project

General

Profile

Download (16.2 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.Collections;
18
import java.util.EnumSet;
19
import java.util.HashSet;
20
import java.util.List;
21
import java.util.Map;
22
import java.util.Set;
23
import java.util.UUID;
24

    
25
import javax.persistence.EntityNotFoundException;
26

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

    
33
import de.micromata.opengis.kml.v_2_2_0.Kml;
34
import eu.etaxonomy.cdm.api.service.dto.CondensedDistribution;
35
import eu.etaxonomy.cdm.api.service.dto.DistributionInfoDTO;
36
import eu.etaxonomy.cdm.api.service.dto.DistributionInfoDTO.InfoPart;
37
import eu.etaxonomy.cdm.api.util.DescriptionUtility;
38
import eu.etaxonomy.cdm.api.util.DistributionOrder;
39
import eu.etaxonomy.cdm.api.util.DistributionTree;
40
import eu.etaxonomy.cdm.ext.geo.kml.KMLDocumentBuilder;
41
import eu.etaxonomy.cdm.model.common.CdmBase;
42
import eu.etaxonomy.cdm.model.common.Language;
43
import eu.etaxonomy.cdm.model.common.MarkerType;
44
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
45
import eu.etaxonomy.cdm.model.description.Distribution;
46
import eu.etaxonomy.cdm.model.description.Feature;
47
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
48
import eu.etaxonomy.cdm.model.description.TaxonDescription;
49
import eu.etaxonomy.cdm.model.location.NamedArea;
50
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
51
import eu.etaxonomy.cdm.model.location.Point;
52
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
53
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
54
import eu.etaxonomy.cdm.model.occurrence.GatheringEvent;
55
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
56
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
57
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
58
import eu.etaxonomy.cdm.model.term.TermVocabulary;
59
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
60
import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
61
import eu.etaxonomy.cdm.persistence.dao.term.IDefinedTermDao;
62
import eu.etaxonomy.cdm.persistence.dao.term.ITermVocabularyDao;
63

    
64
/**
65
 * @author a.kohlbecker
66
 * @since 18.06.2009
67
 */
68
@Service
69
@Transactional(readOnly = true)
70
public class EditGeoService implements IEditGeoService {
71

    
72
    @SuppressWarnings("unused")
73
    private static final Logger logger = LogManager.getLogger(EditGeoService.class);
74

    
75
    @Autowired
76
    private IDescriptionDao dao;
77

    
78
    @Autowired
79
    private IGeoServiceAreaMapping areaMapping;
80

    
81
    @Autowired
82
    private ITermVocabularyDao vocabDao;
83

    
84
    @Autowired
85
    private IDefinedTermDao termDao;
86

    
87
    @Autowired
88
    private IOccurrenceDao occurrenceDao;
89

    
90
    private Set<Feature> getDistributionFeatures() {
91
        Set<Feature> distributionFeature = new HashSet<>();
92
        Feature feature = (Feature) termDao.findByUuid(Feature.DISTRIBUTION().getUuid());
93
        distributionFeature.add(feature);
94
        return distributionFeature;
95
    }
96

    
97
    private Set<Distribution> getDistributionsOf(List<TaxonDescription> taxonDescriptions) {
98
        Set<Distribution> result = new HashSet<>();
99

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

    
128
    @Override
129
    public String getDistributionServiceRequestParameterString(List<TaxonDescription> taxonDescriptions,
130
            boolean subAreaPreference,
131
            boolean statusOrderPreference,
132
            Set<MarkerType> hideMarkedAreas,
133
            Map<PresenceAbsenceTerm, Color> presenceAbsenceTermColors,
134
            List<Language> langs) {
135

    
136
        Set<Distribution> distributions = getDistributionsOf(taxonDescriptions);
137

    
138
        String uriParams = getDistributionServiceRequestParameterString(distributions,
139
                subAreaPreference,
140
                statusOrderPreference,
141
                hideMarkedAreas,
142
                presenceAbsenceTermColors,
143
                langs);
144

    
145
        return uriParams;
146
    }
147

    
148
    @Override
149
    public String getDistributionServiceRequestParameterString(
150
            Set<Distribution> distributions,
151
            boolean subAreaPreference,
152
            boolean statusOrderPreference,
153
            Set<MarkerType> hideMarkedAreas,
154
            Map<PresenceAbsenceTerm, Color> presenceAbsenceTermColors,
155
            List<Language> langs) {
156

    
157
        Collection<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(distributions,
158
                hideMarkedAreas, false, statusOrderPreference, subAreaPreference, true, false);
159

    
160
        String uriParams = EditGeoServiceUtilities.getDistributionServiceRequestParameterString(
161
                filteredDistributions,
162
                areaMapping,
163
                presenceAbsenceTermColors,
164
                null, langs);
165
        return uriParams;
166
    }
167

    
168
    @Override
169
    public OccurrenceServiceRequestParameterDto getOccurrenceServiceRequestParameters(
170
            List<SpecimenOrObservationBase> specimensOrObservations,
171
            Map<SpecimenOrObservationType, Color> specimenOrObservationTypeColors) {
172

    
173
        List<Point> fieldUnitPoints = new ArrayList<>();
174
        List<Point> derivedUnitPoints = new ArrayList<>();
175

    
176
        for (SpecimenOrObservationBase<?> specimenOrObservationBase : specimensOrObservations) {
177
            SpecimenOrObservationBase<?> specimensOrObservation = occurrenceDao
178
                    .load(specimenOrObservationBase.getUuid());
179

    
180
            if (specimensOrObservation instanceof FieldUnit) {
181
                GatheringEvent gatherEvent = ((FieldUnit) specimensOrObservation).getGatheringEvent();
182
                if (gatherEvent != null && gatherEvent.getExactLocation() != null){
183
                    fieldUnitPoints.add(gatherEvent.getExactLocation());
184
                }
185
            }
186
            if (specimensOrObservation instanceof DerivedUnit) {
187
                registerDerivedUnitLocations((DerivedUnit) specimensOrObservation, derivedUnitPoints);
188
            }
189
        }
190

    
191
        return EditGeoServiceUtilities.getOccurrenceServiceRequestParameterString(fieldUnitPoints,
192
                derivedUnitPoints, specimenOrObservationTypeColors);
193
    }
194

    
195
    @Override
196
    public Kml occurrencesToKML(
197
            @SuppressWarnings("rawtypes") List<SpecimenOrObservationBase> specimensOrObservations,
198
            Map<SpecimenOrObservationType, Color> specimenOrObservationTypeColors) {
199

    
200
    		KMLDocumentBuilder builder = new KMLDocumentBuilder();
201

    
202
    		for (SpecimenOrObservationBase<?> specimenOrObservationBase : specimensOrObservations) {
203
    			builder.addSpecimenOrObservationBase(occurrenceDao.load(specimenOrObservationBase.getUuid()));
204
    		}
205

    
206
    		Kml kml = builder.build();
207

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

    
222
    @Override
223
    public CondensedDistribution getCondensedDistribution(Set<Distribution> distributions,
224
            boolean statusOrderPreference,
225
            Set<MarkerType> hiddenAreaMarkerTypes,
226
            CondensedDistributionConfiguration config,
227
            List<Language> langs) {
228

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

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

    
240
        @SuppressWarnings("rawtypes")
241
        Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals();
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
    @Override
268
    public void setMapping(NamedArea area, GeoServiceArea geoServiceArea) {
269
        areaMapping.set(area, geoServiceArea);
270
    }
271

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

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

    
280
        if(areaVocabularyUuid != null){
281
            @SuppressWarnings("unchecked")
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
            boolean neverUseFallbackAreaAsParent, Set<NamedAreaLevel> omitLevels,
304
            Map<PresenceAbsenceTerm, Color> presenceAbsenceTermColors,
305
            List<Language> languages,  List<String> propertyPaths, CondensedDistributionConfiguration config,
306
            DistributionOrder distributionOrder, boolean ignoreDistributionStatusUndefined){
307

    
308
        final boolean PREFER_AGGREGATED = true;
309
        final boolean PREFER_SUBAREA = true;
310

    
311
        DistributionInfoDTO dto = new DistributionInfoDTO();
312

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

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

    
342
        // for all later applications apply the rules statusOrderPreference, hideHiddenArea and ignoreUndefinedStatus
343
        // to all distributions, but KEEP fallback area distributions
344
        Set<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(distributions, hiddenAreaMarkerTypes,
345
                !PREFER_AGGREGATED, statusOrderPreference, !PREFER_SUBAREA, false, ignoreDistributionStatusUndefined);
346

    
347
        if(parts.contains(InfoPart.elements)) {
348
            dto.setElements(filteredDistributions);
349
        }
350

    
351
        if(parts.contains(InfoPart.tree)) {
352
            DistributionTree tree = DescriptionUtility.buildOrderedTree(omitLevels,
353
                    filteredDistributions, hiddenAreaMarkerTypes, neverUseFallbackAreaAsParent,
354
                    distributionOrder, termDao);
355
            dto.setTree(tree);
356
        }
357

    
358
        if(parts.contains(InfoPart.condensedDistribution)) {
359
            CondensedDistribution condensedDistribution = EditGeoServiceUtilities.getCondensedDistribution(
360
                    filteredDistributions, config, languages);
361
            dto.setCondensedDistribution(condensedDistribution);
362
        }
363

    
364
        if (parts.contains(InfoPart.mapUriParams)) {
365
            boolean IGNORE_STATUS_ORDER_PREF_ = false;
366
            Set<MarkerType> hiddenAreaMarkerType = null;
367
            // only apply the subAreaPreference rule for the maps
368
            Set<Distribution> filteredMapDistributions = DescriptionUtility.filterDistributions(
369
                    filteredDistributions, hiddenAreaMarkerType, !PREFER_AGGREGATED,
370
                    IGNORE_STATUS_ORDER_PREF_, subAreaPreference, true, ignoreDistributionStatusUndefined);
371

    
372
            dto.setMapUriParams(EditGeoServiceUtilities.getDistributionServiceRequestParameterString(filteredMapDistributions,
373
                    areaMapping,
374
                    presenceAbsenceTermColors,
375
                    null, languages));
376
        }
377

    
378
        return dto;
379
    }
380
}
(4-4/11)