2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.api
.service
;
12 import java
.io
.IOException
;
14 import java
.net
.URISyntaxException
;
15 import java
.util
.ArrayList
;
16 import java
.util
.Arrays
;
17 import java
.util
.Collection
;
18 import java
.util
.Collections
;
19 import java
.util
.HashMap
;
20 import java
.util
.HashSet
;
21 import java
.util
.Iterator
;
22 import java
.util
.List
;
24 import java
.util
.Map
.Entry
;
26 import java
.util
.UUID
;
28 import org
.apache
.log4j
.Logger
;
29 import org
.apache
.lucene
.queryparser
.classic
.ParseException
;
30 import org
.apache
.lucene
.search
.BooleanClause
.Occur
;
31 import org
.apache
.lucene
.search
.BooleanQuery
.Builder
;
32 import org
.apache
.lucene
.search
.SortField
;
33 import org
.apache
.lucene
.search
.grouping
.TopGroups
;
34 import org
.apache
.lucene
.util
.BytesRef
;
35 import org
.hibernate
.TransientObjectException
;
36 import org
.hibernate
.search
.spatial
.impl
.Rectangle
;
37 import org
.joda
.time
.Partial
;
38 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
39 import org
.springframework
.dao
.DataRetrievalFailureException
;
40 import org
.springframework
.stereotype
.Service
;
41 import org
.springframework
.transaction
.annotation
.Transactional
;
43 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacade
;
44 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacadeConfigurator
;
45 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacadeNotSupportedException
;
46 import eu
.etaxonomy
.cdm
.api
.service
.UpdateResult
.Status
;
47 import eu
.etaxonomy
.cdm
.api
.service
.config
.DeleteConfiguratorBase
;
48 import eu
.etaxonomy
.cdm
.api
.service
.config
.FindOccurrencesConfigurator
;
49 import eu
.etaxonomy
.cdm
.api
.service
.config
.IIdentifiableEntityServiceConfigurator
;
50 import eu
.etaxonomy
.cdm
.api
.service
.config
.SpecimenDeleteConfigurator
;
51 import eu
.etaxonomy
.cdm
.api
.service
.dto
.DerivateDTO
;
52 import eu
.etaxonomy
.cdm
.api
.service
.dto
.DerivateDataDTO
;
53 import eu
.etaxonomy
.cdm
.api
.service
.dto
.DerivateDataDTO
.ContigFile
;
54 import eu
.etaxonomy
.cdm
.api
.service
.dto
.DerivateDataDTO
.Link
;
55 import eu
.etaxonomy
.cdm
.api
.service
.dto
.DerivateDataDTO
.MolecularData
;
56 import eu
.etaxonomy
.cdm
.api
.service
.dto
.FieldUnitDTO
;
57 import eu
.etaxonomy
.cdm
.api
.service
.dto
.PreservedSpecimenDTO
;
58 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
59 import eu
.etaxonomy
.cdm
.api
.service
.molecular
.ISequenceService
;
60 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
61 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
62 import eu
.etaxonomy
.cdm
.api
.service
.search
.ILuceneIndexToolProvider
;
63 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
64 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneParseException
;
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
.CdmUtils
;
71 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
72 import eu
.etaxonomy
.cdm
.format
.CdmFormatterFactory
;
73 import eu
.etaxonomy
.cdm
.format
.ICdmFormatter
.FormatKey
;
74 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
75 import eu
.etaxonomy
.cdm
.model
.CdmBaseType
;
76 import eu
.etaxonomy
.cdm
.model
.agent
.AgentBase
;
77 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
78 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTerm
;
79 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTermBase
;
80 import eu
.etaxonomy
.cdm
.model
.common
.ICdmBase
;
81 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
82 import eu
.etaxonomy
.cdm
.model
.description
.CategoricalData
;
83 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
84 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
85 import eu
.etaxonomy
.cdm
.model
.description
.IndividualsAssociation
;
86 import eu
.etaxonomy
.cdm
.model
.description
.QuantitativeData
;
87 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
88 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
89 import eu
.etaxonomy
.cdm
.model
.location
.Country
;
90 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
91 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
92 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
93 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentationPart
;
94 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
95 import eu
.etaxonomy
.cdm
.model
.molecular
.AmplificationResult
;
96 import eu
.etaxonomy
.cdm
.model
.molecular
.DnaSample
;
97 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
98 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleRead
;
99 import eu
.etaxonomy
.cdm
.model
.name
.SpecimenTypeDesignation
;
100 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
101 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationStatusBase
;
102 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivationEvent
;
103 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
104 import eu
.etaxonomy
.cdm
.model
.occurrence
.DeterminationEvent
;
105 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldUnit
;
106 import eu
.etaxonomy
.cdm
.model
.occurrence
.GatheringEvent
;
107 import eu
.etaxonomy
.cdm
.model
.occurrence
.MediaSpecimen
;
108 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
109 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationType
;
110 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
111 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
112 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IDefinedTermDao
;
113 import eu
.etaxonomy
.cdm
.persistence
.dao
.initializer
.AbstractBeanInitializer
;
114 import eu
.etaxonomy
.cdm
.persistence
.dao
.molecular
.ISingleReadDao
;
115 import eu
.etaxonomy
.cdm
.persistence
.dao
.occurrence
.IOccurrenceDao
;
116 import eu
.etaxonomy
.cdm
.persistence
.dto
.UuidAndTitleCache
;
117 import eu
.etaxonomy
.cdm
.persistence
.query
.AssignmentStatus
;
118 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
119 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
120 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IdentifiableEntityDefaultCacheStrategy
;
123 * @author a.babadshanjan
124 * @created 01.09.2008
127 @Transactional(readOnly
= true)
128 public class OccurrenceServiceImpl
extends IdentifiableServiceBase
<SpecimenOrObservationBase
, IOccurrenceDao
> implements IOccurrenceService
{
130 static private final Logger logger
= Logger
.getLogger(OccurrenceServiceImpl
.class);
133 private IDefinedTermDao definedTermDao
;
136 private IDescriptionService descriptionService
;
139 private INameService nameService
;
142 private IEventBaseService eventService
;
145 private ITaxonService taxonService
;
148 private ISequenceService sequenceService
;
151 private ISingleReadDao singleReadDao
;
154 private AbstractBeanInitializer beanInitializer
;
157 private ILuceneIndexToolProvider luceneIndexToolProvider
;
159 private static final String SEPARATOR_STRING
= ", ";
161 public OccurrenceServiceImpl() {
162 logger
.debug("Load OccurrenceService Bean");
167 @Transactional(readOnly
= false)
168 public void updateTitleCache(Class
<?
extends SpecimenOrObservationBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<SpecimenOrObservationBase
> cacheStrategy
, IProgressMonitor monitor
) {
170 clazz
= SpecimenOrObservationBase
.class;
172 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
176 * FIXME Candidate for harmonization
177 * move to termService
180 public Country
getCountryByIso(String iso639
) {
181 return this.definedTermDao
.getCountryByIso(iso639
);
186 * FIXME Candidate for harmonization
187 * move to termService
190 public List
<Country
> getCountryByName(String name
) {
191 List
<?
extends DefinedTermBase
> terms
= this.definedTermDao
.findByTitle(Country
.class, name
, null, null, null, null, null, null);
192 List
<Country
> countries
= new ArrayList
<>();
193 for (int i
= 0; i
< terms
.size(); i
++) {
194 countries
.add((Country
) terms
.get(i
));
201 protected void setDao(IOccurrenceDao dao
) {
206 public Pager
<DerivationEvent
> getDerivationEvents(SpecimenOrObservationBase occurence
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
207 Integer numberOfResults
= dao
.countDerivationEvents(occurence
);
209 List
<DerivationEvent
> results
= new ArrayList
<>();
210 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
211 results
= dao
.getDerivationEvents(occurence
, pageSize
, pageNumber
, propertyPaths
);
214 return new DefaultPagerImpl
<DerivationEvent
>(pageNumber
, numberOfResults
, pageSize
, results
);
218 public int countDeterminations(SpecimenOrObservationBase occurence
, TaxonBase taxonbase
) {
219 return dao
.countDeterminations(occurence
, taxonbase
);
223 public Pager
<DeterminationEvent
> getDeterminations(SpecimenOrObservationBase occurrence
, TaxonBase taxonBase
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
224 Integer numberOfResults
= dao
.countDeterminations(occurrence
, taxonBase
);
226 List
<DeterminationEvent
> results
= new ArrayList
<>();
227 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
228 results
= dao
.getDeterminations(occurrence
, taxonBase
, pageSize
, pageNumber
, propertyPaths
);
231 return new DefaultPagerImpl
<DeterminationEvent
>(pageNumber
, numberOfResults
, pageSize
, results
);
235 public Pager
<Media
> getMedia(SpecimenOrObservationBase occurence
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
236 Integer numberOfResults
= dao
.countMedia(occurence
);
238 List
<Media
> results
= new ArrayList
<>();
239 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
240 results
= dao
.getMedia(occurence
, pageSize
, pageNumber
, propertyPaths
);
243 return new DefaultPagerImpl
<Media
>(pageNumber
, numberOfResults
, pageSize
, results
);
247 public Pager
<Media
> getMediainHierarchy(SpecimenOrObservationBase rootOccurence
, Integer pageSize
,
248 Integer pageNumber
, List
<String
> propertyPaths
) {
249 List
<Media
> media
= new ArrayList
<>();
251 if(rootOccurence
.isInstanceOf(MediaSpecimen
.class)){
252 MediaSpecimen mediaSpecimen
= HibernateProxyHelper
.deproxy(rootOccurence
, MediaSpecimen
.class);
253 media
.add(mediaSpecimen
.getMediaSpecimen());
255 // pherograms & gelPhotos
256 if (rootOccurence
.isInstanceOf(DnaSample
.class)) {
257 DnaSample dnaSample
= CdmBase
.deproxy(rootOccurence
, DnaSample
.class);
258 Set
<Sequence
> sequences
= dnaSample
.getSequences();
259 //we do show only those gelPhotos which lead to a consensus sequence
260 for (Sequence sequence
: sequences
) {
261 Set
<Media
> dnaRelatedMedia
= new HashSet
<>();
262 for (SingleRead singleRead
: sequence
.getSingleReads()){
263 AmplificationResult amplification
= singleRead
.getAmplificationResult();
264 dnaRelatedMedia
.add(amplification
.getGelPhoto());
265 dnaRelatedMedia
.add(singleRead
.getPherogram());
266 dnaRelatedMedia
.remove(null);
268 media
.addAll(dnaRelatedMedia
);
271 if(rootOccurence
.isInstanceOf(DerivedUnit
.class)){
272 DerivedUnit derivedUnit
= HibernateProxyHelper
.deproxy(rootOccurence
, DerivedUnit
.class);
273 for (DerivationEvent derivationEvent
: derivedUnit
.getDerivationEvents()) {
274 for (DerivedUnit childDerivative
: derivationEvent
.getDerivatives()) {
275 media
.addAll(getMediainHierarchy(childDerivative
, pageSize
, pageNumber
, propertyPaths
).getRecords());
279 return new DefaultPagerImpl
<Media
>(pageNumber
, media
.size(), pageSize
, media
);
283 public Pager
<SpecimenOrObservationBase
> list(Class
<?
extends SpecimenOrObservationBase
> type
, TaxonName determinedAs
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
284 Integer numberOfResults
= dao
.count(type
, determinedAs
);
285 List
<SpecimenOrObservationBase
> results
= new ArrayList
<>();
286 pageNumber
= pageNumber
== null ?
0 : pageNumber
;
287 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
288 Integer start
= pageSize
== null ?
0 : pageSize
* pageNumber
;
289 results
= dao
.list(type
, determinedAs
, pageSize
, start
, orderHints
, propertyPaths
);
291 return new DefaultPagerImpl
<SpecimenOrObservationBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
295 public Pager
<SpecimenOrObservationBase
> list(Class
<?
extends SpecimenOrObservationBase
> type
, TaxonBase determinedAs
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
296 Integer numberOfResults
= dao
.count(type
, determinedAs
);
297 List
<SpecimenOrObservationBase
> results
= new ArrayList
<>();
298 pageNumber
= pageNumber
== null ?
0 : pageNumber
;
299 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
300 Integer start
= pageSize
== null ?
0 : pageSize
* pageNumber
;
301 results
= dao
.list(type
, determinedAs
, pageSize
, start
, orderHints
, propertyPaths
);
303 return new DefaultPagerImpl
<SpecimenOrObservationBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
307 public List
<UuidAndTitleCache
<DerivedUnit
>> getDerivedUnitUuidAndTitleCache(Integer limit
, String pattern
) {
308 return dao
.getDerivedUnitUuidAndTitleCache(limit
, pattern
);
312 public List
<UuidAndTitleCache
<FieldUnit
>> getFieldUnitUuidAndTitleCache() {
313 return dao
.getFieldUnitUuidAndTitleCache();
317 public DerivedUnitFacade
getDerivedUnitFacade(DerivedUnit derivedUnit
, List
<String
> propertyPaths
) throws DerivedUnitFacadeNotSupportedException
{
318 derivedUnit
= (DerivedUnit
) dao
.load(derivedUnit
.getUuid(), null);
319 DerivedUnitFacadeConfigurator config
= DerivedUnitFacadeConfigurator
.NewInstance();
320 config
.setThrowExceptionForNonSpecimenPreservationMethodRequest(false);
321 DerivedUnitFacade derivedUnitFacade
= DerivedUnitFacade
.NewInstance(derivedUnit
, config
);
322 beanInitializer
.initialize(derivedUnitFacade
, propertyPaths
);
323 return derivedUnitFacade
;
327 public List
<DerivedUnitFacade
> listDerivedUnitFacades(
328 DescriptionBase description
, List
<String
> propertyPaths
) {
330 List
<DerivedUnitFacade
> derivedUnitFacadeList
= new ArrayList
<>();
331 IndividualsAssociation tempIndividualsAssociation
;
332 SpecimenOrObservationBase tempSpecimenOrObservationBase
;
333 List
<IndividualsAssociation
> elements
= descriptionService
.listDescriptionElements(description
, null, IndividualsAssociation
.class, null, 0, Arrays
.asList(new String
[]{"associatedSpecimenOrObservation"}));
334 for (IndividualsAssociation element
: elements
) {
335 tempIndividualsAssociation
= HibernateProxyHelper
.deproxy(element
, IndividualsAssociation
.class);
336 if (tempIndividualsAssociation
.getAssociatedSpecimenOrObservation() != null) {
337 tempSpecimenOrObservationBase
= HibernateProxyHelper
.deproxy(tempIndividualsAssociation
.getAssociatedSpecimenOrObservation(), SpecimenOrObservationBase
.class);
338 if (tempSpecimenOrObservationBase
.isInstanceOf(DerivedUnit
.class)) {
340 derivedUnitFacadeList
.add(DerivedUnitFacade
.NewInstance(HibernateProxyHelper
.deproxy(tempSpecimenOrObservationBase
, DerivedUnit
.class)));
341 } catch (DerivedUnitFacadeNotSupportedException e
) {
342 logger
.warn(tempIndividualsAssociation
.getAssociatedSpecimenOrObservation().getTitleCache() + " : " + e
.getMessage());
348 beanInitializer
.initializeAll(derivedUnitFacadeList
, propertyPaths
);
350 return derivedUnitFacadeList
;
355 public <T
extends SpecimenOrObservationBase
> List
<T
> listByAssociatedTaxon(Class
<T
> type
, Set
<TaxonRelationshipEdge
> includeRelationships
,
356 Taxon associatedTaxon
, Integer maxDepth
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
358 return pageByAssociatedTaxon(type
, includeRelationships
, associatedTaxon
, maxDepth
, pageSize
, pageNumber
, orderHints
, propertyPaths
).getRecords();
362 public Collection
<SpecimenOrObservationBase
> listFieldUnitsByAssociatedTaxon(Taxon associatedTaxon
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
363 return pageFieldUnitsByAssociatedTaxon(null, associatedTaxon
, null, null, null, null, propertyPaths
).getRecords();
367 public Pager
<SpecimenOrObservationBase
> pageFieldUnitsByAssociatedTaxon(Set
<TaxonRelationshipEdge
> includeRelationships
,
368 Taxon associatedTaxon
, Integer maxDepth
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
,
369 List
<String
> propertyPaths
) {
371 if (!getSession().contains(associatedTaxon
)) {
372 associatedTaxon
= (Taxon
) taxonService
.load(associatedTaxon
.getUuid());
375 // gather the IDs of all relevant field units
376 Set
<UUID
> fieldUnitUuids
= new HashSet
<>();
377 List
<SpecimenOrObservationBase
> records
= listByAssociatedTaxon(null, includeRelationships
, associatedTaxon
, maxDepth
, null, null, orderHints
, propertyPaths
);
378 for (SpecimenOrObservationBase
<?
> specimen
: records
) {
379 for (FieldUnit fieldUnit
: getFieldUnits(specimen
.getUuid())) {
380 fieldUnitUuids
.add(fieldUnit
.getUuid());
383 //dao.list() does the paging of the field units. Passing the field units directly to the Pager would not work
384 List
<SpecimenOrObservationBase
> fieldUnits
= dao
.list(fieldUnitUuids
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
385 return new DefaultPagerImpl
<SpecimenOrObservationBase
>(pageNumber
, fieldUnitUuids
.size(), pageSize
, fieldUnits
);
389 public FieldUnitDTO
assembleFieldUnitDTO(FieldUnit fieldUnit
, UUID associatedTaxonUuid
) {
391 if (!getSession().contains(fieldUnit
)) {
392 fieldUnit
= (FieldUnit
) load(fieldUnit
.getUuid());
394 TaxonBase associatedTaxon
= taxonService
.load(associatedTaxonUuid
);
396 FieldUnitDTO fieldUnitDTO
= new FieldUnitDTO();
398 if (fieldUnit
.getGatheringEvent() != null) {
399 GatheringEvent gatheringEvent
= fieldUnit
.getGatheringEvent();
401 NamedArea country
= gatheringEvent
.getCountry();
402 fieldUnitDTO
.setCountry(country
!= null ? country
.getLabel() : null);
404 AgentBase collector
= gatheringEvent
.getCollector();
405 String fieldNumber
= fieldUnit
.getFieldNumber();
406 String collectionString
= "";
407 if (collector
!= null || fieldNumber
!= null) {
408 collectionString
+= collector
!= null ? collector
: "";
409 if (!collectionString
.isEmpty()) {
410 collectionString
+= " ";
412 collectionString
+= (fieldNumber
!= null ? fieldNumber
: "");
413 collectionString
.trim();
415 fieldUnitDTO
.setCollection(collectionString
);
417 Partial gatheringDate
= gatheringEvent
.getGatheringDate();
418 String dateString
= null;
419 if (gatheringDate
!= null) {
420 dateString
= gatheringDate
.toString();
422 else if(gatheringEvent
.getTimeperiod()!=null && gatheringEvent
.getTimeperiod().getFreeText()!=null){
423 dateString
= gatheringEvent
.getTimeperiod().getFreeText();
425 fieldUnitDTO
.setDate(dateString
);
429 fieldUnitDTO
.setTaxonName(associatedTaxon
.getName().getTitleCache());
432 Map
<eu
.etaxonomy
.cdm
.model
.occurrence
.Collection
, Integer
> collectionToCountMap
= new HashMap
<>();
433 // List of accession numbers for citation
434 List
<String
> preservedSpecimenAccessionNumbers
= new ArrayList
<>();
436 // assemble preserved specimen DTOs
437 Set
<DerivationEvent
> derivationEvents
= fieldUnit
.getDerivationEvents();
438 for (DerivationEvent derivationEvent
: derivationEvents
) {
439 Set
<DerivedUnit
> derivatives
= derivationEvent
.getDerivatives();
440 for (DerivedUnit derivedUnit
: derivatives
) {
441 if(!derivedUnit
.isPublish()){
444 // collect accession numbers for citation
445 String mostSignificantIdentifier
= getMostSignificantIdentifier(derivedUnit
);
446 if (mostSignificantIdentifier
!= null) {
447 preservedSpecimenAccessionNumbers
.add(mostSignificantIdentifier
);
449 // collect collections for herbaria column
450 if (derivedUnit
.getCollection() != null) {
451 Integer herbariumCount
= collectionToCountMap
.get(derivedUnit
.getCollection());
452 if (herbariumCount
== null) {
455 collectionToCountMap
.put(derivedUnit
.getCollection(), herbariumCount
+ 1);
457 if (derivedUnit
.getRecordBasis().equals(SpecimenOrObservationType
.PreservedSpecimen
)) {
458 PreservedSpecimenDTO preservedSpecimenDTO
= assemblePreservedSpecimenDTO(derivedUnit
, fieldUnitDTO
);
459 fieldUnitDTO
.addPreservedSpecimenDTO(preservedSpecimenDTO
);
460 fieldUnitDTO
.setHasCharacterData(fieldUnitDTO
.isHasCharacterData() || preservedSpecimenDTO
.isHasCharacterData());
461 fieldUnitDTO
.setHasDetailImage(fieldUnitDTO
.isHasDetailImage() || preservedSpecimenDTO
.isHasDetailImage());
462 fieldUnitDTO
.setHasDna(fieldUnitDTO
.isHasDna() || preservedSpecimenDTO
.isHasDna());
463 fieldUnitDTO
.setHasSpecimenScan(fieldUnitDTO
.isHasSpecimenScan() || preservedSpecimenDTO
.isHasSpecimenScan());
467 // assemble derivate data DTO
468 assembleDerivateDataDTO(fieldUnitDTO
, fieldUnit
);
471 String citation
= fieldUnit
.getTitleCache();
472 if((CdmUtils
.isBlank(citation
) || citation
.equals(IdentifiableEntityDefaultCacheStrategy
.TITLE_CACHE_GENERATION_NOT_IMPLEMENTED
))
473 && !fieldUnit
.isProtectedTitleCache()){
474 fieldUnit
.setTitleCache(null);
475 citation
= fieldUnit
.getTitleCache();
477 if (!preservedSpecimenAccessionNumbers
.isEmpty()) {
479 for (String accessionNumber
: preservedSpecimenAccessionNumbers
) {
480 if (!accessionNumber
.isEmpty()) {
481 citation
+= accessionNumber
+ SEPARATOR_STRING
;
484 citation
= removeTail(citation
, SEPARATOR_STRING
);
487 fieldUnitDTO
.setCitation(citation
);
489 // assemble herbaria string
490 String herbariaString
= "";
491 for (Entry
<eu
.etaxonomy
.cdm
.model
.occurrence
.Collection
, Integer
> e
: collectionToCountMap
.entrySet()) {
492 eu
.etaxonomy
.cdm
.model
.occurrence
.Collection collection
= e
.getKey();
493 if (collection
.getCode() != null) {
494 herbariaString
+= collection
.getCode();
496 if (e
.getValue() > 1) {
497 herbariaString
+= "(" + e
.getValue() + ")";
499 herbariaString
+= SEPARATOR_STRING
;
501 herbariaString
= removeTail(herbariaString
, SEPARATOR_STRING
);
502 fieldUnitDTO
.setHerbarium(herbariaString
);
508 public PreservedSpecimenDTO
assemblePreservedSpecimenDTO(DerivedUnit derivedUnit
) {
509 return assemblePreservedSpecimenDTO(derivedUnit
, null);
513 public String
getMostSignificantIdentifier(DerivedUnit derivedUnit
) {
514 if (derivedUnit
.getAccessionNumber() != null && !derivedUnit
.getAccessionNumber().isEmpty()) {
515 return derivedUnit
.getAccessionNumber();
517 else if(derivedUnit
.getBarcode()!=null && !derivedUnit
.getBarcode().isEmpty()){
518 return derivedUnit
.getBarcode();
520 else if(derivedUnit
.getCatalogNumber()!=null && !derivedUnit
.getCatalogNumber().isEmpty()){
521 return derivedUnit
.getCatalogNumber();
526 public PreservedSpecimenDTO
assemblePreservedSpecimenDTO(DerivedUnit derivedUnit
, FieldUnitDTO fieldUnitDTO
) {
527 if (!getSession().contains(derivedUnit
)) {
528 derivedUnit
= (DerivedUnit
) load(derivedUnit
.getUuid());
530 PreservedSpecimenDTO preservedSpecimenDTO
= new PreservedSpecimenDTO();
532 //specimen identifier
533 FormatKey collectionKey
= FormatKey
.COLLECTION_CODE
;
534 String specimenIdentifier
= CdmFormatterFactory
.format(derivedUnit
, collectionKey
);
535 if (CdmUtils
.isBlank(specimenIdentifier
)) {
536 collectionKey
= FormatKey
.COLLECTION_NAME
;
538 specimenIdentifier
= CdmFormatterFactory
.format(derivedUnit
, new FormatKey
[] {
539 collectionKey
, FormatKey
.SPACE
,
540 FormatKey
.MOST_SIGNIFICANT_IDENTIFIER
, FormatKey
.SPACE
});
541 if(CdmUtils
.isBlank(specimenIdentifier
)){
542 specimenIdentifier
= derivedUnit
.getUuid().toString();
544 preservedSpecimenDTO
.setAccessionNumber(specimenIdentifier
);
545 preservedSpecimenDTO
.setUuid(derivedUnit
.getUuid().toString());
547 //preferred stable URI
548 preservedSpecimenDTO
.setPreferredStableUri(derivedUnit
.getPreferredStableUri());
551 Collection
<FieldUnit
> fieldUnits
= getFieldUnits(derivedUnit
);
552 if (fieldUnits
.size() == 1) {
553 preservedSpecimenDTO
.setCitation(fieldUnits
.iterator().next().getTitleCache());
556 preservedSpecimenDTO
.setCitation("No Citation available. This specimen either has no or multiple field units.");
559 // character state data
560 Collection
<DescriptionElementBase
> characterDataForSpecimen
= getCharacterDataForSpecimen(derivedUnit
);
561 if (!characterDataForSpecimen
.isEmpty()) {
562 if (fieldUnitDTO
!= null) {
563 fieldUnitDTO
.setHasCharacterData(true);
566 for (DescriptionElementBase descriptionElementBase
: characterDataForSpecimen
) {
567 String character
= descriptionElementBase
.getFeature().getLabel();
568 ArrayList
<Language
> languages
= new ArrayList
<>(Collections
.singleton(Language
.DEFAULT()));
569 if (descriptionElementBase
instanceof QuantitativeData
) {
570 QuantitativeData quantitativeData
= (QuantitativeData
) descriptionElementBase
;
571 DefaultQuantitativeDescriptionBuilder builder
= new DefaultQuantitativeDescriptionBuilder();
572 String state
= builder
.build(quantitativeData
, languages
).getText(Language
.DEFAULT());
573 preservedSpecimenDTO
.addCharacterData(character
, state
);
575 else if(descriptionElementBase
instanceof CategoricalData
){
576 CategoricalData categoricalData
= (CategoricalData
) descriptionElementBase
;
577 DefaultCategoricalDescriptionBuilder builder
= new DefaultCategoricalDescriptionBuilder();
578 String state
= builder
.build(categoricalData
, languages
).getText(Language
.DEFAULT());
579 preservedSpecimenDTO
.addCharacterData(character
, state
);
582 // check type designations
583 Collection
<SpecimenTypeDesignation
> specimenTypeDesignations
= listTypeDesignations(derivedUnit
, null, null, null, null);
584 for (SpecimenTypeDesignation specimenTypeDesignation
: specimenTypeDesignations
) {
585 if (fieldUnitDTO
!= null) {
586 fieldUnitDTO
.setHasType(true);
588 TypeDesignationStatusBase
<?
> typeStatus
= specimenTypeDesignation
.getTypeStatus();
589 if (typeStatus
!= null) {
590 List
<String
> typedTaxaNames
= new ArrayList
<>();
591 String label
= typeStatus
.getLabel();
592 Set
<TaxonName
> typifiedNames
= specimenTypeDesignation
.getTypifiedNames();
593 for (TaxonName taxonName
: typifiedNames
) {
594 typedTaxaNames
.add(taxonName
.getFullTitleCache());
596 preservedSpecimenDTO
.addTypes(label
, typedTaxaNames
);
600 // individuals associations
601 Collection
<IndividualsAssociation
> individualsAssociations
= listIndividualsAssociations(derivedUnit
, null, null, null, null);
602 for (IndividualsAssociation individualsAssociation
: individualsAssociations
) {
603 if (individualsAssociation
.getInDescription() != null) {
604 if (individualsAssociation
.getInDescription().isInstanceOf(TaxonDescription
.class)) {
605 TaxonDescription taxonDescription
= HibernateProxyHelper
.deproxy(individualsAssociation
.getInDescription(), TaxonDescription
.class);
606 Taxon taxon
= taxonDescription
.getTaxon();
608 preservedSpecimenDTO
.addAssociatedTaxon(taxon
);
613 // assemble sub derivates
614 preservedSpecimenDTO
.setDerivateDataDTO(assembleDerivateDataDTO(preservedSpecimenDTO
, derivedUnit
));
615 return preservedSpecimenDTO
;
618 private DerivateDataDTO
assembleDerivateDataDTO(DerivateDTO derivateDTO
, SpecimenOrObservationBase
<?
> specimenOrObservation
) {
619 DerivateDataDTO derivateDataDTO
= new DerivateDataDTO();
620 Collection
<DerivedUnit
> childDerivates
= getDerivedUnitsFor(specimenOrObservation
);
621 for (DerivedUnit childDerivate
: childDerivates
) {
622 // assemble molecular data
623 //pattern: DNAMarker [contig1, primer1_1, primer1_2, ...][contig2, primer2_1, ...]...
624 if (childDerivate
.isInstanceOf(DnaSample
.class)) {
625 if (childDerivate
.getRecordBasis() == SpecimenOrObservationType
.TissueSample
) {
626 // TODO implement TissueSample assembly for web service
628 if (childDerivate
.getRecordBasis() == SpecimenOrObservationType
.DnaSample
) {
630 DnaSample dna
= HibernateProxyHelper
.deproxy(childDerivate
, DnaSample
.class);
631 if (!dna
.getSequences().isEmpty()) {
632 derivateDTO
.setHasDna(true);
634 for (Sequence sequence
: dna
.getSequences()) {
637 boldUri
= sequence
.getBoldUri();
638 } catch (URISyntaxException e1
) {
639 logger
.error("Could not create BOLD URI", e1
);
641 final DefinedTerm dnaMarker
= sequence
.getDnaMarker();
642 Link providerLink
= null;
643 if(boldUri
!=null && dnaMarker
!=null){
644 providerLink
= new DerivateDataDTO
.Link(boldUri
, dnaMarker
.getLabel());
646 MolecularData molecularData
= derivateDataDTO
.addProviderLink(providerLink
);
649 ContigFile contigFile
= null;
650 if (sequence
.getContigFile() != null) {
651 MediaRepresentationPart contigMediaRepresentationPart
= MediaUtils
.getFirstMediaRepresentationPart(sequence
.getContigFile());
652 if (contigMediaRepresentationPart
!= null) {
653 contigFile
= molecularData
.addContigFile(new Link(contigMediaRepresentationPart
.getUri(), "contig"));
657 contigFile
= molecularData
.addContigFile(null);
660 if (sequence
.getSingleReads() != null) {
662 for (SingleRead singleRead
: sequence
.getSingleReads()) {
663 MediaRepresentationPart pherogramMediaRepresentationPart
= MediaUtils
.getFirstMediaRepresentationPart(singleRead
.getPherogram());
664 if (pherogramMediaRepresentationPart
!= null) {
665 contigFile
.addPrimerLink(pherogramMediaRepresentationPart
.getUri(), "read"+readCount
++);
672 // assemble media data
673 else if (childDerivate
.isInstanceOf(MediaSpecimen
.class)) {
674 MediaSpecimen media
= HibernateProxyHelper
.deproxy(childDerivate
, MediaSpecimen
.class);
676 URI mediaUri
= getMediaUri(media
);
677 if (media
.getKindOfUnit() != null) {
679 if (media
.getKindOfUnit().getUuid().equals(DefinedTerm
.uuidSpecimenScan
)) {
680 derivateDataDTO
.addSpecimenScanUuid(media
.getMediaSpecimen().getUuid());
681 derivateDTO
.setHasSpecimenScan(true);
682 String imageLinkText
= "scan";
683 if (derivateDTO
instanceof PreservedSpecimenDTO
&& ((PreservedSpecimenDTO
) derivateDTO
).getAccessionNumber() != null) {
684 imageLinkText
= ((PreservedSpecimenDTO
) derivateDTO
).getAccessionNumber();
686 derivateDataDTO
.addSpecimenScan(mediaUri
, imageLinkText
);
689 else if (media
.getKindOfUnit().getUuid().equals(DefinedTerm
.uuidDetailImage
)) {
690 derivateDataDTO
.addDetailImageUuid(media
.getMediaSpecimen().getUuid());
691 derivateDTO
.setHasDetailImage(true);
692 String motif
= "detail image";
693 if (media
.getMediaSpecimen()!=null){
694 if(CdmUtils
.isNotBlank(media
.getMediaSpecimen().getTitleCache())) {
695 motif
= media
.getMediaSpecimen().getTitleCache();
698 derivateDataDTO
.addDetailImage(mediaUri
, motif
);
703 return derivateDataDTO
;
706 private String
removeTail(String string
, final String tail
) {
707 if (string
.endsWith(tail
)) {
708 string
= string
.substring(0, string
.length() - tail
.length());
713 private URI
getMediaUri(MediaSpecimen mediaSpecimen
) {
715 Collection
<MediaRepresentation
> mediaRepresentations
= mediaSpecimen
.getMediaSpecimen().getRepresentations();
716 if (mediaRepresentations
!= null && !mediaRepresentations
.isEmpty()) {
717 Collection
<MediaRepresentationPart
> mediaRepresentationParts
= mediaRepresentations
.iterator().next().getParts();
718 if (mediaRepresentationParts
!= null && !mediaRepresentationParts
.isEmpty()) {
719 MediaRepresentationPart part
= mediaRepresentationParts
.iterator().next();
720 if (part
.getUri() != null) {
721 mediaUri
= part
.getUri();
728 private Collection
<DerivedUnit
> getDerivedUnitsFor(SpecimenOrObservationBase
<?
> specimen
) {
729 Collection
<DerivedUnit
> derivedUnits
= new ArrayList
<>();
730 for (DerivationEvent derivationEvent
: specimen
.getDerivationEvents()) {
731 for (DerivedUnit derivative
: derivationEvent
.getDerivatives()) {
732 derivedUnits
.add(derivative
);
733 derivedUnits
.addAll(getDerivedUnitsFor(derivative
));
740 @SuppressWarnings("unchecked")
742 public <T
extends SpecimenOrObservationBase
> Pager
<T
> pageByAssociatedTaxon(Class
<T
> type
, Set
<TaxonRelationshipEdge
> includeRelationships
,
743 Taxon associatedTaxon
, Integer maxDepth
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
745 Set
<Taxon
> taxa
= new HashSet
<>();
746 Set
<Integer
> occurrenceIds
= new HashSet
<>();
747 List
<T
> occurrences
= new ArrayList
<>();
749 // Integer limit = PagerUtils.limitFor(pageSize);
750 // Integer start = PagerUtils.startFor(pageSize, pageNumber);
752 if (!getSession().contains(associatedTaxon
)) {
753 associatedTaxon
= (Taxon
) taxonService
.load(associatedTaxon
.getUuid());
756 if (includeRelationships
!= null) {
757 taxa
= taxonService
.listRelatedTaxa(associatedTaxon
, includeRelationships
, maxDepth
, null, null, propertyPaths
);
760 taxa
.add(associatedTaxon
);
762 for (Taxon taxon
: taxa
) {
763 List
<T
> perTaxonOccurrences
= dao
.listByAssociatedTaxon(type
, taxon
, null, null, orderHints
, propertyPaths
);
764 for (SpecimenOrObservationBase o
: perTaxonOccurrences
) {
765 occurrenceIds
.add(o
.getId());
768 occurrences
= (List
<T
>) dao
.loadList(occurrenceIds
, propertyPaths
);
770 return new DefaultPagerImpl
<T
>(pageNumber
, occurrenceIds
.size(), pageSize
, occurrences
);
775 public <T
extends SpecimenOrObservationBase
> Pager
<T
> pageByAssociatedTaxon(Class
<T
> type
, Set
<TaxonRelationshipEdge
> includeRelationships
,
776 String taxonUUID
, Integer maxDepth
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
778 UUID uuid
= UUID
.fromString(taxonUUID
);
779 Taxon tax
= (Taxon
) taxonService
.load(uuid
);
780 // TODO REMOVE NULL STATEMENT
782 return pageByAssociatedTaxon(type
, includeRelationships
, tax
, maxDepth
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
787 public Pager
<SearchResult
<SpecimenOrObservationBase
>> findByFullText(
788 Class
<?
extends SpecimenOrObservationBase
> clazz
, String queryString
, Rectangle boundingBox
, List
<Language
> languages
,
789 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
,
790 List
<String
> propertyPaths
) throws IOException
, LuceneParseException
{
792 LuceneSearch luceneSearch
= prepareByFullTextSearch(clazz
, queryString
, boundingBox
, languages
, highlightFragments
);
794 // --- execute search
795 TopGroups
<BytesRef
> topDocsResultSet
;
797 topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
798 } catch (ParseException e
) {
799 LuceneParseException parseException
= new LuceneParseException(e
.getMessage());
800 parseException
.setStackTrace(e
.getStackTrace());
801 throw parseException
;
804 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<>();
805 idFieldMap
.put(CdmBaseType
.SPECIMEN_OR_OBSERVATIONBASE
, "id");
807 // --- initialize taxa, highlight matches ....
808 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
809 @SuppressWarnings("rawtypes")
810 List
<SearchResult
<SpecimenOrObservationBase
>> searchResults
= searchResultBuilder
.createResultSet(
811 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
813 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.totalGroupCount
: 0;
815 return new DefaultPagerImpl
<SearchResult
<SpecimenOrObservationBase
>>(pageNumber
, totalHits
, pageSize
,
820 private LuceneSearch
prepareByFullTextSearch(Class
<?
extends SpecimenOrObservationBase
> clazz
, String queryString
, Rectangle bbox
,
821 List
<Language
> languages
, boolean highlightFragments
) {
823 Builder finalQueryBuilder
= new Builder();
824 Builder textQueryBuilder
= new Builder();
826 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, FieldUnit
.class);
827 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(FieldUnit
.class);
830 luceneSearch
.setCdmTypRestriction(clazz
);
831 if (queryString
!= null) {
832 textQueryBuilder
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
833 finalQueryBuilder
.add(textQueryBuilder
.build(), Occur
.MUST
);
838 finalQueryBuilder
.add(QueryFactory
.buildSpatialQueryByRange(bbox
, "gatheringEvent.exactLocation.point"), Occur
.MUST
);
841 luceneSearch
.setQuery(finalQueryBuilder
.build());
844 SortField
[] sortFields
= new SortField
[] { SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.Type
.STRING
, false) };
845 luceneSearch
.setSortFields(sortFields
);
847 if (highlightFragments
) {
848 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
855 public Collection
<FieldUnit
> getFieldUnits(UUID derivedUnitUuid
) {
856 //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})
857 //from which this DerivedUnit was derived until all FieldUnits are found.
859 // FIXME: use HQL queries to increase performance
860 SpecimenOrObservationBase
<?
> specimen
= load(derivedUnitUuid
);
861 // specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
862 Collection
<FieldUnit
> fieldUnits
= new ArrayList
<>();
864 if (specimen
.isInstanceOf(FieldUnit
.class)) {
865 fieldUnits
.add(HibernateProxyHelper
.deproxy(specimen
, FieldUnit
.class));
867 else if(specimen
.isInstanceOf(DerivedUnit
.class)){
868 fieldUnits
.addAll(getFieldUnits(HibernateProxyHelper
.deproxy(specimen
, DerivedUnit
.class)));
873 private Collection
<FieldUnit
> getFieldUnits(DerivedUnit derivedUnit
) {
874 Collection
<FieldUnit
> fieldUnits
= new HashSet
<>();
875 Set
<SpecimenOrObservationBase
> originals
= derivedUnit
.getOriginals();
876 if (originals
!= null && !originals
.isEmpty()) {
877 for (SpecimenOrObservationBase
<?
> original
: originals
) {
878 if (original
.isInstanceOf(FieldUnit
.class)) {
879 fieldUnits
.add(HibernateProxyHelper
.deproxy(original
, FieldUnit
.class));
881 else if(original
.isInstanceOf(DerivedUnit
.class)){
882 fieldUnits
.addAll(getFieldUnits(HibernateProxyHelper
.deproxy(original
, DerivedUnit
.class)));
890 @Transactional(readOnly
= false)
891 public UpdateResult
moveSequence(DnaSample from
, DnaSample to
, Sequence sequence
) {
892 return moveSequence(from
.getUuid(), to
.getUuid(), sequence
.getUuid());
896 @Transactional(readOnly
= false)
897 public UpdateResult
moveSequence(UUID fromUuid
, UUID toUuid
, UUID sequenceUuid
) {
898 // reload specimens to avoid session conflicts
899 DnaSample from
= (DnaSample
) load(fromUuid
);
900 DnaSample to
= (DnaSample
) load(toUuid
);
901 Sequence sequence
= sequenceService
.load(sequenceUuid
);
903 if (from
== null || to
== null || sequence
== null) {
904 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" +
905 "Operation was move "+sequence
+ " from "+from
+" to "+to
);
907 UpdateResult result
= new UpdateResult();
908 from
.removeSequence(sequence
);
910 to
.addSequence(sequence
);
912 result
.setStatus(Status
.OK
);
913 result
.addUpdatedObject(from
);
914 result
.addUpdatedObject(to
);
919 @Transactional(readOnly
= false)
920 public boolean moveDerivate(SpecimenOrObservationBase
<?
> from
, SpecimenOrObservationBase
<?
> to
, DerivedUnit derivate
) {
921 return moveDerivate(from
!=null?from
.getUuid():null, to
.getUuid(), derivate
.getUuid()).isOk();
925 @Transactional(readOnly
= false)
926 public UpdateResult
moveDerivate(UUID specimenFromUuid
, UUID specimenToUuid
, UUID derivateUuid
) {
927 // reload specimens to avoid session conflicts
928 SpecimenOrObservationBase
<?
> from
= null;
929 if(specimenFromUuid
!=null){
930 from
= load(specimenFromUuid
);
932 SpecimenOrObservationBase
<?
> to
= load(specimenToUuid
);
933 DerivedUnit derivate
= (DerivedUnit
) load(derivateUuid
);
935 if ((specimenFromUuid
!=null && from
== null) || to
== null || derivate
== null) {
936 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" +
937 "Operation was move "+derivate
+ " from "+from
+" to "+to
);
939 UpdateResult result
= new UpdateResult();
940 SpecimenOrObservationType derivateType
= derivate
.getRecordBasis();
941 SpecimenOrObservationType toType
= to
.getRecordBasis();
942 // check if type is a sub derivate type
943 if(toType
==SpecimenOrObservationType
.FieldUnit
//moving to FieldUnit always works
944 || derivateType
==SpecimenOrObservationType
.Media
//moving media always works
945 || (derivateType
.isKindOf(toType
) && toType
!=derivateType
)){ //moving only to parent derivate type
947 // remove derivation event from parent specimen of dragged object
948 DerivationEvent eventToRemove
= null;
949 for (DerivationEvent event
: from
.getDerivationEvents()) {
950 if (event
.getDerivatives().contains(derivate
)) {
951 eventToRemove
= event
;
955 from
.removeDerivationEvent(eventToRemove
);
956 if(eventToRemove
!=null){
957 // add new derivation event to target and copy the event parameters of the old one
958 DerivationEvent derivedFromNewOriginalEvent
= DerivationEvent
.NewSimpleInstance(to
, derivate
, null);
959 derivedFromNewOriginalEvent
.setActor(eventToRemove
.getActor());
960 derivedFromNewOriginalEvent
.setDescription(eventToRemove
.getDescription());
961 derivedFromNewOriginalEvent
.setInstitution(eventToRemove
.getInstitution());
962 derivedFromNewOriginalEvent
.setTimeperiod(eventToRemove
.getTimeperiod());
963 derivedFromNewOriginalEvent
.setType(eventToRemove
.getType());
964 to
.addDerivationEvent(derivedFromNewOriginalEvent
);
965 derivate
.setDerivedFrom(derivedFromNewOriginalEvent
);
969 //derivative had no parent before so we use empty derivation event
970 DerivationEvent derivedFromNewOriginalEvent
= DerivationEvent
.NewSimpleInstance(to
, derivate
, null);
971 to
.addDerivationEvent(derivedFromNewOriginalEvent
);
972 derivate
.setDerivedFrom(derivedFromNewOriginalEvent
);
979 result
.setStatus(Status
.OK
);
980 result
.addUpdatedObject(from
);
981 result
.addUpdatedObject(to
);
983 result
.setStatus(Status
.ERROR
);
989 public Collection
<ICdmBase
> getNonCascadedAssociatedElements(SpecimenOrObservationBase
<?
> specimen
) {
990 // potential fields that are not persisted cascadingly
1003 --CollectingAreas TERM
1011 -storedUnder CDM TaxonName
1014 Collection
<ICdmBase
> nonCascadedCdmEntities
= new HashSet
<>();
1016 //Choose the correct entry point to traverse the graph (FieldUnit or DerivedUnit)
1019 if (specimen
.isInstanceOf(FieldUnit
.class)) {
1020 nonCascadedCdmEntities
.addAll(getFieldUnitNonCascadedAssociatedElements(HibernateProxyHelper
.deproxy(specimen
, FieldUnit
.class)));
1023 else if (specimen
.isInstanceOf(DerivedUnit
.class)) {
1024 DerivedUnit derivedUnit
= HibernateProxyHelper
.deproxy(specimen
, DerivedUnit
.class);
1025 if (derivedUnit
.getDerivedFrom() != null) {
1026 Collection
<FieldUnit
> fieldUnits
= getFieldUnits(derivedUnit
);
1027 for (FieldUnit fieldUnit
: fieldUnits
) {
1028 nonCascadedCdmEntities
.addAll(getFieldUnitNonCascadedAssociatedElements(fieldUnit
));
1032 return nonCascadedCdmEntities
;
1035 private Collection
<ICdmBase
> getFieldUnitNonCascadedAssociatedElements(FieldUnit fieldUnit
) {
1036 // get non cascaded element on SpecimenOrObservationBase level
1037 Collection
<ICdmBase
> nonCascadedCdmEntities
= getSpecimenOrObservationNonCascadedAssociatedElements(fieldUnit
);
1039 // get FieldUnit specific elements
1040 GatheringEvent gatheringEvent
= fieldUnit
.getGatheringEvent();
1041 if (gatheringEvent
!= null) {
1043 if (gatheringEvent
.getCountry() != null) {
1044 nonCascadedCdmEntities
.add(gatheringEvent
.getCountry());
1047 for (NamedArea namedArea
: gatheringEvent
.getCollectingAreas()) {
1048 nonCascadedCdmEntities
.add(namedArea
);
1051 for (DerivationEvent derivationEvent
: fieldUnit
.getDerivationEvents()) {
1052 for (DerivedUnit derivedUnit
: derivationEvent
.getDerivatives()) {
1053 nonCascadedCdmEntities
.addAll(getDerivedUnitNonCascadedAssociatedElements(derivedUnit
));
1056 return nonCascadedCdmEntities
;
1059 private Collection
<ICdmBase
> getDerivedUnitNonCascadedAssociatedElements(DerivedUnit derivedUnit
) {
1060 // get non cascaded element on SpecimenOrObservationBase level
1061 Collection
<ICdmBase
> nonCascadedCdmEntities
= getSpecimenOrObservationNonCascadedAssociatedElements(derivedUnit
);
1063 // get DerivedUnit specific elements
1064 if (derivedUnit
.getCollection() != null && derivedUnit
.getCollection().getInstitute() != null) {
1065 for (DefinedTerm type
: derivedUnit
.getCollection().getInstitute().getTypes()) {
1066 nonCascadedCdmEntities
.add(type
);
1069 if (derivedUnit
.getPreservation() != null && derivedUnit
.getPreservation().getMedium() != null) {
1070 nonCascadedCdmEntities
.add(derivedUnit
.getPreservation().getMedium());
1072 if (derivedUnit
.getStoredUnder() != null) {
1073 nonCascadedCdmEntities
.add(derivedUnit
.getStoredUnder());
1075 return nonCascadedCdmEntities
;
1078 private Collection
<ICdmBase
> getSpecimenOrObservationNonCascadedAssociatedElements(
1079 SpecimenOrObservationBase
<?
> specimen
) {
1080 Collection
<ICdmBase
> nonCascadedCdmEntities
= new HashSet
<>();
1081 // scan SpecimenOrObservationBase
1082 for (DeterminationEvent determinationEvent
: specimen
.getDeterminations()) {
1084 if (determinationEvent
.getModifier() != null) {
1085 nonCascadedCdmEntities
.add(determinationEvent
.getModifier());
1089 if (specimen
.getKindOfUnit() != null) {
1090 nonCascadedCdmEntities
.add(specimen
.getKindOfUnit());
1093 if (specimen
.getLifeStage() != null) {
1094 nonCascadedCdmEntities
.add(specimen
.getLifeStage());
1097 if (specimen
.getSex() != null) {
1098 nonCascadedCdmEntities
.add(specimen
.getSex());
1100 return nonCascadedCdmEntities
;
1104 public DeleteResult
isDeletable(UUID specimenUuid
, DeleteConfiguratorBase config
) {
1105 DeleteResult deleteResult
= new DeleteResult();
1106 SpecimenOrObservationBase specimen
= this.load(specimenUuid
);
1107 SpecimenDeleteConfigurator specimenDeleteConfigurator
= (SpecimenDeleteConfigurator
) config
;
1109 // check elements found by super method
1110 Set
<CdmBase
> relatedObjects
= super.isDeletable(specimenUuid
, config
).getRelatedObjects();
1111 for (CdmBase cdmBase
: relatedObjects
) {
1112 // check for type designation
1113 if (cdmBase
.isInstanceOf(SpecimenTypeDesignation
.class) && !specimenDeleteConfigurator
.isDeleteFromTypeDesignation()) {
1114 deleteResult
.setAbort();
1115 deleteResult
.addException(new ReferencedObjectUndeletableException("Specimen or obeservation is a type specimen."));
1116 deleteResult
.addRelatedObject(cdmBase
);
1119 // check for IndividualsAssociations
1120 else if (cdmBase
.isInstanceOf(IndividualsAssociation
.class) && !specimenDeleteConfigurator
.isDeleteFromIndividualsAssociation()) {
1121 deleteResult
.setAbort();
1122 deleteResult
.addException(new ReferencedObjectUndeletableException("Specimen or obeservation is still associated via IndividualsAssociations"));
1123 deleteResult
.addRelatedObject(cdmBase
);
1126 // check for taxon description
1127 else if(cdmBase
.isInstanceOf(TaxonDescription
.class)
1128 && HibernateProxyHelper
.deproxy(cdmBase
, TaxonDescription
.class).getDescribedSpecimenOrObservation().equals(specimen
)
1129 && !specimenDeleteConfigurator
.isDeleteFromDescription()){
1130 deleteResult
.setAbort();
1131 deleteResult
.addException(new ReferencedObjectUndeletableException("Specimen or obeservation is still used as \"Described Specimen\" in a taxon description."));
1132 deleteResult
.addRelatedObject(cdmBase
);
1135 // check for children and parents (derivation events)
1136 else if (cdmBase
.isInstanceOf(DerivationEvent
.class)) {
1137 DerivationEvent derivationEvent
= HibernateProxyHelper
.deproxy(cdmBase
, DerivationEvent
.class);
1138 // check if derivation event is empty
1139 if (!derivationEvent
.getDerivatives().isEmpty() && derivationEvent
.getOriginals().contains(specimen
)) {
1140 // if derivationEvent is the childEvent and contains derivations
1141 // if (derivationEvent.getDerivatives().contains(specimen)) {
1142 // //if it is the parent event the specimen is still deletable
1145 if(!specimenDeleteConfigurator
.isDeleteChildren()){
1146 //if children should not be deleted then it is undeletable
1147 deleteResult
.setAbort();
1148 deleteResult
.addException(new ReferencedObjectUndeletableException("Specimen or obeservation still has child derivatives."));
1149 deleteResult
.addRelatedObject(cdmBase
);
1153 // check all children if they can be deleted
1154 Set
<DerivedUnit
> derivatives
= derivationEvent
.getDerivatives();
1155 DeleteResult childResult
= new DeleteResult();
1156 for (DerivedUnit derivedUnit
: derivatives
) {
1157 childResult
.includeResult(isDeletable(derivedUnit
.getUuid(), specimenDeleteConfigurator
));
1159 if (!childResult
.isOk()) {
1160 deleteResult
.setAbort();
1161 deleteResult
.includeResult(childResult
);
1162 deleteResult
.addRelatedObject(cdmBase
);
1168 // check for amplification
1169 else if (cdmBase
.isInstanceOf(AmplificationResult
.class)
1170 && !specimenDeleteConfigurator
.isDeleteMolecularData()
1171 && !specimenDeleteConfigurator
.isDeleteChildren()) {
1172 deleteResult
.setAbort();
1173 deleteResult
.addException(new ReferencedObjectUndeletableException("DnaSample is used in amplification results."));
1174 deleteResult
.addRelatedObject(cdmBase
);
1177 // check for sequence
1178 else if (cdmBase
.isInstanceOf(Sequence
.class)
1179 && !specimenDeleteConfigurator
.isDeleteMolecularData()
1180 && !specimenDeleteConfigurator
.isDeleteChildren()) {
1181 deleteResult
.setAbort();
1182 deleteResult
.addException(new ReferencedObjectUndeletableException("DnaSample is used in sequences."));
1183 deleteResult
.addRelatedObject(cdmBase
);
1187 if (deleteResult
.isOk()) {
1188 //add all related object if deletion is OK so they can be handled by the delete() method
1189 deleteResult
.addRelatedObjects(relatedObjects
);
1191 return deleteResult
;
1197 @Transactional(readOnly
= false)
1199 public DeleteResult
delete(UUID specimenUuid
, SpecimenDeleteConfigurator config
) {
1200 return delete(load(specimenUuid
), config
);
1204 @Transactional(readOnly
= false)
1206 public DeleteResult
delete(SpecimenOrObservationBase
<?
> specimen
, SpecimenDeleteConfigurator config
) {
1207 specimen
= HibernateProxyHelper
.deproxy(specimen
, SpecimenOrObservationBase
.class);
1209 DeleteResult deleteResult
= isDeletable(specimen
.getUuid(), config
);
1210 if (!deleteResult
.isOk()) {
1211 return deleteResult
;
1214 if (config
.isDeleteChildren()) {
1215 Set
<DerivationEvent
> derivationEvents
= specimen
.getDerivationEvents();
1216 //clone to avoid concurrent modification
1217 //can happen if the child is deleted and deleted its own derivedFrom event
1218 Set
<DerivationEvent
> derivationEventsClone
= new HashSet
<>(derivationEvents
);
1219 for (DerivationEvent derivationEvent
: derivationEventsClone
) {
1220 Set
<DerivedUnit
> derivatives
= derivationEvent
.getDerivatives();
1221 Iterator
<DerivedUnit
> it
= derivatives
.iterator();
1222 Set
<DerivedUnit
> derivativesToDelete
= new HashSet
<>();
1223 while (it
.hasNext()) {
1224 DerivedUnit unit
= it
.next();
1225 derivativesToDelete
.add(unit
);
1227 for (DerivedUnit unit
:derivativesToDelete
){
1228 deleteResult
.includeResult(delete(unit
, config
));
1236 // check related objects
1237 Set
<CdmBase
> relatedObjects
= deleteResult
.getRelatedObjects();
1239 for (CdmBase relatedObject
: relatedObjects
) {
1240 // check for TypeDesignations
1241 if (relatedObject
.isInstanceOf(SpecimenTypeDesignation
.class)) {
1242 SpecimenTypeDesignation designation
= HibernateProxyHelper
.deproxy(relatedObject
, SpecimenTypeDesignation
.class);
1243 designation
.setTypeSpecimen(null);
1244 List
<TaxonName
> typifiedNames
= new ArrayList
<>();
1245 typifiedNames
.addAll(designation
.getTypifiedNames());
1246 for (TaxonName taxonName
: typifiedNames
) {
1247 taxonName
.removeTypeDesignation(designation
);
1250 // delete IndividualsAssociation
1251 if (relatedObject
.isInstanceOf(IndividualsAssociation
.class)) {
1252 IndividualsAssociation association
= HibernateProxyHelper
.deproxy(relatedObject
, IndividualsAssociation
.class);
1253 association
.setAssociatedSpecimenOrObservation(null);
1254 association
.getInDescription().removeElement(association
);
1256 // check for "described specimen" (deprecated)
1257 if (relatedObject
.isInstanceOf(TaxonDescription
.class)) {
1258 TaxonDescription description
= HibernateProxyHelper
.deproxy(relatedObject
, TaxonDescription
.class);
1259 description
.setDescribedSpecimenOrObservation(null);
1261 // check for specimen description
1262 if (relatedObject
.isInstanceOf(SpecimenDescription
.class)) {
1263 SpecimenDescription specimenDescription
= HibernateProxyHelper
.deproxy(relatedObject
, SpecimenDescription
.class);
1264 specimenDescription
.setDescribedSpecimenOrObservation(null);
1265 // check if description is a description of the given specimen
1266 if (specimen
.getDescriptions().contains(specimenDescription
)) {
1267 specimen
.removeDescription(specimenDescription
);
1269 DeleteResult descriptionDelete
= descriptionService
.isDeletable(specimenDescription
.getUuid(), null);
1270 if (descriptionDelete
.isOk()){
1271 deleteResult
.includeResult(descriptionService
.delete(specimenDescription
));
1274 // check for amplification
1275 if (relatedObject
.isInstanceOf(AmplificationResult
.class)) {
1276 AmplificationResult amplificationResult
= HibernateProxyHelper
.deproxy(relatedObject
, AmplificationResult
.class);
1277 amplificationResult
.getDnaSample().removeAmplificationResult(amplificationResult
);
1279 // check for sequence
1280 if (relatedObject
.isInstanceOf(Sequence
.class)) {
1281 Sequence sequence
= HibernateProxyHelper
.deproxy(relatedObject
, Sequence
.class);
1282 sequence
.getDnaSample().removeSequence(sequence
);
1284 // check for children and parents (derivation events)
1285 if (relatedObject
.isInstanceOf(DerivationEvent
.class)) {
1286 DerivationEvent derivationEvent
= HibernateProxyHelper
.deproxy(relatedObject
, DerivationEvent
.class);
1287 // parent derivation event (derivedFrom)
1288 if (derivationEvent
.getDerivatives().contains(specimen
) && specimen
.isInstanceOf(DerivedUnit
.class)) {
1289 derivationEvent
.removeDerivative(HibernateProxyHelper
.deproxy(specimen
, DerivedUnit
.class));
1290 if (derivationEvent
.getDerivatives().isEmpty()) {
1291 Set
<SpecimenOrObservationBase
> originals
= derivationEvent
.getOriginals();
1292 for (SpecimenOrObservationBase specimenOrObservationBase
: originals
) {
1293 specimenOrObservationBase
.removeDerivationEvent(derivationEvent
);
1294 deleteResult
.addUpdatedObject(specimenOrObservationBase
);
1296 // if derivationEvent has no derivates anymore, delete it
1297 deleteResult
.includeResult(eventService
.delete(derivationEvent
));
1301 //child derivation events should not occur since we delete the hierarchy from bottom to top
1305 if (specimen
instanceof FieldUnit
){
1306 FieldUnit fieldUnit
= HibernateProxyHelper
.deproxy(specimen
, FieldUnit
.class);
1307 GatheringEvent event
= fieldUnit
.getGatheringEvent();
1308 fieldUnit
.setGatheringEvent(null);
1310 DeleteResult result
= eventService
.isDeletable(event
.getUuid(), null);
1312 deleteResult
.includeResult( eventService
.delete(event
));
1317 deleteResult
.includeResult(delete(specimen
));
1319 return deleteResult
;
1323 public Collection
<IndividualsAssociation
> listIndividualsAssociations(SpecimenOrObservationBase
<?
> specimen
, Integer limit
, Integer start
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
1324 return dao
.listIndividualsAssociations(specimen
, null, null, null, null);
1328 public Collection
<TaxonBase
<?
>> listAssociatedTaxa(SpecimenOrObservationBase
<?
> specimen
, Integer limit
, Integer start
,
1329 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
1330 Collection
<TaxonBase
<?
>> associatedTaxa
= new HashSet
<>();
1332 //individuals associations
1333 associatedTaxa
.addAll(listIndividualsAssociationTaxa(specimen
, limit
, start
, orderHints
, propertyPaths
));
1335 if(specimen
.isInstanceOf(DerivedUnit
.class)){
1336 associatedTaxa
.addAll(listTypeDesignationTaxa(HibernateProxyHelper
.deproxy(specimen
, DerivedUnit
.class), limit
, start
, orderHints
, propertyPaths
));
1339 associatedTaxa
.addAll(listDeterminedTaxa(specimen
, limit
, start
, orderHints
, propertyPaths
));
1341 return associatedTaxa
;
1346 public Collection
<TaxonBase
<?
>> listDeterminedTaxa(SpecimenOrObservationBase
<?
> specimen
, Integer limit
, Integer start
,
1347 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
1348 Collection
<TaxonBase
<?
>> associatedTaxa
= new HashSet
<>();
1349 for (DeterminationEvent determinationEvent
: listDeterminationEvents(specimen
, limit
, start
, orderHints
, propertyPaths
)) {
1350 if(determinationEvent
.getIdentifiedUnit().equals(specimen
)){
1351 if(determinationEvent
.getTaxon()!=null){
1352 associatedTaxa
.add(determinationEvent
.getTaxon());
1354 if(determinationEvent
.getTaxonName()!=null){
1355 associatedTaxa
.addAll((Collection
)determinationEvent
.getTaxonName().getTaxonBases());
1359 return associatedTaxa
;
1363 public Collection
<TaxonBase
<?
>> listTypeDesignationTaxa(DerivedUnit specimen
, Integer limit
, Integer start
,
1364 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
1365 Collection
<TaxonBase
<?
>> associatedTaxa
= new HashSet
<>();
1366 for (SpecimenTypeDesignation typeDesignation
: listTypeDesignations(specimen
, limit
, start
, orderHints
, propertyPaths
)) {
1367 if(typeDesignation
.getTypeSpecimen().equals(specimen
)){
1368 Set
<TaxonName
> typifiedNames
= typeDesignation
.getTypifiedNames();
1369 for (TaxonName taxonName
: typifiedNames
) {
1370 associatedTaxa
.addAll(taxonName
.getTaxa());
1374 return associatedTaxa
;
1378 public Collection
<TaxonBase
<?
>> listIndividualsAssociationTaxa(SpecimenOrObservationBase
<?
> specimen
, Integer limit
, Integer start
,
1379 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
1380 Collection
<TaxonBase
<?
>> associatedTaxa
= new HashSet
<>();
1381 for (IndividualsAssociation individualsAssociation
: listIndividualsAssociations(specimen
, limit
, start
, orderHints
, propertyPaths
)) {
1382 if(individualsAssociation
.getInDescription().isInstanceOf(TaxonDescription
.class)){
1383 TaxonDescription taxonDescription
= HibernateProxyHelper
.deproxy(individualsAssociation
.getInDescription(), TaxonDescription
.class);
1384 if(taxonDescription
.getTaxon()!=null){
1385 associatedTaxa
.add(taxonDescription
.getTaxon());
1389 return associatedTaxa
;
1393 public Collection
<DeterminationEvent
> listDeterminationEvents(SpecimenOrObservationBase
<?
> specimen
,
1394 Integer limit
, Integer start
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
1395 return dao
.listDeterminationEvents(specimen
, limit
, start
, orderHints
, propertyPaths
);
1399 public Map
<DerivedUnit
, Collection
<SpecimenTypeDesignation
>> listTypeDesignations(
1400 Collection
<DerivedUnit
> specimens
, Integer limit
, Integer start
,
1401 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
1402 Map
<DerivedUnit
, Collection
<SpecimenTypeDesignation
>> typeDesignationMap
= new HashMap
<>();
1403 for (DerivedUnit specimen
: specimens
) {
1404 Collection
<SpecimenTypeDesignation
> typeDesignations
= listTypeDesignations(specimen
, limit
, start
, orderHints
, propertyPaths
);
1405 typeDesignationMap
.put(specimen
, typeDesignations
);
1407 return typeDesignationMap
;
1411 public Collection
<SpecimenTypeDesignation
> listTypeDesignations(DerivedUnit specimen
,
1412 Integer limit
, Integer start
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
1413 return dao
.listTypeDesignations(specimen
, limit
, start
, orderHints
, propertyPaths
);
1417 public Collection
<DescriptionBase
<?
>> listDescriptionsWithDescriptionSpecimen(
1418 SpecimenOrObservationBase
<?
> specimen
, Integer limit
, Integer start
, List
<OrderHint
> orderHints
,
1419 List
<String
> propertyPaths
) {
1420 return dao
.listDescriptionsWithDescriptionSpecimen(specimen
, limit
, start
, orderHints
, propertyPaths
);
1424 @Deprecated //this is not a service layer task so it may be removed in future versions
1425 public Collection
<DescriptionElementBase
> getCharacterDataForSpecimen(SpecimenOrObservationBase
<?
> specimen
) {
1426 if (specimen
!= null) {
1427 return specimen
.characterData();
1429 return new ArrayList
<>();
1434 public Collection
<DescriptionElementBase
> getCharacterDataForSpecimen(UUID specimenUuid
) {
1435 SpecimenOrObservationBase
<?
> specimen
= load(specimenUuid
);
1436 if (specimen
!= null) {
1437 return getCharacterDataForSpecimen(specimen
);
1440 throw new DataRetrievalFailureException("Specimen with the given uuid not found in the data base");
1446 public Integer
countByTitle(IIdentifiableEntityServiceConfigurator
<SpecimenOrObservationBase
> config
){
1447 if (config
instanceof FindOccurrencesConfigurator
) {
1448 FindOccurrencesConfigurator occurrenceConfig
= (FindOccurrencesConfigurator
) config
;
1450 if(occurrenceConfig
.getAssociatedTaxonUuid()!=null){
1451 TaxonBase taxonBase
= taxonService
.load(occurrenceConfig
.getAssociatedTaxonUuid());
1452 if(taxonBase
.isInstanceOf(Taxon
.class)){
1453 taxon
= HibernateProxyHelper
.deproxy(taxonBase
, Taxon
.class);
1456 TaxonName taxonName
= null;
1457 if(occurrenceConfig
.getAssociatedTaxonNameUuid()!=null){
1458 taxonName
= nameService
.load(occurrenceConfig
.getAssociatedTaxonNameUuid());
1460 return dao
.countOccurrences(occurrenceConfig
.getClazz(),
1461 occurrenceConfig
.getTitleSearchString(), occurrenceConfig
.getSignificantIdentifier(),
1462 occurrenceConfig
.getSpecimenType(), taxon
, taxonName
, occurrenceConfig
.getMatchMode(), null, null,
1463 occurrenceConfig
.getOrderHints(), occurrenceConfig
.getPropertyPaths());
1466 return dao
.countByTitle(config
.getTitleSearchString());
1472 public Pager
<SpecimenOrObservationBase
> findByTitle(
1473 IIdentifiableEntityServiceConfigurator
<SpecimenOrObservationBase
> config
) {
1474 if (config
instanceof FindOccurrencesConfigurator
) {
1475 FindOccurrencesConfigurator occurrenceConfig
= (FindOccurrencesConfigurator
) config
;
1476 List
<SpecimenOrObservationBase
> occurrences
= new ArrayList
<>();
1478 if(occurrenceConfig
.getAssociatedTaxonUuid()!=null){
1479 TaxonBase taxonBase
= taxonService
.load(occurrenceConfig
.getAssociatedTaxonUuid());
1480 if(taxonBase
.isInstanceOf(Taxon
.class)){
1481 taxon
= HibernateProxyHelper
.deproxy(taxonBase
, Taxon
.class);
1484 TaxonName taxonName
= null;
1485 if(occurrenceConfig
.getAssociatedTaxonNameUuid()!=null){
1486 taxonName
= nameService
.load(occurrenceConfig
.getAssociatedTaxonNameUuid());
1488 occurrences
.addAll(dao
.findOccurrences(occurrenceConfig
.getClazz(),
1489 occurrenceConfig
.getTitleSearchString(), occurrenceConfig
.getSignificantIdentifier(),
1490 occurrenceConfig
.getSpecimenType(), taxon
, taxonName
, occurrenceConfig
.getMatchMode(), null, null,
1491 occurrenceConfig
.getOrderHints(), occurrenceConfig
.getPropertyPaths()));
1492 //filter out (un-)assigned specimens
1493 if(taxon
==null && taxonName
==null){
1494 AssignmentStatus assignmentStatus
= occurrenceConfig
.getAssignmentStatus();
1495 List
<SpecimenOrObservationBase
<?
>> specimenWithAssociations
= new ArrayList
<>();
1496 if(!assignmentStatus
.equals(AssignmentStatus
.ALL_SPECIMENS
)){
1497 for (SpecimenOrObservationBase specimenOrObservationBase
: occurrences
) {
1498 Collection
<TaxonBase
<?
>> associatedTaxa
= listAssociatedTaxa(specimenOrObservationBase
, null, null, null, null);
1499 if(!associatedTaxa
.isEmpty()){
1500 specimenWithAssociations
.add(specimenOrObservationBase
);
1504 if(assignmentStatus
.equals(AssignmentStatus
.UNASSIGNED_SPECIMENS
)){
1505 occurrences
.removeAll(specimenWithAssociations
);
1507 if(assignmentStatus
.equals(AssignmentStatus
.ASSIGNED_SPECIMENS
)){
1508 occurrences
= new ArrayList
<>(specimenWithAssociations
);
1511 // indirectly associated specimens
1512 if(occurrenceConfig
.isRetrieveIndirectlyAssociatedSpecimens()){
1513 List
<SpecimenOrObservationBase
> indirectlyAssociatedOccurrences
= new ArrayList
<>(occurrences
);
1514 for (SpecimenOrObservationBase specimen
: occurrences
) {
1515 List
<SpecimenOrObservationBase
<?
>> allHierarchyDerivates
= getAllHierarchyDerivatives(specimen
);
1516 for (SpecimenOrObservationBase
<?
> specimenOrObservationBase
: allHierarchyDerivates
) {
1517 if(!occurrences
.contains(specimenOrObservationBase
)){
1518 indirectlyAssociatedOccurrences
.add(specimenOrObservationBase
);
1522 occurrences
= indirectlyAssociatedOccurrences
;
1525 return new DefaultPagerImpl
<SpecimenOrObservationBase
>(config
.getPageNumber(), occurrences
.size(), config
.getPageSize(), occurrences
);
1527 return super.findByTitle(config
);
1531 public List
<SpecimenOrObservationBase
<?
>> getAllHierarchyDerivatives(SpecimenOrObservationBase
<?
> specimen
){
1532 List
<SpecimenOrObservationBase
<?
>> allHierarchyDerivatives
= new ArrayList
<>();
1533 Collection
<FieldUnit
> fieldUnits
= getFieldUnits(specimen
.getUuid());
1534 if(fieldUnits
.isEmpty()){
1535 allHierarchyDerivatives
.add(specimen
);
1536 allHierarchyDerivatives
.addAll(getAllChildDerivatives(specimen
));
1539 for (FieldUnit fieldUnit
: fieldUnits
) {
1540 allHierarchyDerivatives
.add(fieldUnit
);
1541 allHierarchyDerivatives
.addAll(getAllChildDerivatives(fieldUnit
));
1544 return allHierarchyDerivatives
;
1548 public List
<DerivedUnit
> getAllChildDerivatives(UUID specimenUuid
){
1549 return getAllChildDerivatives(load(specimenUuid
));
1553 public List
<DerivedUnit
> getAllChildDerivatives(SpecimenOrObservationBase
<?
> specimen
){
1554 if (specimen
== null){
1557 List
<DerivedUnit
> childDerivate
= new ArrayList
<>();
1558 Set
<DerivationEvent
> derivationEvents
= specimen
.getDerivationEvents();
1559 for (DerivationEvent derivationEvent
: derivationEvents
) {
1560 Set
<DerivedUnit
> derivatives
= derivationEvent
.getDerivatives();
1561 for (DerivedUnit derivedUnit
: derivatives
) {
1562 childDerivate
.add(derivedUnit
);
1563 childDerivate
.addAll(getAllChildDerivatives(derivedUnit
.getUuid()));
1566 return childDerivate
;
1570 public int countOccurrences(IIdentifiableEntityServiceConfigurator
<SpecimenOrObservationBase
> config
){
1571 return countByTitle(config
);
1578 public List
<FieldUnit
> getFieldUnitsForGatheringEvent(UUID gatheringEventUuid
) {
1579 return dao
.getFieldUnitsForGatheringEvent(gatheringEventUuid
, null, null, null, null);