Project

General

Profile

Download (12.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.GenericGenerator;
41
import org.hibernate.annotations.NaturalId;
42
import org.hibernate.annotations.OptimisticLock;
43
import org.hibernate.annotations.Type;
44
import org.hibernate.search.annotations.DocumentId;
45
import org.hibernate.search.annotations.Field;
46
import org.hibernate.search.annotations.FieldBridge;
47
import org.joda.time.DateTime;
48

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

    
56

    
57

    
58

    
59
/**
60
 * The base class for all CDM domain classes implementing UUIDs and bean property change event firing.
61
 * It provides a globally unique UUID and keeps track of creation date and person.
62
 * The UUID is the same for different versions (see {@link VersionableEntity}) of a CDM object, so a locally unique id exists in addition
63
 * that allows to safely access and store several objects (=version) with the same UUID.
64
 *
65
 * This class together with the {@link eu.etaxonomy.cdm.aspectj.PropertyChangeAspect}
66
 * will fire bean change events to all registered listeners. Listener registration and event firing
67
 * is done with the help of the {@link PropertyChangeSupport} class.
68
 *
69
 * @author m.doering
70
 *
71
 */
72
@XmlAccessorType(XmlAccessType.FIELD)
73
@XmlType(name = "CdmBase", propOrder = {
74
    "created",
75
    "createdBy"
76
})
77
@MappedSuperclass
78
public abstract class CdmBase implements Serializable, ICdmBase, Cloneable{
79
	private static final long serialVersionUID = -3053225700018294809L;
80
	@SuppressWarnings("unused")
81
	private static final Logger logger = Logger.getLogger(CdmBase.class);
82

    
83
	@Transient
84
	@XmlTransient
85
	private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
86

    
87
	//@XmlAttribute(name = "id", required = true)
88
	@XmlTransient
89
	@Id
90
//	@GeneratedValue(generator = "system-increment")
91
//	@GeneratedValue(generator = "enhanced-table")
92
	@GeneratedValue(generator = "custom-enhanced-table")
93
	@GenericGenerator(name = "custom-enhanced-table", strategy="eu.etaxonomy.cdm.persistence.hibernate.TableGenerator")
94
	@DocumentId
95
	@Match(MatchMode.IGNORE)
96
	@NotNull
97
	@Min(0)
98
	private int id;
99

    
100
	@XmlAttribute(required = true)
101
    @XmlJavaTypeAdapter(UUIDAdapter.class)
102
    @Type(type="uuidUserType")
103
	@NaturalId // This has the effect of placing a "unique" constraint on the database column
104
	@XmlID
105
	@Column(length=36)
106
	@Match(MatchMode.IGNORE)
107
	@NotNull
108
	protected UUID uuid;
109

    
110
	@XmlElement (name = "Created", type= String.class)
111
	@XmlJavaTypeAdapter(DateTimeAdapter.class)
112
	@Type(type="dateTimeUserType")
113
	@Basic(fetch = FetchType.LAZY)
114
	@Match(MatchMode.IGNORE)
115
	@Field(index = org.hibernate.search.annotations.Index.UN_TOKENIZED)
116
	@FieldBridge(impl = DateTimeBridge.class)
117
	private DateTime created;
118

    
119
	@XmlElement (name = "CreatedBy")
120
	@XmlIDREF
121
	@XmlSchemaType(name = "IDREF")
122
	@ManyToOne(fetch=FetchType.LAZY)
123
    @Match(MatchMode.IGNORE)
124
	private User createdBy;
125

    
126
	/**
127
	 * Class constructor assigning a unique UUID and creation date.
128
	 * UUID can be changed later via setUuid method.
129
	 */
130
	public CdmBase() {
131
		this.uuid = UUID.randomUUID();
132
		this.created = new DateTime().withMillisOfSecond(0);
133
	}
134

    
135
	/**
136
	 * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
137
	 * @param listener
138
	 */
139
	public void addPropertyChangeListener(PropertyChangeListener listener) {
140
		propertyChangeSupport.addPropertyChangeListener(listener);
141
	}
142

    
143
	/**
144
	 * see {@link PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)}
145
	 */
146
	public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
147
		propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
148
	}
149

    
150
	/**
151
	 * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
152
	 */
153
	public void removePropertyChangeListener(PropertyChangeListener listener) {
154
		propertyChangeSupport.removePropertyChangeListener(listener);
155
	}
156

    
157
	/**
158
	 * @see PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)
159
	 */
160
	public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
161
		propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
162
	}
163

    
164
	public boolean hasListeners(String propertyName) {
165
		return propertyChangeSupport.hasListeners(propertyName);
166
	}
167

    
168
	public void firePropertyChange(String property, String oldval, String newval) {
169
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
170
	}
171
	public void firePropertyChange(String property, int oldval, int newval) {
172
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
173
	}
174
	public void firePropertyChange(String property, float oldval, float newval) {
175
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
176
	}
177
	public void firePropertyChange(String property, boolean oldval, boolean newval) {
178
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
179
	}
180
	public void firePropertyChange(String property, Object oldval, Object newval) {
181
		propertyChangeSupport.firePropertyChange(property, oldval, newval);
182
	}
183
	public void firePropertyChange(PropertyChangeEvent evt) {
184
		propertyChangeSupport.firePropertyChange(evt);
185
	}
186

    
187
	/* (non-Javadoc)
188
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getUuid()
189
	 */
190
	public UUID getUuid() {
191
		return uuid;
192
	}
193
	/* (non-Javadoc)
194
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setUuid(java.util.UUID)
195
	 */
196
	public void setUuid(UUID uuid) {
197
		this.uuid = uuid;
198
	}
199

    
200
	/* (non-Javadoc)
201
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getId()
202
	 */
203
	public int getId() {
204
		return this.id;
205
	}
206
	/* (non-Javadoc)
207
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setId(int)
208
	 */
209
	public void setId(int id) {
210
		this.id = id;
211
	}
212

    
213
	/* (non-Javadoc)
214
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreated()
215
	 */
216
	public DateTime getCreated() {
217
		return created;
218
	}
219
	/* (non-Javadoc)
220
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreated(java.util.Calendar)
221
	 */
222
	public void setCreated(DateTime created) {
223
		if (created != null){
224
			new DateTime();
225
			created = created.withMillisOfSecond(0);
226
			//created.set(Calendar.MILLISECOND, 0);  //old, can be deleted
227
		}
228
		this.created = created;
229
	}
230

    
231

    
232
	/* (non-Javadoc)
233
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreatedBy()
234
	 */
235
	public User getCreatedBy() {
236
		return this.createdBy;
237
	}
238
	/* (non-Javadoc)
239
	 * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreatedBy(eu.etaxonomy.cdm.model.agent.Person)
240
	 */
241
	public void setCreatedBy(User createdBy) {
242
		this.createdBy = createdBy;
243
	}
244

    
245
// ************************** Hibernate proxies *******************/
246
	/**
247
	 * These methods are present due to HHH-1517 - that in a one-to-many
248
	 * relationship with a superclass at the "one" end, the proxy created
249
	 * by hibernate is the superclass, and not the subclass, resulting in
250
	 * a classcastexception when you try to cast it.
251
	 *
252
	 * Hopefully this will be resolved through improvements with the creation of
253
	 * proxy objects by hibernate and the following methods will become redundant,
254
	 * but for the time being . . .
255
	 * @param <T>
256
	 * @param object
257
	 * @param clazz
258
	 * @return
259
	 * @throws ClassCastException
260
	 */
261
	//non-static does not work because javassist already unwrapps the proxy before calling the method
262
	 public static <T extends CdmBase> T deproxy(Object object, Class<T> clazz) throws ClassCastException {
263
		 return HibernateProxyHelper.deproxy(object, clazz);
264
	 }
265

    
266
	 public boolean isInstanceOf(Class<? extends CdmBase> clazz) throws ClassCastException {
267
	     return HibernateProxyHelper.isInstanceOf(this, clazz);
268
	 }
269

    
270
// ************* Object overrides *************************/
271

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

    
299

    
300
	/** Overrides {@link java.lang.Object#hashCode()}
301
	 *  See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities}
302
	 * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
303
	 * for more information about equals and hashcode.
304
	 */
305
	@Override
306
	public int hashCode() {
307
		   int hashCode = 7;
308
		   if(this.getUuid() != null) {
309
			   //this unfortunately leads to errors when loading maps via hibernate
310
			   //as hibernate computes hash values for CdmBase objects used as key at
311
			   // a time when the uuid is not yet loaded from the database. Therefore
312
			   //the hash values later change and give wrong results when retrieving
313
			   //data from the map (map.get(key) returns null, though there is an entry
314
			   //for key in the map.
315
			   //see further comments in #2114
316
		       int result = 29 * hashCode + this.getUuid().hashCode();
317
//		       int shresult = 29 * hashCode + Integer.valueOf(this.getId()).hashCode();
318
			   return result;
319
		   } else {
320
			   return 29 * hashCode;
321
		   }
322
	}
323

    
324
	/**
325
	 * Overrides {@link java.lang.Object#toString()}.
326
	 * This returns an String that identifies the object well without beeing necessarily unique.
327
	 * Specification: This method should never call other object' methods so it can be well used for debugging
328
	 * without problems like lazy loading, unreal states etc.
329
	 * Note: If overriding this method's javadoc always copy or link the above requirement.
330
	 * If not overwritten by a subclass method returns the class, id and uuid as a string for any CDM object.
331
	 * For example: Taxon#13<b5938a98-c1de-4dda-b040-d5cc5bfb3bc0>
332
	 * @see java.lang.Object#toString()
333
	 */
334
	@Override
335
	public String toString() {
336
		return this.getClass().getSimpleName()+"#"+this.getId()+"<"+this.getUuid()+">";
337
	}
338

    
339
// **************** invoke methods **************************/
340

    
341
	protected void invokeSetMethod(Method method, Object object){
342
		try {
343
			method.invoke(object, this);
344
		} catch (Exception e) {
345
			e.printStackTrace();
346
			//TODO handle exceptioin;
347
		}
348
	}
349

    
350
	protected void invokeSetMethodWithNull(Method method, Object object){
351
		try {
352
			Object[] nul = new Object[]{null};
353
			method.invoke(object, nul);
354
		} catch (Exception e) {
355
			e.printStackTrace();
356
			//TODO handle exceptioin;
357
		}
358
	}
359

    
360
//********************** CLONE *****************************************/
361

    
362
	protected void clone(CdmBase clone){
363
		clone.setCreatedBy(createdBy);
364
		clone.setId(id);
365
		clone.propertyChangeSupport=new PropertyChangeSupport(clone);
366
		//Constructor Attributes
367
		//clone.setCreated(created);
368
		//clone.setUuid(getUuid());
369

    
370
	}
371

    
372
	/* (non-Javadoc)
373
	 * @see java.lang.Object#clone()
374
	 */
375
	@Override
376
	public Object clone() throws CloneNotSupportedException{
377
		CdmBase result = (CdmBase)super.clone();
378
		result.propertyChangeSupport=new PropertyChangeSupport(result);
379

    
380
		//TODO ?
381
		result.setId(0);
382
		result.setUuid(UUID.randomUUID());
383
		result.setCreated(new DateTime());
384
		result.setCreatedBy(null);
385

    
386
		//no changes to: -
387
		return result;
388
	}
389

    
390
}
(5-5/63)