commit after merge from trunc
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / name / BotanicalName.java
index e30a145e315f63ad6f506cfcfdacd77b553f2713..9e635ebe3ac060f2377d6b3459421c4286106690 100644 (file)
 package eu.etaxonomy.cdm.model.name;
 
 
-import org.apache.log4j.Logger;
-import org.hibernate.annotations.Cascade;
-import org.hibernate.annotations.CascadeType;
+import java.util.Map;
 
-import eu.etaxonomy.cdm.model.agent.Agent;
-import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
-import eu.etaxonomy.cdm.strategy.BotanicNameCacheStrategy;
-import eu.etaxonomy.cdm.strategy.TaxonNameParserBotanicalNameImpl;
+import javax.persistence.Entity;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
 
-import java.util.*;
+import org.apache.log4j.Logger;
+import org.hibernate.envers.Audited;
+import org.hibernate.search.annotations.Indexed;
+import org.springframework.beans.factory.annotation.Configurable;
 
-import javax.naming.NameParser;
-import javax.persistence.*;
+import eu.etaxonomy.cdm.common.CdmUtils;
+import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
+import eu.etaxonomy.cdm.model.common.CdmBase;
+import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
+import eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy;
+import eu.etaxonomy.cdm.strategy.parser.INonViralNameParser;
+import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
 
 /**
- * Taxon name class for plants
+ * The taxon name class for plants and fungi.
+ * <P>
+ * This class corresponds to: NameBotanical according to the ABCD schema.
+ * 
  * @author m.doering
  * @version 1.0
  * @created 08-Nov-2007 13:06:15
  */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "BotanicalName", propOrder = {
+    "anamorphic"
+})
+@XmlRootElement(name = "BotanicalName")
 @Entity
-public class BotanicalName extends NonViralName {
-       static Logger logger = Logger.getLogger(BotanicalName.class);
-       //if set: this name is a hybrid formula (a hybrid that does not have an own name) and no other hybrid flags may be set. A
-       //hybrid name  may not have either an authorteam nor other name components.
-       private boolean isHybridFormula = false;
-       private boolean isMonomHybrid = false;
-       private boolean isBinomHybrid = false;
-       private boolean isTrinomHybrid = false;
+@Indexed(index = "eu.etaxonomy.cdm.model.name.TaxonNameBase")
+@Audited
+@Configurable
+public class BotanicalName extends NonViralName<BotanicalName> implements Cloneable /*, IMergable*/ {
+       private static final long serialVersionUID = 6818651572463497727L;
+       @SuppressWarnings("unused")
+       private static final Logger logger = Logger.getLogger(BotanicalName.class);
+       
        //Only for fungi: to indicate that the type of the name is asexual or not
-       private boolean isAnamorphic;
-       private Set<HybridRelationship> hybridRelationships = new HashSet();
+    @XmlElement(name ="IsAnamorphic")
+       private boolean anamorphic;
 
-       /**
-        * @param rank
-        * @return
-        */
-       public static BotanicalName NewInstance(Rank rank){
-               return new BotanicalName(rank);
-       }
-       
-       /**
-        * Returns a parsed Name
-        * @param fullName
-        * @return
-        */
-       public static BotanicalName PARSED_NAME(String fullName){
-               return PARSED_NAME(fullName, Rank.GENUS());
-       }
-       
-       /**
-        * Returns a parsed Name
-        * @param fullName
-        * @return
-        */
-       public static BotanicalName PARSED_NAME(String fullName, Rank rank){
-               if (nameParser == null){
-                       nameParser = new TaxonNameParserBotanicalNameImpl();
-               }
-               return (BotanicalName)nameParser.parseFullName(fullName, rank);
-       }
+       static private INonViralNameParser<?> nameParser = new NonViralNameParserImpl();
        
+       // ************* CONSTRUCTORS *************/    
        //needed by hibernate
+       /** 
+        * Class constructor: creates a new botanical taxon name instance
+        * only containing the {@link eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy default cache strategy}.
+        * 
+        * @see #BotanicalName(Rank, HomotypicalGroup)
+        * @see #BotanicalName(Rank, String, String, String, String, TeamOrPersonBase, INomenclaturalReference, String, HomotypicalGroup)
+        * @see eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy
+        */
        protected BotanicalName(){
                super();
-               this.cacheStrategy = BotanicNameCacheStrategy.NewInstance();
+               this.cacheStrategy = BotanicNameDefaultCacheStrategy.NewInstance();
        }
-       public BotanicalName(Rank rank) {
-               super(rank);
-               this.cacheStrategy = BotanicNameCacheStrategy.NewInstance();
+       /** 
+        * Class constructor: creates a new botanical taxon name instance
+        * only containing its {@link Rank rank},
+        * its {@link HomotypicalGroup homotypical group} and
+        * the {@link eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy default cache strategy}.
+        * The new botanical taxon name instance will be also added to the set of
+        * botanical taxon names belonging to this homotypical group.
+        * 
+        * @param       rank  the rank to be assigned to <i>this</i> botanical taxon name
+        * @param       homotypicalGroup  the homotypical group to which <i>this</i> botanical taxon name belongs
+        * @see         #BotanicalName()
+        * @see         #BotanicalName(Rank, String, String, String, TeamOrPersonBase, INomenclaturalReference, String, HomotypicalGroup)
+        * @see         eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy
+        */
+       protected BotanicalName(Rank rank, HomotypicalGroup homotypicalGroup) {
+               super(rank, homotypicalGroup);
+               this.cacheStrategy = BotanicNameDefaultCacheStrategy.NewInstance();
        }
-       public BotanicalName(Rank rank, String genusOrUninomial, String specificEpithet, String infraSpecificEpithet, Agent combinationAuthorTeam, INomenclaturalReference nomenclaturalReference, String nomenclMicroRef) {
-               super(rank, genusOrUninomial, specificEpithet, infraSpecificEpithet, combinationAuthorTeam, nomenclaturalReference, nomenclMicroRef);
-               this.cacheStrategy = BotanicNameCacheStrategy.NewInstance();
+       /** 
+        * Class constructor: creates a new botanical taxon name instance
+        * containing its {@link Rank rank},
+        * its {@link HomotypicalGroup homotypical group},
+        * its scientific name components, its {@link eu.etaxonomy.cdm.model.agent.TeamOrPersonBase author(team)},
+        * its {@link eu.etaxonomy.cdm.model.reference.INomenclaturalReference nomenclatural reference} and
+        * the {@link eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy default cache strategy}.
+        * The new botanical taxon name instance will be also added to the set of
+        * botanical taxon names belonging to this homotypical group.
+        * 
+        * @param       rank  the rank to be assigned to <i>this</i> botanical taxon name
+        * @param       genusOrUninomial the string for <i>this</i> botanical taxon name
+        *                      if its rank is genus or higher or for the genus part
+        *                      if its rank is lower than genus
+        * @param       infraGenericEpithet  the string for the first epithet of
+        *                      <i>this</i> botanical taxon name if its rank is lower than genus
+        *                      and higher than species aggregate
+        * @param       specificEpithet  the string for the first epithet of
+        *                      <i>this</i> botanical taxon name if its rank is species aggregate or lower
+        * @param       infraSpecificEpithet  the string for the second epithet of
+        *                      <i>this</i> botanical taxon name if its rank is lower than species
+        * @param       combinationAuthorTeam  the author or the team who published <i>this</i> botanical taxon name
+        * @param       nomenclaturalReference  the nomenclatural reference where <i>this</i> botanical taxon name was published
+        * @param       nomenclMicroRef  the string with the details for precise location within the nomenclatural reference
+        * @param       homotypicalGroup  the homotypical group to which <i>this</i> botanical taxon name belongs
+        * @see         #BotanicalName()
+        * @see         #BotanicalName(Rank, HomotypicalGroup)
+        * @see         #NewInstance(Rank, String, String, String, String, TeamOrPersonBase, INomenclaturalReference, String, HomotypicalGroup)
+        * @see         eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy
+        * @see         eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy
+        * @see         eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy
+        */
+       protected BotanicalName(Rank rank, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, TeamOrPersonBase combinationAuthorTeam, INomenclaturalReference nomenclaturalReference, String nomenclMicroRef, HomotypicalGroup homotypicalGroup) {
+               super(rank, genusOrUninomial, infraGenericEpithet, specificEpithet, infraSpecificEpithet, combinationAuthorTeam, nomenclaturalReference, nomenclMicroRef, homotypicalGroup);
+               this.cacheStrategy = BotanicNameDefaultCacheStrategy.NewInstance();
        }
 
        
-       @OneToMany
-       @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
-       public Set<HybridRelationship> getHybridRelationships() {
-               return hybridRelationships;
-       }
-       protected void setHybridRelationships(Set<HybridRelationship> relationships) {
-               this.hybridRelationships = relationships;
-       }
-       public void addHybridRelationship(HybridRelationship relationship) {
-               this.hybridRelationships.add(relationship);
-       }
-       public void removeHybridRelationship(HybridRelationship relationship) {
-               this.hybridRelationships.remove(relationship);
-       }
-
-       @Transient
-       public Set<HybridRelationship> getParentRelationships() {
-               // FIXME: filter relations
-               return hybridRelationships;
+       //********* METHODS **************************************/
+       
+       /** 
+        * Creates a new botanical taxon name instance
+        * only containing its {@link Rank rank} and
+        * the {@link eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy default cache strategy}.
+        * 
+        * @param       rank    the rank to be assigned to <i>this</i> botanical taxon name
+        * @see                         #BotanicalName(Rank, HomotypicalGroup)
+        * @see                         #NewInstance(Rank, HomotypicalGroup)
+        * @see                         #NewInstance(Rank, String, String, String, String, TeamOrPersonBase, INomenclaturalReference, String, HomotypicalGroup)
+        * @see                         eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy
+        */
+       public static BotanicalName NewInstance(Rank rank){
+               return new BotanicalName(rank, null);
        }
-       @Transient
-       public Set<HybridRelationship> getChildRelationships() {
-               // FIXME: filter relations
-               return hybridRelationships;
+       /** 
+        * Creates a new botanical taxon name instance
+        * only containing its {@link Rank rank},
+        * its {@link HomotypicalGroup homotypical group} and 
+        * the {@link eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy default cache strategy}.
+        * The new botanical taxon name instance will be also added to the set of
+        * botanical taxon names belonging to this homotypical group.
+        * 
+        * @param  rank  the rank to be assigned to <i>this</i> botanical taxon name
+        * @param  homotypicalGroup  the homotypical group to which <i>this</i> botanical taxon name belongs
+        * @see    #NewInstance(Rank)
+        * @see    #NewInstance(Rank, String, String, String, String, TeamOrPersonBase, INomenclaturalReference, String, HomotypicalGroup)
+        * @see    #BotanicalName(Rank, HomotypicalGroup)
+        * @see    eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy
+        */
+       public static BotanicalName NewInstance(Rank rank, HomotypicalGroup homotypicalGroup){
+               return new BotanicalName(rank, homotypicalGroup);
        }
-
-
-
-       public boolean isHybridFormula(){
-               return this.isHybridFormula;
+       /** 
+        * Creates a new botanical taxon name instance
+        * containing its {@link Rank rank},
+        * its {@link HomotypicalGroup homotypical group},
+        * its scientific name components, its {@link eu.etaxonomy.cdm.model.agent.TeamOrPersonBase author(team)},
+        * its {@link eu.etaxonomy.cdm.model.reference.INomenclaturalReference nomenclatural reference} and
+        * the {@link eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy default cache strategy}.
+        * The new botanical taxon name instance will be also added to the set of
+        * botanical taxon names belonging to this homotypical group.
+        * 
+        * @param       rank  the rank to be assigned to <i>this</i> botanical taxon name
+        * @param       genusOrUninomial the string for <i>this</i> botanical taxon name
+        *                      if its rank is genus or higher or for the genus part
+        *                      if its rank is lower than genus
+        * @param       infraGenericEpithet  the string for the first epithet of
+        *                      <i>this</i> botanical taxon name if its rank is lower than genus
+        *                      and higher than species aggregate
+        * @param       specificEpithet  the string for the first epithet of
+        *                      <i>this</i> botanical taxon name if its rank is species aggregate or lower
+        * @param       infraSpecificEpithet  the string for the second epithet of
+        *                      <i>this</i> botanical taxon name if its rank is lower than species
+        * @param       combinationAuthorTeam  the author or the team who published <i>this</i> botanical taxon name
+        * @param       nomenclaturalReference  the nomenclatural reference where <i>this</i> botanical taxon name was published
+        * @param       nomenclMicroRef  the string with the details for precise location within the nomenclatural reference
+        * @param       homotypicalGroup  the homotypical group to which <i>this</i> botanical taxon name belongs
+        * @see         #NewInstance(Rank)
+        * @see         #NewInstance(Rank, HomotypicalGroup)
+        * @see         ZoologicalName#ZoologicalName(Rank, String, String, String, String, TeamOrPersonBase, INomenclaturalReference, String, HomotypicalGroup)
+        * @see         eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy
+        */
+       public static  BotanicalName NewInstance(Rank rank, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, TeamOrPersonBase combinationAuthorTeam, INomenclaturalReference nomenclaturalReference, String nomenclMicroRef, HomotypicalGroup homotypicalGroup) {
+               return new BotanicalName(rank, genusOrUninomial, infraGenericEpithet, specificEpithet, infraSpecificEpithet, combinationAuthorTeam, nomenclaturalReference, nomenclMicroRef, homotypicalGroup);
        }
-
+       
        /**
+        * Returns a botanical taxon name based on parsing a string representing
+        * all elements (according to the ICBN) of a botanical taxon name (where
+        * the scientific name is an uninomial) including authorship but without
+        * nomenclatural reference. If the {@link Rank rank} is not "Genus" it should be
+        * set afterwards with the {@link TaxonNameBase#setRank(Rank) setRank} methode.
         * 
-        * @param isHybridFormula    isHybridFormula
+        * @param       fullNameString  the string to be parsed 
+        * @return                                      the new botanical taxon name
         */
-       public void setHybridFormula(boolean isHybridFormula){
-               this.isHybridFormula = isHybridFormula;
-       }
-
-       public boolean isMonomHybrid(){
-               return this.isMonomHybrid;
+       public static BotanicalName PARSED_NAME(String fullNameString){
+               return PARSED_NAME(fullNameString, Rank.GENUS());
        }
-
+       
        /**
+        * Returns a botanical taxon name based on parsing a string representing
+        * all elements (according to the ICBN) of a botanical taxon name including
+        * authorship but without nomenclatural reference. The parsing result
+        * depends on the given rank of the botanical taxon name to be created.
         * 
-        * @param isMonomHybrid    isMonomHybrid
+        * @param       fullNameString  the string to be parsed 
+        * @param   rank                        the rank of the taxon name
+        * @return                                      the new botanical taxon name
         */
-       public void setMonomHybrid(boolean isMonomHybrid){
-               this.isMonomHybrid = isMonomHybrid;
+       public static BotanicalName PARSED_NAME(String fullNameString, Rank rank){
+               if (nameParser == null){
+                       nameParser = new NonViralNameParserImpl();
+               }
+               return (BotanicalName)nameParser.parseFullName(fullNameString, NomenclaturalCode.ICNAFP,  rank);
        }
-
-       public boolean isBinomHybrid(){
-               return this.isBinomHybrid;
+       
+       /**
+        * Returns a botanical taxon name based on parsing a string representing
+        * all elements (according to the ICBN) of a botanical taxon name (where
+        * the scientific name is an uninomial) including authorship and
+        * nomenclatural reference. Eventually a new {@link eu.etaxonomy.cdm.model.reference.INomenclaturalReference nomenclatural reference}
+        * instance will also be created. If the {@link Rank rank} is not "Genus" it should be
+        * set afterwards with the {@link TaxonNameBase#setRank(Rank) setRank} methode.
+        * 
+        * @param       fullNameAndReferenceString  the string to be parsed 
+        * @return                                                              the new botanical taxon name
+        */
+       public static BotanicalName PARSED_REFERENCE(String fullNameAndReferenceString){
+               return PARSED_REFERENCE(fullNameAndReferenceString, Rank.GENUS());
        }
-
+       
        /**
+        * Returns a botanical taxon name based on parsing a string representing
+        * all elements (according to the ICBN) of a botanical taxon name including
+        * authorship and nomenclatural reference. The parsing result depends on
+        * the given rank of the botanical taxon name to be created.
+        * Eventually a new {@link eu.etaxonomy.cdm.model.reference.INomenclaturalReference nomenclatural reference}
+        * instance will also be created.
         * 
-        * @param isBinomHybrid    isBinomHybrid
+        * @param       fullNameAndReferenceString  the string to be parsed 
+        * @param   rank                                                the rank of the taxon name
+        * @return                                                              the new botanical taxon name
         */
-       public void setBinomHybrid(boolean isBinomHybrid){
-               this.isBinomHybrid = isBinomHybrid;
+       public static BotanicalName PARSED_REFERENCE(String fullNameAndReferenceString, Rank rank){
+               if (nameParser == null){
+                       nameParser = new NonViralNameParserImpl();
+               }
+               return (BotanicalName)nameParser.parseReferencedName(fullNameAndReferenceString, NomenclaturalCode.ICNAFP, rank);
        }
 
-       public boolean isTrinomHybrid(){
-               return this.isTrinomHybrid;
-       }
+//***********************      
 
+       private static Map<String, java.lang.reflect.Field> allFields = null;
+       @Override
+    protected Map<String, java.lang.reflect.Field> getAllFields(){
+       if (allFields == null){
+                       allFields = CdmUtils.getAllFields(this.getClass(), CdmBase.class, false, false, false, true);
+               }
+       return allFields;
+    }
+
+//************************* 
+       
        /**
-        * 
-        * @param isTrinomHybrid    isTrinomHybrid
+        * Returns the boolean value of the flag indicating whether the specimen
+        * type of <i>this</i> botanical taxon name for a fungus is asexual (true) or not
+        * (false). This applies only in case of fungi. The Article 59 of the ICBN
+        * permits mycologists to give asexually reproducing fungi (anamorphs)
+        * separate names from their sexual states (teleomorphs).
+        *  
+        * @return  the boolean value of the isAnamorphic flag
         */
-       public void setTrinomHybrid(boolean isTrinomHybrid){
-               this.isTrinomHybrid = isTrinomHybrid;
+       public boolean isAnamorphic(){
+               return this.anamorphic;
        }
 
-       public boolean isAnamorphic(){
-               return this.isAnamorphic;
+       /**
+        * @see  #isAnamorphic()
+        */
+       public void setAnamorphic(boolean anamorphic){
+               this.anamorphic = anamorphic;
+       }
+       
+       
+       /**
+        * Returns the {@link NomenclaturalCode nomenclatural code} that governs
+        * the construction of <i>this</i> botanical taxon name, that is the
+        * International Code of Botanical Nomenclature. This method overrides
+        * the getNomeclaturalCode method from {@link NonViralName NonViralName}.
+        *
+        * @return  the nomenclatural code for plants
+        * @see         NonViralName#isCodeCompliant()
+        * @see         TaxonNameBase#getHasProblem()
+        */
+       @Override
+       public NomenclaturalCode getNomenclaturalCode(){
+               return NomenclaturalCode.ICNAFP;
        }
 
+       
        /**
+        * Checks if this name is an autonym.<BR>
+        * An autonym is a taxon name that has equal specific and infra specific epithets.<BR>
+        * {@link http://ibot.sav.sk/icbn/frameset/0010Ch2Sec1a006.htm#6.8. Vienna Code ยง6.8}
+        * @return true, if name has Rank, Rank is below species and species epithet equals infraSpeciesEpithtet, else false
+        */
+       @Override
+       public boolean isAutonym(){
+               if (this.getRank() != null && this.getSpecificEpithet() != null && this.getInfraSpecificEpithet() != null && 
+                               this.getRank().isInfraSpecific() && this.getSpecificEpithet().trim().equals(this.getInfraSpecificEpithet().trim())){
+                       return true;
+               }else{
+                       return false;
+               }
+       }
+       
+//*********************** CLONE ********************************************************/
+       
+       /** 
+        * Clones <i>this</i> botanical name. This is a shortcut that enables to create
+        * a new instance that differs only slightly from <i>this</i> botanical name by
+        * modifying only some of the attributes.
         * 
-        * @param isAnamorphic    isAnamorphic
+        * @see eu.etaxonomy.cdm.model.name.NonViralName#clone()
+        * @see java.lang.Object#clone()
         */
-       public void setAnamorphic(boolean isAnamorphic){
-               this.isAnamorphic = isAnamorphic;
+       @Override
+       public Object clone() {
+               BotanicalName result = (BotanicalName)super.clone();
+               //no changes to: title, authorTeam, hasProblem, nomenclaturallyRelevant, uri
+               return result;
        }
 
+
 }
\ No newline at end of file