Fix moving of derivatives with null parent (+test)
[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.Collections;
20 import java.util.HashMap;
21 import java.util.HashSet;
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.dao.DataRetrievalFailureException;
39 import org.springframework.stereotype.Service;
40 import org.springframework.transaction.annotation.Transactional;
41
42 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
43 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeConfigurator;
44 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeNotSupportedException;
45 import eu.etaxonomy.cdm.api.service.UpdateResult.Status;
46 import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase;
47 import eu.etaxonomy.cdm.api.service.config.FindOccurrencesConfigurator;
48 import eu.etaxonomy.cdm.api.service.config.IIdentifiableEntityServiceConfigurator;
49 import eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator;
50 import eu.etaxonomy.cdm.api.service.dto.DerivateDTO;
51 import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO;
52 import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO.ContigFile;
53 import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO.MolecularData;
54 import eu.etaxonomy.cdm.api.service.dto.FieldUnitDTO;
55 import eu.etaxonomy.cdm.api.service.dto.PreservedSpecimenDTO;
56 import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
57 import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;
58 import eu.etaxonomy.cdm.api.service.pager.Pager;
59 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
60 import eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider;
61 import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;
62 import eu.etaxonomy.cdm.api.service.search.LuceneSearch;
63 import eu.etaxonomy.cdm.api.service.search.LuceneSearch.TopGroupsWithMaxScore;
64 import eu.etaxonomy.cdm.api.service.search.QueryFactory;
65 import eu.etaxonomy.cdm.api.service.search.SearchResult;
66 import eu.etaxonomy.cdm.api.service.search.SearchResultBuilder;
67 import eu.etaxonomy.cdm.api.service.util.TaxonRelationshipEdge;
68 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
69 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
70 import eu.etaxonomy.cdm.model.CdmBaseType;
71 import eu.etaxonomy.cdm.model.agent.AgentBase;
72 import eu.etaxonomy.cdm.model.common.CdmBase;
73 import eu.etaxonomy.cdm.model.common.DefinedTerm;
74 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
75 import eu.etaxonomy.cdm.model.common.ICdmBase;
76 import eu.etaxonomy.cdm.model.common.Language;
77 import eu.etaxonomy.cdm.model.description.CategoricalData;
78 import eu.etaxonomy.cdm.model.description.DescriptionBase;
79 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
80 import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
81 import eu.etaxonomy.cdm.model.description.QuantitativeData;
82 import eu.etaxonomy.cdm.model.description.SpecimenDescription;
83 import eu.etaxonomy.cdm.model.description.TaxonDescription;
84 import eu.etaxonomy.cdm.model.location.Country;
85 import eu.etaxonomy.cdm.model.location.NamedArea;
86 import eu.etaxonomy.cdm.model.media.Media;
87 import eu.etaxonomy.cdm.model.media.MediaRepresentation;
88 import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
89 import eu.etaxonomy.cdm.model.media.MediaUtils;
90 import eu.etaxonomy.cdm.model.molecular.AmplificationResult;
91 import eu.etaxonomy.cdm.model.molecular.DnaSample;
92 import eu.etaxonomy.cdm.model.molecular.Sequence;
93 import eu.etaxonomy.cdm.model.molecular.SingleRead;
94 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
95 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
96 import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;
97 import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;
98 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
99 import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;
100 import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
101 import eu.etaxonomy.cdm.model.occurrence.GatheringEvent;
102 import eu.etaxonomy.cdm.model.occurrence.MediaSpecimen;
103 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
104 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
105 import eu.etaxonomy.cdm.model.taxon.Taxon;
106 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
107 import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
108 import eu.etaxonomy.cdm.persistence.dao.initializer.AbstractBeanInitializer;
109 import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
110 import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
111 import eu.etaxonomy.cdm.persistence.query.OrderHint;
112 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
113
114 /**
115 * @author a.babadshanjan
116 * @created 01.09.2008
117 */
118 @Service
119 @Transactional(readOnly = true)
120 public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObservationBase, IOccurrenceDao> implements IOccurrenceService {
121
122 static private final Logger logger = Logger.getLogger(OccurrenceServiceImpl.class);
123
124 @Autowired
125 private IDefinedTermDao definedTermDao;
126
127 @Autowired
128 private IDescriptionService descriptionService;
129
130 @Autowired
131 private ITaxonService taxonService;
132
133 @Autowired
134 private ISequenceService sequenceService;
135
136 @Autowired
137 private AbstractBeanInitializer beanInitializer;
138
139 @Autowired
140 private ILuceneIndexToolProvider luceneIndexToolProvider;
141
142 private static final String SEPARATOR_STRING = ", ";
143
144 public OccurrenceServiceImpl() {
145 logger.debug("Load OccurrenceService Bean");
146 }
147
148
149 @Override
150 @Transactional(readOnly = false)
151 public void updateTitleCache(Class<? extends SpecimenOrObservationBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<SpecimenOrObservationBase> cacheStrategy, IProgressMonitor monitor) {
152 if (clazz == null) {
153 clazz = SpecimenOrObservationBase.class;
154 }
155 super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
156 }
157
158 /**
159 * FIXME Candidate for harmonization
160 * move to termService
161 */
162 @Override
163 public Country getCountryByIso(String iso639) {
164 return this.definedTermDao.getCountryByIso(iso639);
165
166 }
167
168 /**
169 * FIXME Candidate for harmonization
170 * move to termService
171 */
172 @Override
173 public List<Country> getCountryByName(String name) {
174 List<? extends DefinedTermBase> terms = this.definedTermDao.findByTitle(Country.class, name, null, null, null, null, null, null);
175 List<Country> countries = new ArrayList<Country>();
176 for (int i = 0; i < terms.size(); i++) {
177 countries.add((Country) terms.get(i));
178 }
179 return countries;
180 }
181
182 @Override
183 @Autowired
184 protected void setDao(IOccurrenceDao dao) {
185 this.dao = dao;
186 }
187
188 @Override
189 public Pager<DerivationEvent> getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
190 Integer numberOfResults = dao.countDerivationEvents(occurence);
191
192 List<DerivationEvent> results = new ArrayList<DerivationEvent>();
193 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
194 results = dao.getDerivationEvents(occurence, pageSize, pageNumber, propertyPaths);
195 }
196
197 return new DefaultPagerImpl<DerivationEvent>(pageNumber, numberOfResults, pageSize, results);
198 }
199
200 @Override
201 public int countDeterminations(SpecimenOrObservationBase occurence, TaxonBase taxonbase) {
202 return dao.countDeterminations(occurence, taxonbase);
203 }
204
205 @Override
206 public Pager<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
207 Integer numberOfResults = dao.countDeterminations(occurrence, taxonBase);
208
209 List<DeterminationEvent> results = new ArrayList<DeterminationEvent>();
210 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
211 results = dao.getDeterminations(occurrence, taxonBase, pageSize, pageNumber, propertyPaths);
212 }
213
214 return new DefaultPagerImpl<DeterminationEvent>(pageNumber, numberOfResults, pageSize, results);
215 }
216
217 @Override
218 public Pager<Media> getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
219 Integer numberOfResults = dao.countMedia(occurence);
220
221 List<Media> results = new ArrayList<Media>();
222 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
223 results = dao.getMedia(occurence, pageSize, pageNumber, propertyPaths);
224 }
225
226 return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);
227 }
228
229 @Override
230 public Pager<Media> getMediainHierarchy(SpecimenOrObservationBase rootOccurence, Integer pageSize,
231 Integer pageNumber, List<String> propertyPaths) {
232 List<Media> media = new ArrayList<Media>();
233 //media specimens
234 if(rootOccurence.isInstanceOf(MediaSpecimen.class)){
235 MediaSpecimen mediaSpecimen = HibernateProxyHelper.deproxy(rootOccurence, MediaSpecimen.class);
236 media.add(mediaSpecimen.getMediaSpecimen());
237 }
238 // pherograms & gelPhotos
239 if (rootOccurence.isInstanceOf(DnaSample.class)) {
240 DnaSample dnaSample = CdmBase.deproxy(rootOccurence, DnaSample.class);
241 Set<Sequence> sequences = dnaSample.getSequences();
242 //we do show only those gelPhotos which lead to a consensus sequence
243 for (Sequence sequence : sequences) {
244 Set<Media> dnaRelatedMedia = new HashSet<Media>();
245 for (SingleRead singleRead : sequence.getSingleReads()){
246 AmplificationResult amplification = singleRead.getAmplificationResult();
247 dnaRelatedMedia.add(amplification.getGelPhoto());
248 dnaRelatedMedia.add(singleRead.getPherogram());
249 dnaRelatedMedia.remove(null);
250 }
251 media.addAll(dnaRelatedMedia);
252 }
253 }
254 if(rootOccurence.isInstanceOf(DerivedUnit.class)){
255 DerivedUnit derivedUnit = HibernateProxyHelper.deproxy(rootOccurence, DerivedUnit.class);
256 for (DerivationEvent derivationEvent : derivedUnit.getDerivationEvents()) {
257 for (DerivedUnit childDerivative : derivationEvent.getDerivatives()) {
258 media.addAll(getMediainHierarchy(childDerivative, pageSize, pageNumber, propertyPaths).getRecords());
259 }
260 }
261 }
262 return new DefaultPagerImpl<Media>(pageNumber, media.size(), pageSize, media);
263 }
264
265 @Override
266 public Pager<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> type, TaxonBase determinedAs, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
267 Integer numberOfResults = dao.count(type, determinedAs);
268 List<SpecimenOrObservationBase> results = new ArrayList<SpecimenOrObservationBase>();
269 pageNumber = pageNumber == null ? 0 : pageNumber;
270 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
271 Integer start = pageSize == null ? 0 : pageSize * pageNumber;
272 results = dao.list(type, determinedAs, pageSize, start, orderHints, propertyPaths);
273 }
274 return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, numberOfResults, pageSize, results);
275 }
276
277 @Override
278 public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache() {
279 return dao.getDerivedUnitUuidAndTitleCache();
280 }
281
282 @Override
283 public List<UuidAndTitleCache<FieldUnit>> getFieldUnitUuidAndTitleCache() {
284 return dao.getFieldUnitUuidAndTitleCache();
285 }
286
287 @Override
288 public DerivedUnitFacade getDerivedUnitFacade(DerivedUnit derivedUnit, List<String> propertyPaths) throws DerivedUnitFacadeNotSupportedException {
289 derivedUnit = (DerivedUnit) dao.load(derivedUnit.getUuid(), null);
290 DerivedUnitFacadeConfigurator config = DerivedUnitFacadeConfigurator.NewInstance();
291 config.setThrowExceptionForNonSpecimenPreservationMethodRequest(false);
292 DerivedUnitFacade derivedUnitFacade = DerivedUnitFacade.NewInstance(derivedUnit, config);
293 beanInitializer.initialize(derivedUnitFacade, propertyPaths);
294 return derivedUnitFacade;
295 }
296
297 @Override
298 public List<DerivedUnitFacade> listDerivedUnitFacades(
299 DescriptionBase description, List<String> propertyPaths) {
300
301 List<DerivedUnitFacade> derivedUnitFacadeList = new ArrayList<DerivedUnitFacade>();
302 IndividualsAssociation tempIndividualsAssociation;
303 SpecimenOrObservationBase tempSpecimenOrObservationBase;
304 List<DescriptionElementBase> elements = descriptionService.listDescriptionElements(description, null, IndividualsAssociation.class, null, 0, Arrays.asList(new String []{"associatedSpecimenOrObservation"}));
305 for (DescriptionElementBase element : elements) {
306 if (element.isInstanceOf(IndividualsAssociation.class)) {
307 tempIndividualsAssociation = HibernateProxyHelper.deproxy(element, IndividualsAssociation.class);
308 if (tempIndividualsAssociation.getAssociatedSpecimenOrObservation() != null) {
309 tempSpecimenOrObservationBase = HibernateProxyHelper.deproxy(tempIndividualsAssociation.getAssociatedSpecimenOrObservation(), SpecimenOrObservationBase.class);
310 if (tempSpecimenOrObservationBase.isInstanceOf(DerivedUnit.class)) {
311 try {
312 derivedUnitFacadeList.add(DerivedUnitFacade.NewInstance(HibernateProxyHelper.deproxy(tempSpecimenOrObservationBase, DerivedUnit.class)));
313 } catch (DerivedUnitFacadeNotSupportedException e) {
314 logger.warn(tempIndividualsAssociation.getAssociatedSpecimenOrObservation().getTitleCache() + " : " + e.getMessage());
315 }
316 }
317 }
318
319 }
320 }
321
322 beanInitializer.initializeAll(derivedUnitFacadeList, propertyPaths);
323
324 return derivedUnitFacadeList;
325 }
326
327
328 @Override
329 public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
330 Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
331
332 return pageByAssociatedTaxon(type, includeRelationships, associatedTaxon, maxDepth, pageSize, pageNumber, orderHints, propertyPaths).getRecords();
333 }
334
335 @Override
336 public Collection<SpecimenOrObservationBase> listFieldUnitsByAssociatedTaxon(Taxon associatedTaxon, List<OrderHint> orderHints, List<String> propertyPaths) {
337 return pageFieldUnitsByAssociatedTaxon(null, associatedTaxon, null, null, null, null, propertyPaths).getRecords();
338 }
339
340 @Override
341 public Pager<SpecimenOrObservationBase> pageFieldUnitsByAssociatedTaxon(Set<TaxonRelationshipEdge> includeRelationships,
342 Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
343 List<String> propertyPaths) {
344
345 if (!getSession().contains(associatedTaxon)) {
346 associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());
347 }
348
349 // gather the IDs of all relevant field units
350 Set<Integer> fieldUnitIds = new HashSet<Integer>();
351 List<SpecimenOrObservationBase> records = listByAssociatedTaxon(null, includeRelationships, associatedTaxon, maxDepth, null, null, orderHints, propertyPaths);
352 for (SpecimenOrObservationBase<?> specimen : records) {
353 for (FieldUnit fieldUnit : getFieldUnits(specimen.getUuid())) {
354 fieldUnitIds.add(fieldUnit.getId());
355 }
356 }
357 //dao.listByIds() does the paging of the field units. Passing the field units directly to the Pager would not work
358 List<SpecimenOrObservationBase> fieldUnits = dao.listByIds(fieldUnitIds, pageSize, pageNumber, orderHints, propertyPaths);
359 return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, fieldUnitIds.size(), pageSize, fieldUnits);
360 }
361
362 @Override
363 public FieldUnitDTO assembleFieldUnitDTO(FieldUnit fieldUnit, UUID associatedTaxonUuid) {
364
365 if (!getSession().contains(fieldUnit)) {
366 fieldUnit = (FieldUnit) load(fieldUnit.getUuid());
367 }
368 TaxonBase associatedTaxon = taxonService.load(associatedTaxonUuid);
369
370 FieldUnitDTO fieldUnitDTO = new FieldUnitDTO();
371
372 if (fieldUnit.getGatheringEvent() != null) {
373 GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();
374 // Country
375 NamedArea country = gatheringEvent.getCountry();
376 fieldUnitDTO.setCountry(country != null ? country.getDescription() : null);
377 // Collection
378 AgentBase collector = gatheringEvent.getCollector();
379 String fieldNumber = fieldUnit.getFieldNumber();
380 String collectionString = "";
381 if (collector != null || fieldNumber != null) {
382 collectionString += collector != null ? collector : "";
383 if (!collectionString.isEmpty()) {
384 collectionString += " ";
385 }
386 collectionString += (fieldNumber != null ? fieldNumber : "");
387 collectionString.trim();
388 }
389 fieldUnitDTO.setCollection(collectionString);
390 // Date
391 Partial gatheringDate = gatheringEvent.getGatheringDate();
392 String dateString = null;
393 if (gatheringDate != null) {
394 gatheringDate.toString();
395 }
396 else if(gatheringEvent.getTimeperiod()!=null && gatheringEvent.getTimeperiod().getFreeText()!=null){
397 dateString = gatheringEvent.getTimeperiod().getFreeText();
398 }
399 fieldUnitDTO.setDate(dateString);
400 }
401
402 // Taxon Name
403 fieldUnitDTO.setTaxonName(associatedTaxon.getName().getTitleCache());
404
405 // Herbaria map
406 Map<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> collectionToCountMap = new HashMap<eu.etaxonomy.cdm.model.occurrence.Collection, Integer>();
407 // List of accession numbers for citation
408 List<String> preservedSpecimenAccessionNumbers = new ArrayList<String>();
409
410 // assemble preserved specimen DTOs
411 Set<DerivationEvent> derivationEvents = fieldUnit.getDerivationEvents();
412 for (DerivationEvent derivationEvent : derivationEvents) {
413 Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
414 for (DerivedUnit derivedUnit : derivatives) {
415 // collect accession numbers for citation
416 String mostSignificantIdentifier = getMostSignificantIdentifier(derivedUnit);
417 if (mostSignificantIdentifier != null) {
418 preservedSpecimenAccessionNumbers.add(mostSignificantIdentifier);
419 }
420 // collect collections for herbaria column
421 if (derivedUnit.getCollection() != null) {
422 Integer herbariumCount = collectionToCountMap.get(derivedUnit.getCollection());
423 if (herbariumCount == null) {
424 herbariumCount = 0;
425 }
426 collectionToCountMap.put(derivedUnit.getCollection(), herbariumCount + 1);
427 }
428 if (derivedUnit.getRecordBasis().equals(SpecimenOrObservationType.PreservedSpecimen)) {
429 PreservedSpecimenDTO preservedSpecimenDTO = assemblePreservedSpecimenDTO(derivedUnit, fieldUnitDTO);
430 fieldUnitDTO.addPreservedSpecimenDTO(preservedSpecimenDTO);
431 fieldUnitDTO.setHasCharacterData(fieldUnitDTO.isHasCharacterData() || preservedSpecimenDTO.isHasCharacterData());
432 fieldUnitDTO.setHasDetailImage(fieldUnitDTO.isHasDetailImage() || preservedSpecimenDTO.isHasDetailImage());
433 fieldUnitDTO.setHasDna(fieldUnitDTO.isHasDna() || preservedSpecimenDTO.isHasDna());
434 fieldUnitDTO.setHasSpecimenScan(fieldUnitDTO.isHasSpecimenScan() || preservedSpecimenDTO.isHasSpecimenScan());
435 }
436 }
437 }
438 // assemble derivate data DTO
439 assembleDerivateDataDTO(fieldUnitDTO, fieldUnit);
440
441 // assemble citation
442 String citation = fieldUnit.getTitleCache();
443 if (!preservedSpecimenAccessionNumbers.isEmpty()) {
444 citation += " (";
445 for (String accessionNumber : preservedSpecimenAccessionNumbers) {
446 if (!accessionNumber.isEmpty()) {
447 citation += accessionNumber + SEPARATOR_STRING;
448 }
449 }
450 citation = removeTail(citation, SEPARATOR_STRING);
451 citation += ")";
452 }
453 fieldUnitDTO.setCitation(citation);
454
455 // assemble herbaria string
456 String herbariaString = "";
457 for (Entry<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> e : collectionToCountMap.entrySet()) {
458 eu.etaxonomy.cdm.model.occurrence.Collection collection = e.getKey();
459 if (collection.getCode() != null) {
460 herbariaString += collection.getCode();
461 }
462 if (e.getValue() > 1) {
463 herbariaString += "(" + e.getValue() + ")";
464 }
465 herbariaString += SEPARATOR_STRING;
466 }
467 herbariaString = removeTail(herbariaString, SEPARATOR_STRING);
468 fieldUnitDTO.setHerbarium(herbariaString);
469
470 return fieldUnitDTO;
471 }
472
473 @Override
474 public PreservedSpecimenDTO assemblePreservedSpecimenDTO(DerivedUnit derivedUnit) {
475 return assemblePreservedSpecimenDTO(derivedUnit, null);
476 }
477
478 @Override
479 public String getMostSignificantIdentifier(DerivedUnit derivedUnit) {
480 if (derivedUnit.getAccessionNumber() != null && !derivedUnit.getAccessionNumber().isEmpty()) {
481 return derivedUnit.getAccessionNumber();
482 }
483 else if(derivedUnit.getBarcode()!=null && !derivedUnit.getBarcode().isEmpty()){
484 return derivedUnit.getBarcode();
485 }
486 else if(derivedUnit.getCatalogNumber()!=null && !derivedUnit.getCatalogNumber().isEmpty()){
487 return derivedUnit.getCatalogNumber();
488 }
489 return null;
490 }
491
492 public PreservedSpecimenDTO assemblePreservedSpecimenDTO(DerivedUnit derivedUnit, FieldUnitDTO fieldUnitDTO) {
493 if (!getSession().contains(derivedUnit)) {
494 derivedUnit = (DerivedUnit) load(derivedUnit.getUuid());
495 }
496 PreservedSpecimenDTO preservedSpecimenDTO = new PreservedSpecimenDTO();
497
498 // check identifiers in priority order accNo>barCode>catalogNumber
499 if (derivedUnit.getAccessionNumber() != null && !derivedUnit.getAccessionNumber().isEmpty()) {
500 preservedSpecimenDTO.setAccessionNumber(derivedUnit.getAccessionNumber());
501 }
502 else if(derivedUnit.getBarcode()!=null && !derivedUnit.getBarcode().isEmpty()){
503 preservedSpecimenDTO.setAccessionNumber(derivedUnit.getBarcode());
504 }
505 else if(derivedUnit.getCatalogNumber()!=null && !derivedUnit.getCatalogNumber().isEmpty()){
506 preservedSpecimenDTO.setAccessionNumber(derivedUnit.getCatalogNumber());
507 }
508 preservedSpecimenDTO.setUuid(derivedUnit.getUuid().toString());
509
510 // citation
511 Collection<FieldUnit> fieldUnits = getFieldUnits(derivedUnit);
512 if (fieldUnits.size() == 1) {
513 preservedSpecimenDTO.setCitation(fieldUnits.iterator().next().getTitleCache());
514 }
515 else{
516 preservedSpecimenDTO.setCitation("No Citation available. This specimen either has no or multiple field units.");
517 }
518
519 // character state data
520 Collection<DescriptionElementBase> characterDataForSpecimen = getCharacterDataForSpecimen(derivedUnit);
521 if (!characterDataForSpecimen.isEmpty()) {
522 if (fieldUnitDTO != null) {
523 fieldUnitDTO.setHasCharacterData(true);
524 }
525 }
526 for (DescriptionElementBase descriptionElementBase : characterDataForSpecimen) {
527 String character = descriptionElementBase.getFeature().getLabel();
528 ArrayList<Language> languages = new ArrayList<Language>(Collections.singleton(Language.DEFAULT()));
529 if (descriptionElementBase instanceof QuantitativeData) {
530 QuantitativeData quantitativeData = (QuantitativeData) descriptionElementBase;
531 DefaultQuantitativeDescriptionBuilder builder = new DefaultQuantitativeDescriptionBuilder();
532 String state = builder.build(quantitativeData, languages).getText(Language.DEFAULT());
533 preservedSpecimenDTO.addCharacterData(character, state);
534 }
535 else if(descriptionElementBase instanceof CategoricalData){
536 CategoricalData categoricalData = (CategoricalData) descriptionElementBase;
537 DefaultCategoricalDescriptionBuilder builder = new DefaultCategoricalDescriptionBuilder();
538 String state = builder.build(categoricalData, languages).getText(Language.DEFAULT());
539 preservedSpecimenDTO.addCharacterData(character, state);
540 }
541 }
542 // check type designations
543 Collection<SpecimenTypeDesignation> specimenTypeDesignations = listTypeDesignations(derivedUnit, null, null, null, null);
544 for (SpecimenTypeDesignation specimenTypeDesignation : specimenTypeDesignations) {
545 if (fieldUnitDTO != null) {
546 fieldUnitDTO.setHasType(true);
547 }
548 TypeDesignationStatusBase<?> typeStatus = specimenTypeDesignation.getTypeStatus();
549 if (typeStatus != null) {
550 List<String> typedTaxaNames = new ArrayList<String>();
551 String label = typeStatus.getLabel();
552 Set<TaxonNameBase> typifiedNames = specimenTypeDesignation.getTypifiedNames();
553 for (TaxonNameBase taxonNameBase : typifiedNames) {
554 typedTaxaNames.add(taxonNameBase.getFullTitleCache());
555 }
556 preservedSpecimenDTO.addTypes(label, typedTaxaNames);
557 }
558 }
559
560 // individuals associations
561 Collection<IndividualsAssociation> individualsAssociations = listIndividualsAssociations(derivedUnit, null, null, null, null);
562 for (IndividualsAssociation individualsAssociation : individualsAssociations) {
563 if (individualsAssociation.getInDescription() != null) {
564 if (individualsAssociation.getInDescription().isInstanceOf(TaxonDescription.class)) {
565 TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(individualsAssociation.getInDescription(), TaxonDescription.class);
566 Taxon taxon = taxonDescription.getTaxon();
567 if (taxon != null && taxon.getName() != null) {
568 preservedSpecimenDTO.addAssociatedTaxon(taxon.getName().getTitleCache());
569 }
570 }
571 }
572 }
573 // assemble sub derivates
574 preservedSpecimenDTO.setDerivateDataDTO(assembleDerivateDataDTO(preservedSpecimenDTO, derivedUnit));
575 return preservedSpecimenDTO;
576 }
577
578 private DerivateDataDTO assembleDerivateDataDTO(DerivateDTO derivateDTO, SpecimenOrObservationBase<?> specimenOrObservation) {
579 DerivateDataDTO derivateDataDTO = new DerivateDataDTO();
580 Collection<DerivedUnit> childDerivates = getDerivedUnitsFor(specimenOrObservation);
581 for (DerivedUnit childDerivate : childDerivates) {
582 // assemble molecular data
583 //pattern: DNAMarker [contig1, primer1_1, primer1_2, ...][contig2, primer2_1, ...]...
584 if (childDerivate.isInstanceOf(DnaSample.class)) {
585 if (childDerivate.getRecordBasis() == SpecimenOrObservationType.TissueSample) {
586 // TODO implement TissueSample assembly for web service
587 }
588 if (childDerivate.getRecordBasis() == SpecimenOrObservationType.DnaSample) {
589
590 DnaSample dna = HibernateProxyHelper.deproxy(childDerivate, DnaSample.class);
591 if (!dna.getSequences().isEmpty()) {
592 derivateDTO.setHasDna(true);
593 }
594 for (Sequence sequence : dna.getSequences()) {
595 URI boldUri = null;
596 try {
597 boldUri = sequence.getBoldUri();
598 } catch (URISyntaxException e1) {
599 logger.error("Could not create BOLD URI", e1);
600 }
601 final DefinedTerm dnaMarker = sequence.getDnaMarker();
602 MolecularData molecularData = derivateDataDTO.addProviderLink(boldUri != null ? boldUri : null, dnaMarker != null ? dnaMarker.getLabel() : "[no marker]");
603
604 //contig file
605 ContigFile contigFile = null;
606 if (sequence.getContigFile() != null) {
607 MediaRepresentationPart contigMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(sequence.getContigFile());
608 if (contigMediaRepresentationPart != null) {
609 contigFile = molecularData.addContigFile(contigMediaRepresentationPart.getUri(), "contig");
610 }
611 }
612 if(contigFile==null){
613 contigFile = molecularData.addContigFile(null, "[no contig]");
614 }
615 // primer files
616 if (sequence.getSingleReads() != null) {
617 int readCount = 1;
618 for (SingleRead singleRead : sequence.getSingleReads()) {
619 MediaRepresentationPart pherogramMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(singleRead.getPherogram());
620 if (pherogramMediaRepresentationPart != null) {
621 contigFile.addPrimerLink(pherogramMediaRepresentationPart.getUri(), "read"+readCount++);
622 }
623 }
624 }
625 }
626 }
627 }
628 // assemble media data
629 else if (childDerivate.isInstanceOf(MediaSpecimen.class)) {
630 MediaSpecimen media = HibernateProxyHelper.deproxy(childDerivate, MediaSpecimen.class);
631
632 String mediaUriString = getMediaUriString(media);
633 if (media.getKindOfUnit() != null) {
634 // specimen scan
635 if (media.getKindOfUnit().getUuid().equals(UUID.fromString("acda15be-c0e2-4ea8-8783-b9b0c4ad7f03"))) {
636 derivateDataDTO.addSpecimenScanUuid(media.getMediaSpecimen().getUuid());
637 derivateDTO.setHasSpecimenScan(true);
638 String imageLinkText = "scan";
639 if (derivateDTO instanceof PreservedSpecimenDTO && ((PreservedSpecimenDTO) derivateDTO).getAccessionNumber() != null) {
640 imageLinkText = ((PreservedSpecimenDTO) derivateDTO).getAccessionNumber();
641 }
642 derivateDataDTO.addSpecimenScan(mediaUriString == null ? "" : mediaUriString, imageLinkText);
643 }
644 // detail image
645 else if (media.getKindOfUnit().getUuid().equals(UUID.fromString("31eb8d02-bf5d-437c-bcc6-87a626445f34"))) {
646 derivateDataDTO.addDetailImageUuid(media.getMediaSpecimen().getUuid());
647 derivateDTO.setHasDetailImage(true);
648 String motif = "";
649 if (media.getMediaSpecimen() != null && media.getMediaSpecimen().getTitle() != null) {
650 motif = media.getMediaSpecimen().getTitle().getText();
651 }
652 derivateDataDTO.addDetailImage(mediaUriString == null ? "" : mediaUriString, motif != null ? motif : "[no motif]");
653 }
654 }
655 }
656 }
657 return derivateDataDTO;
658 }
659
660 private String removeTail(String string, final String tail) {
661 if (string.endsWith(tail)) {
662 string = string.substring(0, string.length() - tail.length());
663 }
664 return string;
665 }
666
667 private String getMediaUriString(MediaSpecimen mediaSpecimen) {
668 String mediaUri = null;
669 Collection<MediaRepresentation> mediaRepresentations = mediaSpecimen.getMediaSpecimen().getRepresentations();
670 if (mediaRepresentations != null && !mediaRepresentations.isEmpty()) {
671 Collection<MediaRepresentationPart> mediaRepresentationParts = mediaRepresentations.iterator().next().getParts();
672 if (mediaRepresentationParts != null && !mediaRepresentationParts.isEmpty()) {
673 MediaRepresentationPart part = mediaRepresentationParts.iterator().next();
674 if (part.getUri() != null) {
675 mediaUri = part.getUri().toASCIIString();
676 }
677 }
678 }
679 return mediaUri;
680 }
681
682 private Collection<DerivedUnit> getDerivedUnitsFor(SpecimenOrObservationBase<?> specimen) {
683 Collection<DerivedUnit> derivedUnits = new ArrayList<DerivedUnit>();
684 for (DerivationEvent derivationEvent : specimen.getDerivationEvents()) {
685 for (DerivedUnit derivative : derivationEvent.getDerivatives()) {
686 derivedUnits.add(derivative);
687 derivedUnits.addAll(getDerivedUnitsFor(derivative));
688 }
689 }
690 return derivedUnits;
691 }
692
693
694 @SuppressWarnings("unchecked")
695 @Override
696 public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
697 Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
698
699 Set<Taxon> taxa = new HashSet<Taxon>();
700 Set<Integer> occurrenceIds = new HashSet<Integer>();
701 List<T> occurrences = new ArrayList<T>();
702
703 // Integer limit = PagerUtils.limitFor(pageSize);
704 // Integer start = PagerUtils.startFor(pageSize, pageNumber);
705
706 if (!getSession().contains(associatedTaxon)) {
707 associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());
708 }
709
710 if (includeRelationships != null) {
711 taxa = taxonService.listRelatedTaxa(associatedTaxon, includeRelationships, maxDepth, null, null, propertyPaths);
712 }
713
714 taxa.add(associatedTaxon);
715
716 for (Taxon taxon : taxa) {
717 List<T> perTaxonOccurrences = dao.listByAssociatedTaxon(type, taxon, null, null, orderHints, propertyPaths);
718 for (SpecimenOrObservationBase o : perTaxonOccurrences) {
719 occurrenceIds.add(o.getId());
720 }
721 }
722 occurrences = (List<T>) dao.listByIds(occurrenceIds, pageSize, pageNumber, orderHints, propertyPaths);
723
724 return new DefaultPagerImpl<T>(pageNumber, occurrenceIds.size(), pageSize, occurrences);
725
726 }
727
728 @Override
729 public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
730 String taxonUUID, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
731
732 UUID uuid = UUID.fromString(taxonUUID);
733 Taxon tax = (Taxon) taxonService.load(uuid);
734 // TODO REMOVE NULL STATEMENT
735 type = null;
736 return pageByAssociatedTaxon(type, includeRelationships, tax, maxDepth, pageSize, pageNumber, orderHints, propertyPaths);
737
738 }
739
740 @Override
741 public Pager<SearchResult<SpecimenOrObservationBase>> findByFullText(
742 Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle boundingBox, List<Language> languages,
743 boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
744 List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {
745
746 LuceneSearch luceneSearch = prepareByFullTextSearch(clazz, queryString, boundingBox, languages, highlightFragments);
747
748 // --- execute search
749 TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);
750
751 Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
752 idFieldMap.put(CdmBaseType.SPECIMEN_OR_OBSERVATIONBASE, "id");
753
754 // --- initialize taxa, highlight matches ....
755 ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
756 @SuppressWarnings("rawtypes")
757 List<SearchResult<SpecimenOrObservationBase>> searchResults = searchResultBuilder.createResultSet(
758 topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);
759
760 int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupCount : 0;
761
762 return new DefaultPagerImpl<SearchResult<SpecimenOrObservationBase>>(pageNumber, totalHits, pageSize,
763 searchResults);
764
765 }
766
767 private LuceneSearch prepareByFullTextSearch(Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle bbox,
768 List<Language> languages, boolean highlightFragments) {
769
770 BooleanQuery finalQuery = new BooleanQuery();
771 BooleanQuery textQuery = new BooleanQuery();
772
773 LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, FieldUnit.class);
774 QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(FieldUnit.class);
775
776 // --- criteria
777 luceneSearch.setCdmTypRestriction(clazz);
778 if (queryString != null) {
779 textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);
780 finalQuery.add(textQuery, Occur.MUST);
781 }
782
783 // --- spacial query
784 if (bbox != null) {
785 finalQuery.add(QueryFactory.buildSpatialQueryByRange(bbox, "gatheringEvent.exactLocation.point"), Occur.MUST);
786 }
787
788 luceneSearch.setQuery(finalQuery);
789
790 // --- sorting
791 SortField[] sortFields = new SortField[] { SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false) };
792 luceneSearch.setSortFields(sortFields);
793
794 if (highlightFragments) {
795 luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
796 }
797 return luceneSearch;
798 }
799
800
801 @Override
802 public Collection<FieldUnit> getFieldUnits(UUID derivedUnitUuid) {
803 //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})
804 //from which this DerivedUnit was derived until all FieldUnits are found.
805
806 // FIXME: use HQL queries to increase performance
807 SpecimenOrObservationBase<?> specimen = load(derivedUnitUuid);
808 // specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
809 Collection<FieldUnit> fieldUnits = new ArrayList<FieldUnit>();
810
811 if (specimen.isInstanceOf(FieldUnit.class)) {
812 fieldUnits.add(HibernateProxyHelper.deproxy(specimen, FieldUnit.class));
813 }
814 else if(specimen.isInstanceOf(DerivedUnit.class)){
815 fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class)));
816 }
817 return fieldUnits;
818 }
819
820 private Collection<FieldUnit> getFieldUnits(DerivedUnit derivedUnit) {
821 Collection<FieldUnit> fieldUnits = new HashSet<FieldUnit>();
822 Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals();
823 if (originals != null && !originals.isEmpty()) {
824 for (SpecimenOrObservationBase<?> original : originals) {
825 if (original.isInstanceOf(FieldUnit.class)) {
826 fieldUnits.add(HibernateProxyHelper.deproxy(original, FieldUnit.class));
827 }
828 else if(original.isInstanceOf(DerivedUnit.class)){
829 fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(original, DerivedUnit.class)));
830 }
831 }
832 }
833 return fieldUnits;
834 }
835
836 @Override
837 @Transactional(readOnly = false)
838 public UpdateResult moveSequence(DnaSample from, DnaSample to, Sequence sequence) {
839 return moveSequence(from.getUuid(), to.getUuid(), sequence.getUuid());
840 }
841
842 @Override
843 @Transactional(readOnly = false)
844 public UpdateResult moveSequence(UUID fromUuid, UUID toUuid, UUID sequenceUuid) {
845 // reload specimens to avoid session conflicts
846 DnaSample from = (DnaSample) load(fromUuid);
847 DnaSample to = (DnaSample) load(toUuid);
848 Sequence sequence = sequenceService.load(sequenceUuid);
849
850 if (from == null || to == null || sequence == null) {
851 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" +
852 "Operation was move "+sequence+ " from "+from+" to "+to);
853 }
854 UpdateResult result = new UpdateResult();
855 from.removeSequence(sequence);
856 saveOrUpdate(from);
857 to.addSequence(sequence);
858 saveOrUpdate(to);
859 result.setStatus(Status.OK);
860 result.addUpdatedObject(from);
861 result.addUpdatedObject(to);
862 return result;
863 }
864
865 @Override
866 @Transactional(readOnly = false)
867 public boolean moveDerivate(SpecimenOrObservationBase<?> from, SpecimenOrObservationBase<?> to, DerivedUnit derivate) {
868 return moveDerivate(from!=null?from.getUuid():null, to.getUuid(), derivate.getUuid()).isOk();
869 }
870
871 @Override
872 @Transactional(readOnly = false)
873 public UpdateResult moveDerivate(UUID specimenFromUuid, UUID specimenToUuid, UUID derivateUuid) {
874 // reload specimens to avoid session conflicts
875 SpecimenOrObservationBase<?> from = null;
876 if(specimenFromUuid!=null){
877 from = load(specimenFromUuid);
878 }
879 SpecimenOrObservationBase<?> to = load(specimenToUuid);
880 DerivedUnit derivate = (DerivedUnit) load(derivateUuid);
881
882 if ((specimenFromUuid!=null && from == null) || to == null || derivate == null) {
883 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" +
884 "Operation was move "+derivate+ " from "+from+" to "+to);
885 }
886 UpdateResult result = new UpdateResult();
887 SpecimenOrObservationType derivateType = derivate.getRecordBasis();
888 SpecimenOrObservationType toType = to.getRecordBasis();
889 // check if type is a sub derivate type
890 if(toType==SpecimenOrObservationType.FieldUnit //moving to FieldUnit always works
891 || derivateType==SpecimenOrObservationType.Media //moving media always works
892 || (derivateType.isKindOf(toType) && toType!=derivateType)){ //moving only to parent derivate type
893 if(from!=null){
894 // remove derivation event from parent specimen of dragged object
895 DerivationEvent eventToRemove = null;
896 for (DerivationEvent event : from.getDerivationEvents()) {
897 if (event.getDerivatives().contains(derivate)) {
898 eventToRemove = event;
899 break;
900 }
901 }
902 from.removeDerivationEvent(eventToRemove);
903 if(eventToRemove!=null){
904 // add new derivation event to target and copy the event parameters of the old one
905 DerivationEvent derivedFromNewOriginalEvent = DerivationEvent.NewSimpleInstance(to, derivate, null);
906 derivedFromNewOriginalEvent.setActor(eventToRemove.getActor());
907 derivedFromNewOriginalEvent.setDescription(eventToRemove.getDescription());
908 derivedFromNewOriginalEvent.setInstitution(eventToRemove.getInstitution());
909 derivedFromNewOriginalEvent.setTimeperiod(eventToRemove.getTimeperiod());
910 derivedFromNewOriginalEvent.setType(eventToRemove.getType());
911 to.addDerivationEvent(derivedFromNewOriginalEvent);
912 derivate.setDerivedFrom(derivedFromNewOriginalEvent);
913 }
914 }
915 else{
916 //derivative had no parent before so we use empty derivation event
917 DerivationEvent derivedFromNewOriginalEvent = DerivationEvent.NewSimpleInstance(to, derivate, null);
918 to.addDerivationEvent(derivedFromNewOriginalEvent);
919 derivate.setDerivedFrom(derivedFromNewOriginalEvent);
920 }
921
922 if(from!=null){
923 saveOrUpdate(from);
924 }
925 saveOrUpdate(to);
926 result.setStatus(Status.OK);
927 result.addUpdatedObject(from);
928 result.addUpdatedObject(to);
929 } else {
930 result.setStatus(Status.ERROR);
931 }
932 return result;
933 }
934
935 @Override
936 public Collection<ICdmBase> getNonCascadedAssociatedElements(SpecimenOrObservationBase<?> specimen) {
937 // potential fields that are not persisted cascadingly
938 /*
939 * SOOB
940 -DescriptionBase
941 -determinations
942 --modifier TERM
943 -kindOfUnit TERM
944 -lifeStage TERM
945 -sex TERM
946
947 FieldUnit
948 -GatheringEvent
949 --Country TERM
950 --CollectingAreas TERM
951
952 DerivedUnit
953 -collection
954 --institute
955 ---types TERM
956 -preservationMethod
957 --medium TERM
958 -storedUnder CDM TaxonNameBase
959 */
960
961 Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();
962
963 //Choose the correct entry point to traverse the graph (FieldUnit or DerivedUnit)
964
965 // FieldUnit
966 if (specimen.isInstanceOf(FieldUnit.class)) {
967 nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(HibernateProxyHelper.deproxy(specimen, FieldUnit.class)));
968 }
969 // DerivedUnit
970 else if (specimen.isInstanceOf(DerivedUnit.class)) {
971 DerivedUnit derivedUnit = HibernateProxyHelper.deproxy(specimen, DerivedUnit.class);
972 if (derivedUnit.getDerivedFrom() != null) {
973 Collection<FieldUnit> fieldUnits = getFieldUnits(derivedUnit);
974 for (FieldUnit fieldUnit : fieldUnits) {
975 nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(fieldUnit));
976 }
977 }
978 }
979 return nonCascadedCdmEntities;
980 }
981
982 private Collection<ICdmBase> getFieldUnitNonCascadedAssociatedElements(FieldUnit fieldUnit) {
983 // get non cascaded element on SpecimenOrObservationBase level
984 Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(fieldUnit);
985
986 // get FieldUnit specific elements
987 GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();
988 if (gatheringEvent != null) {
989 // country
990 if (gatheringEvent.getCountry() != null) {
991 nonCascadedCdmEntities.add(gatheringEvent.getCountry());
992 }
993 // collecting areas
994 for (NamedArea namedArea : gatheringEvent.getCollectingAreas()) {
995 nonCascadedCdmEntities.add(namedArea);
996 }
997 }
998 for (DerivationEvent derivationEvent : fieldUnit.getDerivationEvents()) {
999 for (DerivedUnit derivedUnit : derivationEvent.getDerivatives()) {
1000 nonCascadedCdmEntities.addAll(getDerivedUnitNonCascadedAssociatedElements(derivedUnit));
1001 }
1002 }
1003 return nonCascadedCdmEntities;
1004 }
1005
1006 private Collection<ICdmBase> getDerivedUnitNonCascadedAssociatedElements(DerivedUnit derivedUnit) {
1007 // get non cascaded element on SpecimenOrObservationBase level
1008 Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(derivedUnit);
1009
1010 // get DerivedUnit specific elements
1011 if (derivedUnit.getCollection() != null && derivedUnit.getCollection().getInstitute() != null) {
1012 for (DefinedTerm type : derivedUnit.getCollection().getInstitute().getTypes()) {
1013 nonCascadedCdmEntities.add(type);
1014 }
1015 }
1016 if (derivedUnit.getPreservation() != null && derivedUnit.getPreservation().getMedium() != null) {
1017 nonCascadedCdmEntities.add(derivedUnit.getPreservation().getMedium());
1018 }
1019 if (derivedUnit.getStoredUnder() != null) {
1020 nonCascadedCdmEntities.add(derivedUnit.getStoredUnder());
1021 }
1022 return nonCascadedCdmEntities;
1023 }
1024
1025 private Collection<ICdmBase> getSpecimenOrObservationNonCascadedAssociatedElements(
1026 SpecimenOrObservationBase<?> specimen) {
1027 Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();
1028 // scan SpecimenOrObservationBase
1029 for (DeterminationEvent determinationEvent : specimen.getDeterminations()) {
1030 // modifier
1031 if (determinationEvent.getModifier() != null) {
1032 nonCascadedCdmEntities.add(determinationEvent.getModifier());
1033 }
1034 }
1035 // kindOfUnit
1036 if (specimen.getKindOfUnit() != null) {
1037 nonCascadedCdmEntities.add(specimen.getKindOfUnit());
1038 }
1039 // lifeStage
1040 if (specimen.getLifeStage() != null) {
1041 nonCascadedCdmEntities.add(specimen.getLifeStage());
1042 }
1043 // sex
1044 if (specimen.getSex() != null) {
1045 nonCascadedCdmEntities.add(specimen.getSex());
1046 }
1047 return nonCascadedCdmEntities;
1048 }
1049
1050 @Override
1051 public DeleteResult isDeletable(SpecimenOrObservationBase specimen, DeleteConfiguratorBase config) {
1052 DeleteResult deleteResult = new DeleteResult();
1053 SpecimenDeleteConfigurator specimenDeleteConfigurator = (SpecimenDeleteConfigurator) config;
1054
1055 // check elements found by super method
1056 Set<CdmBase> relatedObjects = super.isDeletable(specimen, config).getRelatedObjects();
1057 for (CdmBase cdmBase : relatedObjects) {
1058 // check for type designation
1059 if (cdmBase.isInstanceOf(SpecimenTypeDesignation.class) && !specimenDeleteConfigurator.isDeleteFromTypeDesignation()) {
1060 deleteResult.setAbort();
1061 deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is a type specimen."));
1062 deleteResult.addRelatedObject(cdmBase);
1063 break;
1064 }
1065 // check for IndividualsAssociations
1066 else if (cdmBase.isInstanceOf(IndividualsAssociation.class) && !specimenDeleteConfigurator.isDeleteFromIndividualsAssociation()) {
1067 deleteResult.setAbort();
1068 deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still associated via IndividualsAssociations"));
1069 deleteResult.addRelatedObject(cdmBase);
1070 break;
1071 }
1072 // check for specimen/taxon description
1073 else if((cdmBase.isInstanceOf(SpecimenDescription.class) || cdmBase.isInstanceOf(TaxonDescription.class))
1074 && !specimenDeleteConfigurator.isDeleteFromDescription()){
1075 deleteResult.setAbort();
1076 deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still used in a Description."));
1077 deleteResult.addRelatedObject(cdmBase);
1078 break;
1079 }
1080 // check for children and parents (derivation events)
1081 else if (cdmBase.isInstanceOf(DerivationEvent.class)) {
1082 DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(cdmBase, DerivationEvent.class);
1083 // check if derivation event is empty
1084 if (!derivationEvent.getDerivatives().isEmpty()) {
1085 if (derivationEvent.getDerivatives().size() == 1 && derivationEvent.getDerivatives().contains(specimen)) {
1086 //if it is the parent event with only one derivate then the specimen is still deletable
1087 continue;
1088 }
1089 else if(!specimenDeleteConfigurator.isDeleteChildren()){
1090 //if not and children should not be deleted then it is undeletable
1091 deleteResult.setAbort();
1092 deleteResult.addException(new ReferencedObjectUndeletableException("Derivative still has child derivatives."));
1093 deleteResult.addRelatedObject(cdmBase);
1094 break;
1095 }
1096 else{
1097 // check all children if they can be deleted
1098 Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
1099 DeleteResult childResult = new DeleteResult();
1100 for (DerivedUnit derivedUnit : derivatives) {
1101 childResult.includeResult(isDeletable(derivedUnit, specimenDeleteConfigurator));
1102 }
1103 if (!childResult.isOk()) {
1104 deleteResult.setAbort();
1105 deleteResult.includeResult(childResult);
1106 deleteResult.addRelatedObject(cdmBase);
1107 break;
1108 }
1109 }
1110 }
1111 }
1112 // check for amplification
1113 else if (cdmBase.isInstanceOf(AmplificationResult.class) && !specimenDeleteConfigurator.isDeleteMolecularData()) {
1114 deleteResult.setAbort();
1115 deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in amplification results."));
1116 deleteResult.addRelatedObject(cdmBase);
1117 break;
1118 }
1119 // check for sequence
1120 else if (cdmBase.isInstanceOf(Sequence.class) && !specimenDeleteConfigurator.isDeleteMolecularData()) {
1121 deleteResult.setAbort();
1122 deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in sequences."));
1123 deleteResult.addRelatedObject(cdmBase);
1124 break;
1125 }
1126 }
1127 if (deleteResult.isOk()) {
1128 //add all related object if deletion is OK so they can be handled by the delete() method
1129 deleteResult.addRelatedObjects(relatedObjects);
1130 }
1131 return deleteResult;
1132 }
1133
1134 @Override
1135 public DeleteResult delete(SpecimenOrObservationBase<?> specimen, SpecimenDeleteConfigurator config) {
1136 specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
1137
1138 if (config.isDeleteChildren()) {
1139 Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();
1140 //clone to avoid concurrent modification
1141 //can happen if the child is deleted and deleted its own derivedFrom event
1142 Set<DerivationEvent> derivationEventsClone = new HashSet<DerivationEvent>(derivationEvents);
1143 for (DerivationEvent derivationEvent : derivationEventsClone) {
1144 Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
1145 for (DerivedUnit derivedUnit : derivatives) {
1146 delete(derivedUnit, config);
1147 }
1148 }
1149 }
1150
1151 DeleteResult deleteResult = isDeletable(specimen, config);
1152 if (!deleteResult.isOk()) {
1153 return deleteResult;
1154 }
1155
1156 // check related objects
1157 Set<CdmBase> relatedObjects = deleteResult.getRelatedObjects();
1158
1159 for (CdmBase relatedObject : relatedObjects) {
1160 // check for TypeDesignations
1161 if (relatedObject.isInstanceOf(SpecimenTypeDesignation.class)) {
1162 SpecimenTypeDesignation designation = HibernateProxyHelper.deproxy(relatedObject, SpecimenTypeDesignation.class);
1163 designation.setTypeSpecimen(null);
1164 Set<TaxonNameBase> typifiedNames = designation.getTypifiedNames();
1165 for (TaxonNameBase taxonNameBase : typifiedNames) {
1166 taxonNameBase.removeTypeDesignation(designation);
1167 }
1168 }
1169 // delete IndividualsAssociation
1170 if (relatedObject.isInstanceOf(IndividualsAssociation.class)) {
1171 IndividualsAssociation assciation = HibernateProxyHelper.deproxy(relatedObject, IndividualsAssociation.class);
1172 assciation.setAssociatedSpecimenOrObservation(null);
1173 assciation.getInDescription().removeElement(assciation);
1174 }
1175 // check for taxon description
1176 if (relatedObject.isInstanceOf(TaxonDescription.class)) {
1177 TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(relatedObject, TaxonDescription.class);
1178 taxonDescription.setDescribedSpecimenOrObservation(null);
1179 }
1180 // check for specimen description
1181 if (relatedObject.isInstanceOf(SpecimenDescription.class)) {
1182 SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(relatedObject, SpecimenDescription.class);
1183 // check if specimen is "described" specimen
1184 if (specimenDescription.getDescribedSpecimenOrObservation().equals(specimen)) {
1185 specimenDescription.setDescribedSpecimenOrObservation(null);
1186 }
1187 // check if description is a description of the given specimen
1188 if (specimen.getDescriptions().contains(specimenDescription)) {
1189 specimen.removeDescription(specimenDescription);
1190 }
1191 DeleteResult descriptionDelete = descriptionService.isDeletable(specimenDescription, null);
1192 if (descriptionDelete.isOk()){
1193 descriptionService.delete(specimenDescription);
1194 }
1195 }
1196 // check for amplification
1197 if (relatedObject.isInstanceOf(AmplificationResult.class)) {
1198 AmplificationResult amplificationResult = HibernateProxyHelper.deproxy(relatedObject, AmplificationResult.class);
1199 amplificationResult.getDnaSample().removeAmplificationResult(amplificationResult);
1200 }
1201 // check for sequence
1202 if (relatedObject.isInstanceOf(Sequence.class)) {
1203 Sequence sequence = HibernateProxyHelper.deproxy(relatedObject, Sequence.class);
1204 sequence.getDnaSample().removeSequence(sequence);
1205 }
1206 // check for children and parents (derivation events)
1207 if (relatedObject.isInstanceOf(DerivationEvent.class)) {
1208 DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(relatedObject, DerivationEvent.class);
1209 // parent derivation event (derivedFrom)
1210 if (derivationEvent.getDerivatives().contains(specimen) && specimen.isInstanceOf(DerivedUnit.class)) {
1211 derivationEvent.removeDerivative(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class));
1212 if (derivationEvent.getDerivatives().isEmpty()) {
1213 Set<SpecimenOrObservationBase> originals = derivationEvent.getOriginals();
1214 for (SpecimenOrObservationBase specimenOrObservationBase : originals) {
1215 specimenOrObservationBase.removeDerivationEvent(derivationEvent);
1216 deleteResult.addUpdatedObject(specimenOrObservationBase);
1217 }
1218 }
1219 }
1220 else{
1221 //child derivation events should not occur since we delete the hierarchy from bottom to top
1222 }
1223 }
1224 }
1225
1226 deleteResult.includeResult(delete(specimen));
1227 return deleteResult;
1228 }
1229
1230 @Override
1231 public DeleteResult deleteSingleRead(SingleRead singleRead, Sequence sequence){
1232 DeleteResult deleteResult = new DeleteResult();
1233 singleRead = HibernateProxyHelper.deproxy(singleRead, SingleRead.class);
1234 //delete from amplification result
1235 if(singleRead.getAmplificationResult()!=null){
1236 singleRead.getAmplificationResult().removeSingleRead(singleRead);
1237 }
1238 //delete from sequence
1239 sequence.removeSingleRead(singleRead);
1240 deleteResult.addUpdatedObject(sequence);
1241 deleteResult.setStatus(Status.OK);
1242 return deleteResult;
1243 }
1244
1245 @Override
1246 @Transactional(readOnly = false)
1247 public DeleteResult deleteSingleRead(UUID singleReadUuid, UUID sequenceUuid){
1248 SingleRead singleRead = null;
1249 Sequence sequence = CdmBase.deproxy(sequenceService.load(sequenceUuid), Sequence.class);
1250 for(SingleRead sr : sequence.getSingleReads()) {
1251 if(sr.getUuid().equals(singleReadUuid)) {
1252 singleRead = sr;
1253 break;
1254 }
1255 }
1256 return deleteSingleRead(singleRead, sequence);
1257 }
1258
1259 @Override
1260 public DeleteResult deleteDerivateHierarchy(CdmBase from, SpecimenDeleteConfigurator config) {
1261 DeleteResult deleteResult = new DeleteResult();
1262 String deleteMolecularNotAllowed = "Deleting molecular data is not allowed in config";
1263 if (from.isInstanceOf(Sequence.class)) {
1264 if (!config.isDeleteMolecularData()) {
1265 deleteResult.setAbort();
1266 deleteResult.addException(new ReferencedObjectUndeletableException(deleteMolecularNotAllowed));
1267 return deleteResult;
1268 }
1269 Sequence sequence = HibernateProxyHelper.deproxy(from, Sequence.class);
1270 DnaSample dnaSample = sequence.getDnaSample();
1271 dnaSample.removeSequence(sequence);
1272 deleteResult = sequenceService.delete(sequence);
1273 deleteResult.addUpdatedObject(dnaSample);
1274 }
1275 else if(from instanceof SingleRead){
1276 SingleRead singleRead = (SingleRead)from;
1277 //delete from amplification result
1278 if(singleRead.getAmplificationResult()!=null){
1279 singleRead.getAmplificationResult().removeSingleRead(singleRead);
1280 }
1281 deleteResult.setAbort();
1282 deleteResult.addException(new ReferencedObjectUndeletableException("Deleted ONLY from amplification. "
1283 + "Single read may still be attached to a consensus sequence."));
1284 }
1285 else if(from.isInstanceOf(SpecimenOrObservationBase.class)) {
1286 deleteResult = delete(HibernateProxyHelper.deproxy(from, SpecimenOrObservationBase.class), config);
1287 }
1288 return deleteResult;
1289 }
1290
1291 @Override
1292 @Transactional(readOnly = false)
1293 public DeleteResult deleteDerivateHierarchy(UUID fromUuid, SpecimenDeleteConfigurator config) {
1294 return deleteDerivateHierarchy(dao.load(fromUuid),config);
1295 }
1296
1297 // private DeleteResult deepDelete(SpecimenOrObservationBase<?> entity, SpecimenDeleteConfigurator config){
1298 // Set<DerivationEvent> derivationEvents = entity.getDerivationEvents();
1299 // for (DerivationEvent derivationEvent : derivationEvents) {
1300 // Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
1301 // for (DerivedUnit derivedUnit : derivatives) {
1302 // DeleteResult deleteResult = deepDelete(derivedUnit, config);
1303 // if(!deleteResult.isOk()){
1304 // return deleteResult;
1305 // }
1306 // }
1307 // }
1308 // return delete(entity, config);
1309 // }
1310
1311 @Override
1312 public Collection<IndividualsAssociation> listIndividualsAssociations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1313 return dao.listIndividualsAssociations(specimen, null, null, null, null);
1314 }
1315
1316 /**
1317 * {@inheritDoc}
1318 */
1319 @Override
1320 public Collection<TaxonBase<?>> listAssociatedTaxa(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start,
1321 List<OrderHint> orderHints, List<String> propertyPaths) {
1322 Collection<TaxonBase<?>> associatedTaxa = new HashSet<TaxonBase<?>>();
1323 for (IndividualsAssociation individualsAssociation : listIndividualsAssociations(specimen, limit, start, orderHints, propertyPaths)) {
1324 if(individualsAssociation.getInDescription().isInstanceOf(TaxonDescription.class)){
1325 TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(individualsAssociation.getInDescription(), TaxonDescription.class);
1326 associatedTaxa.add(taxonDescription.getTaxon());
1327 }
1328 }
1329 return associatedTaxa;
1330 }
1331
1332 @Override
1333 public Collection<SpecimenTypeDesignation> listTypeDesignations(SpecimenOrObservationBase<?> specimen,
1334 Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1335 return dao.listTypeDesignations(specimen, limit, start, orderHints, propertyPaths);
1336 }
1337
1338 @Override
1339 public Collection<DescriptionBase<?>> listDescriptionsWithDescriptionSpecimen(
1340 SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints,
1341 List<String> propertyPaths) {
1342 return dao.listDescriptionsWithDescriptionSpecimen(specimen, limit, start, orderHints, propertyPaths);
1343 }
1344
1345 @Override
1346 @Deprecated //this is not a service layer task so it may be removed in future versions
1347 public Collection<DescriptionElementBase> getCharacterDataForSpecimen(SpecimenOrObservationBase<?> specimen) {
1348 if (specimen != null) {
1349 return specimen.characterData();
1350 }else{
1351 return new ArrayList<DescriptionElementBase>();
1352 }
1353 }
1354
1355 @Override
1356 public Collection<DescriptionElementBase> getCharacterDataForSpecimen(UUID specimenUuid) {
1357 SpecimenOrObservationBase<?> specimen = load(specimenUuid);
1358 if (specimen != null) {
1359 return getCharacterDataForSpecimen(specimen);
1360 }
1361 else{
1362 throw new DataRetrievalFailureException("Specimen with the given uuid not found in the data base");
1363 }
1364 }
1365
1366
1367 @Override
1368 public Pager<SpecimenOrObservationBase> findByTitle(
1369 IIdentifiableEntityServiceConfigurator<SpecimenOrObservationBase> config) {
1370 if (config instanceof FindOccurrencesConfigurator) {
1371 FindOccurrencesConfigurator occurrenceConfig = (FindOccurrencesConfigurator) config;
1372 List<SpecimenOrObservationBase> occurrences = new ArrayList<SpecimenOrObservationBase>();
1373 Taxon taxon = null;
1374 if(occurrenceConfig.getAssociatedTaxonUuid()!=null){
1375 TaxonBase taxonBase = taxonService.load(occurrenceConfig.getAssociatedTaxonUuid());
1376 if(taxonBase.isInstanceOf(Taxon.class)){
1377 taxon = HibernateProxyHelper.deproxy(taxonBase, Taxon.class);
1378 }
1379 }
1380 occurrences.addAll(dao.findOccurrences(occurrenceConfig.getClazz(),
1381 occurrenceConfig.getTitleSearchString(), occurrenceConfig.getSignificantIdentifier(),
1382 occurrenceConfig.getSpecimenType(), taxon, occurrenceConfig.getMatchMode(), null, null,
1383 occurrenceConfig.getOrderHints(), occurrenceConfig.getPropertyPaths()));
1384 // indirectly associated specimens
1385 List<SpecimenOrObservationBase> indirectlyAssociatedOccurrences = new ArrayList<SpecimenOrObservationBase>(occurrences);
1386 if(occurrenceConfig.isRetrieveIndirectlyAssociatedSpecimens()){
1387 for (SpecimenOrObservationBase specimen : occurrences) {
1388 List<SpecimenOrObservationBase<?>> allHierarchyDerivates = getAllHierarchyDerivatives(specimen);
1389 for (SpecimenOrObservationBase<?> specimenOrObservationBase : allHierarchyDerivates) {
1390 if(!occurrences.contains(specimenOrObservationBase)){
1391 indirectlyAssociatedOccurrences.add(specimenOrObservationBase);
1392 }
1393 }
1394 }
1395 occurrences = indirectlyAssociatedOccurrences;
1396 }
1397
1398 return new DefaultPagerImpl<SpecimenOrObservationBase>(config.getPageNumber(), occurrences.size(), config.getPageSize(), occurrences);
1399 }
1400 return super.findByTitle(config);
1401 }
1402
1403 @Override
1404 public List<SpecimenOrObservationBase<?>> getAllHierarchyDerivatives(SpecimenOrObservationBase<?> specimen){
1405 List<SpecimenOrObservationBase<?>> allHierarchyDerivatives = new ArrayList<SpecimenOrObservationBase<?>>();
1406 Collection<FieldUnit> fieldUnits = getFieldUnits(specimen.getUuid());
1407 if(fieldUnits.isEmpty()){
1408 allHierarchyDerivatives.add(specimen);
1409 allHierarchyDerivatives.addAll(getAllChildDerivatives(specimen));
1410 }
1411 else{
1412 for (FieldUnit fieldUnit : fieldUnits) {
1413 allHierarchyDerivatives.add(fieldUnit);
1414 allHierarchyDerivatives.addAll(getAllChildDerivatives(fieldUnit));
1415 }
1416 }
1417 return allHierarchyDerivatives;
1418 }
1419
1420 @Override
1421 public List<DerivedUnit> getAllChildDerivatives(SpecimenOrObservationBase<?> specimen){
1422 List<DerivedUnit> childDerivate = new ArrayList<DerivedUnit>();
1423 Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();
1424 for (DerivationEvent derivationEvent : derivationEvents) {
1425 Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
1426 for (DerivedUnit derivedUnit : derivatives) {
1427 childDerivate.add(derivedUnit);
1428 childDerivate.addAll(getAllChildDerivatives(derivedUnit));
1429 }
1430 }
1431 return childDerivate;
1432 }
1433
1434 @Override
1435 public int countOccurrences(IIdentifiableEntityServiceConfigurator<SpecimenOrObservationBase> config){
1436 if (config instanceof FindOccurrencesConfigurator) {
1437 FindOccurrencesConfigurator occurrenceConfig = (FindOccurrencesConfigurator) config;
1438 Taxon taxon = null;
1439 if(occurrenceConfig.getAssociatedTaxonUuid()!=null){
1440 TaxonBase taxonBase = taxonService.load(occurrenceConfig.getAssociatedTaxonUuid());
1441 if(taxonBase.isInstanceOf(Taxon.class)){
1442 taxon = HibernateProxyHelper.deproxy(taxonBase, Taxon.class);
1443 }
1444 }
1445 // indirectly associated specimens
1446 if(occurrenceConfig.isRetrieveIndirectlyAssociatedSpecimens()){
1447 return findByTitle(config).getRecords().size();
1448 }
1449 return dao.countOccurrences(occurrenceConfig.getClazz(), occurrenceConfig.getTitleSearchString(),
1450 occurrenceConfig.getSignificantIdentifier(), occurrenceConfig.getSpecimenType(), taxon,
1451 occurrenceConfig.getMatchMode(), null, null, occurrenceConfig.getOrderHints(),
1452 occurrenceConfig.getPropertyPaths());
1453 }
1454 return super.countByTitle(config);
1455 }
1456
1457 }