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
;
15 import java
.net
.URISyntaxException
;
16 import java
.util
.ArrayList
;
17 import java
.util
.Arrays
;
18 import java
.util
.Collection
;
19 import java
.util
.HashMap
;
20 import java
.util
.HashSet
;
21 import java
.util
.LinkedHashSet
;
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
.index
.CorruptIndexException
;
30 import org
.apache
.lucene
.queryParser
.ParseException
;
31 import org
.apache
.lucene
.search
.BooleanClause
.Occur
;
32 import org
.apache
.lucene
.search
.BooleanQuery
;
33 import org
.apache
.lucene
.search
.SortField
;
34 import org
.hibernate
.TransientObjectException
;
35 import org
.hibernate
.search
.spatial
.impl
.Rectangle
;
36 import org
.joda
.time
.Partial
;
37 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
38 import org
.springframework
.stereotype
.Service
;
39 import org
.springframework
.transaction
.annotation
.Transactional
;
41 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacade
;
42 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacadeConfigurator
;
43 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacadeNotSupportedException
;
44 import eu
.etaxonomy
.cdm
.api
.service
.dto
.DerivateHierarchyDTO
;
45 import eu
.etaxonomy
.cdm
.api
.service
.molecular
.ISequenceService
;
46 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
47 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
48 import eu
.etaxonomy
.cdm
.api
.service
.search
.ILuceneIndexToolProvider
;
49 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
50 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
51 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
.TopGroupsWithMaxScore
;
52 import eu
.etaxonomy
.cdm
.api
.service
.search
.QueryFactory
;
53 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
54 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
55 import eu
.etaxonomy
.cdm
.api
.service
.util
.TaxonRelationshipEdge
;
56 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
57 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
58 import eu
.etaxonomy
.cdm
.model
.CdmBaseType
;
59 import eu
.etaxonomy
.cdm
.model
.agent
.AgentBase
;
60 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTerm
;
61 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTermBase
;
62 import eu
.etaxonomy
.cdm
.model
.common
.ICdmBase
;
63 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
64 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
65 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
66 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
67 import eu
.etaxonomy
.cdm
.model
.description
.IndividualsAssociation
;
68 import eu
.etaxonomy
.cdm
.model
.location
.Country
;
69 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
70 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
71 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
72 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentationPart
;
73 import eu
.etaxonomy
.cdm
.model
.molecular
.DnaSample
;
74 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
75 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleRead
;
76 import eu
.etaxonomy
.cdm
.model
.name
.SpecimenTypeDesignation
;
77 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
78 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationStatusBase
;
79 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivationEvent
;
80 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
81 import eu
.etaxonomy
.cdm
.model
.occurrence
.DeterminationEvent
;
82 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldUnit
;
83 import eu
.etaxonomy
.cdm
.model
.occurrence
.GatheringEvent
;
84 import eu
.etaxonomy
.cdm
.model
.occurrence
.MediaSpecimen
;
85 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
86 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationType
;
87 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
88 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
89 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IDefinedTermDao
;
90 import eu
.etaxonomy
.cdm
.persistence
.dao
.initializer
.AbstractBeanInitializer
;
91 import eu
.etaxonomy
.cdm
.persistence
.dao
.occurrence
.IOccurrenceDao
;
92 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
93 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
96 * @author a.babadshanjan
100 @Transactional(readOnly
= true)
101 public class OccurrenceServiceImpl
extends IdentifiableServiceBase
<SpecimenOrObservationBase
,IOccurrenceDao
> implements IOccurrenceService
{
103 static private final Logger logger
= Logger
.getLogger(OccurrenceServiceImpl
.class);
106 private IDefinedTermDao definedTermDao
;
109 private IDescriptionService descriptionService
;
112 private ITaxonService taxonService
;
115 private ITermService termService
;
118 private INameService nameService
;
121 private ISequenceService sequenceService
;
124 private AbstractBeanInitializer beanInitializer
;
127 private ILuceneIndexToolProvider luceneIndexToolProvider
;
130 public OccurrenceServiceImpl() {
131 logger
.debug("Load OccurrenceService Bean");
136 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
139 @Transactional(readOnly
= false)
140 public void updateTitleCache(Class
<?
extends SpecimenOrObservationBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<SpecimenOrObservationBase
> cacheStrategy
, IProgressMonitor monitor
) {
142 clazz
= SpecimenOrObservationBase
.class;
144 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
149 * FIXME Candidate for harmonization
150 * move to termService
153 public Country
getCountryByIso(String iso639
) {
154 return this.definedTermDao
.getCountryByIso(iso639
);
159 * FIXME Candidate for harmonization
160 * move to termService
163 public List
<Country
> getCountryByName(String name
) {
164 List
<?
extends DefinedTermBase
> terms
= this.definedTermDao
.findByTitle(Country
.class, name
, null, null, null, null, null, null) ;
165 List
<Country
> countries
= new ArrayList
<Country
>();
166 for (int i
=0;i
<terms
.size();i
++){
167 countries
.add((Country
)terms
.get(i
));
174 protected void setDao(IOccurrenceDao dao
) {
179 public Pager
<DerivationEvent
> getDerivationEvents(SpecimenOrObservationBase occurence
, Integer pageSize
,Integer pageNumber
, List
<String
> propertyPaths
) {
180 Integer numberOfResults
= dao
.countDerivationEvents(occurence
);
182 List
<DerivationEvent
> results
= new ArrayList
<DerivationEvent
>();
183 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
184 results
= dao
.getDerivationEvents(occurence
, pageSize
, pageNumber
,propertyPaths
);
187 return new DefaultPagerImpl
<DerivationEvent
>(pageNumber
, numberOfResults
, pageSize
, results
);
191 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#countDeterminations(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.taxon.TaxonBase)
194 public int countDeterminations(SpecimenOrObservationBase occurence
, TaxonBase taxonbase
) {
195 return dao
.countDeterminations(occurence
, taxonbase
);
199 public Pager
<DeterminationEvent
> getDeterminations(SpecimenOrObservationBase occurrence
, TaxonBase taxonBase
, Integer pageSize
,Integer pageNumber
, List
<String
> propertyPaths
) {
200 Integer numberOfResults
= dao
.countDeterminations(occurrence
, taxonBase
);
202 List
<DeterminationEvent
> results
= new ArrayList
<DeterminationEvent
>();
203 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
204 results
= dao
.getDeterminations(occurrence
,taxonBase
, pageSize
, pageNumber
, propertyPaths
);
207 return new DefaultPagerImpl
<DeterminationEvent
>(pageNumber
, numberOfResults
, pageSize
, results
);
211 public Pager
<Media
> getMedia(SpecimenOrObservationBase occurence
,Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
212 Integer numberOfResults
= dao
.countMedia(occurence
);
214 List
<Media
> results
= new ArrayList
<Media
>();
215 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
216 results
= dao
.getMedia(occurence
, pageSize
, pageNumber
, propertyPaths
);
219 return new DefaultPagerImpl
<Media
>(pageNumber
, numberOfResults
, pageSize
, results
);
223 * @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)
226 public Pager
<SpecimenOrObservationBase
> list(Class
<?
extends SpecimenOrObservationBase
> type
, TaxonBase determinedAs
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
227 Integer numberOfResults
= dao
.count(type
,determinedAs
);
228 List
<SpecimenOrObservationBase
> results
= new ArrayList
<SpecimenOrObservationBase
>();
229 pageNumber
= pageNumber
== null ?
0 : pageNumber
;
230 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
231 Integer start
= pageSize
== null ?
0 : pageSize
* pageNumber
;
232 results
= dao
.list(type
,determinedAs
, pageSize
, start
, orderHints
,propertyPaths
);
234 return new DefaultPagerImpl
<SpecimenOrObservationBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
238 public List
<UuidAndTitleCache
<DerivedUnit
>> getDerivedUnitUuidAndTitleCache() {
239 return dao
.getDerivedUnitUuidAndTitleCache();
243 public List
<UuidAndTitleCache
<FieldUnit
>> getFieldUnitUuidAndTitleCache() {
244 return dao
.getFieldUnitUuidAndTitleCache();
248 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getDerivedUnitFacade(eu.etaxonomy.cdm.model.occurrence.DerivedUnit)
251 public DerivedUnitFacade
getDerivedUnitFacade(DerivedUnit derivedUnit
, List
<String
> propertyPaths
) throws DerivedUnitFacadeNotSupportedException
{
252 derivedUnit
= (DerivedUnit
)dao
.load(derivedUnit
.getUuid(), null);
253 DerivedUnitFacadeConfigurator config
= DerivedUnitFacadeConfigurator
.NewInstance();
254 config
.setThrowExceptionForNonSpecimenPreservationMethodRequest(false);
255 DerivedUnitFacade derivedUnitFacade
= DerivedUnitFacade
.NewInstance(derivedUnit
, config
);
256 beanInitializer
.initialize(derivedUnitFacade
, propertyPaths
);
257 return derivedUnitFacade
;
261 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listDerivedUnitFacades(eu.etaxonomy.cdm.model.description.DescriptionBase, java.util.List)
264 public List
<DerivedUnitFacade
> listDerivedUnitFacades(
265 DescriptionBase description
, List
<String
> propertyPaths
) {
267 List
<DerivedUnitFacade
> derivedUnitFacadeList
= new ArrayList
<DerivedUnitFacade
>();
268 IndividualsAssociation tempIndividualsAssociation
;
269 SpecimenOrObservationBase tempSpecimenOrObservationBase
;
270 List
<DescriptionElementBase
> elements
= descriptionService
.listDescriptionElements(description
, null, IndividualsAssociation
.class, null, 0, Arrays
.asList(new String
[]{"associatedSpecimenOrObservation"}));
271 for(DescriptionElementBase element
: elements
){
272 if(element
instanceof IndividualsAssociation
){
273 tempIndividualsAssociation
= (IndividualsAssociation
)element
;
274 if(tempIndividualsAssociation
.getAssociatedSpecimenOrObservation() != null){
275 tempSpecimenOrObservationBase
= HibernateProxyHelper
.deproxy(tempIndividualsAssociation
.getAssociatedSpecimenOrObservation(), SpecimenOrObservationBase
.class);
276 if(tempSpecimenOrObservationBase
instanceof DerivedUnit
){
278 derivedUnitFacadeList
.add(DerivedUnitFacade
.NewInstance((DerivedUnit
)tempSpecimenOrObservationBase
));
279 } catch (DerivedUnitFacadeNotSupportedException e
) {
280 logger
.warn(tempIndividualsAssociation
.getAssociatedSpecimenOrObservation().getTitleCache() + " : " +e
.getMessage());
288 beanInitializer
.initializeAll(derivedUnitFacadeList
, propertyPaths
);
290 return derivedUnitFacadeList
;
295 * @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)
298 public <T
extends SpecimenOrObservationBase
> List
<T
> listByAssociatedTaxon(Class
<T
> type
, Set
<TaxonRelationshipEdge
> includeRelationships
,
299 Taxon associatedTaxon
, Integer maxDepth
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
301 return pageByAssociatedTaxon(type
, includeRelationships
, associatedTaxon
, maxDepth
, pageSize
, pageNumber
, orderHints
, propertyPaths
).getRecords();
305 * @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)
308 public Collection
<FieldUnit
> listFieldUnitsByAssociatedTaxon(Set
<TaxonRelationshipEdge
> includeRelationships
,
309 Taxon associatedTaxon
, Integer maxDepth
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
311 if(!getSession().contains(associatedTaxon
)){
312 associatedTaxon
= (Taxon
) taxonService
.load(associatedTaxon
.getUuid());
315 Set
<FieldUnit
> fieldUnits
= new HashSet
<FieldUnit
>();
317 List
<SpecimenOrObservationBase
> records
= pageByAssociatedTaxon(null, includeRelationships
, associatedTaxon
, maxDepth
, pageSize
, pageNumber
, orderHints
, propertyPaths
).getRecords();
318 for(SpecimenOrObservationBase
<?
> specimen
:records
){
319 fieldUnits
.addAll(getFieldUnits(specimen
.getUuid()));
325 public DerivateHierarchyDTO
assembleDerivateHierarchyDTO(FieldUnit fieldUnit
, UUID associatedTaxonUuid
){
327 if(!getSession().contains(fieldUnit
)){
328 fieldUnit
= (FieldUnit
) load(fieldUnit
.getUuid());
330 TaxonBase associatedTaxon
= taxonService
.load(associatedTaxonUuid
);
332 DerivateHierarchyDTO dto
= new DerivateHierarchyDTO();
333 Map
<UUID
, TypeDesignationStatusBase
> typeSpecimenUUIDtoTypeDesignationStatus
= new HashMap
<UUID
, TypeDesignationStatusBase
>();
335 //gather types for this taxon name
336 TaxonNameBase
<?
,?
> name
= associatedTaxon
.getName();
337 Set
<?
> typeDesignations
= name
.getSpecimenTypeDesignations();
338 for (Object object
: typeDesignations
) {
339 if(object
instanceof SpecimenTypeDesignation
){
340 SpecimenTypeDesignation specimenTypeDesignation
= (SpecimenTypeDesignation
)object
;
341 DerivedUnit typeSpecimen
= specimenTypeDesignation
.getTypeSpecimen();
342 final TypeDesignationStatusBase typeStatus
= specimenTypeDesignation
.getTypeStatus();
343 typeSpecimenUUIDtoTypeDesignationStatus
.put(typeSpecimen
.getUuid(), typeStatus
);
347 if(fieldUnit
.getGatheringEvent()!=null){
348 GatheringEvent gatheringEvent
= fieldUnit
.getGatheringEvent();
350 final NamedArea country
= gatheringEvent
.getCountry();
351 dto
.setCountry(country
!=null?country
.getDescription():"");
353 final AgentBase collector
= gatheringEvent
.getCollector();
354 final String fieldNumber
= fieldUnit
.getFieldNumber();
355 dto
.setCollection(((collector
!=null?collector
:"") + " " + (fieldNumber
!=null?fieldNumber
:"")).trim());
357 final Partial gatheringDate
= gatheringEvent
.getGatheringDate();
358 dto
.setDate(gatheringDate
!=null?gatheringDate
.toString():"");
362 dto
.setTaxonName(associatedTaxon
.getName().getFullTitleCache());
365 Collection
<DerivedUnit
> derivedUnits
= new ArrayList
<DerivedUnit
>();
366 getDerivedUnitsFor(fieldUnit
, derivedUnits
);
369 Map
<eu
.etaxonomy
.cdm
.model
.occurrence
.Collection
, Integer
> collectionToCountMap
= new HashMap
<eu
.etaxonomy
.cdm
.model
.occurrence
.Collection
, Integer
>();
370 //List of accession numbers for citation
371 List
<String
> preservedSpecimenAccessionNumbers
= new ArrayList
<String
>();
373 //iterate over sub derivates
374 for (DerivedUnit derivedUnit
: derivedUnits
) {
375 //current accession number
376 String currentAccessionNumber
= derivedUnit
.getAccessionNumber()!=null?derivedUnit
.getAccessionNumber():"";
378 String currentHerbarium
= "";
379 eu
.etaxonomy
.cdm
.model
.occurrence
.Collection collection
= derivedUnit
.getCollection();
380 if(collection
!=null){
381 currentHerbarium
= collection
.getCode()!=null?collection
.getCode():"";
383 Integer count
= collectionToCountMap
.get(collection
);
390 collectionToCountMap
.put(collection
, count
);
392 //check if derived unit is a type
393 if(typeSpecimenUUIDtoTypeDesignationStatus
.keySet().contains(derivedUnit
.getUuid())){
394 dto
.setHasType(true);
395 TypeDesignationStatusBase typeDesignationStatus
= typeSpecimenUUIDtoTypeDesignationStatus
.get(derivedUnit
.getUuid());
396 String typeStatus
= typeDesignationStatus
.getLabel();
397 dto
.addTypes(typeStatus
, currentAccessionNumber
);
399 //assemble molecular data
400 if(derivedUnit
instanceof DnaSample
){
401 if(derivedUnit
.getRecordBasis()==SpecimenOrObservationType
.TissueSample
){
402 //TODO implement TissueSample assembly for web service
404 if(derivedUnit
.getRecordBasis()==SpecimenOrObservationType
.DnaSample
){
406 DnaSample dna
= (DnaSample
)derivedUnit
;
407 if(!dna
.getSequences().isEmpty()){
410 for(Sequence sequence
:dna
.getSequences()){
413 boldUri
= sequence
.getBoldUri();
414 } catch (URISyntaxException e1
) {
415 logger
.error("Could not create BOLD URI", e1
);
417 final DefinedTerm dnaMarker
= sequence
.getDnaMarker();
418 dto
.addProviderLink(boldUri
!=null?boldUri
:null,dnaMarker
!=null?dnaMarker
.getLabel():"[no marker]");
422 //assemble media data
423 else if(derivedUnit
instanceof MediaSpecimen
){
425 MediaSpecimen media
= (MediaSpecimen
)derivedUnit
;
426 String mediaUriString
= getMediaUriString(media
);
427 if(media
.getKindOfUnit()!=null){
429 if(media
.getKindOfUnit().getUuid().equals(UUID
.fromString("acda15be-c0e2-4ea8-8783-b9b0c4ad7f03"))){
430 dto
.setHasSpecimenScan(true);
431 final String imageLinkText
= currentHerbarium
+" "+currentAccessionNumber
;
432 dto
.addSpecimenScan(mediaUriString
==null?
"":mediaUriString
, !imageLinkText
.equals(" ")?imageLinkText
:"[no accession]");
435 else if(media
.getKindOfUnit().getUuid().equals(UUID
.fromString("31eb8d02-bf5d-437c-bcc6-87a626445f34"))){
436 dto
.setHasDetailImage(true);
438 if(media
.getMediaSpecimen()!=null && media
.getMediaSpecimen().getTitle()!=null){
439 motif
= media
.getMediaSpecimen().getTitle().getText();
441 dto
.addDetailImage(mediaUriString
==null?
"":mediaUriString
, motif
!=null?motif
:"[no motif]");
445 //assemble preserved specimen data
446 else if(derivedUnit
.getRecordBasis()==SpecimenOrObservationType
.PreservedSpecimen
){
447 if(!currentAccessionNumber
.isEmpty()){
448 preservedSpecimenAccessionNumbers
.add(currentAccessionNumber
);
453 final String separator
= ", ";
455 String citation
= "";
456 citation
+= !dto
.getCountry().isEmpty()?dto
.getCountry()+separator
:"";
457 if(fieldUnit
.getGatheringEvent()!=null){
458 if(fieldUnit
.getGatheringEvent().getLocality()!=null){
459 citation
+= fieldUnit
.getGatheringEvent().getLocality().getText();
460 citation
+= separator
;
462 if(fieldUnit
.getGatheringEvent().getExactLocation()!=null
463 && fieldUnit
.getGatheringEvent().getExactLocation().getLatitude()!=null
464 && fieldUnit
.getGatheringEvent().getExactLocation().getLongitude()!=null){
465 citation
+= fieldUnit
.getGatheringEvent().getExactLocation().getLatitude().toString();
466 citation
+= separator
;
467 citation
+= fieldUnit
.getGatheringEvent().getExactLocation().getLongitude().toString();
468 citation
+= separator
;
471 citation
+= !dto
.getCollection().isEmpty()?dto
.getCollection():"";
472 if(!preservedSpecimenAccessionNumbers
.isEmpty()){
474 for(String accessionNumber
:preservedSpecimenAccessionNumbers
){
475 if(!accessionNumber
.isEmpty()){
476 citation
+= accessionNumber
+separator
;
479 citation
= removeTail(citation
, separator
);
482 citation
= removeTail(citation
, separator
);
483 dto
.setCitation(citation
);
485 //assemble herbaria string
486 String herbariaString
= "";
487 for(Entry
<eu
.etaxonomy
.cdm
.model
.occurrence
.Collection
, Integer
> e
:collectionToCountMap
.entrySet()){
488 eu
.etaxonomy
.cdm
.model
.occurrence
.Collection collection
= e
.getKey();
489 if(collection
.getCode()!=null){
490 herbariaString
+= collection
.getCode();
493 herbariaString
+= "("+e
.getValue()+")";
495 herbariaString
+= separator
;
497 herbariaString
= removeTail(herbariaString
, separator
);
498 dto
.setHerbarium(herbariaString
);
509 private String
removeTail(String string
, final String tail
) {
510 if(string
.endsWith(tail
)){
511 string
= string
.substring(0, string
.length()-tail
.length());
516 private String
getMediaUriString(MediaSpecimen mediaSpecimen
){
517 String mediaUri
= null;
518 Collection
<MediaRepresentation
> mediaRepresentations
= mediaSpecimen
.getMediaSpecimen().getRepresentations();
519 if(mediaRepresentations
!=null && !mediaRepresentations
.isEmpty()){
520 Collection
<MediaRepresentationPart
> mediaRepresentationParts
= mediaRepresentations
.iterator().next().getParts();
521 if(mediaRepresentationParts
!=null && !mediaRepresentationParts
.isEmpty()){
522 MediaRepresentationPart part
= mediaRepresentationParts
.iterator().next();
523 if(part
.getUri()!=null){
524 mediaUri
= part
.getUri().toASCIIString();
531 private void getDerivedUnitsFor(SpecimenOrObservationBase
<?
> specimen
, Collection
<DerivedUnit
> derivedUnits
){
532 for(DerivationEvent derivationEvent
:specimen
.getDerivationEvents()){
533 for(DerivedUnit derivative
:derivationEvent
.getDerivatives()){
534 derivedUnits
.add(derivative
);
535 getDerivedUnitsFor(derivative
, derivedUnits
);
542 * @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)
544 @SuppressWarnings("unchecked")
546 public <T
extends SpecimenOrObservationBase
> Pager
<T
> pageByAssociatedTaxon(Class
<T
> type
, Set
<TaxonRelationshipEdge
> includeRelationships
,
547 Taxon associatedTaxon
, Integer maxDepth
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
549 Set
<Taxon
> taxa
= new HashSet
<Taxon
>();
550 Set
<Integer
> occurrenceIds
= new HashSet
<Integer
>();
551 List
<T
> occurrences
= new ArrayList
<T
>();
553 // Integer limit = PagerUtils.limitFor(pageSize);
554 // Integer start = PagerUtils.startFor(pageSize, pageNumber);
556 if(!getSession().contains(associatedTaxon
)){
557 associatedTaxon
= (Taxon
) taxonService
.load(associatedTaxon
.getUuid());
560 if(includeRelationships
!= null) {
561 taxa
= taxonService
.listRelatedTaxa(associatedTaxon
, includeRelationships
, maxDepth
, null, null, propertyPaths
);
564 taxa
.add(associatedTaxon
);
566 for (Taxon taxon
: taxa
) {
567 List
<T
> perTaxonOccurrences
= dao
.listByAssociatedTaxon(type
, taxon
, null, null, orderHints
, propertyPaths
);
568 for (SpecimenOrObservationBase o
: perTaxonOccurrences
) {
569 occurrenceIds
.add(o
.getId());
572 occurrences
= (List
<T
>) dao
.listByIds(occurrenceIds
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
574 return new DefaultPagerImpl
<T
>(pageNumber
, occurrenceIds
.size(), pageSize
, occurrences
);
579 * @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)
581 @SuppressWarnings("unchecked")
583 public <T
extends SpecimenOrObservationBase
> Pager
<T
> pageByAssociatedTaxon(Class
<T
> type
, Set
<TaxonRelationshipEdge
> includeRelationships
,
584 String taxonUUID
, Integer maxDepth
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
586 UUID uuid
= UUID
.fromString(taxonUUID
);
587 Taxon tax
= (Taxon
) taxonService
.load(uuid
);
588 //TODO REMOVE NULL STATEMENT
590 return pageByAssociatedTaxon( type
,includeRelationships
,tax
, maxDepth
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
596 public Pager
<SearchResult
<SpecimenOrObservationBase
>> findByFullText(
597 Class
<?
extends SpecimenOrObservationBase
> clazz
, String queryString
, Rectangle boundingBox
, List
<Language
> languages
,
598 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
,
599 List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
601 LuceneSearch luceneSearch
= prepareByFullTextSearch(clazz
, queryString
, boundingBox
, languages
, highlightFragments
);
603 // --- execute search
604 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
606 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
607 idFieldMap
.put(CdmBaseType
.SPECIMEN_OR_OBSERVATIONBASE
, "id");
609 // --- initialize taxa, highlight matches ....
610 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
611 @SuppressWarnings("rawtypes")
612 List
<SearchResult
<SpecimenOrObservationBase
>> searchResults
= searchResultBuilder
.createResultSet(
613 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
615 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
617 return new DefaultPagerImpl
<SearchResult
<SpecimenOrObservationBase
>>(pageNumber
, totalHits
, pageSize
,
627 * @param highlightFragments
630 private LuceneSearch
prepareByFullTextSearch(Class
<?
extends SpecimenOrObservationBase
> clazz
, String queryString
, Rectangle bbox
,
631 List
<Language
> languages
, boolean highlightFragments
) {
633 BooleanQuery finalQuery
= new BooleanQuery();
634 BooleanQuery textQuery
= new BooleanQuery();
636 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, FieldUnit
.class);
637 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(FieldUnit
.class);
640 luceneSearch
.setCdmTypRestriction(clazz
);
641 if(queryString
!= null){
642 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
643 finalQuery
.add(textQuery
, Occur
.MUST
);
648 finalQuery
.add(QueryFactory
.buildSpatialQueryByRange(bbox
, "gatheringEvent.exactLocation.point"), Occur
.MUST
);
651 luceneSearch
.setQuery(finalQuery
);
654 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
655 luceneSearch
.setSortFields(sortFields
);
657 if(highlightFragments
){
658 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
665 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getFieldUnits(eu.etaxonomy.cdm.model.occurrence.DerivedUnit)
668 public Collection
<FieldUnit
> getFieldUnits(UUID derivedUnitUuid
) {
669 //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})
670 //from which this DerivedUnit was derived until all FieldUnits are found.
672 //FIXME: use HQL queries to increase performance
673 SpecimenOrObservationBase
<?
> specimen
= load(derivedUnitUuid
);
674 // specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
675 Collection
<FieldUnit
> fieldUnits
= new ArrayList
<FieldUnit
>();
677 if(specimen
instanceof FieldUnit
){
678 fieldUnits
.add((FieldUnit
) specimen
);
680 else if(specimen
instanceof DerivedUnit
){
681 getFieldUnits((DerivedUnit
) specimen
, fieldUnits
);
691 private void getFieldUnits(DerivedUnit derivedUnit
, Collection
<FieldUnit
> fieldUnits
) {
692 Set
<SpecimenOrObservationBase
> originals
= derivedUnit
.getOriginals();
693 if(originals
!=null && !originals
.isEmpty()){
694 for(SpecimenOrObservationBase
<?
> original
:originals
){
695 if(original
instanceof FieldUnit
){
696 fieldUnits
.add((FieldUnit
) original
);
698 else if(original
instanceof DerivedUnit
){
699 getFieldUnits((DerivedUnit
) original
, fieldUnits
);
706 * @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)
709 public boolean moveSequence(DnaSample from
, DnaSample to
, Sequence sequence
) {
710 //reload specimens to avoid session conflicts
711 from
= (DnaSample
) load(from
.getUuid());
712 to
= (DnaSample
) load(to
.getUuid());
713 sequence
= sequenceService
.load(sequence
.getUuid());
715 if(from
==null || to
==null || sequence
==null){
716 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" +
717 "Operation was move "+sequence
+ " from "+from
+" to "+to
);
719 from
.removeSequence(sequence
);
721 to
.addSequence(sequence
);
727 * @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)
730 public boolean moveDerivate(SpecimenOrObservationBase
<?
> from
, SpecimenOrObservationBase
<?
> to
, DerivedUnit derivate
) {
731 //reload specimens to avoid session conflicts
732 from
= load(from
.getUuid());
733 to
= load(to
.getUuid());
734 derivate
= (DerivedUnit
) load(derivate
.getUuid());
736 if(from
==null || to
==null || derivate
==null){
737 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" +
738 "Operation was move "+derivate
+ " from "+from
+" to "+to
);
741 SpecimenOrObservationType derivateType
= derivate
.getRecordBasis();
742 SpecimenOrObservationType toType
= to
.getRecordBasis();
743 //check if type is a sub derivate type
744 if(toType
==SpecimenOrObservationType
.FieldUnit
//moving to FieldUnit always works
745 || derivateType
==SpecimenOrObservationType
.Media
//moving media always works
746 || (derivateType
.isKindOf(toType
) && toType
!=derivateType
)){ //moving only to parent derivate type
747 //remove derivation event from parent specimen of dragged object
748 DerivationEvent eventToRemove
= null;
749 for(DerivationEvent event
:from
.getDerivationEvents()){
750 if(event
.getDerivatives().contains(derivate
)){
751 eventToRemove
= event
;
755 from
.removeDerivationEvent(eventToRemove
);
757 //add new derivation event to target
758 to
.addDerivationEvent(DerivationEvent
.NewSimpleInstance(to
, derivate
, eventToRemove
==null?
null:eventToRemove
.getType()));
766 public Collection
<ICdmBase
> getNonCascadedAssociatedElements(SpecimenOrObservationBase
<?
> specimen
){
767 //potential fields that are not persisted cascadingly
780 --CollectingAreas TERM
788 -storedUnder CDM TaxonNameBase
791 Collection
<ICdmBase
> nonCascadedCdmEntities
= new HashSet
<ICdmBase
>();
793 //Choose the correct entry point to traverse the graph (FieldUnit or DerivedUnit)
796 if(specimen
instanceof FieldUnit
){
797 nonCascadedCdmEntities
.addAll(getFieldUnitNonCascadedAssociatedElements((FieldUnit
)specimen
));
800 else if(specimen
instanceof DerivedUnit
){
801 DerivedUnit derivedUnit
= (DerivedUnit
)specimen
;
802 if(derivedUnit
.getDerivedFrom()!=null){
803 Collection
<FieldUnit
> fieldUnits
= new ArrayList
<FieldUnit
>();
804 getFieldUnits(derivedUnit
, fieldUnits
);
805 for(FieldUnit fieldUnit
:fieldUnits
){
806 nonCascadedCdmEntities
.addAll(getFieldUnitNonCascadedAssociatedElements(fieldUnit
));
810 return nonCascadedCdmEntities
;
813 private Collection
<ICdmBase
> getFieldUnitNonCascadedAssociatedElements(FieldUnit fieldUnit
){
814 //get non cascaded element on SpecimenOrObservationBase level
815 Collection
<ICdmBase
> nonCascadedCdmEntities
= getSpecimenOrObservationNonCascadedAssociatedElements(fieldUnit
);
817 //get FieldUnit specific elements
818 GatheringEvent gatheringEvent
= fieldUnit
.getGatheringEvent();
819 if(gatheringEvent
!=null){
821 if(gatheringEvent
.getCountry()!=null){
822 nonCascadedCdmEntities
.add(gatheringEvent
.getCountry());
825 for (NamedArea namedArea
: gatheringEvent
.getCollectingAreas()) {
826 nonCascadedCdmEntities
.add(namedArea
);
829 for (DerivationEvent derivationEvent
: fieldUnit
.getDerivationEvents()) {
830 for (DerivedUnit derivedUnit
: derivationEvent
.getDerivatives()) {
831 nonCascadedCdmEntities
.addAll(getDerivedUnitNonCascadedAssociatedElements(derivedUnit
));
834 return nonCascadedCdmEntities
;
837 private Collection
<ICdmBase
> getDerivedUnitNonCascadedAssociatedElements(DerivedUnit derivedUnit
){
838 //get non cascaded element on SpecimenOrObservationBase level
839 Collection
<ICdmBase
> nonCascadedCdmEntities
= getSpecimenOrObservationNonCascadedAssociatedElements(derivedUnit
);
841 //get DerivedUnit specific elements
842 if(derivedUnit
.getCollection()!=null && derivedUnit
.getCollection().getInstitute()!=null){
843 for (DefinedTerm type
: derivedUnit
.getCollection().getInstitute().getTypes()) {
844 nonCascadedCdmEntities
.add(type
);
847 if(derivedUnit
.getPreservation()!=null && derivedUnit
.getPreservation().getMedium()!=null){
848 nonCascadedCdmEntities
.add(derivedUnit
.getPreservation().getMedium());
850 if(derivedUnit
.getStoredUnder()!=null){
851 nonCascadedCdmEntities
.add(derivedUnit
.getStoredUnder());
853 return nonCascadedCdmEntities
;
860 private Collection
<ICdmBase
> getSpecimenOrObservationNonCascadedAssociatedElements(
861 SpecimenOrObservationBase
<?
> specimen
) {
862 Collection
<ICdmBase
> nonCascadedCdmEntities
= new HashSet
<ICdmBase
>();
863 //scan SpecimenOrObservationBase
864 for(DeterminationEvent determinationEvent
:specimen
.getDeterminations()){
866 if(determinationEvent
.getModifier()!=null){
867 nonCascadedCdmEntities
.add(determinationEvent
.getModifier());
871 if(specimen
.getKindOfUnit()!=null){
872 nonCascadedCdmEntities
.add(specimen
.getKindOfUnit());
875 if(specimen
.getLifeStage()!=null){
876 nonCascadedCdmEntities
.add(specimen
.getLifeStage());
879 if(specimen
.getSex()!=null){
880 nonCascadedCdmEntities
.add(specimen
.getSex());
882 return nonCascadedCdmEntities
;
886 * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#deleteDerivateHierarchy(eu.etaxonomy.cdm.model.common.ICdmBase)
889 public DeleteResult
deleteDerivateHierarchy(ICdmBase from
) {
890 DeleteResult deleteResult
= new DeleteResult();