X-Git-Url: https://dev.e-taxonomy.eu/gitweb/cdmlib.git/blobdiff_plain/3c0b88b272eee69f6a815769b47ccb5b41fd619f..HEAD:/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/taxon/Synonym.java diff --git a/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/taxon/Synonym.java b/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/taxon/Synonym.java index f6fabaf95b..c8becc9ddd 100644 --- a/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/taxon/Synonym.java +++ b/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/taxon/Synonym.java @@ -1,107 +1,213 @@ /** * Copyright (C) 2007 EDIT -* European Distributed Institute of Taxonomy +* 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.model.taxon; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.ManyToOne; +import javax.persistence.Transient; +import javax.validation.constraints.NotNull; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlIDREF; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.CascadeType; +import org.hibernate.annotations.Type; +import org.hibernate.envers.Audited; +import org.hibernate.search.annotations.ContainedIn; +import org.hibernate.search.annotations.Indexed; +import org.springframework.beans.factory.annotation.Configurable; -import eu.etaxonomy.cdm.model.common.IRelated; -import eu.etaxonomy.cdm.model.name.TaxonNameBase; -import eu.etaxonomy.cdm.model.reference.ReferenceBase; - -import java.util.*; - -import javax.persistence.*; +import eu.etaxonomy.cdm.model.name.HomotypicalGroup; +import eu.etaxonomy.cdm.model.name.ITaxonNameBase; +import eu.etaxonomy.cdm.model.name.TaxonName; +import eu.etaxonomy.cdm.model.reference.Reference; +import eu.etaxonomy.cdm.strategy.cache.taxon.ITaxonCacheStrategy; +import eu.etaxonomy.cdm.validation.Level3; +import eu.etaxonomy.cdm.validation.annotation.HomotypicSynonymsShouldBelongToGroup; /** + * The class for synonyms: these are {@link TaxonBase taxa} the {@link name.TaxonName taxon names} + * of which are not used by the {@link TaxonBase#getSec() reference} to designate a real + * taxon but are mentioned as taxon names that were oder are used by some other + * unspecified references to designate (at least to some extent) the same + * particular real taxon. Synonyms that are {@link #getAcceptedTaxon() attached} to an accepted {@link Taxon taxon} + * are actually meaningless.
+ * Splitting taxa in "accepted/valid" and "synonyms" + * makes it easier to handle particular relationships between + * ("accepted/valid") {@link Taxon taxa} on the one hand and ("synonym") taxa + * on the other. + * * @author m.doering - * @version 1.0 - * @created 08-Nov-2007 13:06:55 + * @since 08-Nov-2007 13:06:55 */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "Synonym", propOrder = { + "acceptedTaxon", + "type", +}) +@XmlRootElement(name = "Synonym") @Entity -public class Synonym extends TaxonBase implements IRelated{ - static Logger logger = Logger.getLogger(Synonym.class); - - private Set synonymRelations = new HashSet(); +@Indexed(index = "eu.etaxonomy.cdm.model.taxon.TaxonBase") +@Audited +@Configurable +@HomotypicSynonymsShouldBelongToGroup(groups = Level3.class) +public class Synonym extends TaxonBase> { + private static final long serialVersionUID = 6977221584815363620L; - public static Synonym NewInstance(TaxonNameBase taxonName, ReferenceBase sec){ - Synonym result = new Synonym(); - result.setName(taxonName); - result.setSec(sec); - return result; - } - + @SuppressWarnings("unused") + private static final Logger logger = LogManager.getLogger(); + + @XmlElement(name = "acceptedTaxon") + @XmlIDREF + @XmlSchemaType(name = "IDREF") + @ManyToOne(fetch = FetchType.LAZY) + @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE}) + @ContainedIn +// @NotEmpty(groups = Level2.class,message="{eu.etaxonomy.cdm.model.taxon.Synonym.noOrphanedSynonyms.message}") +// @NotNull(groups = Level2.class) + private Taxon acceptedTaxon; + + @XmlAttribute(name ="Type") + @NotNull + @Type(type = "eu.etaxonomy.cdm.hibernate.EnumUserType", + parameters = {@org.hibernate.annotations.Parameter(name="enumClass", value="eu.etaxonomy.cdm.model.taxon.SynonymType")} + ) + private SynonymType type = SynonymType.SYNONYM_OF; + +//************************************* FACTORY ****************************/ + /** + * @see #NewInstance(TaxonName, Reference) + * @param taxonName + * @param sec + * @return + */ + public static Synonym NewInstance(ITaxonNameBase taxonName, Reference sec){ + return NewInstance(TaxonName.castAndDeproxy(taxonName), sec); + } + + /** + * Creates a new synonym instance with + * the {@link eu.etaxonomy.cdm.model.name.TaxonName taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.Reference reference} + * using it as a synonym and not as an ("accepted/correct") {@link Taxon taxon}. + * + * @param TAXON_NAME the taxon name used + * @param sec the reference using the taxon name + * @see #Synonym(TaxonName, Reference) + */ + public static Synonym NewInstance(TaxonName taxonName, Reference sec){ + Synonym result = new Synonym(taxonName, sec, null); + return result; + } + + public static Synonym NewInstance(TaxonName taxonName, Reference sec, String secDetail){ + Synonym result = new Synonym(taxonName, sec, secDetail); + return result; + } + +// ********************* CONSTRUCTORS ******************************/ + + //for hibernate use only, *packet* private required by bytebuddy //TODO should be private, but still produces Spring init errors - public Synonym(){ - } - + Synonym(){} - @OneToMany(mappedBy="relatedFrom", fetch=FetchType.EAGER) - @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE}) - public Set getSynonymRelations() { - return synonymRelations; - } - protected void setSynonymRelations(Set synonymRelations) { - this.synonymRelations = synonymRelations; - } - protected void addSynonymRelation(SynonymRelationship synonymRelation) { - this.synonymRelations.add(synonymRelation); - } - protected void removeSynonymRelation(SynonymRelationship synonymRelation) { - synonymRelation.setSynonym(null); - Taxon taxon = synonymRelation.getAcceptedTaxon(); - if (taxon != null){ - synonymRelation.setAcceptedTaxon(null); - taxon.removeSynonymRelation(synonymRelation); - } - this.synonymRelations.remove(synonymRelation); - } - - - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.model.common.IRelated#addRelationship(eu.etaxonomy.cdm.model.common.RelationshipBase) - */ - public void addRelationship(SynonymRelationship rel){ - addSynonymRelation(rel); + private Synonym(TaxonName taxonName, Reference sec, String secDetail){ + super(taxonName, sec, secDetail); } +//********************** GETTER/SETTER ******************************/ - @Transient - public Set getAcceptedTaxa() { - Settaxa=new HashSet(); - for (SynonymRelationship rel:getSynonymRelations()){ - taxa.add(rel.getAcceptedTaxon()); - } - return taxa; + /** + * Returns the "accepted/valid" {@link Taxon taxon} + * + */ + public Taxon getAcceptedTaxon() { + return this.acceptedTaxon; } + protected void setAcceptedTaxon(Taxon acceptedTaxon) { + if (acceptedTaxon == null){ + Taxon oldTaxon = this.acceptedTaxon; + this.acceptedTaxon = null; + oldTaxon.removeSynonym(this); + }else{ + if (this.acceptedTaxon != null){ + this.acceptedTaxon.removeSynonym(this, false); + } + this.acceptedTaxon = acceptedTaxon; + this.acceptedTaxon.addSynonym(this); + checkHomotypic(); + } + } + public SynonymType getType() { + return type; + } + public void setType(SynonymType type) { + this.type = type; + checkHomotypic(); + } + +//***************** METHODS **************************/ /** - * Return the synonymy relationship type for the relation to a given accepted taxon. - * If taxon is null or no relation exists to that taxon null is returned. - * @param taxon - * @return + * Returns true if this is a synonym of the given taxon. + * + * @param taxon the taxon to check synonym for + * @return true if this is a synonm of the given taxon + * + * @see #getAcceptedTaxon() */ @Transient - public SynonymRelationshipType getRelationType(Taxon taxon){ - if (taxon == null ){ - return null; - } - for (SynonymRelationship rel:getSynonymRelations()){ - Taxon acceptedTaxon = rel.getAcceptedTaxon(); - if (taxon.equals(acceptedTaxon)){ - return rel.getType(); - } - } - return null; + public boolean isSynonymOf(Taxon taxon){ + return taxon != null && taxon.equals(this.acceptedTaxon); + } + + @Override + @Transient + public boolean isOrphaned() { + return this.acceptedTaxon == null || this.acceptedTaxon.isOrphaned(); + } + + /** + * Checks if the synonym type is homotypic. If it is + * the name of this synonym is added to the {@link HomotypicalGroup + * homotypic group} of the {@link Taxon accepted taxon}. + */ + private void checkHomotypic() { + if (type != null && type.equals(SynonymType.HOMOTYPIC_SYNONYM_OF) + && acceptedTaxon != null && acceptedTaxon.getName() != null){ + acceptedTaxon.getName().getHomotypicalGroup().addTypifiedName(this.getName()); + } + } + + + +//*********************** CLONE ********************************************************/ + + @Override + public Synonym clone() { + Synonym result; + result = (Synonym)super.clone(); + + //no changes to accepted taxon, type, partial, proParte + + return result; + } -} \ No newline at end of file + + +}