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