Fix upgrade issues after rebase #4716
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / CdmBase.java
index 1d4d31531a24d5691a218248f9f62fee4b1ae757..0ffa01ec8d5a76c2ceba1270a4aa67d28c6250ca 100644 (file)
@@ -13,6 +13,8 @@ import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
 import java.io.Serializable;
 import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.UUID;
 
 import javax.persistence.Basic;
@@ -37,9 +39,10 @@ import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
 import org.apache.log4j.Logger;
-import org.hibernate.annotations.GenericGenerator;
 import org.hibernate.annotations.NaturalId;
 import org.hibernate.annotations.Type;
+import org.hibernate.envers.Audited;
+import org.hibernate.search.annotations.Analyze;
 import org.hibernate.search.annotations.DocumentId;
 import org.hibernate.search.annotations.Field;
 import org.hibernate.search.annotations.FieldBridge;
@@ -49,10 +52,11 @@ import org.joda.time.DateTime;
 
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
 import eu.etaxonomy.cdm.hibernate.search.DateTimeBridge;
-import eu.etaxonomy.cdm.hibernate.search.PaddedIntegerBridge;
+import eu.etaxonomy.cdm.hibernate.search.NotNullAwareIdBridge;
 import eu.etaxonomy.cdm.hibernate.search.UuidBridge;
 import eu.etaxonomy.cdm.jaxb.DateTimeAdapter;
 import eu.etaxonomy.cdm.jaxb.UUIDAdapter;
+import eu.etaxonomy.cdm.model.NewEntityListener;
 import eu.etaxonomy.cdm.strategy.match.Match;
 import eu.etaxonomy.cdm.strategy.match.MatchMode;
 
@@ -78,7 +82,7 @@ import eu.etaxonomy.cdm.strategy.match.MatchMode;
     "createdBy"
 })
 @MappedSuperclass
-public abstract class CdmBase implements Serializable, ICdmBase, Cloneable{
+public abstract class CdmBase implements Serializable, ICdmBase, ISelfDescriptive, Cloneable{
     private static final long serialVersionUID = -3053225700018294809L;
     @SuppressWarnings("unused")
     private static final Logger logger = Logger.getLogger(CdmBase.class);
@@ -87,29 +91,37 @@ public abstract class CdmBase implements Serializable, ICdmBase, Cloneable{
     @XmlTransient
     private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
 
+    @Transient
+    @XmlTransient
+    private static NewEntityListener newEntityListener;
+
     //@XmlAttribute(name = "id", required = true)
     @XmlTransient
     @Id
-//     @GeneratedValue(generator = "system-increment")
+//     @GeneratedValue(generator = "system-increment")  //see also AuditEvent.revisionNumber
 //     @GeneratedValue(generator = "enhanced-table")
     @GeneratedValue(generator = "custom-enhanced-table")
     @DocumentId
-    @FieldBridge(impl=PaddedIntegerBridge.class)
+    @FieldBridge(impl=NotNullAwareIdBridge.class)
+    //commented since Hibernate Search 5.5.x since HSEARCH000247 is thrown otherwise
+//    @Field(store=Store.YES, termVector=TermVector.NO)
     @Match(MatchMode.IGNORE)
     @NotNull
     @Min(0)
+    @Audited
     private int id;
 
     @XmlAttribute(required = true)
     @XmlJavaTypeAdapter(UUIDAdapter.class)
+    @XmlID
     @Type(type="uuidUserType")
     @NaturalId // This has the effect of placing a "unique" constraint on the database column
-    @XmlID
-    @Column(length=36)
+    @Column(length=36)  //TODO needed? Type UUID will always assure that is exactly 36
     @Match(MatchMode.IGNORE)
     @NotNull
-    @Field(store = Store.YES, index = Index.UN_TOKENIZED)
+    @Field(store = Store.YES, index = Index.YES, analyze = Analyze.NO)
     @FieldBridge(impl = UuidBridge.class)
+    @Audited
     protected UUID uuid;
 
     @XmlElement (name = "Created", type= String.class)
@@ -117,8 +129,9 @@ public abstract class CdmBase implements Serializable, ICdmBase, Cloneable{
     @Type(type="dateTimeUserType")
     @Basic(fetch = FetchType.LAZY)
     @Match(MatchMode.IGNORE)
-    @Field(index = Index.UN_TOKENIZED)
+    @Field(analyze = Analyze.NO)
     @FieldBridge(impl = DateTimeBridge.class)
+    @Audited
     private DateTime created;
 
     @XmlElement (name = "CreatedBy")
@@ -126,6 +139,7 @@ public abstract class CdmBase implements Serializable, ICdmBase, Cloneable{
     @XmlSchemaType(name = "IDREF")
     @ManyToOne(fetch=FetchType.LAZY)
     @Match(MatchMode.IGNORE)
+    @Audited
     private User createdBy;
 
     /**
@@ -137,6 +151,16 @@ public abstract class CdmBase implements Serializable, ICdmBase, Cloneable{
         this.created = new DateTime().withMillisOfSecond(0);
     }
 
+    public static void setNewEntityListener(NewEntityListener nel) {
+        newEntityListener = nel;
+    }
+
+    public static void fireOnCreateEvent(CdmBase cdmBase) {
+        if(newEntityListener != null) {
+            newEntityListener.onCreate(cdmBase);
+        }
+    }
+
     /**
      * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
      * @param listener
@@ -189,44 +213,68 @@ public abstract class CdmBase implements Serializable, ICdmBase, Cloneable{
         propertyChangeSupport.firePropertyChange(evt);
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.model.common.ICdmBase#getUuid()
+    /**
+     * This method was initially added to {@link CdmBase} to fix #5161.
+     * It can be overridden by subclasses such as {@link IdentifiableEntity}
+     * to explicitly initialize listeners. This is needed e.g. after de-serialization
+     * as listeners are not serialized due to the @Transient annotation.
+     * However, it can be generally used for other use-cases as well
+     */
+    public void initListener() {}
+
+    /**
+     * Adds an item to a set of <code>this</code> object and fires the according
+     * {@link PropertyChangeEvent}. Workaround as long as add and remove is not yet
+     * implemented in aspectJ.
+     * @param set the set the new item is added to
+     * @param newItem the new item to be added to the set
+     * @param propertyName the name of the set as property in <code>this</code> object
+     */
+    protected <T extends CdmBase> void addToSetWithChangeEvent(Set<T> set, T newItem, String propertyName ){
+        Set<T> oldValue = new HashSet<T>(set);
+        set.add(newItem);
+        firePropertyChange(new PropertyChangeEvent(this, propertyName, oldValue, set));
+    }
+
+    /**
+     * Removes an item from a set of <code>this</code> object and fires the according
+     * {@link PropertyChangeEvent}. Workaround as long as add and remove is not yet
+     * implemented in aspectJ.
+     * @param set the set the item is to be removed from
+     * @param itemToRemove the item to be removed from the set
+     * @param propertyName the name of the set as property in <code>this</code> object
      */
+    protected <T extends CdmBase> void removeFromSetWithChangeEvent(Set<T> set, T itemToRemove, String propertyName ){
+        Set<T> oldValue = new HashSet<T>(set);
+        set.remove(itemToRemove);
+        firePropertyChange(new PropertyChangeEvent(this, propertyName, oldValue, set));
+    }
+
+    @Override
     public UUID getUuid() {
         return uuid;
     }
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.model.common.ICdmBase#setUuid(java.util.UUID)
-     */
+    @Override
     public void setUuid(UUID uuid) {
         this.uuid = uuid;
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.model.common.ICdmBase#getId()
-     */
+    @Override
     public int getId() {
         return this.id;
     }
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.model.common.ICdmBase#setId(int)
-     */
-    public void setId(int id) {
+    @Override
+    public void setId(int id) {  //see #265 (private ?)
         this.id = id;
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreated()
-     */
+    @Override
     public DateTime getCreated() {
         return created;
     }
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreated(java.util.Calendar)
-     */
+    @Override
     public void setCreated(DateTime created) {
         if (created != null){
-            new DateTime();
             created = created.withMillisOfSecond(0);
             //created.set(Calendar.MILLISECOND, 0);  //old, can be deleted
         }
@@ -234,15 +282,11 @@ public abstract class CdmBase implements Serializable, ICdmBase, Cloneable{
     }
 
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreatedBy()
-     */
+    @Override
     public User getCreatedBy() {
         return this.createdBy;
     }
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreatedBy(eu.etaxonomy.cdm.model.agent.Person)
-     */
+    @Override
     public void setCreatedBy(User createdBy) {
         this.createdBy = createdBy;
     }
@@ -376,21 +420,35 @@ public abstract class CdmBase implements Serializable, ICdmBase, Cloneable{
         }
     }
 
+    @Transient
+       @Override
+       public String getUserFriendlyTypeName(){
+               return getClass().getSimpleName();
+       }
+
+       @Transient
+       @Override
+       public String getUserFriendlyDescription(){
+               return toString();
+       }
+
+       @Override
+       public String getUserFriendlyFieldName(String field){
+               return field;
+       }
+
 //********************** CLONE *****************************************/
 
-    protected void clone(CdmBase clone){
-        clone.setCreatedBy(createdBy);
-        clone.setId(id);
-        clone.propertyChangeSupport=new PropertyChangeSupport(clone);
-        //Constructor Attributes
-        //clone.setCreated(created);
-        //clone.setUuid(getUuid());
+//    protected void clone(CdmBase clone){
+//        clone.setCreatedBy(createdBy);
+//        clone.setId(id);
+//        clone.propertyChangeSupport=new PropertyChangeSupport(clone);
+//        //Constructor Attributes
+//        //clone.setCreated(created);
+//        //clone.setUuid(getUuid());
+//
+//    }
 
-    }
-
-    /* (non-Javadoc)
-     * @see java.lang.Object#clone()
-     */
     @Override
     public Object clone() throws CloneNotSupportedException{
         CdmBase result = (CdmBase)super.clone();