free text search: better querying for 'isNotNull' and code harmonization
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / description / DescriptionElementBase.java
index 7ce66f61f538e1e3a41869e7fe470b19c1939f02..879cf25a82261acaa8e6720958d00612d60049ab 100644 (file)
@@ -1,8 +1,8 @@
 /**
 * 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.description;
 
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -35,21 +37,26 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.apache.log4j.Logger;
 import org.hibernate.annotations.Cascade;
 import org.hibernate.annotations.CascadeType;
+import org.hibernate.annotations.IndexColumn;
 import org.hibernate.envers.Audited;
-import org.hibernate.search.annotations.Indexed;
 import org.hibernate.search.annotations.IndexedEmbedded;
 
 import eu.etaxonomy.cdm.jaxb.MultilanguageTextAdapter;
+import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
+import eu.etaxonomy.cdm.model.common.DescriptionElementSource;
+import eu.etaxonomy.cdm.model.common.IMultiLanguageTextHolder;
+import eu.etaxonomy.cdm.model.common.ISourceable;
 import eu.etaxonomy.cdm.model.common.Language;
 import eu.etaxonomy.cdm.model.common.LanguageString;
 import eu.etaxonomy.cdm.model.common.MultilanguageText;
-import eu.etaxonomy.cdm.model.common.ReferencedEntityBase;
 import eu.etaxonomy.cdm.model.common.TermVocabulary;
-import eu.etaxonomy.cdm.model.media.IMediaEntity;
 import eu.etaxonomy.cdm.model.media.Media;
 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
+import eu.etaxonomy.cdm.model.reference.Reference;
 import eu.etaxonomy.cdm.model.taxon.Taxon;
+import eu.etaxonomy.cdm.strategy.merge.Merge;
+import eu.etaxonomy.cdm.strategy.merge.MergeMode;
 
 /**
  * The upmost (abstract) class for a piece of information) about
@@ -57,261 +64,418 @@ import eu.etaxonomy.cdm.model.taxon.Taxon;
  * A concrete description element assigns descriptive data to one {@link Feature feature}.<BR>
  * Experts use the word feature for the property itself but not for the actual
  * description element. Therefore naming this class FeatureBase would have
- * leaded to confusion.  
+ * leaded to confusion.
  * <P>
  * This class corresponds to: <ul>
  * <li> DescriptionsBaseType according to the the SDD schema
  * <li> InfoItem according to the TDWG ontology
  * <li> MeasurementOrFactAtomised according to the ABCD schema
  * </ul>
- * 
+ *
  * @author m.doering
  * @version 1.0
  * @created 08-Nov-2007 13:06:24
  */
 @XmlAccessorType(XmlAccessType.FIELD)
 @XmlType(name = "DescriptionElementBase", propOrder = {
-           "feature",
-           "modifiers",
-           "modifyingText",
-           "media",
-           "inDescription"
+        "feature",
+        "modifiers",
+        "modifyingText",
+        "media",
+        "inDescription",
+        "sources"
 })
 @Entity
 @Audited
 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
-public abstract class DescriptionElementBase extends ReferencedEntityBase implements IMediaEntity {
-       private static final long serialVersionUID = 5000910777835755905L;
-       @SuppressWarnings("unused")
-       private static final Logger logger = Logger.getLogger(DescriptionElementBase.class);
-       
-       //type, category of information. In structured descriptions characters
-       @XmlElement(name = "Feature")
+public abstract class DescriptionElementBase extends AnnotatableEntity implements ISourceable<DescriptionElementSource>, IModifiable, IMultiLanguageTextHolder{
+    private static final long serialVersionUID = 5000910777835755905L;
+    @SuppressWarnings("unused")
+    private static final Logger logger = Logger.getLogger(DescriptionElementBase.class);
+
+    //type, category of information. In structured descriptions characters
+    @XmlElement(name = "Feature")
     @XmlIDREF
     @XmlSchemaType(name = "IDREF")
     @ManyToOne(fetch = FetchType.LAZY)
-       @IndexedEmbedded
-       private Feature feature;
-       
-       @XmlElementWrapper(name = "Modifiers")
-       @XmlElement(name = "Modifier")
-       @XmlIDREF
+    //@Cascade(CascadeType.SAVE_UPDATE)
+    @Cascade(CascadeType.MERGE)
+    @IndexedEmbedded(depth=3)
+    private Feature feature;
+
+    @XmlElementWrapper(name = "Modifiers")
+    @XmlElement(name = "Modifier")
+    @XmlIDREF
     @XmlSchemaType(name = "IDREF")
-       @ManyToMany(fetch = FetchType.LAZY)
+    @ManyToMany(fetch = FetchType.LAZY)
     @JoinTable(name="DescriptionElementBase_Modifier")
-       private Set<Modifier> modifiers = new HashSet<Modifier>();
-       
-       @XmlElement(name = "ModifyingText")
+    @IndexedEmbedded(depth=3)
+    private Set<Modifier> modifiers = new HashSet<Modifier>();
+
+    @XmlElement(name = "ModifyingText")
     @XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
     @OneToMany(fetch = FetchType.LAZY)
     @JoinTable(name = "DescriptionElementBase_ModifyingText")
-       private Map<Language,LanguageString> modifyingText = new HashMap<Language,LanguageString>();
-       
-       @XmlElementWrapper(name = "Media")
-       @XmlElement(name = "Medium")
+    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
+    @IndexedEmbedded
+    private Map<Language,LanguageString> modifyingText = new HashMap<Language,LanguageString>();
+
+    @XmlElementWrapper(name = "Media")
+    @XmlElement(name = "Medium")
     @XmlIDREF
     @XmlSchemaType(name = "IDREF")
     @ManyToMany(fetch = FetchType.LAZY)
-       @Cascade({CascadeType.SAVE_UPDATE})
-       private Set<Media> media = new HashSet<Media>();
-       
-       @XmlElement(name = "InDescription")
-       @XmlIDREF
+    @IndexColumn(name="sortIndex", base = 0)
+    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
+    private List<Media> media = new ArrayList<Media>();
+
+    @XmlElement(name = "InDescription")
+    @XmlIDREF
     @XmlSchemaType(name = "IDREF")
     @ManyToOne(fetch = FetchType.LAZY)
     @Cascade(CascadeType.SAVE_UPDATE)
-       @IndexedEmbedded
+    @IndexedEmbedded
     private DescriptionBase inDescription;
 
-       // ************* CONSTRUCTORS *************/    
-       /** 
-        * Class constructor: creates a new empty description element instance.
-        * 
-        * @see #DescriptionElementBase(Feature)
-        */
-       protected DescriptionElementBase(){
-       }
-       
-       /** 
-        * Class constructor: creates a new description element instance with the
-        * given {@link Feature feature} that is described or measured.
-        * 
-        * @param       feature the feature described or measured
-        * @see                         #DescriptionElementBase()
-        */
-       protected DescriptionElementBase(Feature feature){
-               if (feature == null){
-                       feature = Feature.UNKNOWN();
-               }
-               this.feature = feature; 
-       }
-
-       /** 
-        * Returns the set of {@link Media media} (that is pictures, movies,
-        * recorded sounds ...) <i>this</i> description element is based on.
-        */
-       public Set<Media> getMedia(){
-               return this.media;
-       }
-
-       /**
-        * Adds a {@link Media media} to the set of {@link #getMedia() media}
-        * <i>this</i> description element is based on.
-        * 
-        * @param media the media to be added to <i>this</i> description element
-        * @see                 #getMedia()
-        */
-       public void addMedia(Media media){
-               this.media.add(media);
-       }
-       /** 
-        * Removes one element from the set of {@link #getMedia() media}
-        * <i>this</i> description element is based on.
-        *
-        * @param  media        the media which should be removed
-        * @see                 #getMedia()
-        * @see                 #addMedia(Media)
-        */
-       public void removeMedia(Media media){
-               this.media.remove(media);
-       }
-       
-       /**
-        * Returns the {@link DescriptionBase description} that <i>this</i> DescriptionElement is
-        * part of. 
-        * @return
-        */
-       public DescriptionBase getInDescription() {
-               return this.inDescription;
-       }
-       
-       /**
-        * @see #setInDescription() 
-        */
-       protected void setInDescription(DescriptionBase inDescription) {
-               this.inDescription = inDescription;
-       }
-
-       /**
-        * Does exactly the same as getFeature().
-        * @author ben.clark
-        * FIXME Is there a need to have two methods with different names which do the same thing?
-        * 
-        * @see #getFeature() 
-        */
-       public Feature getType(){
-               return this.getFeature();
-       }
-       /**
-        * Does exactly the same as setFeature(Feature).
-        * 
-        * @param type  the feature to be described or measured
-        * @see                 #setFeature(Feature) 
-        * @see                 #getFeature() 
-        */
-       public void setType(Feature type){
-               this.setFeature(type);
-       }
-       
-       /** 
-        * Returns the {@link Feature feature} <i>this</i> description element is for.
-        * A feature is a property that can be described or measured but not the
-        * description or the measurement itself.
-        */
-       public Feature getFeature(){
-               return this.feature;
-       }
-       
-       /**
-        * @see #getFeature() 
-        */
-       public void setFeature(Feature feature){
-               this.feature = feature;
-       }
-
-       /** 
-        * Returns the set of {@link Modifier modifiers} used to qualify the validity of
-        * <i>this</i> description element. This is only metainformation.
-        */
-       public Set<Modifier> getModifiers(){
-               return this.modifiers;
-       }
-
-       /**
-        * Adds a {@link Modifier modifier} to the set of {@link #getModifiers() modifiers}
-        * used to qualify the validity of <i>this</i> description element.
-        * 
-        * @param modifier      the modifier to be added to <i>this</i> description element
-        * @see                         #getModifiers()
-        */
-       public void addModifier(Modifier modifier){
-               this.modifiers.add(modifier);
-       }
-       /** 
-        * Removes one element from the set of {@link #getModifiers() modifiers}
-        * used to qualify the validity of <i>this</i> description element.
-        *
-        * @param  modifier     the modifier which should be removed
-        * @see                 #getModifiers()
-        * @see                 #addModifier(Modifier)
-        */
-       public void removeModifier(Modifier modifier){
-               this.modifiers.remove(modifier);
-       }
-
-       
-       /** 
-        * Returns the {@link MultilanguageText multilanguage text} used to qualify the validity
-        * of <i>this</i> description element.  The different {@link LanguageString language strings}
-        * contained in the multilanguage text should all have the same meaning.<BR>
-        * A multilanguage text does not belong to a controlled {@link TermVocabulary term vocabulary}
-        * as a {@link Modifier modifier} does.
-        * <P>
-        * NOTE: the actual content of <i>this</i> description element is NOT
-        * stored in the modifying text. This is only metainformation
-        * (like "Some experts express doubt about this assertion").
-        */
-       public Map<Language,LanguageString> getModifyingText(){
-               return this.modifyingText;
-       }
-
-       /**
-        * Adds a translated {@link LanguageString text in a particular language}
-        * to the {@link MultilanguageText multilanguage text} used to qualify the validity
-        * of <i>this</i> description element.
-        * 
-        * @param description   the language string describing the validity
-        *                                              in a particular language
-        * @see                                 #getModifyingText()
-        * @see                                 #addModifyingText(String, Language)
-        */
-       public LanguageString addModifyingText(LanguageString description){
-               return this.modifyingText.put(description.getLanguage(),description);
-       }
-       /**
-        * Creates a {@link LanguageString language string} based on the given text string
-        * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text} 
-        * used to qualify the validity of <i>this</i> description element.
-        * 
-        * @param text          the string describing the validity
-        *                                      in a particular language
-        * @param language      the language in which the text string is formulated
-        * @see                         #getModifyingText()
-        * @see                         #addModifyingText(LanguageString)
-        */
-       public LanguageString addModifyingText(String text, Language language){
-               return this.modifyingText.put(language, LanguageString.NewInstance(text, language));
-       }
-       /** 
-        * Removes from the {@link MultilanguageText multilanguage text} used to qualify the validity
-        * of <i>this</i> description element the one {@link LanguageString language string}
-        * with the given {@link Language language}.
-        *
-        * @param  language     the language in which the language string to be removed
-        *                                      has been formulated
-        * @see                 #getModifyingText()
-        */
-       public LanguageString removeModifyingText(Language language){
-               return this.modifyingText.remove(language);
-       }
+    @XmlElementWrapper(name = "Sources")
+    @XmlElement(name = "DescriptionElementSource")
+    @OneToMany(fetch = FetchType.LAZY)
+    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
+    @Merge(MergeMode.ADD_CLONE)
+    private Set<DescriptionElementSource> sources = new HashSet<DescriptionElementSource>();
+
+
+
+    // ************* CONSTRUCTORS *************/
+    /**
+     * Class constructor: creates a new empty description element instance.
+     *
+     * @see #DescriptionElementBase(Feature)
+     */
+    protected DescriptionElementBase(){
+    }
+
+    /**
+     * Class constructor: creates a new description element instance with the
+     * given {@link Feature feature} that is described or measured.
+     *
+     * @param  feature the feature described or measured
+     * @see                    #DescriptionElementBase()
+     */
+    protected DescriptionElementBase(Feature feature){
+        if (feature == null){
+            feature = Feature.UNKNOWN();
+        }
+        this.feature = feature;
+    }
+
+    /**
+     * Returns the list of {@link Media media} (that is pictures, movies,
+     * recorded sounds ...) <i>this</i> description element is based on.
+     */
+    public List<Media> getMedia(){
+        return this.media;
+    }
+
+    /**
+     * Adds a {@link Media media} to the list of {@link #getMedia() media}
+     * <i>this</i> description element is based on.
+     *
+     * @param media    the media to be added to <i>this</i> description element
+     * @see                    #getMedia()
+     */
+    public void addMedia(Media media){
+        this.media.add(media);
+    }
+    /**
+     * Removes one element from the list of {@link #getMedia() media}
+     * <i>this</i> description element is based on.
+     *
+     * @param  media   the media which should be removed
+     * @see                    #getMedia()
+     * @see                    #addMedia(Media)
+     */
+    public void removeMedia(Media media){
+        this.media.remove(media);
+    }
+
+    /**
+     * Returns the {@link DescriptionBase description} that <i>this</i> DescriptionElement is
+     * part of.
+     * @return
+     */
+    public DescriptionBase getInDescription() {
+        return this.inDescription;
+    }
+
+    /**
+     * @see    #setInDescription()
+     */
+    protected void setInDescription(DescriptionBase inDescription) {
+        this.inDescription = inDescription;
+    }
+
+    /**
+     * Returns the {@link Feature feature} <i>this</i> description element is for.
+     * A feature is a property that can be described or measured but not the
+     * description or the measurement itself.
+     */
+    public Feature getFeature(){
+        return this.feature;
+    }
+
+    /**
+     * @see    #getFeature()
+     */
+    public void setFeature(Feature feature){
+        this.feature = feature;
+    }
+
+    /**
+     * Returns the set of {@link Modifier modifiers} used to qualify the validity of
+     * <i>this</i> description element. This is only metainformation.
+     */
+    public Set<Modifier> getModifiers(){
+        return this.modifiers;
+    }
+
+    /**
+     * Adds a {@link Modifier modifier} to the set of {@link #getModifiers() modifiers}
+     * used to qualify the validity of <i>this</i> description element.
+     *
+     * @param modifier the modifier to be added to <i>this</i> description element
+     * @see                            #getModifiers()
+     */
+    public void addModifier(Modifier modifier){
+        this.modifiers.add(modifier);
+    }
+    /**
+     * Removes one element from the set of {@link #getModifiers() modifiers}
+     * used to qualify the validity of <i>this</i> description element.
+     *
+     * @param  modifier        the modifier which should be removed
+     * @see                    #getModifiers()
+     * @see                    #addModifier(Modifier)
+     */
+    public void removeModifier(Modifier modifier){
+        this.modifiers.remove(modifier);
+    }
+
+
+    /**
+     * Returns the {@link MultilanguageText multilanguage text} used to qualify the validity
+     * of <i>this</i> description element.  The different {@link LanguageString language strings}
+     * contained in the multilanguage text should all have the same meaning.<BR>
+     * A multilanguage text does not belong to a controlled {@link TermVocabulary term vocabulary}
+     * as a {@link Modifier modifier} does.
+     * <P>
+     * NOTE: the actual content of <i>this</i> description element is NOT
+     * stored in the modifying text. This is only metainformation
+     * (like "Some experts express doubt about this assertion").
+     */
+    public Map<Language,LanguageString> getModifyingText(){
+        return this.modifyingText;
+    }
+
+    /**
+     * Adds a translated {@link LanguageString text in a particular language}
+     * to the {@link MultilanguageText multilanguage text} used to qualify the validity
+     * of <i>this</i> description element.
+     *
+     * @param description      the language string describing the validity
+     *                                                 in a particular language
+     * @see                                    #getModifyingText()
+     * @see                                    #putModifyingText(Language, String)
+     * @deprecated                     should follow the put semantic of maps, this method will be removed in v4.0
+     *                                                 Use the {@link #putModifyingText(LanguageString) putModifyingText} method
+     */
+    public LanguageString addModifyingText(LanguageString description){
+        return this.putModifyingText(description);
+    }
+
+    /**
+     * Adds a translated {@link LanguageString text in a particular language}
+     * to the {@link MultilanguageText multilanguage text} used to qualify the validity
+     * of <i>this</i> description element.
+     *
+     * @param description      the language string describing the validity
+     *                                                 in a particular language
+     * @see                                    #getModifyingText()
+     * @see                                    #putModifyingText(Language, String)
+     */
+    public LanguageString putModifyingText(LanguageString description){
+        return this.modifyingText.put(description.getLanguage(),description);
+    }
+    /**
+     * Creates a {@link LanguageString language string} based on the given text string
+     * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text}
+     * used to qualify the validity of <i>this</i> description element.
+     *
+     * @param text             the string describing the validity
+     *                                         in a particular language
+     * @param language the language in which the text string is formulated
+     * @see                            #getModifyingText()
+     * @see                            #putModifyingText(LanguageString)
+     * @deprecated             should follow the put semantic of maps, this method will be removed in v4.0
+     *                                         Use the {@link #putModifyingText(Language, String) putModifyingText} method
+     */
+    public LanguageString addModifyingText(String text, Language language){
+        return this.putModifyingText(language, text);
+    }
+
+    /**
+     * Creates a {@link LanguageString language string} based on the given text string
+     * and the given {@link Language language} and adds it to the {@link MultilanguageText multilanguage text}
+     * used to qualify the validity of <i>this</i> description element.
+     *
+     * @param language the language in which the text string is formulated
+     * @param text             the string describing the validity
+     *                                         in a particular language
+     *
+     * @see                            #getModifyingText()
+     * @see                            #putModifyingText(LanguageString)
+     *
+     */
+    public LanguageString putModifyingText(Language language, String text){
+        return this.modifyingText.put(language, LanguageString.NewInstance(text, language));
+    }
+    /**
+     * Removes from the {@link MultilanguageText multilanguage text} used to qualify the validity
+     * of <i>this</i> description element the one {@link LanguageString language string}
+     * with the given {@link Language language}.
+     *
+     * @param  language        the language in which the language string to be removed
+     *                                         has been formulated
+     * @see                    #getModifyingText()
+     */
+    public LanguageString removeModifyingText(Language language){
+        return this.modifyingText.remove(language);
+    }
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.model.common.ISourceable#getSources()
+     */
+    public Set<DescriptionElementSource> getSources() {
+        return this.sources;
+    }
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.model.common.ISourceable#addSource(eu.etaxonomy.cdm.model.common.IOriginalSource)
+     */
+    public void addSource(DescriptionElementSource source) {
+        if (source != null){
+            DescriptionElementBase oldSourcedObj = source.getSourcedObj();
+            if (oldSourcedObj != null && oldSourcedObj != this){
+                oldSourcedObj.getSources().remove(source);
+            }
+            this.sources.add(source);
+            source.setSourcedObj(this);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.model.common.ISourceable#addSource(java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.reference.Reference, java.lang.String)
+     */
+    public DescriptionElementSource addSource(String id, String idNamespace, Reference citation, String microCitation) {
+        if (id == null && idNamespace == null && citation == null && microCitation == null){
+            return null;
+        }
+        DescriptionElementSource source = DescriptionElementSource.NewInstance(id, idNamespace, citation, microCitation);
+        addSource(source);
+        return source;
+    }
+
+    public void addSource(String id, String idNamespace, Reference citation, String microReference, TaxonNameBase nameUsedInSource, String originalNameString){
+        DescriptionElementSource newSource = DescriptionElementSource.NewInstance(id, idNamespace, citation, microReference, nameUsedInSource, originalNameString);
+        addSource(newSource);
+    }
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.model.common.ISourceable#removeSource(eu.etaxonomy.cdm.model.common.IOriginalSource)
+     */
+    public void removeSource(DescriptionElementSource source) {
+        this.sources.remove(source);
+    }
+
+// ******************* METHODS *************************************************************/
+
+    protected Map<TermVocabulary, List<Modifier>> makeModifierMap(){
+        Map<TermVocabulary, List<Modifier>> result = new HashMap<TermVocabulary, List<Modifier>>();
+        for (Modifier modifier : getModifiers()){
+            TermVocabulary<Modifier> voc = modifier.getVocabulary();
+            if (result.get(voc) == null){
+                result.put(voc, new ArrayList<Modifier>());
+            }
+            result.get(voc).add(modifier);
+        }
+        return result;
+    }
+
+    public List<Modifier> getModifiers(TermVocabulary voc){
+        List<Modifier> result = makeModifierMap().get(voc);
+        if (result == null){
+            result = new ArrayList<Modifier>();
+        }
+        return result;
+    }
+
+
+
+//************************** CLONE **********************************************************/
+
+    /**
+     * Clones the description element. The element is <b>not</b> added to the same
+     * description as the orginal element (inDescription is set to <code>null</null>).
+     * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
+     */
+    @Override
+    public Object clone() throws CloneNotSupportedException{
+        DescriptionElementBase result = (DescriptionElementBase)super.clone();
+
+        //inDescription
+        result.inDescription = null;
+
+        //Sources
+        result.sources = new HashSet<DescriptionElementSource>();
+        for (DescriptionElementSource source : getSources()){
+            DescriptionElementSource newSource = (DescriptionElementSource)source.clone();
+            result.addSource(newSource);
+        }
+
+        //media
+        result.media = new ArrayList<Media>();
+        for (Media media : getMedia()){
+            result.media.add(media);
+        }
+
+        //modifying text
+        result.modifyingText = new HashMap<Language, LanguageString>();
+        for (Language language : getModifyingText().keySet()){
+            //TODO clone needed? See also IndividualsAssociation
+            LanguageString newLanguageString = (LanguageString)getModifyingText().get(language).clone();
+            result.modifyingText.put(language, newLanguageString);
+        }
+
+        //modifiers
+        result.modifiers = new HashSet<Modifier>();
+        for (Modifier modifier : getModifiers()){
+            result.modifiers.add(modifier);
+        }
+
+        //no changes to: feature
+        return result;
+    }
+
+    /**
+     * Clones the description element.<BR>
+     * The new element is added to the <code>description</code>.<BR>
+     * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
+     */
+    public DescriptionElementBase clone(DescriptionBase description) throws CloneNotSupportedException{
+        DescriptionElementBase result = (DescriptionElementBase)clone();
+        description.addElement(result);
+        return result;
+    }
+
+
 }
\ No newline at end of file