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
	@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
}
(4-4/62)