Project

General

Profile

Download (55.5 KB) Statistics
| Branch: | Tag: | Revision:
1
// $Id$
2
/**
3
 * Copyright (C) 2007 EDIT
4
 * European Distributed Institute of Taxonomy
5
 * http://www.e-taxonomy.eu
6
 *
7
 * The contents of this file are subject to the Mozilla Public License Version 1.1
8
 * See LICENSE.TXT at the top of this package for the full license terms.
9
 */
10

    
11
package eu.etaxonomy.cdm.api.service;
12

    
13
import java.io.IOException;
14
import java.net.URI;
15
import java.net.URISyntaxException;
16
import java.util.ArrayList;
17
import java.util.Arrays;
18
import java.util.Collection;
19
import java.util.HashMap;
20
import java.util.HashSet;
21
import java.util.List;
22
import java.util.Map;
23
import java.util.Map.Entry;
24
import java.util.Set;
25
import java.util.UUID;
26

    
27
import org.apache.log4j.Logger;
28
import org.apache.lucene.index.CorruptIndexException;
29
import org.apache.lucene.queryParser.ParseException;
30
import org.apache.lucene.search.BooleanClause.Occur;
31
import org.apache.lucene.search.BooleanQuery;
32
import org.apache.lucene.search.SortField;
33
import org.hibernate.TransientObjectException;
34
import org.hibernate.search.spatial.impl.Rectangle;
35
import org.joda.time.Partial;
36
import org.springframework.beans.factory.annotation.Autowired;
37
import org.springframework.stereotype.Service;
38
import org.springframework.transaction.annotation.Transactional;
39

    
40
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
41
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeConfigurator;
42
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeNotSupportedException;
43
import eu.etaxonomy.cdm.api.service.DeleteResult.DeleteStatus;
44
import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase;
45
import eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator;
46
import eu.etaxonomy.cdm.api.service.dto.DerivateHierarchyDTO;
47
import eu.etaxonomy.cdm.api.service.dto.DerivateHierarchyDTO.ContigFile;
48
import eu.etaxonomy.cdm.api.service.dto.DerivateHierarchyDTO.MolecularData;
49
import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
50
import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;
51
import eu.etaxonomy.cdm.api.service.pager.Pager;
52
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
53
import eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider;
54
import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;
55
import eu.etaxonomy.cdm.api.service.search.LuceneSearch;
56
import eu.etaxonomy.cdm.api.service.search.LuceneSearch.TopGroupsWithMaxScore;
57
import eu.etaxonomy.cdm.api.service.search.QueryFactory;
58
import eu.etaxonomy.cdm.api.service.search.SearchResult;
59
import eu.etaxonomy.cdm.api.service.search.SearchResultBuilder;
60
import eu.etaxonomy.cdm.api.service.util.TaxonRelationshipEdge;
61
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
62
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
63
import eu.etaxonomy.cdm.model.CdmBaseType;
64
import eu.etaxonomy.cdm.model.agent.AgentBase;
65
import eu.etaxonomy.cdm.model.common.CdmBase;
66
import eu.etaxonomy.cdm.model.common.DefinedTerm;
67
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
68
import eu.etaxonomy.cdm.model.common.ICdmBase;
69
import eu.etaxonomy.cdm.model.common.Language;
70
import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;
71
import eu.etaxonomy.cdm.model.description.DescriptionBase;
72
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
73
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
74
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
75
import eu.etaxonomy.cdm.model.description.TaxonDescription;
76
import eu.etaxonomy.cdm.model.location.Country;
77
import eu.etaxonomy.cdm.model.location.NamedArea;
78
import eu.etaxonomy.cdm.model.media.Media;
79
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
80
import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
81
import eu.etaxonomy.cdm.model.media.MediaUtils;
82
import eu.etaxonomy.cdm.model.molecular.AmplificationResult;
83
import eu.etaxonomy.cdm.model.molecular.DnaSample;
84
import eu.etaxonomy.cdm.model.molecular.Sequence;
85
import eu.etaxonomy.cdm.model.molecular.SingleRead;
86
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
87
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
88
import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;
89
import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;
90
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
91
import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;
92
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
93
import eu.etaxonomy.cdm.model.occurrence.GatheringEvent;
94
import eu.etaxonomy.cdm.model.occurrence.MediaSpecimen;
95
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
96
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
97
import eu.etaxonomy.cdm.model.taxon.Taxon;
98
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
99
import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;
100
import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
101
import eu.etaxonomy.cdm.persistence.dao.initializer.AbstractBeanInitializer;
102
import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
103
import eu.etaxonomy.cdm.persistence.query.OrderHint;
104
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
105

    
106
/**
107
 * @author a.babadshanjan
108
 * @created 01.09.2008
109
 */
110
@Service
111
@Transactional(readOnly = true)
112
public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObservationBase,IOccurrenceDao> implements IOccurrenceService {
113

    
114
    static private final Logger logger = Logger.getLogger(OccurrenceServiceImpl.class);
115

    
116
    @Autowired
117
    private IDefinedTermDao definedTermDao;
118

    
119
    @Autowired
120
    private IDescriptionService descriptionService;
121

    
122
    @Autowired
123
    private ITaxonService taxonService;
124

    
125
    @Autowired
126
    private ITermService termService;
127

    
128
    @Autowired
129
    private INameService nameService;
130

    
131
    @Autowired
132
    private ISequenceService sequenceService;
133

    
134
    @Autowired
135
    private AbstractBeanInitializer beanInitializer;
136

    
137
    @Autowired
138
    private ILuceneIndexToolProvider luceneIndexToolProvider;
139

    
140
    @Autowired
141
    private ICdmGenericDao genericDao;
142

    
143

    
144
    public OccurrenceServiceImpl() {
145
        logger.debug("Load OccurrenceService Bean");
146
    }
147

    
148

    
149
    /* (non-Javadoc)
150
     * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
151
     */
152
    @Override
153
    @Transactional(readOnly = false)
154
    public void updateTitleCache(Class<? extends SpecimenOrObservationBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<SpecimenOrObservationBase> cacheStrategy, IProgressMonitor monitor) {
155
        if (clazz == null){
156
            clazz = SpecimenOrObservationBase.class;
157
        }
158
        super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
159
    }
160

    
161

    
162
    /**
163
     * FIXME Candidate for harmonization
164
     * move to termService
165
     */
166
    @Override
167
    public Country getCountryByIso(String iso639) {
168
        return this.definedTermDao.getCountryByIso(iso639);
169

    
170
    }
171

    
172
    /**
173
     * FIXME Candidate for harmonization
174
     * move to termService
175
     */
176
    @Override
177
    public List<Country> getCountryByName(String name) {
178
        List<? extends DefinedTermBase> terms = this.definedTermDao.findByTitle(Country.class, name, null, null, null, null, null, null) ;
179
        List<Country> countries = new ArrayList<Country>();
180
        for (int i=0;i<terms.size();i++){
181
            countries.add((Country)terms.get(i));
182
        }
183
        return countries;
184
    }
185

    
186
    @Override
187
    @Autowired
188
    protected void setDao(IOccurrenceDao dao) {
189
        this.dao = dao;
190
    }
191

    
192
    @Override
193
    public Pager<DerivationEvent> getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber, List<String> propertyPaths) {
194
        Integer numberOfResults = dao.countDerivationEvents(occurence);
195

    
196
        List<DerivationEvent> results = new ArrayList<DerivationEvent>();
197
        if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
198
            results = dao.getDerivationEvents(occurence, pageSize, pageNumber,propertyPaths);
199
        }
200

    
201
        return new DefaultPagerImpl<DerivationEvent>(pageNumber, numberOfResults, pageSize, results);
202
    }
203

    
204
    /* (non-Javadoc)
205
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#countDeterminations(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.taxon.TaxonBase)
206
     */
207
    @Override
208
    public int countDeterminations(SpecimenOrObservationBase occurence, TaxonBase taxonbase) {
209
        return dao.countDeterminations(occurence, taxonbase);
210
    }
211

    
212
    @Override
213
    public Pager<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase, Integer pageSize,Integer pageNumber, List<String> propertyPaths) {
214
        Integer numberOfResults = dao.countDeterminations(occurrence, taxonBase);
215

    
216
        List<DeterminationEvent> results = new ArrayList<DeterminationEvent>();
217
        if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
218
            results = dao.getDeterminations(occurrence,taxonBase, pageSize, pageNumber, propertyPaths);
219
        }
220

    
221
        return new DefaultPagerImpl<DeterminationEvent>(pageNumber, numberOfResults, pageSize, results);
222
    }
223

    
224
    @Override
225
    public Pager<Media> getMedia(SpecimenOrObservationBase occurence,Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
226
        Integer numberOfResults = dao.countMedia(occurence);
227

    
228
        List<Media> results = new ArrayList<Media>();
229
        if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
230
            results = dao.getMedia(occurence, pageSize, pageNumber, propertyPaths);
231
        }
232

    
233
        return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);
234
    }
235

    
236
    /* (non-Javadoc)
237
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#list(java.lang.Class, eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
238
     */
239
    @Override
240
    public Pager<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> type, TaxonBase determinedAs, Integer pageSize, Integer pageNumber,	List<OrderHint> orderHints, List<String> propertyPaths) {
241
        Integer numberOfResults = dao.count(type,determinedAs);
242
        List<SpecimenOrObservationBase> results = new ArrayList<SpecimenOrObservationBase>();
243
        pageNumber = pageNumber == null ? 0 : pageNumber;
244
        if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
245
            Integer start = pageSize == null ? 0 : pageSize * pageNumber;
246
            results = dao.list(type,determinedAs, pageSize, start, orderHints,propertyPaths);
247
        }
248
        return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, numberOfResults, pageSize, results);
249
    }
250

    
251
    @Override
252
    public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache() {
253
        return dao.getDerivedUnitUuidAndTitleCache();
254
    }
255

    
256
    @Override
257
    public List<UuidAndTitleCache<FieldUnit>> getFieldUnitUuidAndTitleCache() {
258
        return dao.getFieldUnitUuidAndTitleCache();
259
    }
260

    
261
    /* (non-Javadoc)
262
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getDerivedUnitFacade(eu.etaxonomy.cdm.model.occurrence.DerivedUnit)
263
     */
264
    @Override
265
    public DerivedUnitFacade getDerivedUnitFacade(DerivedUnit derivedUnit, List<String> propertyPaths) throws DerivedUnitFacadeNotSupportedException {
266
        derivedUnit = (DerivedUnit)dao.load(derivedUnit.getUuid(), null);
267
        DerivedUnitFacadeConfigurator config = DerivedUnitFacadeConfigurator.NewInstance();
268
        config.setThrowExceptionForNonSpecimenPreservationMethodRequest(false);
269
        DerivedUnitFacade derivedUnitFacade = DerivedUnitFacade.NewInstance(derivedUnit, config);
270
        beanInitializer.initialize(derivedUnitFacade, propertyPaths);
271
        return derivedUnitFacade;
272
    }
273

    
274
    /* (non-Javadoc)
275
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listDerivedUnitFacades(eu.etaxonomy.cdm.model.description.DescriptionBase, java.util.List)
276
     */
277
    @Override
278
    public List<DerivedUnitFacade> listDerivedUnitFacades(
279
            DescriptionBase description, List<String> propertyPaths) {
280

    
281
        List<DerivedUnitFacade> derivedUnitFacadeList = new ArrayList<DerivedUnitFacade>();
282
        IndividualsAssociation tempIndividualsAssociation;
283
        SpecimenOrObservationBase tempSpecimenOrObservationBase;
284
        List<DescriptionElementBase> elements = descriptionService.listDescriptionElements(description, null, IndividualsAssociation.class, null, 0, Arrays.asList(new String []{"associatedSpecimenOrObservation"}));
285
        for(DescriptionElementBase element : elements){
286
            if(element instanceof IndividualsAssociation){
287
                tempIndividualsAssociation = (IndividualsAssociation)element;
288
                if(tempIndividualsAssociation.getAssociatedSpecimenOrObservation() != null){
289
                    tempSpecimenOrObservationBase = HibernateProxyHelper.deproxy(tempIndividualsAssociation.getAssociatedSpecimenOrObservation(), SpecimenOrObservationBase.class);
290
                    if(tempSpecimenOrObservationBase instanceof DerivedUnit){
291
                        try {
292
                            derivedUnitFacadeList.add(DerivedUnitFacade.NewInstance((DerivedUnit)tempSpecimenOrObservationBase));
293
                        } catch (DerivedUnitFacadeNotSupportedException e) {
294
                            logger.warn(tempIndividualsAssociation.getAssociatedSpecimenOrObservation().getTitleCache() + " : " +e.getMessage());
295
                        }
296
                    }
297
                }
298

    
299
            }
300
        }
301

    
302
        beanInitializer.initializeAll(derivedUnitFacadeList, propertyPaths);
303

    
304
        return derivedUnitFacadeList;
305
    }
306

    
307

    
308
    /* (non-Javadoc)
309
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listByAnyAssociation(java.lang.Class, java.util.Set, eu.etaxonomy.cdm.model.taxon.Taxon, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
310
     */
311
    @Override
312
    public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
313
            Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
314

    
315
        return pageByAssociatedTaxon(type, includeRelationships, associatedTaxon, maxDepth, pageSize, pageNumber, orderHints, propertyPaths).getRecords();
316
    }
317

    
318
    /* (non-Javadoc)
319
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listByAnyAssociation(java.lang.Class, java.util.Set, eu.etaxonomy.cdm.model.taxon.Taxon, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
320
     */
321
    @Override
322
    public Collection<FieldUnit> listFieldUnitsByAssociatedTaxon(Set<TaxonRelationshipEdge> includeRelationships,
323
            Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
324

    
325
        if(!getSession().contains(associatedTaxon)){
326
            associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());
327
        }
328

    
329
        Set<FieldUnit> fieldUnits = new HashSet<FieldUnit>();
330

    
331
        List<SpecimenOrObservationBase> records = pageByAssociatedTaxon(null, includeRelationships, associatedTaxon, maxDepth, pageSize, pageNumber, orderHints, propertyPaths).getRecords();
332
        for(SpecimenOrObservationBase<?> specimen:records){
333
            fieldUnits.addAll(getFieldUnits(specimen.getUuid()));
334
        }
335
        return fieldUnits;
336
    }
337

    
338
    @Override
339
    public DerivateHierarchyDTO assembleDerivateHierarchyDTO(FieldUnit fieldUnit, UUID associatedTaxonUuid){
340

    
341
        if(!getSession().contains(fieldUnit)){
342
            fieldUnit = (FieldUnit) load(fieldUnit.getUuid());
343
        }
344
        TaxonBase associatedTaxon = taxonService.load(associatedTaxonUuid);
345

    
346
        DerivateHierarchyDTO dto = new DerivateHierarchyDTO();
347
        Map<UUID, TypeDesignationStatusBase> typeSpecimenUUIDtoTypeDesignationStatus = new HashMap<UUID, TypeDesignationStatusBase>();
348

    
349
        //gather types for this taxon name
350
        TaxonNameBase<?,?> name = associatedTaxon.getName();
351
        Set<?> typeDesignations = name.getSpecimenTypeDesignations();
352
        for (Object object : typeDesignations) {
353
            if(object instanceof SpecimenTypeDesignation){
354
                SpecimenTypeDesignation specimenTypeDesignation = (SpecimenTypeDesignation)object;
355
                DerivedUnit typeSpecimen = specimenTypeDesignation.getTypeSpecimen();
356
                final TypeDesignationStatusBase typeStatus = specimenTypeDesignation.getTypeStatus();
357
                typeSpecimenUUIDtoTypeDesignationStatus.put(typeSpecimen.getUuid(), typeStatus);
358
            }
359
        }
360

    
361
        if(fieldUnit.getGatheringEvent()!=null){
362
            GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();
363
            //Country
364
            final NamedArea country = gatheringEvent.getCountry();
365
            dto.setCountry(country!=null?country.getDescription():"");
366
            //Collection
367
            final AgentBase collector = gatheringEvent.getCollector();
368
            final String fieldNumber = fieldUnit.getFieldNumber();
369
            dto.setCollection(((collector!=null?collector:"") + " " + (fieldNumber!=null?fieldNumber:"")).trim());
370
            //Date
371
            final Partial gatheringDate = gatheringEvent.getGatheringDate();
372
            dto.setDate(gatheringDate!=null?gatheringDate.toString():"");
373
        }
374

    
375
        //Taxon Name
376
        dto.setTaxonName(associatedTaxon.getName().getFullTitleCache());
377

    
378

    
379
        Collection<DerivedUnit> derivedUnits = new ArrayList<DerivedUnit>();
380
        getDerivedUnitsFor(fieldUnit, derivedUnits);
381

    
382
        //Herbaria map
383
        Map<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> collectionToCountMap = new HashMap<eu.etaxonomy.cdm.model.occurrence.Collection, Integer>();
384
        //List of accession numbers for citation
385
        List<String> preservedSpecimenAccessionNumbers = new ArrayList<String>();
386

    
387
        //iterate over sub derivates
388
        for (DerivedUnit derivedUnit : derivedUnits) {
389
            //current accession number
390
            String currentAccessionNumber = derivedUnit.getAccessionNumber()!=null?derivedUnit.getAccessionNumber():"";
391
            //current herbarium
392
            String currentHerbarium = "";
393
            eu.etaxonomy.cdm.model.occurrence.Collection collection = derivedUnit.getCollection();
394
            if(collection!=null){
395
                currentHerbarium = collection.getCode()!=null?collection.getCode():"";
396
                //count herbaria
397
                Integer count = collectionToCountMap.get(collection);
398
                if(count==null){
399
                    count = 1;
400
                }
401
                else{
402
                    count++;
403
                }
404
                collectionToCountMap.put(collection, count);
405
            }
406
            //check if derived unit is a type
407
            if(typeSpecimenUUIDtoTypeDesignationStatus.keySet().contains(derivedUnit.getUuid())){
408
                dto.setHasType(true);
409
                TypeDesignationStatusBase typeDesignationStatus = typeSpecimenUUIDtoTypeDesignationStatus.get(derivedUnit.getUuid());
410
                String typeStatus = typeDesignationStatus.getLabel();
411
                dto.addTypes(typeStatus, currentAccessionNumber);
412
            }
413
            //assemble molecular data
414
            //pattern: DNAMarker [contig1, primer1_1, primer1_2, ...][contig2, primer2_1, ...]...
415
            if(derivedUnit instanceof DnaSample){
416
                if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.TissueSample){
417
                    //TODO implement TissueSample assembly for web service
418
                }
419
                if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.DnaSample){
420

    
421
                    DnaSample dna = (DnaSample)derivedUnit;
422
                    if(!dna.getSequences().isEmpty()){
423
                        dto.setHasDna(true);
424
                    }
425
                    for(Sequence sequence:dna.getSequences()){
426
                        URI boldUri = null;
427
                        try {
428
                            boldUri = sequence.getBoldUri();
429
                        } catch (URISyntaxException e1) {
430
                            logger.error("Could not create BOLD URI", e1);
431
                        }
432
                        final DefinedTerm dnaMarker = sequence.getDnaMarker();
433
                        MolecularData molecularData = dto.addProviderLink(boldUri!=null?boldUri:null,dnaMarker!=null?dnaMarker.getLabel():"[no marker]");
434

    
435
                        //contig file FIXME show primer although contig not present?
436
                        if(sequence.getContigFile()!=null){
437
                            MediaRepresentationPart contigMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(sequence.getContigFile());
438
                            if(contigMediaRepresentationPart!=null){
439
                                ContigFile contigFile = molecularData.addContigFile(contigMediaRepresentationPart.getUri(), "contig");
440
                                //primer files
441
                                if(sequence.getSingleReads()!=null){
442
                                    for (SingleRead singleRead : sequence.getSingleReads()) {
443
                                        MediaRepresentationPart pherogramMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(singleRead.getPherogram());
444
                                        if(pherogramMediaRepresentationPart!=null){
445
                                            contigFile.addPrimerLink(pherogramMediaRepresentationPart.getUri(), "primer");
446
                                        }
447
                                    }
448
                                }
449
                            }
450
                        }
451
                    }
452
                }
453
            }
454
            //assemble media data
455
            else if(derivedUnit instanceof MediaSpecimen){
456

    
457
                MediaSpecimen media = (MediaSpecimen)derivedUnit;
458
                String mediaUriString = getMediaUriString(media);
459
                if(media.getKindOfUnit()!=null){
460
                    //specimen scan
461
                    if(media.getKindOfUnit().getUuid().equals(UUID.fromString("acda15be-c0e2-4ea8-8783-b9b0c4ad7f03"))){
462
                        dto.setHasSpecimenScan(true);
463
                            final String imageLinkText = currentHerbarium+" "+currentAccessionNumber;
464
                            dto.addSpecimenScan(mediaUriString==null?"":mediaUriString, !imageLinkText.equals(" ")?imageLinkText:"[no accession]");
465
                    }
466
                    //detail image
467
                    else if(media.getKindOfUnit().getUuid().equals(UUID.fromString("31eb8d02-bf5d-437c-bcc6-87a626445f34"))){
468
                        dto.setHasDetailImage(true);
469
                        String motif = "";
470
                        if(media.getMediaSpecimen()!=null && media.getMediaSpecimen().getTitle()!=null){
471
                            motif = media.getMediaSpecimen().getTitle().getText();
472
                        }
473
                        dto.addDetailImage(mediaUriString==null?"":mediaUriString, motif!=null?motif:"[no motif]");
474
                    }
475
                }
476
            }
477
            //assemble preserved specimen data
478
            else if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.PreservedSpecimen){
479
                if(!currentAccessionNumber.isEmpty()){
480
                    preservedSpecimenAccessionNumbers.add(currentAccessionNumber);
481
                }
482
            }
483
        }
484

    
485
        final String separator = ", ";
486
        //assemble citation
487
        String citation = "";
488
        citation += !dto.getCountry().isEmpty()?dto.getCountry()+separator:"";
489
        if(fieldUnit.getGatheringEvent()!=null){
490
            if(fieldUnit.getGatheringEvent().getLocality()!=null){
491
                citation += fieldUnit.getGatheringEvent().getLocality().getText();
492
                citation += separator;
493
            }
494
            if(fieldUnit.getGatheringEvent().getExactLocation()!=null
495
                    && fieldUnit.getGatheringEvent().getExactLocation().getLatitude()!=null
496
                    && fieldUnit.getGatheringEvent().getExactLocation().getLongitude()!=null){
497
                citation += fieldUnit.getGatheringEvent().getExactLocation().getLatitude().toString();
498
                citation += separator;
499
                citation += fieldUnit.getGatheringEvent().getExactLocation().getLongitude().toString();
500
                citation += separator;
501
            }
502
        }
503
        citation += !dto.getCollection().isEmpty()?dto.getCollection():"";
504
        if(!preservedSpecimenAccessionNumbers.isEmpty()){
505
            citation += " (";
506
            for(String accessionNumber:preservedSpecimenAccessionNumbers){
507
                if(!accessionNumber.isEmpty()){
508
                    citation += accessionNumber+separator;
509
                }
510
            }
511
            citation = removeTail(citation, separator);
512
            citation += ")";
513
        }
514
        citation = removeTail(citation, separator);
515
        dto.setCitation(citation);
516

    
517
        //assemble herbaria string
518
        String herbariaString = "";
519
        for(Entry<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> e:collectionToCountMap.entrySet()){
520
            eu.etaxonomy.cdm.model.occurrence.Collection collection = e.getKey();
521
            if(collection.getCode()!=null){
522
                herbariaString += collection.getCode();
523
            }
524
            if(e.getValue()>1){
525
                herbariaString += "("+e.getValue()+")";
526
            }
527
            herbariaString += separator;
528
        }
529
        herbariaString = removeTail(herbariaString, separator);
530
        dto.setHerbarium(herbariaString);
531

    
532
        return dto;
533
    }
534

    
535

    
536
    /**
537
     * @param string
538
     * @param tail
539
     * @return
540
     */
541
    private String removeTail(String string, final String tail) {
542
        if(string.endsWith(tail)){
543
            string = string.substring(0, string.length()-tail.length());
544
        }
545
        return string;
546
    }
547

    
548
    private String getMediaUriString(MediaSpecimen mediaSpecimen){
549
        String mediaUri = null;
550
        Collection<MediaRepresentation> mediaRepresentations = mediaSpecimen.getMediaSpecimen().getRepresentations();
551
        if(mediaRepresentations!=null && !mediaRepresentations.isEmpty()){
552
            Collection<MediaRepresentationPart> mediaRepresentationParts = mediaRepresentations.iterator().next().getParts();
553
            if(mediaRepresentationParts!=null && !mediaRepresentationParts.isEmpty()){
554
                MediaRepresentationPart part = mediaRepresentationParts.iterator().next();
555
                if(part.getUri()!=null){
556
                    mediaUri = part.getUri().toASCIIString();
557
                }
558
            }
559
        }
560
        return mediaUri;
561
    }
562

    
563
    private void getDerivedUnitsFor(SpecimenOrObservationBase<?> specimen, Collection<DerivedUnit> derivedUnits){
564
        for(DerivationEvent derivationEvent:specimen.getDerivationEvents()){
565
            for(DerivedUnit derivative:derivationEvent.getDerivatives()){
566
                derivedUnits.add(derivative);
567
                getDerivedUnitsFor(derivative, derivedUnits);
568
            }
569
        }
570
    }
571

    
572

    
573
    /* (non-Javadoc)
574
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#pageByAssociatedTaxon(java.lang.Class, java.util.Set, eu.etaxonomy.cdm.model.taxon.Taxon, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
575
     */
576
    @SuppressWarnings("unchecked")
577
    @Override
578
    public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
579
            Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
580

    
581
        Set<Taxon> taxa = new HashSet<Taxon>();
582
        Set<Integer> occurrenceIds = new HashSet<Integer>();
583
        List<T> occurrences = new ArrayList<T>();
584

    
585
//        Integer limit = PagerUtils.limitFor(pageSize);
586
//        Integer start = PagerUtils.startFor(pageSize, pageNumber);
587

    
588
        if(!getSession().contains(associatedTaxon)){
589
            associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());
590
        }
591

    
592
        if(includeRelationships != null) {
593
            taxa = taxonService.listRelatedTaxa(associatedTaxon, includeRelationships, maxDepth, null, null, propertyPaths);
594
        }
595

    
596
        taxa.add(associatedTaxon);
597

    
598
        for (Taxon taxon : taxa) {
599
            List<T> perTaxonOccurrences = dao.listByAssociatedTaxon(type, taxon, null, null, orderHints, propertyPaths);
600
            for (SpecimenOrObservationBase o : perTaxonOccurrences) {
601
                occurrenceIds.add(o.getId());
602
            }
603
        }
604
        occurrences = (List<T>) dao.listByIds(occurrenceIds, pageSize, pageNumber, orderHints, propertyPaths);
605

    
606
        return new DefaultPagerImpl<T>(pageNumber, occurrenceIds.size(), pageSize, occurrences);
607

    
608
    }
609

    
610

    
611
    @Override
612
    public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
613
            String taxonUUID, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
614

    
615
        UUID uuid = UUID.fromString(taxonUUID);
616
        Taxon tax = (Taxon) taxonService.load(uuid);
617
       //TODO REMOVE NULL STATEMENT
618
        type=null;
619
        return pageByAssociatedTaxon( type,includeRelationships,tax, maxDepth, pageSize, pageNumber, orderHints, propertyPaths );
620

    
621
    }
622

    
623

    
624
    @Override
625
    public Pager<SearchResult<SpecimenOrObservationBase>> findByFullText(
626
            Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle boundingBox, List<Language> languages,
627
            boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
628
            List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {
629

    
630
        LuceneSearch luceneSearch = prepareByFullTextSearch(clazz, queryString, boundingBox, languages, highlightFragments);
631

    
632
        // --- execute search
633
        TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);
634

    
635
        Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
636
        idFieldMap.put(CdmBaseType.SPECIMEN_OR_OBSERVATIONBASE, "id");
637

    
638
        // --- initialize taxa, highlight matches ....
639
        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
640
        @SuppressWarnings("rawtypes")
641
        List<SearchResult<SpecimenOrObservationBase>> searchResults = searchResultBuilder.createResultSet(
642
                topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);
643

    
644
        int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupCount : 0;
645

    
646
        return new DefaultPagerImpl<SearchResult<SpecimenOrObservationBase>>(pageNumber, totalHits, pageSize,
647
                searchResults);
648

    
649
    }
650

    
651

    
652
    /**
653
     * @param clazz
654
     * @param queryString
655
     * @param languages
656
     * @param highlightFragments
657
     * @return
658
     */
659
    private LuceneSearch prepareByFullTextSearch(Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle bbox,
660
            List<Language> languages, boolean highlightFragments) {
661

    
662
        BooleanQuery finalQuery = new BooleanQuery();
663
        BooleanQuery textQuery = new BooleanQuery();
664

    
665
        LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, FieldUnit.class);
666
        QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(FieldUnit.class);
667

    
668
        // --- criteria
669
        luceneSearch.setCdmTypRestriction(clazz);
670
        if(queryString != null){
671
            textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);
672
            finalQuery.add(textQuery, Occur.MUST);
673
        }
674

    
675
        // --- spacial query
676
        if(bbox != null){
677
            finalQuery.add(QueryFactory.buildSpatialQueryByRange(bbox, "gatheringEvent.exactLocation.point"), Occur.MUST);
678
        }
679

    
680
        luceneSearch.setQuery(finalQuery);
681

    
682
        // --- sorting
683
        SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
684
        luceneSearch.setSortFields(sortFields);
685

    
686
        if(highlightFragments){
687
            luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
688
        }
689
        return luceneSearch;
690
    }
691

    
692

    
693
    /* (non-Javadoc)
694
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getFieldUnits(eu.etaxonomy.cdm.model.occurrence.DerivedUnit)
695
     */
696
    @Override
697
    public Collection<FieldUnit> getFieldUnits(UUID derivedUnitUuid) {
698
        //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})
699
        //from which this DerivedUnit was derived until all FieldUnits are found.
700

    
701
        //FIXME: use HQL queries to increase performance
702
        SpecimenOrObservationBase<?> specimen = load(derivedUnitUuid);
703
//        specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
704
        Collection<FieldUnit> fieldUnits = new ArrayList<FieldUnit>();
705

    
706
        if(specimen instanceof FieldUnit){
707
            fieldUnits.add((FieldUnit) specimen);
708
        }
709
        else if(specimen instanceof DerivedUnit){
710
            getFieldUnits((DerivedUnit) specimen, fieldUnits);
711
        }
712
        return fieldUnits;
713
    }
714

    
715

    
716
    /**
717
     * @param original
718
     * @param fieldUnits
719
     */
720
    private void getFieldUnits(DerivedUnit derivedUnit, Collection<FieldUnit> fieldUnits) {
721
        Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals();
722
        if(originals!=null && !originals.isEmpty()){
723
            for(SpecimenOrObservationBase<?> original:originals){
724
                if(original instanceof FieldUnit){
725
                    fieldUnits.add((FieldUnit) original);
726
                }
727
                else if(original instanceof DerivedUnit){
728
                    getFieldUnits((DerivedUnit) original, fieldUnits);
729
                }
730
            }
731
        }
732
    }
733

    
734
    /* (non-Javadoc)
735
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#moveSequence(eu.etaxonomy.cdm.model.molecular.DnaSample, eu.etaxonomy.cdm.model.molecular.DnaSample, eu.etaxonomy.cdm.model.molecular.Sequence)
736
     */
737
    @Override
738
    public boolean moveSequence(DnaSample from, DnaSample to, Sequence sequence) {
739
        //reload specimens to avoid session conflicts
740
        from = (DnaSample) load(from.getUuid());
741
        to = (DnaSample) load(to.getUuid());
742
        sequence = sequenceService.load(sequence.getUuid());
743

    
744
        if(from==null || to==null || sequence==null){
745
            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" +
746
                    "Operation was move "+sequence+ " from "+from+" to "+to);
747
        }
748
        from.removeSequence(sequence);
749
        saveOrUpdate(from);
750
        to.addSequence(sequence);
751
        saveOrUpdate(to);
752
        return true;
753
    }
754

    
755
    /* (non-Javadoc)
756
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#moveDerivate(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.occurrence.DerivedUnit)
757
     */
758
    @Override
759
    public boolean moveDerivate(SpecimenOrObservationBase<?> from, SpecimenOrObservationBase<?> to, DerivedUnit derivate) {
760
        //reload specimens to avoid session conflicts
761
        from = load(from.getUuid());
762
        to = load(to.getUuid());
763
        derivate = (DerivedUnit) load(derivate.getUuid());
764

    
765
        if(from==null || to==null || derivate==null){
766
            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" +
767
            		"Operation was move "+derivate+ " from "+from+" to "+to);
768
        }
769

    
770
        SpecimenOrObservationType derivateType = derivate.getRecordBasis();
771
        SpecimenOrObservationType toType = to.getRecordBasis();
772
        //check if type is a sub derivate type
773
        if(toType==SpecimenOrObservationType.FieldUnit //moving to FieldUnit always works
774
                || derivateType==SpecimenOrObservationType.Media //moving media always works
775
                || (derivateType.isKindOf(toType) && toType!=derivateType)){ //moving only to parent derivate type
776
            //remove derivation event from parent specimen of dragged object
777
            DerivationEvent eventToRemove = null;
778
            for(DerivationEvent event:from.getDerivationEvents()){
779
                if(event.getDerivatives().contains(derivate)){
780
                    eventToRemove = event;
781
                    break;
782
                }
783
            }
784
            from.removeDerivationEvent(eventToRemove);
785
            saveOrUpdate(from);
786
            //add new derivation event to target
787
            DerivationEvent derivedFromNewOriginalEvent = DerivationEvent.NewSimpleInstance(to, derivate, eventToRemove==null?null:eventToRemove.getType());
788
            to.addDerivationEvent(derivedFromNewOriginalEvent);
789
            derivate.setDerivedFrom(derivedFromNewOriginalEvent);
790
            saveOrUpdate(to);
791
            return true;
792
        }
793
        return false;
794
    }
795

    
796
    @Override
797
    public Collection<ICdmBase> getNonCascadedAssociatedElements(SpecimenOrObservationBase<?> specimen){
798
        //potential fields that are not persisted cascadingly
799
        /*
800
         * SOOB
801
        -DescriptionBase
802
        -determinations
803
        --modifier TERM
804
        -kindOfUnit TERM
805
        -lifeStage TERM
806
        -sex TERM
807

    
808
        FieldUnit
809
        -GatheringEvent
810
        --Country TERM
811
        --CollectingAreas TERM
812

    
813
        DerivedUnit
814
        -collection
815
        --institute
816
        ---types TERM
817
        -preservationMethod
818
        --medium TERM
819
        -storedUnder CDM TaxonNameBase
820
        */
821

    
822
        Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();
823

    
824
        //Choose the correct entry point to traverse the graph (FieldUnit or DerivedUnit)
825

    
826
        //FieldUnit
827
        if(specimen instanceof FieldUnit){
828
            nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements((FieldUnit)specimen));
829
        }
830
        //DerivedUnit
831
        else if(specimen instanceof DerivedUnit){
832
            DerivedUnit derivedUnit = (DerivedUnit)specimen;
833
            if(derivedUnit.getDerivedFrom()!=null){
834
                Collection<FieldUnit> fieldUnits = new ArrayList<FieldUnit>();
835
                getFieldUnits(derivedUnit, fieldUnits);
836
                for(FieldUnit fieldUnit:fieldUnits){
837
                    nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(fieldUnit));
838
                }
839
            }
840
        }
841
        return nonCascadedCdmEntities;
842
    }
843

    
844
    private Collection<ICdmBase> getFieldUnitNonCascadedAssociatedElements(FieldUnit fieldUnit){
845
        //get non cascaded element on SpecimenOrObservationBase level
846
        Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(fieldUnit);
847

    
848
        //get FieldUnit specific elements
849
        GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();
850
        if(gatheringEvent!=null){
851
            //country
852
            if(gatheringEvent.getCountry()!=null){
853
                nonCascadedCdmEntities.add(gatheringEvent.getCountry());
854
            }
855
            //collecting areas
856
            for (NamedArea namedArea : gatheringEvent.getCollectingAreas()) {
857
                nonCascadedCdmEntities.add(namedArea);
858
            }
859
        }
860
        for (DerivationEvent derivationEvent : fieldUnit.getDerivationEvents()) {
861
            for (DerivedUnit derivedUnit : derivationEvent.getDerivatives()) {
862
                nonCascadedCdmEntities.addAll(getDerivedUnitNonCascadedAssociatedElements(derivedUnit));
863
            }
864
        }
865
        return nonCascadedCdmEntities;
866
    }
867

    
868
    private Collection<ICdmBase> getDerivedUnitNonCascadedAssociatedElements(DerivedUnit derivedUnit){
869
        //get non cascaded element on SpecimenOrObservationBase level
870
        Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(derivedUnit);
871

    
872
        //get DerivedUnit specific elements
873
        if(derivedUnit.getCollection()!=null && derivedUnit.getCollection().getInstitute()!=null){
874
            for (DefinedTerm type : derivedUnit.getCollection().getInstitute().getTypes()) {
875
                nonCascadedCdmEntities.add(type);
876
            }
877
        }
878
        if(derivedUnit.getPreservation()!=null && derivedUnit.getPreservation().getMedium()!=null){
879
            nonCascadedCdmEntities.add(derivedUnit.getPreservation().getMedium());
880
        }
881
        if(derivedUnit.getStoredUnder()!=null){
882
            nonCascadedCdmEntities.add(derivedUnit.getStoredUnder());
883
        }
884
        return nonCascadedCdmEntities;
885
    }
886

    
887
    /**
888
     * @param specimen
889
     * @return
890
     */
891
    private Collection<ICdmBase> getSpecimenOrObservationNonCascadedAssociatedElements(
892
            SpecimenOrObservationBase<?> specimen) {
893
        Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();
894
        //scan SpecimenOrObservationBase
895
        for(DeterminationEvent determinationEvent:specimen.getDeterminations()){
896
            //modifier
897
            if(determinationEvent.getModifier()!=null){
898
                nonCascadedCdmEntities.add(determinationEvent.getModifier());
899
            }
900
        }
901
        //kindOfUnit
902
        if(specimen.getKindOfUnit()!=null){
903
            nonCascadedCdmEntities.add(specimen.getKindOfUnit());
904
        }
905
        //lifeStage
906
        if(specimen.getLifeStage()!=null){
907
            nonCascadedCdmEntities.add(specimen.getLifeStage());
908
        }
909
        //sex
910
        if(specimen.getSex()!=null){
911
            nonCascadedCdmEntities.add(specimen.getSex());
912
        }
913
        return nonCascadedCdmEntities;
914
    }
915

    
916
    /* (non-Javadoc)
917
     * @see eu.etaxonomy.cdm.api.service.VersionableServiceBase#isDeletable(eu.etaxonomy.cdm.model.common.VersionableEntity, eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase)
918
     */
919
    @Override
920
    public DeleteResult isDeletable(SpecimenOrObservationBase specimen, DeleteConfiguratorBase config) {
921
        DeleteResult deleteResult = super.isDeletable(specimen, config);
922
        SpecimenDeleteConfigurator specimenDeleteConfigurator = (SpecimenDeleteConfigurator)config;
923

    
924
        //check elements found by super method
925
        Set<CdmBase> relatedObjects = deleteResult.getRelatedObjects();
926
        boolean isDeletable = true;
927
        for (CdmBase cdmBase : relatedObjects) {
928
            //check for type designation
929
            if(cdmBase.isInstanceOf(SpecimenTypeDesignation.class) && !specimenDeleteConfigurator.isDeleteFromTypeDesignation()){
930
                isDeletable = false;
931
                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is a type specimen."));
932
                break;
933
            }
934
            //check for IndividualsAssociations
935
            else if(cdmBase.isInstanceOf(IndividualsAssociation.class) && !specimenDeleteConfigurator.isDeleteFromIndividualsAssociation()){
936
                isDeletable = false;
937
                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still associated via IndividualsAssociations"));
938
                break;
939
            }
940
            //check for specimen/taxon description
941
            else if((cdmBase.isInstanceOf(SpecimenDescription.class) || cdmBase.isInstanceOf(TaxonDescription.class))
942
                    && !specimenDeleteConfigurator.isDeleteFromDescription()){
943
                isDeletable = false;
944
                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still used in a Description."));
945
                break;
946
            }
947
            //check for children and parents (derivation events)
948
            else if(cdmBase.isInstanceOf(DerivationEvent.class)){
949
                DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(cdmBase, DerivationEvent.class);
950
                //check if derivation event is derivedFrom event (parent -> child)
951
                if(derivationEvent.getDerivatives().contains(specimen)){
952
                    //if it is then the specimen is still deletable
953
                    continue;
954
                }
955
                else if(!specimenDeleteConfigurator.isDeleteChildren()){
956
                    //if not and children should not be deleted then it is undeletable
957
                    isDeletable = false;
958
                    deleteResult.addException(new ReferencedObjectUndeletableException("Derivate still has child derivates."));
959
                    break;
960
                }
961
                else{
962
                    //check all children if they can be deleted
963
                    Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
964
                    DeleteResult childResult = new DeleteResult();
965
                    for (DerivedUnit derivedUnit : derivatives) {
966
                        childResult.includeResult(isDeletable(derivedUnit, specimenDeleteConfigurator));
967
                    }
968
                    if(!childResult.isOk()){
969
                        isDeletable = false;
970
                        deleteResult.includeResult(childResult);
971
                        break;
972
                    }
973
                }
974
            }
975
            //check for amplification
976
            else if(cdmBase.isInstanceOf(AmplificationResult.class) && !specimenDeleteConfigurator.isDeleteMolecularData()){
977
                isDeletable = false;
978
                deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in amplification results."));
979
                break;
980
            }
981
            //check for sequence
982
            else if(cdmBase.isInstanceOf(Sequence.class) && !specimenDeleteConfigurator.isDeleteMolecularData()){
983
                isDeletable = false;
984
                deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in sequences."));
985
                break;
986
            }
987
        }
988
        if(isDeletable){
989
            //set to OK when config allows to delete related objects
990
            deleteResult.setStatus(DeleteStatus.OK);
991
        }
992

    
993
        return deleteResult;
994
    }
995

    
996
    /* (non-Javadoc)
997
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#delete(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator)
998
     */
999
    @Override
1000
    public DeleteResult delete(SpecimenOrObservationBase<?> specimen, SpecimenDeleteConfigurator config) {
1001
        specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
1002

    
1003
        DeleteResult deleteResult = isDeletable(specimen, config);
1004
        if(!deleteResult.isOk()){
1005
            return deleteResult;
1006
        }
1007

    
1008
        //check related objects
1009
        Set<CdmBase> relatedObjects = deleteResult.getRelatedObjects();
1010
        for (CdmBase relatedObject : relatedObjects) {
1011
            //check for TypeDesignations
1012
            if(relatedObject.isInstanceOf(SpecimenTypeDesignation.class)){
1013
                SpecimenTypeDesignation designation = HibernateProxyHelper.deproxy(relatedObject, SpecimenTypeDesignation.class);
1014
                designation.setTypeSpecimen(null);
1015
                Set<TaxonNameBase> typifiedNames = designation.getTypifiedNames();
1016
                for (TaxonNameBase taxonNameBase : typifiedNames) {
1017
                    taxonNameBase.removeTypeDesignation(designation);
1018
                }
1019
            }
1020
            //delete IndividualsAssociation
1021
            if(relatedObject.isInstanceOf(IndividualsAssociation.class)){
1022
                IndividualsAssociation assciation = HibernateProxyHelper.deproxy(relatedObject, IndividualsAssociation.class);
1023
                assciation.setAssociatedSpecimenOrObservation(null);
1024
                assciation.getInDescription().removeElement(assciation);
1025
            }
1026
            //check for taxon description
1027
            if(relatedObject.isInstanceOf(TaxonDescription.class)){
1028
                TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(relatedObject, TaxonDescription.class);
1029
                taxonDescription.setDescribedSpecimenOrObservation(null);
1030
            }
1031
            //check for specimen description
1032
            if(relatedObject.isInstanceOf(SpecimenDescription.class)){
1033
                SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(relatedObject, SpecimenDescription.class);
1034
                //check if specimen is "described" specimen
1035
                if(specimenDescription.getDescribedSpecimenOrObservation().equals(specimen)){
1036
                    specimenDescription.setDescribedSpecimenOrObservation(null);
1037
                }
1038
                //check if description is a description of the given specimen
1039
                if(specimen.getDescriptions().contains(specimenDescription)){
1040
                    specimen.removeDescription(specimenDescription);
1041
                }
1042
            }
1043
            //check for amplification
1044
            if(relatedObject.isInstanceOf(AmplificationResult.class)){
1045
                AmplificationResult amplificationResult = HibernateProxyHelper.deproxy(relatedObject, AmplificationResult.class);
1046
                amplificationResult.getDnaSample().removeAmplificationResult(amplificationResult);
1047
            }
1048
            //check for sequence
1049
            if(relatedObject.isInstanceOf(Sequence.class)){
1050
                Sequence sequence = HibernateProxyHelper.deproxy(relatedObject, Sequence.class);
1051
                sequence.getDnaSample().removeSequence(sequence);
1052
            }
1053
            //check for children and parents (derivation events)
1054
            if(relatedObject.isInstanceOf(DerivationEvent.class)){
1055
                DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(relatedObject, DerivationEvent.class);
1056
                //parent derivation event (derivedFrom)
1057
                if(derivationEvent.getDerivatives().contains(specimen) && specimen.isInstanceOf(DerivedUnit.class)){
1058
                    derivationEvent.removeDerivative(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class));
1059
                    if(derivationEvent.getDerivatives().isEmpty()){
1060
                        Set<SpecimenOrObservationBase> originals = derivationEvent.getOriginals();
1061
                        for (SpecimenOrObservationBase specimenOrObservationBase : originals) {
1062
                            specimenOrObservationBase.removeDerivationEvent(derivationEvent);
1063
                        }
1064
                    }
1065
                }
1066
                //child derivation events
1067
                else{
1068
                    deleteResult.includeResult(deepDelete(specimen, config));
1069
                }
1070
            }
1071
        }
1072

    
1073
        deleteResult.includeResult(delete(specimen));
1074
        return deleteResult;
1075
    }
1076

    
1077
    /* (non-Javadoc)
1078
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#deleteDerivateHierarchy(eu.etaxonomy.cdm.model.common.ICdmBase)
1079
     */
1080
    @Override
1081
    public DeleteResult deleteDerivateHierarchy(CdmBase from, SpecimenDeleteConfigurator config) {
1082
        DeleteResult deleteResult = new DeleteResult();
1083
        if(from.isInstanceOf(Sequence.class)){
1084
            if(!config.isDeleteMolecularData()){
1085
                deleteResult.setAbort();
1086
                deleteResult.addException(new ReferencedObjectUndeletableException("deleting molecur data is not allowed in config"));
1087
                return deleteResult;
1088
            }
1089
            Sequence sequence = HibernateProxyHelper.deproxy(from, Sequence.class);
1090
            sequence.getDnaSample().removeSequence(sequence);
1091
            deleteResult = sequenceService.delete(sequence);
1092
        }
1093
        else if(from.isInstanceOf(SingleRead.class))  {
1094
            if(!config.isDeleteMolecularData()){
1095
                deleteResult.setAbort();
1096
                deleteResult.addException(new ReferencedObjectUndeletableException("deleting molecur data is not allowed in config"));
1097
                return deleteResult;
1098
            }
1099
            SingleRead singleRead = HibernateProxyHelper.deproxy(from, SingleRead.class);
1100
            singleRead.getAmplificationResult().removeSingleRead(singleRead);
1101
            deleteResult.setStatus(DeleteStatus.OK);
1102
        }
1103
        else if(from.isInstanceOf(SpecimenOrObservationBase.class))  {
1104
            deleteResult = deepDelete(HibernateProxyHelper.deproxy(from, SpecimenOrObservationBase.class), config);
1105
        }
1106
        return deleteResult;
1107
    }
1108

    
1109
    private DeleteResult deepDelete(SpecimenOrObservationBase<?> entity, SpecimenDeleteConfigurator config){
1110
        DeleteResult deleteResult = isDeletable(entity, config);
1111
        if(!deleteResult.isOk()){
1112
            return deleteResult;
1113
        }
1114
        Set<DerivationEvent> derivationEvents = entity.getDerivationEvents();
1115
        for (DerivationEvent derivationEvent : derivationEvents) {
1116
            Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
1117
            for (DerivedUnit derivedUnit : derivatives) {
1118
                deleteResult.includeResult(deepDelete(derivedUnit, config));
1119
            }
1120
        }
1121
        deleteResult.includeResult(delete(entity, config));
1122
        return deleteResult;
1123
    }
1124

    
1125
    /* (non-Javadoc)
1126
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listAssociatedTaxa(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase)
1127
     */
1128
    @Override
1129
    public Collection<IndividualsAssociation> listIndividualsAssociations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1130
        return dao.listIndividualsAssociations(specimen, null, null, null, null);
1131
    }
1132

    
1133
    /* (non-Javadoc)
1134
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listTypeDesignations(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
1135
     */
1136
    @Override
1137
    public Collection<SpecimenTypeDesignation> listTypeDesignations(SpecimenOrObservationBase<?> specimen,
1138
            Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1139
        return dao.listTypeDesignations(specimen, limit, start, orderHints, propertyPaths);
1140
    }
1141

    
1142
    /* (non-Javadoc)
1143
     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listDescriptionsWithDescriptionSpecimen(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
1144
     */
1145
    @Override
1146
    public Collection<DescriptionBase<?>> listDescriptionsWithDescriptionSpecimen(
1147
            SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints,
1148
            List<String> propertyPaths) {
1149
        return dao.listDescriptionsWithDescriptionSpecimen(specimen, limit, start, orderHints, propertyPaths);
1150
    }
1151

    
1152
}
(69-69/84)