Project

General

Profile

Download (11.3 KB) Statistics
| Branch: | Tag: | Revision:
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.UUID;
9

    
10
import javax.persistence.Basic;
11
import javax.persistence.FetchType;
12
import javax.persistence.GeneratedValue;
13
import javax.persistence.Id;
14
import javax.persistence.ManyToOne;
15
import javax.persistence.MappedSuperclass;
16
import javax.persistence.Transient;
17
import javax.xml.bind.annotation.XmlAccessType;
18
import javax.xml.bind.annotation.XmlAccessorType;
19
import javax.xml.bind.annotation.XmlAttribute;
20
import javax.xml.bind.annotation.XmlElement;
21
import javax.xml.bind.annotation.XmlID;
22
import javax.xml.bind.annotation.XmlRootElement;
23
import javax.xml.bind.annotation.XmlSchemaType;
24
import javax.xml.bind.annotation.XmlTransient;
25
import javax.xml.bind.annotation.XmlType;
26
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
27

    
28
import org.apache.log4j.Logger;
29
import org.hibernate.annotations.Cascade;
30
import org.hibernate.annotations.CascadeType;
31
import org.hibernate.annotations.Type;
32
import org.hibernate.search.annotations.DocumentId;
33
import org.joda.time.DateTime;
34

    
35
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
36
import eu.etaxonomy.cdm.jaxb.DateTimeAdapter;
37
import eu.etaxonomy.cdm.jaxb.UUIDAdapter;
38
import eu.etaxonomy.cdm.model.agent.Person;
39

    
40

    
41

    
42

    
43
/**
44
 * The base class for all CDM domain classes implementing UUIDs and bean property change event firing.
45
 * It provides a globally unique UUID and keeps track of creation date and person.
46
 * The UUID is the same for different versions (see {@link VersionableEntity}) of a CDM object, so a locally unique id exists in addition 
47
 * that allows to safely access and store several objects (=version) with the same UUID.
48
 * 
49
 * This class together with the {@link eu.etaxonomy.cdm.aspectj.PropertyChangeAspect} 
50
 * will fire bean change events to all registered listeners. Listener registration and event firing
51
 * is done with the help of the {@link PropertyChangeSupport} class.
52
 * 
53
 * @author m.doering
54
 *
55
 */
56
@XmlAccessorType(XmlAccessType.PROPERTY)
57
@XmlType(name = "CdmBase", propOrder = {
58
    "created",
59
    "createdBy"
60
})
61
@XmlRootElement(name = "CdmBase")
62
@MappedSuperclass
63
public abstract class CdmBase implements Serializable, ICdmBase{
64
	private static final long serialVersionUID = -3053225700018294809L;
65
	@SuppressWarnings("unused")
66
	private static final Logger logger = Logger.getLogger(CdmBase.class);
67
	
68
	private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
69
	private int id;
70
    
71
	private UUID uuid;
72
	private DateTime created;
73
    private Person createdBy;
74

    
75
	/**
76
	 * Class constructor assigning a unique UUID and creation date.
77
	 * UUID can be changed later via setUuid method.
78
	 */
79
	public CdmBase() {
80
		this.uuid = UUID.randomUUID();
81
		this.setCreated(new DateTime());
82
	}
83
	
84
	/**
85
	 * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
86
	 * @param listener
87
	 */
88
	public void addPropertyChangeListener(PropertyChangeListener listener) {
89
		propertyChangeSupport.addPropertyChangeListener(listener);
90
	}
91

    
92
	/**
93
	 * see {@link PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)}
94
	 */
95
	public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
96
		propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
97
	}
98

    
99
	/**
100
	 * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
101
	 */
102
	public void removePropertyChangeListener(PropertyChangeListener listener) {
103
		propertyChangeSupport.removePropertyChangeListener(listener);
104
	}
105
	
106
	/**
107
	 * @see PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)
108
	 */
109
	public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
110
		propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
111
	}
112
	
113
	@Transient
114
	public boolean hasListeners(String propertyName) {
115
		return propertyChangeSupport.hasListeners(propertyName);
116
	}
117

    
118
	public void firePropertyChange(String property, String oldval, String newval) {
119
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
120
	}
121
	public void firePropertyChange(String property, int oldval, int newval) {
122
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
123
	}
124
	public void firePropertyChange(String property, float oldval, float newval) {
125
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
126
	}
127
	public void firePropertyChange(String property, boolean oldval, boolean newval) {
128
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
129
	}
130
	public void firePropertyChange(String property, Object oldval, Object newval) {
131
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
132
	}
133
	public void firePropertyChange(PropertyChangeEvent evt) {
134
		propertyChangeSupport.firePropertyChange(evt);
135
	}
136

    
137
	/**
138
	 * Method for JAXB only to obtain the UUID value as a String instance.
139
	 * For getting the UUID please use the getUuid method.
140
	 * @return String representation of the UUID
141
	 */
142
	@XmlAttribute(name = "uuid", required = true)
143
    @XmlJavaTypeAdapter(UUIDAdapter.class)
144
    @XmlID
145
	@XmlSchemaType(name = "ID")
146
	@Transient
147
	private String getStrUuid() {
148
		return this.uuid.toString();
149
	}
150
		
151
	/**
152
	 * Method for JAXB only to set the UUID value as a String instance.
153
	 * For setting the UUID please use setUuid method.
154
	 */
155
	@Transient
156
	private void setStrUuid(String uuid) {
157
		this.uuid = UUID.fromString(uuid);
158
	}
159

    
160
	/* (non-Javadoc)
161
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getUuid()
162
	 */
163
    @XmlTransient
164
	@Type(type="uuidUserType")
165
	public UUID getUuid() {
166
		return this.uuid;
167
	}
168
	/* (non-Javadoc)
169
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setUuid(java.util.UUID)
170
	 */
171
	public void setUuid(UUID uuid) {
172
		this.uuid = uuid;
173
	}
174
	
175
	/* (non-Javadoc)
176
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getId()
177
	 */
178
	@XmlAttribute(name = "id", required = true)
179
	@Id
180
	@GeneratedValue(generator = "system-increment")
181
	@DocumentId
182
	public int getId() {
183
		return this.id;
184
	}
185
	/* (non-Javadoc)
186
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setId(int)
187
	 */
188
	public void setId(int id) {
189
		this.id = id;
190
	}
191
	
192
	/* (non-Javadoc)
193
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreated()
194
	 */
195
	@XmlElement (name = "Created", type= String.class)
196
	@XmlJavaTypeAdapter(DateTimeAdapter.class)
197
	@Type(type="dateTimeUserType")
198
	@Basic(fetch = FetchType.LAZY)
199
	public DateTime getCreated() {
200
		return created;
201
	}
202
	/* (non-Javadoc)
203
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreated(java.util.Calendar)
204
	 */
205
	public void setCreated(DateTime created) {
206
		if (created != null){
207
			new DateTime();
208
			created = created.withMillisOfSecond(0);
209
			//created.set(Calendar.MILLISECOND, 0);  //old, can be deleted
210
		}
211
		this.created = created;
212
	}
213

    
214

    
215
	/* (non-Javadoc)
216
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreatedBy()
217
	 */
218
	@XmlElement (name = "CreatedBy")
219
	@ManyToOne(fetch=FetchType.LAZY)
220
	@Cascade( { CascadeType.SAVE_UPDATE })
221
	public Person getCreatedBy() {
222
		return this.createdBy;
223
	}
224
	/* (non-Javadoc)
225
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreatedBy(eu.etaxonomy.cdm.model.agent.Person)
226
	 */
227
	public void setCreatedBy(Person createdBy) {
228
		this.createdBy = createdBy;
229
	}
230

    
231
	
232
	/**
233
	 * Is true if UUID is the same for the passed Object and this one.
234
	 * @see java.lang.Object#equals(java.lang.Object)
235
	 * See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities} 
236
	 * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
237
	 * for more information about equals and hashcode. 
238
	 */
239
	@Override
240
	public boolean equals(Object obj) {
241
		if (obj == this){
242
			return true;
243
		}
244
		if (obj == null){
245
			return false;
246
		}
247
		if (!CdmBase.class.isAssignableFrom(obj.getClass())){
248
			return false;
249
		}
250
		ICdmBase cdmObj = (ICdmBase)obj;
251
		boolean uuidEqual = cdmObj.getUuid().equals(this.getUuid());
252
		boolean createdEqual = cdmObj.getCreated().equals(this.getCreated());
253
		if (! uuidEqual || !createdEqual){
254
				return false;
255
		}
256
		return true;
257
	}
258

    
259
	
260
	/** Overrides {@link java.lang.Object#hashCode()}
261
	 *  See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities} 
262
	 * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
263
	 * for more information about equals and hashcode. 
264
	 */
265
	 @Override
266
	public int hashCode() {
267
		   int hashCode = 7;
268
		   hashCode = 29 * hashCode + this.getUuid().hashCode();
269
		   return hashCode;
270
	}
271

    
272
	/**
273
	 * Overrides {@link java.lang.Object#toString()}.
274
	 * This returns an String that identifies the object well without beeing necessarily unique.
275
	 * Specification: This method should never call other object' methods so it can be well used for debugging 
276
	 * without problems like lazy loading, unreal states etc.
277
	 * Note: If overriding this method's javadoc always copy or link the above requirement. 
278
	 * If not overwritten by a subclass method returns the class, id and uuid as a string for any CDM object. 
279
	 * For example: Taxon#13<b5938a98-c1de-4dda-b040-d5cc5bfb3bc0>
280
	 * @see java.lang.Object#toString()
281
	 */
282
	@Override
283
	public String toString() {
284
		return this.getClass().getSimpleName()+"#"+this.getId()+"<"+this.getUuid()+">";
285
	}
286
	
287
	protected void invokeSetMethod(Method method, Object object){
288
		try {
289
			method.invoke(object, this);
290
		} catch (Exception e) {
291
			e.printStackTrace();
292
			//TODO handle exceptioin;
293
		}
294
	}
295
	
296
	protected void invokeSetMethodWithNull(Method method, Object object){
297
		try {
298
			Object[] nul = new Object[]{null}; 
299
			method.invoke(object, nul);
300
		} catch (Exception e) {
301
			e.printStackTrace();
302
			//TODO handle exceptioin;
303
		}
304
	}
305
	
306
//********************** CLONE *****************************************/
307
	
308
	protected void clone(CdmBase clone){
309
		clone.setCreatedBy(createdBy);
310
		clone.setId(id);
311
		//Constructor Attributes
312
		//clone.setCreated(created);
313
		//clone.setUuid(getUuid());
314

    
315
	}
316
	
317
	/* (non-Javadoc)
318
	 * @see java.lang.Object#clone()
319
	 */
320
	@Override
321
	public Object clone() throws CloneNotSupportedException{
322
		CdmBase result = (CdmBase)super.clone();
323
		
324
		//TODO ?
325
		result.setId(0);
326
		result.setUuid(UUID.randomUUID());
327
		result.setCreated(new DateTime());
328
		result.setCreatedBy(null);
329
		
330
		//no changes to: -
331
		return result;
332
	}
333
	
334
	// ************************** Hibernate proxies *******************/
335
	/**
336
	 * These methods are present due to HHH-1517 - that in a one-to-many
337
	 * relationship with a superclass at the "one" end, the proxy created
338
	 * by hibernate is the superclass, and not the subclass, resulting in
339
	 * a classcastexception when you try to cast it.
340
	 *
341
	 * Hopefully this will be resolved through improvements with the creation of
342
	 * proxy objects by hibernate and the following methods will become redundant,
343
	 * but for the time being . . .
344
	 * @param <T>
345
	 * @param object
346
	 * @param clazz
347
	 * @return
348
	 * @throws ClassCastException
349
	 */
350
	//non-static does not work because javassist already unwrapps the proxy before calling the method
351
	 public static <T extends CdmBase> T deproxy(Object object, Class<T> clazz) throws ClassCastException {
352
		 return HibernateProxyHelper.deproxy(object, clazz);
353
	 }
354
	        
355
	 public boolean isInstanceOf(Class<? extends CdmBase> clazz) throws ClassCastException {
356
	     return HibernateProxyHelper.isInstanceOf(this, clazz);
357
	 }
358
	
359
}
(4-4/50)