(no commit message)
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / CdmBase.java
1 package eu.etaxonomy.cdm.model.common;
2
3 import java.beans.PropertyChangeEvent;
4 import java.beans.PropertyChangeListener;
5 import java.beans.PropertyChangeSupport;
6 import java.io.Serializable;
7 import java.lang.reflect.Method;
8 import java.util.Calendar;
9 import java.util.UUID;
10
11 import javax.persistence.Basic;
12 import javax.persistence.FetchType;
13 import javax.persistence.GeneratedValue;
14 import javax.persistence.Id;
15 import javax.persistence.ManyToOne;
16 import javax.persistence.MappedSuperclass;
17 import javax.persistence.Temporal;
18 import javax.persistence.TemporalType;
19 import javax.persistence.Transient;
20
21 import javax.xml.bind.annotation.XmlAccessType;
22 import javax.xml.bind.annotation.XmlAccessorType;
23 import javax.xml.bind.annotation.XmlAttribute;
24 import javax.xml.bind.annotation.XmlElement;
25 import javax.xml.bind.annotation.XmlID;
26 import javax.xml.bind.annotation.XmlRootElement;
27 import javax.xml.bind.annotation.XmlSchemaType;
28 import javax.xml.bind.annotation.XmlTransient;
29 import javax.xml.bind.annotation.XmlType;
30 import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
31 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
32
33 import org.hibernate.annotations.Cascade;
34 import org.hibernate.annotations.CascadeType;
35
36 import eu.etaxonomy.cdm.model.agent.Person;
37
38
39
40
41 /**
42 * The base class for all CDM domain classes implementing UUIDs and bean property change event firing.
43 * It provides a globally unique UUID and keeps track of creation date and person.
44 * The UUID is the same for different versions (see {@link VersionableEntity}) of a CDM object, so a locally unique id exists in addition
45 * that allows to safely access and store several objects (=version) with the same UUID.
46 *
47 * This class together with the {@link eu.etaxonomy.cdm.aspectj.PropertyChangeAspect}
48 * will fire bean change events to all registered listeners. Listener registration and event firing
49 * is done with the help of the {@link PropertyChangeSupport} class.
50 *
51 * @author m.doering
52 *
53 */
54 @XmlAccessorType(XmlAccessType.PROPERTY)
55 @XmlType(name = "CdmBase", propOrder = {
56 "created",
57 "createdBy"
58 })
59 @XmlRootElement(name = "CdmBase")
60 @MappedSuperclass
61 public abstract class CdmBase implements Serializable, ICdmBase{
62
63 private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
64 private int id;
65 private UUID uuid;
66 private Calendar created;
67 private Person createdBy;
68
69 /**
70 * Class constructor assigning a unique UUID and creation date.
71 * UUID can be changed later via setUuid method.
72 */
73 public CdmBase() {
74 this.uuid = UUID.randomUUID();
75 this.setCreated(Calendar.getInstance());
76 }
77
78 /**
79 * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
80 * @param listener
81 */
82 public void addPropertyChangeListener(PropertyChangeListener listener) {
83 propertyChangeSupport.addPropertyChangeListener(listener);
84 }
85
86 /**
87 * see {@link PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)}
88 */
89 public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
90 propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
91 }
92
93 /**
94 * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
95 */
96 public void removePropertyChangeListener(PropertyChangeListener listener) {
97 propertyChangeSupport.removePropertyChangeListener(listener);
98 }
99
100 /**
101 * @see PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)
102 */
103 public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
104 propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
105 }
106
107 @Transient
108 public boolean hasListeners(String propertyName) {
109 return propertyChangeSupport.hasListeners(propertyName);
110 }
111
112 public void firePropertyChange(String property, String oldval, String newval) {
113 propertyChangeSupport.firePropertyChange(property, oldval, newval);
114 }
115 public void firePropertyChange(String property, int oldval, int newval) {
116 propertyChangeSupport.firePropertyChange(property, oldval, newval);
117 }
118 public void firePropertyChange(String property, float oldval, float newval) {
119 propertyChangeSupport.firePropertyChange(property, oldval, newval);
120 }
121 public void firePropertyChange(String property, boolean oldval, boolean newval) {
122 propertyChangeSupport.firePropertyChange(property, oldval, newval);
123 }
124 public void firePropertyChange(String property, Object oldval, Object newval) {
125 propertyChangeSupport.firePropertyChange(property, oldval, newval);
126 }
127 public void firePropertyChange(PropertyChangeEvent evt) {
128 propertyChangeSupport.firePropertyChange(evt);
129 }
130
131 /**
132 * Method for hibernate only to read the UUID value as a simple string from the object and persist it (e.g. in a database).
133 * For reading the UUID please use getUuid method
134 * @return String representation of the UUID
135 */
136 @XmlAttribute(name = "uuid", required = true)
137 @XmlID
138 @XmlSchemaType(name = "ID")
139 private String getStrUuid() {
140 return this.uuid.toString();
141 }
142 /**
143 * 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).
144 * For setting the UUID please use setUuid method
145 */
146 private void setStrUuid(String uuid) {
147 this.uuid = UUID.fromString(uuid);
148 }
149
150
151 /* (non-Javadoc)
152 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getId()
153 */
154 @XmlAttribute(name = "id", required = true)
155 @Id
156 @GeneratedValue(generator = "system-increment")
157 public int getId() {
158 return this.id;
159 }
160 /* (non-Javadoc)
161 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setId(int)
162 */
163 public void setId(int id) {
164 this.id = id;
165 }
166
167 /* (non-Javadoc)
168 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getUuid()
169 */
170 @XmlTransient
171 @Transient
172 public UUID getUuid() {
173 return this.uuid;
174 }
175 /* (non-Javadoc)
176 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setUuid(java.util.UUID)
177 */
178 public void setUuid(UUID uuid) {
179 this.uuid = uuid;
180 }
181
182
183 /* (non-Javadoc)
184 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreated()
185 */
186 @XmlElement (name = "Created")
187 @Temporal(TemporalType.TIMESTAMP)
188 @Basic(fetch = FetchType.LAZY)
189 public Calendar getCreated() {
190 return created;
191 }
192 /* (non-Javadoc)
193 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreated(java.util.Calendar)
194 */
195 public void setCreated(Calendar created) {
196 if (created != null){
197 created.set(Calendar.MILLISECOND, 0);
198 }
199 this.created = created;
200 }
201
202
203 /* (non-Javadoc)
204 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreatedBy()
205 */
206 @XmlElement (name = "CreatedBy")
207 @ManyToOne(fetch=FetchType.LAZY)
208 @Cascade( { CascadeType.SAVE_UPDATE })
209 public Person getCreatedBy() {
210 return this.createdBy;
211 }
212 /* (non-Javadoc)
213 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreatedBy(eu.etaxonomy.cdm.model.agent.Person)
214 */
215 public void setCreatedBy(Person createdBy) {
216 this.createdBy = createdBy;
217 }
218
219
220 /**
221 * Is true if UUID is the same for the passed Object and this one.
222 * @see java.lang.Object#equals(java.lang.Object)
223 * See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities}
224 * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
225 * for more information about equals and hashcode.
226 */
227 @Override
228 public boolean equals(Object obj) {
229 if (obj == this){
230 return true;
231 }
232 if (obj == null){
233 return false;
234 }
235 if (!CdmBase.class.isAssignableFrom(obj.getClass())){
236 return false;
237 }
238 ICdmBase cdmObj = (ICdmBase)obj;
239 boolean uuidEqual = cdmObj.getUuid().equals(this.getUuid());
240 boolean createdEqual = cdmObj.getCreated().equals(this.getCreated());
241 if (! uuidEqual || !createdEqual){
242 return false;
243 }
244 return true;
245 }
246
247
248 /** Overrides {@link java.lang.Object#hashCode()}
249 * See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities}
250 * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
251 * for more information about equals and hashcode.
252 */
253 @Override
254 public int hashCode() {
255 int hashCode = 7;
256 hashCode = 29 * hashCode + this.getUuid().hashCode();
257 return hashCode;
258 }
259
260 /**
261 * Overrides {@link java.lang.Object#toString()}.
262 * This returns an String that identifies the object well without beeing necessarily unique.
263 * Specification: This method should never call other object' methods so it can be well used for debugging
264 * without problems like lazy loading, unreal states etc.
265 * Note: If overriding this method's javadoc always copy or link the above requirement.
266 * If not overwritten by a subclass method returns the class, id and uuid as a string for any CDM object.
267 * For example: Taxon#13<b5938a98-c1de-4dda-b040-d5cc5bfb3bc0>
268 * @see java.lang.Object#toString()
269 */
270 @Override
271 public String toString() {
272 return this.getClass().getSimpleName()+"#"+this.getId()+"<"+this.getUuid()+">";
273 }
274
275 protected void invokeSetMethod(Method method, Object object){
276 try {
277 method.invoke(object, this);
278 } catch (Exception e) {
279 e.printStackTrace();
280 //TODO handle exceptioin;
281 }
282 }
283
284 protected void invokeSetMethodWithNull(Method method, Object object){
285 try {
286 Object[] nul = new Object[]{null};
287 method.invoke(object, nul);
288 } catch (Exception e) {
289 e.printStackTrace();
290 //TODO handle exceptioin;
291 }
292 }
293
294 //********************** CLONE *****************************************/
295
296 protected void clone(CdmBase clone){
297 clone.setCreatedBy(createdBy);
298 clone.setId(id);
299 //Constructor Attributes
300 //clone.setCreated(created);
301 //clone.setUuid(getUuid());
302
303 }
304
305 /* (non-Javadoc)
306 * @see java.lang.Object#clone()
307 */
308 public Object clone() throws CloneNotSupportedException{
309 CdmBase result = (CdmBase)super.clone();
310
311 //TODO ?
312 result.setId(0);
313 result.setUuid(UUID.randomUUID());
314 result.setCreated(Calendar.getInstance());
315 result.setCreatedBy(null);
316
317 //no changes to: -
318 return result;
319 }
320
321 }