-// $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.Collections;\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.dao.DataRetrievalFailureException;\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.UpdateResult.Status;\r
-import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase;\r
-import eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator;\r
-import eu.etaxonomy.cdm.api.service.dto.DerivateDTO;\r
-import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO;\r
-import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO.ContigFile;\r
-import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO.MolecularData;\r
-import eu.etaxonomy.cdm.api.service.dto.FieldUnitDTO;\r
-import eu.etaxonomy.cdm.api.service.dto.PreservedSpecimenDTO;\r
-import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;\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.CdmBase;\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.CategoricalData;\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.description.QuantitativeData;\r
-import eu.etaxonomy.cdm.model.description.SpecimenDescription;\r
-import eu.etaxonomy.cdm.model.description.TaxonDescription;\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.media.MediaUtils;\r
-import eu.etaxonomy.cdm.model.molecular.AmplificationResult;\r
-import eu.etaxonomy.cdm.model.molecular.DnaSample;\r
-import eu.etaxonomy.cdm.model.molecular.Sequence;\r
-import eu.etaxonomy.cdm.model.molecular.SingleRead;\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 ISequenceService sequenceService;\r
-\r
- @Autowired\r
- private AbstractBeanInitializer beanInitializer;\r
-\r
- @Autowired\r
- private ILuceneIndexToolProvider luceneIndexToolProvider;\r
-\r
- private static final String SEPARATOR_STRING = ", ";\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.isInstanceOf(IndividualsAssociation.class)){\r
- tempIndividualsAssociation = HibernateProxyHelper.deproxy(element, IndividualsAssociation.class);\r
- if(tempIndividualsAssociation.getAssociatedSpecimenOrObservation() != null){\r
- tempSpecimenOrObservationBase = HibernateProxyHelper.deproxy(tempIndividualsAssociation.getAssociatedSpecimenOrObservation(), SpecimenOrObservationBase.class);\r
- if(tempSpecimenOrObservationBase.isInstanceOf(DerivedUnit.class)){\r
- try {\r
- derivedUnitFacadeList.add(DerivedUnitFacade.NewInstance(HibernateProxyHelper.deproxy(tempSpecimenOrObservationBase, DerivedUnit.class)));\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<SpecimenOrObservationBase> listFieldUnitsByAssociatedTaxon(Taxon associatedTaxon, List<OrderHint> orderHints, List<String> propertyPaths) {\r
- return pageFieldUnitsByAssociatedTaxon(null, associatedTaxon, null, null, null, null, propertyPaths).getRecords();\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#pageFieldUnitsByAssociatedTaxon(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
- @Override\r
- public Pager<SpecimenOrObservationBase> pageFieldUnitsByAssociatedTaxon(Set<TaxonRelationshipEdge> includeRelationships,\r
- Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,\r
- List<String> propertyPaths) {\r
-\r
- if(!getSession().contains(associatedTaxon)){\r
- associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());\r
- }\r
-\r
- //gather the IDs of all relevant field units\r
- Set<Integer> fieldUnitIds = new HashSet<Integer>();\r
- List<SpecimenOrObservationBase> records = listByAssociatedTaxon(null, includeRelationships, associatedTaxon, maxDepth, null, null, orderHints, propertyPaths);\r
- for(SpecimenOrObservationBase<?> specimen:records){\r
- for (FieldUnit fieldUnit : getFieldUnits(specimen.getUuid())) {\r
- fieldUnitIds.add(fieldUnit.getId());\r
- }\r
- }\r
- //dao.listByIds() does the paging of the field units. Passing the field units directly to the Pager would not work\r
- List<SpecimenOrObservationBase> fieldUnits = dao.listByIds(fieldUnitIds, pageSize, pageNumber, orderHints, propertyPaths);\r
- return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, fieldUnitIds.size(), pageSize, fieldUnits);\r
- }\r
-\r
- @Override\r
- public FieldUnitDTO assembleFieldUnitDTO(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
- FieldUnitDTO fieldUnitDTO = new FieldUnitDTO();\r
-\r
- if(fieldUnit.getGatheringEvent()!=null){\r
- GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();\r
- //Country\r
- NamedArea country = gatheringEvent.getCountry();\r
- fieldUnitDTO.setCountry(country!=null?country.getDescription():null);\r
- //Collection\r
- AgentBase collector = gatheringEvent.getCollector();\r
- String fieldNumber = fieldUnit.getFieldNumber();\r
- String collectionString = "";\r
- if(collector!=null || fieldNumber!=null){\r
- collectionString += collector!=null?collector:"";\r
- if(!collectionString.isEmpty()){\r
- collectionString += " ";\r
- }\r
- collectionString += (fieldNumber!=null?fieldNumber:"");\r
- collectionString.trim();\r
- }\r
- fieldUnitDTO.setCollection(collectionString);\r
- //Date\r
- Partial gatheringDate = gatheringEvent.getGatheringDate();\r
- String dateString = null;\r
- if(gatheringDate!=null){\r
- gatheringDate.toString();\r
- }\r
- else if(gatheringEvent.getTimeperiod().getFreeText()!=null){\r
- dateString = gatheringEvent.getTimeperiod().getFreeText();\r
- }\r
- fieldUnitDTO.setDate(dateString);\r
- }\r
-\r
- //Taxon Name\r
- fieldUnitDTO.setTaxonName(associatedTaxon.getName().getFullTitleCache());\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
- //assemble preserved specimen DTOs\r
- Set<DerivationEvent> derivationEvents = fieldUnit.getDerivationEvents();\r
- for (DerivationEvent derivationEvent : derivationEvents) {\r
- Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();\r
- for (DerivedUnit derivedUnit : derivatives) {\r
- //collect accession numbers for citation\r
- String mostSignificantIdentifier = getMostSignificantIdentifier(derivedUnit);\r
- if(mostSignificantIdentifier!=null){\r
- preservedSpecimenAccessionNumbers.add(mostSignificantIdentifier);\r
- }\r
- //collect collections for herbaria column\r
- if(derivedUnit.getCollection()!=null){\r
- Integer herbariumCount = collectionToCountMap.get(derivedUnit.getCollection());\r
- if(herbariumCount==null){\r
- herbariumCount = 0;\r
- }\r
- collectionToCountMap.put(derivedUnit.getCollection(), herbariumCount+1);\r
- }\r
- if(derivedUnit.getRecordBasis().equals(SpecimenOrObservationType.PreservedSpecimen)){\r
- PreservedSpecimenDTO preservedSpecimenDTO = assemblePreservedSpecimenDTO(derivedUnit, fieldUnitDTO);\r
- fieldUnitDTO.addPreservedSpecimenDTO(preservedSpecimenDTO);\r
- fieldUnitDTO.setHasCharacterData(fieldUnitDTO.isHasCharacterData()||preservedSpecimenDTO.isHasCharacterData());\r
- fieldUnitDTO.setHasDetailImage(fieldUnitDTO.isHasDetailImage()||preservedSpecimenDTO.isHasDetailImage());\r
- fieldUnitDTO.setHasDna(fieldUnitDTO.isHasDna()||preservedSpecimenDTO.isHasDna());\r
- fieldUnitDTO.setHasSpecimenScan(fieldUnitDTO.isHasSpecimenScan()||preservedSpecimenDTO.isHasSpecimenScan());\r
- }\r
- }\r
- }\r
- //assemble derivate data DTO\r
- assembleDerivateDataDTO(fieldUnitDTO, fieldUnit);\r
-\r
- //assemble citation\r
- String citation = assembleCitation(fieldUnit);\r
- if(!preservedSpecimenAccessionNumbers.isEmpty()){\r
- citation += " (";\r
- for(String accessionNumber:preservedSpecimenAccessionNumbers){\r
- if(!accessionNumber.isEmpty()){\r
- citation += accessionNumber+SEPARATOR_STRING;\r
- }\r
- }\r
- citation = removeTail(citation, SEPARATOR_STRING);\r
- citation += ")";\r
- }\r
- fieldUnitDTO.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_STRING;\r
- }\r
- herbariaString = removeTail(herbariaString, SEPARATOR_STRING);\r
- fieldUnitDTO.setHerbarium(herbariaString);\r
-\r
- return fieldUnitDTO;\r
- }\r
-\r
-\r
- /**\r
- * @param fieldUnit\r
- * @param fieldUnitDTO\r
- * @param preservedSpecimenAccessionNumbers\r
- * @param SEPARATOR_STRING\r
- * @return\r
- */\r
- private String assembleCitation(FieldUnit fieldUnit) {\r
- String citation = "";\r
- if(fieldUnit.getGatheringEvent()!=null){\r
- //Country\r
- GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();\r
- NamedArea country = gatheringEvent.getCountry();\r
- String countryString = country!=null?country.getDescription():null;\r
- citation += countryString+SEPARATOR_STRING;\r
-\r
- //Collection\r
- AgentBase collector = gatheringEvent.getCollector();\r
- String fieldNumber = fieldUnit.getFieldNumber();\r
- String collectionString = "";\r
- if(collector!=null || fieldNumber!=null){\r
- collectionString += collector!=null?collector:"";\r
- if(!collectionString.isEmpty()){\r
- collectionString += " ";\r
- }\r
- collectionString += (fieldNumber!=null?fieldNumber:"");\r
- collectionString.trim();\r
- }\r
- citation += collectionString;\r
- if(fieldUnit.getGatheringEvent().getLocality()!=null){\r
- citation += fieldUnit.getGatheringEvent().getLocality().getText();\r
- citation += SEPARATOR_STRING;\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_STRING;\r
- citation += fieldUnit.getGatheringEvent().getExactLocation().getLongitude().toString();\r
- citation += SEPARATOR_STRING;\r
- }\r
- }\r
- citation = removeTail(citation, SEPARATOR_STRING);\r
- return citation;\r
- }\r
-\r
-\r
- @Override\r
- public PreservedSpecimenDTO assemblePreservedSpecimenDTO(DerivedUnit derivedUnit){\r
- return assemblePreservedSpecimenDTO(derivedUnit, null);\r
- }\r
-\r
- @Override\r
- public String getMostSignificantIdentifier(DerivedUnit derivedUnit){\r
- if(derivedUnit.getAccessionNumber()!=null && !derivedUnit.getAccessionNumber().isEmpty()){\r
- return derivedUnit.getAccessionNumber();\r
- }\r
- else if(derivedUnit.getBarcode()!=null && !derivedUnit.getBarcode().isEmpty()){\r
- return derivedUnit.getBarcode();\r
- }\r
- else if(derivedUnit.getCatalogNumber()!=null && !derivedUnit.getCatalogNumber().isEmpty()){\r
- return derivedUnit.getCatalogNumber();\r
- }\r
- return null;\r
- }\r
-\r
- public PreservedSpecimenDTO assemblePreservedSpecimenDTO(DerivedUnit derivedUnit, FieldUnitDTO fieldUnitDTO){\r
- if(!getSession().contains(derivedUnit)){\r
- derivedUnit = (DerivedUnit) load(derivedUnit.getUuid());\r
- }\r
- PreservedSpecimenDTO preservedSpecimenDTO = new PreservedSpecimenDTO();\r
-\r
- //check identifiers in priority order accNo>barCode>catalogNumber\r
- if(derivedUnit.getAccessionNumber()!=null && !derivedUnit.getAccessionNumber().isEmpty()){\r
- preservedSpecimenDTO.setAccessionNumber(derivedUnit.getAccessionNumber());\r
- }\r
- else if(derivedUnit.getBarcode()!=null && !derivedUnit.getBarcode().isEmpty()){\r
- preservedSpecimenDTO.setAccessionNumber(derivedUnit.getBarcode());\r
- }\r
- else if(derivedUnit.getCatalogNumber()!=null && !derivedUnit.getCatalogNumber().isEmpty()){\r
- preservedSpecimenDTO.setAccessionNumber(derivedUnit.getCatalogNumber());\r
- }\r
- preservedSpecimenDTO.setUuid(derivedUnit.getUuid().toString());\r
-\r
- //citation\r
- Collection<FieldUnit> fieldUnits = getFieldUnits(derivedUnit);\r
- if(fieldUnits.size()==1){\r
- preservedSpecimenDTO.setCitation(assembleCitation(fieldUnits.iterator().next()));\r
- }\r
- else{\r
- preservedSpecimenDTO.setCitation("No Citation available. This specimen either has no or multiple field units.");\r
- }\r
-\r
- //character state data\r
- Collection<DescriptionElementBase> characterDataForSpecimen = getCharacterDataForSpecimen(derivedUnit);\r
- if(!characterDataForSpecimen.isEmpty()){\r
- if(fieldUnitDTO!=null){\r
- fieldUnitDTO.setHasCharacterData(true);\r
- }\r
- }\r
- for (DescriptionElementBase descriptionElementBase : characterDataForSpecimen) {\r
- String character = descriptionElementBase.getFeature().getLabel();\r
- ArrayList<Language> languages = new ArrayList<Language>(Collections.singleton(Language.DEFAULT()));\r
- if(descriptionElementBase instanceof QuantitativeData){\r
- QuantitativeData quantitativeData = (QuantitativeData)descriptionElementBase;\r
- DefaultQuantitativeDescriptionBuilder builder = new DefaultQuantitativeDescriptionBuilder();\r
- String state = builder.build(quantitativeData, languages).getText(Language.DEFAULT());\r
- preservedSpecimenDTO.addCharacterData(character, state);\r
- }\r
- else if(descriptionElementBase instanceof CategoricalData){\r
- CategoricalData categoricalData = (CategoricalData)descriptionElementBase;\r
- DefaultCategoricalDescriptionBuilder builder = new DefaultCategoricalDescriptionBuilder();\r
- String state = builder.build(categoricalData, languages).getText(Language.DEFAULT());\r
- preservedSpecimenDTO.addCharacterData(character, state);\r
- }\r
- }\r
- //check type designations\r
- Collection<SpecimenTypeDesignation> specimenTypeDesignations = listTypeDesignations(derivedUnit, null, null, null, null);\r
- for (SpecimenTypeDesignation specimenTypeDesignation : specimenTypeDesignations) {\r
- if(fieldUnitDTO!=null){\r
- fieldUnitDTO.setHasType(true);\r
- }\r
- TypeDesignationStatusBase<?> typeStatus = specimenTypeDesignation.getTypeStatus();\r
- if(typeStatus!=null){\r
- List<String> typedTaxaNames = new ArrayList<String>();\r
- String label = typeStatus.getLabel();\r
- Set<TaxonNameBase> typifiedNames = specimenTypeDesignation.getTypifiedNames();\r
- for (TaxonNameBase taxonNameBase : typifiedNames) {\r
- typedTaxaNames.add(taxonNameBase.getFullTitleCache());\r
- }\r
- preservedSpecimenDTO.addTypes(label, typedTaxaNames);\r
- }\r
- }\r
-\r
- //individuals associations\r
- Collection<IndividualsAssociation> individualsAssociations = listIndividualsAssociations(derivedUnit, null, null, null, null);\r
- for (IndividualsAssociation individualsAssociation : individualsAssociations) {\r
- if(individualsAssociation.getInDescription()!=null){\r
- if(individualsAssociation.getInDescription().isInstanceOf(TaxonDescription.class)){\r
- TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(individualsAssociation.getInDescription(), TaxonDescription.class);\r
- Taxon taxon = taxonDescription.getTaxon();\r
- if(taxon!=null && taxon.getName()!=null){\r
- preservedSpecimenDTO.addAssociatedTaxon(taxon.getName().getFullTitleCache());\r
- }\r
- }\r
- }\r
- }\r
- //assemble sub derivates\r
- preservedSpecimenDTO.setDerivateDataDTO(assembleDerivateDataDTO(preservedSpecimenDTO, derivedUnit));\r
- return preservedSpecimenDTO;\r
- }\r
-\r
- /**\r
- * @param derivedUnit\r
- * @param derivateDataDTO\r
- * @return\r
- */\r
- private DerivateDataDTO assembleDerivateDataDTO(DerivateDTO derivateDTO, SpecimenOrObservationBase<?> specimenOrObservation) {\r
- DerivateDataDTO derivateDataDTO = new DerivateDataDTO();\r
- Collection<DerivedUnit> childDerivates = getDerivedUnitsFor(specimenOrObservation);\r
- for (DerivedUnit childDerivate : childDerivates) {\r
- //assemble molecular data\r
- //pattern: DNAMarker [contig1, primer1_1, primer1_2, ...][contig2, primer2_1, ...]...\r
- if(childDerivate.isInstanceOf(DnaSample.class)){\r
- if(childDerivate.getRecordBasis()==SpecimenOrObservationType.TissueSample){\r
- //TODO implement TissueSample assembly for web service\r
- }\r
- if(childDerivate.getRecordBasis()==SpecimenOrObservationType.DnaSample){\r
-\r
- DnaSample dna = HibernateProxyHelper.deproxy(childDerivate, DnaSample.class);\r
- if(!dna.getSequences().isEmpty()){\r
- derivateDTO.setHasDna(true);\r
- }\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
- MolecularData molecularData = derivateDataDTO.addProviderLink(boldUri!=null?boldUri:null,dnaMarker!=null?dnaMarker.getLabel():"[no marker]");\r
-\r
- //contig file FIXME show primer although contig not present?\r
- if(sequence.getContigFile()!=null){\r
- MediaRepresentationPart contigMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(sequence.getContigFile());\r
- if(contigMediaRepresentationPart!=null){\r
- ContigFile contigFile = molecularData.addContigFile(contigMediaRepresentationPart.getUri(), "contig");\r
- //primer files\r
- if(sequence.getSingleReads()!=null){\r
- for (SingleRead singleRead : sequence.getSingleReads()) {\r
- MediaRepresentationPart pherogramMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(singleRead.getPherogram());\r
- if(pherogramMediaRepresentationPart!=null){\r
- contigFile.addPrimerLink(pherogramMediaRepresentationPart.getUri(), "primer");\r
- }\r
- }\r
- }\r
- }\r
- }\r
- }\r
- }\r
- }\r
- //assemble media data\r
- else if(childDerivate.isInstanceOf(MediaSpecimen.class)){\r
-\r
- MediaSpecimen media = HibernateProxyHelper.deproxy(childDerivate, MediaSpecimen.class);\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
- derivateDTO.setHasSpecimenScan(true);\r
- String imageLinkText = "scan";\r
- if(derivateDTO instanceof PreservedSpecimenDTO && ((PreservedSpecimenDTO) derivateDTO).getAccessionNumber()!=null){\r
- imageLinkText = ((PreservedSpecimenDTO) derivateDTO).getAccessionNumber();\r
- }\r
- derivateDataDTO.addSpecimenScan(mediaUriString==null?"":mediaUriString, imageLinkText);\r
- }\r
- //detail image\r
- else if(media.getKindOfUnit().getUuid().equals(UUID.fromString("31eb8d02-bf5d-437c-bcc6-87a626445f34"))){\r
- derivateDTO.setHasDetailImage(true);\r
- String motif = "";\r
- if(media.getMediaSpecimen()!=null && media.getMediaSpecimen().getTitle()!=null){\r
- motif = media.getMediaSpecimen().getTitle().getText();\r
- }\r
- derivateDataDTO.addDetailImage(mediaUriString==null?"":mediaUriString, motif!=null?motif:"[no motif]");\r
- }\r
- }\r
- }\r
- }\r
- return derivateDataDTO;\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 Collection<DerivedUnit> getDerivedUnitsFor(SpecimenOrObservationBase<?> specimen){\r
- Collection<DerivedUnit> derivedUnits = new ArrayList<DerivedUnit>();\r
- for(DerivationEvent derivationEvent:specimen.getDerivationEvents()){\r
- for(DerivedUnit derivative:derivationEvent.getDerivatives()){\r
- derivedUnits.add(derivative);\r
- derivedUnits.addAll(getDerivedUnitsFor(derivative));\r
- }\r
- }\r
- return derivedUnits;\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
-\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.isInstanceOf(FieldUnit.class)){\r
- fieldUnits.add(HibernateProxyHelper.deproxy(specimen, FieldUnit.class));\r
- }\r
- else if(specimen.isInstanceOf(DerivedUnit.class)){\r
- fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class)));\r
- }\r
- return fieldUnits;\r
- }\r
-\r
-\r
- /**\r
- * @param original\r
- * @param fieldUnits\r
- */\r
- private Collection<FieldUnit> getFieldUnits(DerivedUnit derivedUnit) {\r
- Collection<FieldUnit> fieldUnits = new HashSet<FieldUnit>();\r
- Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals();\r
- if(originals!=null && !originals.isEmpty()){\r
- for(SpecimenOrObservationBase<?> original:originals){\r
- if(original.isInstanceOf(FieldUnit.class)){\r
- fieldUnits.add(HibernateProxyHelper.deproxy(original, FieldUnit.class));\r
- }\r
- else if(original.isInstanceOf(DerivedUnit.class)){\r
- fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(original, DerivedUnit.class)));\r
- }\r
- }\r
- }\r
- return fieldUnits;\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
- DerivationEvent derivedFromNewOriginalEvent = DerivationEvent.NewSimpleInstance(to, derivate, eventToRemove==null?null:eventToRemove.getType());\r
- to.addDerivationEvent(derivedFromNewOriginalEvent);\r
- derivate.setDerivedFrom(derivedFromNewOriginalEvent);\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.isInstanceOf(FieldUnit.class)){\r
- nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(HibernateProxyHelper.deproxy(specimen, FieldUnit.class)));\r
- }\r
- //DerivedUnit\r
- else if(specimen.isInstanceOf(DerivedUnit.class)){\r
- DerivedUnit derivedUnit = HibernateProxyHelper.deproxy(specimen, DerivedUnit.class);\r
- if(derivedUnit.getDerivedFrom()!=null){\r
- Collection<FieldUnit> fieldUnits = getFieldUnits(derivedUnit);\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.VersionableServiceBase#isDeletable(eu.etaxonomy.cdm.model.common.VersionableEntity, eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase)\r
- */\r
- @Override\r
- public DeleteResult isDeletable(SpecimenOrObservationBase specimen, DeleteConfiguratorBase config) {\r
- DeleteResult deleteResult = new DeleteResult();\r
- SpecimenDeleteConfigurator specimenDeleteConfigurator = (SpecimenDeleteConfigurator)config;\r
-\r
- //check elements found by super method\r
- Set<CdmBase> relatedObjects = super.isDeletable(specimen, config).getRelatedObjects();\r
- for (CdmBase cdmBase : relatedObjects) {\r
- //check for type designation\r
- if(cdmBase.isInstanceOf(SpecimenTypeDesignation.class) && !specimenDeleteConfigurator.isDeleteFromTypeDesignation()){\r
- deleteResult.setAbort();\r
- deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is a type specimen."));\r
- deleteResult.addRelatedObject(cdmBase);\r
- break;\r
- }\r
- //check for IndividualsAssociations\r
- else if(cdmBase.isInstanceOf(IndividualsAssociation.class) && !specimenDeleteConfigurator.isDeleteFromIndividualsAssociation()){\r
- deleteResult.setAbort();\r
- deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still associated via IndividualsAssociations"));\r
- deleteResult.addRelatedObject(cdmBase);\r
- break;\r
- }\r
- //check for specimen/taxon description\r
- else if((cdmBase.isInstanceOf(SpecimenDescription.class) || cdmBase.isInstanceOf(TaxonDescription.class))\r
- && !specimenDeleteConfigurator.isDeleteFromDescription()){\r
- deleteResult.setAbort();\r
- deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still used in a Description."));\r
- deleteResult.addRelatedObject(cdmBase);\r
- break;\r
- }\r
- //check for children and parents (derivation events)\r
- else if(cdmBase.isInstanceOf(DerivationEvent.class)){\r
- DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(cdmBase, DerivationEvent.class);\r
- //check if derivation event is empty\r
- if(!derivationEvent.getDerivatives().isEmpty()){\r
- if(derivationEvent.getDerivatives().size()==1 && derivationEvent.getDerivatives().contains(specimen)){\r
- //if it is the parent event with only one derivate then the specimen is still deletable\r
- continue;\r
- }\r
- else if(!specimenDeleteConfigurator.isDeleteChildren()){\r
- //if not and children should not be deleted then it is undeletable\r
- deleteResult.setAbort();\r
- deleteResult.addException(new ReferencedObjectUndeletableException("Derivate still has child derivates."));\r
- deleteResult.addRelatedObject(cdmBase);\r
- break;\r
- }\r
- else{\r
- //check all children if they can be deleted\r
- Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();\r
- DeleteResult childResult = new DeleteResult();\r
- for (DerivedUnit derivedUnit : derivatives) {\r
- childResult.includeResult(isDeletable(derivedUnit, specimenDeleteConfigurator));\r
- }\r
- if(!childResult.isOk()){\r
- deleteResult.setAbort();\r
- deleteResult.includeResult(childResult);\r
- deleteResult.addRelatedObject(cdmBase);\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- //check for amplification\r
- else if(cdmBase.isInstanceOf(AmplificationResult.class) && !specimenDeleteConfigurator.isDeleteMolecularData()){\r
- deleteResult.setAbort();\r
- deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in amplification results."));\r
- deleteResult.addRelatedObject(cdmBase);\r
- break;\r
- }\r
- //check for sequence\r
- else if(cdmBase.isInstanceOf(Sequence.class) && !specimenDeleteConfigurator.isDeleteMolecularData()){\r
- deleteResult.setAbort();\r
- deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in sequences."));\r
- deleteResult.addRelatedObject(cdmBase);\r
- break;\r
- }\r
- }\r
- if(deleteResult.isOk()){\r
- //add all related object if deletion is OK so they can be handled by the delete() method\r
- deleteResult.addRelatedObjects(relatedObjects);\r
- }\r
- return deleteResult;\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#delete(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator)\r
- */\r
- @Override\r
- public DeleteResult delete(SpecimenOrObservationBase<?> specimen, SpecimenDeleteConfigurator config) {\r
- specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);\r
-\r
- if(config.isDeleteChildren()){\r
- Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();\r
- for (DerivationEvent derivationEvent : derivationEvents) {\r
- Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();\r
- for (DerivedUnit derivedUnit : derivatives) {\r
- delete(derivedUnit, config);\r
- }\r
- }\r
- }\r
-\r
- DeleteResult deleteResult = isDeletable(specimen, config);\r
- if(!deleteResult.isOk()){\r
- return deleteResult;\r
- }\r
-\r
- //check related objects\r
- Set<CdmBase> relatedObjects = deleteResult.getRelatedObjects();\r
-\r
- for (CdmBase relatedObject : relatedObjects) {\r
- //check for TypeDesignations\r
- if(relatedObject.isInstanceOf(SpecimenTypeDesignation.class)){\r
- SpecimenTypeDesignation designation = HibernateProxyHelper.deproxy(relatedObject, SpecimenTypeDesignation.class);\r
- designation.setTypeSpecimen(null);\r
- Set<TaxonNameBase> typifiedNames = designation.getTypifiedNames();\r
- for (TaxonNameBase taxonNameBase : typifiedNames) {\r
- taxonNameBase.removeTypeDesignation(designation);\r
- }\r
- }\r
- //delete IndividualsAssociation\r
- if(relatedObject.isInstanceOf(IndividualsAssociation.class)){\r
- IndividualsAssociation assciation = HibernateProxyHelper.deproxy(relatedObject, IndividualsAssociation.class);\r
- assciation.setAssociatedSpecimenOrObservation(null);\r
- assciation.getInDescription().removeElement(assciation);\r
- }\r
- //check for taxon description\r
- if(relatedObject.isInstanceOf(TaxonDescription.class)){\r
- TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(relatedObject, TaxonDescription.class);\r
- taxonDescription.setDescribedSpecimenOrObservation(null);\r
- }\r
- //check for specimen description\r
- if(relatedObject.isInstanceOf(SpecimenDescription.class)){\r
- SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(relatedObject, SpecimenDescription.class);\r
- //check if specimen is "described" specimen\r
- if(specimenDescription.getDescribedSpecimenOrObservation().equals(specimen)){\r
- specimenDescription.setDescribedSpecimenOrObservation(null);\r
- }\r
- //check if description is a description of the given specimen\r
- if(specimen.getDescriptions().contains(specimenDescription)){\r
- specimen.removeDescription(specimenDescription);\r
- }\r
- }\r
- //check for amplification\r
- if(relatedObject.isInstanceOf(AmplificationResult.class)){\r
- AmplificationResult amplificationResult = HibernateProxyHelper.deproxy(relatedObject, AmplificationResult.class);\r
- amplificationResult.getDnaSample().removeAmplificationResult(amplificationResult);\r
- }\r
- //check for sequence\r
- if(relatedObject.isInstanceOf(Sequence.class)){\r
- Sequence sequence = HibernateProxyHelper.deproxy(relatedObject, Sequence.class);\r
- sequence.getDnaSample().removeSequence(sequence);\r
- }\r
- //check for children and parents (derivation events)\r
- if(relatedObject.isInstanceOf(DerivationEvent.class)){\r
- DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(relatedObject, DerivationEvent.class);\r
- //parent derivation event (derivedFrom)\r
- if(derivationEvent.getDerivatives().contains(specimen) && specimen.isInstanceOf(DerivedUnit.class)){\r
- derivationEvent.removeDerivative(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class));\r
- if(derivationEvent.getDerivatives().isEmpty()){\r
- Set<SpecimenOrObservationBase> originals = derivationEvent.getOriginals();\r
- for (SpecimenOrObservationBase specimenOrObservationBase : originals) {\r
- specimenOrObservationBase.removeDerivationEvent(derivationEvent);\r
- }\r
- }\r
- }\r
- else{\r
- //child derivation events should not occur since we delete the hierarchy from bottom to top\r
- }\r
- }\r
- }\r
-\r
- deleteResult.includeResult(delete(specimen));\r
- return deleteResult;\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(CdmBase from, SpecimenDeleteConfigurator config) {\r
- DeleteResult deleteResult = new DeleteResult();\r
- if(from.isInstanceOf(Sequence.class)){\r
- if(!config.isDeleteMolecularData()){\r
- deleteResult.setAbort();\r
- deleteResult.addException(new ReferencedObjectUndeletableException("deleting molecur data is not allowed in config"));\r
- return deleteResult;\r
- }\r
- Sequence sequence = HibernateProxyHelper.deproxy(from, Sequence.class);\r
- sequence.getDnaSample().removeSequence(sequence);\r
- deleteResult = sequenceService.delete(sequence);\r
- }\r
- else if(from.isInstanceOf(SingleRead.class)) {\r
- if(!config.isDeleteMolecularData()){\r
- deleteResult.setAbort();\r
- deleteResult.addException(new ReferencedObjectUndeletableException("deleting molecur data is not allowed in config"));\r
- return deleteResult;\r
- }\r
- SingleRead singleRead = HibernateProxyHelper.deproxy(from, SingleRead.class);\r
- singleRead.getAmplificationResult().removeSingleRead(singleRead);\r
- deleteResult.setStatus(Status.OK);\r
- }\r
- else if(from.isInstanceOf(SpecimenOrObservationBase.class)) {\r
- deleteResult = delete(HibernateProxyHelper.deproxy(from, SpecimenOrObservationBase.class), config);\r
- }\r
- return deleteResult;\r
- }\r
-\r
-// private DeleteResult deepDelete(SpecimenOrObservationBase<?> entity, SpecimenDeleteConfigurator config){\r
-// Set<DerivationEvent> derivationEvents = entity.getDerivationEvents();\r
-// for (DerivationEvent derivationEvent : derivationEvents) {\r
-// Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();\r
-// for (DerivedUnit derivedUnit : derivatives) {\r
-// DeleteResult deleteResult = deepDelete(derivedUnit, config);\r
-// if(!deleteResult.isOk()){\r
-// return deleteResult;\r
-// }\r
-// }\r
-// }\r
-// return delete(entity, config);\r
-// }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listAssociatedTaxa(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase)\r
- */\r
- @Override\r
- public Collection<IndividualsAssociation> listIndividualsAssociations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
- return dao.listIndividualsAssociations(specimen, null, null, null, null);\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listTypeDesignations(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
- */\r
- @Override\r
- public Collection<SpecimenTypeDesignation> listTypeDesignations(SpecimenOrObservationBase<?> specimen,\r
- Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
- return dao.listTypeDesignations(specimen, limit, start, orderHints, propertyPaths);\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listDescriptionsWithDescriptionSpecimen(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
- */\r
- @Override\r
- public Collection<DescriptionBase<?>> listDescriptionsWithDescriptionSpecimen(\r
- SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints,\r
- List<String> propertyPaths) {\r
- return dao.listDescriptionsWithDescriptionSpecimen(specimen, limit, start, orderHints, propertyPaths);\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getStatesForSpecimen(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase)\r
- */\r
- @Override\r
- public Collection<DescriptionElementBase> getCharacterDataForSpecimen(SpecimenOrObservationBase<?> specimen) {\r
- Collection<DescriptionElementBase> states = new ArrayList<DescriptionElementBase>();\r
- if(specimen!=null){\r
- Set<DescriptionBase> descriptions = specimen.getDescriptions();\r
- for (DescriptionBase<?> descriptionBase : descriptions) {\r
- if(descriptionBase.isInstanceOf(SpecimenDescription.class)){\r
- SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(descriptionBase, SpecimenDescription.class);\r
- Set<DescriptionElementBase> elements = specimenDescription.getElements();\r
- for (DescriptionElementBase descriptionElementBase : elements) {\r
- if(descriptionElementBase.getFeature().isSupportsCategoricalData()\r
- ||descriptionElementBase.getFeature().isSupportsQuantitativeData()){\r
- states.add(descriptionElementBase);\r
- }\r
- }\r
- }\r
- }\r
- }\r
- return states;\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getStatesForSpecimen(java.util.UUID)\r
- */\r
- @Override\r
- public Collection<DescriptionElementBase> getCharacterDataForSpecimen(UUID specimenUuid) {\r
- SpecimenOrObservationBase<?> specimen = load(specimenUuid);\r
- if(specimen!=null){\r
- return getCharacterDataForSpecimen(specimen);\r
- }\r
- else{\r
- throw new DataRetrievalFailureException("Specimen with the given uuid not found in the data base");\r
- }\r
- }\r
-\r
-}\r
+// $Id$
+/**
+ * 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.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.index.CorruptIndexException;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.search.BooleanClause.Occur;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.SortField;
+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.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.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.LuceneSearch;
+import eu.etaxonomy.cdm.api.service.search.LuceneSearch.TopGroupsWithMaxScore;
+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.monitor.IProgressMonitor;
+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.TaxonNameBase;
+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.occurrence.IOccurrenceDao;
+import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
+import eu.etaxonomy.cdm.persistence.query.OrderHint;
+import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
+
+/**
+ * @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 ITaxonService taxonService;
+
+ @Autowired
+ private ISequenceService sequenceService;
+
+ @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<Country>();
+ 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<DerivationEvent>();
+ 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<DeterminationEvent>();
+ 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<Media>();
+ 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<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<SpecimenOrObservationBase>();
+ 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() {
+ return dao.getDerivedUnitUuidAndTitleCache();
+ }
+
+ @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<DerivedUnitFacade>();
+ IndividualsAssociation tempIndividualsAssociation;
+ SpecimenOrObservationBase tempSpecimenOrObservationBase;
+ List<DescriptionElementBase> elements = descriptionService.listDescriptionElements(description, null, IndividualsAssociation.class, null, 0, Arrays.asList(new String []{"associatedSpecimenOrObservation"}));
+ for (DescriptionElementBase element : elements) {
+ if (element.isInstanceOf(IndividualsAssociation.class)) {
+ 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<Integer> fieldUnitIds = new HashSet<Integer>();
+ List<SpecimenOrObservationBase> records = listByAssociatedTaxon(null, includeRelationships, associatedTaxon, maxDepth, null, null, orderHints, propertyPaths);
+ for (SpecimenOrObservationBase<?> specimen : records) {
+ for (FieldUnit fieldUnit : getFieldUnits(specimen.getUuid())) {
+ fieldUnitIds.add(fieldUnit.getId());
+ }
+ }
+ //dao.listByIds() does the paging of the field units. Passing the field units directly to the Pager would not work
+ List<SpecimenOrObservationBase> fieldUnits = dao.listByIds(fieldUnitIds, pageSize, pageNumber, orderHints, propertyPaths);
+ return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, fieldUnitIds.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.getDescription() : 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) {
+ 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<eu.etaxonomy.cdm.model.occurrence.Collection, Integer>();
+ // List of accession numbers for citation
+ List<String> preservedSpecimenAccessionNumbers = new ArrayList<String>();
+
+ // assemble preserved specimen DTOs
+ Set<DerivationEvent> derivationEvents = fieldUnit.getDerivationEvents();
+ for (DerivationEvent derivationEvent : derivationEvents) {
+ Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
+ for (DerivedUnit derivedUnit : derivatives) {
+ // 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 (!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();
+
+ // check identifiers in priority order accNo>barCode>catalogNumber
+ if (derivedUnit.getAccessionNumber() != null && !derivedUnit.getAccessionNumber().isEmpty()) {
+ preservedSpecimenDTO.setAccessionNumber(derivedUnit.getAccessionNumber());
+ }
+ else if(derivedUnit.getBarcode()!=null && !derivedUnit.getBarcode().isEmpty()){
+ preservedSpecimenDTO.setAccessionNumber(derivedUnit.getBarcode());
+ }
+ else if(derivedUnit.getCatalogNumber()!=null && !derivedUnit.getCatalogNumber().isEmpty()){
+ preservedSpecimenDTO.setAccessionNumber(derivedUnit.getCatalogNumber());
+ }
+ preservedSpecimenDTO.setUuid(derivedUnit.getUuid().toString());
+
+ // 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<Language>(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>();
+ String label = typeStatus.getLabel();
+ Set<TaxonNameBase> typifiedNames = specimenTypeDesignation.getTypifiedNames();
+ for (TaxonNameBase taxonNameBase : typifiedNames) {
+ typedTaxaNames.add(taxonNameBase.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 && taxon.getName() != null) {
+ preservedSpecimenDTO.addAssociatedTaxon(taxon.getName().getTitleCache());
+ }
+ }
+ }
+ }
+ // 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();
+ MolecularData molecularData = derivateDataDTO.addProviderLink(boldUri != null ? boldUri : null, dnaMarker != null ? dnaMarker.getLabel() : "[no marker]");
+
+ //contig file
+ ContigFile contigFile = null;
+ if (sequence.getContigFile() != null) {
+ MediaRepresentationPart contigMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(sequence.getContigFile());
+ if (contigMediaRepresentationPart != null) {
+ contigFile = molecularData.addContigFile(contigMediaRepresentationPart.getUri(), "contig");
+ }
+ }
+ if(contigFile==null){
+ contigFile = molecularData.addContigFile(null, "[no contig]");
+ }
+ // 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);
+
+ String mediaUriString = getMediaUriString(media);
+ if (media.getKindOfUnit() != null) {
+ // specimen scan
+ if (media.getKindOfUnit().getUuid().equals(UUID.fromString("acda15be-c0e2-4ea8-8783-b9b0c4ad7f03"))) {
+ 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(mediaUriString == null ? "" : mediaUriString, imageLinkText);
+ }
+ // detail image
+ else if (media.getKindOfUnit().getUuid().equals(UUID.fromString("31eb8d02-bf5d-437c-bcc6-87a626445f34"))) {
+ derivateDataDTO.addDetailImageUuid(media.getMediaSpecimen().getUuid());
+ derivateDTO.setHasDetailImage(true);
+ String motif = "";
+ if (media.getMediaSpecimen() != null && media.getMediaSpecimen().getTitle() != null) {
+ motif = media.getMediaSpecimen().getTitle().getText();
+ }
+ derivateDataDTO.addDetailImage(mediaUriString == null ? "" : mediaUriString, motif != null ? motif : "[no 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 String getMediaUriString(MediaSpecimen mediaSpecimen) {
+ String 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().toASCIIString();
+ }
+ }
+ }
+ return mediaUri;
+ }
+
+ private Collection<DerivedUnit> getDerivedUnitsFor(SpecimenOrObservationBase<?> specimen) {
+ Collection<DerivedUnit> derivedUnits = new ArrayList<DerivedUnit>();
+ 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<Taxon>();
+ Set<Integer> occurrenceIds = new HashSet<Integer>();
+ List<T> occurrences = new ArrayList<T>();
+
+ // 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.listByIds(occurrenceIds, pageSize, pageNumber, orderHints, 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 CorruptIndexException, IOException, ParseException {
+
+ LuceneSearch luceneSearch = prepareByFullTextSearch(clazz, queryString, boundingBox, languages, highlightFragments);
+
+ // --- execute search
+ TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);
+
+ Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
+ 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.topGroups.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) {
+
+ BooleanQuery finalQuery = new BooleanQuery();
+ BooleanQuery textQuery = new BooleanQuery();
+
+ LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, FieldUnit.class);
+ QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(FieldUnit.class);
+
+ // --- criteria
+ luceneSearch.setCdmTypRestriction(clazz);
+ if (queryString != null) {
+ textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);
+ finalQuery.add(textQuery, Occur.MUST);
+ }
+
+ // --- spacial query
+ if (bbox != null) {
+ finalQuery.add(QueryFactory.buildSpatialQueryByRange(bbox, "gatheringEvent.exactLocation.point"), Occur.MUST);
+ }
+
+ luceneSearch.setQuery(finalQuery);
+
+ // --- sorting
+ SortField[] sortFields = new SortField[] { SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.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<FieldUnit>();
+
+ 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<FieldUnit>();
+ 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.getUuid(), 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 = load(specimenFromUuid);
+ SpecimenOrObservationBase<?> to = load(specimenToUuid);
+ DerivedUnit derivate = (DerivedUnit) load(derivateUuid);
+
+ if (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
+ // 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);
+ }
+
+ 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 TaxonNameBase
+ */
+
+ Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();
+
+ //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<ICdmBase>();
+ // 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(SpecimenOrObservationBase specimen, DeleteConfiguratorBase config) {
+ DeleteResult deleteResult = new DeleteResult();
+ SpecimenDeleteConfigurator specimenDeleteConfigurator = (SpecimenDeleteConfigurator) config;
+
+ // check elements found by super method
+ Set<CdmBase> relatedObjects = super.isDeletable(specimen, config).getRelatedObjects();
+ for (CdmBase cdmBase : relatedObjects) {
+ // check for type designation
+ if (cdmBase.isInstanceOf(SpecimenTypeDesignation.class) && !specimenDeleteConfigurator.isDeleteFromTypeDesignation()) {
+ deleteResult.setAbort();
+ deleteResult.addException(new ReferencedObjectUndeletableException("Specimen 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 is still associated via IndividualsAssociations"));
+ deleteResult.addRelatedObject(cdmBase);
+ break;
+ }
+ // check for specimen/taxon description
+ else if((cdmBase.isInstanceOf(SpecimenDescription.class) || cdmBase.isInstanceOf(TaxonDescription.class))
+ && !specimenDeleteConfigurator.isDeleteFromDescription()){
+ deleteResult.setAbort();
+ deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still used in a 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()) {
+ if (derivationEvent.getDerivatives().size() == 1 && derivationEvent.getDerivatives().contains(specimen)) {
+ //if it is the parent event with only one derivate then the specimen is still deletable
+ continue;
+ }
+ else if(!specimenDeleteConfigurator.isDeleteChildren()){
+ //if not and children should not be deleted then it is undeletable
+ deleteResult.setAbort();
+ deleteResult.addException(new ReferencedObjectUndeletableException("Derivative 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, specimenDeleteConfigurator));
+ }
+ if (!childResult.isOk()) {
+ deleteResult.setAbort();
+ deleteResult.includeResult(childResult);
+ deleteResult.addRelatedObject(cdmBase);
+ break;
+ }
+ }
+ }
+ }
+ // check for amplification
+ else if (cdmBase.isInstanceOf(AmplificationResult.class) && !specimenDeleteConfigurator.isDeleteMolecularData()) {
+ 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()) {
+ 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;
+ }
+
+ @Override
+ public DeleteResult delete(SpecimenOrObservationBase<?> specimen, SpecimenDeleteConfigurator config) {
+ specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
+
+ 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<DerivationEvent>(derivationEvents);
+ for (DerivationEvent derivationEvent : derivationEventsClone) {
+ Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
+ for (DerivedUnit derivedUnit : derivatives) {
+ delete(derivedUnit, config);
+ }
+ }
+ }
+
+ DeleteResult deleteResult = isDeletable(specimen, config);
+ if (!deleteResult.isOk()) {
+ return deleteResult;
+ }
+
+ // 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);
+ Set<TaxonNameBase> typifiedNames = designation.getTypifiedNames();
+ for (TaxonNameBase taxonNameBase : typifiedNames) {
+ taxonNameBase.removeTypeDesignation(designation);
+ }
+ }
+ // delete IndividualsAssociation
+ if (relatedObject.isInstanceOf(IndividualsAssociation.class)) {
+ IndividualsAssociation assciation = HibernateProxyHelper.deproxy(relatedObject, IndividualsAssociation.class);
+ assciation.setAssociatedSpecimenOrObservation(null);
+ assciation.getInDescription().removeElement(assciation);
+ }
+ // check for taxon description
+ if (relatedObject.isInstanceOf(TaxonDescription.class)) {
+ TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(relatedObject, TaxonDescription.class);
+ taxonDescription.setDescribedSpecimenOrObservation(null);
+ }
+ // check for specimen description
+ if (relatedObject.isInstanceOf(SpecimenDescription.class)) {
+ SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(relatedObject, SpecimenDescription.class);
+ // check if specimen is "described" specimen
+ if (specimenDescription.getDescribedSpecimenOrObservation().equals(specimen)) {
+ specimenDescription.setDescribedSpecimenOrObservation(null);
+ }
+ // check if description is a description of the given specimen
+ if (specimen.getDescriptions().contains(specimenDescription)) {
+ specimen.removeDescription(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);
+ }
+ }
+ }
+ else{
+ //child derivation events should not occur since we delete the hierarchy from bottom to top
+ }
+ }
+ }
+
+ deleteResult.includeResult(delete(specimen));
+ return deleteResult;
+ }
+
+ @Override
+ public DeleteResult deleteSingleRead(SingleRead singleRead, Sequence sequence){
+ DeleteResult deleteResult = new DeleteResult();
+ singleRead = HibernateProxyHelper.deproxy(singleRead, SingleRead.class);
+ //delete from amplification result
+ if(singleRead.getAmplificationResult()!=null){
+ singleRead.getAmplificationResult().removeSingleRead(singleRead);
+ }
+ //delete from sequence
+ sequence.removeSingleRead(singleRead);
+ deleteResult.addUpdatedObject(sequence);
+ deleteResult.setStatus(Status.OK);
+ return deleteResult;
+ }
+
+ @Override
+ @Transactional(readOnly = false)
+ public DeleteResult deleteSingleRead(UUID singleReadUuid, UUID sequenceUuid){
+ SingleRead singleRead = null;
+ Sequence sequence = CdmBase.deproxy(sequenceService.load(sequenceUuid), Sequence.class);
+ for(SingleRead sr : sequence.getSingleReads()) {
+ if(sr.getUuid().equals(singleReadUuid)) {
+ singleRead = sr;
+ break;
+ }
+ }
+ return deleteSingleRead(singleRead, sequence);
+ }
+
+ @Override
+ public DeleteResult deleteDerivateHierarchy(CdmBase from, SpecimenDeleteConfigurator config) {
+ DeleteResult deleteResult = new DeleteResult();
+ String deleteMolecularNotAllowed = "Deleting molecular data is not allowed in config";
+ if (from.isInstanceOf(Sequence.class)) {
+ if (!config.isDeleteMolecularData()) {
+ deleteResult.setAbort();
+ deleteResult.addException(new ReferencedObjectUndeletableException(deleteMolecularNotAllowed));
+ return deleteResult;
+ }
+ Sequence sequence = HibernateProxyHelper.deproxy(from, Sequence.class);
+ DnaSample dnaSample = sequence.getDnaSample();
+ dnaSample.removeSequence(sequence);
+ deleteResult = sequenceService.delete(sequence);
+ deleteResult.addUpdatedObject(dnaSample);
+ }
+ else if(from instanceof SingleRead){
+ SingleRead singleRead = (SingleRead)from;
+ //delete from amplification result
+ if(singleRead.getAmplificationResult()!=null){
+ singleRead.getAmplificationResult().removeSingleRead(singleRead);
+ }
+ deleteResult.setAbort();
+ deleteResult.addException(new ReferencedObjectUndeletableException("Deleted ONLY from amplification. "
+ + "Single read may still be attached to a consensus sequence."));
+ }
+ else if(from.isInstanceOf(SpecimenOrObservationBase.class)) {
+ deleteResult = delete(HibernateProxyHelper.deproxy(from, SpecimenOrObservationBase.class), config);
+ }
+ return deleteResult;
+ }
+
+ @Override
+ @Transactional(readOnly = false)
+ public DeleteResult deleteDerivateHierarchy(UUID fromUuid, SpecimenDeleteConfigurator config) {
+ return deleteDerivateHierarchy(dao.load(fromUuid),config);
+ }
+
+// private DeleteResult deepDelete(SpecimenOrObservationBase<?> entity, SpecimenDeleteConfigurator config){
+ // Set<DerivationEvent> derivationEvents = entity.getDerivationEvents();
+ // for (DerivationEvent derivationEvent : derivationEvents) {
+ // Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
+ // for (DerivedUnit derivedUnit : derivatives) {
+ // DeleteResult deleteResult = deepDelete(derivedUnit, config);
+ // if(!deleteResult.isOk()){
+ // return deleteResult;
+ // }
+ // }
+ // }
+ // return delete(entity, config);
+ // }
+
+ @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<SpecimenTypeDesignation> listTypeDesignations(SpecimenOrObservationBase<?> 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<DescriptionElementBase>();
+ }
+ }
+
+ @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 Pager<SpecimenOrObservationBase> findByTitle(
+ IIdentifiableEntityServiceConfigurator<SpecimenOrObservationBase> config) {
+ if (config instanceof FindOccurrencesConfigurator) {
+ FindOccurrencesConfigurator occurrenceConfig = (FindOccurrencesConfigurator) config;
+ List<SpecimenOrObservationBase> occurrences = new ArrayList<SpecimenOrObservationBase>();
+ Taxon taxon = null;
+ if(occurrenceConfig.getAssociatedTaxonUuid()!=null){
+ TaxonBase taxonBase = taxonService.load(occurrenceConfig.getAssociatedTaxonUuid());
+ if(taxonBase.isInstanceOf(Taxon.class)){
+ taxon = HibernateProxyHelper.deproxy(taxonBase, Taxon.class);
+ }
+ }
+ occurrences.addAll(dao.findOccurrences(occurrenceConfig.getClazz(),
+ occurrenceConfig.getTitleSearchString(), occurrenceConfig.getSignificantIdentifier(),
+ occurrenceConfig.getSpecimenType(), taxon, occurrenceConfig.getMatchMode(), null, null,
+ occurrenceConfig.getOrderHints(), occurrenceConfig.getPropertyPaths()));
+ // indirectly associated specimens
+ List<SpecimenOrObservationBase> indirectlyAssociatedOccurrences = new ArrayList<SpecimenOrObservationBase>(occurrences);
+ if(occurrenceConfig.isRetrieveIndirectlyAssociatedSpecimens()){
+ 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<SpecimenOrObservationBase<?>>();
+ 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(SpecimenOrObservationBase<?> specimen){
+ List<DerivedUnit> childDerivate = new ArrayList<DerivedUnit>();
+ 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));
+ }
+ }
+ return childDerivate;
+ }
+
+ @Override
+ public int countOccurrences(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);
+ }
+ }
+ // indirectly associated specimens
+ if(occurrenceConfig.isRetrieveIndirectlyAssociatedSpecimens()){
+ return findByTitle(config).getRecords().size();
+ }
+ return dao.countOccurrences(occurrenceConfig.getClazz(), occurrenceConfig.getTitleSearchString(),
+ occurrenceConfig.getSignificantIdentifier(), occurrenceConfig.getSpecimenType(), taxon,
+ occurrenceConfig.getMatchMode(), null, null, occurrenceConfig.getOrderHints(),
+ occurrenceConfig.getPropertyPaths());
+ }
+ return super.countByTitle(config);
+ }
+
+}