Project

General

Profile

Download (11.8 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.Min;
27
import javax.validation.constraints.NotNull;
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.hibernate.search.annotations.Field;
44
import org.hibernate.search.annotations.FieldBridge;
45
import org.joda.time.DateTime;
46

    
47
import eu.etaxonomy.cdm.hibernate.DateTimeBridge;
48
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
49
import eu.etaxonomy.cdm.jaxb.DateTimeAdapter;
50
import eu.etaxonomy.cdm.jaxb.UUIDAdapter;
51
import eu.etaxonomy.cdm.strategy.match.Match;
52
import eu.etaxonomy.cdm.strategy.match.MatchMode;
53

    
54

    
55

    
56

    
57
/**
58
 * The base class for all CDM domain classes implementing UUIDs and bean property change event firing.
59
 * It provides a globally unique UUID and keeps track of creation date and person.
60
 * The UUID is the same for different versions (see {@link VersionableEntity}) of a CDM object, so a locally unique id exists in addition 
61
 * that allows to safely access and store several objects (=version) with the same UUID.
62
 * 
63
 * This class together with the {@link eu.etaxonomy.cdm.aspectj.PropertyChangeAspect} 
64
 * will fire bean change events to all registered listeners. Listener registration and event firing
65
 * is done with the help of the {@link PropertyChangeSupport} class.
66
 * 
67
 * @author m.doering
68
 *
69
 */
70
@XmlAccessorType(XmlAccessType.FIELD)
71
@XmlType(name = "CdmBase", propOrder = {
72
    "created",
73
    "createdBy"
74
})
75
@MappedSuperclass
76
public abstract class CdmBase implements Serializable, ICdmBase{
77
	private static final long serialVersionUID = -3053225700018294809L;
78
	@SuppressWarnings("unused")
79
	private static final Logger logger = Logger.getLogger(CdmBase.class);
80
	
81
	@Transient
82
	@XmlTransient
83
	private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
84
	
85
	//@XmlAttribute(name = "id", required = true)
86
	@XmlTransient
87
	@Id
88
	@GeneratedValue(generator = "system-increment")
89
	@DocumentId
90
	@Match(MatchMode.IGNORE)
91
	@NotNull
92
	@Min(0)
93
	private int id;
94
    
95
	@XmlAttribute(required = true)
96
    @XmlJavaTypeAdapter(UUIDAdapter.class)
97
    @Type(type="uuidUserType")
98
	@NaturalId // This has the effect of placing a "unique" constraint on the database column
99
	@XmlID
100
	@Column(length=36)
101
	@Match(MatchMode.IGNORE)
102
	@NotNull
103
	protected UUID uuid;
104
	
105
	@XmlElement (name = "Created", type= String.class)
106
	@XmlJavaTypeAdapter(DateTimeAdapter.class)
107
	@Type(type="dateTimeUserType")
108
	@Basic(fetch = FetchType.LAZY)
109
	@Match(MatchMode.IGNORE)
110
	@Field(index = org.hibernate.search.annotations.Index.UN_TOKENIZED)
111
	@FieldBridge(impl = DateTimeBridge.class)
112
	private DateTime created;
113
	
114
	@XmlElement (name = "CreatedBy")
115
	@XmlIDREF
116
	@XmlSchemaType(name = "IDREF")
117
	@ManyToOne(fetch=FetchType.LAZY)
118
    @Match(MatchMode.IGNORE)
119
	private User createdBy;
120

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

    
138
	/**
139
	 * see {@link PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)}
140
	 */
141
	public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
142
		propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
143
	}
144

    
145
	/**
146
	 * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
147
	 */
148
	public void removePropertyChangeListener(PropertyChangeListener listener) {
149
		propertyChangeSupport.removePropertyChangeListener(listener);
150
	}
151
	
152
	/**
153
	 * @see PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)
154
	 */
155
	public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
156
		propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
157
	}
158
	
159
	public boolean hasListeners(String propertyName) {
160
		return propertyChangeSupport.hasListeners(propertyName);
161
	}
162

    
163
	public void firePropertyChange(String property, String oldval, String newval) {
164
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
165
	}
166
	public void firePropertyChange(String property, int oldval, int newval) {
167
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
168
	}
169
	public void firePropertyChange(String property, float oldval, float newval) {
170
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
171
	}
172
	public void firePropertyChange(String property, boolean oldval, boolean newval) {
173
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
174
	}
175
	public void firePropertyChange(String property, Object oldval, Object newval) {
176
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
177
	}
178
	public void firePropertyChange(PropertyChangeEvent evt) {
179
		propertyChangeSupport.firePropertyChange(evt);
180
	}
181

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

    
226

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

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

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

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

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