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