Credits in model
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / IdentifiableEntity.java
index f7cf5d39fa661534412488e78970ccc3f6d0838f..b4b69e8895acfda218e9e337d67f1adcc1f88dfd 100644 (file)
 package eu.etaxonomy.cdm.model.common;
 
 
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import javax.persistence.Column;
-import javax.persistence.ManyToMany;
+import javax.persistence.Embedded;
+import javax.persistence.FetchType;
 import javax.persistence.MappedSuperclass;
 import javax.persistence.OneToMany;
-import javax.persistence.Transient;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
+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.search.annotations.Field;
+import org.hibernate.search.annotations.FieldBridge;
+import org.hibernate.search.annotations.Fields;
 
+import eu.etaxonomy.cdm.jaxb.FormattedTextAdapter;
+import eu.etaxonomy.cdm.jaxb.LSIDAdapter;
 import eu.etaxonomy.cdm.model.media.Rights;
+import eu.etaxonomy.cdm.model.name.NonViralName;
+import eu.etaxonomy.cdm.model.name.TaxonNameBase;
+import eu.etaxonomy.cdm.model.taxon.TaxonBase;
 
 /**
  * Superclass for the primary CDM classes that can be referenced from outside via LSIDs and contain a simple generated title string as a label for human reading.
@@ -50,21 +62,32 @@ import eu.etaxonomy.cdm.model.media.Rights;
     "protectedTitleCache",
     "rights",
     "extensions",
+    "credits",
     "sources"
 })
 @MappedSuperclass
-public abstract class IdentifiableEntity<T extends IdentifiableEntity> extends AnnotatableEntity<T> implements ISourceable, IIdentifiableEntitiy<T> {
-       static Logger logger = Logger.getLogger(IdentifiableEntity.class);
+public abstract class IdentifiableEntity extends AnnotatableEntity 
+implements ISourceable, IIdentifiableEntity, Comparable<IdentifiableEntity> {
+       private static final long serialVersionUID = -5610995424730659058L;
+       private static final Logger logger = Logger.getLogger(IdentifiableEntity.class);
 
        @XmlTransient
-       public final boolean PROTECTED = true;
+       public static final boolean PROTECTED = true;
        @XmlTransient
-       public final boolean NOT_PROTECTED = false;
+       public static final boolean NOT_PROTECTED = false;
        
-       @XmlElement(name = "LSID")
-       private String lsid;
+       @XmlElement(name = "LSID", type = String.class)
+       @XmlJavaTypeAdapter(LSIDAdapter.class)
+       @Embedded
+       private LSID lsid;
        
        @XmlElement(name = "TitleCache", required = true)
+       @XmlJavaTypeAdapter(FormattedTextAdapter.class)
+       @Column(length=255, name="titleCache")
+       @Fields({@Field(index = org.hibernate.search.annotations.Index.TOKENIZED),
+                @Field(name = "titleCache_forSort", index = org.hibernate.search.annotations.Index.UN_TOKENIZED)
+       })
+       @FieldBridge(impl=StripHtmlBridge.class)
        private String titleCache;
        
        //if true titleCache will not be automatically generated/updated
@@ -73,39 +96,62 @@ public abstract class IdentifiableEntity<T extends IdentifiableEntity> extends A
        
     @XmlElementWrapper(name = "Rights")
     @XmlElement(name = "Rights")
-       private Set<Rights> rights = getNewRightsSet();
+    @OneToMany(fetch = FetchType.LAZY)
+       @Cascade({CascadeType.SAVE_UPDATE})
+       private Set<Rights> rights = new HashSet<Rights>();
+    
+    @XmlElementWrapper(name = "Credits")
+    @XmlElement(name = "Credit")
+    @IndexColumn(name="sortIndex", base = 0)
+       @OneToMany(fetch = FetchType.LAZY)
+       @Cascade({CascadeType.SAVE_UPDATE})
+    private List<Credit> credits = new ArrayList<Credit>();
        
     @XmlElementWrapper(name = "Extensions")
     @XmlElement(name = "Extension")
-       private Set<Extension> extensions = getNewExtensionSet();
+    @OneToMany(fetch = FetchType.LAZY)
+       @Cascade({CascadeType.SAVE_UPDATE})
+       private Set<Extension> extensions = new HashSet<Extension>();
        
     @XmlElementWrapper(name = "Sources")
     @XmlElement(name = "OriginalSource")
-       private Set<OriginalSource> sources = getNewOriginalSourcesSet();
+    @OneToMany(fetch = FetchType.LAZY)         
+       @Cascade({CascadeType.SAVE_UPDATE})
+       private Set<OriginalSource> sources = new HashSet<OriginalSource>();
 
        
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#getLsid()
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getLsid()
         */
-       public String getLsid(){
+       public LSID getLsid(){
                return this.lsid;
        }
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#setLsid(java.lang.String)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setLsid(java.lang.String)
         */
-       public void setLsid(String lsid){
+       public void setLsid(LSID lsid){
                this.lsid = lsid;
        }
 
+       /**
+        * By default, we expect most cdm objects to be abstract things 
+        * i.e. unable to return a data representation.
+        * 
+        * Specific subclasses (e.g. Sequence) can override if necessary.
+        */
+       public byte[] getData() {
+               return null;
+       }
+
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#generateTitle()
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#generateTitle()
         */
        public abstract String generateTitle();
 
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#getTitleCache()
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getTitleCache()
         */
-    @Transient
+       //@Transient
        public String getTitleCache(){
                if (protectedTitleCache){
                        return this.titleCache;                 
@@ -117,35 +163,19 @@ public abstract class IdentifiableEntity<T extends IdentifiableEntity> extends A
                return titleCache;
        }
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#setTitleCache(java.lang.String)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setTitleCache(java.lang.String)
         */
        public void setTitleCache(String titleCache){
                setTitleCache(titleCache, PROTECTED);
        }
        
-       //@Index(name="titleCacheIndex")
-       /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#getTitleCache()
-        */
-       @Column(length=254)
-       @Deprecated //for hibernate use only
-       protected String getPersistentTitleCache(){
-               return getTitleCache();
-       }       
-       @Deprecated //for hibernate use only
-       protected void setPersistentTitleCache(String titleCache){
-               this.titleCache = titleCache;
-       }
-       
-       
-       
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#setTitleCache(java.lang.String, boolean)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setTitleCache(java.lang.String, boolean)
         */
        public void setTitleCache(String titleCache, boolean protectCache){
                //TODO truncation of title cache
-               if (titleCache != null && titleCache.length() > 250){
-                       logger.warn("Truncation of title cache: " + this.toString());
+               if (titleCache != null && titleCache.length() > 254){
+                       logger.warn("Truncation of title cache: " + this.toString() + "/" + titleCache);
                        titleCache = titleCache.substring(0, 249) + "...";
                }
                this.titleCache = titleCache;
@@ -153,49 +183,85 @@ public abstract class IdentifiableEntity<T extends IdentifiableEntity> extends A
        }
        
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#getRights()
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getRights()
         */
-       @ManyToMany
-       @Cascade({CascadeType.SAVE_UPDATE})
-       public Set<Rights> getRights(){
-               return this.rights;
-       }
-
-       protected void setRights(Set<Rights> rights) {
-               this.rights = rights;
+       public Set<Rights> getRights() {
+               return this.rights;             
        }
+       
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#addRights(eu.etaxonomy.cdm.model.media.Rights)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addRights(eu.etaxonomy.cdm.model.media.Rights)
         */
        public void addRights(Rights right){
                this.rights.add(right);
        }
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#removeRights(eu.etaxonomy.cdm.model.media.Rights)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeRights(eu.etaxonomy.cdm.model.media.Rights)
         */
        public void removeRights(Rights right){
                this.rights.remove(right);
        }
 
+       
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#getExtensions()
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getCredits()
+        */
+       public List<Credit> getCredits() {
+               return this.credits;            
+       }
+       
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getCredits(int)
+        */
+       public Credit getCredits(int index){
+               return this.credits.get(index);
+       }
+       
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addCredit(eu.etaxonomy.cdm.model.common.Credit)
+        */
+       public void addCredit(Credit credit){
+               this.credits.add(credit);
+       }
+       
+
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addCredit(eu.etaxonomy.cdm.model.common.Credit, int)
+        */
+       public void addCredit(Credit credit, int index){
+               this.credits.add(index, credit);
+       }
+       
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeCredit(eu.etaxonomy.cdm.model.common.Credit)
+        */
+       public void removeCredit(Credit credit){
+               this.credits.remove(credit);
+       }
+       
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeCredit(int)
+        */
+       public void removeCredit(int index){
+               this.credits.remove(index);
+       }
+       
+       
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getExtensions()
         */
-       @OneToMany//(mappedBy="extendedObj")
-       @Cascade({CascadeType.SAVE_UPDATE})
        public Set<Extension> getExtensions(){
                return this.extensions;
        }
-       protected void setExtensions(Set<Extension> extensions) {
-               this.extensions = extensions;
-       }
+       
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#addExtension(eu.etaxonomy.cdm.model.common.Extension)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addExtension(eu.etaxonomy.cdm.model.common.Extension)
         */
        public void addExtension(Extension extension){
                this.extensions.add(extension);
        }
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#removeExtension(eu.etaxonomy.cdm.model.common.Extension)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeExtension(eu.etaxonomy.cdm.model.common.Extension)
         */
        public void removeExtension(Extension extension){
                this.extensions.remove(extension);
@@ -203,32 +269,27 @@ public abstract class IdentifiableEntity<T extends IdentifiableEntity> extends A
 
        
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#isProtectedTitleCache()
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#isProtectedTitleCache()
         */
        public boolean isProtectedTitleCache() {
                return protectedTitleCache;
        }
 
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#setProtectedTitleCache(boolean)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setProtectedTitleCache(boolean)
         */
        public void setProtectedTitleCache(boolean protectedTitleCache) {
                this.protectedTitleCache = protectedTitleCache;
        }
 
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#getSources()
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getSources()
         */
-       @OneToMany //(mappedBy="sourcedObj")            
-       @Cascade({CascadeType.SAVE_UPDATE})
        public Set<OriginalSource> getSources() {
                return this.sources;            
        }
-       protected void setSources(Set<OriginalSource> sources) {
-               this.sources = sources;         
-       }
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#addSource(eu.etaxonomy.cdm.model.common.OriginalSource)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addSource(eu.etaxonomy.cdm.model.common.OriginalSource)
         */
        public void addSource(OriginalSource source) {
                if (source != null){
@@ -241,14 +302,14 @@ public abstract class IdentifiableEntity<T extends IdentifiableEntity> extends A
                }
        }
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#removeSource(eu.etaxonomy.cdm.model.common.OriginalSource)
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeSource(eu.etaxonomy.cdm.model.common.OriginalSource)
         */
        public void removeSource(OriginalSource source) {
                this.sources.remove(source);            
        }
        
        /* (non-Javadoc)
-        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntitiy#toString()
+        * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#toString()
         */
         @Override
        public String toString() {
@@ -261,56 +322,89 @@ public abstract class IdentifiableEntity<T extends IdentifiableEntity> extends A
                return result;  
        }
         
+        public int compareTo(IdentifiableEntity identifiableEntity) {
+
+                int result = 0;
+                
+                if (identifiableEntity == null) {
+                        throw new NullPointerException("Cannot compare to null.");
+                }
+
+                // First, compare the name cache.
+                // TODO: Avoid using instanceof operator
+                // Use Class.getDeclaredMethod() instead to find out whether class has getNameCache() method?
+
+                // Compare name cache
+                String specifiedNameCache = "";
+                String thisNameCache = "";
+                
+                if(identifiableEntity instanceof NonViralName) {
+                        specifiedNameCache = ((NonViralName<?>)identifiableEntity).getNameCache();
+                } else if(identifiableEntity instanceof TaxonBase) {
+                        TaxonNameBase<?,?> taxonNameBase= ((TaxonBase)identifiableEntity).getName();
+                        specifiedNameCache = ((NonViralName<?>)taxonNameBase).getNameCache();
+                }
+                
+                if(this instanceof NonViralName) {
+                        thisNameCache = ((NonViralName<?>)this).getNameCache();
+                } else if(this instanceof TaxonBase) {
+                        TaxonNameBase<?,?> taxonNameBase= ((TaxonBase)this).getName();
+                        thisNameCache = ((NonViralName<?>)taxonNameBase).getNameCache();
+                }
+                
+                if (!specifiedNameCache.equals("") && !thisNameCache.equals("")) {
+                        result = thisNameCache.compareTo(specifiedNameCache);
+                }
+                
+                // Compare title cache
+                if (result == 0) {
+                        String thisTitleCache = getTitleCache();
+                        String specifiedTitleCache = identifiableEntity.getTitleCache();
+                        result = thisTitleCache.compareTo(specifiedTitleCache);
+                }
+                return result;
+        }
+        
+        
 //****************** CLONE ************************************************/
         
        /* (non-Javadoc)
         * @see eu.etaxonomy.cdm.model.common.AnnotatableEntity#clone()
         */
+       @Override
        public Object clone() throws CloneNotSupportedException{
                IdentifiableEntity result = (IdentifiableEntity)super.clone();
                
                //Extensions
-               Set<Extension> newExtensions = getNewExtensionSet();
+               result.extensions = new HashSet<Extension>();
                for (Extension extension : this.extensions ){
-                       Extension newExtension = (Extension)extension.clone(this);
-                       newExtensions.add(newExtension);
+                       Extension newExtension = (Extension)extension.clone();
+                       result.addExtension(newExtension);
                }
-               result.setExtensions(newExtensions);
                
                //OriginalSources
-               Set<OriginalSource> newOriginalSources = getNewOriginalSourcesSet();
+               result.sources = new HashSet<OriginalSource>();
                for (OriginalSource originalSource : this.sources){
-                       OriginalSource newSource = (OriginalSource)originalSource.clone(this);
-                       newOriginalSources.add(newSource);      
+                       OriginalSource newSource = (OriginalSource)originalSource.clone();
+                       result.addSource(newSource);
                }
-               result.setSources(newOriginalSources);
                
                //Rights
-               Set<Rights> rights = getNewRightsSet();
-               rights.addAll(this.rights);
-               result.setRights(rights);
+               result.rights = new HashSet<Rights>();
+        for(Rights rights : this.rights) {
+               result.addRights(rights);
+        }
                
                //result.setLsid(lsid);
                //result.setTitleCache(titleCache); 
                //result.setProtectedTitleCache(protectedTitleCache);  //must be after setTitleCache
                
                //no changes to: lsid, titleCache, protectedTitleCache
+               
+               //empty titleCache
+               if (! protectedTitleCache){
+                       titleCache = null;
+               }
                return result;
        }
-       
-       @Transient
-       private Set<Extension> getNewExtensionSet(){
-               return new HashSet<Extension>();
-       }
-       
-       @Transient
-       private Set<OriginalSource> getNewOriginalSourcesSet(){
-               return new HashSet<OriginalSource>();
-       }
-       
-       @Transient
-       private Set<Rights> getNewRightsSet(){
-               return new HashSet<Rights>();
-       }
-
 }
\ No newline at end of file