X-Git-Url: https://dev.e-taxonomy.eu/gitweb/cdmlib.git/blobdiff_plain/fcd1daf643c47ede1fab4ba26835ce47917d9f22..05cdf24eb427a5e1bae9582208aaa65d8468a815:/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonServiceImpl.java diff --git a/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonServiceImpl.java b/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonServiceImpl.java index e3e72a46e1..7c21fc2d77 100644 --- a/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonServiceImpl.java +++ b/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonServiceImpl.java @@ -21,6 +21,8 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import javax.persistence.EntityNotFoundException; + import org.apache.log4j.Logger; import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.queryParser.ParseException; @@ -35,11 +37,15 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase; import eu.etaxonomy.cdm.api.service.config.IFindTaxaAndNamesConfigurator; +import eu.etaxonomy.cdm.api.service.config.IncludedTaxonConfiguration; import eu.etaxonomy.cdm.api.service.config.MatchingTaxonConfigurator; import eu.etaxonomy.cdm.api.service.config.SynonymDeletionConfigurator; import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator; import eu.etaxonomy.cdm.api.service.config.TaxonNodeDeletionConfigurator.ChildHandling; +import eu.etaxonomy.cdm.api.service.dto.FindByIdentifierDTO; +import eu.etaxonomy.cdm.api.service.dto.IncludedTaxaDTO; import eu.etaxonomy.cdm.api.service.exception.DataChangeNoRollbackException; import eu.etaxonomy.cdm.api.service.exception.HomotypicalGroupChangeException; import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException; @@ -62,6 +68,7 @@ import eu.etaxonomy.cdm.hibernate.search.GroupByTaxonClassBridge; import eu.etaxonomy.cdm.hibernate.search.MultilanguageTextFieldBridge; import eu.etaxonomy.cdm.model.CdmBaseType; import eu.etaxonomy.cdm.model.common.CdmBase; +import eu.etaxonomy.cdm.model.common.DefinedTerm; import eu.etaxonomy.cdm.model.common.IdentifiableEntity; import eu.etaxonomy.cdm.model.common.IdentifiableSource; import eu.etaxonomy.cdm.model.common.Language; @@ -77,7 +84,7 @@ import eu.etaxonomy.cdm.model.description.Distribution; import eu.etaxonomy.cdm.model.description.Feature; import eu.etaxonomy.cdm.model.description.IIdentificationKey; import eu.etaxonomy.cdm.model.description.PolytomousKeyNode; -import eu.etaxonomy.cdm.model.description.PresenceAbsenceTermBase; +import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm; import eu.etaxonomy.cdm.model.description.SpecimenDescription; import eu.etaxonomy.cdm.model.description.TaxonDescription; import eu.etaxonomy.cdm.model.description.TaxonInteraction; @@ -86,18 +93,21 @@ 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.MediaUtils; -import eu.etaxonomy.cdm.model.molecular.Amplification; +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.HomotypicalGroup; +import eu.etaxonomy.cdm.model.name.NameRelationship; import eu.etaxonomy.cdm.model.name.Rank; import eu.etaxonomy.cdm.model.name.TaxonNameBase; import eu.etaxonomy.cdm.model.name.ZoologicalName; import eu.etaxonomy.cdm.model.occurrence.DerivedUnit; +import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent; import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase; import eu.etaxonomy.cdm.model.reference.Reference; import eu.etaxonomy.cdm.model.taxon.Classification; +import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode; import eu.etaxonomy.cdm.model.taxon.Synonym; import eu.etaxonomy.cdm.model.taxon.SynonymRelationship; import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType; @@ -111,6 +121,7 @@ import eu.etaxonomy.cdm.persistence.dao.common.IOrderedTermVocabularyDao; import eu.etaxonomy.cdm.persistence.dao.initializer.AbstractBeanInitializer; import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao; import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao; +import eu.etaxonomy.cdm.persistence.dao.taxon.IClassificationDao; import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao; import eu.etaxonomy.cdm.persistence.fetch.CdmFetch; import eu.etaxonomy.cdm.persistence.query.MatchMode; @@ -145,7 +156,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase getAllSynonyms(int limit, int start) { - return dao.getAllSynonyms(limit, start); - } - - /** - * FIXME Candidate for harmonization - * list(Taxon.class, ...) - * (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int) - */ - @Override - public List getAllTaxa(int limit, int start) { - return dao.getAllTaxa(limit, start); - } - /** * FIXME Candidate for harmonization * merge with getRootTaxa(Reference sec, ..., ...) @@ -216,18 +207,11 @@ public class TaxonServiceImpl extends IdentifiableServiceBase getRootTaxa(Rank rank, Reference sec, boolean onlyWithChildren,boolean withMisapplications, List propertyPaths) { return dao.getRootTaxa(rank, sec, null, onlyWithChildren, withMisapplications, propertyPaths); } - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int) - */ @Override public List getAllRelationships(int limit, int start){ return dao.getAllRelationships(limit, start); @@ -294,10 +278,12 @@ public class TaxonServiceImpl extends IdentifiableServiceBase heteroSynonyms = acceptedTaxon.getSynonymsInGroup(synonymHomotypicGroup); + Set basionymsAndReplacedSynonyms = synonymHomotypicGroup.getBasionymAndReplacedSynonymRelations(); for (Synonym heteroSynonym : heteroSynonyms){ if (synonym.equals(heteroSynonym)){ acceptedTaxon.removeSynonym(heteroSynonym, false); + }else{ //move synonyms in same homotypic group to new accepted taxon heteroSynonym.replaceAcceptedTaxon(newAcceptedTaxon, relTypeForGroup, copyCitationInfo, citation, microCitation); @@ -310,7 +296,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase synonymName = synonym.getName(); - // remove synonym from taxon + /* // remove synonym from taxon toTaxon.removeSynonym(synonym); - +*/ // Create a taxon with synonym name Taxon fromTaxon = Taxon.NewInstance(synonymName, null); @@ -338,7 +326,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase findTaxaByName(Class clazz, String uninomial, String infragenericEpithet, String specificEpithet, String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) { Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank); @@ -441,9 +427,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase(pageNumber, numberOfResults, pageSize, results); } - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxaByName(java.lang.Class, java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer) - */ @Override public List listTaxaByName(Class clazz, String uninomial, String infragenericEpithet, String specificEpithet, String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) { Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank); @@ -456,9 +439,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase listToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths){ Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo); @@ -470,9 +450,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase pageToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths) { Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo); @@ -484,9 +461,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase(pageNumber, numberOfResults, pageSize, results); } - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.ITaxonService#listFromTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List) - */ @Override public List listFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths){ Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom); @@ -498,9 +472,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase pageFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths) { Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom); @@ -512,15 +483,50 @@ public class TaxonServiceImpl extends IdentifiableServiceBase(pageNumber, numberOfResults, pageSize, results); } - /** - * @param taxon - * @param includeRelationships - * @param maxDepth - * @param limit - * @param starts - * @param propertyPaths - * @return an List which is not specifically ordered - */ + @Override + public List listAcceptedTaxaFor(UUID synonymUuid, UUID classificationUuid, Integer pageSize, Integer pageNumber, + List orderHints, List propertyPaths){ + return pageAcceptedTaxaFor(synonymUuid, classificationUuid, pageSize, pageNumber, orderHints, propertyPaths).getRecords(); + } + + @Override + public Pager pageAcceptedTaxaFor(UUID synonymUuid, UUID classificationUuid, Integer pageSize, Integer pageNumber, + List orderHints, List propertyPaths){ + + List list = new ArrayList(); + Long count = 0l; + + Synonym synonym = null; + + try { + synonym = (Synonym) dao.load(synonymUuid); + } catch (ClassCastException e){ + throw new EntityNotFoundException("The TaxonBase entity referenced by " + synonymUuid + " is not a Synonmy"); + } catch (NullPointerException e){ + throw new EntityNotFoundException("No TaxonBase entity found for " + synonymUuid); + } + + Classification classificationFilter = null; + if(classificationUuid != null){ + try { + classificationFilter = classificationDao.load(classificationUuid); + } catch (NullPointerException e){ + throw new EntityNotFoundException("No Classification entity found for " + classificationUuid); + } + if(classificationFilter == null){ + + } + } + + count = dao.countAcceptedTaxaFor(synonym, classificationFilter) ; + if(count > (pageSize * pageNumber)){ + list = dao.listAcceptedTaxaFor(synonym, classificationFilter, pageSize, pageNumber, orderHints, propertyPaths); + } + + return new DefaultPagerImpl(pageNumber, count.intValue(), pageSize, list); + } + + @Override public Set listRelatedTaxa(Taxon taxon, Set includeRelationships, Integer maxDepth, Integer limit, Integer start, List propertyPaths) { @@ -548,6 +554,10 @@ public class TaxonServiceImpl extends IdentifiableServiceBase(pageNumber, numberOfResults, pageSize, results); } + /* (non-Javadoc) + * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List) + */ + @Override + public List> getSynonymsByHomotypicGroup(Taxon taxon, List propertyPaths){ + List> result = new ArrayList>(); + Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths); + + //homotypic + result.add(t.getHomotypicSynonymsByHomotypicGroup()); + + //heterotypic + List homotypicalGroups = t.getHeterotypicSynonymyGroups(); + for(HomotypicalGroup homotypicalGroup : homotypicalGroups){ + result.add(t.getSynonymsInGroup(homotypicalGroup)); + } + + return result; + + } + /* (non-Javadoc) * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List) */ @@ -642,25 +673,23 @@ public class TaxonServiceImpl extends IdentifiableServiceBase> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator){ - - List> result = new ArrayList>(); -// Class clazz = null; -// if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) { -// clazz = TaxonBase.class; -// //propertyPath.addAll(configurator.getTaxonPropertyPath()); -// //propertyPath.addAll(configurator.getSynonymPropertyPath()); -// } else if(configurator.isDoTaxa()) { -// clazz = Taxon.class; -// //propertyPath = configurator.getTaxonPropertyPath(); -// } else if (configurator.isDoSynonyms()) { -// clazz = Synonym.class; -// //propertyPath = configurator.getSynonymPropertyPath(); -// } + public List> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator){ + List> results = new ArrayList>(); - result = dao.getTaxaByNameForEditor(configurator.isDoTaxa(), configurator.isDoSynonyms(), configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas()); - return result; + + if (configurator.isDoSynonyms() || configurator.isDoTaxa() || configurator.isDoNamesWithoutTaxa()){ + results = dao.getTaxaByNameForEditor(configurator.isDoTaxa(), configurator.isDoSynonyms(), configurator.isDoNamesWithoutTaxa(), configurator.isDoMisappliedNames(),configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas()); + } + if (configurator.isDoTaxaByCommonNames()) { + //if(configurator.getPageSize() == null ){ + List> commonNameResults = dao.getTaxaByCommonNameForEditor(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas()); + if(commonNameResults != null){ + results.addAll(commonNameResults); + } + // } + } + return results; } /* (non-Javadoc) @@ -736,10 +765,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase configurator.getPageSize() * configurator.getPageNumber()){ - List commonNameResults = dao.getTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas(), configurator.getPageSize(), configurator.getPageNumber(), configurator.getTaxonPropertyPath()); - for( Object[] entry : commonNameResults ) { - taxa.add((TaxonBase) entry[0]); - } + List commonNameResults = dao.getTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas(), configurator.getPageSize(), configurator.getPageNumber(), configurator.getTaxonPropertyPath()); + taxa.addAll(commonNameResults); } if(taxa != null){ results.addAll(taxa); @@ -795,21 +822,26 @@ public class TaxonServiceImpl extends IdentifiableServiceBase propertyPath) { + logger.trace("listMedia() - START"); + Set taxa = new HashSet(); List taxonMedia = new ArrayList(); + List nonImageGalleryImages = new ArrayList(); if (limitToGalleries == null) { limitToGalleries = false; } // --- resolve related taxa - if (includeRelationships != null) { + if (includeRelationships != null && ! includeRelationships.isEmpty()) { + logger.trace("listMedia() - resolve related taxa"); taxa = listRelatedTaxa(taxon, includeRelationships, null, null, null, null); } taxa.add((Taxon) dao.load(taxon.getUuid())); if(includeTaxonDescriptions != null && includeTaxonDescriptions){ + logger.trace("listMedia() - includeTaxonDescriptions"); List taxonDescriptions = new ArrayList(); // --- TaxonDescriptions for (Taxon t : taxa) { @@ -819,14 +851,23 @@ public class TaxonServiceImpl extends IdentifiableServiceBase specimensOrObservations = new HashSet(); // --- Specimens for (Taxon t : taxa) { @@ -867,7 +908,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase dnaRelatedMedia = new HashSet(); for (SingleRead singleRead : sequence.getSingleReads()){ - Amplification amplification = singleRead.getAmplification(); + AmplificationResult amplification = singleRead.getAmplificationResult(); dnaRelatedMedia.add(amplification.getGelPhoto()); dnaRelatedMedia.add(singleRead.getPherogram()); dnaRelatedMedia.remove(null); @@ -880,6 +921,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase nameDescriptions = new HashSet(); for (Taxon t : taxa) { @@ -897,7 +939,12 @@ public class TaxonServiceImpl extends IdentifiableServiceBase synRelsToDelete = new HashSet(); synRelsToDelete.addAll(taxon.getSynonymRelations()); for (SynonymRelationship synRel : synRelsToDelete){ Synonym synonym = synRel.getSynonym(); + // taxon.removeSynonymRelation will set the accepted taxon and the synonym to NULL + // this will cause hibernate to delete the relationship since + // the SynonymRelationship field on both is annotated with removeOrphan + // so no further explicit deleting of the relationship should be done here taxon.removeSynonymRelation(synRel, removeSynonymNameFromHomotypicalGroup); + + // --- DeleteSynonymsIfPossible if (config.isDeleteSynonymsIfPossible()){ //TODO which value boolean newHomotypicGroupIfNeeded = true; SynonymDeletionConfigurator synConfig = new SynonymDeletionConfigurator(); - deleteSynonym(synonym, taxon, synConfig); - }else{ - deleteSynonymRelationships(synonym, taxon); } + // relationship will be deleted by hibernate automatically, + // see comment above and http://dev.e-taxonomy.eu/trac/ticket/3797 + // else{ + // deleteSynonymRelationships(synonym, taxon); + // } } } - // TaxonRelationship + // --- DeleteTaxonRelationships if (! config.isDeleteTaxonRelationships()){ if (taxon.getTaxonRelations().size() > 0){ - String message = "Taxon can't be deleted as it is related to another taxon. Remove taxon from all relations to other taxa prior to deletion."; - throw new ReferencedObjectUndeletableException(message); + String message = "Taxon can't be deleted as it is related to another taxon. " + + "Remove taxon from all relations to other taxa prior to deletion."; + // throw new ReferencedObjectUndeletableException(message); } } else{ for (TaxonRelationship taxRel: taxon.getTaxonRelations()){ - - - if (config.isDeleteMisappliedNamesAndInvalidDesignations()){ if (taxRel.getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR()) || taxRel.getType().equals(TaxonRelationshipType.INVALID_DESIGNATION_FOR())){ if (taxon.equals(taxRel.getToTaxon())){ @@ -1002,38 +1060,39 @@ public class TaxonServiceImpl extends IdentifiableServiceBase descriptions = taxon.getDescriptions(); - - for (TaxonDescription desc: descriptions){ - //TODO use description delete configurator ? - //FIXME check if description is ALWAYS deletable - if (desc.getDescribedSpecimenOrObservation() != null){ - String message = "Taxon can't be deleted as it is used in a TaxonDescription" + - " which also describes specimens or abservations"; - throw new ReferencedObjectUndeletableException(message); - } - descriptionService.delete(desc); - taxon.removeDescription(desc); + Set descriptions = taxon.getDescriptions(); + List removeDescriptions = new ArrayList(); + for (TaxonDescription desc: descriptions){ + //TODO use description delete configurator ? + //FIXME check if description is ALWAYS deletable + if (desc.getDescribedSpecimenOrObservation() != null){ + String message = "Taxon can't be deleted as it is used in a TaxonDescription" + + " which also describes specimens or abservations"; + //throw new ReferencedObjectUndeletableException(message); } + removeDescriptions.add(desc); + descriptionService.delete(desc); + + } + for (TaxonDescription desc: removeDescriptions){ + taxon.removeDescription(desc); + } } - //check references with only reverse mapping + /* //check references with only reverse mapping String message = checkForReferences(taxon); if (message != null){ - throw new ReferencedObjectUndeletableException(message.toString()); - } + //throw new ReferencedObjectUndeletableException(message.toString()); + }*/ if (! config.isDeleteTaxonNodes() || (!config.isDeleteInAllClassifications() && classification == null )){ - if (taxon.getTaxonNodes().size() > 0){ - message = "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion or define a classification where it should be deleted or adapt the taxon deletion configurator."; - throw new ReferencedObjectUndeletableException(message); - } + //if (taxon.getTaxonNodes().size() > 0){ + // message = "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion or define a classification where it should be deleted or adapt the taxon deletion configurator."; + // throw new ReferencedObjectUndeletableException(message); + //} }else{ if (taxon.getTaxonNodes().size() != 0){ Set nodes = taxon.getTaxonNodes(); @@ -1058,16 +1117,18 @@ public class TaxonServiceImpl extends IdentifiableServiceBase nodesList = new ArrayList(); + Set nodesList = new HashSet(); nodesList.addAll(taxon.getTaxonNodes()); - for (TaxonNode taxonNode: nodesList){ - if(deleteChildren){ - Object[] childNodes = taxonNode.getChildNodes().toArray(); + for (ITaxonTreeNode treeNode: nodesList){ + TaxonNode taxonNode = (TaxonNode) treeNode; + if(!deleteChildren){ + /* Object[] childNodes = taxonNode.getChildNodes().toArray(); + //nodesList.addAll(taxonNode.getChildNodes()); for (Object childNode: childNodes){ TaxonNode childNodeCast = (TaxonNode) childNode; deleteTaxon(childNodeCast.getTaxon(), config, classification); @@ -1077,9 +1138,11 @@ public class TaxonServiceImpl extends IdentifiableServiceBase exceptions = new ArrayList(); +// for (String message: referencedObjects){ +// ReferencedObjectUndeletableException exception = new ReferencedObjectUndeletableException(message); +// exceptions.add(exception); +// } +// result.addExceptions(exceptions); +// result.setError(); +// +// } + return result; } @@ -1166,22 +1258,39 @@ public class TaxonServiceImpl extends IdentifiableServiceBase list = genericDao.getCdmBasesByFieldAndClass(PolytomousKeyNode.class, "taxon", taxon); + if (!list.isEmpty()) { + result = true; + } + return result; + } + @Transactional(readOnly = false) public UUID delete(Synonym syn){ UUID result = syn.getUuid(); @@ -1189,13 +1298,15 @@ public class TaxonServiceImpl extends IdentifiableServiceBase taxonSet = new HashSet(); - if (taxon != null){ - taxonSet.add(taxon); - }else{ - taxonSet.addAll(synonym.getAcceptedTaxa()); - } - for (Taxon relatedTaxon : taxonSet){ -// dao.deleteSynonymRelationships(synonym, relatedTaxon); - relatedTaxon.removeSynonym(synonym, config.isNewHomotypicGroupIfNeeded()); - } - this.saveOrUpdate(synonym); - //TODO remove name from homotypical group? + if (result.isOk()){ + synonym = CdmBase.deproxy(dao.merge(synonym), Synonym.class); - //remove synonym (if necessary) + //remove synonymRelationship + Set taxonSet = new HashSet(); + if (taxon != null){ + taxonSet.add(taxon); + }else{ + taxonSet.addAll(synonym.getAcceptedTaxa()); + } + for (Taxon relatedTaxon : taxonSet){ + relatedTaxon = HibernateProxyHelper.deproxy(relatedTaxon, Taxon.class); + relatedTaxon.removeSynonym(synonym, false); + this.saveOrUpdate(relatedTaxon); + } + this.saveOrUpdate(synonym); + //TODO remove name from homotypical group? - if (synonym.getSynonymRelations().isEmpty()){ - TaxonNameBase name = synonym.getName(); - synonym.setName(null); - dao.delete(synonym); + //remove synonym (if necessary) + + if (synonym.getSynonymRelations().isEmpty()){ + TaxonNameBase name = synonym.getName(); + synonym.setName(null); + dao.delete(synonym); + + //remove name if possible (and required) + if (name != null && config.isDeleteNameIfPossible()){ + + DeleteResult nameDeleteresult = nameService.delete(name, config.getNameDeletionConfig()); + if (nameDeleteresult.isAbort()){ + result.addExceptions(nameDeleteresult.getExceptions()); + result.addUpdatedObject(name); + } - //remove name if possible (and required) - if (name != null && config.isDeleteNameIfPossible()){ - try{ - nameService.delete(name, config.getNameDeletionConfig()); - }catch (ReferencedObjectUndeletableException ex){ - System.err.println("Name wasn't deleted as it is referenced"); - if (logger.isDebugEnabled()) { - logger.debug("Name wasn't deleted as it is referenced"); - } } + + }else { + result.setError(); + result.addException(new ReferencedObjectUndeletableException("Synonym can not be deleted it is used in a synonymRelationship.")); + return result; } + + } + return result; +// else{ +// List exceptions = new ArrayList(); +// for (String message :messages){ +// exceptions.add(new ReferencedObjectUndeletableException(message)); +// } +// result.setError(); +// result.addExceptions(exceptions); +// return result; +// } + + } @@ -1497,6 +1634,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase orderHints, List propertyPaths) throws CorruptIndexException, IOException, ParseException { - LuceneSearch luceneSearch = prepareFindByFullTextSearch(clazz, queryString, classification, languages, highlightFragments); + LuceneSearch luceneSearch = prepareFindByFullTextSearch(clazz, queryString, classification, languages, highlightFragments, null); // --- execute search TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber); @@ -1565,7 +1705,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase> findByDistribution(List areaFilter, List> statusFilter, + public Pager> findByDistribution(List areaFilter, List statusFilter, Classification classification, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths) throws IOException, ParseException { @@ -1593,18 +1733,21 @@ public class TaxonServiceImpl extends IdentifiableServiceBase clazz, String queryString, Classification classification, List languages, - boolean highlightFragments) { + boolean highlightFragments, SortField[] sortFields) { BooleanQuery finalQuery = new BooleanQuery(); BooleanQuery textQuery = new BooleanQuery(); LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, GroupByTaxonClassBridge.GROUPBY_TAXON_FIELD, TaxonBase.class); QueryFactory taxonBaseQueryFactory = luceneIndexToolProvider.newQueryFactoryFor(TaxonBase.class); - SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)}; + if(sortFields == null){ + sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)}; + } luceneSearch.setSortFields(sortFields); // ---- search criteria @@ -1637,16 +1780,17 @@ public class TaxonServiceImpl extends IdentifiableServiceBasedirect, everted: {@link Direction.relatedTo}: TaxonRelationShip.relatedTo.id --> Taxon.id *
  • inverse: {@link Direction.relatedFrom}: TaxonRelationShip.relatedFrom.id --> Taxon.id
  • *
      - * * @param queryString * @param classification * @param languages * @param highlightFragments + * @param sortFields TODO + * * @return * @throws IOException */ protected LuceneSearch prepareFindByTaxonRelationFullTextSearch(TaxonRelationshipEdge edge, String queryString, Classification classification, List languages, - boolean highlightFragments) throws IOException { + boolean highlightFragments, SortField[] sortFields) throws IOException { String fromField; String queryTermField; @@ -1675,7 +1819,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase> findTaxaAndNamesByFullText( EnumSet searchModes, String queryString, Classification classification, - Set namedAreas, Set> distributionStatus, List languages, + Set namedAreas, Set distributionStatus, List languages, boolean highlightFragments, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths) throws CorruptIndexException, IOException, ParseException, LuceneMultiSearchException { @@ -1716,13 +1862,13 @@ public class TaxonServiceImpl extends IdentifiableServiceBase namedAreaList = null; - List>distributionStatusList = null; + ListdistributionStatusList = null; if(namedAreas != null){ namedAreaList = new ArrayList(namedAreas.size()); namedAreaList.addAll(namedAreas); } if(distributionStatus != null){ - distributionStatusList = new ArrayList>(distributionStatus.size()); + distributionStatusList = new ArrayList(distributionStatus.size()); distributionStatusList.addAll(distributionStatus); } @@ -1731,6 +1877,20 @@ public class TaxonServiceImpl extends IdentifiableServiceBase 0; List luceneSearches = new ArrayList(); @@ -1788,7 +1948,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase namedAreaList, - List> distributionStatusList, + List distributionStatusList, QueryFactory queryFactory ) throws IOException { @@ -1975,7 +2138,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase namedAreaList, - List> distributionStatusList, QueryFactory queryFactory) { + List distributionStatusList, QueryFactory queryFactory) { BooleanQuery areaQuery = new BooleanQuery(); // area field from Distribution areaQuery.add(queryFactory.newEntityIdsQuery("area.id", namedAreaList), Occur.MUST); @@ -2001,7 +2164,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase namedAreaList, List> distributionStatusList, + List namedAreaList, List distributionStatusList, Classification classification) throws IOException { BooleanQuery finalQuery = new BooleanQuery(); @@ -2067,7 +2230,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase orderHints, List propertyPaths) throws CorruptIndexException, IOException, ParseException, LuceneMultiSearchException { LuceneSearch luceneSearchByDescriptionElement = prepareByDescriptionElementFullTextSearch(null, queryString, classification, null, languages, highlightFragments); - LuceneSearch luceneSearchByTaxonBase = prepareFindByFullTextSearch(null, queryString, classification, languages, highlightFragments); + LuceneSearch luceneSearchByTaxonBase = prepareFindByFullTextSearch(null, queryString, classification, languages, highlightFragments, null); LuceneMultiSearch multiSearch = new LuceneMultiSearch(luceneIndexToolProvider, luceneSearchByDescriptionElement, luceneSearchByTaxonBase); @@ -2237,7 +2400,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase nodes = taxon.getTaxonNodes(); - List taxonNames = new ArrayList(); + List taxonNames = new ArrayList(); for (TaxonNode node: nodes){ // HashMap synonymsGenus = new HashMap(); // Changed this to be able to store the idInSource to a genusName @@ -2590,8 +2753,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase listClassifications(TaxonBase taxonBase, Integer limit, Integer start, List propertyPaths) { @@ -2878,9 +3032,291 @@ public class TaxonServiceImpl extends IdentifiableServiceBase synonymName = fromTaxon.getName(); + Synonym synonym = Synonym.NewInstance(synonymName, fromTaxon.getSec()); + + // Remove concept relation from taxon + toTaxon.removeTaxon(fromTaxon, oldRelationshipType); + + + + + // Create a new synonym for the taxon + SynonymRelationship synonymRelationship; + if (synonymRelationshipType != null + && synonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){ + synonymRelationship = toTaxon.addHomotypicSynonym(synonym, null, null); + } else{ + synonymRelationship = toTaxon.addHeterotypicSynonymName(synonymName); + } + + this.saveOrUpdate(toTaxon); + //TODO: configurator and classification + TaxonDeletionConfigurator config = new TaxonDeletionConfigurator(); + config.setDeleteNameIfPossible(false); + this.deleteTaxon(fromTaxon, config, null); + return synonymRelationship.getSynonym(); + + } + @Override + public DeleteResult isDeletable(TaxonBase taxonBase, DeleteConfiguratorBase config){ + DeleteResult result = new DeleteResult(); + Set references = commonService.getReferencingObjectsForDeletion(taxonBase); + if (taxonBase instanceof Taxon){ + TaxonDeletionConfigurator taxonConfig = (TaxonDeletionConfigurator) config; + result = isDeletableForTaxon(references, taxonConfig); + }else{ + SynonymDeletionConfigurator synonymConfig = (SynonymDeletionConfigurator) config; + result = isDeletableForSynonym(references, synonymConfig); + } + return result; + } + + private DeleteResult isDeletableForSynonym(Set references, SynonymDeletionConfigurator config){ + String message; + DeleteResult result = new DeleteResult(); + for (CdmBase ref: references){ + if (!(ref instanceof SynonymRelationship || ref instanceof Taxon || ref instanceof TaxonNameBase )){ + message = "The Synonym can't be deleted as long as it is referenced by " + ref.getClass().getSimpleName() + " with id "+ ref.getId(); + result.addException(new ReferencedObjectUndeletableException(message)); + result.addRelatedObject(ref); + result.setAbort(); + } + } + + return result; + } + private DeleteResult isDeletableForTaxon(Set references, TaxonDeletionConfigurator config){ + String message = null; + DeleteResult result = new DeleteResult(); + for (CdmBase ref: references){ + if (!(ref instanceof TaxonNameBase)){ + if (!config.isDeleteSynonymRelations() && (ref instanceof SynonymRelationship)){ + message = "The Taxon can't be deleted as long as it has synonyms."; + + } + if (!config.isDeleteDescriptions() && (ref instanceof DescriptionBase)){ + message = "The Taxon can't be deleted as long as it has factual data."; + + } + + if (!config.isDeleteTaxonNodes() && (ref instanceof TaxonNode)){ + message = "The Taxon can't be deleted as long as it belongs to a taxon node."; + + } + if (!config.isDeleteTaxonRelationships() && (ref instanceof TaxonNode)){ + if (!config.isDeleteMisappliedNamesAndInvalidDesignations() && (((TaxonRelationship)ref).getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())|| ((TaxonRelationship)ref).getType().equals(TaxonRelationshipType.INVALID_DESIGNATION_FOR()))){ + message = "The Taxon can't be deleted as long as it has misapplied names or invalid designations."; + + } else{ + message = "The Taxon can't be deleted as long as it belongs to a taxon node."; + + } + } + if (ref instanceof PolytomousKeyNode){ + message = "The Taxon can't be deleted as long as it is referenced by a polytomous key node."; + + } + + if (HibernateProxyHelper.isInstanceOf(ref, IIdentificationKey.class)){ + message = "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name"; + + + } + + + /* //PolytomousKeyNode + if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){ + String message = "Taxon" + taxon.getTitleCache() + " can't be deleted as it is used in polytomous key node"; + return message; + }*/ + + //TaxonInteraction + if (ref.isInstanceOf(TaxonInteraction.class)){ + message = "Taxon can't be deleted as it is used in taxonInteraction#taxon2"; + + } + + //TaxonInteraction + if (ref.isInstanceOf(DeterminationEvent.class)){ + message = "Taxon can't be deleted as it is used in a determination event"; + + } + + } + if (message != null){ + result.addException(new ReferencedObjectUndeletableException(message)); + result.addRelatedObject(ref); + result.setAbort(); + } + } + + return result; + } + + @Override + public IncludedTaxaDTO listIncludedTaxa(UUID taxonUuid, IncludedTaxonConfiguration config) { + IncludedTaxaDTO result = new IncludedTaxaDTO(taxonUuid); + + //preliminary implementation + + Set taxa = new HashSet(); + TaxonBase taxonBase = find(taxonUuid); + if (taxonBase == null){ + return new IncludedTaxaDTO(); + }else if (taxonBase.isInstanceOf(Taxon.class)){ + Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class); + taxa.add(taxon); + }else if (taxonBase.isInstanceOf(Synonym.class)){ + //TODO partial synonyms ?? + //TODO synonyms in general + Synonym syn = CdmBase.deproxy(taxonBase, Synonym.class); + taxa.addAll(syn.getAcceptedTaxa()); + }else{ + throw new IllegalArgumentException("Unhandled class " + taxonBase.getClass().getSimpleName()); + } + + Set related = makeRelatedIncluded(taxa, result, config); + int i = 0; + while((! related.isEmpty()) && i++ < 100){ //to avoid + related = makeRelatedIncluded(related, result, config); + } + + return result; + } + + /** + * Computes all children and conceptually congruent and included taxa and adds them to the existingTaxa + * data structure. + * @return the set of conceptually related taxa for further use + */ + /** + * @param uncheckedTaxa + * @param existingTaxa + * @param config + * @return + */ + private Set makeRelatedIncluded(Set uncheckedTaxa, IncludedTaxaDTO existingTaxa, IncludedTaxonConfiguration config) { + + //children + Set taxonNodes = new HashSet(); + for (Taxon taxon: uncheckedTaxa){ + taxonNodes.addAll(taxon.getTaxonNodes()); + } + + Set children = new HashSet(); + if (! config.onlyCongruent){ + for (TaxonNode node: taxonNodes){ + List childNodes = nodeService.loadChildNodesOfTaxonNode(node, null, true, false); + for (TaxonNode child : childNodes){ + children.add(child.getTaxon()); + } + } + children.remove(null); // just to be on the save side + } + + Iterator it = children.iterator(); + while(it.hasNext()){ + UUID uuid = it.next().getUuid(); + if (existingTaxa.contains(uuid)){ + it.remove(); + }else{ + existingTaxa.addIncludedTaxon(uuid, new ArrayList(), false); + } + } + + //concept relations + Set uncheckedAndChildren = new HashSet(uncheckedTaxa); + uncheckedAndChildren.addAll(children); + + Set relatedTaxa = makeConceptIncludedTaxa(uncheckedAndChildren, existingTaxa, config); + + + Set result = new HashSet(relatedTaxa); + return result; + } + + /** + * Computes all conceptually congruent or included taxa and adds them to the existingTaxa data structure. + * @return the set of these computed taxa + */ + private Set makeConceptIncludedTaxa(Set unchecked, IncludedTaxaDTO existingTaxa, IncludedTaxonConfiguration config) { + Set result = new HashSet(); + for (Taxon taxon : unchecked){ + Set fromRelations = taxon.getRelationsFromThisTaxon(); + Set toRelations = taxon.getRelationsToThisTaxon(); + for (TaxonRelationship fromRel : fromRelations){ + if (config.includeDoubtful == false && fromRel.isDoubtful()){ + continue; + } + if (fromRel.getType().equals(TaxonRelationshipType.CONGRUENT_TO()) || + !config.onlyCongruent && fromRel.getType().equals(TaxonRelationshipType.INCLUDES()) || + !config.onlyCongruent && fromRel.getType().equals(TaxonRelationshipType.CONGRUENT_OR_INCLUDES()) + ){ + result.add(fromRel.getToTaxon()); + } + } + for (TaxonRelationship toRel : toRelations){ + if (config.includeDoubtful == false && toRel.isDoubtful()){ + continue; + } + if (toRel.getType().equals(TaxonRelationshipType.CONGRUENT_TO())){ + result.add(toRel.getFromTaxon()); + } + } + } + Iterator it = result.iterator(); + while(it.hasNext()){ + UUID uuid = it.next().getUuid(); + if (existingTaxa.contains(uuid)){ + it.remove(); + }else{ + existingTaxa.addIncludedTaxon(uuid, new ArrayList(), false); + } + } + return result; + } + + @Override + public List findTaxaByName(MatchingTaxonConfigurator config){ + List taxonList = dao.getTaxaByName(true, false, false, config.getTaxonNameTitle(), null, MatchMode.EXACT, null, 0, 0, config.getPropertyPath()); + return taxonList; + } + + @Override + @Transactional(readOnly = true) + public Pager> findByIdentifier( + Class clazz, String identifier, DefinedTerm identifierType, TaxonNode subtreeFilter, + MatchMode matchmode, boolean includeEntity, Integer pageSize, + Integer pageNumber, List propertyPaths) { + if (subtreeFilter == null){ + return findByIdentifier(clazz, identifier, identifierType, matchmode, includeEntity, pageSize, pageNumber, propertyPaths); + } + + Integer numberOfResults = dao.countByIdentifier(clazz, identifier, identifierType, subtreeFilter, matchmode); + List daoResults = new ArrayList(); + if(numberOfResults > 0) { // no point checking again + daoResults = dao.findByIdentifier(clazz, identifier, identifierType, subtreeFilter, + matchmode, includeEntity, pageSize, pageNumber, propertyPaths); + } + + List> result = new ArrayList>(); + for (Object[] daoObj : daoResults){ + if (includeEntity){ + result.add(new FindByIdentifierDTO((DefinedTerm)daoObj[0], (String)daoObj[1], (S)daoObj[2])); + }else{ + result.add(new FindByIdentifierDTO((DefinedTerm)daoObj[0], (String)daoObj[1], (UUID)daoObj[2], (String)daoObj[3])); + } + } + return new DefaultPagerImpl>(pageNumber, numberOfResults, pageSize, result); + } }