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