Project

General

Profile

Download (85.5 KB) Statistics
| Branch: | Tag: | Revision:
1 887126ca Andreas Müller
/**
2
 * Copyright (C) 2007 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
10
package eu.etaxonomy.cdm.api.service;
11
12
import java.io.IOException;
13
import java.net.URI;
14
import java.net.URISyntaxException;
15
import java.util.ArrayList;
16
import java.util.Arrays;
17
import java.util.Collection;
18
import java.util.Collections;
19
import java.util.HashMap;
20
import java.util.HashSet;
21 09a260bb Katja Luther
import java.util.Iterator;
22 887126ca Andreas Müller
import java.util.List;
23
import java.util.Map;
24
import java.util.Map.Entry;
25
import java.util.Set;
26
import java.util.UUID;
27
28
import org.apache.log4j.Logger;
29 2622a38b Andreas Müller
import org.apache.lucene.queryparser.classic.ParseException;
30 887126ca Andreas Müller
import org.apache.lucene.search.BooleanClause.Occur;
31 f6b282fc Andreas Kohlbecker
import org.apache.lucene.search.BooleanQuery.Builder;
32 887126ca Andreas Müller
import org.apache.lucene.search.SortField;
33 57ea8a3a Andreas Kohlbecker
import org.apache.lucene.search.grouping.TopGroups;
34
import org.apache.lucene.util.BytesRef;
35 887126ca Andreas Müller
import org.hibernate.TransientObjectException;
36
import org.hibernate.search.spatial.impl.Rectangle;
37
import org.joda.time.Partial;
38
import org.springframework.beans.factory.annotation.Autowired;
39
import org.springframework.dao.DataRetrievalFailureException;
40
import org.springframework.stereotype.Service;
41
import org.springframework.transaction.annotation.Transactional;
42
43
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
44
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeConfigurator;
45
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeNotSupportedException;
46
import eu.etaxonomy.cdm.api.service.UpdateResult.Status;
47
import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase;
48
import eu.etaxonomy.cdm.api.service.config.FindOccurrencesConfigurator;
49
import eu.etaxonomy.cdm.api.service.config.IIdentifiableEntityServiceConfigurator;
50
import eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator;
51 a7e45124 Katja Luther
import eu.etaxonomy.cdm.api.service.dto.DNASampleDTO;
52 887126ca Andreas Müller
import eu.etaxonomy.cdm.api.service.dto.DerivateDTO;
53
import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO;
54
import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO.ContigFile;
55 91cdf81a Patrick Plitzner
import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO.Link;
56 887126ca Andreas Müller
import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO.MolecularData;
57
import eu.etaxonomy.cdm.api.service.dto.FieldUnitDTO;
58
import eu.etaxonomy.cdm.api.service.dto.PreservedSpecimenDTO;
59
import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
60
import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;
61
import eu.etaxonomy.cdm.api.service.pager.Pager;
62
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
63
import eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider;
64
import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;
65 3ca8a283 Patrick Plitzner
import eu.etaxonomy.cdm.api.service.search.LuceneParseException;
66 887126ca Andreas Müller
import eu.etaxonomy.cdm.api.service.search.LuceneSearch;
67
import eu.etaxonomy.cdm.api.service.search.QueryFactory;
68
import eu.etaxonomy.cdm.api.service.search.SearchResult;
69
import eu.etaxonomy.cdm.api.service.search.SearchResultBuilder;
70
import eu.etaxonomy.cdm.api.service.util.TaxonRelationshipEdge;
71 3c8d638c Patrick Plitzner
import eu.etaxonomy.cdm.common.CdmUtils;
72 887126ca Andreas Müller
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
73 6557bce4 Patrick Plitzner
import eu.etaxonomy.cdm.format.CdmFormatterFactory;
74
import eu.etaxonomy.cdm.format.ICdmFormatter.FormatKey;
75 887126ca Andreas Müller
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
76
import eu.etaxonomy.cdm.model.CdmBaseType;
77
import eu.etaxonomy.cdm.model.agent.AgentBase;
78
import eu.etaxonomy.cdm.model.common.CdmBase;
79
import eu.etaxonomy.cdm.model.common.DefinedTerm;
80
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
81
import eu.etaxonomy.cdm.model.common.Language;
82
import eu.etaxonomy.cdm.model.description.CategoricalData;
83
import eu.etaxonomy.cdm.model.description.DescriptionBase;
84
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
85
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
86
import eu.etaxonomy.cdm.model.description.QuantitativeData;
87
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
88
import eu.etaxonomy.cdm.model.description.TaxonDescription;
89
import eu.etaxonomy.cdm.model.location.Country;
90
import eu.etaxonomy.cdm.model.location.NamedArea;
91 6b53ead8 Katja Luther
import eu.etaxonomy.cdm.model.location.Point;
92 887126ca Andreas Müller
import eu.etaxonomy.cdm.model.media.Media;
93
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
94
import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
95
import eu.etaxonomy.cdm.model.media.MediaUtils;
96
import eu.etaxonomy.cdm.model.molecular.AmplificationResult;
97
import eu.etaxonomy.cdm.model.molecular.DnaSample;
98
import eu.etaxonomy.cdm.model.molecular.Sequence;
99
import eu.etaxonomy.cdm.model.molecular.SingleRead;
100
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
101 9dc896c9 Andreas Müller
import eu.etaxonomy.cdm.model.name.TaxonName;
102 887126ca Andreas Müller
import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;
103
import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;
104
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
105
import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;
106
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
107
import eu.etaxonomy.cdm.model.occurrence.GatheringEvent;
108
import eu.etaxonomy.cdm.model.occurrence.MediaSpecimen;
109
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
110
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
111
import eu.etaxonomy.cdm.model.taxon.Taxon;
112
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
113
import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
114
import eu.etaxonomy.cdm.persistence.dao.initializer.AbstractBeanInitializer;
115
import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
116 edfed701 Patrick Plitzner
import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;
117 887126ca Andreas Müller
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
118 1cfc76cb Patrick Plitzner
import eu.etaxonomy.cdm.persistence.query.AssignmentStatus;
119 887126ca Andreas Müller
import eu.etaxonomy.cdm.persistence.query.OrderHint;
120
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
121 9c61a32b Patrick Plitzner
import eu.etaxonomy.cdm.strategy.cache.common.IdentifiableEntityDefaultCacheStrategy;
122 887126ca Andreas Müller
123
/**
124
 * @author a.babadshanjan
125 a88578ce Andreas Müller
 * @since 01.09.2008
126 887126ca Andreas Müller
 */
127
@Service
128
@Transactional(readOnly = true)
129
public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObservationBase, IOccurrenceDao> implements IOccurrenceService {
130
131
    static private final Logger logger = Logger.getLogger(OccurrenceServiceImpl.class);
132
133
    @Autowired
134
    private IDefinedTermDao definedTermDao;
135
136
    @Autowired
137
    private IDescriptionService descriptionService;
138
139 e6e5ebdc Patrick Plitzner
    @Autowired
140
    private INameService nameService;
141
142 a9c2b3c3 Katja Luther
    @Autowired
143
    private IEventBaseService eventService;
144
145 887126ca Andreas Müller
    @Autowired
146
    private ITaxonService taxonService;
147
148
    @Autowired
149
    private ISequenceService sequenceService;
150
151
    @Autowired
152
    private AbstractBeanInitializer beanInitializer;
153
154
    @Autowired
155
    private ILuceneIndexToolProvider luceneIndexToolProvider;
156
157
    private static final String SEPARATOR_STRING = ", ";
158
159 ee6e05c9 Katja Luther
    private static final List<String> DERIVED_UNIT_INIT_STRATEGY =  Arrays.asList(new String []{
160
            "derivedFrom.derivatives",
161
            "derivedFrom.originals",
162
            "specimenTypeDesignations.*",
163
            "specimenTypeDesignations.citation.*",
164
            "specimenTypeDesignations.homotypicalGroup.*",
165
            "specimenTypeDesignations.typifiedNames",
166
            "collection.$"
167
    });
168
169 887126ca Andreas Müller
    public OccurrenceServiceImpl() {
170
        logger.debug("Load OccurrenceService Bean");
171
    }
172
173
174
    @Override
175
    @Transactional(readOnly = false)
176
    public void updateTitleCache(Class<? extends SpecimenOrObservationBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<SpecimenOrObservationBase> cacheStrategy, IProgressMonitor monitor) {
177
        if (clazz == null) {
178
            clazz = SpecimenOrObservationBase.class;
179
        }
180
        super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
181
    }
182
183
    /**
184
     * FIXME Candidate for harmonization
185
     * move to termService
186
     */
187
    @Override
188
    public Country getCountryByIso(String iso639) {
189
        return this.definedTermDao.getCountryByIso(iso639);
190
191
    }
192
193
    /**
194
     * FIXME Candidate for harmonization
195
     * move to termService
196
     */
197
    @Override
198
    public List<Country> getCountryByName(String name) {
199 024d9b21 Andreas Kohlbecker
        List<? extends DefinedTermBase> terms = this.definedTermDao.findByTitleWithRestrictions(Country.class, name, null, null, null, null, null, null);
200 7e7e032e Andreas Müller
        List<Country> countries = new ArrayList<>();
201 887126ca Andreas Müller
        for (int i = 0; i < terms.size(); i++) {
202
            countries.add((Country) terms.get(i));
203
        }
204
        return countries;
205
    }
206
207
    @Override
208
    @Autowired
209
    protected void setDao(IOccurrenceDao dao) {
210
        this.dao = dao;
211
    }
212
213
    @Override
214
    public Pager<DerivationEvent> getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
215 9a21de1f Andreas Müller
        long numberOfResults = dao.countDerivationEvents(occurence);
216 887126ca Andreas Müller
217 7e7e032e Andreas Müller
        List<DerivationEvent> results = new ArrayList<>();
218 887126ca Andreas Müller
        if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
219
            results = dao.getDerivationEvents(occurence, pageSize, pageNumber, propertyPaths);
220
        }
221
222 9a21de1f Andreas Müller
        return new DefaultPagerImpl<DerivationEvent>(pageNumber, numberOfResults, pageSize, results);
223 887126ca Andreas Müller
    }
224
225
    @Override
226 9a21de1f Andreas Müller
    public long countDeterminations(SpecimenOrObservationBase occurence, TaxonBase taxonbase) {
227 887126ca Andreas Müller
        return dao.countDeterminations(occurence, taxonbase);
228
    }
229
230
    @Override
231 2a4c4dd0 Andreas Müller
    public Pager<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase,
232
            Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
233 9a21de1f Andreas Müller
        long numberOfResults = dao.countDeterminations(occurrence, taxonBase);
234 887126ca Andreas Müller
235 7e7e032e Andreas Müller
        List<DeterminationEvent> results = new ArrayList<>();
236 887126ca Andreas Müller
        if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
237
            results = dao.getDeterminations(occurrence, taxonBase, pageSize, pageNumber, propertyPaths);
238
        }
239
240 9a21de1f Andreas Müller
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
241 887126ca Andreas Müller
    }
242
243
    @Override
244
    public Pager<Media> getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
245 9a21de1f Andreas Müller
        long numberOfResults = dao.countMedia(occurence);
246 887126ca Andreas Müller
247 7e7e032e Andreas Müller
        List<Media> results = new ArrayList<>();
248 887126ca Andreas Müller
        if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
249
            results = dao.getMedia(occurence, pageSize, pageNumber, propertyPaths);
250
        }
251
252 9a21de1f Andreas Müller
        return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);
253 887126ca Andreas Müller
    }
254
255 6eccaa42 Patrick Plitzner
    @Override
256
    public Pager<Media> getMediainHierarchy(SpecimenOrObservationBase rootOccurence, Integer pageSize,
257
            Integer pageNumber, List<String> propertyPaths) {
258 7e7e032e Andreas Müller
        List<Media> media = new ArrayList<>();
259 6eccaa42 Patrick Plitzner
        //media specimens
260
        if(rootOccurence.isInstanceOf(MediaSpecimen.class)){
261
            MediaSpecimen mediaSpecimen = HibernateProxyHelper.deproxy(rootOccurence, MediaSpecimen.class);
262
            media.add(mediaSpecimen.getMediaSpecimen());
263
        }
264
        // pherograms & gelPhotos
265
        if (rootOccurence.isInstanceOf(DnaSample.class)) {
266
            DnaSample dnaSample = CdmBase.deproxy(rootOccurence, DnaSample.class);
267
            Set<Sequence> sequences = dnaSample.getSequences();
268
            //we do show only those gelPhotos which lead to a consensus sequence
269
            for (Sequence sequence : sequences) {
270 7e7e032e Andreas Müller
                Set<Media> dnaRelatedMedia = new HashSet<>();
271 6eccaa42 Patrick Plitzner
                for (SingleRead singleRead : sequence.getSingleReads()){
272
                    AmplificationResult amplification = singleRead.getAmplificationResult();
273
                    dnaRelatedMedia.add(amplification.getGelPhoto());
274
                    dnaRelatedMedia.add(singleRead.getPherogram());
275
                    dnaRelatedMedia.remove(null);
276
                }
277
                media.addAll(dnaRelatedMedia);
278
            }
279
        }
280
        if(rootOccurence.isInstanceOf(DerivedUnit.class)){
281
            DerivedUnit derivedUnit = HibernateProxyHelper.deproxy(rootOccurence, DerivedUnit.class);
282
            for (DerivationEvent derivationEvent : derivedUnit.getDerivationEvents()) {
283
                for (DerivedUnit childDerivative : derivationEvent.getDerivatives()) {
284
                    media.addAll(getMediainHierarchy(childDerivative, pageSize, pageNumber, propertyPaths).getRecords());
285
                }
286
            }
287
        }
288 2a4c4dd0 Andreas Müller
        return new DefaultPagerImpl<Media>(pageNumber, Long.valueOf(media.size()), pageSize, media);
289 6eccaa42 Patrick Plitzner
    }
290
291 e6e5ebdc Patrick Plitzner
    @Override
292 2a4c4dd0 Andreas Müller
    public Pager<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> type, TaxonName determinedAs,
293
            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
294 9a21de1f Andreas Müller
        long numberOfResults = dao.count(type, determinedAs);
295 2a4c4dd0 Andreas Müller
        @SuppressWarnings("rawtypes")
296 7e7e032e Andreas Müller
        List<SpecimenOrObservationBase> results = new ArrayList<>();
297 e6e5ebdc Patrick Plitzner
        if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
298 2a4c4dd0 Andreas Müller
            results = dao.list(type, determinedAs, pageSize, pageNumber, orderHints, propertyPaths);
299 e6e5ebdc Patrick Plitzner
        }
300 9a21de1f Andreas Müller
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
301 e6e5ebdc Patrick Plitzner
    }
302
303 887126ca Andreas Müller
    @Override
304 2a4c4dd0 Andreas Müller
    public Pager<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> type, TaxonBase determinedAs,
305
            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
306 9a21de1f Andreas Müller
        long numberOfResults = dao.count(type, determinedAs);
307 2a4c4dd0 Andreas Müller
        @SuppressWarnings("rawtypes")
308 7e7e032e Andreas Müller
        List<SpecimenOrObservationBase> results = new ArrayList<>();
309 887126ca Andreas Müller
        if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
310 2a4c4dd0 Andreas Müller
            results = dao.list(type, determinedAs, pageSize, pageNumber, orderHints, propertyPaths);
311 887126ca Andreas Müller
        }
312 9a21de1f Andreas Müller
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
313 887126ca Andreas Müller
    }
314
315
    @Override
316 a9c2b3c3 Katja Luther
    public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache(Integer limit, String pattern) {
317
        return dao.getDerivedUnitUuidAndTitleCache(limit, pattern);
318 887126ca Andreas Müller
    }
319
320
    @Override
321
    public List<UuidAndTitleCache<FieldUnit>> getFieldUnitUuidAndTitleCache() {
322
        return dao.getFieldUnitUuidAndTitleCache();
323
    }
324
325
    @Override
326
    public DerivedUnitFacade getDerivedUnitFacade(DerivedUnit derivedUnit, List<String> propertyPaths) throws DerivedUnitFacadeNotSupportedException {
327
        derivedUnit = (DerivedUnit) dao.load(derivedUnit.getUuid(), null);
328
        DerivedUnitFacadeConfigurator config = DerivedUnitFacadeConfigurator.NewInstance();
329
        config.setThrowExceptionForNonSpecimenPreservationMethodRequest(false);
330
        DerivedUnitFacade derivedUnitFacade = DerivedUnitFacade.NewInstance(derivedUnit, config);
331
        beanInitializer.initialize(derivedUnitFacade, propertyPaths);
332
        return derivedUnitFacade;
333
    }
334
335
    @Override
336
    public List<DerivedUnitFacade> listDerivedUnitFacades(
337
            DescriptionBase description, List<String> propertyPaths) {
338
339 7e7e032e Andreas Müller
        List<DerivedUnitFacade> derivedUnitFacadeList = new ArrayList<>();
340 887126ca Andreas Müller
        IndividualsAssociation tempIndividualsAssociation;
341
        SpecimenOrObservationBase tempSpecimenOrObservationBase;
342 a1439def Andreas Müller
        List<IndividualsAssociation> elements = descriptionService.listDescriptionElements(description, null, IndividualsAssociation.class, null, 0, Arrays.asList(new String []{"associatedSpecimenOrObservation"}));
343
        for (IndividualsAssociation element : elements) {
344
            tempIndividualsAssociation = HibernateProxyHelper.deproxy(element, IndividualsAssociation.class);
345
            if (tempIndividualsAssociation.getAssociatedSpecimenOrObservation() != null) {
346
                tempSpecimenOrObservationBase = HibernateProxyHelper.deproxy(tempIndividualsAssociation.getAssociatedSpecimenOrObservation(), SpecimenOrObservationBase.class);
347
                if (tempSpecimenOrObservationBase.isInstanceOf(DerivedUnit.class)) {
348
                    try {
349
                        derivedUnitFacadeList.add(DerivedUnitFacade.NewInstance(HibernateProxyHelper.deproxy(tempSpecimenOrObservationBase, DerivedUnit.class)));
350
                    } catch (DerivedUnitFacadeNotSupportedException e) {
351
                        logger.warn(tempIndividualsAssociation.getAssociatedSpecimenOrObservation().getTitleCache() + " : " + e.getMessage());
352 887126ca Andreas Müller
                    }
353
                }
354
            }
355
        }
356
357
        beanInitializer.initializeAll(derivedUnitFacadeList, propertyPaths);
358
359
        return derivedUnitFacadeList;
360
    }
361
362
363
    @Override
364
    public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
365
            Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
366
367
        return pageByAssociatedTaxon(type, includeRelationships, associatedTaxon, maxDepth, pageSize, pageNumber, orderHints, propertyPaths).getRecords();
368
    }
369
370 edfed701 Patrick Plitzner
    @Override
371 d9b27602 Patrick Plitzner
    public Collection<SpecimenNodeWrapper> listUuidAndTitleCacheByAssociatedTaxon(List<UUID> taxonNodeUuids,
372 b27b3345 Patrick Plitzner
            Integer limit, Integer start) {
373
        return dao.listUuidAndTitleCacheByAssociatedTaxon(taxonNodeUuids, limit, start);
374 edfed701 Patrick Plitzner
        }
375
376 887126ca Andreas Müller
    @Override
377
    public Collection<SpecimenOrObservationBase> listFieldUnitsByAssociatedTaxon(Taxon associatedTaxon, List<OrderHint> orderHints, List<String> propertyPaths) {
378
        return pageFieldUnitsByAssociatedTaxon(null, associatedTaxon, null, null, null, null, propertyPaths).getRecords();
379
    }
380
381
    @Override
382
    public Pager<SpecimenOrObservationBase> pageFieldUnitsByAssociatedTaxon(Set<TaxonRelationshipEdge> includeRelationships,
383
            Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
384
            List<String> propertyPaths) {
385
386
        if (!getSession().contains(associatedTaxon)) {
387
            associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());
388
        }
389
390
        // gather the IDs of all relevant field units
391 7e7e032e Andreas Müller
        Set<UUID> fieldUnitUuids = new HashSet<>();
392 887126ca Andreas Müller
        List<SpecimenOrObservationBase> records = listByAssociatedTaxon(null, includeRelationships, associatedTaxon, maxDepth, null, null, orderHints, propertyPaths);
393
        for (SpecimenOrObservationBase<?> specimen : records) {
394 6b53ead8 Katja Luther
            for (FieldUnit fieldUnit : findFieldUnits(specimen.getUuid(), null)) {
395 88d0b58a Patrick Plitzner
                fieldUnitUuids.add(fieldUnit.getUuid());
396 887126ca Andreas Müller
            }
397
        }
398 88d0b58a Patrick Plitzner
        //dao.list() does the paging of the field units. Passing the field units directly to the Pager would not work
399
        List<SpecimenOrObservationBase> fieldUnits = dao.list(fieldUnitUuids, pageSize, pageNumber, orderHints, propertyPaths);
400 ea33ac4f Andreas Müller
        return new DefaultPagerImpl<>(pageNumber, fieldUnitUuids.size(), pageSize, fieldUnits);
401 887126ca Andreas Müller
    }
402
403
    @Override
404 eec520d3 Andreas Kohlbecker
    public FieldUnitDTO assembleFieldUnitDTO(FieldUnit fieldUnit) {
405 887126ca Andreas Müller
406
        if (!getSession().contains(fieldUnit)) {
407
            fieldUnit = (FieldUnit) load(fieldUnit.getUuid());
408
        }
409
410 d70a126f Katja Luther
        FieldUnitDTO fieldUnitDTO = new FieldUnitDTO(fieldUnit);
411 887126ca Andreas Müller
412
        if (fieldUnit.getGatheringEvent() != null) {
413
            GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();
414
            // Country
415
            NamedArea country = gatheringEvent.getCountry();
416 4103e3d4 Patrick Plitzner
            fieldUnitDTO.setCountry(country != null ? country.getLabel() : null);
417 887126ca Andreas Müller
            // Collection
418
            AgentBase collector = gatheringEvent.getCollector();
419
            String fieldNumber = fieldUnit.getFieldNumber();
420
            String collectionString = "";
421
            if (collector != null || fieldNumber != null) {
422
                collectionString += collector != null ? collector : "";
423
                if (!collectionString.isEmpty()) {
424
                    collectionString += " ";
425
                }
426
                collectionString += (fieldNumber != null ? fieldNumber : "");
427
                collectionString.trim();
428
            }
429
            fieldUnitDTO.setCollection(collectionString);
430
            // Date
431
            Partial gatheringDate = gatheringEvent.getGatheringDate();
432
            String dateString = null;
433
            if (gatheringDate != null) {
434 6557bce4 Patrick Plitzner
                dateString = gatheringDate.toString();
435 887126ca Andreas Müller
            }
436
            else if(gatheringEvent.getTimeperiod()!=null && gatheringEvent.getTimeperiod().getFreeText()!=null){
437
                dateString = gatheringEvent.getTimeperiod().getFreeText();
438
            }
439
            fieldUnitDTO.setDate(dateString);
440
        }
441
442
        // Herbaria map
443 7e7e032e Andreas Müller
        Map<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> collectionToCountMap = new HashMap<>();
444 887126ca Andreas Müller
        // List of accession numbers for citation
445 7e7e032e Andreas Müller
        List<String> preservedSpecimenAccessionNumbers = new ArrayList<>();
446 887126ca Andreas Müller
447
        // assemble preserved specimen DTOs
448
        Set<DerivationEvent> derivationEvents = fieldUnit.getDerivationEvents();
449
        for (DerivationEvent derivationEvent : derivationEvents) {
450
            Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
451
            for (DerivedUnit derivedUnit : derivatives) {
452 612d9ce9 Patrick Plitzner
                if(!derivedUnit.isPublish()){
453
                    continue;
454
                }
455 887126ca Andreas Müller
                // collect accession numbers for citation
456 5a143666 Patrick Plitzner
                String identifier = getMostSignificantIdentifier(derivedUnit);
457 887126ca Andreas Müller
                // collect collections for herbaria column
458 5a143666 Patrick Plitzner
                eu.etaxonomy.cdm.model.occurrence.Collection collection = derivedUnit.getCollection();
459
                if (collection != null) {
460
                    //combine collection with identifier
461
                    if (identifier != null) {
462
                        if(collection.getCode()!=null){
463
                            identifier = (collection.getCode()!=null?collection.getCode():"[no collection]")+" "+identifier;
464
                        }
465
                        preservedSpecimenAccessionNumbers.add(identifier);
466
                    }
467
468
                    Integer herbariumCount = collectionToCountMap.get(collection);
469 887126ca Andreas Müller
                    if (herbariumCount == null) {
470
                        herbariumCount = 0;
471
                    }
472 5a143666 Patrick Plitzner
                    collectionToCountMap.put(collection, herbariumCount + 1);
473 887126ca Andreas Müller
                }
474
                if (derivedUnit.getRecordBasis().equals(SpecimenOrObservationType.PreservedSpecimen)) {
475
                    PreservedSpecimenDTO preservedSpecimenDTO = assemblePreservedSpecimenDTO(derivedUnit, fieldUnitDTO);
476 77993547 Katja Luther
                    fieldUnitDTO.addDerivate(preservedSpecimenDTO);
477 887126ca Andreas Müller
                    fieldUnitDTO.setHasCharacterData(fieldUnitDTO.isHasCharacterData() || preservedSpecimenDTO.isHasCharacterData());
478
                    fieldUnitDTO.setHasDetailImage(fieldUnitDTO.isHasDetailImage() || preservedSpecimenDTO.isHasDetailImage());
479
                    fieldUnitDTO.setHasDna(fieldUnitDTO.isHasDna() || preservedSpecimenDTO.isHasDna());
480
                    fieldUnitDTO.setHasSpecimenScan(fieldUnitDTO.isHasSpecimenScan() || preservedSpecimenDTO.isHasSpecimenScan());
481
                }
482
            }
483
        }
484
        // assemble derivate data DTO
485
        assembleDerivateDataDTO(fieldUnitDTO, fieldUnit);
486
487
        // assemble citation
488
        String citation = fieldUnit.getTitleCache();
489 9c61a32b Patrick Plitzner
        if((CdmUtils.isBlank(citation) || citation.equals(IdentifiableEntityDefaultCacheStrategy.TITLE_CACHE_GENERATION_NOT_IMPLEMENTED))
490 4fd26794 Patrick Plitzner
                && !fieldUnit.isProtectedTitleCache()){
491
            fieldUnit.setTitleCache(null);
492
            citation = fieldUnit.getTitleCache();
493
        }
494 887126ca Andreas Müller
        if (!preservedSpecimenAccessionNumbers.isEmpty()) {
495
            citation += " (";
496
            for (String accessionNumber : preservedSpecimenAccessionNumbers) {
497
                if (!accessionNumber.isEmpty()) {
498
                    citation += accessionNumber + SEPARATOR_STRING;
499
                }
500
            }
501
            citation = removeTail(citation, SEPARATOR_STRING);
502
            citation += ")";
503
        }
504
        fieldUnitDTO.setCitation(citation);
505
506
        // assemble herbaria string
507
        String herbariaString = "";
508
        for (Entry<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> e : collectionToCountMap.entrySet()) {
509
            eu.etaxonomy.cdm.model.occurrence.Collection collection = e.getKey();
510
            if (collection.getCode() != null) {
511
                herbariaString += collection.getCode();
512
            }
513
            if (e.getValue() > 1) {
514
                herbariaString += "(" + e.getValue() + ")";
515
            }
516
            herbariaString += SEPARATOR_STRING;
517
        }
518
        herbariaString = removeTail(herbariaString, SEPARATOR_STRING);
519 cb9801c1 Katja Luther
        fieldUnitDTO.setCollection(herbariaString);
520 887126ca Andreas Müller
521
        return fieldUnitDTO;
522
    }
523
524
    @Override
525
    public PreservedSpecimenDTO assemblePreservedSpecimenDTO(DerivedUnit derivedUnit) {
526
        return assemblePreservedSpecimenDTO(derivedUnit, null);
527
    }
528
529
    @Override
530
    public String getMostSignificantIdentifier(DerivedUnit derivedUnit) {
531
        if (derivedUnit.getAccessionNumber() != null && !derivedUnit.getAccessionNumber().isEmpty()) {
532
            return derivedUnit.getAccessionNumber();
533
        }
534
        else if(derivedUnit.getBarcode()!=null && !derivedUnit.getBarcode().isEmpty()){
535
            return derivedUnit.getBarcode();
536
        }
537
        else if(derivedUnit.getCatalogNumber()!=null && !derivedUnit.getCatalogNumber().isEmpty()){
538
            return derivedUnit.getCatalogNumber();
539
        }
540
        return null;
541
    }
542
543
    public PreservedSpecimenDTO assemblePreservedSpecimenDTO(DerivedUnit derivedUnit, FieldUnitDTO fieldUnitDTO) {
544
        if (!getSession().contains(derivedUnit)) {
545
            derivedUnit = (DerivedUnit) load(derivedUnit.getUuid());
546
        }
547 d70a126f Katja Luther
        PreservedSpecimenDTO preservedSpecimenDTO = new PreservedSpecimenDTO(derivedUnit);
548 887126ca Andreas Müller
549 6557bce4 Patrick Plitzner
        //specimen identifier
550
        FormatKey collectionKey = FormatKey.COLLECTION_CODE;
551 2837fda6 Andreas Müller
        String specimenIdentifier = CdmFormatterFactory.format(derivedUnit, collectionKey);
552 6557bce4 Patrick Plitzner
        if (CdmUtils.isBlank(specimenIdentifier)) {
553
            collectionKey = FormatKey.COLLECTION_NAME;
554 887126ca Andreas Müller
        }
555 6557bce4 Patrick Plitzner
        specimenIdentifier = CdmFormatterFactory.format(derivedUnit, new FormatKey[] {
556
                collectionKey, FormatKey.SPACE,
557
                FormatKey.MOST_SIGNIFICANT_IDENTIFIER, FormatKey.SPACE });
558 01371d61 Patrick Plitzner
        if(CdmUtils.isBlank(specimenIdentifier)){
559
            specimenIdentifier = derivedUnit.getTitleCache();
560
        }
561 6557bce4 Patrick Plitzner
        if(CdmUtils.isBlank(specimenIdentifier)){
562
            specimenIdentifier = derivedUnit.getUuid().toString();
563 e1207484 Patrick Plitzner
        }
564 6557bce4 Patrick Plitzner
        preservedSpecimenDTO.setAccessionNumber(specimenIdentifier);
565 77993547 Katja Luther
566 887126ca Andreas Müller
567 4a39cd98 Patrick Plitzner
        //preferred stable URI
568
        preservedSpecimenDTO.setPreferredStableUri(derivedUnit.getPreferredStableUri());
569
570 887126ca Andreas Müller
        // citation
571 42002c0a Patrick Plitzner
        Collection<FieldUnit> fieldUnits = getFieldUnits(derivedUnit, null);
572 887126ca Andreas Müller
        if (fieldUnits.size() == 1) {
573
            preservedSpecimenDTO.setCitation(fieldUnits.iterator().next().getTitleCache());
574
        }
575
        else{
576
            preservedSpecimenDTO.setCitation("No Citation available. This specimen either has no or multiple field units.");
577
        }
578
579
        // character state data
580
        Collection<DescriptionElementBase> characterDataForSpecimen = getCharacterDataForSpecimen(derivedUnit);
581
        if (!characterDataForSpecimen.isEmpty()) {
582
            if (fieldUnitDTO != null) {
583
                fieldUnitDTO.setHasCharacterData(true);
584
            }
585
        }
586
        for (DescriptionElementBase descriptionElementBase : characterDataForSpecimen) {
587
            String character = descriptionElementBase.getFeature().getLabel();
588 7e7e032e Andreas Müller
            ArrayList<Language> languages = new ArrayList<>(Collections.singleton(Language.DEFAULT()));
589 887126ca Andreas Müller
            if (descriptionElementBase instanceof QuantitativeData) {
590
                QuantitativeData quantitativeData = (QuantitativeData) descriptionElementBase;
591
                DefaultQuantitativeDescriptionBuilder builder = new DefaultQuantitativeDescriptionBuilder();
592
                String state = builder.build(quantitativeData, languages).getText(Language.DEFAULT());
593
                preservedSpecimenDTO.addCharacterData(character, state);
594
            }
595
            else if(descriptionElementBase instanceof CategoricalData){
596
                CategoricalData categoricalData = (CategoricalData) descriptionElementBase;
597
                DefaultCategoricalDescriptionBuilder builder = new DefaultCategoricalDescriptionBuilder();
598
                String state = builder.build(categoricalData, languages).getText(Language.DEFAULT());
599
                preservedSpecimenDTO.addCharacterData(character, state);
600
            }
601
        }
602
        // check type designations
603
        Collection<SpecimenTypeDesignation> specimenTypeDesignations = listTypeDesignations(derivedUnit, null, null, null, null);
604
        for (SpecimenTypeDesignation specimenTypeDesignation : specimenTypeDesignations) {
605
            if (fieldUnitDTO != null) {
606
                fieldUnitDTO.setHasType(true);
607
            }
608
            TypeDesignationStatusBase<?> typeStatus = specimenTypeDesignation.getTypeStatus();
609 cd175378 Patrick Plitzner
            Set<TaxonName> typifiedNames = specimenTypeDesignation.getTypifiedNames();
610
            List<String> typedTaxaNames = new ArrayList<>();
611
            for (TaxonName taxonName : typifiedNames) {
612 9657122e Patrick Plitzner
                typedTaxaNames.add(taxonName.getTitleCache());
613 887126ca Andreas Müller
            }
614 64688697 Patrick Plitzner
            preservedSpecimenDTO.addTypes(typeStatus!=null?typeStatus.getLabel():"", typedTaxaNames);
615 887126ca Andreas Müller
        }
616
617
        // individuals associations
618
        Collection<IndividualsAssociation> individualsAssociations = listIndividualsAssociations(derivedUnit, null, null, null, null);
619
        for (IndividualsAssociation individualsAssociation : individualsAssociations) {
620
            if (individualsAssociation.getInDescription() != null) {
621
                if (individualsAssociation.getInDescription().isInstanceOf(TaxonDescription.class)) {
622
                    TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(individualsAssociation.getInDescription(), TaxonDescription.class);
623
                    Taxon taxon = taxonDescription.getTaxon();
624 172def0a Patrick Plitzner
                    if (taxon != null) {
625
                        preservedSpecimenDTO.addAssociatedTaxon(taxon);
626 887126ca Andreas Müller
                    }
627
                }
628
            }
629
        }
630
        // assemble sub derivates
631
        preservedSpecimenDTO.setDerivateDataDTO(assembleDerivateDataDTO(preservedSpecimenDTO, derivedUnit));
632
        return preservedSpecimenDTO;
633
    }
634
635
    private DerivateDataDTO assembleDerivateDataDTO(DerivateDTO derivateDTO, SpecimenOrObservationBase<?> specimenOrObservation) {
636
        DerivateDataDTO derivateDataDTO = new DerivateDataDTO();
637
        Collection<DerivedUnit> childDerivates = getDerivedUnitsFor(specimenOrObservation);
638
        for (DerivedUnit childDerivate : childDerivates) {
639
            // assemble molecular data
640
            //pattern: DNAMarker [contig1, primer1_1, primer1_2, ...][contig2, primer2_1, ...]...
641
            if (childDerivate.isInstanceOf(DnaSample.class)) {
642
                if (childDerivate.getRecordBasis() == SpecimenOrObservationType.TissueSample) {
643
                    // TODO implement TissueSample assembly for web service
644
                }
645
                if (childDerivate.getRecordBasis() == SpecimenOrObservationType.DnaSample) {
646
647
                    DnaSample dna = HibernateProxyHelper.deproxy(childDerivate, DnaSample.class);
648
                    if (!dna.getSequences().isEmpty()) {
649
                        derivateDTO.setHasDna(true);
650
                    }
651
                    for (Sequence sequence : dna.getSequences()) {
652
                        URI boldUri = null;
653
                        try {
654
                            boldUri = sequence.getBoldUri();
655
                        } catch (URISyntaxException e1) {
656
                            logger.error("Could not create BOLD URI", e1);
657
                        }
658
                        final DefinedTerm dnaMarker = sequence.getDnaMarker();
659 91cdf81a Patrick Plitzner
                        Link providerLink = null;
660
                        if(boldUri!=null && dnaMarker!=null){
661
                        	providerLink = new DerivateDataDTO.Link(boldUri, dnaMarker.getLabel());
662
                        }
663
                        MolecularData molecularData = derivateDataDTO.addProviderLink(providerLink);
664 887126ca Andreas Müller
665
                        //contig file
666
                        ContigFile contigFile = null;
667
                        if (sequence.getContigFile() != null) {
668
                            MediaRepresentationPart contigMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(sequence.getContigFile());
669
                            if (contigMediaRepresentationPart != null) {
670 91cdf81a Patrick Plitzner
                                contigFile = molecularData.addContigFile(new Link(contigMediaRepresentationPart.getUri(), "contig"));
671 887126ca Andreas Müller
                            }
672
                        }
673 91cdf81a Patrick Plitzner
                        else{
674
                        	contigFile = molecularData.addContigFile(null);
675 887126ca Andreas Müller
                        }
676
                        // primer files
677
                        if (sequence.getSingleReads() != null) {
678
                            int readCount = 1;
679
                            for (SingleRead singleRead : sequence.getSingleReads()) {
680
                                MediaRepresentationPart pherogramMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(singleRead.getPherogram());
681
                                if (pherogramMediaRepresentationPart != null) {
682
                                    contigFile.addPrimerLink(pherogramMediaRepresentationPart.getUri(), "read"+readCount++);
683
                                }
684
                            }
685
                        }
686
                    }
687
                }
688
            }
689
            // assemble media data
690
            else if (childDerivate.isInstanceOf(MediaSpecimen.class)) {
691
                MediaSpecimen media = HibernateProxyHelper.deproxy(childDerivate, MediaSpecimen.class);
692
693 e1207484 Patrick Plitzner
                URI mediaUri = getMediaUri(media);
694 887126ca Andreas Müller
                if (media.getKindOfUnit() != null) {
695
                    // specimen scan
696 91cdf81a Patrick Plitzner
                    if (media.getKindOfUnit().getUuid().equals(DefinedTerm.uuidSpecimenScan)) {
697 887126ca Andreas Müller
                        derivateDataDTO.addSpecimenScanUuid(media.getMediaSpecimen().getUuid());
698
                        derivateDTO.setHasSpecimenScan(true);
699
                        String imageLinkText = "scan";
700
                        if (derivateDTO instanceof PreservedSpecimenDTO && ((PreservedSpecimenDTO) derivateDTO).getAccessionNumber() != null) {
701
                            imageLinkText = ((PreservedSpecimenDTO) derivateDTO).getAccessionNumber();
702
                        }
703 e1207484 Patrick Plitzner
                        derivateDataDTO.addSpecimenScan(mediaUri, imageLinkText);
704 887126ca Andreas Müller
                    }
705
                    // detail image
706 91cdf81a Patrick Plitzner
                    else if (media.getKindOfUnit().getUuid().equals(DefinedTerm.uuidDetailImage)) {
707 887126ca Andreas Müller
                        derivateDataDTO.addDetailImageUuid(media.getMediaSpecimen().getUuid());
708
                        derivateDTO.setHasDetailImage(true);
709 e1207484 Patrick Plitzner
                        String motif = "detail image";
710
                        if (media.getMediaSpecimen()!=null){
711
                        	if(CdmUtils.isNotBlank(media.getMediaSpecimen().getTitleCache())) {
712
                        		motif = media.getMediaSpecimen().getTitleCache();
713
                        	}
714 887126ca Andreas Müller
                        }
715 91cdf81a Patrick Plitzner
                        derivateDataDTO.addDetailImage(mediaUri, motif);
716 887126ca Andreas Müller
                    }
717
                }
718
            }
719
        }
720
        return derivateDataDTO;
721
    }
722
723
    private String removeTail(String string, final String tail) {
724
        if (string.endsWith(tail)) {
725
            string = string.substring(0, string.length() - tail.length());
726
        }
727
        return string;
728
    }
729
730 e1207484 Patrick Plitzner
    private URI getMediaUri(MediaSpecimen mediaSpecimen) {
731
        URI mediaUri = null;
732 887126ca Andreas Müller
        Collection<MediaRepresentation> mediaRepresentations = mediaSpecimen.getMediaSpecimen().getRepresentations();
733
        if (mediaRepresentations != null && !mediaRepresentations.isEmpty()) {
734
            Collection<MediaRepresentationPart> mediaRepresentationParts = mediaRepresentations.iterator().next().getParts();
735
            if (mediaRepresentationParts != null && !mediaRepresentationParts.isEmpty()) {
736
                MediaRepresentationPart part = mediaRepresentationParts.iterator().next();
737
                if (part.getUri() != null) {
738 e1207484 Patrick Plitzner
                    mediaUri = part.getUri();
739 887126ca Andreas Müller
                }
740
            }
741
        }
742
        return mediaUri;
743
    }
744
745
    private Collection<DerivedUnit> getDerivedUnitsFor(SpecimenOrObservationBase<?> specimen) {
746 7e7e032e Andreas Müller
        Collection<DerivedUnit> derivedUnits = new ArrayList<>();
747 887126ca Andreas Müller
        for (DerivationEvent derivationEvent : specimen.getDerivationEvents()) {
748
            for (DerivedUnit derivative : derivationEvent.getDerivatives()) {
749
                derivedUnits.add(derivative);
750
                derivedUnits.addAll(getDerivedUnitsFor(derivative));
751
            }
752
        }
753
        return derivedUnits;
754
    }
755
756 6b53ead8 Katja Luther
    private Set<DerivateDTO> getDerivedUnitDTOsFor(DerivateDTO specimenDto, DerivedUnit specimen, HashMap<UUID, DerivateDTO> alreadyCollectedSpecimen) {
757
        Set<DerivateDTO> derivedUnits = new HashSet<>();
758
//        load
759
        for (DerivationEvent derivationEvent : specimen.getDerivationEvents()) {
760
            for (DerivedUnit derivative : derivationEvent.getDerivatives()) {
761
                if (!alreadyCollectedSpecimen.containsKey(specimenDto.getUuid())){
762 a7e45124 Katja Luther
                    PreservedSpecimenDTO dto;
763
                    if (derivative instanceof DnaSample) {
764
                        dto = new DNASampleDTO(derivative);
765
                    } else {
766 484a120f Katja Luther
                        dto = new PreservedSpecimenDTO(derivative);
767 a7e45124 Katja Luther
                    }
768 6b53ead8 Katja Luther
                    alreadyCollectedSpecimen.put(dto.getUuid(), dto);
769
                    dto.addAllDerivates(getDerivedUnitDTOsFor(dto, derivative, alreadyCollectedSpecimen));
770
                    derivedUnits.add(dto);
771
                }
772
            }
773
        }
774
        return derivedUnits;
775
    }
776 887126ca Andreas Müller
777 d70a126f Katja Luther
//    private Set<DerivateDTO> getDerivedUnitDTOsFor(DerivateDTO specimenDto, DerivedUnit specimen, HashMap<UUID, DerivateDTO> alreadyCollectedSpecimen) {
778
//        Set<DerivateDTO> derivedUnits = new HashSet<>();
779
////        load
780
//        for (DerivationEvent derivationEvent : specimen.getDerivationEvents()) {
781
//            for (DerivedUnit derivative : derivationEvent.getDerivatives()) {
782
//                if (!alreadyCollectedSpecimen.containsKey(specimenDto.getUuid())){
783
//                    PreservedSpecimenDTO dto;
784
//                    if (derivative instanceof DnaSample){
785
//                        dto = DNASampleDTO.newInstance(derivative);
786
//                    }else{
787
//                        dto = PreservedSpecimenDTO.newInstance(derivative);
788
//                    }
789
//                    alreadyCollectedSpecimen.put(dto.getUuid(), dto);
790
//                    dto.addAllDerivates(getDerivedUnitDTOsFor(dto, derivative, alreadyCollectedSpecimen));
791
//                    derivedUnits.add(dto);
792
//                }
793
//            }
794
//        }
795
//        return derivedUnits;
796
//    }
797
798
799 887126ca Andreas Müller
    @SuppressWarnings("unchecked")
800
    @Override
801 e08838f0 Andreas Müller
    public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includedRelationships,
802 887126ca Andreas Müller
            Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
803
804 7e7e032e Andreas Müller
        Set<Taxon> taxa = new HashSet<>();
805
        Set<Integer> occurrenceIds = new HashSet<>();
806
        List<T> occurrences = new ArrayList<>();
807 e08838f0 Andreas Müller
        boolean includeUnpublished = INCLUDE_UNPUBLISHED;
808 887126ca Andreas Müller
809
        // Integer limit = PagerUtils.limitFor(pageSize);
810
        // Integer start = PagerUtils.startFor(pageSize, pageNumber);
811
812
        if (!getSession().contains(associatedTaxon)) {
813
            associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());
814
        }
815
816 e08838f0 Andreas Müller
        if (includedRelationships != null) {
817
            taxa = taxonService.listRelatedTaxa(associatedTaxon, includedRelationships, maxDepth, includeUnpublished, null, null, propertyPaths);
818 887126ca Andreas Müller
        }
819
820
        taxa.add(associatedTaxon);
821
822
        for (Taxon taxon : taxa) {
823
            List<T> perTaxonOccurrences = dao.listByAssociatedTaxon(type, taxon, null, null, orderHints, propertyPaths);
824 11d3d7eb Andreas Müller
            for (SpecimenOrObservationBase<?> o : perTaxonOccurrences) {
825 887126ca Andreas Müller
                occurrenceIds.add(o.getId());
826
            }
827
        }
828 1ec74f53 Andreas Kohlbecker
        occurrences = (List<T>) dao.loadList(occurrenceIds, propertyPaths);
829 887126ca Andreas Müller
830 6b53ead8 Katja Luther
        return new DefaultPagerImpl<T>(pageNumber, Long.valueOf(occurrences.size()), pageSize, occurrences);
831 887126ca Andreas Müller
832
    }
833
834
    @Override
835
    public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
836
            String taxonUUID, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
837
838
        UUID uuid = UUID.fromString(taxonUUID);
839
        Taxon tax = (Taxon) taxonService.load(uuid);
840
        // TODO REMOVE NULL STATEMENT
841
        type = null;
842
        return pageByAssociatedTaxon(type, includeRelationships, tax, maxDepth, pageSize, pageNumber, orderHints, propertyPaths);
843
844
    }
845
846 6b53ead8 Katja Luther
    @SuppressWarnings("unchecked")
847
    @Override
848
    public List<FieldUnitDTO> findFieldUnitDTOByAssociatedTaxon(Set<TaxonRelationshipEdge> includedRelationships,
849
            UUID associatedTaxonUuid) {
850
851
        Set<Taxon> taxa = new HashSet<>();
852
        Set<Integer> occurrenceIds = new HashSet<>();
853
        List<FieldUnitDTO> fieldUnitDTOs = new ArrayList<>();
854
        HashMap<UUID, DerivateDTO> alreadyCollectedSpecimen = new HashMap<>();
855
        List<SpecimenOrObservationBase> occurrences = new ArrayList<>();
856
        boolean includeUnpublished = INCLUDE_UNPUBLISHED;
857
858
        // Integer limit = PagerUtils.limitFor(pageSize);
859
        // Integer start = PagerUtils.startFor(pageSize, pageNumber);
860
861
        Taxon associatedTaxon = (Taxon) taxonService.load(associatedTaxonUuid);
862
863
864
        if (includedRelationships != null) {
865
            taxa = taxonService.listRelatedTaxa(associatedTaxon, includedRelationships, null, includeUnpublished, null, null, null);
866
        }
867
868
        taxa.add(associatedTaxon);
869
870
        for (Taxon taxon : taxa) {
871 ee6e05c9 Katja Luther
            List<SpecimenOrObservationBase> perTaxonOccurrences = dao.listByAssociatedTaxon(null,taxon, null, null, null, DERIVED_UNIT_INIT_STRATEGY);
872 6b53ead8 Katja Luther
            for (SpecimenOrObservationBase<?> o : perTaxonOccurrences) {
873
                if (o.isInstanceOf(DerivedUnit.class)){
874 a7e45124 Katja Luther
                    DerivedUnit derivedUnit;
875
                    DerivateDTO derivedUnitDTO;
876
                    if (o.isInstanceOf(DnaSample.class)) {
877
                         derivedUnit = HibernateProxyHelper.deproxy(o, DnaSample.class);
878
                        derivedUnitDTO = new DNASampleDTO(derivedUnit);
879
                    } else {
880
                        derivedUnit = HibernateProxyHelper.deproxy(o, DerivedUnit.class);
881 484a120f Katja Luther
                        derivedUnitDTO = new PreservedSpecimenDTO(derivedUnit);
882 a7e45124 Katja Luther
                    }
883 6b53ead8 Katja Luther
                    if (alreadyCollectedSpecimen.get(derivedUnitDTO.getUuid()) == null){
884
                        alreadyCollectedSpecimen.put(derivedUnitDTO.getUuid(), derivedUnitDTO);
885
                    }
886
                    derivedUnitDTO.addAllDerivates(getDerivedUnitDTOsFor(derivedUnitDTO, derivedUnit, alreadyCollectedSpecimen));
887
                    this.findFieldUnitDTO(derivedUnitDTO, fieldUnitDTOs, alreadyCollectedSpecimen);
888
                }
889
            }
890
891
        }
892
893
        return fieldUnitDTOs;
894
895
    }
896
897 a7e45124 Katja Luther
898
899 f2716206 Katja Luther
    @Override
900
    public  List<DerivedUnit> findByAccessionNumber(
901
            String accessionNumberString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
902
            List<String> propertyPaths)  {
903
904
        List<DerivedUnit> records = new ArrayList<>();
905 6b53ead8 Katja Luther
        records = dao.findByGeneticAccessionNumber(accessionNumberString, propertyPaths);
906 f2716206 Katja Luther
907
        return records;
908
909
    }
910
911 887126ca Andreas Müller
    @Override
912
    public Pager<SearchResult<SpecimenOrObservationBase>> findByFullText(
913
            Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle boundingBox, List<Language> languages,
914
            boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
915 3ca8a283 Patrick Plitzner
            List<String> propertyPaths) throws IOException, LuceneParseException {
916 887126ca Andreas Müller
917
        LuceneSearch luceneSearch = prepareByFullTextSearch(clazz, queryString, boundingBox, languages, highlightFragments);
918
919
        // --- execute search
920 3ca8a283 Patrick Plitzner
        TopGroups<BytesRef> topDocsResultSet;
921
        try {
922
            topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);
923
        } catch (ParseException e) {
924
            LuceneParseException parseException = new LuceneParseException(e.getMessage());
925
            parseException.setStackTrace(e.getStackTrace());
926
            throw parseException;
927
        }
928 887126ca Andreas Müller
929 7e7e032e Andreas Müller
        Map<CdmBaseType, String> idFieldMap = new HashMap<>();
930 887126ca Andreas Müller
        idFieldMap.put(CdmBaseType.SPECIMEN_OR_OBSERVATIONBASE, "id");
931
932
        // --- initialize taxa, highlight matches ....
933
        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
934
        @SuppressWarnings("rawtypes")
935
        List<SearchResult<SpecimenOrObservationBase>> searchResults = searchResultBuilder.createResultSet(
936
                topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);
937
938 57ea8a3a Andreas Kohlbecker
        int totalHits = topDocsResultSet != null ? topDocsResultSet.totalGroupCount : 0;
939 887126ca Andreas Müller
940 9a21de1f Andreas Müller
        return new DefaultPagerImpl<>(pageNumber, Long.valueOf(totalHits), pageSize, searchResults);
941 887126ca Andreas Müller
942
    }
943
944
    private LuceneSearch prepareByFullTextSearch(Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle bbox,
945
            List<Language> languages, boolean highlightFragments) {
946
947 f6b282fc Andreas Kohlbecker
        Builder finalQueryBuilder = new Builder();
948
        Builder textQueryBuilder = new Builder();
949 887126ca Andreas Müller
950
        LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, FieldUnit.class);
951
        QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(FieldUnit.class);
952
953
        // --- criteria
954
        luceneSearch.setCdmTypRestriction(clazz);
955
        if (queryString != null) {
956 f6b282fc Andreas Kohlbecker
            textQueryBuilder.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);
957
            finalQueryBuilder.add(textQueryBuilder.build(), Occur.MUST);
958 887126ca Andreas Müller
        }
959
960
        // --- spacial query
961
        if (bbox != null) {
962 f6b282fc Andreas Kohlbecker
            finalQueryBuilder.add(QueryFactory.buildSpatialQueryByRange(bbox, "gatheringEvent.exactLocation.point"), Occur.MUST);
963 887126ca Andreas Müller
        }
964
965 f6b282fc Andreas Kohlbecker
        luceneSearch.setQuery(finalQueryBuilder.build());
966 887126ca Andreas Müller
967
        // --- sorting
968 2622a38b Andreas Müller
        SortField[] sortFields = new SortField[] { SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.Type.STRING, false) };
969 887126ca Andreas Müller
        luceneSearch.setSortFields(sortFields);
970
971
        if (highlightFragments) {
972
            luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
973
        }
974
        return luceneSearch;
975
    }
976
977
978
    @Override
979 6b53ead8 Katja Luther
    public Collection<FieldUnit> findFieldUnits(UUID derivedUnitUuid, List<String> propertyPaths) {
980 887126ca Andreas Müller
        //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})
981
        //from which this DerivedUnit was derived until all FieldUnits are found.
982
983
        // FIXME: use HQL queries to increase performance
984 42002c0a Patrick Plitzner
        SpecimenOrObservationBase<?> specimen = load(derivedUnitUuid, propertyPaths);
985 887126ca Andreas Müller
//        specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
986 7e7e032e Andreas Müller
        Collection<FieldUnit> fieldUnits = new ArrayList<>();
987 887126ca Andreas Müller
988
        if (specimen.isInstanceOf(FieldUnit.class)) {
989
            fieldUnits.add(HibernateProxyHelper.deproxy(specimen, FieldUnit.class));
990
        }
991
        else if(specimen.isInstanceOf(DerivedUnit.class)){
992 42002c0a Patrick Plitzner
            fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class), propertyPaths));
993 887126ca Andreas Müller
        }
994
        return fieldUnits;
995
    }
996
997 42002c0a Patrick Plitzner
    private Collection<FieldUnit> getFieldUnits(DerivedUnit derivedUnit, List<String> propertyPaths) {
998 7e7e032e Andreas Müller
        Collection<FieldUnit> fieldUnits = new HashSet<>();
999 887126ca Andreas Müller
        Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals();
1000
        if (originals != null && !originals.isEmpty()) {
1001
            for (SpecimenOrObservationBase<?> original : originals) {
1002
                if (original.isInstanceOf(FieldUnit.class)) {
1003 42002c0a Patrick Plitzner
                    fieldUnits.add((FieldUnit) load(original.getUuid(), propertyPaths));
1004 887126ca Andreas Müller
                }
1005
                else if(original.isInstanceOf(DerivedUnit.class)){
1006 42002c0a Patrick Plitzner
                    fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(original, DerivedUnit.class), propertyPaths));
1007 887126ca Andreas Müller
                }
1008
            }
1009
        }
1010
        return fieldUnits;
1011
    }
1012
1013 abfe22d1 Katja Luther
1014 d70a126f Katja Luther
1015
    @Override
1016 6b53ead8 Katja Luther
    public FieldUnitDTO findFieldUnitDTO(DerivateDTO derivedUnitDTO, Collection<FieldUnitDTO> fieldUnits, HashMap<UUID, DerivateDTO> alreadyCollectedSpecimen) {
1017
        //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})
1018
        //from which this DerivedUnit was derived until all FieldUnits are found.
1019
        List<SpecimenOrObservationBase> specimens = new ArrayList<>();
1020
        List<String> propertyPaths = new ArrayList<>();
1021 c31ff29d Katja Luther
1022 6b53ead8 Katja Luther
        propertyPaths.add("descriptions.elements.media.title");
1023 c31ff29d Katja Luther
        propertyPaths.add("kindOfUnit");
1024 6b53ead8 Katja Luther
1025
        specimens = dao.findOriginalsForDerivedUnit(derivedUnitDTO.getUuid(), propertyPaths);
1026 abfe22d1 Katja Luther
1027 6b53ead8 Katja Luther
        if (specimens.size() > 1){
1028
            logger.debug("The derived unit with uuid " + derivedUnitDTO.getUuid() + "has more than one orginal");
1029
        }
1030
      //  for (SpecimenOrObservationBase specimen: specimens){
1031
        SpecimenOrObservationBase specimen = null;
1032
        if (specimens.size() > 0){
1033
            specimen = specimens.get(0);
1034
        }else{
1035
            return null;
1036
        }
1037
        FieldUnitDTO fieldUnitDto = null;
1038
        if (alreadyCollectedSpecimen.get(specimen.getUuid()) != null){
1039
            alreadyCollectedSpecimen.get(specimen.getUuid()).addDerivate(derivedUnitDTO);
1040
            if ( alreadyCollectedSpecimen.get(specimen.getUuid()) instanceof FieldUnitDTO){
1041
                ((FieldUnitDTO)alreadyCollectedSpecimen.get(specimen.getUuid())).getTaxonRelatedDerivedUnits().add(derivedUnitDTO.getUuid());
1042
            }
1043
        }else{
1044
            if (specimen.isInstanceOf(FieldUnit.class)){
1045
                fieldUnitDto = FieldUnitDTO.newInstance((FieldUnit)specimen);
1046 77993547 Katja Luther
                fieldUnitDto.addDerivate(derivedUnitDTO);
1047 6b53ead8 Katja Luther
                fieldUnits.add(fieldUnitDto);
1048
            }else{
1049 a7e45124 Katja Luther
                DerivateDTO originalDTO;
1050
                if (specimen instanceof DnaSample){
1051
                    originalDTO = new DNASampleDTO((DnaSample)specimen);
1052
                } else {
1053 484a120f Katja Luther
                    originalDTO = new PreservedSpecimenDTO((DerivedUnit)specimen);
1054 a7e45124 Katja Luther
                }
1055 6b53ead8 Katja Luther
                originalDTO.addDerivate(derivedUnitDTO);
1056
                fieldUnitDto = findFieldUnitDTO(originalDTO, fieldUnits, alreadyCollectedSpecimen);
1057
            }
1058
1059
        }
1060
      //  }
1061
        alreadyCollectedSpecimen.put(derivedUnitDTO.getUuid(), derivedUnitDTO);
1062 abfe22d1 Katja Luther
        if (fieldUnitDto != null){
1063
            fieldUnitDto.addTaxonRelatedDerivedUnits(derivedUnitDTO);
1064
        }
1065 6b53ead8 Katja Luther
        return fieldUnitDto;
1066 abfe22d1 Katja Luther
1067 6b53ead8 Katja Luther
    }
1068
1069 887126ca Andreas Müller
    @Override
1070
    @Transactional(readOnly = false)
1071
    public UpdateResult moveSequence(DnaSample from, DnaSample to, Sequence sequence) {
1072
        return moveSequence(from.getUuid(), to.getUuid(), sequence.getUuid());
1073
    }
1074
1075
    @Override
1076
    @Transactional(readOnly = false)
1077
    public UpdateResult moveSequence(UUID fromUuid, UUID toUuid, UUID sequenceUuid) {
1078
        // reload specimens to avoid session conflicts
1079
        DnaSample from = (DnaSample) load(fromUuid);
1080
        DnaSample to = (DnaSample) load(toUuid);
1081
        Sequence sequence = sequenceService.load(sequenceUuid);
1082
1083
        if (from == null || to == null || sequence == null) {
1084
            throw new TransientObjectException("One of the CDM entities has not been saved to the data base yet. Moving only works for persisted/saved CDM entities.\n" +
1085
                    "Operation was move "+sequence+ " from "+from+" to "+to);
1086
        }
1087
        UpdateResult result = new UpdateResult();
1088
        from.removeSequence(sequence);
1089
        saveOrUpdate(from);
1090
        to.addSequence(sequence);
1091
        saveOrUpdate(to);
1092
        result.setStatus(Status.OK);
1093
        result.addUpdatedObject(from);
1094
        result.addUpdatedObject(to);
1095
        return result;
1096
    }
1097
1098
    @Override
1099
    @Transactional(readOnly = false)
1100
    public boolean moveDerivate(SpecimenOrObservationBase<?> from, SpecimenOrObservationBase<?> to, DerivedUnit derivate) {
1101 55e09b37 Patrick Plitzner
        return moveDerivate(from!=null?from.getUuid():null, to.getUuid(), derivate.getUuid()).isOk();
1102 887126ca Andreas Müller
    }
1103
1104
    @Override
1105
    @Transactional(readOnly = false)
1106
    public UpdateResult moveDerivate(UUID specimenFromUuid, UUID specimenToUuid, UUID derivateUuid) {
1107
        // reload specimens to avoid session conflicts
1108 55e09b37 Patrick Plitzner
        SpecimenOrObservationBase<?> from = null;
1109
        if(specimenFromUuid!=null){
1110
            from = load(specimenFromUuid);
1111
        }
1112 887126ca Andreas Müller
        SpecimenOrObservationBase<?> to = load(specimenToUuid);
1113
        DerivedUnit derivate = (DerivedUnit) load(derivateUuid);
1114
1115 55e09b37 Patrick Plitzner
        if ((specimenFromUuid!=null && from == null) || to == null || derivate == null) {
1116 887126ca Andreas Müller
            throw new TransientObjectException("One of the CDM entities has not been saved to the data base yet. Moving only works for persisted/saved CDM entities.\n" +
1117 eec2d79d Andreas Müller
                    "Operation was move "+derivate+ " from "+from+" to "+to);
1118 887126ca Andreas Müller
        }
1119
        UpdateResult result = new UpdateResult();
1120
        SpecimenOrObservationType derivateType = derivate.getRecordBasis();
1121
        SpecimenOrObservationType toType = to.getRecordBasis();
1122
        // check if type is a sub derivate type
1123
        if(toType==SpecimenOrObservationType.FieldUnit //moving to FieldUnit always works
1124
                || derivateType==SpecimenOrObservationType.Media //moving media always works
1125
                || (derivateType.isKindOf(toType) && toType!=derivateType)){ //moving only to parent derivate type
1126 55e09b37 Patrick Plitzner
            if(from!=null){
1127
                // remove derivation event from parent specimen of dragged object
1128
                DerivationEvent eventToRemove = null;
1129
                for (DerivationEvent event : from.getDerivationEvents()) {
1130
                    if (event.getDerivatives().contains(derivate)) {
1131
                        eventToRemove = event;
1132
                        break;
1133
                    }
1134
                }
1135
                from.removeDerivationEvent(eventToRemove);
1136
                if(eventToRemove!=null){
1137
                    // add new derivation event to target and copy the event parameters of the old one
1138
                    DerivationEvent derivedFromNewOriginalEvent = DerivationEvent.NewSimpleInstance(to, derivate, null);
1139
                    derivedFromNewOriginalEvent.setActor(eventToRemove.getActor());
1140
                    derivedFromNewOriginalEvent.setDescription(eventToRemove.getDescription());
1141
                    derivedFromNewOriginalEvent.setInstitution(eventToRemove.getInstitution());
1142
                    derivedFromNewOriginalEvent.setTimeperiod(eventToRemove.getTimeperiod());
1143
                    derivedFromNewOriginalEvent.setType(eventToRemove.getType());
1144
                    to.addDerivationEvent(derivedFromNewOriginalEvent);
1145
                    derivate.setDerivedFrom(derivedFromNewOriginalEvent);
1146 887126ca Andreas Müller
                }
1147
            }
1148 55e09b37 Patrick Plitzner
            else{
1149
                //derivative had no parent before so we use empty derivation event
1150 887126ca Andreas Müller
                DerivationEvent derivedFromNewOriginalEvent = DerivationEvent.NewSimpleInstance(to, derivate, null);
1151
                to.addDerivationEvent(derivedFromNewOriginalEvent);
1152
                derivate.setDerivedFrom(derivedFromNewOriginalEvent);
1153
            }
1154
1155 d11716c6 Patrick Plitzner
            if(from!=null){
1156
                saveOrUpdate(from);
1157
            }
1158 887126ca Andreas Müller
            saveOrUpdate(to);
1159
            result.setStatus(Status.OK);
1160
            result.addUpdatedObject(from);
1161
            result.addUpdatedObject(to);
1162
        } else {
1163
            result.setStatus(Status.ERROR);
1164
        }
1165
        return result;
1166
    }
1167
1168
    @Override
1169 645658b9 Katja Luther
    public DeleteResult isDeletable(UUID specimenUuid, DeleteConfiguratorBase config) {
1170 887126ca Andreas Müller
        DeleteResult deleteResult = new DeleteResult();
1171 645658b9 Katja Luther
        SpecimenOrObservationBase specimen = this.load(specimenUuid);
1172 887126ca Andreas Müller
        SpecimenDeleteConfigurator specimenDeleteConfigurator = (SpecimenDeleteConfigurator) config;
1173
1174
        // check elements found by super method
1175 645658b9 Katja Luther
        Set<CdmBase> relatedObjects = super.isDeletable(specimenUuid, config).getRelatedObjects();
1176 887126ca Andreas Müller
        for (CdmBase cdmBase : relatedObjects) {
1177
            // check for type designation
1178
            if (cdmBase.isInstanceOf(SpecimenTypeDesignation.class) && !specimenDeleteConfigurator.isDeleteFromTypeDesignation()) {
1179
                deleteResult.setAbort();
1180 56897765 Patrick Plitzner
                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen or obeservation is a type specimen."));
1181 887126ca Andreas Müller
                deleteResult.addRelatedObject(cdmBase);
1182
                break;
1183
            }
1184
            // check for IndividualsAssociations
1185
            else if (cdmBase.isInstanceOf(IndividualsAssociation.class) && !specimenDeleteConfigurator.isDeleteFromIndividualsAssociation()) {
1186
                deleteResult.setAbort();
1187 56897765 Patrick Plitzner
                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen or obeservation is still associated via IndividualsAssociations"));
1188 887126ca Andreas Müller
                deleteResult.addRelatedObject(cdmBase);
1189
                break;
1190
            }
1191 651c925a Patrick Plitzner
            // check for taxon description
1192
            else if(cdmBase.isInstanceOf(TaxonDescription.class)
1193
                    && HibernateProxyHelper.deproxy(cdmBase, TaxonDescription.class).getDescribedSpecimenOrObservation().equals(specimen)
1194 887126ca Andreas Müller
                    && !specimenDeleteConfigurator.isDeleteFromDescription()){
1195
                deleteResult.setAbort();
1196 56897765 Patrick Plitzner
                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen or obeservation is still used as \"Described Specimen\" in a taxon description."));
1197 887126ca Andreas Müller
                deleteResult.addRelatedObject(cdmBase);
1198
                break;
1199
            }
1200
            // check for children and parents (derivation events)
1201
            else if (cdmBase.isInstanceOf(DerivationEvent.class)) {
1202
                DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(cdmBase, DerivationEvent.class);
1203
                // check if derivation event is empty
1204 4a1ab701 Katja Luther
                if (!derivationEvent.getDerivatives().isEmpty() && derivationEvent.getOriginals().contains(specimen)) {
1205
                    // if derivationEvent is the childEvent and contains derivations
1206
//                    if (derivationEvent.getDerivatives().contains(specimen)) {
1207
//                        //if it is the parent event the specimen is still deletable
1208
//                        continue;
1209
//                    }
1210
                    if(!specimenDeleteConfigurator.isDeleteChildren()){
1211
                        //if children should not be deleted then it is undeletable
1212 887126ca Andreas Müller
                        deleteResult.setAbort();
1213 56897765 Patrick Plitzner
                        deleteResult.addException(new ReferencedObjectUndeletableException("Specimen or obeservation still has child derivatives."));
1214 887126ca Andreas Müller
                        deleteResult.addRelatedObject(cdmBase);
1215
                        break;
1216
                    }
1217
                    else{
1218
                        // check all children if they can be deleted
1219
                        Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
1220
                        DeleteResult childResult = new DeleteResult();
1221
                        for (DerivedUnit derivedUnit : derivatives) {
1222 645658b9 Katja Luther
                            childResult.includeResult(isDeletable(derivedUnit.getUuid(), specimenDeleteConfigurator));
1223 887126ca Andreas Müller
                        }
1224
                        if (!childResult.isOk()) {
1225
                            deleteResult.setAbort();
1226
                            deleteResult.includeResult(childResult);
1227
                            deleteResult.addRelatedObject(cdmBase);
1228
                            break;
1229
                        }
1230
                    }
1231
                }
1232
            }
1233
            // check for amplification
1234 651c925a Patrick Plitzner
            else if (cdmBase.isInstanceOf(AmplificationResult.class)
1235
                    && !specimenDeleteConfigurator.isDeleteMolecularData()
1236
                    && !specimenDeleteConfigurator.isDeleteChildren()) {
1237 887126ca Andreas Müller
                deleteResult.setAbort();
1238
                deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in amplification results."));
1239
                deleteResult.addRelatedObject(cdmBase);
1240
                break;
1241
            }
1242
            // check for sequence
1243 651c925a Patrick Plitzner
            else if (cdmBase.isInstanceOf(Sequence.class)
1244
                    && !specimenDeleteConfigurator.isDeleteMolecularData()
1245
                    && !specimenDeleteConfigurator.isDeleteChildren()) {
1246 887126ca Andreas Müller
                deleteResult.setAbort();
1247
                deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in sequences."));
1248
                deleteResult.addRelatedObject(cdmBase);
1249
                break;
1250
            }
1251
        }
1252
        if (deleteResult.isOk()) {
1253
            //add all related object if deletion is OK so they can be handled by the delete() method
1254
            deleteResult.addRelatedObjects(relatedObjects);
1255
        }
1256
        return deleteResult;
1257
    }
1258
1259 f2fdced6 Patrick Plitzner
    /**
1260
     * {@inheritDoc}
1261
     */
1262 eb3c2286 Patrick Plitzner
    @Transactional(readOnly = false)
1263 f2fdced6 Patrick Plitzner
    @Override
1264
    public DeleteResult delete(UUID specimenUuid, SpecimenDeleteConfigurator config) {
1265
        return delete(load(specimenUuid), config);
1266
    }
1267
1268 eb3c2286 Patrick Plitzner
1269
    @Transactional(readOnly = false)
1270 887126ca Andreas Müller
    @Override
1271
    public DeleteResult delete(SpecimenOrObservationBase<?> specimen, SpecimenDeleteConfigurator config) {
1272
        specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
1273
1274 a9c2b3c3 Katja Luther
        DeleteResult deleteResult = isDeletable(specimen.getUuid(), config);
1275
        if (!deleteResult.isOk()) {
1276
            return deleteResult;
1277
        }
1278
1279 887126ca Andreas Müller
        if (config.isDeleteChildren()) {
1280
            Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();
1281
            //clone to avoid concurrent modification
1282
            //can happen if the child is deleted and deleted its own derivedFrom event
1283 7e7e032e Andreas Müller
            Set<DerivationEvent> derivationEventsClone = new HashSet<>(derivationEvents);
1284 887126ca Andreas Müller
            for (DerivationEvent derivationEvent : derivationEventsClone) {
1285
                Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
1286 09a260bb Katja Luther
                Iterator<DerivedUnit> it = derivatives.iterator();
1287
                Set<DerivedUnit> derivativesToDelete = new HashSet<>();
1288
                while (it.hasNext()) {
1289
                    DerivedUnit unit = it.next();
1290
                    derivativesToDelete.add(unit);
1291
                }
1292
                for (DerivedUnit unit:derivativesToDelete){
1293 bd1626d9 Patrick Plitzner
                    deleteResult.includeResult(delete(unit, config));
1294 887126ca Andreas Müller
                }
1295
            }
1296
        }
1297
1298 07dbf1bc Katja Luther
1299
1300 887126ca Andreas Müller
1301
        // check related objects
1302
        Set<CdmBase> relatedObjects = deleteResult.getRelatedObjects();
1303
1304
        for (CdmBase relatedObject : relatedObjects) {
1305
            // check for TypeDesignations
1306
            if (relatedObject.isInstanceOf(SpecimenTypeDesignation.class)) {
1307
                SpecimenTypeDesignation designation = HibernateProxyHelper.deproxy(relatedObject, SpecimenTypeDesignation.class);
1308
                designation.setTypeSpecimen(null);
1309 9dc896c9 Andreas Müller
                List<TaxonName> typifiedNames = new ArrayList<>();
1310 4a1ab701 Katja Luther
                typifiedNames.addAll(designation.getTypifiedNames());
1311 9dc896c9 Andreas Müller
                for (TaxonName taxonName : typifiedNames) {
1312
                    taxonName.removeTypeDesignation(designation);
1313 887126ca Andreas Müller
                }
1314
            }
1315
            // delete IndividualsAssociation
1316
            if (relatedObject.isInstanceOf(IndividualsAssociation.class)) {
1317 4a1ab701 Katja Luther
                IndividualsAssociation association = HibernateProxyHelper.deproxy(relatedObject, IndividualsAssociation.class);
1318
                association.setAssociatedSpecimenOrObservation(null);
1319
                association.getInDescription().removeElement(association);
1320 887126ca Andreas Müller
            }
1321 651c925a Patrick Plitzner
            // check for "described specimen" (deprecated)
1322 887126ca Andreas Müller
            if (relatedObject.isInstanceOf(TaxonDescription.class)) {
1323 651c925a Patrick Plitzner
                TaxonDescription description = HibernateProxyHelper.deproxy(relatedObject, TaxonDescription.class);
1324
                description.setDescribedSpecimenOrObservation(null);
1325 887126ca Andreas Müller
            }
1326
            // check for specimen description
1327
            if (relatedObject.isInstanceOf(SpecimenDescription.class)) {
1328
                SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(relatedObject, SpecimenDescription.class);
1329 651c925a Patrick Plitzner
                specimenDescription.setDescribedSpecimenOrObservation(null);
1330 887126ca Andreas Müller
                // check if description is a description of the given specimen
1331
                if (specimen.getDescriptions().contains(specimenDescription)) {
1332
                    specimen.removeDescription(specimenDescription);
1333
                }
1334 645658b9 Katja Luther
                DeleteResult descriptionDelete = descriptionService.isDeletable(specimenDescription.getUuid(), null);
1335 07c3eb13 Katja Luther
                if (descriptionDelete.isOk()){
1336 815a9015 Katja Luther
                    deleteResult.includeResult(descriptionService.delete(specimenDescription));
1337 07c3eb13 Katja Luther
                }
1338 887126ca Andreas Müller
            }
1339
            // check for amplification
1340
            if (relatedObject.isInstanceOf(AmplificationResult.class)) {
1341
                AmplificationResult amplificationResult = HibernateProxyHelper.deproxy(relatedObject, AmplificationResult.class);
1342
                amplificationResult.getDnaSample().removeAmplificationResult(amplificationResult);
1343
            }
1344
            // check for sequence
1345
            if (relatedObject.isInstanceOf(Sequence.class)) {
1346
                Sequence sequence = HibernateProxyHelper.deproxy(relatedObject, Sequence.class);
1347
                sequence.getDnaSample().removeSequence(sequence);
1348
            }
1349
            // check for children and parents (derivation events)
1350
            if (relatedObject.isInstanceOf(DerivationEvent.class)) {
1351
                DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(relatedObject, DerivationEvent.class);
1352
                // parent derivation event (derivedFrom)
1353
                if (derivationEvent.getDerivatives().contains(specimen) && specimen.isInstanceOf(DerivedUnit.class)) {
1354
                    derivationEvent.removeDerivative(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class));
1355
                    if (derivationEvent.getDerivatives().isEmpty()) {
1356
                        Set<SpecimenOrObservationBase> originals = derivationEvent.getOriginals();
1357
                        for (SpecimenOrObservationBase specimenOrObservationBase : originals) {
1358
                            specimenOrObservationBase.removeDerivationEvent(derivationEvent);
1359
                            deleteResult.addUpdatedObject(specimenOrObservationBase);
1360
                        }
1361 a9c2b3c3 Katja Luther
                        // if derivationEvent has no derivates anymore, delete it
1362 815a9015 Katja Luther
                        deleteResult.includeResult(eventService.delete(derivationEvent));
1363 887126ca Andreas Müller
                    }
1364
                }
1365
                else{
1366
                    //child derivation events should not occur since we delete the hierarchy from bottom to top
1367
                }
1368
            }
1369
        }
1370 07dbf1bc Katja Luther
        if (specimen instanceof FieldUnit){
1371
            FieldUnit fieldUnit = HibernateProxyHelper.deproxy(specimen, FieldUnit.class);
1372
            GatheringEvent event = fieldUnit.getGatheringEvent();
1373
            fieldUnit.setGatheringEvent(null);
1374 8f5a9520 Katja Luther
            if (event != null){
1375
                DeleteResult result = eventService.isDeletable(event.getUuid(), null);
1376
                if (result.isOk()){
1377 815a9015 Katja Luther
                    deleteResult.includeResult( eventService.delete(event));
1378 8f5a9520 Katja Luther
                }
1379
            }
1380 07dbf1bc Katja Luther
1381
        }
1382 887126ca Andreas Müller
        deleteResult.includeResult(delete(specimen));
1383 eb3c2286 Patrick Plitzner
1384 887126ca Andreas Müller
        return deleteResult;
1385
    }
1386
1387
    @Override
1388
    public Collection<IndividualsAssociation> listIndividualsAssociations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1389 42002c0a Patrick Plitzner
        return dao.listIndividualsAssociations(specimen, limit, start, orderHints, propertyPaths);
1390 887126ca Andreas Müller
    }
1391
1392 12b3d645 Andreas Müller
    /**
1393
     * {@inheritDoc}
1394
     */
1395 b6b6d586 Patrick Plitzner
    @Override
1396 12b3d645 Andreas Müller
    public Collection<TaxonBase<?>> listAssociatedTaxa(SpecimenOrObservationBase<?> specimen, Integer limit,
1397
            Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1398
        return listAssociatedTaxa(specimen, INCLUDE_UNPUBLISHED, limit, start, orderHints, propertyPaths);
1399
    }
1400
    @Override
1401
    public Collection<TaxonBase<?>> listAssociatedTaxa(SpecimenOrObservationBase<?> specimen, boolean includeUnpublished,
1402
            Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1403 7e7e032e Andreas Müller
        Collection<TaxonBase<?>> associatedTaxa = new HashSet<>();
1404 550eeb6f Patrick Plitzner
1405
        //individuals associations
1406 12b3d645 Andreas Müller
        associatedTaxa.addAll(listIndividualsAssociationTaxa(specimen, includeUnpublished, limit, start, orderHints, propertyPaths));
1407 40b943c7 Patrick Plitzner
        //type designation
1408 95964a96 Patrick Plitzner
        if(specimen.isInstanceOf(DerivedUnit.class)){
1409 12b3d645 Andreas Müller
            associatedTaxa.addAll(listTypeDesignationTaxa(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class),
1410
                  includeUnpublished, limit, start, orderHints, propertyPaths));
1411 95964a96 Patrick Plitzner
        }
1412 40b943c7 Patrick Plitzner
        //determinations
1413 12b3d645 Andreas Müller
        associatedTaxa.addAll(listDeterminedTaxa(specimen, includeUnpublished, limit, start, orderHints, propertyPaths));
1414 40b943c7 Patrick Plitzner
1415
        return associatedTaxa;
1416
    }
1417
1418
1419 12b3d645 Andreas Müller
1420
    /**
1421
     * {@inheritDoc}
1422
     */
1423 40b943c7 Patrick Plitzner
    @Override
1424 12b3d645 Andreas Müller
    public Collection<TaxonBase<?>> listDeterminedTaxa(SpecimenOrObservationBase<?> specimen, Integer limit,
1425
            Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1426
        return listDeterminedTaxa(specimen, INCLUDE_UNPUBLISHED, limit, start, orderHints, propertyPaths);
1427
    }
1428
    @Override
1429
    public Collection<TaxonBase<?>> listDeterminedTaxa(SpecimenOrObservationBase<?> specimen, boolean includeUnpublished, Integer limit, Integer start,
1430 40b943c7 Patrick Plitzner
            List<OrderHint> orderHints, List<String> propertyPaths) {
1431 7e7e032e Andreas Müller
        Collection<TaxonBase<?>> associatedTaxa = new HashSet<>();
1432 40b943c7 Patrick Plitzner
        for (DeterminationEvent determinationEvent : listDeterminationEvents(specimen, limit, start, orderHints, propertyPaths)) {
1433
            if(determinationEvent.getIdentifiedUnit().equals(specimen)){
1434
                if(determinationEvent.getTaxon()!=null){
1435 12b3d645 Andreas Müller
                    associatedTaxa.add(taxonService.load(determinationEvent.getTaxon().getUuid(), includeUnpublished, propertyPaths));
1436 40b943c7 Patrick Plitzner
                }
1437
                if(determinationEvent.getTaxonName()!=null){
1438 42002c0a Patrick Plitzner
                    Collection<TaxonBase> taxonBases = determinationEvent.getTaxonName().getTaxonBases();
1439
                    for (TaxonBase taxonBase : taxonBases) {
1440 12b3d645 Andreas Müller
                        associatedTaxa.add(taxonService.load(taxonBase.getUuid(), includeUnpublished, propertyPaths));
1441 42002c0a Patrick Plitzner
                    }
1442 550eeb6f Patrick Plitzner
                }
1443 b6b6d586 Patrick Plitzner
            }
1444
        }
1445 40b943c7 Patrick Plitzner
        return associatedTaxa;
1446
    }
1447
1448 12b3d645 Andreas Müller
    /**
1449
     * {@inheritDoc}
1450
     */
1451 40b943c7 Patrick Plitzner
    @Override
1452 95964a96 Patrick Plitzner
    public Collection<TaxonBase<?>> listTypeDesignationTaxa(DerivedUnit specimen, Integer limit, Integer start,
1453 40b943c7 Patrick Plitzner
            List<OrderHint> orderHints, List<String> propertyPaths) {
1454 12b3d645 Andreas Müller
        return listTypeDesignationTaxa(specimen, INCLUDE_UNPUBLISHED, limit, start, orderHints, propertyPaths);
1455
    }
1456
    @Override
1457
    public Collection<TaxonBase<?>> listTypeDesignationTaxa(DerivedUnit specimen, boolean includeUnpublished,
1458
            Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1459 7e7e032e Andreas Müller
        Collection<TaxonBase<?>> associatedTaxa = new HashSet<>();
1460 eeef091f Patrick Plitzner
        for (SpecimenTypeDesignation typeDesignation : listTypeDesignations(specimen, limit, start, orderHints, propertyPaths)) {
1461
            if(typeDesignation.getTypeSpecimen().equals(specimen)){
1462 9dc896c9 Andreas Müller
                Set<TaxonName> typifiedNames = typeDesignation.getTypifiedNames();
1463
                for (TaxonName taxonName : typifiedNames) {
1464 42002c0a Patrick Plitzner
                    Set<Taxon> taxa = taxonName.getTaxa();
1465
                    for (Taxon taxon : taxa) {
1466 12b3d645 Andreas Müller
                        associatedTaxa.add(taxonService.load(taxon.getUuid(), includeUnpublished, propertyPaths));
1467 42002c0a Patrick Plitzner
                    }
1468 eeef091f Patrick Plitzner
                }
1469
            }
1470
        }
1471 40b943c7 Patrick Plitzner
        return associatedTaxa;
1472
    }
1473
1474 12b3d645 Andreas Müller
    /**
1475
     * {@inheritDoc}
1476
     */
1477
    @Override
1478
    public Collection<TaxonBase<?>> listIndividualsAssociationTaxa(SpecimenOrObservationBase<?> specimen, Integer limit,
1479
            Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1480
        return listIndividualsAssociationTaxa(specimen, INCLUDE_UNPUBLISHED, limit, start, orderHints, propertyPaths);
1481
    }
1482
1483 40b943c7 Patrick Plitzner
    @Override
1484 12b3d645 Andreas Müller
    public Collection<TaxonBase<?>> listIndividualsAssociationTaxa(SpecimenOrObservationBase<?> specimen, boolean includeUnpublished,
1485
            Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1486 7e7e032e Andreas Müller
        Collection<TaxonBase<?>> associatedTaxa = new HashSet<>();
1487 42002c0a Patrick Plitzner
        for (IndividualsAssociation individualsAssociation : listIndividualsAssociations(specimen, null, null, null, null)) {
1488 40b943c7 Patrick Plitzner
            if(individualsAssociation.getInDescription().isInstanceOf(TaxonDescription.class)){
1489
                TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(individualsAssociation.getInDescription(), TaxonDescription.class);
1490
                if(taxonDescription.getTaxon()!=null){
1491 12b3d645 Andreas Müller
                    associatedTaxa.add(taxonService.load(taxonDescription.getTaxon().getUuid(), includeUnpublished, propertyPaths));
1492 550eeb6f Patrick Plitzner
                }
1493
            }
1494
        }
1495 b6b6d586 Patrick Plitzner
        return associatedTaxa;
1496
    }
1497
1498 550eeb6f Patrick Plitzner
    @Override
1499
    public Collection<DeterminationEvent> listDeterminationEvents(SpecimenOrObservationBase<?> specimen,
1500
            Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1501
        return dao.listDeterminationEvents(specimen, limit, start, orderHints, propertyPaths);
1502
    }
1503
1504 887126ca Andreas Müller
    @Override
1505 95964a96 Patrick Plitzner
    public Map<DerivedUnit, Collection<SpecimenTypeDesignation>> listTypeDesignations(
1506
            Collection<DerivedUnit> specimens, Integer limit, Integer start,
1507
            List<OrderHint> orderHints, List<String> propertyPaths) {
1508 7e7e032e Andreas Müller
        Map<DerivedUnit, Collection<SpecimenTypeDesignation>> typeDesignationMap = new HashMap<>();
1509 95964a96 Patrick Plitzner
        for (DerivedUnit specimen : specimens) {
1510
            Collection<SpecimenTypeDesignation> typeDesignations = listTypeDesignations(specimen, limit, start, orderHints, propertyPaths);
1511
            typeDesignationMap.put(specimen, typeDesignations);
1512
        }
1513
        return typeDesignationMap;
1514
    }
1515
1516
    @Override
1517
    public Collection<SpecimenTypeDesignation> listTypeDesignations(DerivedUnit specimen,
1518 887126ca Andreas Müller
            Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1519
        return dao.listTypeDesignations(specimen, limit, start, orderHints, propertyPaths);
1520
    }
1521
1522
    @Override
1523
    public Collection<DescriptionBase<?>> listDescriptionsWithDescriptionSpecimen(
1524
            SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints,
1525
            List<String> propertyPaths) {
1526
        return dao.listDescriptionsWithDescriptionSpecimen(specimen, limit, start, orderHints, propertyPaths);
1527
    }
1528
1529
    @Override
1530 45546a91 Andreas Müller
    @Deprecated //this is not a service layer task so it may be removed in future versions
1531 887126ca Andreas Müller
    public Collection<DescriptionElementBase> getCharacterDataForSpecimen(SpecimenOrObservationBase<?> specimen) {
1532
        if (specimen != null) {
1533
            return specimen.characterData();
1534
        }else{
1535 7e7e032e Andreas Müller
            return new ArrayList<>();
1536 887126ca Andreas Müller
        }
1537
    }
1538
1539
    @Override
1540
    public Collection<DescriptionElementBase> getCharacterDataForSpecimen(UUID specimenUuid) {
1541
        SpecimenOrObservationBase<?> specimen = load(specimenUuid);
1542
        if (specimen != null) {
1543
            return getCharacterDataForSpecimen(specimen);
1544
        }
1545
        else{
1546
            throw new DataRetrievalFailureException("Specimen with the given uuid not found in the data base");
1547
        }
1548
    }
1549
1550
1551 1c1517f9 Patrick Plitzner
    @Override
1552 9a21de1f Andreas Müller
    public long countByTitle(IIdentifiableEntityServiceConfigurator<SpecimenOrObservationBase> config){
1553 1c1517f9 Patrick Plitzner
        if (config instanceof FindOccurrencesConfigurator) {
1554
            FindOccurrencesConfigurator occurrenceConfig = (FindOccurrencesConfigurator) config;
1555
            Taxon taxon = null;
1556
            if(occurrenceConfig.getAssociatedTaxonUuid()!=null){
1557 9a21de1f Andreas Müller
                TaxonBase<?> taxonBase = taxonService.load(occurrenceConfig.getAssociatedTaxonUuid());
1558 1c1517f9 Patrick Plitzner
                if(taxonBase.isInstanceOf(Taxon.class)){
1559
                    taxon = HibernateProxyHelper.deproxy(taxonBase, Taxon.class);
1560
                }
1561
            }
1562 9dc896c9 Andreas Müller
            TaxonName taxonName = null;
1563 1c1517f9 Patrick Plitzner
            if(occurrenceConfig.getAssociatedTaxonNameUuid()!=null){
1564
                taxonName = nameService.load(occurrenceConfig.getAssociatedTaxonNameUuid());
1565
            }
1566 7dab8082 Patrick Plitzner
            /*TODO: #6484 Neither isRetrieveIndirectlyAssociatedSpecimens() nor the AssignmentStatus
1567
             * is currently reflected in the HQL query. So using these in the count method will
1568
             * significantly slow down this method as we have to retreive the entities instead of
1569
             * the just the amount.
1570
             */
1571
            if(occurrenceConfig.isRetrieveIndirectlyAssociatedSpecimens() || !occurrenceConfig.getAssignmentStatus().equals(AssignmentStatus.ALL_SPECIMENS)){
1572
                List<SpecimenOrObservationBase> occurrences = new ArrayList<>();
1573
                occurrences.addAll(dao.findOccurrences(occurrenceConfig.getClazz(),
1574 1e037cd6 Patrick Plitzner
                        occurrenceConfig.getTitleSearchStringSqlized(), occurrenceConfig.getSignificantIdentifier(),
1575 7dab8082 Patrick Plitzner
                        occurrenceConfig.getSpecimenType(), taxon, taxonName, occurrenceConfig.getMatchMode(), null, null,
1576
                        occurrenceConfig.getOrderHints(), occurrenceConfig.getPropertyPaths()));
1577
                occurrences = filterOccurencesByAssignmentAndHierarchy(occurrenceConfig, occurrences, taxon, taxonName);
1578
                return occurrences.size();
1579
            }
1580
1581 1c1517f9 Patrick Plitzner
            return dao.countOccurrences(occurrenceConfig.getClazz(),
1582 1e037cd6 Patrick Plitzner
                    occurrenceConfig.getTitleSearchStringSqlized(), occurrenceConfig.getSignificantIdentifier(),
1583 1c1517f9 Patrick Plitzner
                    occurrenceConfig.getSpecimenType(), taxon, taxonName, occurrenceConfig.getMatchMode(), null, null,
1584
                    occurrenceConfig.getOrderHints(), occurrenceConfig.getPropertyPaths());
1585
        }
1586
        else{
1587 1e037cd6 Patrick Plitzner
            return super.countByTitle(config);
1588 1c1517f9 Patrick Plitzner
        }
1589
    }
1590
1591 79c29018 Patrick Plitzner
    @Override
1592
    public Pager<UuidAndTitleCache<SpecimenOrObservationBase>> findByTitleUuidAndTitleCache(
1593
            FindOccurrencesConfigurator config){
1594
        List<UuidAndTitleCache<SpecimenOrObservationBase>> occurrences = new ArrayList<>();
1595
        Taxon taxon = null;
1596
        if(config.getAssociatedTaxonUuid()!=null){
1597 9a21de1f Andreas Müller
            TaxonBase<?> taxonBase = taxonService.load(config.getAssociatedTaxonUuid());
1598 79c29018 Patrick Plitzner
            if(taxonBase.isInstanceOf(Taxon.class)){
1599 f6df4cfb Andreas Müller
                taxon = CdmBase.deproxy(taxonBase, Taxon.class);
1600 79c29018 Patrick Plitzner
            }
1601
        }
1602
        TaxonName taxonName = null;
1603
        if(config.getAssociatedTaxonNameUuid()!=null){
1604
            taxonName = nameService.load(config.getAssociatedTaxonNameUuid());
1605
        }
1606
        occurrences.addAll(dao.findOccurrencesUuidAndTitleCache(config.getClazz(),
1607
                config.getTitleSearchString(), config.getSignificantIdentifier(),
1608
                config.getSpecimenType(), taxon, taxonName, config.getMatchMode(), null, null,
1609
                config.getOrderHints()));
1610
1611 f6df4cfb Andreas Müller
        return new DefaultPagerImpl<>(config.getPageNumber(), occurrences.size(), config.getPageSize(), occurrences);
1612 79c29018 Patrick Plitzner
    }
1613
1614 887126ca Andreas Müller
    @Override
1615 98ce4a92 Andreas Müller
    public <S extends SpecimenOrObservationBase> Pager<S> findByTitle(
1616
            IIdentifiableEntityServiceConfigurator<S> config) {
1617 887126ca Andreas Müller
        if (config instanceof FindOccurrencesConfigurator) {
1618
            FindOccurrencesConfigurator occurrenceConfig = (FindOccurrencesConfigurator) config;
1619 7e7e032e Andreas Müller
            List<SpecimenOrObservationBase> occurrences = new ArrayList<>();
1620 887126ca Andreas Müller
            Taxon taxon = null;
1621
            if(occurrenceConfig.getAssociatedTaxonUuid()!=null){
1622 f6df4cfb Andreas Müller
                TaxonBase<?> taxonBase = taxonService.load(occurrenceConfig.getAssociatedTaxonUuid());
1623 887126ca Andreas Müller
                if(taxonBase.isInstanceOf(Taxon.class)){
1624
                    taxon = HibernateProxyHelper.deproxy(taxonBase, Taxon.class);
1625
                }
1626
            }
1627 9dc896c9 Andreas Müller
            TaxonName taxonName = null;
1628 e6e5ebdc Patrick Plitzner
            if(occurrenceConfig.getAssociatedTaxonNameUuid()!=null){
1629 604df0ab Patrick Plitzner
                taxonName = nameService.load(occurrenceConfig.getAssociatedTaxonNameUuid());
1630 e6e5ebdc Patrick Plitzner
            }
1631 98ce4a92 Andreas Müller
            List<? extends SpecimenOrObservationBase> foundOccurrences = dao.findOccurrences(occurrenceConfig.getClazz(),
1632 887126ca Andreas Müller
                    occurrenceConfig.getTitleSearchString(), occurrenceConfig.getSignificantIdentifier(),
1633 e6e5ebdc Patrick Plitzner
                    occurrenceConfig.getSpecimenType(), taxon, taxonName, occurrenceConfig.getMatchMode(), null, null,
1634 98ce4a92 Andreas Müller
                    occurrenceConfig.getOrderHints(), occurrenceConfig.getPropertyPaths());
1635
            occurrences.addAll(foundOccurrences);
1636 7dab8082 Patrick Plitzner
            occurrences = filterOccurencesByAssignmentAndHierarchy(occurrenceConfig, occurrences, taxon, taxonName);
1637
1638 98ce4a92 Andreas Müller
            return new DefaultPagerImpl<>(config.getPageNumber(), occurrences.size(), config.getPageSize(), (List<S>)occurrences);
1639 7dab8082 Patrick Plitzner
        }
1640
        return super.findByTitle(config);
1641
    }
1642
1643
    private List<SpecimenOrObservationBase> filterOccurencesByAssignmentAndHierarchy(
1644
            FindOccurrencesConfigurator occurrenceConfig, List<SpecimenOrObservationBase> occurrences, Taxon taxon,
1645
            TaxonName taxonName) {
1646
        //filter out (un-)assigned specimens
1647
        if(taxon==null && taxonName==null){
1648
            AssignmentStatus assignmentStatus = occurrenceConfig.getAssignmentStatus();
1649 98ce4a92 Andreas Müller
            List<SpecimenOrObservationBase> specimenWithAssociations = new ArrayList<>();
1650 7dab8082 Patrick Plitzner
            if(!assignmentStatus.equals(AssignmentStatus.ALL_SPECIMENS)){
1651 98ce4a92 Andreas Müller
                for (SpecimenOrObservationBase specimenOrObservationBase : occurrences) {
1652 12b3d645 Andreas Müller
                    boolean includeUnpublished = true;  //TODO not sure if this is correct, maybe we have to propagate publish flag to higher methods.
1653
                    Collection<TaxonBase<?>> associatedTaxa = listAssociatedTaxa(specimenOrObservationBase,
1654
                            includeUnpublished, null, null, null, null);
1655 7dab8082 Patrick Plitzner
                    if(!associatedTaxa.isEmpty()){
1656
                        specimenWithAssociations.add(specimenOrObservationBase);
1657 02942c8c Patrick Plitzner
                    }
1658
                }
1659
            }
1660 7dab8082 Patrick Plitzner
            if(assignmentStatus.equals(AssignmentStatus.UNASSIGNED_SPECIMENS)){
1661
                occurrences.removeAll(specimenWithAssociations);
1662
            }
1663
            if(assignmentStatus.equals(AssignmentStatus.ASSIGNED_SPECIMENS)){
1664
                occurrences = new ArrayList<>(specimenWithAssociations);
1665
            }
1666
        }
1667
        // indirectly associated specimens
1668
        if(occurrenceConfig.isRetrieveIndirectlyAssociatedSpecimens()){
1669
            List<SpecimenOrObservationBase> indirectlyAssociatedOccurrences = new ArrayList<>(occurrences);
1670 f6df4cfb Andreas Müller
            for (SpecimenOrObservationBase<?> specimen : occurrences) {
1671 7dab8082 Patrick Plitzner
                List<SpecimenOrObservationBase<?>> allHierarchyDerivates = getAllHierarchyDerivatives(specimen);
1672
                for (SpecimenOrObservationBase<?> specimenOrObservationBase : allHierarchyDerivates) {
1673
                    if(!occurrences.contains(specimenOrObservationBase)){
1674
                        indirectlyAssociatedOccurrences.add(specimenOrObservationBase);
1675 887126ca Andreas Müller
                    }
1676
                }
1677
            }
1678 7dab8082 Patrick Plitzner
            occurrences = indirectlyAssociatedOccurrences;
1679 887126ca Andreas Müller
        }
1680 7dab8082 Patrick Plitzner
        return occurrences;
1681 887126ca Andreas Müller
    }
1682
1683
    @Override
1684
    public List<SpecimenOrObservationBase<?>> getAllHierarchyDerivatives(SpecimenOrObservationBase<?> specimen){
1685 7e7e032e Andreas Müller
        List<SpecimenOrObservationBase<?>> allHierarchyDerivatives = new ArrayList<>();
1686 6b53ead8 Katja Luther
        Collection<FieldUnit> fieldUnits = findFieldUnits(specimen.getUuid(), null);
1687 887126ca Andreas Müller
        if(fieldUnits.isEmpty()){
1688
            allHierarchyDerivatives.add(specimen);
1689
            allHierarchyDerivatives.addAll(getAllChildDerivatives(specimen));
1690
        }
1691
        else{
1692
            for (FieldUnit fieldUnit : fieldUnits) {
1693
                allHierarchyDerivatives.add(fieldUnit);
1694
                allHierarchyDerivatives.addAll(getAllChildDerivatives(fieldUnit));
1695
            }
1696
        }
1697
        return allHierarchyDerivatives;
1698
    }
1699
1700 d496803d Patrick Plitzner
    @Override
1701
    public List<DerivedUnit> getAllChildDerivatives(UUID specimenUuid){
1702
        return getAllChildDerivatives(load(specimenUuid));
1703
    }
1704
1705 887126ca Andreas Müller
    @Override
1706
    public List<DerivedUnit> getAllChildDerivatives(SpecimenOrObservationBase<?> specimen){
1707 09a260bb Katja Luther
        if (specimen == null){
1708
            return null;
1709
        }
1710 7e7e032e Andreas Müller
        List<DerivedUnit> childDerivate = new ArrayList<>();
1711 887126ca Andreas Müller
        Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();
1712
        for (DerivationEvent derivationEvent : derivationEvents) {
1713
            Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
1714
            for (DerivedUnit derivedUnit : derivatives) {
1715
                childDerivate.add(derivedUnit);
1716 d496803d Patrick Plitzner
                childDerivate.addAll(getAllChildDerivatives(derivedUnit.getUuid()));
1717 887126ca Andreas Müller
            }
1718
        }
1719
        return childDerivate;
1720
    }
1721
1722
    @Override
1723 9a21de1f Andreas Müller
    public long countOccurrences(IIdentifiableEntityServiceConfigurator<SpecimenOrObservationBase> config){
1724 1c1517f9 Patrick Plitzner
        return countByTitle(config);
1725 887126ca Andreas Müller
    }
1726
1727 3835ed3e Patrick Plitzner
    /**
1728
     * {@inheritDoc}
1729
     */
1730
    @Override
1731 6b53ead8 Katja Luther
    public List<FieldUnit> findFieldUnitsForGatheringEvent(UUID gatheringEventUuid) {
1732
        return dao.findFieldUnitsForGatheringEvent(gatheringEventUuid, null, null, null, null);
1733
    }
1734
1735
1736
    /**
1737
     * {@inheritDoc}
1738
     */
1739
    @Override
1740
    public List<Point> findPointsForFieldUnitList(List<UUID> fieldUnitUuids) {
1741
1742
        return dao.findPointsForFieldUnitList(fieldUnitUuids);
1743 3835ed3e Patrick Plitzner
    }
1744 887126ca Andreas Müller
}