3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
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.
11 package eu
.etaxonomy
.cdm
.api
.service
;
13 import java
.io
.IOException
;
14 import java
.util
.ArrayList
;
15 import java
.util
.Arrays
;
16 import java
.util
.Collection
;
17 import java
.util
.HashMap
;
18 import java
.util
.HashSet
;
19 import java
.util
.List
;
22 import java
.util
.UUID
;
24 import org
.apache
.log4j
.Logger
;
25 import org
.apache
.lucene
.index
.CorruptIndexException
;
26 import org
.apache
.lucene
.queryParser
.ParseException
;
27 import org
.apache
.lucene
.search
.BooleanClause
.Occur
;
28 import org
.apache
.lucene
.search
.BooleanQuery
;
29 import org
.apache
.lucene
.search
.SortField
;
30 import org
.hibernate
.TransientObjectException
;
31 import org
.hibernate
.search
.spatial
.impl
.Rectangle
;
32 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
33 import org
.springframework
.stereotype
.Service
;
34 import org
.springframework
.transaction
.annotation
.Transactional
;
36 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacade
;
37 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacadeConfigurator
;
38 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacadeNotSupportedException
;
39 import eu
.etaxonomy
.cdm
.api
.service
.molecular
.ISequenceService
;
40 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
41 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
42 import eu
.etaxonomy
.cdm
.api
.service
.search
.ILuceneIndexToolProvider
;
43 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
44 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
45 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
.TopGroupsWithMaxScore
;
46 import eu
.etaxonomy
.cdm
.api
.service
.search
.QueryFactory
;
47 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
48 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
49 import eu
.etaxonomy
.cdm
.api
.service
.util
.TaxonRelationshipEdge
;
50 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
51 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
52 import eu
.etaxonomy
.cdm
.model
.CdmBaseType
;
53 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTerm
;
54 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTermBase
;
55 import eu
.etaxonomy
.cdm
.model
.common
.ICdmBase
;
56 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
57 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
58 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
59 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
60 import eu
.etaxonomy
.cdm
.model
.description
.IndividualsAssociation
;
61 import eu
.etaxonomy
.cdm
.model
.location
.Country
;
62 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
63 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
64 import eu
.etaxonomy
.cdm
.model
.molecular
.DnaSample
;
65 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
66 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivationEvent
;
67 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
68 import eu
.etaxonomy
.cdm
.model
.occurrence
.DeterminationEvent
;
69 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldUnit
;
70 import eu
.etaxonomy
.cdm
.model
.occurrence
.GatheringEvent
;
71 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
72 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationType
;
73 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
74 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
75 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IDefinedTermDao
;
76 import eu
.etaxonomy
.cdm
.persistence
.dao
.initializer
.AbstractBeanInitializer
;
77 import eu
.etaxonomy
.cdm
.persistence
.dao
.occurrence
.IOccurrenceDao
;
78 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
79 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
80 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
83 * @author a.babadshanjan
87 @Transactional(readOnly
= true)
88 public class OccurrenceServiceImpl
extends IdentifiableServiceBase
<SpecimenOrObservationBase
,IOccurrenceDao
> implements IOccurrenceService
{
90 static private final Logger logger
= Logger
.getLogger(OccurrenceServiceImpl
.class);
93 private IDefinedTermDao definedTermDao
;
96 private IDescriptionService descriptionService
;
99 private ITaxonService taxonService
;
102 private ITermService termService
;
105 private INameService nameService
;
108 private ISequenceService sequenceService
;
111 private AbstractBeanInitializer beanInitializer
;
114 private ITaxonDao taxonDao
;
117 private ILuceneIndexToolProvider luceneIndexToolProvider
;
120 public OccurrenceServiceImpl() {
121 logger
.debug("Load OccurrenceService Bean");
126 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
129 @Transactional(readOnly
= false)
130 public void updateTitleCache(Class
<?
extends SpecimenOrObservationBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<SpecimenOrObservationBase
> cacheStrategy
, IProgressMonitor monitor
) {
132 clazz
= SpecimenOrObservationBase
.class;
134 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
139 * FIXME Candidate for harmonization
140 * move to termService
143 public Country
getCountryByIso(String iso639
) {
144 return this.definedTermDao
.getCountryByIso(iso639
);
149 * FIXME Candidate for harmonization
150 * move to termService
153 public List
<Country
> getCountryByName(String name
) {
154 List
<?
extends DefinedTermBase
> terms
= this.definedTermDao
.findByTitle(Country
.class, name
, null, null, null, null, null, null) ;
155 List
<Country
> countries
= new ArrayList
<Country
>();
156 for (int i
=0;i
<terms
.size();i
++){
157 countries
.add((Country
)terms
.get(i
));
164 protected void setDao(IOccurrenceDao dao
) {
169 public Pager
<DerivationEvent
> getDerivationEvents(SpecimenOrObservationBase occurence
, Integer pageSize
,Integer pageNumber
, List
<String
> propertyPaths
) {
170 Integer numberOfResults
= dao
.countDerivationEvents(occurence
);
172 List
<DerivationEvent
> results
= new ArrayList
<DerivationEvent
>();
173 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
174 results
= dao
.getDerivationEvents(occurence
, pageSize
, pageNumber
,propertyPaths
);
177 return new DefaultPagerImpl
<DerivationEvent
>(pageNumber
, numberOfResults
, pageSize
, results
);
181 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#countDeterminations(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.taxon.TaxonBase)
184 public int countDeterminations(SpecimenOrObservationBase occurence
, TaxonBase taxonbase
) {
185 return dao
.countDeterminations(occurence
, taxonbase
);
189 public Pager
<DeterminationEvent
> getDeterminations(SpecimenOrObservationBase occurrence
, TaxonBase taxonBase
, Integer pageSize
,Integer pageNumber
, List
<String
> propertyPaths
) {
190 Integer numberOfResults
= dao
.countDeterminations(occurrence
, taxonBase
);
192 List
<DeterminationEvent
> results
= new ArrayList
<DeterminationEvent
>();
193 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
194 results
= dao
.getDeterminations(occurrence
,taxonBase
, pageSize
, pageNumber
, propertyPaths
);
197 return new DefaultPagerImpl
<DeterminationEvent
>(pageNumber
, numberOfResults
, pageSize
, results
);
201 public Pager
<Media
> getMedia(SpecimenOrObservationBase occurence
,Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
202 Integer numberOfResults
= dao
.countMedia(occurence
);
204 List
<Media
> results
= new ArrayList
<Media
>();
205 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
206 results
= dao
.getMedia(occurence
, pageSize
, pageNumber
, propertyPaths
);
209 return new DefaultPagerImpl
<Media
>(pageNumber
, numberOfResults
, pageSize
, results
);
213 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#list(java.lang.Class, eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
216 public Pager
<SpecimenOrObservationBase
> list(Class
<?
extends SpecimenOrObservationBase
> type
, TaxonBase determinedAs
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
217 Integer numberOfResults
= dao
.count(type
,determinedAs
);
218 List
<SpecimenOrObservationBase
> results
= new ArrayList
<SpecimenOrObservationBase
>();
219 pageNumber
= pageNumber
== null ?
0 : pageNumber
;
220 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
221 Integer start
= pageSize
== null ?
0 : pageSize
* pageNumber
;
222 results
= dao
.list(type
,determinedAs
, pageSize
, start
, orderHints
,propertyPaths
);
224 return new DefaultPagerImpl
<SpecimenOrObservationBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
228 public List
<UuidAndTitleCache
<DerivedUnit
>> getDerivedUnitUuidAndTitleCache() {
229 return dao
.getDerivedUnitUuidAndTitleCache();
233 public List
<UuidAndTitleCache
<FieldUnit
>> getFieldUnitUuidAndTitleCache() {
234 return dao
.getFieldUnitUuidAndTitleCache();
238 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getDerivedUnitFacade(eu.etaxonomy.cdm.model.occurrence.DerivedUnit)
241 public DerivedUnitFacade
getDerivedUnitFacade(DerivedUnit derivedUnit
, List
<String
> propertyPaths
) throws DerivedUnitFacadeNotSupportedException
{
242 derivedUnit
= (DerivedUnit
)dao
.load(derivedUnit
.getUuid(), null);
243 DerivedUnitFacadeConfigurator config
= DerivedUnitFacadeConfigurator
.NewInstance();
244 config
.setThrowExceptionForNonSpecimenPreservationMethodRequest(false);
245 DerivedUnitFacade derivedUnitFacade
= DerivedUnitFacade
.NewInstance(derivedUnit
, config
);
246 beanInitializer
.initialize(derivedUnitFacade
, propertyPaths
);
247 return derivedUnitFacade
;
251 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listDerivedUnitFacades(eu.etaxonomy.cdm.model.description.DescriptionBase, java.util.List)
254 public List
<DerivedUnitFacade
> listDerivedUnitFacades(
255 DescriptionBase description
, List
<String
> propertyPaths
) {
257 List
<DerivedUnitFacade
> derivedUnitFacadeList
= new ArrayList
<DerivedUnitFacade
>();
258 IndividualsAssociation tempIndividualsAssociation
;
259 SpecimenOrObservationBase tempSpecimenOrObservationBase
;
260 List
<DescriptionElementBase
> elements
= descriptionService
.listDescriptionElements(description
, null, IndividualsAssociation
.class, null, 0, Arrays
.asList(new String
[]{"associatedSpecimenOrObservation"}));
261 for(DescriptionElementBase element
: elements
){
262 if(element
instanceof IndividualsAssociation
){
263 tempIndividualsAssociation
= (IndividualsAssociation
)element
;
264 if(tempIndividualsAssociation
.getAssociatedSpecimenOrObservation() != null){
265 tempSpecimenOrObservationBase
= HibernateProxyHelper
.deproxy(tempIndividualsAssociation
.getAssociatedSpecimenOrObservation(), SpecimenOrObservationBase
.class);
266 if(tempSpecimenOrObservationBase
instanceof DerivedUnit
){
268 derivedUnitFacadeList
.add(DerivedUnitFacade
.NewInstance((DerivedUnit
)tempSpecimenOrObservationBase
));
269 } catch (DerivedUnitFacadeNotSupportedException e
) {
270 logger
.warn(tempIndividualsAssociation
.getAssociatedSpecimenOrObservation().getTitleCache() + " : " +e
.getMessage());
278 beanInitializer
.initializeAll(derivedUnitFacadeList
, propertyPaths
);
280 return derivedUnitFacadeList
;
285 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listByAnyAssociation(java.lang.Class, java.util.Set, eu.etaxonomy.cdm.model.taxon.Taxon, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
288 public <T
extends SpecimenOrObservationBase
> List
<T
> listByAssociatedTaxon(Class
<T
> type
, Set
<TaxonRelationshipEdge
> includeRelationships
,
289 Taxon associatedTaxon
, Integer maxDepth
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
291 return pageByAssociatedTaxon(type
, includeRelationships
, associatedTaxon
, maxDepth
, pageSize
, pageNumber
, orderHints
, propertyPaths
).getRecords();
296 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#pageByAssociatedTaxon(java.lang.Class, java.util.Set, eu.etaxonomy.cdm.model.taxon.Taxon, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
298 @SuppressWarnings("unchecked")
300 public <T
extends SpecimenOrObservationBase
> Pager
<T
> pageByAssociatedTaxon(Class
<T
> type
, Set
<TaxonRelationshipEdge
> includeRelationships
,
301 Taxon associatedTaxon
, Integer maxDepth
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
303 Set
<Taxon
> taxa
= new HashSet
<Taxon
>();
304 Set
<Integer
> occurrenceIds
= new HashSet
<Integer
>();
305 List
<T
> occurrences
= new ArrayList
<T
>();
307 // Integer limit = PagerUtils.limitFor(pageSize);
308 // Integer start = PagerUtils.startFor(pageSize, pageNumber);
310 associatedTaxon
= (Taxon
) taxonDao
.load(associatedTaxon
.getUuid());
312 if(includeRelationships
!= null) {
313 taxa
= taxonService
.listRelatedTaxa(associatedTaxon
, includeRelationships
, maxDepth
, null, null, propertyPaths
);
316 taxa
.add(associatedTaxon
);
318 for (Taxon taxon
: taxa
) {
319 List
<T
> perTaxonOccurrences
= dao
.listByAssociatedTaxon(type
, taxon
, null, null, orderHints
, propertyPaths
);
320 for (SpecimenOrObservationBase o
: perTaxonOccurrences
) {
321 occurrenceIds
.add(o
.getId());
324 occurrences
= (List
<T
>) dao
.listByIds(occurrenceIds
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
326 return new DefaultPagerImpl
<T
>(pageNumber
, occurrenceIds
.size(), pageSize
, occurrences
);
331 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#pageByAssociatedTaxon(java.lang.Class, java.util.Set, eu.etaxonomy.cdm.model.taxon.Taxon, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
333 @SuppressWarnings("unchecked")
335 public <T
extends SpecimenOrObservationBase
> Pager
<T
> pageByAssociatedTaxon(Class
<T
> type
, Set
<TaxonRelationshipEdge
> includeRelationships
,
336 String taxonUUID
, Integer maxDepth
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
338 UUID uuid
= UUID
.fromString(taxonUUID
);
339 Taxon tax
= (Taxon
) taxonDao
.load(uuid
);
340 //TODO REMOVE NULL STATEMENT
342 return pageByAssociatedTaxon( type
,includeRelationships
,tax
, maxDepth
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
348 public Pager
<SearchResult
<SpecimenOrObservationBase
>> findByFullText(
349 Class
<?
extends SpecimenOrObservationBase
> clazz
, String queryString
, Rectangle boundingBox
, List
<Language
> languages
,
350 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
,
351 List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
353 LuceneSearch luceneSearch
= prepareByFullTextSearch(clazz
, queryString
, boundingBox
, languages
, highlightFragments
);
355 // --- execute search
356 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
358 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
359 idFieldMap
.put(CdmBaseType
.SPECIMEN_OR_OBSERVATIONBASE
, "id");
361 // --- initialize taxa, highlight matches ....
362 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
363 @SuppressWarnings("rawtypes")
364 List
<SearchResult
<SpecimenOrObservationBase
>> searchResults
= searchResultBuilder
.createResultSet(
365 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
367 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
369 return new DefaultPagerImpl
<SearchResult
<SpecimenOrObservationBase
>>(pageNumber
, totalHits
, pageSize
,
379 * @param highlightFragments
382 private LuceneSearch
prepareByFullTextSearch(Class
<?
extends SpecimenOrObservationBase
> clazz
, String queryString
, Rectangle bbox
,
383 List
<Language
> languages
, boolean highlightFragments
) {
385 BooleanQuery finalQuery
= new BooleanQuery();
386 BooleanQuery textQuery
= new BooleanQuery();
388 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, FieldUnit
.class);
389 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(FieldUnit
.class);
392 luceneSearch
.setCdmTypRestriction(clazz
);
393 if(queryString
!= null){
394 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
395 finalQuery
.add(textQuery
, Occur
.MUST
);
400 finalQuery
.add(QueryFactory
.buildSpatialQueryByRange(bbox
, "gatheringEvent.exactLocation.point"), Occur
.MUST
);
403 luceneSearch
.setQuery(finalQuery
);
406 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
407 luceneSearch
.setSortFields(sortFields
);
409 if(highlightFragments
){
410 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
417 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getFieldUnits(eu.etaxonomy.cdm.model.occurrence.DerivedUnit)
420 public Collection
<FieldUnit
> getFieldUnits(UUID derivedUnitUuid
) {
421 //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})
422 //from which this DerivedUnit was derived until all FieldUnits are found.
424 //FIXME: use HQL queries to increase performance
425 Collection
<FieldUnit
> fieldUnits
= new ArrayList
<FieldUnit
>();
426 SpecimenOrObservationBase derivedUnit
= load(derivedUnitUuid
);
427 if(derivedUnit
instanceof DerivedUnit
){
428 getFieldUnits((DerivedUnit
) derivedUnit
, fieldUnits
);
438 private void getFieldUnits(DerivedUnit derivedUnit
, Collection
<FieldUnit
> fieldUnits
) {
439 Set
<SpecimenOrObservationBase
> originals
= derivedUnit
.getOriginals();
440 if(originals
!=null && !originals
.isEmpty()){
441 for(SpecimenOrObservationBase
<?
> original
:originals
){
442 if(original
instanceof FieldUnit
){
443 fieldUnits
.add((FieldUnit
) original
);
445 else if(original
instanceof DerivedUnit
){
446 getFieldUnits((DerivedUnit
) original
, fieldUnits
);
453 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#moveSequence(eu.etaxonomy.cdm.model.molecular.DnaSample, eu.etaxonomy.cdm.model.molecular.DnaSample, eu.etaxonomy.cdm.model.molecular.Sequence)
456 public boolean moveSequence(DnaSample from
, DnaSample to
, Sequence sequence
) {
457 //reload specimens to avoid session conflicts
458 from
= (DnaSample
) load(from
.getUuid());
459 to
= (DnaSample
) load(to
.getUuid());
460 sequence
= sequenceService
.load(sequence
.getUuid());
462 if(from
==null || to
==null || sequence
==null){
463 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" +
464 "Operation was move "+sequence
+ " from "+from
+" to "+to
);
466 from
.removeSequence(sequence
);
468 to
.addSequence(sequence
);
474 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#moveDerivate(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.occurrence.DerivedUnit)
477 public boolean moveDerivate(SpecimenOrObservationBase
<?
> from
, SpecimenOrObservationBase
<?
> to
, DerivedUnit derivate
) {
478 //reload specimens to avoid session conflicts
479 from
= load(from
.getUuid());
480 to
= load(to
.getUuid());
481 derivate
= (DerivedUnit
) load(derivate
.getUuid());
483 if(from
==null || to
==null || derivate
==null){
484 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" +
485 "Operation was move "+derivate
+ " from "+from
+" to "+to
);
488 SpecimenOrObservationType derivateType
= derivate
.getRecordBasis();
489 SpecimenOrObservationType toType
= to
.getRecordBasis();
490 //check if type is a sub derivate type
491 if(toType
==SpecimenOrObservationType
.FieldUnit
//moving to FieldUnit always works
492 || derivateType
==SpecimenOrObservationType
.Media
//moving media always works
493 || (derivateType
.isKindOf(toType
) && toType
!=derivateType
)){ //moving only to parent derivate type
494 //remove derivation event from parent specimen of dragged object
495 DerivationEvent eventToRemove
= null;
496 for(DerivationEvent event
:from
.getDerivationEvents()){
497 if(event
.getDerivatives().contains(derivate
)){
498 eventToRemove
= event
;
502 from
.removeDerivationEvent(eventToRemove
);
504 //add new derivation event to target
505 to
.addDerivationEvent(DerivationEvent
.NewSimpleInstance(to
, derivate
, eventToRemove
==null?
null:eventToRemove
.getType()));
513 public Collection
<ICdmBase
> getNonCascadedAssociatedElements(SpecimenOrObservationBase
<?
> specimen
){
514 //potential fields that are not persisted cascadingly
527 --CollectingAreas TERM
535 -storedUnder CDM TaxonNameBase
538 Collection
<ICdmBase
> nonCascadedCdmEntities
= new HashSet
<ICdmBase
>();
539 //scan SpecimenOrObservationBase
540 for(DeterminationEvent determinationEvent
:specimen
.getDeterminations()){
542 if(determinationEvent
.getModifier()!=null){
543 nonCascadedCdmEntities
.add(determinationEvent
.getModifier());
547 if(specimen
.getKindOfUnit()!=null){
548 nonCascadedCdmEntities
.add(specimen
.getKindOfUnit());
551 if(specimen
.getLifeStage()!=null){
552 nonCascadedCdmEntities
.add(specimen
.getLifeStage());
555 if(specimen
.getSex()!=null){
556 nonCascadedCdmEntities
.add(specimen
.getSex());
560 if(specimen
instanceof FieldUnit
){
561 FieldUnit fieldUnit
= (FieldUnit
)specimen
;
562 GatheringEvent gatheringEvent
= fieldUnit
.getGatheringEvent();
563 if(gatheringEvent
!=null){
565 if(gatheringEvent
.getCountry()!=null){
566 nonCascadedCdmEntities
.add(gatheringEvent
.getCountry());
569 for (NamedArea namedArea
: gatheringEvent
.getCollectingAreas()) {
570 nonCascadedCdmEntities
.add(namedArea
);
573 for (DerivationEvent derivationEvent
: fieldUnit
.getDerivationEvents()) {
574 for (DerivedUnit derivedUnit
: derivationEvent
.getDerivatives()) {
575 nonCascadedCdmEntities
.addAll(getNonCascadedAssociatedElements(derivedUnit
));
581 else if(specimen
instanceof DerivedUnit
){
582 DerivedUnit derivedUnit
= (DerivedUnit
)specimen
;
583 if(derivedUnit
.getCollection()!=null && derivedUnit
.getCollection().getInstitute()!=null){
584 for (DefinedTerm type
: derivedUnit
.getCollection().getInstitute().getTypes()) {
585 nonCascadedCdmEntities
.add(type
);
588 if(derivedUnit
.getPreservation()!=null && derivedUnit
.getPreservation().getMedium()!=null){
589 nonCascadedCdmEntities
.add(derivedUnit
.getPreservation().getMedium());
591 if(derivedUnit
.getStoredUnder()!=null){
592 nonCascadedCdmEntities
.add(derivedUnit
.getStoredUnder());
595 return nonCascadedCdmEntities
;