Small changes to the cdmlib-model package, mainly due to read-write operations on...
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / CdmBase.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.model.common;
10
11 import java.beans.PropertyChangeEvent;
12 import java.beans.PropertyChangeListener;
13 import java.beans.PropertyChangeSupport;
14 import java.io.Serializable;
15 import java.lang.reflect.Method;
16 import java.util.UUID;
17
18 import javax.persistence.Basic;
19 import javax.persistence.Column;
20 import javax.persistence.FetchType;
21 import javax.persistence.GeneratedValue;
22 import javax.persistence.Id;
23 import javax.persistence.ManyToOne;
24 import javax.persistence.MappedSuperclass;
25 import javax.persistence.Transient;
26 import javax.validation.constraints.NotNull;
27 import javax.validation.constraints.Min;
28 import javax.xml.bind.annotation.XmlAccessType;
29 import javax.xml.bind.annotation.XmlAccessorType;
30 import javax.xml.bind.annotation.XmlAttribute;
31 import javax.xml.bind.annotation.XmlElement;
32 import javax.xml.bind.annotation.XmlID;
33 import javax.xml.bind.annotation.XmlIDREF;
34 import javax.xml.bind.annotation.XmlSchemaType;
35 import javax.xml.bind.annotation.XmlTransient;
36 import javax.xml.bind.annotation.XmlType;
37 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
38
39 import org.apache.log4j.Logger;
40 import org.hibernate.annotations.NaturalId;
41 import org.hibernate.annotations.Type;
42 import org.hibernate.search.annotations.DocumentId;
43 import org.joda.time.DateTime;
44
45 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
46 import eu.etaxonomy.cdm.jaxb.DateTimeAdapter;
47 import eu.etaxonomy.cdm.jaxb.UUIDAdapter;
48 import eu.etaxonomy.cdm.strategy.match.Match;
49 import eu.etaxonomy.cdm.strategy.match.MatchMode;
50
51
52
53
54 /**
55 * The base class for all CDM domain classes implementing UUIDs and bean property change event firing.
56 * It provides a globally unique UUID and keeps track of creation date and person.
57 * The UUID is the same for different versions (see {@link VersionableEntity}) of a CDM object, so a locally unique id exists in addition
58 * that allows to safely access and store several objects (=version) with the same UUID.
59 *
60 * This class together with the {@link eu.etaxonomy.cdm.aspectj.PropertyChangeAspect}
61 * will fire bean change events to all registered listeners. Listener registration and event firing
62 * is done with the help of the {@link PropertyChangeSupport} class.
63 *
64 * @author m.doering
65 *
66 */
67 @XmlAccessorType(XmlAccessType.FIELD)
68 @XmlType(name = "CdmBase", propOrder = {
69 "created",
70 "createdBy"
71 })
72 @MappedSuperclass
73 public abstract class CdmBase implements Serializable, ICdmBase{
74 private static final long serialVersionUID = -3053225700018294809L;
75 @SuppressWarnings("unused")
76 private static final Logger logger = Logger.getLogger(CdmBase.class);
77
78 @Transient
79 @XmlTransient
80 private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
81
82 @XmlAttribute(name = "id", required = true)
83 @Id
84 @GeneratedValue(generator = "system-increment")
85 @DocumentId
86 @Match(MatchMode.IGNORE)
87 @NotNull
88 @Min(0)
89 private int id;
90
91 @XmlAttribute(required = true)
92 @XmlJavaTypeAdapter(UUIDAdapter.class)
93 @XmlID
94 @Type(type="uuidUserType")
95 @NaturalId // This has the effect of placing a "unique" constraint on the database column
96 @Column(length=36)
97 @Match(MatchMode.IGNORE)
98 @NotNull
99 protected UUID uuid;
100
101 @XmlElement (name = "Created", type= String.class)
102 @XmlJavaTypeAdapter(DateTimeAdapter.class)
103 @Type(type="dateTimeUserType")
104 @Basic(fetch = FetchType.LAZY)
105 @Match(MatchMode.IGNORE)
106 private DateTime created;
107
108 @XmlElement (name = "CreatedBy")
109 @XmlIDREF
110 @XmlSchemaType(name = "IDREF")
111 @ManyToOne(fetch=FetchType.LAZY)
112 @Match(MatchMode.IGNORE)
113 private User createdBy;
114
115 /**
116 * Class constructor assigning a unique UUID and creation date.
117 * UUID can be changed later via setUuid method.
118 */
119 public CdmBase() {
120 this.uuid = UUID.randomUUID();
121 this.created = new DateTime().withMillisOfSecond(0);
122 }
123
124 /**
125 * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
126 * @param listener
127 */
128 public void addPropertyChangeListener(PropertyChangeListener listener) {
129 propertyChangeSupport.addPropertyChangeListener(listener);
130 }
131
132 /**
133 * see {@link PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)}
134 */
135 public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
136 propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
137 }
138
139 /**
140 * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
141 */
142 public void removePropertyChangeListener(PropertyChangeListener listener) {
143 propertyChangeSupport.removePropertyChangeListener(listener);
144 }
145
146 /**
147 * @see PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)
148 */
149 public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
150 propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
151 }
152
153 public boolean hasListeners(String propertyName) {
154 return propertyChangeSupport.hasListeners(propertyName);
155 }
156
157 public void firePropertyChange(String property, String oldval, String newval) {
158 propertyChangeSupport.firePropertyChange(property, oldval, newval);
159 }
160 public void firePropertyChange(String property, int oldval, int newval) {
161 propertyChangeSupport.firePropertyChange(property, oldval, newval);
162 }
163 public void firePropertyChange(String property, float oldval, float newval) {
164 propertyChangeSupport.firePropertyChange(property, oldval, newval);
165 }
166 public void firePropertyChange(String property, boolean oldval, boolean newval) {
167 propertyChangeSupport.firePropertyChange(property, oldval, newval);
168 }
169 public void firePropertyChange(String property, Object oldval, Object newval) {
170 propertyChangeSupport.firePropertyChange(property, oldval, newval);
171 }
172 public void firePropertyChange(PropertyChangeEvent evt) {
173 propertyChangeSupport.firePropertyChange(evt);
174 }
175
176 /* (non-Javadoc)
177 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getUuid()
178 */
179 public UUID getUuid() {
180 return uuid;
181 }
182 /* (non-Javadoc)
183 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setUuid(java.util.UUID)
184 */
185 public void setUuid(UUID uuid) {
186 this.uuid = uuid;
187 }
188
189 /* (non-Javadoc)
190 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getId()
191 */
192 public int getId() {
193 return this.id;
194 }
195 /* (non-Javadoc)
196 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setId(int)
197 */
198 public void setId(int id) {
199 this.id = id;
200 }
201
202 /* (non-Javadoc)
203 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreated()
204 */
205 public DateTime getCreated() {
206 return created;
207 }
208 /* (non-Javadoc)
209 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreated(java.util.Calendar)
210 */
211 public void setCreated(DateTime created) {
212 if (created != null){
213 new DateTime();
214 created = created.withMillisOfSecond(0);
215 //created.set(Calendar.MILLISECOND, 0); //old, can be deleted
216 }
217 this.created = created;
218 }
219
220
221 /* (non-Javadoc)
222 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreatedBy()
223 */
224 public User getCreatedBy() {
225 return this.createdBy;
226 }
227 /* (non-Javadoc)
228 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreatedBy(eu.etaxonomy.cdm.model.agent.Person)
229 */
230 public void setCreatedBy(User createdBy) {
231 this.createdBy = createdBy;
232 }
233
234 // ************************** Hibernate proxies *******************/
235 /**
236 * These methods are present due to HHH-1517 - that in a one-to-many
237 * relationship with a superclass at the "one" end, the proxy created
238 * by hibernate is the superclass, and not the subclass, resulting in
239 * a classcastexception when you try to cast it.
240 *
241 * Hopefully this will be resolved through improvements with the creation of
242 * proxy objects by hibernate and the following methods will become redundant,
243 * but for the time being . . .
244 * @param <T>
245 * @param object
246 * @param clazz
247 * @return
248 * @throws ClassCastException
249 */
250 //non-static does not work because javassist already unwrapps the proxy before calling the method
251 public static <T extends CdmBase> T deproxy(Object object, Class<T> clazz) throws ClassCastException {
252 return HibernateProxyHelper.deproxy(object, clazz);
253 }
254
255 public boolean isInstanceOf(Class<? extends CdmBase> clazz) throws ClassCastException {
256 return HibernateProxyHelper.isInstanceOf(this, clazz);
257 }
258
259 // ************* Object overrides *************************/
260
261 /**
262 * Is true if UUID is the same for the passed Object and this one.
263 * @see java.lang.Object#equals(java.lang.Object)
264 * See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities}
265 * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
266 * for more information about equals and hashcode.
267 */
268 @Override
269 public boolean equals(Object obj) {
270 if (obj == this){
271 return true;
272 }
273 if (obj == null){
274 return false;
275 }
276 if (!CdmBase.class.isAssignableFrom(obj.getClass())){
277 return false;
278 }
279 ICdmBase cdmObj = (ICdmBase)obj;
280 boolean uuidEqual = cdmObj.getUuid().equals(this.getUuid());
281 boolean createdEqual = cdmObj.getCreated().equals(this.getCreated());
282 if (! uuidEqual || !createdEqual){
283 return false;
284 }
285 return true;
286 }
287
288
289 /** Overrides {@link java.lang.Object#hashCode()}
290 * See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities}
291 * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
292 * for more information about equals and hashcode.
293 */
294 @Override
295 public int hashCode() {
296 int hashCode = 7;
297 hashCode = 29 * hashCode + this.getUuid().hashCode();
298 return hashCode;
299 }
300
301 /**
302 * Overrides {@link java.lang.Object#toString()}.
303 * This returns an String that identifies the object well without beeing necessarily unique.
304 * Specification: This method should never call other object' methods so it can be well used for debugging
305 * without problems like lazy loading, unreal states etc.
306 * Note: If overriding this method's javadoc always copy or link the above requirement.
307 * If not overwritten by a subclass method returns the class, id and uuid as a string for any CDM object.
308 * For example: Taxon#13<b5938a98-c1de-4dda-b040-d5cc5bfb3bc0>
309 * @see java.lang.Object#toString()
310 */
311 @Override
312 public String toString() {
313 return this.getClass().getSimpleName()+"#"+this.getId()+"<"+this.getUuid()+">";
314 }
315
316 // **************** invoke methods **************************/
317
318 protected void invokeSetMethod(Method method, Object object){
319 try {
320 method.invoke(object, this);
321 } catch (Exception e) {
322 e.printStackTrace();
323 //TODO handle exceptioin;
324 }
325 }
326
327 protected void invokeSetMethodWithNull(Method method, Object object){
328 try {
329 Object[] nul = new Object[]{null};
330 method.invoke(object, nul);
331 } catch (Exception e) {
332 e.printStackTrace();
333 //TODO handle exceptioin;
334 }
335 }
336
337 //********************** CLONE *****************************************/
338
339 protected void clone(CdmBase clone){
340 clone.setCreatedBy(createdBy);
341 clone.setId(id);
342 //Constructor Attributes
343 //clone.setCreated(created);
344 //clone.setUuid(getUuid());
345
346 }
347
348 /* (non-Javadoc)
349 * @see java.lang.Object#clone()
350 */
351 @Override
352 public Object clone() throws CloneNotSupportedException{
353 CdmBase result = (CdmBase)super.clone();
354
355 //TODO ?
356 result.setId(0);
357 result.setUuid(UUID.randomUUID());
358 result.setCreated(new DateTime());
359 result.setCreatedBy(null);
360
361 //no changes to: -
362 return result;
363 }
364
365 }