Project

General

Profile

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

    
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;
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.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.CdmBase;
37
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
38
import eu.etaxonomy.cdm.model.common.Language;
39
import eu.etaxonomy.cdm.model.common.MarkerType;
40
import eu.etaxonomy.cdm.model.common.TermVocabulary;
41
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
42
import eu.etaxonomy.cdm.model.description.Distribution;
43
import eu.etaxonomy.cdm.model.description.Feature;
44
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
45
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
46
import eu.etaxonomy.cdm.model.description.TaxonDescription;
47
import eu.etaxonomy.cdm.model.location.NamedArea;
48
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
49
import eu.etaxonomy.cdm.model.location.Point;
50
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
51
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
52
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
53
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
54
import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
55
import eu.etaxonomy.cdm.persistence.dao.common.ITermVocabularyDao;
56
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
57
import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
58

    
59
/**
60
 * @author a.kohlbecker
61
 * @date 18.06.2009
62
 *
63
 */
64
@Service
65
@Transactional(readOnly = true)
66
public class EditGeoService implements IEditGeoService {
67
    public static final Logger logger = Logger.getLogger(EditGeoService.class);
68

    
69
    @Autowired
70
    private IDescriptionDao dao;
71

    
72
    @Autowired
73
    private IGeoServiceAreaMapping areaMapping;
74

    
75
    @Autowired
76
    private IDescriptionService descriptionService;
77

    
78
    @Autowired
79
    private ITermVocabularyDao vocabDao;
80

    
81
    private IDefinedTermDao termDao;
82
    @Autowired
83
    public void setTermDao(IDefinedTermDao termDao) {
84
        this.termDao = termDao;
85
        EditGeoServiceUtilities.setTermDao(termDao);
86
    }
87

    
88
    @Autowired
89
    private IOccurrenceDao occurrenceDao;
90

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

    
98
    /**
99
     * @param taxonDescriptions
100
     * @return
101
     */
102
    private Set<Distribution> getDistributionsOf(List<TaxonDescription> taxonDescriptions) {
103
        Set<Distribution> result = new HashSet<Distribution>();
104

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

    
133
    /**
134
     * {@inheritDoc}
135
     */
136
    @Override
137
    public String getDistributionServiceRequestParameterString(List<TaxonDescription> taxonDescriptions,
138
            boolean subAreaPreference,
139
            boolean statusOrderPreference,
140
            Set<MarkerType> hideMarkedAreas,
141
            Map<PresenceAbsenceTerm, Color> presenceAbsenceTermColors,
142
            List<Language> langs) {
143

    
144
        Set<Distribution> distributions = getDistributionsOf(taxonDescriptions);
145

    
146
        String uriParams = getDistributionServiceRequestParameterString(distributions,
147
                subAreaPreference,
148
                statusOrderPreference,
149
                hideMarkedAreas,
150
                presenceAbsenceTermColors,
151
                langs);
152

    
153
        return uriParams;
154
    }
155

    
156
    /**
157
     * {@inheritDoc}
158
     */
159
    @Override
160
    public String getDistributionServiceRequestParameterString(
161
            Set<Distribution> distributions,
162
            boolean subAreaPreference,
163
            boolean statusOrderPreference,
164
            Set<MarkerType> hideMarkedAreas,
165
            Map<PresenceAbsenceTerm, Color> presenceAbsenceTermColors,
166
            List<Language> langs) {
167

    
168
        Collection<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(distributions,
169
                hideMarkedAreas, true, statusOrderPreference, subAreaPreference);
170

    
171

    
172
        String uriParams = EditGeoServiceUtilities.getDistributionServiceRequestParameterString(
173
                filteredDistributions,
174
                areaMapping,
175
                presenceAbsenceTermColors,
176
                null, langs);
177
        return uriParams;
178
    }
179

    
180
    /**
181
     * {@inheritDoc}
182
     */
183
    @Override
184
    @Deprecated
185
    public String getDistributionServiceRequestParameterString(TaxonDescription taxonDescription,
186
            boolean subAreaPreference,
187
            boolean statusOrderPreference,
188
            Set<MarkerType> hideMarkedAreas,
189
            Map<PresenceAbsenceTerm, Color> presenceAbsenceTermColors,
190
            List<Language> langs) {
191

    
192
        List<TaxonDescription> taxonDescriptions = new ArrayList<TaxonDescription>();
193
        taxonDescriptions.add(taxonDescription);
194

    
195
        return getDistributionServiceRequestParameterString(taxonDescriptions,
196
                subAreaPreference,
197
                statusOrderPreference,
198
                hideMarkedAreas,
199
                presenceAbsenceTermColors,
200
                langs);
201
    }
202

    
203
    /**
204
     * {@inheritDoc}
205
     */
206
    @Override
207
    public OccurrenceServiceRequestParameterDto getOccurrenceServiceRequestParameterString(List<SpecimenOrObservationBase> specimensOrObersvations,
208
            Map<SpecimenOrObservationType, Color> specimenOrObservationTypeColors) {
209

    
210
        List<Point> fieldUnitPoints = new ArrayList<Point>();
211
        List<Point> derivedUnitPoints = new ArrayList<Point>();
212

    
213
        IndividualsAssociation individualsAssociation;
214
        DerivedUnit derivedUnit;
215

    
216
        for (SpecimenOrObservationBase specimenOrObservationBase : specimensOrObersvations) {
217
            SpecimenOrObservationBase<?> specimenOrObservation = occurrenceDao
218
                    .load(specimenOrObservationBase.getUuid());
219

    
220
            if (specimenOrObservation instanceof FieldUnit) {
221
                fieldUnitPoints.add(((FieldUnit) specimenOrObservation).getGatheringEvent()
222
                        .getExactLocation());
223
            }
224
            if (specimenOrObservation instanceof DerivedUnit) {
225
                registerDerivedUnitLocations((DerivedUnit) specimenOrObservation, derivedUnitPoints);
226
            }
227
        }
228

    
229
        return EditGeoServiceUtilities.getOccurrenceServiceRequestParameterString(fieldUnitPoints,
230
                derivedUnitPoints, specimenOrObservationTypeColors);
231

    
232
    }
233

    
234
    public CondensedDistribution getCondensedDistribution(List<TaxonDescription> taxonDescriptions,
235
            boolean statusOrderPreference,
236
            Set<MarkerType> hideMarkedAreas,
237
            MarkerType fallbackAreaMarkerType,
238
            CondensedDistributionRecipe recipe,
239
            List<Language> langs) {
240
        Set<Distribution> distributions = getDistributionsOf(taxonDescriptions);
241
        return getCondensedDistribution(distributions, statusOrderPreference,
242
                hideMarkedAreas, fallbackAreaMarkerType, recipe, langs);
243
    }
244

    
245
    public CondensedDistribution getCondensedDistribution(Set<Distribution> distributions,
246
            boolean statusOrderPreference,
247
            Set<MarkerType> hideMarkedAreas,
248
            MarkerType fallbackAreaMarkerType,
249
            CondensedDistributionRecipe recipe,
250
            List<Language> langs) {
251

    
252
        Collection<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(
253
                distributions, hideMarkedAreas, true, statusOrderPreference, false);
254

    
255

    
256

    
257
        CondensedDistribution condensedDistribution = EditGeoServiceUtilities.getCondensedDistribution(
258
                filteredDistributions,
259
                recipe,
260
                langs);
261

    
262
        return condensedDistribution;
263
    }
264

    
265
    /**
266
     * @param derivedUnit
267
     * @param derivedUnitPoints
268
     */
269
    private void registerDerivedUnitLocations(DerivedUnit derivedUnit, List<Point> derivedUnitPoints) {
270

    
271
        Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals();
272
        if (originals != null) {
273
            for (SpecimenOrObservationBase original : originals) {
274
                if (original instanceof FieldUnit) {
275
                    if (((FieldUnit) original).getGatheringEvent() != null) {
276
                        Point point = ((FieldUnit) original).getGatheringEvent().getExactLocation();
277
                        if (point != null) {
278
                            // points with no longitude or latitude should not exist
279
                            // see  #4173 ([Rule] Longitude and Latitude in Point must not be null)
280
                            if (point.getLatitude() == null || point.getLongitude() == null){
281
                                continue;
282
                            }
283
                            // FIXME: remove next statement after
284
                            // DerivedUnitFacade or ABCD import is fixed
285
                            //
286
                            if(point.getLatitude() == 0.0 || point.getLongitude() == 0.0) {
287
                                continue;
288
                            }
289
                            derivedUnitPoints.add(point);
290
                        }
291
                    }
292
                } else {
293
                    registerDerivedUnitLocations((DerivedUnit) original, derivedUnitPoints);
294
                }
295
            }
296
        }
297

    
298
    }
299

    
300

    
301
    /**
302
     * {@inheritDoc}
303
     */
304
    @Override
305
    public void setMapping(NamedArea area, GeoServiceArea geoServiceArea) {
306
        areaMapping.set(area, geoServiceArea);
307

    
308
    }
309

    
310
    /**
311
     * {@inheritDoc}
312
     */
313
    @Override
314
    @Transactional(readOnly=false)
315
    public Map<NamedArea, String> mapShapeFileToNamedAreas(Reader csvReader,
316
            List<String> idSearchFields, String wmsLayerName, UUID areaVocabularyUuid,
317
            Set<UUID> namedAreaUuids) throws IOException {
318

    
319
        Set<NamedArea> areas = new HashSet<NamedArea>();
320

    
321
        if(areaVocabularyUuid != null){
322
            TermVocabulary<NamedArea> areaVocabulary = vocabDao.load(areaVocabularyUuid);
323
            if(areaVocabulary == null){
324
                throw new EntityNotFoundException("No Vocabulary found for uuid " + areaVocabularyUuid);
325
            }
326
            areas.addAll(areaVocabulary.getTerms());
327
        }
328
        if(namedAreaUuids != null && !namedAreaUuids.isEmpty()){
329
            for(DefinedTermBase dtb : termDao.list(namedAreaUuids, null, null, null, null)){
330
                areas.add((NamedArea)dtb);
331
            }
332
        }
333

    
334
        ShpAttributesToNamedAreaMapper mapper = new ShpAttributesToNamedAreaMapper(areas, areaMapping);
335
        Map<NamedArea, String> resultMap = mapper.readCsv(csvReader, idSearchFields, wmsLayerName);
336
        termDao.saveOrUpdateAll((Collection)areas);
337
        return resultMap;
338
    }
339

    
340
    /**
341
     * {@inheritDoc}
342
     */
343
    @Override
344
    public DistributionInfoDTO composeDistributionInfoFor(EnumSet<DistributionInfoDTO.InfoPart> parts, UUID taxonUUID,
345
            boolean subAreaPreference, boolean statusOrderPreference, Set<MarkerType> hiddenAreaMarkerTypes,
346
            Set<NamedAreaLevel> omitLevels, Map<PresenceAbsenceTerm, Color> presenceAbsenceTermColors,
347
            List<Language> languages,  List<String> propertyPaths, CondensedDistributionRecipe recipe){
348

    
349
        DistributionInfoDTO dto = new DistributionInfoDTO();
350

    
351
        // Adding default initStrategies to improve the performance of this method
352
        // adding 'status' and 'area' has a good positive effect:
353
        // filterDistributions() only takes 21% of the total method time (before it was 46%)
354
        // at the same time the cost of the getDescriptionElementForTaxon is not increased at all!
355
        //
356
        // adding 'markers.markerType' is not improving the performance since it only
357
        // moved the load from the filter method to the getDescriptionElementForTaxon()
358
        // method.
359
        // overall improvement by this means is by 42% (from 77,711 ms to 44,868 ms)
360
        ArrayList<String> initStrategy = new ArrayList<String>(propertyPaths);
361
        if(!initStrategy.contains("status")) {
362
            initStrategy.add("status");
363
        }
364
        if(!initStrategy.contains("area")) {
365
            initStrategy.add("area");
366
        }
367
        if(!initStrategy.contains("markers.markerType")) {
368
            initStrategy.add("markers.markerType");
369
        }
370
        if(omitLevels == null) {
371
            omitLevels = new HashSet<NamedAreaLevel>(0);
372
        }
373

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

    
376
        // Apply the rules statusOrderPreference and hideMarkedAreas for textual distribution info
377
        Set<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(distributions, hiddenAreaMarkerTypes,
378
                true, statusOrderPreference, false);
379

    
380
        if(parts.contains(InfoPart.elements)) {
381
            dto.setElements(filteredDistributions);
382
        }
383

    
384
        if(parts.contains(InfoPart.tree)) {
385
            dto.setTree(DescriptionUtility.orderDistributions(termDao, omitLevels, filteredDistributions, hiddenAreaMarkerTypes));
386
        }
387

    
388
        if(parts.contains(InfoPart.condensedDistribution)) {
389
            dto.setCondensedDistribution(EditGeoServiceUtilities.getCondensedDistribution(filteredDistributions, recipe, languages));
390
        }
391

    
392
        if (parts.contains(InfoPart.mapUriParams)) {
393
            // only apply the subAreaPreference rule for the maps
394
            Set<Distribution> filteredMapDistributions = DescriptionUtility.filterDistributions(filteredDistributions, null, false, false, subAreaPreference);
395

    
396
            dto.setMapUriParams(EditGeoServiceUtilities.getDistributionServiceRequestParameterString(filteredMapDistributions,
397
                    areaMapping,
398
                    presenceAbsenceTermColors,
399
                    null, languages));
400
        }
401

    
402
        return dto;
403
    }
404
}
(2-2/11)