import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
+import java.lang.reflect.Method;
import java.util.Calendar;
import java.util.UUID;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
+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.XmlID;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import eu.etaxonomy.cdm.model.agent.Person;
+
+
+/**
+ * The base class for all CDM domain classes implementing UUIDs and bean property change event firing.
+ * It provides a globally unique UUID and keeps track of creation date and person.
+ * The UUID is the same for different versions (see {@link VersionableEntity}) of a CDM object, so a locally unique id exists in addition
+ * that allows to safely access and store several objects (=version) with the same UUID.
+ *
+ * This class together with the {@link eu.etaxonomy.cdm.aspectj.PropertyChangeAspect}
+ * will fire bean change events to all registered listeners. Listener registration and event firing
+ * is done with the help of the {@link PropertyChangeSupport} class.
+ *
+ * @author m.doering
+ *
+ */
+@XmlAccessorType(XmlAccessType.PROPERTY)
+@XmlType(name = "CdmBase", propOrder = {
+ "created",
+ "createdBy"
+})
+@XmlRootElement(name = "CdmBase")
@MappedSuperclass
-public abstract class CdmBase implements Serializable{
+public abstract class CdmBase implements Serializable, ICdmBase{
+
private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
private int id;
- private UUID uuid;
+ private UUID uuid;
private Calendar created;
- private Person createdBy;
+ private Person createdBy;
+ /**
+ * Class constructor assigning a unique UUID and creation date.
+ * UUID can be changed later via setUuid method.
+ */
public CdmBase() {
this.uuid = UUID.randomUUID();
- this.created = Calendar.getInstance();
+ this.setCreated(Calendar.getInstance());
}
-
+ /**
+ * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
+ * @param listener
+ */
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
+ /**
+ * see {@link PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)}
+ */
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
}
+ /**
+ * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
+ */
public void removePropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
+ /**
+ * @see PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)
+ */
public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
}
propertyChangeSupport.firePropertyChange(evt);
}
+ /**
+ * Method for hibernate only to read the UUID value as a simple string from the object and persist it (e.g. in a database).
+ * For reading the UUID please use getUuid method
+ * @return String representation of the UUID
+ */
+ @XmlAttribute(name = "uuid", required = true)
+ @XmlID
+ @XmlSchemaType(name = "ID")
+ private String getStrUuid() {
+ return this.uuid.toString();
+ }
+ /**
+ * Method for hibernate only to set the UUID value as a simple string as it was stored in the persistence layer (e.g. a database).
+ * For setting the UUID please use setUuid method
+ */
+ private void setStrUuid(String uuid) {
+ this.uuid = UUID.fromString(uuid);
+ }
+
+
+ /* (non-Javadoc)
+ * @see eu.etaxonomy.cdm.model.common.ICdmBase#getId()
+ */
+ @XmlAttribute(name = "id", required = true)
@Id
@GeneratedValue(generator = "system-increment")
public int getId() {
return this.id;
}
+ /* (non-Javadoc)
+ * @see eu.etaxonomy.cdm.model.common.ICdmBase#setId(int)
+ */
public void setId(int id) {
this.id = id;
}
-
- private String getStrUuid() {
- return this.uuid.toString();
- }
- private void setStrUuid(String uuid) {
- this.uuid = UUID.fromString(uuid);
- }
-
-
+ /* (non-Javadoc)
+ * @see eu.etaxonomy.cdm.model.common.ICdmBase#getUuid()
+ */
+ @XmlTransient
@Transient
public UUID getUuid() {
return this.uuid;
}
+ /* (non-Javadoc)
+ * @see eu.etaxonomy.cdm.model.common.ICdmBase#setUuid(java.util.UUID)
+ */
public void setUuid(UUID uuid) {
this.uuid = uuid;
}
+ /* (non-Javadoc)
+ * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreated()
+ */
+ @XmlElement (name = "Created")
@Temporal(TemporalType.TIMESTAMP)
@Basic(fetch = FetchType.LAZY)
public Calendar getCreated() {
- return this.created;
+ return created;
}
+ /* (non-Javadoc)
+ * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreated(java.util.Calendar)
+ */
public void setCreated(Calendar created) {
+ if (created != null){
+ created.set(Calendar.MILLISECOND, 0);
+ }
this.created = created;
}
+ /* (non-Javadoc)
+ * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreatedBy()
+ */
+ @XmlElement (name = "CreatedBy")
@ManyToOne(fetch=FetchType.LAZY)
@Cascade( { CascadeType.SAVE_UPDATE })
public Person getCreatedBy() {
return this.createdBy;
}
+ /* (non-Javadoc)
+ * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreatedBy(eu.etaxonomy.cdm.model.agent.Person)
+ */
public void setCreatedBy(Person createdBy) {
this.createdBy = createdBy;
}
+ /**
+ * Is true if UUID is the same for the passed Object and this one.
+ * @see java.lang.Object#equals(java.lang.Object)
+ * See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities}
+ * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
+ * for more information about equals and hashcode.
+ */
@Override
- // equals if UUID and created timestamp are the same!
public boolean equals(Object obj) {
- if (CdmBase.class.isAssignableFrom(obj.getClass())){
- CdmBase cdmObj = (CdmBase)obj;
- if (cdmObj.getUuid().equals(this.getUuid()) && cdmObj.getCreated().equals(this.getCreated())){
- return true;
- }
+ if (obj == this){
+ return true;
+ }
+ if (obj == null){
+ return false;
+ }
+ if (!CdmBase.class.isAssignableFrom(obj.getClass())){
+ return false;
+ }
+ ICdmBase cdmObj = (ICdmBase)obj;
+ boolean uuidEqual = cdmObj.getUuid().equals(this.getUuid());
+ boolean createdEqual = cdmObj.getCreated().equals(this.getCreated());
+ if (! uuidEqual || !createdEqual){
+ return false;
}
- return false;
+ return true;
}
+
+ /** Overrides {@link java.lang.Object#hashCode()}
+ * See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities}
+ * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
+ * for more information about equals and hashcode.
+ */
+ @Override
+ public int hashCode() {
+ int hashCode = 7;
+ hashCode = 29 * hashCode + this.getUuid().hashCode();
+ return hashCode;
+ }
+
+ /**
+ * Overrides {@link java.lang.Object#toString()}.
+ * This returns an String that identifies the object well without beeing necessarily unique.
+ * Specification: This method should never call other object' methods so it can be well used for debugging
+ * without problems like lazy loading, unreal states etc.
+ * Note: If overriding this method's javadoc always copy or link the above requirement.
+ * If not overwritten by a subclass method returns the class, id and uuid as a string for any CDM object.
+ * For example: Taxon#13<b5938a98-c1de-4dda-b040-d5cc5bfb3bc0>
+ * @see java.lang.Object#toString()
+ */
@Override
public String toString() {
- return this.getClass().getSimpleName()+"<"+this.getUuid()+">";
+ return this.getClass().getSimpleName()+"#"+this.getId()+"<"+this.getUuid()+">";
+ }
+
+ protected void invokeSetMethod(Method method, Object object){
+ try {
+ method.invoke(object, this);
+ } catch (Exception e) {
+ e.printStackTrace();
+ //TODO handle exceptioin;
+ }
+ }
+
+ protected void invokeSetMethodWithNull(Method method, Object object){
+ try {
+ Object[] nul = new Object[]{null};
+ method.invoke(object, nul);
+ } catch (Exception e) {
+ e.printStackTrace();
+ //TODO handle exceptioin;
+ }
+ }
+
+//********************** CLONE *****************************************/
+
+ protected void clone(CdmBase clone){
+ clone.setCreatedBy(createdBy);
+ clone.setId(id);
+ //Constructor Attributes
+ //clone.setCreated(created);
+ //clone.setUuid(getUuid());
+
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#clone()
+ */
+ public Object clone() throws CloneNotSupportedException{
+ CdmBase result = (CdmBase)super.clone();
+
+ //TODO ?
+ result.setId(0);
+ result.setUuid(UUID.randomUUID());
+ result.setCreated(Calendar.getInstance());
+ result.setCreatedBy(null);
+
+ //no changes to: -
+ return result;
}
}