Project

General

Profile

Download (11.5 KB) Statistics
| Branch: | Tag: | Revision:
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
	@XmlTransient
84
	@Id
85
	@GeneratedValue(generator = "system-increment")
86
	@DocumentId
87
	@Match(MatchMode.IGNORE)
88
	@NotNull
89
	@Min(0)
90
	private int id;
91
    
92
	@XmlAttribute(required = true)
93
    @XmlJavaTypeAdapter(UUIDAdapter.class)
94
    @Type(type="uuidUserType")
95
	@NaturalId // This has the effect of placing a "unique" constraint on the database column
96
	@XmlID
97
	@Column(length=36)
98
	@Match(MatchMode.IGNORE)
99
	@NotNull
100
	protected UUID uuid;
101
	
102
	@XmlElement (name = "Created", type= String.class)
103
	@XmlJavaTypeAdapter(DateTimeAdapter.class)
104
	@Type(type="dateTimeUserType")
105
	@Basic(fetch = FetchType.LAZY)
106
	@Match(MatchMode.IGNORE)
107
	private DateTime created;
108
	
109
	@XmlElement (name = "CreatedBy")
110
	@XmlIDREF
111
	@XmlSchemaType(name = "IDREF")
112
	@ManyToOne(fetch=FetchType.LAZY)
113
    @Match(MatchMode.IGNORE)
114
	private User createdBy;
115

    
116
	/**
117
	 * Class constructor assigning a unique UUID and creation date.
118
	 * UUID can be changed later via setUuid method.
119
	 */
120
	public CdmBase() {
121
		this.uuid = UUID.randomUUID();
122
		this.created = new DateTime().withMillisOfSecond(0);
123
	}
124
	
125
	/**
126
	 * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
127
	 * @param listener
128
	 */
129
	public void addPropertyChangeListener(PropertyChangeListener listener) {
130
		propertyChangeSupport.addPropertyChangeListener(listener);
131
	}
132

    
133
	/**
134
	 * see {@link PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)}
135
	 */
136
	public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
137
		propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
138
	}
139

    
140
	/**
141
	 * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
142
	 */
143
	public void removePropertyChangeListener(PropertyChangeListener listener) {
144
		propertyChangeSupport.removePropertyChangeListener(listener);
145
	}
146
	
147
	/**
148
	 * @see PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)
149
	 */
150
	public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
151
		propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
152
	}
153
	
154
	public boolean hasListeners(String propertyName) {
155
		return propertyChangeSupport.hasListeners(propertyName);
156
	}
157

    
158
	public void firePropertyChange(String property, String oldval, String newval) {
159
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
160
	}
161
	public void firePropertyChange(String property, int oldval, int newval) {
162
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
163
	}
164
	public void firePropertyChange(String property, float oldval, float newval) {
165
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
166
	}
167
	public void firePropertyChange(String property, boolean oldval, boolean newval) {
168
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
169
	}
170
	public void firePropertyChange(String property, Object oldval, Object newval) {
171
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
172
	}
173
	public void firePropertyChange(PropertyChangeEvent evt) {
174
		propertyChangeSupport.firePropertyChange(evt);
175
	}
176

    
177
	/* (non-Javadoc)
178
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getUuid()
179
	 */	
180
	public UUID getUuid() {
181
		return uuid;
182
	}
183
	/* (non-Javadoc)
184
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setUuid(java.util.UUID)
185
	 */
186
	public void setUuid(UUID uuid) {
187
		this.uuid = uuid;
188
	}
189
	
190
	/* (non-Javadoc)
191
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getId()
192
	 */
193
	public int getId() {
194
		return this.id;
195
	}
196
	/* (non-Javadoc)
197
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setId(int)
198
	 */
199
	public void setId(int id) {
200
		this.id = id;
201
	}
202
	
203
	/* (non-Javadoc)
204
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreated()
205
	 */
206
	public DateTime getCreated() {
207
		return created;
208
	}
209
	/* (non-Javadoc)
210
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreated(java.util.Calendar)
211
	 */
212
	public void setCreated(DateTime created) {
213
		if (created != null){
214
			new DateTime();
215
			created = created.withMillisOfSecond(0);
216
			//created.set(Calendar.MILLISECOND, 0);  //old, can be deleted
217
		}
218
		this.created = created;
219
	}
220

    
221

    
222
	/* (non-Javadoc)
223
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreatedBy()
224
	 */
225
	public User getCreatedBy() {
226
		return this.createdBy;
227
	}
228
	/* (non-Javadoc)
229
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreatedBy(eu.etaxonomy.cdm.model.agent.Person)
230
	 */
231
	public void setCreatedBy(User createdBy) {
232
		this.createdBy = createdBy;
233
	}
234
	
235
// ************************** Hibernate proxies *******************/
236
	/**
237
	 * These methods are present due to HHH-1517 - that in a one-to-many
238
	 * relationship with a superclass at the "one" end, the proxy created
239
	 * by hibernate is the superclass, and not the subclass, resulting in
240
	 * a classcastexception when you try to cast it.
241
	 *
242
	 * Hopefully this will be resolved through improvements with the creation of
243
	 * proxy objects by hibernate and the following methods will become redundant,
244
	 * but for the time being . . .
245
	 * @param <T>
246
	 * @param object
247
	 * @param clazz
248
	 * @return
249
	 * @throws ClassCastException
250
	 */
251
	//non-static does not work because javassist already unwrapps the proxy before calling the method
252
	 public static <T extends CdmBase> T deproxy(Object object, Class<T> clazz) throws ClassCastException {
253
		 return HibernateProxyHelper.deproxy(object, clazz);
254
	 }
255
	        
256
	 public boolean isInstanceOf(Class<? extends CdmBase> clazz) throws ClassCastException {
257
	     return HibernateProxyHelper.isInstanceOf(this, clazz);
258
	 }
259

    
260
// ************* Object overrides *************************/ 
261
	
262
	/**
263
	 * Is true if UUID is the same for the passed Object and this one.
264
	 * @see java.lang.Object#equals(java.lang.Object)
265
	 * See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities} 
266
	 * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
267
	 * for more information about equals and hashcode. 
268
	 */
269
	@Override
270
	public boolean equals(Object obj) {
271
		if (obj == this){
272
			return true;
273
		}
274
		if (obj == null){
275
			return false;
276
		}
277
		if (!CdmBase.class.isAssignableFrom(obj.getClass())){
278
			return false;
279
		}
280
		ICdmBase cdmObj = (ICdmBase)obj;
281
		boolean uuidEqual = cdmObj.getUuid().equals(this.getUuid());
282
		boolean createdEqual = cdmObj.getCreated().equals(this.getCreated());
283
		if (! uuidEqual || !createdEqual){
284
				return false;
285
		}
286
		return true;
287
	}
288

    
289
	
290
	/** Overrides {@link java.lang.Object#hashCode()}
291
	 *  See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities} 
292
	 * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
293
	 * for more information about equals and hashcode. 
294
	 */
295
	@Override
296
	public int hashCode() {
297
		   int hashCode = 7;
298
		   hashCode = 29 * hashCode + this.getUuid().hashCode();
299
		   return hashCode;
300
	}
301

    
302
	/**
303
	 * Overrides {@link java.lang.Object#toString()}.
304
	 * This returns an String that identifies the object well without beeing necessarily unique.
305
	 * Specification: This method should never call other object' methods so it can be well used for debugging 
306
	 * without problems like lazy loading, unreal states etc.
307
	 * Note: If overriding this method's javadoc always copy or link the above requirement. 
308
	 * If not overwritten by a subclass method returns the class, id and uuid as a string for any CDM object. 
309
	 * For example: Taxon#13<b5938a98-c1de-4dda-b040-d5cc5bfb3bc0>
310
	 * @see java.lang.Object#toString()
311
	 */
312
	@Override
313
	public String toString() {
314
		return this.getClass().getSimpleName()+"#"+this.getId()+"<"+this.getUuid()+">";
315
	}
316
	
317
// **************** invoke methods **************************/
318
	
319
	protected void invokeSetMethod(Method method, Object object){
320
		try {
321
			method.invoke(object, this);
322
		} catch (Exception e) {
323
			e.printStackTrace();
324
			//TODO handle exceptioin;
325
		}
326
	}
327
	
328
	protected void invokeSetMethodWithNull(Method method, Object object){
329
		try {
330
			Object[] nul = new Object[]{null}; 
331
			method.invoke(object, nul);
332
		} catch (Exception e) {
333
			e.printStackTrace();
334
			//TODO handle exceptioin;
335
		}
336
	}
337
	
338
//********************** CLONE *****************************************/
339
	
340
	protected void clone(CdmBase clone){
341
		clone.setCreatedBy(createdBy);
342
		clone.setId(id);
343
		//Constructor Attributes
344
		//clone.setCreated(created);
345
		//clone.setUuid(getUuid());
346

    
347
	}
348
	
349
	/* (non-Javadoc)
350
	 * @see java.lang.Object#clone()
351
	 */
352
	@Override
353
	public Object clone() throws CloneNotSupportedException{
354
		CdmBase result = (CdmBase)super.clone();
355
		
356
		//TODO ?
357
		result.setId(0);
358
		result.setUuid(UUID.randomUUID());
359
		result.setCreated(new DateTime());
360
		result.setCreatedBy(null);
361
		
362
		//no changes to: -
363
		return result;
364
	}
365
	
366
}
(4-4/62)