(no commit message)
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / VersionableEntity.java
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
10 package eu.etaxonomy.cdm.model.common;
11
12 import eu.etaxonomy.cdm.model.agent.Person;
13 import org.apache.log4j.Logger;
14 import org.hibernate.annotations.Cascade;
15 import org.hibernate.annotations.CascadeType;
16
17 import java.util.*;
18
19 import javax.persistence.*;
20 import javax.xml.bind.annotation.XmlAccessType;
21 import javax.xml.bind.annotation.XmlAccessorType;
22 import javax.xml.bind.annotation.XmlElement;
23 import javax.xml.bind.annotation.XmlRootElement;
24 import javax.xml.bind.annotation.XmlTransient;
25 import javax.xml.bind.annotation.XmlType;
26
27 /**
28 * The class keeps track of versions via a full linked list to different version objects, or a simple updated/updatedBy property in the same object.
29 *
30 * Full versioning allows concrete subclasses to keep track of previous or later versions of an object.
31 * A different version is another (persistent) java object, but with the same UUID.
32 * The version history is established as a linked list of the version objects in time.
33 * If versioning via the linked list is used, updated/updatedBy is the same as created/createdBy (better NULL?).
34 *
35 * Versioning can be turned off and in this case this class provides updated/updatedBy to keep track of the latest change event.
36 *
37 * @author m.doering
38 * @created 08-Nov-2007 13:07:01
39 *
40 * @param <T>
41 */
42 @XmlAccessorType(XmlAccessType.FIELD)
43 @XmlType(name = "VersionableEntity", propOrder = {
44 // "updated",
45 "updatedBy",
46 "nextVersion",
47 "previousVersion"
48 })
49 @XmlRootElement(name = "VersionableEntity")
50 @MappedSuperclass
51 public abstract class VersionableEntity<T extends VersionableEntity> extends CdmBase {
52 private static final Logger logger = Logger.getLogger(VersionableEntity.class);
53
54 //time of last update for this object
55 // There is a problem with "updated" during deserialization because of the @Version annotation.
56 @XmlTransient
57 //@XmlElement(name ="Updated")
58 private Calendar updated;
59
60 @XmlElement(name = "UpdatedBy")
61 private Person updatedBy;
62
63 @XmlElement(name = "NextVersion")
64 private T nextVersion;
65
66 @XmlElement(name = "PreviousVersion")
67 private T previousVersion;
68
69
70 /**
71 * Returns the succeeding version of this object with the same UUID
72 * @return next, i.e. succeeding version of this object
73 */
74 //@OneToOne(mappedBy="previousVersion")
75 @Transient
76 public T getNextVersion(){
77 return this.nextVersion;
78 }
79 public void setNextVersion(T nextVersion){
80 this.nextVersion = nextVersion;
81 }
82
83 //@OneToOne
84 @Transient
85 public T getPreviousVersion(){
86 return this.previousVersion;
87 }
88 public void setPreviousVersion(T previousVersion){
89 this.previousVersion = previousVersion;
90 }
91
92
93 @ManyToOne(fetch=FetchType.LAZY)
94 @Cascade({CascadeType.SAVE_UPDATE})
95 public Person getUpdatedBy(){
96 return this.updatedBy;
97 }
98
99 /**
100 *
101 * @param updatedBy updatedBy
102 */
103 public void setUpdatedBy(Person updatedBy){
104 this.updatedBy = updatedBy;
105 }
106
107 /**
108 *
109 * @return
110 */
111 @Temporal(TemporalType.TIMESTAMP)
112 @Version
113 @Basic(fetch = FetchType.LAZY)
114 public Calendar getUpdated(){
115 return this.updated;
116 }
117
118 /**
119 *
120 * @param updated updated
121 */
122 public void setUpdated(Calendar updated){
123 this.updated = updated;
124 }
125
126 /**
127 * based on created
128 */
129 @Transient
130 public Calendar getValidFrom(){
131 return null;
132 }
133
134 /**
135 * based on updated
136 */
137 @Transient
138 public Calendar getValidTo(){
139 return null;
140 }
141
142 /**
143 * Is true if UUID and created timestamp are the same for the passed Object and this one.
144 * @see eu.etaxonomy.cdm.model.common.CdmBase#equals(java.lang.Object)
145 * See {@link http://www.hibernate.org/109.html hibernate109}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html geocities}
146 * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html ibm}
147 * for more information about equals and hashcode.
148 */
149 @Override
150 public boolean equals(Object obj) {
151 if (obj == this){
152 return true;
153 }
154 if (obj == null){
155 return false;
156 }
157 if (!CdmBase.class.isAssignableFrom(obj.getClass())){
158 return false;
159 }
160 ICdmBase cdmObj = (ICdmBase)obj;
161 boolean uuidEqual = cdmObj.getUuid().equals(this.getUuid());
162 boolean createdEqual = cdmObj.getCreated().equals(this.getCreated());
163 if (! uuidEqual || !createdEqual){
164 return false;
165 }
166 return true;
167 }
168
169
170 /** Overrides {@link eu.etaxonomy.cdm.model.common.CdmBase#hashCode()}
171 * See {@link http://www.hibernate.org/109.html}, {@link http://www.geocities.com/technofundo/tech/java/equalhash.html}
172 * or {@link http://www.ibm.com/developerworks/java/library/j-jtp05273.html}
173 * for more information about equals and hashcode.
174 */
175 @Override
176 public int hashCode() {
177 int hashCode = 7;
178 hashCode = 29 * hashCode + this.getUuid().hashCode();
179 //hashCode = 29 * hashCode + this.getCreated().hashCode();
180 return hashCode;
181 }
182
183 //********************** CLONE *****************************************/
184
185 /**
186 * Clones this versionable entity.
187 * Set fields for nextVersion, previousVersion, updated, updatedBy and createdBy are set to <tt>null</tt>
188 * The id is set to 0.
189 * The uuid is created new.
190 * The createdWhen is set to the current date.
191 * @see java.lang.Object#clone()
192 */
193 public Object clone() throws CloneNotSupportedException{
194 VersionableEntity result = (VersionableEntity)super.clone();
195
196 //TODO ?
197 result.setNextVersion(null);
198 result.setPreviousVersion(null);
199 result.setUpdated(null);
200 result.setUpdatedBy(null);
201
202 //no changes to: -
203 return result;
204 }
205 }