+\r
+ @Override\r
+ public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,\r
+ String taxonUUID, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+\r
+ UUID uuid = UUID.fromString(taxonUUID);\r
+ Taxon tax = (Taxon) taxonService.load(uuid);\r
+ //TODO REMOVE NULL STATEMENT\r
+ type=null;\r
+ return pageByAssociatedTaxon( type,includeRelationships,tax, maxDepth, pageSize, pageNumber, orderHints, propertyPaths );\r
+\r
+ }\r
+\r
+\r
+ @Override\r
+ public Pager<SearchResult<SpecimenOrObservationBase>> findByFullText(\r
+ Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle boundingBox, List<Language> languages,\r
+ boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,\r
+ List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {\r
+\r
+ LuceneSearch luceneSearch = prepareByFullTextSearch(clazz, queryString, boundingBox, languages, highlightFragments);\r
+\r
+ // --- execute search\r
+ TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);\r
+\r
+ Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();\r
+ idFieldMap.put(CdmBaseType.SPECIMEN_OR_OBSERVATIONBASE, "id");\r
+\r
+ // --- initialize taxa, highlight matches ....\r
+ ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());\r
+ @SuppressWarnings("rawtypes")\r
+ List<SearchResult<SpecimenOrObservationBase>> searchResults = searchResultBuilder.createResultSet(\r
+ topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);\r
+\r
+ int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupCount : 0;\r
+\r
+ return new DefaultPagerImpl<SearchResult<SpecimenOrObservationBase>>(pageNumber, totalHits, pageSize,\r
+ searchResults);\r
+\r
+ }\r
+\r
+\r
+ /**\r
+ * @param clazz\r
+ * @param queryString\r
+ * @param languages\r
+ * @param highlightFragments\r
+ * @return\r
+ */\r
+ private LuceneSearch prepareByFullTextSearch(Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle bbox,\r
+ List<Language> languages, boolean highlightFragments) {\r
+\r
+ BooleanQuery finalQuery = new BooleanQuery();\r
+ BooleanQuery textQuery = new BooleanQuery();\r
+\r
+ LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, FieldUnit.class);\r
+ QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(FieldUnit.class);\r
+\r
+ // --- criteria\r
+ luceneSearch.setCdmTypRestriction(clazz);\r
+ if(queryString != null){\r
+ textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
+ finalQuery.add(textQuery, Occur.MUST);\r
+ }\r
+\r
+ // --- spacial query\r
+ if(bbox != null){\r
+ finalQuery.add(QueryFactory.buildSpatialQueryByRange(bbox, "gatheringEvent.exactLocation.point"), Occur.MUST);\r
+ }\r
+\r
+ luceneSearch.setQuery(finalQuery);\r
+\r
+ // --- sorting\r
+ SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};\r
+ luceneSearch.setSortFields(sortFields);\r
+\r
+ if(highlightFragments){\r
+ luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());\r
+ }\r
+ return luceneSearch;\r
+ }\r
+\r
+\r
+ /* (non-Javadoc)\r
+ * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getFieldUnits(eu.etaxonomy.cdm.model.occurrence.DerivedUnit)\r
+ */\r
+ @Override\r
+ public Collection<FieldUnit> getFieldUnits(UUID derivedUnitUuid) {\r
+ //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})\r
+ //from which this DerivedUnit was derived until all FieldUnits are found.\r
+\r
+ //FIXME: use HQL queries to increase performance\r
+ SpecimenOrObservationBase<?> specimen = load(derivedUnitUuid);\r
+// specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);\r
+ Collection<FieldUnit> fieldUnits = new ArrayList<FieldUnit>();\r
+\r
+ if(specimen instanceof FieldUnit){\r
+ fieldUnits.add((FieldUnit) specimen);\r
+ }\r
+ else if(specimen instanceof DerivedUnit){\r
+ getFieldUnits((DerivedUnit) specimen, fieldUnits);\r
+ }\r
+ return fieldUnits;\r
+ }\r
+\r
+\r
+ /**\r
+ * @param original\r
+ * @param fieldUnits\r
+ */\r
+ private void getFieldUnits(DerivedUnit derivedUnit, Collection<FieldUnit> fieldUnits) {\r
+ Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals();\r
+ if(originals!=null && !originals.isEmpty()){\r
+ for(SpecimenOrObservationBase<?> original:originals){\r
+ if(original instanceof FieldUnit){\r
+ fieldUnits.add((FieldUnit) original);\r
+ }\r
+ else if(original instanceof DerivedUnit){\r
+ getFieldUnits((DerivedUnit) original, fieldUnits);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#moveSequence(eu.etaxonomy.cdm.model.molecular.DnaSample, eu.etaxonomy.cdm.model.molecular.DnaSample, eu.etaxonomy.cdm.model.molecular.Sequence)\r
+ */\r
+ @Override\r
+ public boolean moveSequence(DnaSample from, DnaSample to, Sequence sequence) {\r
+ //reload specimens to avoid session conflicts\r
+ from = (DnaSample) load(from.getUuid());\r
+ to = (DnaSample) load(to.getUuid());\r
+ sequence = sequenceService.load(sequence.getUuid());\r
+\r
+ if(from==null || to==null || sequence==null){\r
+ throw new TransientObjectException("One of the CDM entities has not been saved to the data base yet. Moving only works for persisted/saved CDM entities.\n" +\r
+ "Operation was move "+sequence+ " from "+from+" to "+to);\r
+ }\r
+ from.removeSequence(sequence);\r
+ saveOrUpdate(from);\r
+ to.addSequence(sequence);\r
+ saveOrUpdate(to);\r
+ return true;\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#moveDerivate(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.occurrence.DerivedUnit)\r
+ */\r
+ @Override\r
+ public boolean moveDerivate(SpecimenOrObservationBase<?> from, SpecimenOrObservationBase<?> to, DerivedUnit derivate) {\r
+ //reload specimens to avoid session conflicts\r
+ from = load(from.getUuid());\r
+ to = load(to.getUuid());\r
+ derivate = (DerivedUnit) load(derivate.getUuid());\r
+\r
+ if(from==null || to==null || derivate==null){\r
+ throw new TransientObjectException("One of the CDM entities has not been saved to the data base yet. Moving only works for persisted/saved CDM entities.\n" +\r
+ "Operation was move "+derivate+ " from "+from+" to "+to);\r
+ }\r
+\r
+ SpecimenOrObservationType derivateType = derivate.getRecordBasis();\r
+ SpecimenOrObservationType toType = to.getRecordBasis();\r
+ //check if type is a sub derivate type\r
+ if(toType==SpecimenOrObservationType.FieldUnit //moving to FieldUnit always works\r
+ || derivateType==SpecimenOrObservationType.Media //moving media always works\r
+ || (derivateType.isKindOf(toType) && toType!=derivateType)){ //moving only to parent derivate type\r
+ //remove derivation event from parent specimen of dragged object\r
+ DerivationEvent eventToRemove = null;\r
+ for(DerivationEvent event:from.getDerivationEvents()){\r
+ if(event.getDerivatives().contains(derivate)){\r
+ eventToRemove = event;\r
+ break;\r
+ }\r
+ }\r
+ from.removeDerivationEvent(eventToRemove);\r
+ saveOrUpdate(from);\r
+ //add new derivation event to target\r
+ 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 instanceof FieldUnit){\r
+ nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements((FieldUnit)specimen));\r
+ }\r
+ //DerivedUnit\r
+ else if(specimen instanceof DerivedUnit){\r
+ DerivedUnit derivedUnit = (DerivedUnit)specimen;\r
+ if(derivedUnit.getDerivedFrom()!=null){\r
+ Collection<FieldUnit> fieldUnits = new ArrayList<FieldUnit>();\r
+ getFieldUnits(derivedUnit, fieldUnits);\r
+ for(FieldUnit fieldUnit:fieldUnits){\r
+ nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(fieldUnit));\r
+ }\r
+ }\r
+ }\r
+ return nonCascadedCdmEntities;\r
+ }\r
+\r
+ private Collection<ICdmBase> getFieldUnitNonCascadedAssociatedElements(FieldUnit fieldUnit){\r
+ //get non cascaded element on SpecimenOrObservationBase level\r
+ Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(fieldUnit);\r
+\r
+ //get FieldUnit specific elements\r
+ GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();\r
+ if(gatheringEvent!=null){\r
+ //country\r
+ if(gatheringEvent.getCountry()!=null){\r
+ nonCascadedCdmEntities.add(gatheringEvent.getCountry());\r
+ }\r
+ //collecting areas\r
+ for (NamedArea namedArea : gatheringEvent.getCollectingAreas()) {\r
+ nonCascadedCdmEntities.add(namedArea);\r
+ }\r
+ }\r
+ for (DerivationEvent derivationEvent : fieldUnit.getDerivationEvents()) {\r
+ for (DerivedUnit derivedUnit : derivationEvent.getDerivatives()) {\r
+ nonCascadedCdmEntities.addAll(getDerivedUnitNonCascadedAssociatedElements(derivedUnit));\r
+ }\r
+ }\r
+ return nonCascadedCdmEntities;\r
+ }\r
+\r
+ private Collection<ICdmBase> getDerivedUnitNonCascadedAssociatedElements(DerivedUnit derivedUnit){\r
+ //get non cascaded element on SpecimenOrObservationBase level\r
+ Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(derivedUnit);\r
+\r
+ //get DerivedUnit specific elements\r
+ if(derivedUnit.getCollection()!=null && derivedUnit.getCollection().getInstitute()!=null){\r
+ for (DefinedTerm type : derivedUnit.getCollection().getInstitute().getTypes()) {\r
+ nonCascadedCdmEntities.add(type);\r
+ }\r
+ }\r
+ if(derivedUnit.getPreservation()!=null && derivedUnit.getPreservation().getMedium()!=null){\r
+ nonCascadedCdmEntities.add(derivedUnit.getPreservation().getMedium());\r
+ }\r
+ if(derivedUnit.getStoredUnder()!=null){\r
+ nonCascadedCdmEntities.add(derivedUnit.getStoredUnder());\r
+ }\r
+ return nonCascadedCdmEntities;\r
+ }\r
+\r
+ /**\r
+ * @param specimen\r
+ * @return\r
+ */\r
+ private Collection<ICdmBase> getSpecimenOrObservationNonCascadedAssociatedElements(\r
+ SpecimenOrObservationBase<?> specimen) {\r
+ Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();\r
+ //scan SpecimenOrObservationBase\r
+ for(DeterminationEvent determinationEvent:specimen.getDeterminations()){\r
+ //modifier\r
+ if(determinationEvent.getModifier()!=null){\r
+ nonCascadedCdmEntities.add(determinationEvent.getModifier());\r
+ }\r
+ }\r
+ //kindOfUnit\r
+ if(specimen.getKindOfUnit()!=null){\r
+ nonCascadedCdmEntities.add(specimen.getKindOfUnit());\r
+ }\r
+ //lifeStage\r
+ if(specimen.getLifeStage()!=null){\r
+ nonCascadedCdmEntities.add(specimen.getLifeStage());\r
+ }\r
+ //sex\r
+ if(specimen.getSex()!=null){\r
+ nonCascadedCdmEntities.add(specimen.getSex());\r
+ }\r
+ return nonCascadedCdmEntities;\r
+ }\r
+\r
+\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
+ DeleteResult deleteResult = new DeleteResult();\r
+ //check for derivation events\r
+ Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();\r
+ for (DerivationEvent derivationEvent : derivationEvents) {\r
+ if(!derivationEvent.getDerivatives().isEmpty()){\r
+ deleteResult.setAbort();\r
+ deleteResult.addException(new ReferencedObjectUndeletableException("Derivate with children cannot be deleted."));\r
+ return deleteResult;\r
+ }\r
+ }\r
+ //check for original (parent derivate)\r
+ if(specimen instanceof DerivedUnit){\r
+ DerivationEvent derivedFromEvent = ((DerivedUnit) specimen).getDerivedFrom();\r
+ if(derivedFromEvent!=null){\r
+ derivedFromEvent.removeDerivative((DerivedUnit) specimen);\r
+ }\r
+ }\r
+ //check for IndividualsAssociation (e.g. in TaxonDescriptions)\r
+ Collection<TaxonBase<?>> associatedTaxa = listAssociatedTaxa(specimen, null, null, null, null);\r
+ if(!associatedTaxa.isEmpty()){\r
+ if(config.isDeleteFromIndividualsAssociation()){\r
+ for (TaxonBase<?> taxonBase : associatedTaxa) {\r
+ if(taxonBase instanceof Taxon){\r
+ Set<TaxonDescription> descriptions = ((Taxon) taxonBase).getDescriptions();\r
+ for (TaxonDescription taxonDescription : descriptions) {\r
+ Set<DescriptionElementBase> elements = taxonDescription.getElements();\r
+ for (DescriptionElementBase descriptionElementBase : elements) {\r
+ if(descriptionElementBase instanceof IndividualsAssociation){\r
+ IndividualsAssociation individualsAssociation = (IndividualsAssociation) descriptionElementBase;\r
+ if(individualsAssociation.getAssociatedSpecimenOrObservation().equals(specimen)){\r
+ individualsAssociation.setAssociatedSpecimenOrObservation(null);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else{\r
+ deleteResult.addRelatedObjects(new HashSet<CdmBase>(associatedTaxa));\r
+ deleteResult.setAbort();\r
+ deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still associated with taxa."));\r
+ return deleteResult;\r
+ }\r
+ }\r
+ //check for TypeDesignations\r
+ Collection<TaxonBase<?>> typedTaxa = listTypedTaxa(specimen, null, null, null, null);\r
+ if(!typedTaxa.isEmpty()){\r
+ if(config.isdeleteFromTypeDesignation()){\r
+ for (TaxonBase<?> taxonBase : typedTaxa) {\r
+ if(taxonBase.getName()!=null){\r
+ Set<TypeDesignationBase> typeDesignations = taxonBase.getName().getTypeDesignations();\r
+ for (TypeDesignationBase typeDesignationBase : typeDesignations) {\r
+ if(typeDesignationBase instanceof SpecimenTypeDesignation){\r
+ ((SpecimenTypeDesignation) typeDesignationBase).setTypeSpecimen(null);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else{\r
+ deleteResult.addRelatedObjects(new HashSet<CdmBase>(typedTaxa));\r
+ deleteResult.setAbort();\r
+ deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is a type specimen."));\r
+ return deleteResult;\r
+ }\r
+ }\r
+ if(!config.isDeleteChildren()){\r
+ Set<CdmBase> referencingObjects = genericDao.getReferencingObjects(specimen);\r
+ for (CdmBase referencingObject : referencingObjects){\r
+ //DerivedUnit?.storedUnder\r
+ if (referencingObject.isInstanceOf(DerivedUnit.class)){\r
+ String message = "Name can't be deleted as it is used as derivedUnit#storedUnder by %s. Remove 'stored under' prior to deleting this name";\r
+ message = String.format(message, CdmBase.deproxy(referencingObject, DerivedUnit.class).getTitleCache());\r
+ }\r
+ //DescriptionElementSource#nameUsedInSource\r
+ if (referencingObject.isInstanceOf(DescriptionElementSource.class)){\r
+ String message = "Name can't be deleted as it is used as descriptionElementSource#nameUsedInSource";\r
+ }\r
+ //NameTypeDesignation#typeName\r
+ if (referencingObject.isInstanceOf(NameTypeDesignation.class)){\r
+ String message = "Name can't be deleted as it is used as a name type in a NameTypeDesignation";\r
+ }\r
+ }\r
+ deleteResult = delete(specimen);\r
+ }\r
+ else{\r
+ //TODO implement deep delete\r
+ }\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(ICdmBase from, SpecimenDeleteConfigurator config) {\r
+ DeleteResult deleteResult = new DeleteResult();\r
+ if(from instanceof Sequence){\r
+ Sequence sequence = (Sequence)from;\r
+ sequence.getDnaSample().removeSequence(sequence);\r
+ deleteResult.setStatus(DeleteStatus.OK);\r
+ }\r
+ else if(from instanceof SpecimenOrObservationBase<?>) {\r
+ deleteResult = delete((SpecimenOrObservationBase<?>) from, config);\r
+ }\r
+ return deleteResult;\r
+ }\r
+\r
+ private Set<ICdmBase> collectEntitiesToDelete(ICdmBase entity){\r
+ Set<ICdmBase> entitiesToDelete = new LinkedHashSet<ICdmBase>();\r
+\r
+ if(entity instanceof SpecimenOrObservationBase<?>){\r
+ SpecimenOrObservationBase<?> specimen = (SpecimenOrObservationBase<?>) entity;\r
+ if(entity instanceof DerivedUnit){\r
+ DerivedUnit derivedUnit = (DerivedUnit)entity;\r
+ DerivationEvent derivedFrom = derivedUnit.getDerivedFrom();\r
+ Set<SpecimenOrObservationBase> originals = derivedFrom.getOriginals();\r
+ for (SpecimenOrObservationBase<?> original: originals) {\r
+ original.removeDerivationEvent(derivedFrom);\r
+// saveOrUpdate(original);\r
+ }\r
+ }\r
+ if(entity instanceof DnaSample && ((DnaSample) entity).getRecordBasis()==SpecimenOrObservationType.DnaSample){\r
+ DnaSample dnaSample = (DnaSample)entity;\r
+ for (Sequence sequence : dnaSample.getSequences()) {\r
+ entitiesToDelete.addAll(collectEntitiesToDelete(sequence));\r
+ dnaSample.removeSequence(sequence);\r
+// saveOrUpdate(dnaSample);\r
+ }\r
+ }\r
+ Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();\r
+ for (DerivationEvent derivationEvent : derivationEvents) {\r
+ for (DerivedUnit derivedUnit : derivationEvent.getDerivatives()) {\r
+ entitiesToDelete.addAll(collectEntitiesToDelete(derivedUnit));\r
+ }\r
+ }\r
+ }\r
+ else if(entity instanceof Sequence){\r
+ Sequence sequence = (Sequence)entity;\r
+ for (SingleRead singleRead : sequence.getSingleReads()) {\r
+ entitiesToDelete.addAll(collectEntitiesToDelete(singleRead));\r
+ sequence.removeSingleRead(singleRead);\r
+ }\r
+// sequenceService.saveOrUpdate(sequence);\r
+ }\r
+ entitiesToDelete.add(entity);\r
+ return entitiesToDelete;\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<TaxonBase<?>> listAssociatedTaxa(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+ return dao.listAssociatedTaxa(specimen, null, null, null, null);\r
+ }\r
+\r
+ @Override\r
+ public Collection<TaxonBase<?>> listTypedTaxa(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+ return dao.listTypedTaxa(specimen, limit, start, orderHints, propertyPaths);\r
+ }\r
+\r