-// $Id$\r
-/**\r
- * Copyright (C) 2007 EDIT\r
- * European Distributed Institute of Taxonomy\r
- * http://www.e-taxonomy.eu\r
- *\r
- * The contents of this file are subject to the Mozilla Public License Version 1.1\r
- * See LICENSE.TXT at the top of this package for the full license terms.\r
- */\r
-\r
-package eu.etaxonomy.cdm.api.service;\r
-\r
-import java.io.IOException;\r
-import java.net.URI;\r
-import java.net.URISyntaxException;\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Map.Entry;\r
-import java.util.Set;\r
-import java.util.UUID;\r
-\r
-import org.apache.log4j.Logger;\r
-import org.apache.lucene.index.CorruptIndexException;\r
-import org.apache.lucene.queryParser.ParseException;\r
-import org.apache.lucene.search.BooleanClause.Occur;\r
-import org.apache.lucene.search.BooleanQuery;\r
-import org.apache.lucene.search.SortField;\r
-import org.hibernate.TransientObjectException;\r
-import org.hibernate.search.spatial.impl.Rectangle;\r
-import org.joda.time.Partial;\r
-import org.springframework.beans.factory.annotation.Autowired;\r
-import org.springframework.stereotype.Service;\r
-import org.springframework.transaction.annotation.Transactional;\r
-\r
-import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;\r
-import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeConfigurator;\r
-import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeNotSupportedException;\r
-import eu.etaxonomy.cdm.api.service.dto.DerivateHierarchyDTO;\r
-import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;\r
-import eu.etaxonomy.cdm.api.service.pager.Pager;\r
-import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;\r
-import eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider;\r
-import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;\r
-import eu.etaxonomy.cdm.api.service.search.LuceneSearch;\r
-import eu.etaxonomy.cdm.api.service.search.LuceneSearch.TopGroupsWithMaxScore;\r
-import eu.etaxonomy.cdm.api.service.search.QueryFactory;\r
-import eu.etaxonomy.cdm.api.service.search.SearchResult;\r
-import eu.etaxonomy.cdm.api.service.search.SearchResultBuilder;\r
-import eu.etaxonomy.cdm.api.service.util.TaxonRelationshipEdge;\r
-import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;\r
-import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;\r
-import eu.etaxonomy.cdm.model.CdmBaseType;\r
-import eu.etaxonomy.cdm.model.agent.AgentBase;\r
-import eu.etaxonomy.cdm.model.common.DefinedTerm;\r
-import eu.etaxonomy.cdm.model.common.DefinedTermBase;\r
-import eu.etaxonomy.cdm.model.common.ICdmBase;\r
-import eu.etaxonomy.cdm.model.common.Language;\r
-import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;\r
-import eu.etaxonomy.cdm.model.description.DescriptionBase;\r
-import eu.etaxonomy.cdm.model.description.DescriptionElementBase;\r
-import eu.etaxonomy.cdm.model.description.IndividualsAssociation;\r
-import eu.etaxonomy.cdm.model.location.Country;\r
-import eu.etaxonomy.cdm.model.location.NamedArea;\r
-import eu.etaxonomy.cdm.model.media.Media;\r
-import eu.etaxonomy.cdm.model.media.MediaRepresentation;\r
-import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;\r
-import eu.etaxonomy.cdm.model.molecular.DnaSample;\r
-import eu.etaxonomy.cdm.model.molecular.Sequence;\r
-import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;\r
-import eu.etaxonomy.cdm.model.name.TaxonNameBase;\r
-import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;\r
-import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;\r
-import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;\r
-import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;\r
-import eu.etaxonomy.cdm.model.occurrence.FieldUnit;\r
-import eu.etaxonomy.cdm.model.occurrence.GatheringEvent;\r
-import eu.etaxonomy.cdm.model.occurrence.MediaSpecimen;\r
-import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;\r
-import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;\r
-import eu.etaxonomy.cdm.model.taxon.Taxon;\r
-import eu.etaxonomy.cdm.model.taxon.TaxonBase;\r
-import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;\r
-import eu.etaxonomy.cdm.persistence.dao.initializer.AbstractBeanInitializer;\r
-import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;\r
-import eu.etaxonomy.cdm.persistence.query.OrderHint;\r
-import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;\r
-\r
-/**\r
- * @author a.babadshanjan\r
- * @created 01.09.2008\r
- */\r
-@Service\r
-@Transactional(readOnly = true)\r
-public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObservationBase,IOccurrenceDao> implements IOccurrenceService {\r
-\r
- static private final Logger logger = Logger.getLogger(OccurrenceServiceImpl.class);\r
-\r
- @Autowired\r
- private IDefinedTermDao definedTermDao;\r
-\r
- @Autowired\r
- private IDescriptionService descriptionService;\r
-\r
- @Autowired\r
- private ITaxonService taxonService;\r
-\r
- @Autowired\r
- private ITermService termService;\r
-\r
- @Autowired\r
- private INameService nameService;\r
-\r
- @Autowired\r
- private ISequenceService sequenceService;\r
-\r
- @Autowired\r
- private AbstractBeanInitializer beanInitializer;\r
-\r
- @Autowired\r
- private ILuceneIndexToolProvider luceneIndexToolProvider;\r
-\r
-\r
- public OccurrenceServiceImpl() {\r
- logger.debug("Load OccurrenceService Bean");\r
- }\r
-\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)\r
- */\r
- @Override\r
- @Transactional(readOnly = false)\r
- public void updateTitleCache(Class<? extends SpecimenOrObservationBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<SpecimenOrObservationBase> cacheStrategy, IProgressMonitor monitor) {\r
- if (clazz == null){\r
- clazz = SpecimenOrObservationBase.class;\r
- }\r
- super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);\r
- }\r
-\r
-\r
- /**\r
- * FIXME Candidate for harmonization\r
- * move to termService\r
- */\r
- @Override\r
- public Country getCountryByIso(String iso639) {\r
- return this.definedTermDao.getCountryByIso(iso639);\r
-\r
- }\r
-\r
- /**\r
- * FIXME Candidate for harmonization\r
- * move to termService\r
- */\r
- @Override\r
- public List<Country> getCountryByName(String name) {\r
- List<? extends DefinedTermBase> terms = this.definedTermDao.findByTitle(Country.class, name, null, null, null, null, null, null) ;\r
- List<Country> countries = new ArrayList<Country>();\r
- for (int i=0;i<terms.size();i++){\r
- countries.add((Country)terms.get(i));\r
- }\r
- return countries;\r
- }\r
-\r
- @Override\r
- @Autowired\r
- protected void setDao(IOccurrenceDao dao) {\r
- this.dao = dao;\r
- }\r
-\r
- @Override\r
- public Pager<DerivationEvent> getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber, List<String> propertyPaths) {\r
- Integer numberOfResults = dao.countDerivationEvents(occurence);\r
-\r
- List<DerivationEvent> results = new ArrayList<DerivationEvent>();\r
- if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)\r
- results = dao.getDerivationEvents(occurence, pageSize, pageNumber,propertyPaths);\r
- }\r
-\r
- return new DefaultPagerImpl<DerivationEvent>(pageNumber, numberOfResults, pageSize, results);\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#countDeterminations(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.taxon.TaxonBase)\r
- */\r
- @Override\r
- public int countDeterminations(SpecimenOrObservationBase occurence, TaxonBase taxonbase) {\r
- return dao.countDeterminations(occurence, taxonbase);\r
- }\r
-\r
- @Override\r
- public Pager<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase, Integer pageSize,Integer pageNumber, List<String> propertyPaths) {\r
- Integer numberOfResults = dao.countDeterminations(occurrence, taxonBase);\r
-\r
- List<DeterminationEvent> results = new ArrayList<DeterminationEvent>();\r
- if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)\r
- results = dao.getDeterminations(occurrence,taxonBase, pageSize, pageNumber, propertyPaths);\r
- }\r
-\r
- return new DefaultPagerImpl<DeterminationEvent>(pageNumber, numberOfResults, pageSize, results);\r
- }\r
-\r
- @Override\r
- public Pager<Media> getMedia(SpecimenOrObservationBase occurence,Integer pageSize, Integer pageNumber, List<String> propertyPaths) {\r
- Integer numberOfResults = dao.countMedia(occurence);\r
-\r
- List<Media> results = new ArrayList<Media>();\r
- if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)\r
- results = dao.getMedia(occurence, pageSize, pageNumber, propertyPaths);\r
- }\r
-\r
- return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @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)\r
- */\r
- @Override\r
- public Pager<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> type, TaxonBase determinedAs, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
- Integer numberOfResults = dao.count(type,determinedAs);\r
- List<SpecimenOrObservationBase> results = new ArrayList<SpecimenOrObservationBase>();\r
- pageNumber = pageNumber == null ? 0 : pageNumber;\r
- if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)\r
- Integer start = pageSize == null ? 0 : pageSize * pageNumber;\r
- results = dao.list(type,determinedAs, pageSize, start, orderHints,propertyPaths);\r
- }\r
- return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, numberOfResults, pageSize, results);\r
- }\r
-\r
- @Override\r
- public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache() {\r
- return dao.getDerivedUnitUuidAndTitleCache();\r
- }\r
-\r
- @Override\r
- public List<UuidAndTitleCache<FieldUnit>> getFieldUnitUuidAndTitleCache() {\r
- return dao.getFieldUnitUuidAndTitleCache();\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getDerivedUnitFacade(eu.etaxonomy.cdm.model.occurrence.DerivedUnit)\r
- */\r
- @Override\r
- public DerivedUnitFacade getDerivedUnitFacade(DerivedUnit derivedUnit, List<String> propertyPaths) throws DerivedUnitFacadeNotSupportedException {\r
- derivedUnit = (DerivedUnit)dao.load(derivedUnit.getUuid(), null);\r
- DerivedUnitFacadeConfigurator config = DerivedUnitFacadeConfigurator.NewInstance();\r
- config.setThrowExceptionForNonSpecimenPreservationMethodRequest(false);\r
- DerivedUnitFacade derivedUnitFacade = DerivedUnitFacade.NewInstance(derivedUnit, config);\r
- beanInitializer.initialize(derivedUnitFacade, propertyPaths);\r
- return derivedUnitFacade;\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listDerivedUnitFacades(eu.etaxonomy.cdm.model.description.DescriptionBase, java.util.List)\r
- */\r
- @Override\r
- public List<DerivedUnitFacade> listDerivedUnitFacades(\r
- DescriptionBase description, List<String> propertyPaths) {\r
-\r
- List<DerivedUnitFacade> derivedUnitFacadeList = new ArrayList<DerivedUnitFacade>();\r
- IndividualsAssociation tempIndividualsAssociation;\r
- SpecimenOrObservationBase tempSpecimenOrObservationBase;\r
- List<DescriptionElementBase> elements = descriptionService.listDescriptionElements(description, null, IndividualsAssociation.class, null, 0, Arrays.asList(new String []{"associatedSpecimenOrObservation"}));\r
- for(DescriptionElementBase element : elements){\r
- if(element instanceof IndividualsAssociation){\r
- tempIndividualsAssociation = (IndividualsAssociation)element;\r
- if(tempIndividualsAssociation.getAssociatedSpecimenOrObservation() != null){\r
- tempSpecimenOrObservationBase = HibernateProxyHelper.deproxy(tempIndividualsAssociation.getAssociatedSpecimenOrObservation(), SpecimenOrObservationBase.class);\r
- if(tempSpecimenOrObservationBase instanceof DerivedUnit){\r
- try {\r
- derivedUnitFacadeList.add(DerivedUnitFacade.NewInstance((DerivedUnit)tempSpecimenOrObservationBase));\r
- } catch (DerivedUnitFacadeNotSupportedException e) {\r
- logger.warn(tempIndividualsAssociation.getAssociatedSpecimenOrObservation().getTitleCache() + " : " +e.getMessage());\r
- }\r
- }\r
- }\r
-\r
- }\r
- }\r
-\r
- beanInitializer.initializeAll(derivedUnitFacadeList, propertyPaths);\r
-\r
- return derivedUnitFacadeList;\r
- }\r
-\r
-\r
- /* (non-Javadoc)\r
- * @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)\r
- */\r
- @Override\r
- public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,\r
- Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
-\r
- return pageByAssociatedTaxon(type, includeRelationships, associatedTaxon, maxDepth, pageSize, pageNumber, orderHints, propertyPaths).getRecords();\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @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)\r
- */\r
- @Override\r
- public Collection<FieldUnit> listFieldUnitsByAssociatedTaxon(Set<TaxonRelationshipEdge> includeRelationships,\r
- Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
-\r
- if(!getSession().contains(associatedTaxon)){\r
- associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());\r
- }\r
-\r
- Set<FieldUnit> fieldUnits = new HashSet<FieldUnit>();\r
-\r
- List<SpecimenOrObservationBase> records = pageByAssociatedTaxon(null, includeRelationships, associatedTaxon, maxDepth, pageSize, pageNumber, orderHints, propertyPaths).getRecords();\r
- for(SpecimenOrObservationBase<?> specimen:records){\r
- fieldUnits.addAll(getFieldUnits(specimen.getUuid()));\r
- }\r
- return fieldUnits;\r
- }\r
-\r
- @Override\r
- public DerivateHierarchyDTO assembleDerivateHierarchyDTO(FieldUnit fieldUnit, UUID associatedTaxonUuid){\r
-\r
- if(!getSession().contains(fieldUnit)){\r
- fieldUnit = (FieldUnit) load(fieldUnit.getUuid());\r
- }\r
- TaxonBase associatedTaxon = taxonService.load(associatedTaxonUuid);\r
-\r
- DerivateHierarchyDTO dto = new DerivateHierarchyDTO();\r
- Map<UUID, TypeDesignationStatusBase> typeSpecimenUUIDtoTypeDesignationStatus = new HashMap<UUID, TypeDesignationStatusBase>();\r
-\r
- //gather types for this taxon name\r
- TaxonNameBase<?,?> name = associatedTaxon.getName();\r
- Set<?> typeDesignations = name.getSpecimenTypeDesignations();\r
- for (Object object : typeDesignations) {\r
- if(object instanceof SpecimenTypeDesignation){\r
- SpecimenTypeDesignation specimenTypeDesignation = (SpecimenTypeDesignation)object;\r
- DerivedUnit typeSpecimen = specimenTypeDesignation.getTypeSpecimen();\r
- final TypeDesignationStatusBase typeStatus = specimenTypeDesignation.getTypeStatus();\r
- typeSpecimenUUIDtoTypeDesignationStatus.put(typeSpecimen.getUuid(), typeStatus);\r
- }\r
- }\r
-\r
- if(fieldUnit.getGatheringEvent()!=null){\r
- GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();\r
- //Country\r
- final NamedArea country = gatheringEvent.getCountry();\r
- dto.setCountry(country!=null?country.getDescription():"");\r
- //Collection\r
- final AgentBase collector = gatheringEvent.getCollector();\r
- final String fieldNumber = fieldUnit.getFieldNumber();\r
- dto.setCollection(((collector!=null?collector:"") + " " + (fieldNumber!=null?fieldNumber:"")).trim());\r
- //Date\r
- final Partial gatheringDate = gatheringEvent.getGatheringDate();\r
- dto.setDate(gatheringDate!=null?gatheringDate.toString():"");\r
- }\r
-\r
- //Taxon Name\r
- dto.setTaxonName(associatedTaxon.getName().getFullTitleCache());\r
-\r
-\r
- Collection<DerivedUnit> derivedUnits = new ArrayList<DerivedUnit>();\r
- getDerivedUnitsFor(fieldUnit, derivedUnits);\r
-\r
- //Herbaria map\r
- Map<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> collectionToCountMap = new HashMap<eu.etaxonomy.cdm.model.occurrence.Collection, Integer>();\r
- //List of accession numbers for citation\r
- List<String> preservedSpecimenAccessionNumbers = new ArrayList<String>();\r
-\r
- //iterate over sub derivates\r
- for (DerivedUnit derivedUnit : derivedUnits) {\r
- //current accession number\r
- String currentAccessionNumber = derivedUnit.getAccessionNumber()!=null?derivedUnit.getAccessionNumber():"";\r
- //current herbarium\r
- String currentHerbarium = "";\r
- eu.etaxonomy.cdm.model.occurrence.Collection collection = derivedUnit.getCollection();\r
- if(collection!=null){\r
- currentHerbarium = collection.getCode()!=null?collection.getCode():"";\r
- //count herbaria\r
- Integer count = collectionToCountMap.get(collection);\r
- if(count==null){\r
- count = 1;\r
- }\r
- else{\r
- count++;\r
- }\r
- collectionToCountMap.put(collection, count);\r
- }\r
- //check if derived unit is a type\r
- if(typeSpecimenUUIDtoTypeDesignationStatus.keySet().contains(derivedUnit.getUuid())){\r
- dto.setHasType(true);\r
- TypeDesignationStatusBase typeDesignationStatus = typeSpecimenUUIDtoTypeDesignationStatus.get(derivedUnit.getUuid());\r
- String typeStatus = typeDesignationStatus.getLabel();\r
- dto.addTypes(typeStatus, currentAccessionNumber);\r
- }\r
- //assemble molecular data\r
- if(derivedUnit instanceof DnaSample){\r
- if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.TissueSample){\r
- //TODO implement TissueSample assembly for web service\r
- }\r
- if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.DnaSample){\r
- dto.setHasDna(true);\r
-\r
- DnaSample dna = (DnaSample)derivedUnit;\r
- for(Sequence sequence:dna.getSequences()){\r
- URI boldUri = null;\r
- try {\r
- boldUri = sequence.getBoldUri();\r
- } catch (URISyntaxException e1) {\r
- logger.error("Could not create BOLD URI", e1);\r
- }\r
- final DefinedTerm dnaMarker = sequence.getDnaMarker();\r
- dto.addMolecularData(boldUri!=null?boldUri.toString():"", dnaMarker!=null?dnaMarker.getLabel():"[no marker]");\r
- }\r
- }\r
- }\r
- //assemble media data\r
- else if(derivedUnit instanceof MediaSpecimen){\r
-\r
- MediaSpecimen media = (MediaSpecimen)derivedUnit;\r
- String mediaUriString = getMediaUriString(media);\r
- if(media.getKindOfUnit()!=null){\r
- //specimen scan\r
- if(media.getKindOfUnit().getUuid().equals(UUID.fromString("acda15be-c0e2-4ea8-8783-b9b0c4ad7f03"))){\r
- dto.setHasSpecimenScan(true);\r
- final String imageLinkText = currentHerbarium+" "+currentAccessionNumber;\r
- dto.addSpecimenScan(mediaUriString==null?"":mediaUriString, !imageLinkText.equals(" ")?imageLinkText:"[no accession]");\r
- }\r
- //detail image\r
- else if(media.getKindOfUnit().getUuid().equals(UUID.fromString("31eb8d02-bf5d-437c-bcc6-87a626445f34"))){\r
- dto.setHasDetailImage(true);\r
- String motif = "";\r
- if(media.getMediaSpecimen()!=null && media.getMediaSpecimen().getTitle()!=null){\r
- motif = media.getMediaSpecimen().getTitle().getText();\r
- }\r
- dto.addDetailImage(mediaUriString==null?"":mediaUriString, motif!=null?motif:"[no motif]");\r
- }\r
- }\r
- }\r
- //assemble preserved specimen data\r
- else if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.PreservedSpecimen){\r
- if(!currentAccessionNumber.isEmpty()){\r
- preservedSpecimenAccessionNumbers.add(currentAccessionNumber);\r
- }\r
- }\r
- }\r
-\r
- final String separator = ", ";\r
- //assemble citation\r
- String citation = "";\r
- citation += !dto.getCountry().isEmpty()?dto.getCountry()+separator:"";\r
- if(fieldUnit.getGatheringEvent()!=null){\r
- if(fieldUnit.getGatheringEvent().getLocality()!=null){\r
- citation += fieldUnit.getGatheringEvent().getLocality().getText();\r
- citation += separator;\r
- }\r
- if(fieldUnit.getGatheringEvent().getExactLocation()!=null\r
- && fieldUnit.getGatheringEvent().getExactLocation().getLatitude()!=null\r
- && fieldUnit.getGatheringEvent().getExactLocation().getLongitude()!=null){\r
- citation += fieldUnit.getGatheringEvent().getExactLocation().getLatitude().toString();\r
- citation += separator;\r
- citation += fieldUnit.getGatheringEvent().getExactLocation().getLongitude().toString();\r
- citation += separator;\r
- }\r
- }\r
- citation += !dto.getCollection().isEmpty()?dto.getCollection()+separator:"";\r
- if(!preservedSpecimenAccessionNumbers.isEmpty()){\r
- citation += "(";\r
- for(String accessionNumber:preservedSpecimenAccessionNumbers){\r
- if(!accessionNumber.isEmpty()){\r
- citation += accessionNumber+separator;\r
- }\r
- }\r
- citation = removeTail(citation, separator);\r
- citation += ")";\r
- }\r
- citation = removeTail(citation, separator);\r
- dto.setCitation(citation);\r
-\r
- //assemble herbaria string\r
- String herbariaString = "";\r
- for(Entry<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> e:collectionToCountMap.entrySet()){\r
- eu.etaxonomy.cdm.model.occurrence.Collection collection = e.getKey();\r
- if(collection.getCode()!=null){\r
- herbariaString += collection.getCode();\r
- }\r
- if(e.getValue()>1){\r
- herbariaString += "("+e.getValue()+")";\r
- }\r
- herbariaString += separator;\r
- }\r
- herbariaString = removeTail(herbariaString, separator);\r
- dto.setHerbarium(herbariaString);\r
-\r
- return dto;\r
- }\r
-\r
-\r
- /**\r
- * @param string\r
- * @param tail\r
- * @return\r
- */\r
- private String removeTail(String string, final String tail) {\r
- if(string.endsWith(tail)){\r
- string = string.substring(0, string.length()-tail.length());\r
- }\r
- return string;\r
- }\r
-\r
- private String getMediaUriString(MediaSpecimen mediaSpecimen){\r
- String mediaUri = null;\r
- Collection<MediaRepresentation> mediaRepresentations = mediaSpecimen.getMediaSpecimen().getRepresentations();\r
- if(mediaRepresentations!=null && !mediaRepresentations.isEmpty()){\r
- Collection<MediaRepresentationPart> mediaRepresentationParts = mediaRepresentations.iterator().next().getParts();\r
- if(mediaRepresentationParts!=null && !mediaRepresentationParts.isEmpty()){\r
- MediaRepresentationPart part = mediaRepresentationParts.iterator().next();\r
- if(part.getUri()!=null){\r
- mediaUri = part.getUri().toASCIIString();\r
- }\r
- }\r
- }\r
- return mediaUri;\r
- }\r
-\r
- private void getDerivedUnitsFor(SpecimenOrObservationBase<?> specimen, Collection<DerivedUnit> derivedUnits){\r
- for(DerivationEvent derivationEvent:specimen.getDerivationEvents()){\r
- for(DerivedUnit derivative:derivationEvent.getDerivatives()){\r
- derivedUnits.add(derivative);\r
- getDerivedUnitsFor(derivative, derivedUnits);\r
- }\r
- }\r
- }\r
-\r
-\r
- /* (non-Javadoc)\r
- * @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)\r
- */\r
- @SuppressWarnings("unchecked")\r
- @Override\r
- public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,\r
- Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
-\r
- Set<Taxon> taxa = new HashSet<Taxon>();\r
- Set<Integer> occurrenceIds = new HashSet<Integer>();\r
- List<T> occurrences = new ArrayList<T>();\r
-\r
-// Integer limit = PagerUtils.limitFor(pageSize);\r
-// Integer start = PagerUtils.startFor(pageSize, pageNumber);\r
-\r
- if(!getSession().contains(associatedTaxon)){\r
- associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());\r
- }\r
-\r
- if(includeRelationships != null) {\r
- taxa = taxonService.listRelatedTaxa(associatedTaxon, includeRelationships, maxDepth, null, null, propertyPaths);\r
- }\r
-\r
- taxa.add(associatedTaxon);\r
-\r
- for (Taxon taxon : taxa) {\r
- List<T> perTaxonOccurrences = dao.listByAssociatedTaxon(type, taxon, null, null, orderHints, propertyPaths);\r
- for (SpecimenOrObservationBase o : perTaxonOccurrences) {\r
- occurrenceIds.add(o.getId());\r
- }\r
- }\r
- occurrences = (List<T>) dao.listByIds(occurrenceIds, pageSize, pageNumber, orderHints, propertyPaths);\r
-\r
- return new DefaultPagerImpl<T>(pageNumber, occurrenceIds.size(), pageSize, occurrences);\r
-\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @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)\r
- */\r
- @SuppressWarnings("unchecked")\r
- @Override\r
- public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,\r
- String taxonUUID, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
-\r
- UUID uuid = UUID.fromString(taxonUUID);\r
- Taxon tax = (Taxon) taxonService.load(uuid);\r
- //TODO REMOVE NULL STATEMENT\r
-type=null;\r
- return pageByAssociatedTaxon( type,includeRelationships,tax, maxDepth, pageSize, pageNumber, orderHints, propertyPaths );\r
-\r
- }\r
-\r
-\r
- @Override\r
- public Pager<SearchResult<SpecimenOrObservationBase>> findByFullText(\r
- Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle boundingBox, List<Language> languages,\r
- boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,\r
- List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {\r
-\r
- LuceneSearch luceneSearch = prepareByFullTextSearch(clazz, queryString, boundingBox, languages, highlightFragments);\r
-\r
- // --- execute search\r
- TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);\r
-\r
- Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();\r
- idFieldMap.put(CdmBaseType.SPECIMEN_OR_OBSERVATIONBASE, "id");\r
-\r
- // --- initialize taxa, highlight matches ....\r
- ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());\r
- @SuppressWarnings("rawtypes")\r
- List<SearchResult<SpecimenOrObservationBase>> searchResults = searchResultBuilder.createResultSet(\r
- topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);\r
-\r
- int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupCount : 0;\r
-\r
- return new DefaultPagerImpl<SearchResult<SpecimenOrObservationBase>>(pageNumber, totalHits, pageSize,\r
- searchResults);\r
-\r
- }\r
-\r
-\r
- /**\r
- * @param clazz\r
- * @param queryString\r
- * @param languages\r
- * @param highlightFragments\r
- * @return\r
- */\r
- private LuceneSearch prepareByFullTextSearch(Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle bbox,\r
- List<Language> languages, boolean highlightFragments) {\r
-\r
- BooleanQuery finalQuery = new BooleanQuery();\r
- BooleanQuery textQuery = new BooleanQuery();\r
-\r
- LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, FieldUnit.class);\r
- QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(FieldUnit.class);\r
-\r
- // --- criteria\r
- luceneSearch.setCdmTypRestriction(clazz);\r
- if(queryString != null){\r
- textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
- finalQuery.add(textQuery, Occur.MUST);\r
- }\r
-\r
- // --- spacial query\r
- if(bbox != null){\r
- finalQuery.add(QueryFactory.buildSpatialQueryByRange(bbox, "gatheringEvent.exactLocation.point"), Occur.MUST);\r
- }\r
-\r
- luceneSearch.setQuery(finalQuery);\r
-\r
- // --- sorting\r
- SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};\r
- luceneSearch.setSortFields(sortFields);\r
-\r
- if(highlightFragments){\r
- luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());\r
- }\r
- return luceneSearch;\r
- }\r
-\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getFieldUnits(eu.etaxonomy.cdm.model.occurrence.DerivedUnit)\r
- */\r
- @Override\r
- public Collection<FieldUnit> getFieldUnits(UUID derivedUnitUuid) {\r
- //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})\r
- //from which this DerivedUnit was derived until all FieldUnits are found.\r
-\r
- //FIXME: use HQL queries to increase performance\r
- SpecimenOrObservationBase<?> specimen = load(derivedUnitUuid);\r
-// specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);\r
- Collection<FieldUnit> fieldUnits = new ArrayList<FieldUnit>();\r
-\r
- if(specimen instanceof FieldUnit){\r
- fieldUnits.add((FieldUnit) specimen);\r
- }\r
- else if(specimen instanceof DerivedUnit){\r
- getFieldUnits((DerivedUnit) specimen, fieldUnits);\r
- }\r
- return fieldUnits;\r
- }\r
-\r
-\r
- /**\r
- * @param original\r
- * @param fieldUnits\r
- */\r
- private void getFieldUnits(DerivedUnit derivedUnit, Collection<FieldUnit> fieldUnits) {\r
- Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals();\r
- if(originals!=null && !originals.isEmpty()){\r
- for(SpecimenOrObservationBase<?> original:originals){\r
- if(original instanceof FieldUnit){\r
- fieldUnits.add((FieldUnit) original);\r
- }\r
- else if(original instanceof DerivedUnit){\r
- getFieldUnits((DerivedUnit) original, fieldUnits);\r
- }\r
- }\r
- }\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @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)\r
- */\r
- @Override\r
- public boolean moveSequence(DnaSample from, DnaSample to, Sequence sequence) {\r
- //reload specimens to avoid session conflicts\r
- from = (DnaSample) load(from.getUuid());\r
- to = (DnaSample) load(to.getUuid());\r
- sequence = sequenceService.load(sequence.getUuid());\r
-\r
- if(from==null || to==null || sequence==null){\r
- 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" +\r
- "Operation was move "+sequence+ " from "+from+" to "+to);\r
- }\r
- from.removeSequence(sequence);\r
- saveOrUpdate(from);\r
- to.addSequence(sequence);\r
- saveOrUpdate(to);\r
- return true;\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @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)\r
- */\r
- @Override\r
- public boolean moveDerivate(SpecimenOrObservationBase<?> from, SpecimenOrObservationBase<?> to, DerivedUnit derivate) {\r
- //reload specimens to avoid session conflicts\r
- from = load(from.getUuid());\r
- to = load(to.getUuid());\r
- derivate = (DerivedUnit) load(derivate.getUuid());\r
-\r
- if(from==null || to==null || derivate==null){\r
- 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" +\r
- "Operation was move "+derivate+ " from "+from+" to "+to);\r
- }\r
-\r
- SpecimenOrObservationType derivateType = derivate.getRecordBasis();\r
- SpecimenOrObservationType toType = to.getRecordBasis();\r
- //check if type is a sub derivate type\r
- if(toType==SpecimenOrObservationType.FieldUnit //moving to FieldUnit always works\r
- || derivateType==SpecimenOrObservationType.Media //moving media always works\r
- || (derivateType.isKindOf(toType) && toType!=derivateType)){ //moving only to parent derivate type\r
- //remove derivation event from parent specimen of dragged object\r
- DerivationEvent eventToRemove = null;\r
- for(DerivationEvent event:from.getDerivationEvents()){\r
- if(event.getDerivatives().contains(derivate)){\r
- eventToRemove = event;\r
- break;\r
- }\r
- }\r
- from.removeDerivationEvent(eventToRemove);\r
- saveOrUpdate(from);\r
- //add new derivation event to target\r
- to.addDerivationEvent(DerivationEvent.NewSimpleInstance(to, derivate, eventToRemove==null?null:eventToRemove.getType()));\r
- saveOrUpdate(to);\r
- return true;\r
- }\r
- return false;\r
- }\r
-\r
- @Override\r
- public Collection<ICdmBase> getNonCascadedAssociatedElements(SpecimenOrObservationBase<?> specimen){\r
- //potential fields that are not persisted cascadingly\r
- /*\r
- * SOOB\r
- -DescriptionBase\r
- -determinations\r
- --modifier TERM\r
- -kindOfUnit TERM\r
- -lifeStage TERM\r
- -sex TERM\r
-\r
- FieldUnit\r
- -GatheringEvent\r
- --Country TERM\r
- --CollectingAreas TERM\r
-\r
- DerivedUnit\r
- -collection\r
- --institute\r
- ---types TERM\r
- -preservationMethod\r
- --medium TERM\r
- -storedUnder CDM TaxonNameBase\r
- */\r
-\r
- Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();\r
-\r
- //Choose the correct entry point to traverse the graph (FieldUnit or DerivedUnit)\r
-\r
- //FieldUnit\r
- if(specimen instanceof FieldUnit){\r
- nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements((FieldUnit)specimen));\r
- }\r
- //DerivedUnit\r
- else if(specimen instanceof DerivedUnit){\r
- DerivedUnit derivedUnit = (DerivedUnit)specimen;\r
- if(derivedUnit.getDerivedFrom()!=null){\r
- Collection<FieldUnit> fieldUnits = new ArrayList<FieldUnit>();\r
- getFieldUnits(derivedUnit, fieldUnits);\r
- for(FieldUnit fieldUnit:fieldUnits){\r
- nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(fieldUnit));\r
- }\r
- }\r
- }\r
- return nonCascadedCdmEntities;\r
- }\r
-\r
- private Collection<ICdmBase> getFieldUnitNonCascadedAssociatedElements(FieldUnit fieldUnit){\r
- //get non cascaded element on SpecimenOrObservationBase level\r
- Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(fieldUnit);\r
-\r
- //get FieldUnit specific elements\r
- GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();\r
- if(gatheringEvent!=null){\r
- //country\r
- if(gatheringEvent.getCountry()!=null){\r
- nonCascadedCdmEntities.add(gatheringEvent.getCountry());\r
- }\r
- //collecting areas\r
- for (NamedArea namedArea : gatheringEvent.getCollectingAreas()) {\r
- nonCascadedCdmEntities.add(namedArea);\r
- }\r
- }\r
- for (DerivationEvent derivationEvent : fieldUnit.getDerivationEvents()) {\r
- for (DerivedUnit derivedUnit : derivationEvent.getDerivatives()) {\r
- nonCascadedCdmEntities.addAll(getDerivedUnitNonCascadedAssociatedElements(derivedUnit));\r
- }\r
- }\r
- return nonCascadedCdmEntities;\r
- }\r
-\r
- private Collection<ICdmBase> getDerivedUnitNonCascadedAssociatedElements(DerivedUnit derivedUnit){\r
- //get non cascaded element on SpecimenOrObservationBase level\r
- Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(derivedUnit);\r
-\r
- //get DerivedUnit specific elements\r
- if(derivedUnit.getCollection()!=null && derivedUnit.getCollection().getInstitute()!=null){\r
- for (DefinedTerm type : derivedUnit.getCollection().getInstitute().getTypes()) {\r
- nonCascadedCdmEntities.add(type);\r
- }\r
- }\r
- if(derivedUnit.getPreservation()!=null && derivedUnit.getPreservation().getMedium()!=null){\r
- nonCascadedCdmEntities.add(derivedUnit.getPreservation().getMedium());\r
- }\r
- if(derivedUnit.getStoredUnder()!=null){\r
- nonCascadedCdmEntities.add(derivedUnit.getStoredUnder());\r
- }\r
- return nonCascadedCdmEntities;\r
- }\r
-\r
- /**\r
- * @param specimen\r
- * @return\r
- */\r
- private Collection<ICdmBase> getSpecimenOrObservationNonCascadedAssociatedElements(\r
- SpecimenOrObservationBase<?> specimen) {\r
- Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();\r
- //scan SpecimenOrObservationBase\r
- for(DeterminationEvent determinationEvent:specimen.getDeterminations()){\r
- //modifier\r
- if(determinationEvent.getModifier()!=null){\r
- nonCascadedCdmEntities.add(determinationEvent.getModifier());\r
- }\r
- }\r
- //kindOfUnit\r
- if(specimen.getKindOfUnit()!=null){\r
- nonCascadedCdmEntities.add(specimen.getKindOfUnit());\r
- }\r
- //lifeStage\r
- if(specimen.getLifeStage()!=null){\r
- nonCascadedCdmEntities.add(specimen.getLifeStage());\r
- }\r
- //sex\r
- if(specimen.getSex()!=null){\r
- nonCascadedCdmEntities.add(specimen.getSex());\r
- }\r
- return nonCascadedCdmEntities;\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#deleteDerivateHierarchy(eu.etaxonomy.cdm.model.common.ICdmBase)\r
- */\r
- @Override\r
- public DeleteResult deleteDerivateHierarchy(ICdmBase from) {\r
- DeleteResult deleteResult = new DeleteResult();\r
- return deleteResult;\r
- }\r
-\r
-}\r
+/**
+ * Copyright (C) 2007 EDIT
+ * European Distributed Institute of Taxonomy
+ * http://www.e-taxonomy.eu
+ *
+ * The contents of this file are subject to the Mozilla Public License Version 1.1
+ * See LICENSE.TXT at the top of this package for the full license terms.
+ */
+
+package eu.etaxonomy.cdm.api.service;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.log4j.Logger;
+import org.apache.lucene.queryparser.classic.ParseException;
+import org.apache.lucene.search.BooleanClause.Occur;
+import org.apache.lucene.search.BooleanQuery.Builder;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.grouping.TopGroups;
+import org.apache.lucene.util.BytesRef;
+import org.hibernate.TransientObjectException;
+import org.hibernate.search.spatial.impl.Rectangle;
+import org.joda.time.Partial;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataRetrievalFailureException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
+import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeConfigurator;
+import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeNotSupportedException;
+import eu.etaxonomy.cdm.api.service.UpdateResult.Status;
+import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase;
+import eu.etaxonomy.cdm.api.service.config.FindOccurrencesConfigurator;
+import eu.etaxonomy.cdm.api.service.config.FindOccurrencesConfigurator.AssignmentStatus;
+import eu.etaxonomy.cdm.api.service.config.IIdentifiableEntityServiceConfigurator;
+import eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator;
+import eu.etaxonomy.cdm.api.service.dto.DerivateDTO;
+import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO;
+import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO.ContigFile;
+import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO.Link;
+import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO.MolecularData;
+import eu.etaxonomy.cdm.api.service.dto.FieldUnitDTO;
+import eu.etaxonomy.cdm.api.service.dto.PreservedSpecimenDTO;
+import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
+import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;
+import eu.etaxonomy.cdm.api.service.pager.Pager;
+import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
+import eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider;
+import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;
+import eu.etaxonomy.cdm.api.service.search.LuceneParseException;
+import eu.etaxonomy.cdm.api.service.search.LuceneSearch;
+import eu.etaxonomy.cdm.api.service.search.QueryFactory;
+import eu.etaxonomy.cdm.api.service.search.SearchResult;
+import eu.etaxonomy.cdm.api.service.search.SearchResultBuilder;
+import eu.etaxonomy.cdm.api.service.util.TaxonRelationshipEdge;
+import eu.etaxonomy.cdm.common.CdmUtils;
+import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
+import eu.etaxonomy.cdm.format.CdmFormatterFactory;
+import eu.etaxonomy.cdm.format.ICdmFormatter.FormatKey;
+import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
+import eu.etaxonomy.cdm.model.CdmBaseType;
+import eu.etaxonomy.cdm.model.agent.AgentBase;
+import eu.etaxonomy.cdm.model.common.CdmBase;
+import eu.etaxonomy.cdm.model.common.DefinedTerm;
+import eu.etaxonomy.cdm.model.common.DefinedTermBase;
+import eu.etaxonomy.cdm.model.common.ICdmBase;
+import eu.etaxonomy.cdm.model.common.Language;
+import eu.etaxonomy.cdm.model.description.CategoricalData;
+import eu.etaxonomy.cdm.model.description.DescriptionBase;
+import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
+import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
+import eu.etaxonomy.cdm.model.description.QuantitativeData;
+import eu.etaxonomy.cdm.model.description.SpecimenDescription;
+import eu.etaxonomy.cdm.model.description.TaxonDescription;
+import eu.etaxonomy.cdm.model.location.Country;
+import eu.etaxonomy.cdm.model.location.NamedArea;
+import eu.etaxonomy.cdm.model.media.Media;
+import eu.etaxonomy.cdm.model.media.MediaRepresentation;
+import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
+import eu.etaxonomy.cdm.model.media.MediaUtils;
+import eu.etaxonomy.cdm.model.molecular.AmplificationResult;
+import eu.etaxonomy.cdm.model.molecular.DnaSample;
+import eu.etaxonomy.cdm.model.molecular.Sequence;
+import eu.etaxonomy.cdm.model.molecular.SingleRead;
+import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
+import eu.etaxonomy.cdm.model.name.TaxonName;
+import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;
+import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;
+import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
+import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;
+import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
+import eu.etaxonomy.cdm.model.occurrence.GatheringEvent;
+import eu.etaxonomy.cdm.model.occurrence.MediaSpecimen;
+import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
+import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
+import eu.etaxonomy.cdm.model.taxon.Taxon;
+import eu.etaxonomy.cdm.model.taxon.TaxonBase;
+import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
+import eu.etaxonomy.cdm.persistence.dao.initializer.AbstractBeanInitializer;
+import eu.etaxonomy.cdm.persistence.dao.molecular.ISingleReadDao;
+import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
+import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
+import eu.etaxonomy.cdm.persistence.query.OrderHint;
+import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
+import eu.etaxonomy.cdm.strategy.cache.common.IdentifiableEntityDefaultCacheStrategy;
+
+/**
+ * @author a.babadshanjan
+ * @created 01.09.2008
+ */
+@Service
+@Transactional(readOnly = true)
+public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObservationBase, IOccurrenceDao> implements IOccurrenceService {
+
+ static private final Logger logger = Logger.getLogger(OccurrenceServiceImpl.class);
+
+ @Autowired
+ private IDefinedTermDao definedTermDao;
+
+ @Autowired
+ private IDescriptionService descriptionService;
+
+ @Autowired
+ private INameService nameService;
+
+ @Autowired
+ private IEventBaseService eventService;
+
+ @Autowired
+ private ITaxonService taxonService;
+
+ @Autowired
+ private ISequenceService sequenceService;
+
+ @Autowired
+ private ISingleReadDao singleReadDao;
+
+ @Autowired
+ private AbstractBeanInitializer beanInitializer;
+
+ @Autowired
+ private ILuceneIndexToolProvider luceneIndexToolProvider;
+
+ private static final String SEPARATOR_STRING = ", ";
+
+ public OccurrenceServiceImpl() {
+ logger.debug("Load OccurrenceService Bean");
+ }
+
+
+ @Override
+ @Transactional(readOnly = false)
+ public void updateTitleCache(Class<? extends SpecimenOrObservationBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<SpecimenOrObservationBase> cacheStrategy, IProgressMonitor monitor) {
+ if (clazz == null) {
+ clazz = SpecimenOrObservationBase.class;
+ }
+ super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
+ }
+
+ /**
+ * FIXME Candidate for harmonization
+ * move to termService
+ */
+ @Override
+ public Country getCountryByIso(String iso639) {
+ return this.definedTermDao.getCountryByIso(iso639);
+
+ }
+
+ /**
+ * FIXME Candidate for harmonization
+ * move to termService
+ */
+ @Override
+ public List<Country> getCountryByName(String name) {
+ List<? extends DefinedTermBase> terms = this.definedTermDao.findByTitle(Country.class, name, null, null, null, null, null, null);
+ List<Country> countries = new ArrayList<>();
+ for (int i = 0; i < terms.size(); i++) {
+ countries.add((Country) terms.get(i));
+ }
+ return countries;
+ }
+
+ @Override
+ @Autowired
+ protected void setDao(IOccurrenceDao dao) {
+ this.dao = dao;
+ }
+
+ @Override
+ public Pager<DerivationEvent> getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
+ Integer numberOfResults = dao.countDerivationEvents(occurence);
+
+ List<DerivationEvent> results = new ArrayList<>();
+ if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
+ results = dao.getDerivationEvents(occurence, pageSize, pageNumber, propertyPaths);
+ }
+
+ return new DefaultPagerImpl<DerivationEvent>(pageNumber, numberOfResults, pageSize, results);
+ }
+
+ @Override
+ public int countDeterminations(SpecimenOrObservationBase occurence, TaxonBase taxonbase) {
+ return dao.countDeterminations(occurence, taxonbase);
+ }
+
+ @Override
+ public Pager<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
+ Integer numberOfResults = dao.countDeterminations(occurrence, taxonBase);
+
+ List<DeterminationEvent> results = new ArrayList<>();
+ if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
+ results = dao.getDeterminations(occurrence, taxonBase, pageSize, pageNumber, propertyPaths);
+ }
+
+ return new DefaultPagerImpl<DeterminationEvent>(pageNumber, numberOfResults, pageSize, results);
+ }
+
+ @Override
+ public Pager<Media> getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
+ Integer numberOfResults = dao.countMedia(occurence);
+
+ List<Media> results = new ArrayList<>();
+ if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
+ results = dao.getMedia(occurence, pageSize, pageNumber, propertyPaths);
+ }
+
+ return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);
+ }
+
+ @Override
+ public Pager<Media> getMediainHierarchy(SpecimenOrObservationBase rootOccurence, Integer pageSize,
+ Integer pageNumber, List<String> propertyPaths) {
+ List<Media> media = new ArrayList<>();
+ //media specimens
+ if(rootOccurence.isInstanceOf(MediaSpecimen.class)){
+ MediaSpecimen mediaSpecimen = HibernateProxyHelper.deproxy(rootOccurence, MediaSpecimen.class);
+ media.add(mediaSpecimen.getMediaSpecimen());
+ }
+ // pherograms & gelPhotos
+ if (rootOccurence.isInstanceOf(DnaSample.class)) {
+ DnaSample dnaSample = CdmBase.deproxy(rootOccurence, DnaSample.class);
+ Set<Sequence> sequences = dnaSample.getSequences();
+ //we do show only those gelPhotos which lead to a consensus sequence
+ for (Sequence sequence : sequences) {
+ Set<Media> dnaRelatedMedia = new HashSet<>();
+ for (SingleRead singleRead : sequence.getSingleReads()){
+ AmplificationResult amplification = singleRead.getAmplificationResult();
+ dnaRelatedMedia.add(amplification.getGelPhoto());
+ dnaRelatedMedia.add(singleRead.getPherogram());
+ dnaRelatedMedia.remove(null);
+ }
+ media.addAll(dnaRelatedMedia);
+ }
+ }
+ if(rootOccurence.isInstanceOf(DerivedUnit.class)){
+ DerivedUnit derivedUnit = HibernateProxyHelper.deproxy(rootOccurence, DerivedUnit.class);
+ for (DerivationEvent derivationEvent : derivedUnit.getDerivationEvents()) {
+ for (DerivedUnit childDerivative : derivationEvent.getDerivatives()) {
+ media.addAll(getMediainHierarchy(childDerivative, pageSize, pageNumber, propertyPaths).getRecords());
+ }
+ }
+ }
+ return new DefaultPagerImpl<Media>(pageNumber, media.size(), pageSize, media);
+ }
+
+ @Override
+ public Pager<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> type, TaxonName determinedAs, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
+ Integer numberOfResults = dao.count(type, determinedAs);
+ List<SpecimenOrObservationBase> results = new ArrayList<>();
+ pageNumber = pageNumber == null ? 0 : pageNumber;
+ if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
+ Integer start = pageSize == null ? 0 : pageSize * pageNumber;
+ results = dao.list(type, determinedAs, pageSize, start, orderHints, propertyPaths);
+ }
+ return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, numberOfResults, pageSize, results);
+ }
+
+ @Override
+ public Pager<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> type, TaxonBase determinedAs, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
+ Integer numberOfResults = dao.count(type, determinedAs);
+ List<SpecimenOrObservationBase> results = new ArrayList<>();
+ pageNumber = pageNumber == null ? 0 : pageNumber;
+ if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
+ Integer start = pageSize == null ? 0 : pageSize * pageNumber;
+ results = dao.list(type, determinedAs, pageSize, start, orderHints, propertyPaths);
+ }
+ return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, numberOfResults, pageSize, results);
+ }
+
+ @Override
+ public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache(Integer limit, String pattern) {
+ return dao.getDerivedUnitUuidAndTitleCache(limit, pattern);
+ }
+
+ @Override
+ public List<UuidAndTitleCache<FieldUnit>> getFieldUnitUuidAndTitleCache() {
+ return dao.getFieldUnitUuidAndTitleCache();
+ }
+
+ @Override
+ public DerivedUnitFacade getDerivedUnitFacade(DerivedUnit derivedUnit, List<String> propertyPaths) throws DerivedUnitFacadeNotSupportedException {
+ derivedUnit = (DerivedUnit) dao.load(derivedUnit.getUuid(), null);
+ DerivedUnitFacadeConfigurator config = DerivedUnitFacadeConfigurator.NewInstance();
+ config.setThrowExceptionForNonSpecimenPreservationMethodRequest(false);
+ DerivedUnitFacade derivedUnitFacade = DerivedUnitFacade.NewInstance(derivedUnit, config);
+ beanInitializer.initialize(derivedUnitFacade, propertyPaths);
+ return derivedUnitFacade;
+ }
+
+ @Override
+ public List<DerivedUnitFacade> listDerivedUnitFacades(
+ DescriptionBase description, List<String> propertyPaths) {
+
+ List<DerivedUnitFacade> derivedUnitFacadeList = new ArrayList<>();
+ IndividualsAssociation tempIndividualsAssociation;
+ SpecimenOrObservationBase tempSpecimenOrObservationBase;
+ List<IndividualsAssociation> elements = descriptionService.listDescriptionElements(description, null, IndividualsAssociation.class, null, 0, Arrays.asList(new String []{"associatedSpecimenOrObservation"}));
+ for (IndividualsAssociation element : elements) {
+ tempIndividualsAssociation = HibernateProxyHelper.deproxy(element, IndividualsAssociation.class);
+ if (tempIndividualsAssociation.getAssociatedSpecimenOrObservation() != null) {
+ tempSpecimenOrObservationBase = HibernateProxyHelper.deproxy(tempIndividualsAssociation.getAssociatedSpecimenOrObservation(), SpecimenOrObservationBase.class);
+ if (tempSpecimenOrObservationBase.isInstanceOf(DerivedUnit.class)) {
+ try {
+ derivedUnitFacadeList.add(DerivedUnitFacade.NewInstance(HibernateProxyHelper.deproxy(tempSpecimenOrObservationBase, DerivedUnit.class)));
+ } catch (DerivedUnitFacadeNotSupportedException e) {
+ logger.warn(tempIndividualsAssociation.getAssociatedSpecimenOrObservation().getTitleCache() + " : " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ beanInitializer.initializeAll(derivedUnitFacadeList, propertyPaths);
+
+ return derivedUnitFacadeList;
+ }
+
+
+ @Override
+ public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
+ Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
+
+ return pageByAssociatedTaxon(type, includeRelationships, associatedTaxon, maxDepth, pageSize, pageNumber, orderHints, propertyPaths).getRecords();
+ }
+
+ @Override
+ public Collection<SpecimenOrObservationBase> listFieldUnitsByAssociatedTaxon(Taxon associatedTaxon, List<OrderHint> orderHints, List<String> propertyPaths) {
+ return pageFieldUnitsByAssociatedTaxon(null, associatedTaxon, null, null, null, null, propertyPaths).getRecords();
+ }
+
+ @Override
+ public Pager<SpecimenOrObservationBase> pageFieldUnitsByAssociatedTaxon(Set<TaxonRelationshipEdge> includeRelationships,
+ Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
+ List<String> propertyPaths) {
+
+ if (!getSession().contains(associatedTaxon)) {
+ associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());
+ }
+
+ // gather the IDs of all relevant field units
+ Set<UUID> fieldUnitUuids = new HashSet<>();
+ List<SpecimenOrObservationBase> records = listByAssociatedTaxon(null, includeRelationships, associatedTaxon, maxDepth, null, null, orderHints, propertyPaths);
+ for (SpecimenOrObservationBase<?> specimen : records) {
+ for (FieldUnit fieldUnit : getFieldUnits(specimen.getUuid())) {
+ fieldUnitUuids.add(fieldUnit.getUuid());
+ }
+ }
+ //dao.list() does the paging of the field units. Passing the field units directly to the Pager would not work
+ List<SpecimenOrObservationBase> fieldUnits = dao.list(fieldUnitUuids, pageSize, pageNumber, orderHints, propertyPaths);
+ return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, fieldUnitUuids.size(), pageSize, fieldUnits);
+ }
+
+ @Override
+ public FieldUnitDTO assembleFieldUnitDTO(FieldUnit fieldUnit, UUID associatedTaxonUuid) {
+
+ if (!getSession().contains(fieldUnit)) {
+ fieldUnit = (FieldUnit) load(fieldUnit.getUuid());
+ }
+ TaxonBase associatedTaxon = taxonService.load(associatedTaxonUuid);
+
+ FieldUnitDTO fieldUnitDTO = new FieldUnitDTO();
+
+ if (fieldUnit.getGatheringEvent() != null) {
+ GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();
+ // Country
+ NamedArea country = gatheringEvent.getCountry();
+ fieldUnitDTO.setCountry(country != null ? country.getLabel() : null);
+ // Collection
+ AgentBase collector = gatheringEvent.getCollector();
+ String fieldNumber = fieldUnit.getFieldNumber();
+ String collectionString = "";
+ if (collector != null || fieldNumber != null) {
+ collectionString += collector != null ? collector : "";
+ if (!collectionString.isEmpty()) {
+ collectionString += " ";
+ }
+ collectionString += (fieldNumber != null ? fieldNumber : "");
+ collectionString.trim();
+ }
+ fieldUnitDTO.setCollection(collectionString);
+ // Date
+ Partial gatheringDate = gatheringEvent.getGatheringDate();
+ String dateString = null;
+ if (gatheringDate != null) {
+ dateString = gatheringDate.toString();
+ }
+ else if(gatheringEvent.getTimeperiod()!=null && gatheringEvent.getTimeperiod().getFreeText()!=null){
+ dateString = gatheringEvent.getTimeperiod().getFreeText();
+ }
+ fieldUnitDTO.setDate(dateString);
+ }
+
+ // Taxon Name
+ fieldUnitDTO.setTaxonName(associatedTaxon.getName().getTitleCache());
+
+ // Herbaria map
+ Map<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> collectionToCountMap = new HashMap<>();
+ // List of accession numbers for citation
+ List<String> preservedSpecimenAccessionNumbers = new ArrayList<>();
+
+ // assemble preserved specimen DTOs
+ Set<DerivationEvent> derivationEvents = fieldUnit.getDerivationEvents();
+ for (DerivationEvent derivationEvent : derivationEvents) {
+ Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
+ for (DerivedUnit derivedUnit : derivatives) {
+ if(!derivedUnit.isPublish()){
+ continue;
+ }
+ // collect accession numbers for citation
+ String mostSignificantIdentifier = getMostSignificantIdentifier(derivedUnit);
+ if (mostSignificantIdentifier != null) {
+ preservedSpecimenAccessionNumbers.add(mostSignificantIdentifier);
+ }
+ // collect collections for herbaria column
+ if (derivedUnit.getCollection() != null) {
+ Integer herbariumCount = collectionToCountMap.get(derivedUnit.getCollection());
+ if (herbariumCount == null) {
+ herbariumCount = 0;
+ }
+ collectionToCountMap.put(derivedUnit.getCollection(), herbariumCount + 1);
+ }
+ if (derivedUnit.getRecordBasis().equals(SpecimenOrObservationType.PreservedSpecimen)) {
+ PreservedSpecimenDTO preservedSpecimenDTO = assemblePreservedSpecimenDTO(derivedUnit, fieldUnitDTO);
+ fieldUnitDTO.addPreservedSpecimenDTO(preservedSpecimenDTO);
+ fieldUnitDTO.setHasCharacterData(fieldUnitDTO.isHasCharacterData() || preservedSpecimenDTO.isHasCharacterData());
+ fieldUnitDTO.setHasDetailImage(fieldUnitDTO.isHasDetailImage() || preservedSpecimenDTO.isHasDetailImage());
+ fieldUnitDTO.setHasDna(fieldUnitDTO.isHasDna() || preservedSpecimenDTO.isHasDna());
+ fieldUnitDTO.setHasSpecimenScan(fieldUnitDTO.isHasSpecimenScan() || preservedSpecimenDTO.isHasSpecimenScan());
+ }
+ }
+ }
+ // assemble derivate data DTO
+ assembleDerivateDataDTO(fieldUnitDTO, fieldUnit);
+
+ // assemble citation
+ String citation = fieldUnit.getTitleCache();
+ if((CdmUtils.isBlank(citation) || citation.equals(IdentifiableEntityDefaultCacheStrategy.TITLE_CACHE_GENERATION_NOT_IMPLEMENTED))
+ && !fieldUnit.isProtectedTitleCache()){
+ fieldUnit.setTitleCache(null);
+ citation = fieldUnit.getTitleCache();
+ }
+ if (!preservedSpecimenAccessionNumbers.isEmpty()) {
+ citation += " (";
+ for (String accessionNumber : preservedSpecimenAccessionNumbers) {
+ if (!accessionNumber.isEmpty()) {
+ citation += accessionNumber + SEPARATOR_STRING;
+ }
+ }
+ citation = removeTail(citation, SEPARATOR_STRING);
+ citation += ")";
+ }
+ fieldUnitDTO.setCitation(citation);
+
+ // assemble herbaria string
+ String herbariaString = "";
+ for (Entry<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> e : collectionToCountMap.entrySet()) {
+ eu.etaxonomy.cdm.model.occurrence.Collection collection = e.getKey();
+ if (collection.getCode() != null) {
+ herbariaString += collection.getCode();
+ }
+ if (e.getValue() > 1) {
+ herbariaString += "(" + e.getValue() + ")";
+ }
+ herbariaString += SEPARATOR_STRING;
+ }
+ herbariaString = removeTail(herbariaString, SEPARATOR_STRING);
+ fieldUnitDTO.setHerbarium(herbariaString);
+
+ return fieldUnitDTO;
+ }
+
+ @Override
+ public PreservedSpecimenDTO assemblePreservedSpecimenDTO(DerivedUnit derivedUnit) {
+ return assemblePreservedSpecimenDTO(derivedUnit, null);
+ }
+
+ @Override
+ public String getMostSignificantIdentifier(DerivedUnit derivedUnit) {
+ if (derivedUnit.getAccessionNumber() != null && !derivedUnit.getAccessionNumber().isEmpty()) {
+ return derivedUnit.getAccessionNumber();
+ }
+ else if(derivedUnit.getBarcode()!=null && !derivedUnit.getBarcode().isEmpty()){
+ return derivedUnit.getBarcode();
+ }
+ else if(derivedUnit.getCatalogNumber()!=null && !derivedUnit.getCatalogNumber().isEmpty()){
+ return derivedUnit.getCatalogNumber();
+ }
+ return null;
+ }
+
+ public PreservedSpecimenDTO assemblePreservedSpecimenDTO(DerivedUnit derivedUnit, FieldUnitDTO fieldUnitDTO) {
+ if (!getSession().contains(derivedUnit)) {
+ derivedUnit = (DerivedUnit) load(derivedUnit.getUuid());
+ }
+ PreservedSpecimenDTO preservedSpecimenDTO = new PreservedSpecimenDTO();
+
+ //specimen identifier
+ FormatKey collectionKey = FormatKey.COLLECTION_CODE;
+ String specimenIdentifier = CdmFormatterFactory.format(derivedUnit, collectionKey);
+ if (CdmUtils.isBlank(specimenIdentifier)) {
+ collectionKey = FormatKey.COLLECTION_NAME;
+ }
+ specimenIdentifier = CdmFormatterFactory.format(derivedUnit, new FormatKey[] {
+ collectionKey, FormatKey.SPACE,
+ FormatKey.MOST_SIGNIFICANT_IDENTIFIER, FormatKey.SPACE });
+ if(CdmUtils.isBlank(specimenIdentifier)){
+ specimenIdentifier = derivedUnit.getUuid().toString();
+ }
+ preservedSpecimenDTO.setAccessionNumber(specimenIdentifier);
+ preservedSpecimenDTO.setUuid(derivedUnit.getUuid().toString());
+
+ //preferred stable URI
+ preservedSpecimenDTO.setPreferredStableUri(derivedUnit.getPreferredStableUri());
+
+ // citation
+ Collection<FieldUnit> fieldUnits = getFieldUnits(derivedUnit);
+ if (fieldUnits.size() == 1) {
+ preservedSpecimenDTO.setCitation(fieldUnits.iterator().next().getTitleCache());
+ }
+ else{
+ preservedSpecimenDTO.setCitation("No Citation available. This specimen either has no or multiple field units.");
+ }
+
+ // character state data
+ Collection<DescriptionElementBase> characterDataForSpecimen = getCharacterDataForSpecimen(derivedUnit);
+ if (!characterDataForSpecimen.isEmpty()) {
+ if (fieldUnitDTO != null) {
+ fieldUnitDTO.setHasCharacterData(true);
+ }
+ }
+ for (DescriptionElementBase descriptionElementBase : characterDataForSpecimen) {
+ String character = descriptionElementBase.getFeature().getLabel();
+ ArrayList<Language> languages = new ArrayList<>(Collections.singleton(Language.DEFAULT()));
+ if (descriptionElementBase instanceof QuantitativeData) {
+ QuantitativeData quantitativeData = (QuantitativeData) descriptionElementBase;
+ DefaultQuantitativeDescriptionBuilder builder = new DefaultQuantitativeDescriptionBuilder();
+ String state = builder.build(quantitativeData, languages).getText(Language.DEFAULT());
+ preservedSpecimenDTO.addCharacterData(character, state);
+ }
+ else if(descriptionElementBase instanceof CategoricalData){
+ CategoricalData categoricalData = (CategoricalData) descriptionElementBase;
+ DefaultCategoricalDescriptionBuilder builder = new DefaultCategoricalDescriptionBuilder();
+ String state = builder.build(categoricalData, languages).getText(Language.DEFAULT());
+ preservedSpecimenDTO.addCharacterData(character, state);
+ }
+ }
+ // check type designations
+ Collection<SpecimenTypeDesignation> specimenTypeDesignations = listTypeDesignations(derivedUnit, null, null, null, null);
+ for (SpecimenTypeDesignation specimenTypeDesignation : specimenTypeDesignations) {
+ if (fieldUnitDTO != null) {
+ fieldUnitDTO.setHasType(true);
+ }
+ TypeDesignationStatusBase<?> typeStatus = specimenTypeDesignation.getTypeStatus();
+ if (typeStatus != null) {
+ List<String> typedTaxaNames = new ArrayList<>();
+ String label = typeStatus.getLabel();
+ Set<TaxonName> typifiedNames = specimenTypeDesignation.getTypifiedNames();
+ for (TaxonName taxonName : typifiedNames) {
+ typedTaxaNames.add(taxonName.getFullTitleCache());
+ }
+ preservedSpecimenDTO.addTypes(label, typedTaxaNames);
+ }
+ }
+
+ // individuals associations
+ Collection<IndividualsAssociation> individualsAssociations = listIndividualsAssociations(derivedUnit, null, null, null, null);
+ for (IndividualsAssociation individualsAssociation : individualsAssociations) {
+ if (individualsAssociation.getInDescription() != null) {
+ if (individualsAssociation.getInDescription().isInstanceOf(TaxonDescription.class)) {
+ TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(individualsAssociation.getInDescription(), TaxonDescription.class);
+ Taxon taxon = taxonDescription.getTaxon();
+ if (taxon != null) {
+ preservedSpecimenDTO.addAssociatedTaxon(taxon);
+ }
+ }
+ }
+ }
+ // assemble sub derivates
+ preservedSpecimenDTO.setDerivateDataDTO(assembleDerivateDataDTO(preservedSpecimenDTO, derivedUnit));
+ return preservedSpecimenDTO;
+ }
+
+ private DerivateDataDTO assembleDerivateDataDTO(DerivateDTO derivateDTO, SpecimenOrObservationBase<?> specimenOrObservation) {
+ DerivateDataDTO derivateDataDTO = new DerivateDataDTO();
+ Collection<DerivedUnit> childDerivates = getDerivedUnitsFor(specimenOrObservation);
+ for (DerivedUnit childDerivate : childDerivates) {
+ // assemble molecular data
+ //pattern: DNAMarker [contig1, primer1_1, primer1_2, ...][contig2, primer2_1, ...]...
+ if (childDerivate.isInstanceOf(DnaSample.class)) {
+ if (childDerivate.getRecordBasis() == SpecimenOrObservationType.TissueSample) {
+ // TODO implement TissueSample assembly for web service
+ }
+ if (childDerivate.getRecordBasis() == SpecimenOrObservationType.DnaSample) {
+
+ DnaSample dna = HibernateProxyHelper.deproxy(childDerivate, DnaSample.class);
+ if (!dna.getSequences().isEmpty()) {
+ derivateDTO.setHasDna(true);
+ }
+ for (Sequence sequence : dna.getSequences()) {
+ URI boldUri = null;
+ try {
+ boldUri = sequence.getBoldUri();
+ } catch (URISyntaxException e1) {
+ logger.error("Could not create BOLD URI", e1);
+ }
+ final DefinedTerm dnaMarker = sequence.getDnaMarker();
+ Link providerLink = null;
+ if(boldUri!=null && dnaMarker!=null){
+ providerLink = new DerivateDataDTO.Link(boldUri, dnaMarker.getLabel());
+ }
+ MolecularData molecularData = derivateDataDTO.addProviderLink(providerLink);
+
+ //contig file
+ ContigFile contigFile = null;
+ if (sequence.getContigFile() != null) {
+ MediaRepresentationPart contigMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(sequence.getContigFile());
+ if (contigMediaRepresentationPart != null) {
+ contigFile = molecularData.addContigFile(new Link(contigMediaRepresentationPart.getUri(), "contig"));
+ }
+ }
+ else{
+ contigFile = molecularData.addContigFile(null);
+ }
+ // primer files
+ if (sequence.getSingleReads() != null) {
+ int readCount = 1;
+ for (SingleRead singleRead : sequence.getSingleReads()) {
+ MediaRepresentationPart pherogramMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(singleRead.getPherogram());
+ if (pherogramMediaRepresentationPart != null) {
+ contigFile.addPrimerLink(pherogramMediaRepresentationPart.getUri(), "read"+readCount++);
+ }
+ }
+ }
+ }
+ }
+ }
+ // assemble media data
+ else if (childDerivate.isInstanceOf(MediaSpecimen.class)) {
+ MediaSpecimen media = HibernateProxyHelper.deproxy(childDerivate, MediaSpecimen.class);
+
+ URI mediaUri = getMediaUri(media);
+ if (media.getKindOfUnit() != null) {
+ // specimen scan
+ if (media.getKindOfUnit().getUuid().equals(DefinedTerm.uuidSpecimenScan)) {
+ derivateDataDTO.addSpecimenScanUuid(media.getMediaSpecimen().getUuid());
+ derivateDTO.setHasSpecimenScan(true);
+ String imageLinkText = "scan";
+ if (derivateDTO instanceof PreservedSpecimenDTO && ((PreservedSpecimenDTO) derivateDTO).getAccessionNumber() != null) {
+ imageLinkText = ((PreservedSpecimenDTO) derivateDTO).getAccessionNumber();
+ }
+ derivateDataDTO.addSpecimenScan(mediaUri, imageLinkText);
+ }
+ // detail image
+ else if (media.getKindOfUnit().getUuid().equals(DefinedTerm.uuidDetailImage)) {
+ derivateDataDTO.addDetailImageUuid(media.getMediaSpecimen().getUuid());
+ derivateDTO.setHasDetailImage(true);
+ String motif = "detail image";
+ if (media.getMediaSpecimen()!=null){
+ if(CdmUtils.isNotBlank(media.getMediaSpecimen().getTitleCache())) {
+ motif = media.getMediaSpecimen().getTitleCache();
+ }
+ }
+ derivateDataDTO.addDetailImage(mediaUri, motif);
+ }
+ }
+ }
+ }
+ return derivateDataDTO;
+ }
+
+ private String removeTail(String string, final String tail) {
+ if (string.endsWith(tail)) {
+ string = string.substring(0, string.length() - tail.length());
+ }
+ return string;
+ }
+
+ private URI getMediaUri(MediaSpecimen mediaSpecimen) {
+ URI mediaUri = null;
+ Collection<MediaRepresentation> mediaRepresentations = mediaSpecimen.getMediaSpecimen().getRepresentations();
+ if (mediaRepresentations != null && !mediaRepresentations.isEmpty()) {
+ Collection<MediaRepresentationPart> mediaRepresentationParts = mediaRepresentations.iterator().next().getParts();
+ if (mediaRepresentationParts != null && !mediaRepresentationParts.isEmpty()) {
+ MediaRepresentationPart part = mediaRepresentationParts.iterator().next();
+ if (part.getUri() != null) {
+ mediaUri = part.getUri();
+ }
+ }
+ }
+ return mediaUri;
+ }
+
+ private Collection<DerivedUnit> getDerivedUnitsFor(SpecimenOrObservationBase<?> specimen) {
+ Collection<DerivedUnit> derivedUnits = new ArrayList<>();
+ for (DerivationEvent derivationEvent : specimen.getDerivationEvents()) {
+ for (DerivedUnit derivative : derivationEvent.getDerivatives()) {
+ derivedUnits.add(derivative);
+ derivedUnits.addAll(getDerivedUnitsFor(derivative));
+ }
+ }
+ return derivedUnits;
+ }
+
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
+ Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
+
+ Set<Taxon> taxa = new HashSet<>();
+ Set<Integer> occurrenceIds = new HashSet<>();
+ List<T> occurrences = new ArrayList<>();
+
+ // Integer limit = PagerUtils.limitFor(pageSize);
+ // Integer start = PagerUtils.startFor(pageSize, pageNumber);
+
+ if (!getSession().contains(associatedTaxon)) {
+ associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());
+ }
+
+ if (includeRelationships != null) {
+ taxa = taxonService.listRelatedTaxa(associatedTaxon, includeRelationships, maxDepth, null, null, propertyPaths);
+ }
+
+ taxa.add(associatedTaxon);
+
+ for (Taxon taxon : taxa) {
+ List<T> perTaxonOccurrences = dao.listByAssociatedTaxon(type, taxon, null, null, orderHints, propertyPaths);
+ for (SpecimenOrObservationBase o : perTaxonOccurrences) {
+ occurrenceIds.add(o.getId());
+ }
+ }
+ occurrences = (List<T>) dao.loadList(occurrenceIds, propertyPaths);
+
+ return new DefaultPagerImpl<T>(pageNumber, occurrenceIds.size(), pageSize, occurrences);
+
+ }
+
+ @Override
+ public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
+ String taxonUUID, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
+
+ UUID uuid = UUID.fromString(taxonUUID);
+ Taxon tax = (Taxon) taxonService.load(uuid);
+ // TODO REMOVE NULL STATEMENT
+ type = null;
+ return pageByAssociatedTaxon(type, includeRelationships, tax, maxDepth, pageSize, pageNumber, orderHints, propertyPaths);
+
+ }
+
+ @Override
+ public Pager<SearchResult<SpecimenOrObservationBase>> findByFullText(
+ Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle boundingBox, List<Language> languages,
+ boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
+ List<String> propertyPaths) throws IOException, LuceneParseException {
+
+ LuceneSearch luceneSearch = prepareByFullTextSearch(clazz, queryString, boundingBox, languages, highlightFragments);
+
+ // --- execute search
+ TopGroups<BytesRef> topDocsResultSet;
+ try {
+ topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);
+ } catch (ParseException e) {
+ LuceneParseException parseException = new LuceneParseException(e.getMessage());
+ parseException.setStackTrace(e.getStackTrace());
+ throw parseException;
+ }
+
+ Map<CdmBaseType, String> idFieldMap = new HashMap<>();
+ idFieldMap.put(CdmBaseType.SPECIMEN_OR_OBSERVATIONBASE, "id");
+
+ // --- initialize taxa, highlight matches ....
+ ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
+ @SuppressWarnings("rawtypes")
+ List<SearchResult<SpecimenOrObservationBase>> searchResults = searchResultBuilder.createResultSet(
+ topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);
+
+ int totalHits = topDocsResultSet != null ? topDocsResultSet.totalGroupCount : 0;
+
+ return new DefaultPagerImpl<SearchResult<SpecimenOrObservationBase>>(pageNumber, totalHits, pageSize,
+ searchResults);
+
+ }
+
+ private LuceneSearch prepareByFullTextSearch(Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle bbox,
+ List<Language> languages, boolean highlightFragments) {
+
+ Builder finalQueryBuilder = new Builder();
+ Builder textQueryBuilder = new Builder();
+
+ LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, FieldUnit.class);
+ QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(FieldUnit.class);
+
+ // --- criteria
+ luceneSearch.setCdmTypRestriction(clazz);
+ if (queryString != null) {
+ textQueryBuilder.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);
+ finalQueryBuilder.add(textQueryBuilder.build(), Occur.MUST);
+ }
+
+ // --- spacial query
+ if (bbox != null) {
+ finalQueryBuilder.add(QueryFactory.buildSpatialQueryByRange(bbox, "gatheringEvent.exactLocation.point"), Occur.MUST);
+ }
+
+ luceneSearch.setQuery(finalQueryBuilder.build());
+
+ // --- sorting
+ SortField[] sortFields = new SortField[] { SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.Type.STRING, false) };
+ luceneSearch.setSortFields(sortFields);
+
+ if (highlightFragments) {
+ luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
+ }
+ return luceneSearch;
+ }
+
+
+ @Override
+ public Collection<FieldUnit> getFieldUnits(UUID derivedUnitUuid) {
+ //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})
+ //from which this DerivedUnit was derived until all FieldUnits are found.
+
+ // FIXME: use HQL queries to increase performance
+ SpecimenOrObservationBase<?> specimen = load(derivedUnitUuid);
+// specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
+ Collection<FieldUnit> fieldUnits = new ArrayList<>();
+
+ if (specimen.isInstanceOf(FieldUnit.class)) {
+ fieldUnits.add(HibernateProxyHelper.deproxy(specimen, FieldUnit.class));
+ }
+ else if(specimen.isInstanceOf(DerivedUnit.class)){
+ fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class)));
+ }
+ return fieldUnits;
+ }
+
+ private Collection<FieldUnit> getFieldUnits(DerivedUnit derivedUnit) {
+ Collection<FieldUnit> fieldUnits = new HashSet<>();
+ Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals();
+ if (originals != null && !originals.isEmpty()) {
+ for (SpecimenOrObservationBase<?> original : originals) {
+ if (original.isInstanceOf(FieldUnit.class)) {
+ fieldUnits.add(HibernateProxyHelper.deproxy(original, FieldUnit.class));
+ }
+ else if(original.isInstanceOf(DerivedUnit.class)){
+ fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(original, DerivedUnit.class)));
+ }
+ }
+ }
+ return fieldUnits;
+ }
+
+ @Override
+ @Transactional(readOnly = false)
+ public UpdateResult moveSequence(DnaSample from, DnaSample to, Sequence sequence) {
+ return moveSequence(from.getUuid(), to.getUuid(), sequence.getUuid());
+ }
+
+ @Override
+ @Transactional(readOnly = false)
+ public UpdateResult moveSequence(UUID fromUuid, UUID toUuid, UUID sequenceUuid) {
+ // reload specimens to avoid session conflicts
+ DnaSample from = (DnaSample) load(fromUuid);
+ DnaSample to = (DnaSample) load(toUuid);
+ Sequence sequence = sequenceService.load(sequenceUuid);
+
+ if (from == null || to == null || sequence == null) {
+ 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" +
+ "Operation was move "+sequence+ " from "+from+" to "+to);
+ }
+ UpdateResult result = new UpdateResult();
+ from.removeSequence(sequence);
+ saveOrUpdate(from);
+ to.addSequence(sequence);
+ saveOrUpdate(to);
+ result.setStatus(Status.OK);
+ result.addUpdatedObject(from);
+ result.addUpdatedObject(to);
+ return result;
+ }
+
+ @Override
+ @Transactional(readOnly = false)
+ public boolean moveDerivate(SpecimenOrObservationBase<?> from, SpecimenOrObservationBase<?> to, DerivedUnit derivate) {
+ return moveDerivate(from!=null?from.getUuid():null, to.getUuid(), derivate.getUuid()).isOk();
+ }
+
+ @Override
+ @Transactional(readOnly = false)
+ public UpdateResult moveDerivate(UUID specimenFromUuid, UUID specimenToUuid, UUID derivateUuid) {
+ // reload specimens to avoid session conflicts
+ SpecimenOrObservationBase<?> from = null;
+ if(specimenFromUuid!=null){
+ from = load(specimenFromUuid);
+ }
+ SpecimenOrObservationBase<?> to = load(specimenToUuid);
+ DerivedUnit derivate = (DerivedUnit) load(derivateUuid);
+
+ if ((specimenFromUuid!=null && from == null) || to == null || derivate == null) {
+ 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" +
+ "Operation was move "+derivate+ " from "+from+" to "+to);
+ }
+ UpdateResult result = new UpdateResult();
+ SpecimenOrObservationType derivateType = derivate.getRecordBasis();
+ SpecimenOrObservationType toType = to.getRecordBasis();
+ // check if type is a sub derivate type
+ if(toType==SpecimenOrObservationType.FieldUnit //moving to FieldUnit always works
+ || derivateType==SpecimenOrObservationType.Media //moving media always works
+ || (derivateType.isKindOf(toType) && toType!=derivateType)){ //moving only to parent derivate type
+ if(from!=null){
+ // remove derivation event from parent specimen of dragged object
+ DerivationEvent eventToRemove = null;
+ for (DerivationEvent event : from.getDerivationEvents()) {
+ if (event.getDerivatives().contains(derivate)) {
+ eventToRemove = event;
+ break;
+ }
+ }
+ from.removeDerivationEvent(eventToRemove);
+ if(eventToRemove!=null){
+ // add new derivation event to target and copy the event parameters of the old one
+ DerivationEvent derivedFromNewOriginalEvent = DerivationEvent.NewSimpleInstance(to, derivate, null);
+ derivedFromNewOriginalEvent.setActor(eventToRemove.getActor());
+ derivedFromNewOriginalEvent.setDescription(eventToRemove.getDescription());
+ derivedFromNewOriginalEvent.setInstitution(eventToRemove.getInstitution());
+ derivedFromNewOriginalEvent.setTimeperiod(eventToRemove.getTimeperiod());
+ derivedFromNewOriginalEvent.setType(eventToRemove.getType());
+ to.addDerivationEvent(derivedFromNewOriginalEvent);
+ derivate.setDerivedFrom(derivedFromNewOriginalEvent);
+ }
+ }
+ else{
+ //derivative had no parent before so we use empty derivation event
+ DerivationEvent derivedFromNewOriginalEvent = DerivationEvent.NewSimpleInstance(to, derivate, null);
+ to.addDerivationEvent(derivedFromNewOriginalEvent);
+ derivate.setDerivedFrom(derivedFromNewOriginalEvent);
+ }
+
+ if(from!=null){
+ saveOrUpdate(from);
+ }
+ saveOrUpdate(to);
+ result.setStatus(Status.OK);
+ result.addUpdatedObject(from);
+ result.addUpdatedObject(to);
+ } else {
+ result.setStatus(Status.ERROR);
+ }
+ return result;
+ }
+
+ @Override
+ public Collection<ICdmBase> getNonCascadedAssociatedElements(SpecimenOrObservationBase<?> specimen) {
+ // potential fields that are not persisted cascadingly
+ /*
+ * SOOB
+ -DescriptionBase
+ -determinations
+ --modifier TERM
+ -kindOfUnit TERM
+ -lifeStage TERM
+ -sex TERM
+
+ FieldUnit
+ -GatheringEvent
+ --Country TERM
+ --CollectingAreas TERM
+
+ DerivedUnit
+ -collection
+ --institute
+ ---types TERM
+ -preservationMethod
+ --medium TERM
+ -storedUnder CDM TaxonName
+ */
+
+ Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<>();
+
+ //Choose the correct entry point to traverse the graph (FieldUnit or DerivedUnit)
+
+ // FieldUnit
+ if (specimen.isInstanceOf(FieldUnit.class)) {
+ nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(HibernateProxyHelper.deproxy(specimen, FieldUnit.class)));
+ }
+ // DerivedUnit
+ else if (specimen.isInstanceOf(DerivedUnit.class)) {
+ DerivedUnit derivedUnit = HibernateProxyHelper.deproxy(specimen, DerivedUnit.class);
+ if (derivedUnit.getDerivedFrom() != null) {
+ Collection<FieldUnit> fieldUnits = getFieldUnits(derivedUnit);
+ for (FieldUnit fieldUnit : fieldUnits) {
+ nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(fieldUnit));
+ }
+ }
+ }
+ return nonCascadedCdmEntities;
+ }
+
+ private Collection<ICdmBase> getFieldUnitNonCascadedAssociatedElements(FieldUnit fieldUnit) {
+ // get non cascaded element on SpecimenOrObservationBase level
+ Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(fieldUnit);
+
+ // get FieldUnit specific elements
+ GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();
+ if (gatheringEvent != null) {
+ // country
+ if (gatheringEvent.getCountry() != null) {
+ nonCascadedCdmEntities.add(gatheringEvent.getCountry());
+ }
+ // collecting areas
+ for (NamedArea namedArea : gatheringEvent.getCollectingAreas()) {
+ nonCascadedCdmEntities.add(namedArea);
+ }
+ }
+ for (DerivationEvent derivationEvent : fieldUnit.getDerivationEvents()) {
+ for (DerivedUnit derivedUnit : derivationEvent.getDerivatives()) {
+ nonCascadedCdmEntities.addAll(getDerivedUnitNonCascadedAssociatedElements(derivedUnit));
+ }
+ }
+ return nonCascadedCdmEntities;
+ }
+
+ private Collection<ICdmBase> getDerivedUnitNonCascadedAssociatedElements(DerivedUnit derivedUnit) {
+ // get non cascaded element on SpecimenOrObservationBase level
+ Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(derivedUnit);
+
+ // get DerivedUnit specific elements
+ if (derivedUnit.getCollection() != null && derivedUnit.getCollection().getInstitute() != null) {
+ for (DefinedTerm type : derivedUnit.getCollection().getInstitute().getTypes()) {
+ nonCascadedCdmEntities.add(type);
+ }
+ }
+ if (derivedUnit.getPreservation() != null && derivedUnit.getPreservation().getMedium() != null) {
+ nonCascadedCdmEntities.add(derivedUnit.getPreservation().getMedium());
+ }
+ if (derivedUnit.getStoredUnder() != null) {
+ nonCascadedCdmEntities.add(derivedUnit.getStoredUnder());
+ }
+ return nonCascadedCdmEntities;
+ }
+
+ private Collection<ICdmBase> getSpecimenOrObservationNonCascadedAssociatedElements(
+ SpecimenOrObservationBase<?> specimen) {
+ Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<>();
+ // scan SpecimenOrObservationBase
+ for (DeterminationEvent determinationEvent : specimen.getDeterminations()) {
+ // modifier
+ if (determinationEvent.getModifier() != null) {
+ nonCascadedCdmEntities.add(determinationEvent.getModifier());
+ }
+ }
+ // kindOfUnit
+ if (specimen.getKindOfUnit() != null) {
+ nonCascadedCdmEntities.add(specimen.getKindOfUnit());
+ }
+ // lifeStage
+ if (specimen.getLifeStage() != null) {
+ nonCascadedCdmEntities.add(specimen.getLifeStage());
+ }
+ // sex
+ if (specimen.getSex() != null) {
+ nonCascadedCdmEntities.add(specimen.getSex());
+ }
+ return nonCascadedCdmEntities;
+ }
+
+ @Override
+ public DeleteResult isDeletable(UUID specimenUuid, DeleteConfiguratorBase config) {
+ DeleteResult deleteResult = new DeleteResult();
+ SpecimenOrObservationBase specimen = this.load(specimenUuid);
+ SpecimenDeleteConfigurator specimenDeleteConfigurator = (SpecimenDeleteConfigurator) config;
+
+ // check elements found by super method
+ Set<CdmBase> relatedObjects = super.isDeletable(specimenUuid, config).getRelatedObjects();
+ for (CdmBase cdmBase : relatedObjects) {
+ // check for type designation
+ if (cdmBase.isInstanceOf(SpecimenTypeDesignation.class) && !specimenDeleteConfigurator.isDeleteFromTypeDesignation()) {
+ deleteResult.setAbort();
+ deleteResult.addException(new ReferencedObjectUndeletableException("Specimen or obeservation is a type specimen."));
+ deleteResult.addRelatedObject(cdmBase);
+ break;
+ }
+ // check for IndividualsAssociations
+ else if (cdmBase.isInstanceOf(IndividualsAssociation.class) && !specimenDeleteConfigurator.isDeleteFromIndividualsAssociation()) {
+ deleteResult.setAbort();
+ deleteResult.addException(new ReferencedObjectUndeletableException("Specimen or obeservation is still associated via IndividualsAssociations"));
+ deleteResult.addRelatedObject(cdmBase);
+ break;
+ }
+ // check for taxon description
+ else if(cdmBase.isInstanceOf(TaxonDescription.class)
+ && HibernateProxyHelper.deproxy(cdmBase, TaxonDescription.class).getDescribedSpecimenOrObservation().equals(specimen)
+ && !specimenDeleteConfigurator.isDeleteFromDescription()){
+ deleteResult.setAbort();
+ deleteResult.addException(new ReferencedObjectUndeletableException("Specimen or obeservation is still used as \"Described Specimen\" in a taxon description."));
+ deleteResult.addRelatedObject(cdmBase);
+ break;
+ }
+ // check for children and parents (derivation events)
+ else if (cdmBase.isInstanceOf(DerivationEvent.class)) {
+ DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(cdmBase, DerivationEvent.class);
+ // check if derivation event is empty
+ if (!derivationEvent.getDerivatives().isEmpty() && derivationEvent.getOriginals().contains(specimen)) {
+ // if derivationEvent is the childEvent and contains derivations
+// if (derivationEvent.getDerivatives().contains(specimen)) {
+// //if it is the parent event the specimen is still deletable
+// continue;
+// }
+ if(!specimenDeleteConfigurator.isDeleteChildren()){
+ //if children should not be deleted then it is undeletable
+ deleteResult.setAbort();
+ deleteResult.addException(new ReferencedObjectUndeletableException("Specimen or obeservation still has child derivatives."));
+ deleteResult.addRelatedObject(cdmBase);
+ break;
+ }
+ else{
+ // check all children if they can be deleted
+ Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
+ DeleteResult childResult = new DeleteResult();
+ for (DerivedUnit derivedUnit : derivatives) {
+ childResult.includeResult(isDeletable(derivedUnit.getUuid(), specimenDeleteConfigurator));
+ }
+ if (!childResult.isOk()) {
+ deleteResult.setAbort();
+ deleteResult.includeResult(childResult);
+ deleteResult.addRelatedObject(cdmBase);
+ break;
+ }
+ }
+ }
+ }
+ // check for amplification
+ else if (cdmBase.isInstanceOf(AmplificationResult.class)
+ && !specimenDeleteConfigurator.isDeleteMolecularData()
+ && !specimenDeleteConfigurator.isDeleteChildren()) {
+ deleteResult.setAbort();
+ deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in amplification results."));
+ deleteResult.addRelatedObject(cdmBase);
+ break;
+ }
+ // check for sequence
+ else if (cdmBase.isInstanceOf(Sequence.class)
+ && !specimenDeleteConfigurator.isDeleteMolecularData()
+ && !specimenDeleteConfigurator.isDeleteChildren()) {
+ deleteResult.setAbort();
+ deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in sequences."));
+ deleteResult.addRelatedObject(cdmBase);
+ break;
+ }
+ }
+ if (deleteResult.isOk()) {
+ //add all related object if deletion is OK so they can be handled by the delete() method
+ deleteResult.addRelatedObjects(relatedObjects);
+ }
+ return deleteResult;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Transactional(readOnly = false)
+ @Override
+ public DeleteResult delete(UUID specimenUuid, SpecimenDeleteConfigurator config) {
+ return delete(load(specimenUuid), config);
+ }
+
+
+ @Transactional(readOnly = false)
+ @Override
+ public DeleteResult delete(SpecimenOrObservationBase<?> specimen, SpecimenDeleteConfigurator config) {
+ specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
+
+ DeleteResult deleteResult = isDeletable(specimen.getUuid(), config);
+ if (!deleteResult.isOk()) {
+ return deleteResult;
+ }
+
+ if (config.isDeleteChildren()) {
+ Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();
+ //clone to avoid concurrent modification
+ //can happen if the child is deleted and deleted its own derivedFrom event
+ Set<DerivationEvent> derivationEventsClone = new HashSet<>(derivationEvents);
+ for (DerivationEvent derivationEvent : derivationEventsClone) {
+ Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
+ Iterator<DerivedUnit> it = derivatives.iterator();
+ Set<DerivedUnit> derivativesToDelete = new HashSet<>();
+ while (it.hasNext()) {
+ DerivedUnit unit = it.next();
+ derivativesToDelete.add(unit);
+ }
+ for (DerivedUnit unit:derivativesToDelete){
+ deleteResult.includeResult(delete(unit, config));
+ }
+ }
+ }
+
+
+
+
+ // check related objects
+ Set<CdmBase> relatedObjects = deleteResult.getRelatedObjects();
+
+ for (CdmBase relatedObject : relatedObjects) {
+ // check for TypeDesignations
+ if (relatedObject.isInstanceOf(SpecimenTypeDesignation.class)) {
+ SpecimenTypeDesignation designation = HibernateProxyHelper.deproxy(relatedObject, SpecimenTypeDesignation.class);
+ designation.setTypeSpecimen(null);
+ List<TaxonName> typifiedNames = new ArrayList<>();
+ typifiedNames.addAll(designation.getTypifiedNames());
+ for (TaxonName taxonName : typifiedNames) {
+ taxonName.removeTypeDesignation(designation);
+ }
+ }
+ // delete IndividualsAssociation
+ if (relatedObject.isInstanceOf(IndividualsAssociation.class)) {
+ IndividualsAssociation association = HibernateProxyHelper.deproxy(relatedObject, IndividualsAssociation.class);
+ association.setAssociatedSpecimenOrObservation(null);
+ association.getInDescription().removeElement(association);
+ }
+ // check for "described specimen" (deprecated)
+ if (relatedObject.isInstanceOf(TaxonDescription.class)) {
+ TaxonDescription description = HibernateProxyHelper.deproxy(relatedObject, TaxonDescription.class);
+ description.setDescribedSpecimenOrObservation(null);
+ }
+ // check for specimen description
+ if (relatedObject.isInstanceOf(SpecimenDescription.class)) {
+ SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(relatedObject, SpecimenDescription.class);
+ specimenDescription.setDescribedSpecimenOrObservation(null);
+ // check if description is a description of the given specimen
+ if (specimen.getDescriptions().contains(specimenDescription)) {
+ specimen.removeDescription(specimenDescription);
+ }
+ DeleteResult descriptionDelete = descriptionService.isDeletable(specimenDescription.getUuid(), null);
+ if (descriptionDelete.isOk()){
+ descriptionService.delete(specimenDescription);
+ }
+ }
+ // check for amplification
+ if (relatedObject.isInstanceOf(AmplificationResult.class)) {
+ AmplificationResult amplificationResult = HibernateProxyHelper.deproxy(relatedObject, AmplificationResult.class);
+ amplificationResult.getDnaSample().removeAmplificationResult(amplificationResult);
+ }
+ // check for sequence
+ if (relatedObject.isInstanceOf(Sequence.class)) {
+ Sequence sequence = HibernateProxyHelper.deproxy(relatedObject, Sequence.class);
+ sequence.getDnaSample().removeSequence(sequence);
+ }
+ // check for children and parents (derivation events)
+ if (relatedObject.isInstanceOf(DerivationEvent.class)) {
+ DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(relatedObject, DerivationEvent.class);
+ // parent derivation event (derivedFrom)
+ if (derivationEvent.getDerivatives().contains(specimen) && specimen.isInstanceOf(DerivedUnit.class)) {
+ derivationEvent.removeDerivative(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class));
+ if (derivationEvent.getDerivatives().isEmpty()) {
+ Set<SpecimenOrObservationBase> originals = derivationEvent.getOriginals();
+ for (SpecimenOrObservationBase specimenOrObservationBase : originals) {
+ specimenOrObservationBase.removeDerivationEvent(derivationEvent);
+ deleteResult.addUpdatedObject(specimenOrObservationBase);
+ }
+ // if derivationEvent has no derivates anymore, delete it
+ eventService.delete(derivationEvent);
+ }
+ }
+ else{
+ //child derivation events should not occur since we delete the hierarchy from bottom to top
+ }
+ }
+ }
+ if (specimen instanceof FieldUnit){
+ FieldUnit fieldUnit = HibernateProxyHelper.deproxy(specimen, FieldUnit.class);
+ GatheringEvent event = fieldUnit.getGatheringEvent();
+ fieldUnit.setGatheringEvent(null);
+ if (event != null){
+ DeleteResult result = eventService.isDeletable(event.getUuid(), null);
+ if (result.isOk()){
+ eventService.delete(event);
+ }
+ }
+
+ }
+ deleteResult.includeResult(delete(specimen));
+
+ return deleteResult;
+ }
+
+ @Override
+ public Collection<IndividualsAssociation> listIndividualsAssociations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
+ return dao.listIndividualsAssociations(specimen, null, null, null, null);
+ }
+
+ @Override
+ public Collection<TaxonBase<?>> listAssociatedTaxa(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start,
+ List<OrderHint> orderHints, List<String> propertyPaths) {
+ Collection<TaxonBase<?>> associatedTaxa = new HashSet<>();
+
+ //individuals associations
+ associatedTaxa.addAll(listIndividualsAssociationTaxa(specimen, limit, start, orderHints, propertyPaths));
+ //type designation
+ if(specimen.isInstanceOf(DerivedUnit.class)){
+ associatedTaxa.addAll(listTypeDesignationTaxa(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class), limit, start, orderHints, propertyPaths));
+ }
+ //determinations
+ associatedTaxa.addAll(listDeterminedTaxa(specimen, limit, start, orderHints, propertyPaths));
+
+ return associatedTaxa;
+ }
+
+
+ @Override
+ public Collection<TaxonBase<?>> listDeterminedTaxa(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start,
+ List<OrderHint> orderHints, List<String> propertyPaths) {
+ Collection<TaxonBase<?>> associatedTaxa = new HashSet<>();
+ for (DeterminationEvent determinationEvent : listDeterminationEvents(specimen, limit, start, orderHints, propertyPaths)) {
+ if(determinationEvent.getIdentifiedUnit().equals(specimen)){
+ if(determinationEvent.getTaxon()!=null){
+ associatedTaxa.add(determinationEvent.getTaxon());
+ }
+ if(determinationEvent.getTaxonName()!=null){
+ associatedTaxa.addAll((Collection)determinationEvent.getTaxonName().getTaxonBases());
+ }
+ }
+ }
+ return associatedTaxa;
+ }
+
+ @Override
+ public Collection<TaxonBase<?>> listTypeDesignationTaxa(DerivedUnit specimen, Integer limit, Integer start,
+ List<OrderHint> orderHints, List<String> propertyPaths) {
+ Collection<TaxonBase<?>> associatedTaxa = new HashSet<>();
+ for (SpecimenTypeDesignation typeDesignation : listTypeDesignations(specimen, limit, start, orderHints, propertyPaths)) {
+ if(typeDesignation.getTypeSpecimen().equals(specimen)){
+ Set<TaxonName> typifiedNames = typeDesignation.getTypifiedNames();
+ for (TaxonName taxonName : typifiedNames) {
+ associatedTaxa.addAll(taxonName.getTaxa());
+ }
+ }
+ }
+ return associatedTaxa;
+ }
+
+ @Override
+ public Collection<TaxonBase<?>> listIndividualsAssociationTaxa(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start,
+ List<OrderHint> orderHints, List<String> propertyPaths) {
+ Collection<TaxonBase<?>> associatedTaxa = new HashSet<>();
+ for (IndividualsAssociation individualsAssociation : listIndividualsAssociations(specimen, limit, start, orderHints, propertyPaths)) {
+ if(individualsAssociation.getInDescription().isInstanceOf(TaxonDescription.class)){
+ TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(individualsAssociation.getInDescription(), TaxonDescription.class);
+ if(taxonDescription.getTaxon()!=null){
+ associatedTaxa.add(taxonDescription.getTaxon());
+ }
+ }
+ }
+ return associatedTaxa;
+ }
+
+ @Override
+ public Collection<DeterminationEvent> listDeterminationEvents(SpecimenOrObservationBase<?> specimen,
+ Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
+ return dao.listDeterminationEvents(specimen, limit, start, orderHints, propertyPaths);
+ }
+
+ @Override
+ public Map<DerivedUnit, Collection<SpecimenTypeDesignation>> listTypeDesignations(
+ Collection<DerivedUnit> specimens, Integer limit, Integer start,
+ List<OrderHint> orderHints, List<String> propertyPaths) {
+ Map<DerivedUnit, Collection<SpecimenTypeDesignation>> typeDesignationMap = new HashMap<>();
+ for (DerivedUnit specimen : specimens) {
+ Collection<SpecimenTypeDesignation> typeDesignations = listTypeDesignations(specimen, limit, start, orderHints, propertyPaths);
+ typeDesignationMap.put(specimen, typeDesignations);
+ }
+ return typeDesignationMap;
+ }
+
+ @Override
+ public Collection<SpecimenTypeDesignation> listTypeDesignations(DerivedUnit specimen,
+ Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
+ return dao.listTypeDesignations(specimen, limit, start, orderHints, propertyPaths);
+ }
+
+ @Override
+ public Collection<DescriptionBase<?>> listDescriptionsWithDescriptionSpecimen(
+ SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints,
+ List<String> propertyPaths) {
+ return dao.listDescriptionsWithDescriptionSpecimen(specimen, limit, start, orderHints, propertyPaths);
+ }
+
+ @Override
+ @Deprecated //this is not a service layer task so it may be removed in future versions
+ public Collection<DescriptionElementBase> getCharacterDataForSpecimen(SpecimenOrObservationBase<?> specimen) {
+ if (specimen != null) {
+ return specimen.characterData();
+ }else{
+ return new ArrayList<>();
+ }
+ }
+
+ @Override
+ public Collection<DescriptionElementBase> getCharacterDataForSpecimen(UUID specimenUuid) {
+ SpecimenOrObservationBase<?> specimen = load(specimenUuid);
+ if (specimen != null) {
+ return getCharacterDataForSpecimen(specimen);
+ }
+ else{
+ throw new DataRetrievalFailureException("Specimen with the given uuid not found in the data base");
+ }
+ }
+
+
+ @Override
+ public Integer countByTitle(IIdentifiableEntityServiceConfigurator<SpecimenOrObservationBase> config){
+ if (config instanceof FindOccurrencesConfigurator) {
+ FindOccurrencesConfigurator occurrenceConfig = (FindOccurrencesConfigurator) config;
+ Taxon taxon = null;
+ if(occurrenceConfig.getAssociatedTaxonUuid()!=null){
+ TaxonBase taxonBase = taxonService.load(occurrenceConfig.getAssociatedTaxonUuid());
+ if(taxonBase.isInstanceOf(Taxon.class)){
+ taxon = HibernateProxyHelper.deproxy(taxonBase, Taxon.class);
+ }
+ }
+ TaxonName taxonName = null;
+ if(occurrenceConfig.getAssociatedTaxonNameUuid()!=null){
+ taxonName = nameService.load(occurrenceConfig.getAssociatedTaxonNameUuid());
+ }
+ return dao.countOccurrences(occurrenceConfig.getClazz(),
+ occurrenceConfig.getTitleSearchString(), occurrenceConfig.getSignificantIdentifier(),
+ occurrenceConfig.getSpecimenType(), taxon, taxonName, occurrenceConfig.getMatchMode(), null, null,
+ occurrenceConfig.getOrderHints(), occurrenceConfig.getPropertyPaths());
+ }
+ else{
+ return dao.countByTitle(config.getTitleSearchString());
+ }
+
+ }
+
+ @Override
+ public Pager<SpecimenOrObservationBase> findByTitle(
+ IIdentifiableEntityServiceConfigurator<SpecimenOrObservationBase> config) {
+ if (config instanceof FindOccurrencesConfigurator) {
+ FindOccurrencesConfigurator occurrenceConfig = (FindOccurrencesConfigurator) config;
+ List<SpecimenOrObservationBase> occurrences = new ArrayList<>();
+ Taxon taxon = null;
+ if(occurrenceConfig.getAssociatedTaxonUuid()!=null){
+ TaxonBase taxonBase = taxonService.load(occurrenceConfig.getAssociatedTaxonUuid());
+ if(taxonBase.isInstanceOf(Taxon.class)){
+ taxon = HibernateProxyHelper.deproxy(taxonBase, Taxon.class);
+ }
+ }
+ TaxonName taxonName = null;
+ if(occurrenceConfig.getAssociatedTaxonNameUuid()!=null){
+ taxonName = nameService.load(occurrenceConfig.getAssociatedTaxonNameUuid());
+ }
+ occurrences.addAll(dao.findOccurrences(occurrenceConfig.getClazz(),
+ occurrenceConfig.getTitleSearchString(), occurrenceConfig.getSignificantIdentifier(),
+ occurrenceConfig.getSpecimenType(), taxon, taxonName, occurrenceConfig.getMatchMode(), null, null,
+ occurrenceConfig.getOrderHints(), occurrenceConfig.getPropertyPaths()));
+ //filter out (un-)assigned specimens
+ if(taxon==null && taxonName==null){
+ AssignmentStatus assignmentStatus = occurrenceConfig.getAssignmentStatus();
+ List<SpecimenOrObservationBase<?>> specimenWithAssociations = new ArrayList<>();
+ if(!assignmentStatus.equals(AssignmentStatus.ALL_SPECIMENS)){
+ for (SpecimenOrObservationBase specimenOrObservationBase : occurrences) {
+ Collection<TaxonBase<?>> associatedTaxa = listAssociatedTaxa(specimenOrObservationBase, null, null, null, null);
+ if(!associatedTaxa.isEmpty()){
+ specimenWithAssociations.add(specimenOrObservationBase);
+ }
+ }
+ }
+ if(assignmentStatus.equals(AssignmentStatus.UNASSIGNED_SPECIMENS)){
+ occurrences.removeAll(specimenWithAssociations);
+ }
+ if(assignmentStatus.equals(AssignmentStatus.ASSIGNED_SPECIMENS)){
+ occurrences = new ArrayList<>(specimenWithAssociations);
+ }
+ }
+ // indirectly associated specimens
+ if(occurrenceConfig.isRetrieveIndirectlyAssociatedSpecimens()){
+ List<SpecimenOrObservationBase> indirectlyAssociatedOccurrences = new ArrayList<>(occurrences);
+ for (SpecimenOrObservationBase specimen : occurrences) {
+ List<SpecimenOrObservationBase<?>> allHierarchyDerivates = getAllHierarchyDerivatives(specimen);
+ for (SpecimenOrObservationBase<?> specimenOrObservationBase : allHierarchyDerivates) {
+ if(!occurrences.contains(specimenOrObservationBase)){
+ indirectlyAssociatedOccurrences.add(specimenOrObservationBase);
+ }
+ }
+ }
+ occurrences = indirectlyAssociatedOccurrences;
+ }
+
+ return new DefaultPagerImpl<SpecimenOrObservationBase>(config.getPageNumber(), occurrences.size(), config.getPageSize(), occurrences);
+ }
+ return super.findByTitle(config);
+ }
+
+ @Override
+ public List<SpecimenOrObservationBase<?>> getAllHierarchyDerivatives(SpecimenOrObservationBase<?> specimen){
+ List<SpecimenOrObservationBase<?>> allHierarchyDerivatives = new ArrayList<>();
+ Collection<FieldUnit> fieldUnits = getFieldUnits(specimen.getUuid());
+ if(fieldUnits.isEmpty()){
+ allHierarchyDerivatives.add(specimen);
+ allHierarchyDerivatives.addAll(getAllChildDerivatives(specimen));
+ }
+ else{
+ for (FieldUnit fieldUnit : fieldUnits) {
+ allHierarchyDerivatives.add(fieldUnit);
+ allHierarchyDerivatives.addAll(getAllChildDerivatives(fieldUnit));
+ }
+ }
+ return allHierarchyDerivatives;
+ }
+
+ @Override
+ public List<DerivedUnit> getAllChildDerivatives(UUID specimenUuid){
+ return getAllChildDerivatives(load(specimenUuid));
+ }
+
+ @Override
+ public List<DerivedUnit> getAllChildDerivatives(SpecimenOrObservationBase<?> specimen){
+ if (specimen == null){
+ return null;
+ }
+ List<DerivedUnit> childDerivate = new ArrayList<>();
+ Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();
+ for (DerivationEvent derivationEvent : derivationEvents) {
+ Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
+ for (DerivedUnit derivedUnit : derivatives) {
+ childDerivate.add(derivedUnit);
+ childDerivate.addAll(getAllChildDerivatives(derivedUnit.getUuid()));
+ }
+ }
+ return childDerivate;
+ }
+
+ @Override
+ public int countOccurrences(IIdentifiableEntityServiceConfigurator<SpecimenOrObservationBase> config){
+ return countByTitle(config);
+ }
+
+}