root/trunk/cdmlib/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/common/CdmBase.java

Revision 14489, 12.6 kB (checked in by n.hoffmann, 2 months ago)

Fixes a problem with the new ID generator, that prevented the creation of new CDM objects

  • Property svn:keywords set to Id
Line 
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*/
9package eu.etaxonomy.cdm.model.common;
10
11import java.beans.PropertyChangeEvent;
12import java.beans.PropertyChangeListener;
13import java.beans.PropertyChangeSupport;
14import java.io.Serializable;
15import java.lang.reflect.Method;
16import java.util.UUID;
17
18import javax.persistence.Basic;
19import javax.persistence.Column;
20import javax.persistence.FetchType;
21import javax.persistence.GeneratedValue;
22import javax.persistence.Id;
23import javax.persistence.ManyToOne;
24import javax.persistence.MappedSuperclass;
25import javax.persistence.Transient;
26import javax.validation.constraints.Min;
27import javax.validation.constraints.NotNull;
28import javax.xml.bind.annotation.XmlAccessType;
29import javax.xml.bind.annotation.XmlAccessorType;
30import javax.xml.bind.annotation.XmlAttribute;
31import javax.xml.bind.annotation.XmlElement;
32import javax.xml.bind.annotation.XmlID;
33import javax.xml.bind.annotation.XmlIDREF;
34import javax.xml.bind.annotation.XmlSchemaType;
35import javax.xml.bind.annotation.XmlTransient;
36import javax.xml.bind.annotation.XmlType;
37import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
38
39import org.apache.log4j.Logger;
40import org.hibernate.annotations.GenericGenerator;
41import org.hibernate.annotations.NaturalId;
42import org.hibernate.annotations.Type;
43import org.hibernate.search.annotations.DocumentId;
44import org.hibernate.search.annotations.Field;
45import org.hibernate.search.annotations.FieldBridge;
46import org.joda.time.DateTime;
47
48import eu.etaxonomy.cdm.hibernate.DateTimeBridge;
49import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
50import eu.etaxonomy.cdm.jaxb.DateTimeAdapter;
51import eu.etaxonomy.cdm.jaxb.UUIDAdapter;
52import eu.etaxonomy.cdm.strategy.match.Match;
53import eu.etaxonomy.cdm.strategy.match.MatchMode;
54
55
56
57
58/**
59 * The base class for all CDM domain classes implementing UUIDs and bean property change event firing.
60 * It provides a globally unique UUID and keeps track of creation date and person.
61 * The UUID is the same for different versions (see {@link VersionableEntity}) of a CDM object, so a locally unique id exists in addition
62 * that allows to safely access and store several objects (=version) with the same UUID.
63 *
64 * This class together with the {@link eu.etaxonomy.cdm.aspectj.PropertyChangeAspect}
65 * will fire bean change events to all registered listeners. Listener registration and event firing
66 * is done with the help of the {@link PropertyChangeSupport} class.
67 *
68 * @author m.doering
69 *
70 */
71@XmlAccessorType(XmlAccessType.FIELD)
72@XmlType(name = "CdmBase", propOrder = {
73    "created",
74    "createdBy"
75})
76@MappedSuperclass
77public abstract class CdmBase implements Serializable, ICdmBase, Cloneable{
78        private static final long serialVersionUID = -3053225700018294809L;
79        @SuppressWarnings("unused")
80        private static final Logger logger = Logger.getLogger(CdmBase.class);
81
82        @Transient
83        @XmlTransient
84        private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
85
86        //@XmlAttribute(name = "id", required = true)
87        @XmlTransient
88        @Id
89//      @GeneratedValue(generator = "system-increment")
90//      @GeneratedValue(generator = "enhanced-table")
91        @GeneratedValue(generator = "custom-enhanced-table")
92        @DocumentId
93        @Match(MatchMode.IGNORE)
94        @NotNull
95        @Min(0)
96        private int id;
97
98        @XmlAttribute(required = true)
99    @XmlJavaTypeAdapter(UUIDAdapter.class)
100    @Type(type="uuidUserType")
101        @NaturalId // This has the effect of placing a "unique" constraint on the database column
102        @XmlID
103        @Column(length=36)
104        @Match(MatchMode.IGNORE)
105        @NotNull
106        protected UUID uuid;
107
108        @XmlElement (name = "Created", type= String.class)
109        @XmlJavaTypeAdapter(DateTimeAdapter.class)
110        @Type(type="dateTimeUserType")
111        @Basic(fetch = FetchType.LAZY)
112        @Match(MatchMode.IGNORE)
113        @Field(index = org.hibernate.search.annotations.Index.UN_TOKENIZED)
114        @FieldBridge(impl = DateTimeBridge.class)
115        private DateTime created;
116
117        @XmlElement (name = "CreatedBy")
118        @XmlIDREF
119        @XmlSchemaType(name = "IDREF")
120        @ManyToOne(fetch=FetchType.LAZY)
121    @Match(MatchMode.IGNORE)
122        private User createdBy;
123
124        /**
125         * Class constructor assigning a unique UUID and creation date.
126         * UUID can be changed later via setUuid method.
127         */
128        public CdmBase() {
129                this.uuid = UUID.randomUUID();
130                this.created = new DateTime().withMillisOfSecond(0);
131        }
132
133        /**
134         * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
135         * @param listener
136         */
137        public void addPropertyChangeListener(PropertyChangeListener listener) {
138                propertyChangeSupport.addPropertyChangeListener(listener);
139        }
140
141        /**
142         * see {@link PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)}
143         */
144        public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
145                propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
146        }
147
148        /**
149         * see {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
150         */
151        public void removePropertyChangeListener(PropertyChangeListener listener) {
152                propertyChangeSupport.removePropertyChangeListener(listener);
153        }
154
155        /**
156         * @see PropertyChangeSupport#addPropertyChangeListener(String, PropertyChangeListener)
157         */
158        public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
159                propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
160        }
161
162        public boolean hasListeners(String propertyName) {
163                return propertyChangeSupport.hasListeners(propertyName);
164        }
165
166        public void firePropertyChange(String property, String oldval, String newval) {
167                propertyChangeSupport.firePropertyChange(property, oldval, newval);
168        }
169        public void firePropertyChange(String property, int oldval, int newval) {
170                propertyChangeSupport.firePropertyChange(property, oldval, newval);
171        }
172        public void firePropertyChange(String property, float oldval, float newval) {
173                propertyChangeSupport.firePropertyChange(property, oldval, newval);
174        }
175        public void firePropertyChange(String property, boolean oldval, boolean newval) {
176                propertyChangeSupport.firePropertyChange(property, oldval, newval);
177        }
178        public void firePropertyChange(String property, Object oldval, Object newval) {
179                propertyChangeSupport.firePropertyChange(property, oldval, newval);
180        }
181        public void firePropertyChange(PropertyChangeEvent evt) {
182                propertyChangeSupport.firePropertyChange(evt);
183        }
184
185        /* (non-Javadoc)
186         * @see eu.etaxonomy.cdm.model.common.ICdmBase#getUuid()
187         */
188        public UUID getUuid() {
189                return uuid;
190        }
191        /* (non-Javadoc)
192         * @see eu.etaxonomy.cdm.model.common.ICdmBase#setUuid(java.util.UUID)
193         */
194        public void setUuid(UUID uuid) {
195                this.uuid = uuid;
196        }
197
198        /* (non-Javadoc)
199         * @see eu.etaxonomy.cdm.model.common.ICdmBase#getId()
200         */
201        public int getId() {
202                return this.id;
203        }
204        /* (non-Javadoc)
205         * @see eu.etaxonomy.cdm.model.common.ICdmBase#setId(int)
206         */
207        public void setId(int id) {
208                this.id = id;
209        }
210
211        /* (non-Javadoc)
212         * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreated()
213         */
214        public DateTime getCreated() {
215                return created;
216        }
217        /* (non-Javadoc)
218         * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreated(java.util.Calendar)
219         */
220        public void setCreated(DateTime created) {
221                if (created != null){
222                        new DateTime();
223                        created = created.withMillisOfSecond(0);
224                        //created.set(Calendar.MILLISECOND, 0);  //old, can be deleted
225                }
226                this.created = created;
227        }
228
229
230        /* (non-Javadoc)
231         * @see eu.etaxonomy.cdm.model.common.ICdmBase#getCreatedBy()
232         */
233        public User getCreatedBy() {
234                return this.createdBy;
235        }
236        /* (non-Javadoc)
237         * @see eu.etaxonomy.cdm.model.common.ICdmBase#setCreatedBy(eu.etaxonomy.cdm.model.agent.Person)
238         */
239        public void setCreatedBy(User createdBy) {
240                this.createdBy = createdBy;
241        }
242
243// ************************** Hibernate proxies *******************/
244        /**
245         * These methods are present due to HHH-1517 - that in a one-to-many
246         * relationship with a superclass at the "one" end, the proxy created
247         * by hibernate is the superclass, and not the subclass, resulting in
248         * a classcastexception when you try to cast it.
249         *
250         * Hopefully this will be resolved through improvements with the creation of
251         * proxy objects by hibernate and the following methods will become redundant,
252         * but for the time being . . .
253         * @param <T>
254         * @param object
255         * @param clazz
256         * @return
257         * @throws ClassCastException
258         */
259        //non-static does not work because javassist already unwrapps the proxy before calling the method
260         public static <T extends CdmBase> T deproxy(Object object, Class<T> clazz) throws ClassCastException {
261                 return HibernateProxyHelper.deproxy(object, clazz);
262         }
263
264         public boolean isInstanceOf(Class<? extends CdmBase> clazz) throws ClassCastException {
265             return HibernateProxyHelper.isInstanceOf(this, clazz);
266         }
267
268// ************* Object overrides *************************/
269
270        /**
271         * Is true if UUID is the same for the passed Object and this one.
272         * @see java.lang.Object#equals(java.lang.Object)
273         * See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities}
274         * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
275         * for more information about equals and hashcode.
276         */
277        @Override
278        public boolean equals(Object obj) {
279                if (obj == this){
280                        return true;
281                }
282                if (obj == null){
283                        return false;
284                }
285                if (!CdmBase.class.isAssignableFrom(obj.getClass())){
286                        return false;
287                }
288                ICdmBase cdmObj = (ICdmBase)obj;
289                boolean uuidEqual = cdmObj.getUuid().equals(this.getUuid());
290                boolean createdEqual = cdmObj.getCreated().equals(this.getCreated());
291                if (! uuidEqual || !createdEqual){
292                                return false;
293                }
294                return true;
295        }
296
297
298        /** Overrides {@link java.lang.Object#hashCode()}
299         *  See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities}
300         * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
301         * for more information about equals and hashcode.
302         */
303        @Override
304        public int hashCode() {
305                   int hashCode = 7;
306                   if(this.getUuid() != null) {
307                           //this unfortunately leads to errors when loading maps via hibernate
308                           //as hibernate computes hash values for CdmBase objects used as key at
309                           // a time when the uuid is not yet loaded from the database. Therefore
310                           //the hash values later change and give wrong results when retrieving
311                           //data from the map (map.get(key) returns null, though there is an entry
312                           //for key in the map.
313                           //see further comments in #2114
314                       int result = 29 * hashCode + this.getUuid().hashCode();
315//                     int shresult = 29 * hashCode + Integer.valueOf(this.getId()).hashCode();
316                           return result;
317                   } else {
318                           return 29 * hashCode;
319                   }
320        }
321
322        /**
323         * Overrides {@link java.lang.Object#toString()}.
324         * This returns an String that identifies the object well without beeing necessarily unique.
325         * Specification: This method should never call other object' methods so it can be well used for debugging
326         * without problems like lazy loading, unreal states etc.
327         * Note: If overriding this method's javadoc always copy or link the above requirement.
328         * If not overwritten by a subclass method returns the class, id and uuid as a string for any CDM object.
329         * For example: Taxon#13<b5938a98-c1de-4dda-b040-d5cc5bfb3bc0>
330         * @see java.lang.Object#toString()
331         */
332        @Override
333        public String toString() {
334                return this.getClass().getSimpleName()+"#"+this.getId()+"<"+this.getUuid()+">";
335        }
336
337// **************** invoke methods **************************/
338
339        protected void invokeSetMethod(Method method, Object object){
340                try {
341                        method.invoke(object, this);
342                } catch (Exception e) {
343                        e.printStackTrace();
344                        //TODO handle exceptioin;
345                }
346        }
347
348        protected void invokeSetMethodWithNull(Method method, Object object){
349                try {
350                        Object[] nul = new Object[]{null};
351                        method.invoke(object, nul);
352                } catch (Exception e) {
353                        e.printStackTrace();
354                        //TODO handle exceptioin;
355                }
356        }
357
358//********************** CLONE *****************************************/
359
360        protected void clone(CdmBase clone){
361                clone.setCreatedBy(createdBy);
362                clone.setId(id);
363                clone.propertyChangeSupport=new PropertyChangeSupport(clone);
364                //Constructor Attributes
365                //clone.setCreated(created);
366                //clone.setUuid(getUuid());
367
368        }
369
370        /* (non-Javadoc)
371         * @see java.lang.Object#clone()
372         */
373        @Override
374        public Object clone() throws CloneNotSupportedException{
375                CdmBase result = (CdmBase)super.clone();
376                result.propertyChangeSupport=new PropertyChangeSupport(result);
377
378                //TODO ?
379                result.setId(0);
380                result.setUuid(UUID.randomUUID());
381                result.setCreated(new DateTime());
382                result.setCreatedBy(null);
383
384                //no changes to: -
385                return result;
386        }
387
388}
Note: See TracBrowser for help on using the browser.