- fixed deletion result relates objects
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / OccurrenceServiceImpl.java
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.IDefinedTermDao;
100 import eu.etaxonomy.cdm.persistence.dao.initializer.AbstractBeanInitializer;
101 import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
102 import eu.etaxonomy.cdm.persistence.query.OrderHint;
103 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
104
105 /**
106 * @author a.babadshanjan
107 * @created 01.09.2008
108 */
109 @Service
110 @Transactional(readOnly = true)
111 public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObservationBase,IOccurrenceDao> implements IOccurrenceService {
112
113 static private final Logger logger = Logger.getLogger(OccurrenceServiceImpl.class);
114
115 @Autowired
116 private IDefinedTermDao definedTermDao;
117
118 @Autowired
119 private IDescriptionService descriptionService;
120
121 @Autowired
122 private ITaxonService taxonService;
123
124 @Autowired
125 private ISequenceService sequenceService;
126
127 @Autowired
128 private AbstractBeanInitializer beanInitializer;
129
130 @Autowired
131 private ILuceneIndexToolProvider luceneIndexToolProvider;
132
133 public OccurrenceServiceImpl() {
134 logger.debug("Load OccurrenceService Bean");
135 }
136
137
138 /* (non-Javadoc)
139 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
140 */
141 @Override
142 @Transactional(readOnly = false)
143 public void updateTitleCache(Class<? extends SpecimenOrObservationBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<SpecimenOrObservationBase> cacheStrategy, IProgressMonitor monitor) {
144 if (clazz == null){
145 clazz = SpecimenOrObservationBase.class;
146 }
147 super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
148 }
149
150
151 /**
152 * FIXME Candidate for harmonization
153 * move to termService
154 */
155 @Override
156 public Country getCountryByIso(String iso639) {
157 return this.definedTermDao.getCountryByIso(iso639);
158
159 }
160
161 /**
162 * FIXME Candidate for harmonization
163 * move to termService
164 */
165 @Override
166 public List<Country> getCountryByName(String name) {
167 List<? extends DefinedTermBase> terms = this.definedTermDao.findByTitle(Country.class, name, null, null, null, null, null, null) ;
168 List<Country> countries = new ArrayList<Country>();
169 for (int i=0;i<terms.size();i++){
170 countries.add((Country)terms.get(i));
171 }
172 return countries;
173 }
174
175 @Override
176 @Autowired
177 protected void setDao(IOccurrenceDao dao) {
178 this.dao = dao;
179 }
180
181 @Override
182 public Pager<DerivationEvent> getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber, List<String> propertyPaths) {
183 Integer numberOfResults = dao.countDerivationEvents(occurence);
184
185 List<DerivationEvent> results = new ArrayList<DerivationEvent>();
186 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
187 results = dao.getDerivationEvents(occurence, pageSize, pageNumber,propertyPaths);
188 }
189
190 return new DefaultPagerImpl<DerivationEvent>(pageNumber, numberOfResults, pageSize, results);
191 }
192
193 /* (non-Javadoc)
194 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#countDeterminations(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.taxon.TaxonBase)
195 */
196 @Override
197 public int countDeterminations(SpecimenOrObservationBase occurence, TaxonBase taxonbase) {
198 return dao.countDeterminations(occurence, taxonbase);
199 }
200
201 @Override
202 public Pager<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase, Integer pageSize,Integer pageNumber, List<String> propertyPaths) {
203 Integer numberOfResults = dao.countDeterminations(occurrence, taxonBase);
204
205 List<DeterminationEvent> results = new ArrayList<DeterminationEvent>();
206 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
207 results = dao.getDeterminations(occurrence,taxonBase, pageSize, pageNumber, propertyPaths);
208 }
209
210 return new DefaultPagerImpl<DeterminationEvent>(pageNumber, numberOfResults, pageSize, results);
211 }
212
213 @Override
214 public Pager<Media> getMedia(SpecimenOrObservationBase occurence,Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
215 Integer numberOfResults = dao.countMedia(occurence);
216
217 List<Media> results = new ArrayList<Media>();
218 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
219 results = dao.getMedia(occurence, pageSize, pageNumber, propertyPaths);
220 }
221
222 return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);
223 }
224
225 /* (non-Javadoc)
226 * @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)
227 */
228 @Override
229 public Pager<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> type, TaxonBase determinedAs, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
230 Integer numberOfResults = dao.count(type,determinedAs);
231 List<SpecimenOrObservationBase> results = new ArrayList<SpecimenOrObservationBase>();
232 pageNumber = pageNumber == null ? 0 : pageNumber;
233 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
234 Integer start = pageSize == null ? 0 : pageSize * pageNumber;
235 results = dao.list(type,determinedAs, pageSize, start, orderHints,propertyPaths);
236 }
237 return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, numberOfResults, pageSize, results);
238 }
239
240 @Override
241 public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache() {
242 return dao.getDerivedUnitUuidAndTitleCache();
243 }
244
245 @Override
246 public List<UuidAndTitleCache<FieldUnit>> getFieldUnitUuidAndTitleCache() {
247 return dao.getFieldUnitUuidAndTitleCache();
248 }
249
250 /* (non-Javadoc)
251 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getDerivedUnitFacade(eu.etaxonomy.cdm.model.occurrence.DerivedUnit)
252 */
253 @Override
254 public DerivedUnitFacade getDerivedUnitFacade(DerivedUnit derivedUnit, List<String> propertyPaths) throws DerivedUnitFacadeNotSupportedException {
255 derivedUnit = (DerivedUnit)dao.load(derivedUnit.getUuid(), null);
256 DerivedUnitFacadeConfigurator config = DerivedUnitFacadeConfigurator.NewInstance();
257 config.setThrowExceptionForNonSpecimenPreservationMethodRequest(false);
258 DerivedUnitFacade derivedUnitFacade = DerivedUnitFacade.NewInstance(derivedUnit, config);
259 beanInitializer.initialize(derivedUnitFacade, propertyPaths);
260 return derivedUnitFacade;
261 }
262
263 /* (non-Javadoc)
264 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listDerivedUnitFacades(eu.etaxonomy.cdm.model.description.DescriptionBase, java.util.List)
265 */
266 @Override
267 public List<DerivedUnitFacade> listDerivedUnitFacades(
268 DescriptionBase description, List<String> propertyPaths) {
269
270 List<DerivedUnitFacade> derivedUnitFacadeList = new ArrayList<DerivedUnitFacade>();
271 IndividualsAssociation tempIndividualsAssociation;
272 SpecimenOrObservationBase tempSpecimenOrObservationBase;
273 List<DescriptionElementBase> elements = descriptionService.listDescriptionElements(description, null, IndividualsAssociation.class, null, 0, Arrays.asList(new String []{"associatedSpecimenOrObservation"}));
274 for(DescriptionElementBase element : elements){
275 if(element.isInstanceOf(IndividualsAssociation.class)){
276 tempIndividualsAssociation = HibernateProxyHelper.deproxy(element, IndividualsAssociation.class);
277 if(tempIndividualsAssociation.getAssociatedSpecimenOrObservation() != null){
278 tempSpecimenOrObservationBase = HibernateProxyHelper.deproxy(tempIndividualsAssociation.getAssociatedSpecimenOrObservation(), SpecimenOrObservationBase.class);
279 if(tempSpecimenOrObservationBase.isInstanceOf(DerivedUnit.class)){
280 try {
281 derivedUnitFacadeList.add(DerivedUnitFacade.NewInstance(HibernateProxyHelper.deproxy(tempSpecimenOrObservationBase, DerivedUnit.class)));
282 } catch (DerivedUnitFacadeNotSupportedException e) {
283 logger.warn(tempIndividualsAssociation.getAssociatedSpecimenOrObservation().getTitleCache() + " : " +e.getMessage());
284 }
285 }
286 }
287
288 }
289 }
290
291 beanInitializer.initializeAll(derivedUnitFacadeList, propertyPaths);
292
293 return derivedUnitFacadeList;
294 }
295
296
297 /* (non-Javadoc)
298 * @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)
299 */
300 @Override
301 public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
302 Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
303
304 return pageByAssociatedTaxon(type, includeRelationships, associatedTaxon, maxDepth, pageSize, pageNumber, orderHints, propertyPaths).getRecords();
305 }
306
307 /* (non-Javadoc)
308 * @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)
309 */
310 @Override
311 public Collection<FieldUnit> listFieldUnitsByAssociatedTaxon(Set<TaxonRelationshipEdge> includeRelationships,
312 Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
313
314 if(!getSession().contains(associatedTaxon)){
315 associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());
316 }
317
318 Set<FieldUnit> fieldUnits = new HashSet<FieldUnit>();
319
320 List<SpecimenOrObservationBase> records = pageByAssociatedTaxon(null, includeRelationships, associatedTaxon, maxDepth, pageSize, pageNumber, orderHints, propertyPaths).getRecords();
321 for(SpecimenOrObservationBase<?> specimen:records){
322 fieldUnits.addAll(getFieldUnits(specimen.getUuid()));
323 }
324 return fieldUnits;
325 }
326
327 @Override
328 public DerivateHierarchyDTO assembleDerivateHierarchyDTO(FieldUnit fieldUnit, UUID associatedTaxonUuid){
329
330 if(!getSession().contains(fieldUnit)){
331 fieldUnit = (FieldUnit) load(fieldUnit.getUuid());
332 }
333 TaxonBase associatedTaxon = taxonService.load(associatedTaxonUuid);
334
335 DerivateHierarchyDTO dto = new DerivateHierarchyDTO();
336 Map<UUID, TypeDesignationStatusBase> typeSpecimenUUIDtoTypeDesignationStatus = new HashMap<UUID, TypeDesignationStatusBase>();
337
338 //gather types for this taxon name
339 TaxonNameBase<?,?> name = associatedTaxon.getName();
340 Set<?> typeDesignations = name.getSpecimenTypeDesignations();
341 for (Object object : typeDesignations) {
342 if(object instanceof CdmBase && ((CdmBase)object).isInstanceOf(SpecimenTypeDesignation.class)){
343 SpecimenTypeDesignation specimenTypeDesignation = HibernateProxyHelper.deproxy(object, SpecimenTypeDesignation.class);
344 DerivedUnit typeSpecimen = specimenTypeDesignation.getTypeSpecimen();
345 final TypeDesignationStatusBase typeStatus = specimenTypeDesignation.getTypeStatus();
346 typeSpecimenUUIDtoTypeDesignationStatus.put(typeSpecimen.getUuid(), typeStatus);
347 }
348 }
349
350 if(fieldUnit.getGatheringEvent()!=null){
351 GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();
352 //Country
353 final NamedArea country = gatheringEvent.getCountry();
354 dto.setCountry(country!=null?country.getDescription():"");
355 //Collection
356 final AgentBase collector = gatheringEvent.getCollector();
357 final String fieldNumber = fieldUnit.getFieldNumber();
358 dto.setCollection(((collector!=null?collector:"") + " " + (fieldNumber!=null?fieldNumber:"")).trim());
359 //Date
360 final Partial gatheringDate = gatheringEvent.getGatheringDate();
361 dto.setDate(gatheringDate!=null?gatheringDate.toString():"");
362 }
363
364 //Taxon Name
365 dto.setTaxonName(associatedTaxon.getName().getFullTitleCache());
366
367
368 Collection<DerivedUnit> derivedUnits = new ArrayList<DerivedUnit>();
369 getDerivedUnitsFor(fieldUnit, derivedUnits);
370
371 //Herbaria map
372 Map<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> collectionToCountMap = new HashMap<eu.etaxonomy.cdm.model.occurrence.Collection, Integer>();
373 //List of accession numbers for citation
374 List<String> preservedSpecimenAccessionNumbers = new ArrayList<String>();
375
376 //iterate over sub derivates
377 for (DerivedUnit derivedUnit : derivedUnits) {
378 //current accession number
379 String currentAccessionNumber = derivedUnit.getAccessionNumber()!=null?derivedUnit.getAccessionNumber():"";
380 //current herbarium
381 String currentHerbarium = "";
382 eu.etaxonomy.cdm.model.occurrence.Collection collection = derivedUnit.getCollection();
383 if(collection!=null){
384 currentHerbarium = collection.getCode()!=null?collection.getCode():"";
385 //count herbaria
386 Integer count = collectionToCountMap.get(collection);
387 if(count==null){
388 count = 1;
389 }
390 else{
391 count++;
392 }
393 collectionToCountMap.put(collection, count);
394 }
395 //check if derived unit is a type
396 if(typeSpecimenUUIDtoTypeDesignationStatus.keySet().contains(derivedUnit.getUuid())){
397 dto.setHasType(true);
398 TypeDesignationStatusBase typeDesignationStatus = typeSpecimenUUIDtoTypeDesignationStatus.get(derivedUnit.getUuid());
399 String typeStatus = typeDesignationStatus.getLabel();
400 dto.addTypes(typeStatus, currentAccessionNumber);
401 }
402 //assemble molecular data
403 //pattern: DNAMarker [contig1, primer1_1, primer1_2, ...][contig2, primer2_1, ...]...
404 if(derivedUnit.isInstanceOf(DnaSample.class)){
405 if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.TissueSample){
406 //TODO implement TissueSample assembly for web service
407 }
408 if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.DnaSample){
409
410 DnaSample dna = HibernateProxyHelper.deproxy(derivedUnit, DnaSample.class);
411 if(!dna.getSequences().isEmpty()){
412 dto.setHasDna(true);
413 }
414 for(Sequence sequence:dna.getSequences()){
415 URI boldUri = null;
416 try {
417 boldUri = sequence.getBoldUri();
418 } catch (URISyntaxException e1) {
419 logger.error("Could not create BOLD URI", e1);
420 }
421 final DefinedTerm dnaMarker = sequence.getDnaMarker();
422 MolecularData molecularData = dto.addProviderLink(boldUri!=null?boldUri:null,dnaMarker!=null?dnaMarker.getLabel():"[no marker]");
423
424 //contig file FIXME show primer although contig not present?
425 if(sequence.getContigFile()!=null){
426 MediaRepresentationPart contigMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(sequence.getContigFile());
427 if(contigMediaRepresentationPart!=null){
428 ContigFile contigFile = molecularData.addContigFile(contigMediaRepresentationPart.getUri(), "contig");
429 //primer files
430 if(sequence.getSingleReads()!=null){
431 for (SingleRead singleRead : sequence.getSingleReads()) {
432 MediaRepresentationPart pherogramMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(singleRead.getPherogram());
433 if(pherogramMediaRepresentationPart!=null){
434 contigFile.addPrimerLink(pherogramMediaRepresentationPart.getUri(), "primer");
435 }
436 }
437 }
438 }
439 }
440 }
441 }
442 }
443 //assemble media data
444 else if(derivedUnit.isInstanceOf(MediaSpecimen.class)){
445
446 MediaSpecimen media = HibernateProxyHelper.deproxy(derivedUnit, MediaSpecimen.class);
447 String mediaUriString = getMediaUriString(media);
448 if(media.getKindOfUnit()!=null){
449 //specimen scan
450 if(media.getKindOfUnit().getUuid().equals(UUID.fromString("acda15be-c0e2-4ea8-8783-b9b0c4ad7f03"))){
451 dto.setHasSpecimenScan(true);
452 final String imageLinkText = currentHerbarium+" "+currentAccessionNumber;
453 dto.addSpecimenScan(mediaUriString==null?"":mediaUriString, !imageLinkText.equals(" ")?imageLinkText:"[no accession]");
454 }
455 //detail image
456 else if(media.getKindOfUnit().getUuid().equals(UUID.fromString("31eb8d02-bf5d-437c-bcc6-87a626445f34"))){
457 dto.setHasDetailImage(true);
458 String motif = "";
459 if(media.getMediaSpecimen()!=null && media.getMediaSpecimen().getTitle()!=null){
460 motif = media.getMediaSpecimen().getTitle().getText();
461 }
462 dto.addDetailImage(mediaUriString==null?"":mediaUriString, motif!=null?motif:"[no motif]");
463 }
464 }
465 }
466 //assemble preserved specimen data
467 else if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.PreservedSpecimen){
468 if(!currentAccessionNumber.isEmpty()){
469 preservedSpecimenAccessionNumbers.add(currentAccessionNumber);
470 }
471 }
472 }
473
474 final String separator = ", ";
475 //assemble citation
476 String citation = "";
477 citation += !dto.getCountry().isEmpty()?dto.getCountry()+separator:"";
478 if(fieldUnit.getGatheringEvent()!=null){
479 if(fieldUnit.getGatheringEvent().getLocality()!=null){
480 citation += fieldUnit.getGatheringEvent().getLocality().getText();
481 citation += separator;
482 }
483 if(fieldUnit.getGatheringEvent().getExactLocation()!=null
484 && fieldUnit.getGatheringEvent().getExactLocation().getLatitude()!=null
485 && fieldUnit.getGatheringEvent().getExactLocation().getLongitude()!=null){
486 citation += fieldUnit.getGatheringEvent().getExactLocation().getLatitude().toString();
487 citation += separator;
488 citation += fieldUnit.getGatheringEvent().getExactLocation().getLongitude().toString();
489 citation += separator;
490 }
491 }
492 citation += !dto.getCollection().isEmpty()?dto.getCollection():"";
493 if(!preservedSpecimenAccessionNumbers.isEmpty()){
494 citation += " (";
495 for(String accessionNumber:preservedSpecimenAccessionNumbers){
496 if(!accessionNumber.isEmpty()){
497 citation += accessionNumber+separator;
498 }
499 }
500 citation = removeTail(citation, separator);
501 citation += ")";
502 }
503 citation = removeTail(citation, separator);
504 dto.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;
517 }
518 herbariaString = removeTail(herbariaString, separator);
519 dto.setHerbarium(herbariaString);
520
521 return dto;
522 }
523
524
525 /**
526 * @param string
527 * @param tail
528 * @return
529 */
530 private String removeTail(String string, final String tail) {
531 if(string.endsWith(tail)){
532 string = string.substring(0, string.length()-tail.length());
533 }
534 return string;
535 }
536
537 private String getMediaUriString(MediaSpecimen mediaSpecimen){
538 String mediaUri = null;
539 Collection<MediaRepresentation> mediaRepresentations = mediaSpecimen.getMediaSpecimen().getRepresentations();
540 if(mediaRepresentations!=null && !mediaRepresentations.isEmpty()){
541 Collection<MediaRepresentationPart> mediaRepresentationParts = mediaRepresentations.iterator().next().getParts();
542 if(mediaRepresentationParts!=null && !mediaRepresentationParts.isEmpty()){
543 MediaRepresentationPart part = mediaRepresentationParts.iterator().next();
544 if(part.getUri()!=null){
545 mediaUri = part.getUri().toASCIIString();
546 }
547 }
548 }
549 return mediaUri;
550 }
551
552 private void getDerivedUnitsFor(SpecimenOrObservationBase<?> specimen, Collection<DerivedUnit> derivedUnits){
553 for(DerivationEvent derivationEvent:specimen.getDerivationEvents()){
554 for(DerivedUnit derivative:derivationEvent.getDerivatives()){
555 derivedUnits.add(derivative);
556 getDerivedUnitsFor(derivative, derivedUnits);
557 }
558 }
559 }
560
561
562 /* (non-Javadoc)
563 * @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)
564 */
565 @SuppressWarnings("unchecked")
566 @Override
567 public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
568 Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
569
570 Set<Taxon> taxa = new HashSet<Taxon>();
571 Set<Integer> occurrenceIds = new HashSet<Integer>();
572 List<T> occurrences = new ArrayList<T>();
573
574 // Integer limit = PagerUtils.limitFor(pageSize);
575 // Integer start = PagerUtils.startFor(pageSize, pageNumber);
576
577 if(!getSession().contains(associatedTaxon)){
578 associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());
579 }
580
581 if(includeRelationships != null) {
582 taxa = taxonService.listRelatedTaxa(associatedTaxon, includeRelationships, maxDepth, null, null, propertyPaths);
583 }
584
585 taxa.add(associatedTaxon);
586
587 for (Taxon taxon : taxa) {
588 List<T> perTaxonOccurrences = dao.listByAssociatedTaxon(type, taxon, null, null, orderHints, propertyPaths);
589 for (SpecimenOrObservationBase o : perTaxonOccurrences) {
590 occurrenceIds.add(o.getId());
591 }
592 }
593 occurrences = (List<T>) dao.listByIds(occurrenceIds, pageSize, pageNumber, orderHints, propertyPaths);
594
595 return new DefaultPagerImpl<T>(pageNumber, occurrenceIds.size(), pageSize, occurrences);
596
597 }
598
599
600 @Override
601 public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
602 String taxonUUID, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
603
604 UUID uuid = UUID.fromString(taxonUUID);
605 Taxon tax = (Taxon) taxonService.load(uuid);
606 //TODO REMOVE NULL STATEMENT
607 type=null;
608 return pageByAssociatedTaxon( type,includeRelationships,tax, maxDepth, pageSize, pageNumber, orderHints, propertyPaths );
609
610 }
611
612
613 @Override
614 public Pager<SearchResult<SpecimenOrObservationBase>> findByFullText(
615 Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle boundingBox, List<Language> languages,
616 boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
617 List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {
618
619 LuceneSearch luceneSearch = prepareByFullTextSearch(clazz, queryString, boundingBox, languages, highlightFragments);
620
621 // --- execute search
622 TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);
623
624 Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
625 idFieldMap.put(CdmBaseType.SPECIMEN_OR_OBSERVATIONBASE, "id");
626
627 // --- initialize taxa, highlight matches ....
628 ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
629 @SuppressWarnings("rawtypes")
630 List<SearchResult<SpecimenOrObservationBase>> searchResults = searchResultBuilder.createResultSet(
631 topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);
632
633 int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupCount : 0;
634
635 return new DefaultPagerImpl<SearchResult<SpecimenOrObservationBase>>(pageNumber, totalHits, pageSize,
636 searchResults);
637
638 }
639
640
641 /**
642 * @param clazz
643 * @param queryString
644 * @param languages
645 * @param highlightFragments
646 * @return
647 */
648 private LuceneSearch prepareByFullTextSearch(Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle bbox,
649 List<Language> languages, boolean highlightFragments) {
650
651 BooleanQuery finalQuery = new BooleanQuery();
652 BooleanQuery textQuery = new BooleanQuery();
653
654 LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, FieldUnit.class);
655 QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(FieldUnit.class);
656
657 // --- criteria
658 luceneSearch.setCdmTypRestriction(clazz);
659 if(queryString != null){
660 textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);
661 finalQuery.add(textQuery, Occur.MUST);
662 }
663
664 // --- spacial query
665 if(bbox != null){
666 finalQuery.add(QueryFactory.buildSpatialQueryByRange(bbox, "gatheringEvent.exactLocation.point"), Occur.MUST);
667 }
668
669 luceneSearch.setQuery(finalQuery);
670
671 // --- sorting
672 SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
673 luceneSearch.setSortFields(sortFields);
674
675 if(highlightFragments){
676 luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
677 }
678 return luceneSearch;
679 }
680
681
682 /* (non-Javadoc)
683 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getFieldUnits(eu.etaxonomy.cdm.model.occurrence.DerivedUnit)
684 */
685 @Override
686 public Collection<FieldUnit> getFieldUnits(UUID derivedUnitUuid) {
687 //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})
688 //from which this DerivedUnit was derived until all FieldUnits are found.
689
690 //FIXME: use HQL queries to increase performance
691 SpecimenOrObservationBase<?> specimen = load(derivedUnitUuid);
692 // specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
693 Collection<FieldUnit> fieldUnits = new ArrayList<FieldUnit>();
694
695 if(specimen.isInstanceOf(FieldUnit.class)){
696 fieldUnits.add(HibernateProxyHelper.deproxy(specimen, FieldUnit.class));
697 }
698 else if(specimen.isInstanceOf(DerivedUnit.class)){
699 fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class)));
700 }
701 return fieldUnits;
702 }
703
704
705 /**
706 * @param original
707 * @param fieldUnits
708 */
709 private Collection<FieldUnit> getFieldUnits(DerivedUnit derivedUnit) {
710 Collection<FieldUnit> fieldUnits = new HashSet<FieldUnit>();
711 Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals();
712 if(originals!=null && !originals.isEmpty()){
713 for(SpecimenOrObservationBase<?> original:originals){
714 if(original.isInstanceOf(FieldUnit.class)){
715 fieldUnits.add(HibernateProxyHelper.deproxy(original, FieldUnit.class));
716 }
717 else if(original.isInstanceOf(DerivedUnit.class)){
718 fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(original, DerivedUnit.class)));
719 }
720 }
721 }
722 return fieldUnits;
723 }
724
725 /* (non-Javadoc)
726 * @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)
727 */
728 @Override
729 public boolean moveSequence(DnaSample from, DnaSample to, Sequence sequence) {
730 //reload specimens to avoid session conflicts
731 from = (DnaSample) load(from.getUuid());
732 to = (DnaSample) load(to.getUuid());
733 sequence = sequenceService.load(sequence.getUuid());
734
735 if(from==null || to==null || sequence==null){
736 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" +
737 "Operation was move "+sequence+ " from "+from+" to "+to);
738 }
739 from.removeSequence(sequence);
740 saveOrUpdate(from);
741 to.addSequence(sequence);
742 saveOrUpdate(to);
743 return true;
744 }
745
746 /* (non-Javadoc)
747 * @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)
748 */
749 @Override
750 public boolean moveDerivate(SpecimenOrObservationBase<?> from, SpecimenOrObservationBase<?> to, DerivedUnit derivate) {
751 //reload specimens to avoid session conflicts
752 from = load(from.getUuid());
753 to = load(to.getUuid());
754 derivate = (DerivedUnit) load(derivate.getUuid());
755
756 if(from==null || to==null || derivate==null){
757 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" +
758 "Operation was move "+derivate+ " from "+from+" to "+to);
759 }
760
761 SpecimenOrObservationType derivateType = derivate.getRecordBasis();
762 SpecimenOrObservationType toType = to.getRecordBasis();
763 //check if type is a sub derivate type
764 if(toType==SpecimenOrObservationType.FieldUnit //moving to FieldUnit always works
765 || derivateType==SpecimenOrObservationType.Media //moving media always works
766 || (derivateType.isKindOf(toType) && toType!=derivateType)){ //moving only to parent derivate type
767 //remove derivation event from parent specimen of dragged object
768 DerivationEvent eventToRemove = null;
769 for(DerivationEvent event:from.getDerivationEvents()){
770 if(event.getDerivatives().contains(derivate)){
771 eventToRemove = event;
772 break;
773 }
774 }
775 from.removeDerivationEvent(eventToRemove);
776 saveOrUpdate(from);
777 //add new derivation event to target
778 DerivationEvent derivedFromNewOriginalEvent = DerivationEvent.NewSimpleInstance(to, derivate, eventToRemove==null?null:eventToRemove.getType());
779 to.addDerivationEvent(derivedFromNewOriginalEvent);
780 derivate.setDerivedFrom(derivedFromNewOriginalEvent);
781 saveOrUpdate(to);
782 return true;
783 }
784 return false;
785 }
786
787 @Override
788 public Collection<ICdmBase> getNonCascadedAssociatedElements(SpecimenOrObservationBase<?> specimen){
789 //potential fields that are not persisted cascadingly
790 /*
791 * SOOB
792 -DescriptionBase
793 -determinations
794 --modifier TERM
795 -kindOfUnit TERM
796 -lifeStage TERM
797 -sex TERM
798
799 FieldUnit
800 -GatheringEvent
801 --Country TERM
802 --CollectingAreas TERM
803
804 DerivedUnit
805 -collection
806 --institute
807 ---types TERM
808 -preservationMethod
809 --medium TERM
810 -storedUnder CDM TaxonNameBase
811 */
812
813 Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();
814
815 //Choose the correct entry point to traverse the graph (FieldUnit or DerivedUnit)
816
817 //FieldUnit
818 if(specimen.isInstanceOf(FieldUnit.class)){
819 nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(HibernateProxyHelper.deproxy(specimen, FieldUnit.class)));
820 }
821 //DerivedUnit
822 else if(specimen.isInstanceOf(DerivedUnit.class)){
823 DerivedUnit derivedUnit = HibernateProxyHelper.deproxy(specimen, DerivedUnit.class);
824 if(derivedUnit.getDerivedFrom()!=null){
825 Collection<FieldUnit> fieldUnits = getFieldUnits(derivedUnit);
826 for(FieldUnit fieldUnit:fieldUnits){
827 nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(fieldUnit));
828 }
829 }
830 }
831 return nonCascadedCdmEntities;
832 }
833
834 private Collection<ICdmBase> getFieldUnitNonCascadedAssociatedElements(FieldUnit fieldUnit){
835 //get non cascaded element on SpecimenOrObservationBase level
836 Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(fieldUnit);
837
838 //get FieldUnit specific elements
839 GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();
840 if(gatheringEvent!=null){
841 //country
842 if(gatheringEvent.getCountry()!=null){
843 nonCascadedCdmEntities.add(gatheringEvent.getCountry());
844 }
845 //collecting areas
846 for (NamedArea namedArea : gatheringEvent.getCollectingAreas()) {
847 nonCascadedCdmEntities.add(namedArea);
848 }
849 }
850 for (DerivationEvent derivationEvent : fieldUnit.getDerivationEvents()) {
851 for (DerivedUnit derivedUnit : derivationEvent.getDerivatives()) {
852 nonCascadedCdmEntities.addAll(getDerivedUnitNonCascadedAssociatedElements(derivedUnit));
853 }
854 }
855 return nonCascadedCdmEntities;
856 }
857
858 private Collection<ICdmBase> getDerivedUnitNonCascadedAssociatedElements(DerivedUnit derivedUnit){
859 //get non cascaded element on SpecimenOrObservationBase level
860 Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(derivedUnit);
861
862 //get DerivedUnit specific elements
863 if(derivedUnit.getCollection()!=null && derivedUnit.getCollection().getInstitute()!=null){
864 for (DefinedTerm type : derivedUnit.getCollection().getInstitute().getTypes()) {
865 nonCascadedCdmEntities.add(type);
866 }
867 }
868 if(derivedUnit.getPreservation()!=null && derivedUnit.getPreservation().getMedium()!=null){
869 nonCascadedCdmEntities.add(derivedUnit.getPreservation().getMedium());
870 }
871 if(derivedUnit.getStoredUnder()!=null){
872 nonCascadedCdmEntities.add(derivedUnit.getStoredUnder());
873 }
874 return nonCascadedCdmEntities;
875 }
876
877 /**
878 * @param specimen
879 * @return
880 */
881 private Collection<ICdmBase> getSpecimenOrObservationNonCascadedAssociatedElements(
882 SpecimenOrObservationBase<?> specimen) {
883 Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();
884 //scan SpecimenOrObservationBase
885 for(DeterminationEvent determinationEvent:specimen.getDeterminations()){
886 //modifier
887 if(determinationEvent.getModifier()!=null){
888 nonCascadedCdmEntities.add(determinationEvent.getModifier());
889 }
890 }
891 //kindOfUnit
892 if(specimen.getKindOfUnit()!=null){
893 nonCascadedCdmEntities.add(specimen.getKindOfUnit());
894 }
895 //lifeStage
896 if(specimen.getLifeStage()!=null){
897 nonCascadedCdmEntities.add(specimen.getLifeStage());
898 }
899 //sex
900 if(specimen.getSex()!=null){
901 nonCascadedCdmEntities.add(specimen.getSex());
902 }
903 return nonCascadedCdmEntities;
904 }
905
906 /* (non-Javadoc)
907 * @see eu.etaxonomy.cdm.api.service.VersionableServiceBase#isDeletable(eu.etaxonomy.cdm.model.common.VersionableEntity, eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase)
908 */
909 @Override
910 public DeleteResult isDeletable(SpecimenOrObservationBase specimen, DeleteConfiguratorBase config) {
911 DeleteResult deleteResult = new DeleteResult();
912 SpecimenDeleteConfigurator specimenDeleteConfigurator = (SpecimenDeleteConfigurator)config;
913
914 //check elements found by super method
915 Set<CdmBase> relatedObjects = super.isDeletable(specimen, config).getRelatedObjects();
916 for (CdmBase cdmBase : relatedObjects) {
917 //check for type designation
918 if(cdmBase.isInstanceOf(SpecimenTypeDesignation.class) && !specimenDeleteConfigurator.isDeleteFromTypeDesignation()){
919 deleteResult.setAbort();
920 deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is a type specimen."));
921 deleteResult.addRelatedObject(cdmBase);
922 break;
923 }
924 //check for IndividualsAssociations
925 else if(cdmBase.isInstanceOf(IndividualsAssociation.class) && !specimenDeleteConfigurator.isDeleteFromIndividualsAssociation()){
926 deleteResult.setAbort();
927 deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still associated via IndividualsAssociations"));
928 deleteResult.addRelatedObject(cdmBase);
929 break;
930 }
931 //check for specimen/taxon description
932 else if((cdmBase.isInstanceOf(SpecimenDescription.class) || cdmBase.isInstanceOf(TaxonDescription.class))
933 && !specimenDeleteConfigurator.isDeleteFromDescription()){
934 deleteResult.setAbort();
935 deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still used in a Description."));
936 deleteResult.addRelatedObject(cdmBase);
937 break;
938 }
939 //check for children and parents (derivation events)
940 else if(cdmBase.isInstanceOf(DerivationEvent.class)){
941 DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(cdmBase, DerivationEvent.class);
942 //check if derivation event is empty
943 if(!derivationEvent.getDerivatives().isEmpty()){
944 if(derivationEvent.getDerivatives().size()==1 && derivationEvent.getDerivatives().contains(specimen)){
945 //if it is the parent event with only one derivate then the specimen is still deletable
946 continue;
947 }
948 else if(!specimenDeleteConfigurator.isDeleteChildren()){
949 //if not and children should not be deleted then it is undeletable
950 deleteResult.setAbort();
951 deleteResult.addException(new ReferencedObjectUndeletableException("Derivate still has child derivates."));
952 deleteResult.addRelatedObject(cdmBase);
953 break;
954 }
955 else{
956 //check all children if they can be deleted
957 Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
958 DeleteResult childResult = new DeleteResult();
959 for (DerivedUnit derivedUnit : derivatives) {
960 childResult.includeResult(isDeletable(derivedUnit, specimenDeleteConfigurator));
961 }
962 if(!childResult.isOk()){
963 deleteResult.setAbort();
964 deleteResult.includeResult(childResult);
965 deleteResult.addRelatedObject(cdmBase);
966 break;
967 }
968 }
969 }
970 }
971 //check for amplification
972 else if(cdmBase.isInstanceOf(AmplificationResult.class) && !specimenDeleteConfigurator.isDeleteMolecularData()){
973 deleteResult.setAbort();
974 deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in amplification results."));
975 deleteResult.addRelatedObject(cdmBase);
976 break;
977 }
978 //check for sequence
979 else if(cdmBase.isInstanceOf(Sequence.class) && !specimenDeleteConfigurator.isDeleteMolecularData()){
980 deleteResult.setAbort();
981 deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in sequences."));
982 deleteResult.addRelatedObject(cdmBase);
983 break;
984 }
985 }
986 if(deleteResult.isOk()){
987 //add all related object if deletion is OK so they can be handled by the delete() method
988 deleteResult.addRelatedObjects(relatedObjects);
989 }
990 return deleteResult;
991 }
992
993 /* (non-Javadoc)
994 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#delete(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator)
995 */
996 @Override
997 public DeleteResult delete(SpecimenOrObservationBase<?> specimen, SpecimenDeleteConfigurator config) {
998 specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
999
1000 if(config.isDeleteChildren()){
1001 Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();
1002 for (DerivationEvent derivationEvent : derivationEvents) {
1003 Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
1004 for (DerivedUnit derivedUnit : derivatives) {
1005 delete(derivedUnit, config);
1006 }
1007 }
1008 }
1009
1010 DeleteResult deleteResult = isDeletable(specimen, config);
1011 if(!deleteResult.isOk()){
1012 return deleteResult;
1013 }
1014
1015 //check related objects
1016 Set<CdmBase> relatedObjects = deleteResult.getRelatedObjects();
1017
1018 for (CdmBase relatedObject : relatedObjects) {
1019 //check for TypeDesignations
1020 if(relatedObject.isInstanceOf(SpecimenTypeDesignation.class)){
1021 SpecimenTypeDesignation designation = HibernateProxyHelper.deproxy(relatedObject, SpecimenTypeDesignation.class);
1022 designation.setTypeSpecimen(null);
1023 Set<TaxonNameBase> typifiedNames = designation.getTypifiedNames();
1024 for (TaxonNameBase taxonNameBase : typifiedNames) {
1025 taxonNameBase.removeTypeDesignation(designation);
1026 }
1027 }
1028 //delete IndividualsAssociation
1029 if(relatedObject.isInstanceOf(IndividualsAssociation.class)){
1030 IndividualsAssociation assciation = HibernateProxyHelper.deproxy(relatedObject, IndividualsAssociation.class);
1031 assciation.setAssociatedSpecimenOrObservation(null);
1032 assciation.getInDescription().removeElement(assciation);
1033 }
1034 //check for taxon description
1035 if(relatedObject.isInstanceOf(TaxonDescription.class)){
1036 TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(relatedObject, TaxonDescription.class);
1037 taxonDescription.setDescribedSpecimenOrObservation(null);
1038 }
1039 //check for specimen description
1040 if(relatedObject.isInstanceOf(SpecimenDescription.class)){
1041 SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(relatedObject, SpecimenDescription.class);
1042 //check if specimen is "described" specimen
1043 if(specimenDescription.getDescribedSpecimenOrObservation().equals(specimen)){
1044 specimenDescription.setDescribedSpecimenOrObservation(null);
1045 }
1046 //check if description is a description of the given specimen
1047 if(specimen.getDescriptions().contains(specimenDescription)){
1048 specimen.removeDescription(specimenDescription);
1049 }
1050 }
1051 //check for amplification
1052 if(relatedObject.isInstanceOf(AmplificationResult.class)){
1053 AmplificationResult amplificationResult = HibernateProxyHelper.deproxy(relatedObject, AmplificationResult.class);
1054 amplificationResult.getDnaSample().removeAmplificationResult(amplificationResult);
1055 }
1056 //check for sequence
1057 if(relatedObject.isInstanceOf(Sequence.class)){
1058 Sequence sequence = HibernateProxyHelper.deproxy(relatedObject, Sequence.class);
1059 sequence.getDnaSample().removeSequence(sequence);
1060 }
1061 //check for children and parents (derivation events)
1062 if(relatedObject.isInstanceOf(DerivationEvent.class)){
1063 DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(relatedObject, DerivationEvent.class);
1064 //parent derivation event (derivedFrom)
1065 if(derivationEvent.getDerivatives().contains(specimen) && specimen.isInstanceOf(DerivedUnit.class)){
1066 derivationEvent.removeDerivative(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class));
1067 if(derivationEvent.getDerivatives().isEmpty()){
1068 Set<SpecimenOrObservationBase> originals = derivationEvent.getOriginals();
1069 for (SpecimenOrObservationBase specimenOrObservationBase : originals) {
1070 specimenOrObservationBase.removeDerivationEvent(derivationEvent);
1071 }
1072 }
1073 }
1074 else{
1075 //child derivation events should not occur since we delete the hierarchy from bottom to top
1076 }
1077 }
1078 }
1079
1080 deleteResult.includeResult(delete(specimen));
1081 return deleteResult;
1082 }
1083
1084 /* (non-Javadoc)
1085 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#deleteDerivateHierarchy(eu.etaxonomy.cdm.model.common.ICdmBase)
1086 */
1087 @Override
1088 public DeleteResult deleteDerivateHierarchy(CdmBase from, SpecimenDeleteConfigurator config) {
1089 DeleteResult deleteResult = new DeleteResult();
1090 if(from.isInstanceOf(Sequence.class)){
1091 if(!config.isDeleteMolecularData()){
1092 deleteResult.setAbort();
1093 deleteResult.addException(new ReferencedObjectUndeletableException("deleting molecur data is not allowed in config"));
1094 return deleteResult;
1095 }
1096 Sequence sequence = HibernateProxyHelper.deproxy(from, Sequence.class);
1097 sequence.getDnaSample().removeSequence(sequence);
1098 deleteResult = sequenceService.delete(sequence);
1099 }
1100 else if(from.isInstanceOf(SingleRead.class)) {
1101 if(!config.isDeleteMolecularData()){
1102 deleteResult.setAbort();
1103 deleteResult.addException(new ReferencedObjectUndeletableException("deleting molecur data is not allowed in config"));
1104 return deleteResult;
1105 }
1106 SingleRead singleRead = HibernateProxyHelper.deproxy(from, SingleRead.class);
1107 singleRead.getAmplificationResult().removeSingleRead(singleRead);
1108 deleteResult.setStatus(DeleteStatus.OK);
1109 }
1110 else if(from.isInstanceOf(SpecimenOrObservationBase.class)) {
1111 deleteResult = delete(HibernateProxyHelper.deproxy(from, SpecimenOrObservationBase.class), config);
1112 }
1113 return deleteResult;
1114 }
1115
1116 // private DeleteResult deepDelete(SpecimenOrObservationBase<?> entity, SpecimenDeleteConfigurator config){
1117 // Set<DerivationEvent> derivationEvents = entity.getDerivationEvents();
1118 // for (DerivationEvent derivationEvent : derivationEvents) {
1119 // Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
1120 // for (DerivedUnit derivedUnit : derivatives) {
1121 // DeleteResult deleteResult = deepDelete(derivedUnit, config);
1122 // if(!deleteResult.isOk()){
1123 // return deleteResult;
1124 // }
1125 // }
1126 // }
1127 // return delete(entity, config);
1128 // }
1129
1130 /* (non-Javadoc)
1131 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listAssociatedTaxa(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase)
1132 */
1133 @Override
1134 public Collection<IndividualsAssociation> listIndividualsAssociations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1135 return dao.listIndividualsAssociations(specimen, null, null, null, null);
1136 }
1137
1138 /* (non-Javadoc)
1139 * @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)
1140 */
1141 @Override
1142 public Collection<SpecimenTypeDesignation> listTypeDesignations(SpecimenOrObservationBase<?> specimen,
1143 Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1144 return dao.listTypeDesignations(specimen, limit, start, orderHints, propertyPaths);
1145 }
1146
1147 /* (non-Javadoc)
1148 * @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)
1149 */
1150 @Override
1151 public Collection<DescriptionBase<?>> listDescriptionsWithDescriptionSpecimen(
1152 SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints,
1153 List<String> propertyPaths) {
1154 return dao.listDescriptionsWithDescriptionSpecimen(specimen, limit, start, orderHints, propertyPaths);
1155 }
1156
1157 }