001 package com.sptci.prevayler;
002
003 import java.util.Date;
004
005 /**
006 * Abstract base class whose instances are stored in the prevalent system.
007 * At present sptodb does not support persisting other types of classes.
008 * This restriction was introduced since we need a {@link #objectId} field
009 * in the class that can be managed by the prevalent system. Making this
010 * an interface would not guarantee us the availability of such a field.
011 *
012 * <p>© Copyright 2008 <a href='http://sptci.com/' target='_top'>Sans
013 * Pareil Technologies, Inc.</a></p>
014 * @author Rakesh Vidyadharan 2008-05-22
015 * @version $Id: PrevalentObject.java 22 2008-11-24 19:04:25Z sptrakesh $
016 */
017 public abstract class PrevalentObject<K>
018 implements java.io.Serializable, Cloneable, Comparable<PrevalentObject<K>>
019 {
020 private static final long serialVersionUID = 1L;
021
022 /** The object id field for the instance. */
023 private K objectId;
024
025 /**
026 * The metadata for the persistent object. This field will be maintained
027 * by the {@link PrevalentSystem} when persistent operations on the object
028 * are performed.
029 */
030 private MetaData _sptodbMetaData;
031
032 /** Default constructor. Note that a no-arg constructor is mandatory. */
033 protected PrevalentObject() {}
034
035 /**
036 * Create a new instance of the prevalent object with the specified object
037 * id. Use this form only when you wish to control the object id (using
038 * custom object id such as {@link java.lang.String}.
039 *
040 * @param oid The {@link #objectId} value to use.
041 */
042 protected PrevalentObject( final K oid )
043 {
044 this.objectId = oid;
045 }
046
047 /**
048 * Compare the specified object with this instance for equality. Two
049 * objects are considered equal if they have the same class and have the
050 * same value of {@link #objectId}. Sub-classes are strongly discouraged
051 * from over-riding this method, since this method compares strictly based
052 * on {@link #objectId} equality. In case you need to over-ride this
053 * method it is strongly recommended that you apply the additional rules
054 * after having invoked this implementation.
055 *
056 * @param object The object to be compared for equality with this object.
057 * @return Return <code>true</code> if the specified object is equivalent
058 * to this object.
059 */
060 @Override
061 public boolean equals( final Object object )
062 {
063 if ( this == object ) return true;
064 if ( object == null ) return false;
065 boolean result = false;
066
067 if ( ( getClass() == object.getClass() ) && ( objectId != null ) )
068 {
069 PrevalentObject po = (PrevalentObject) object;
070 result = objectId.equals( po.getObjectId() );
071 }
072
073 return result;
074 }
075
076 /**
077 * Default implementation of {@link java.lang.Object#hashCode}. Over-ridden
078 * to return the hash code based upon {@link #objectId}. Similar to
079 * {@link #equals}, sub-classes are discouraged from over-riding this
080 * default implementation.
081 *
082 * @return The hash code for this object.
083 */
084 @Override
085 public int hashCode()
086 {
087 int hash = 7;
088
089 hash += ( 31 * 7 ) + getClass().getName().hashCode();
090 hash += ( 31 * 7 ) + ( ( objectId == null ) ? 0 : objectId.hashCode() );
091
092 return hash;
093 }
094
095 /**
096 * Compare the specified prevalent object with this instance for ordering.
097 * Returns a positive integer if the specified object is considered greater
098 * than this instance, 0 if equal and negative is less. Default
099 * implementation compares based upon {@link #objectId}. Sub-classes may
100 * need to over-ride this method for special handling.
101 *
102 * @param prevalentObject The object to be compared with this instance.
103 * @return A positive, 0, or negative number.
104 */
105 @SuppressWarnings( {"unchecked"} )
106 public int compareTo( final PrevalentObject prevalentObject )
107 {
108 int result = 0;
109
110 if ( ( objectId != null ) && ( objectId instanceof Comparable ) )
111 {
112 result = ( (Comparable) objectId ).compareTo(
113 prevalentObject.getObjectId() );
114 }
115
116 return result;
117 }
118
119 /**
120 * Return a string representation of this object. The default
121 * implementation just return the class name and {@link #objectId}.
122 *
123 * @return The string representation of this object.
124 */
125 @Override
126 public String toString()
127 {
128 final StringBuilder builder = new StringBuilder( 64 );
129 builder.append( getClass().getName() );
130 builder.append( " objectId=" ).append( objectId );
131
132 if ( _sptodbMetaData != null )
133 {
134 builder.append( " created=" ).append( getCreationDate() );
135 builder.append( " updated=" ).append( getModificationDate() );
136 }
137
138 return builder.toString();
139 }
140
141 /**
142 * Over-ridden to make publicly accessible.
143 *
144 * @return The cloned instance of this object.
145 * @throws RuntimeException If the object cannot be cloned.
146 */
147 @Override
148 public Object clone() throws RuntimeException
149 {
150 try
151 {
152 return super.clone();
153 }
154 catch ( CloneNotSupportedException cex )
155 {
156 throw new RuntimeException( cex );
157 }
158 }
159
160 /**
161 * Getter for property {@link #_sptodbMetaData}.
162 *
163 * @return Value for property {@link #_sptodbMetaData}.
164 */
165 final MetaData get_sptodbMetaData()
166 {
167 return _sptodbMetaData;
168 }
169
170 /**
171 * Setter for property {@link #_sptodbMetaData}.
172 *
173 * @see #get_sptodbMetaData
174 * @param metadata Value to set for property {@link #_sptodbMetaData}.
175 */
176 final void set_sptodbMetaData( final MetaData metadata )
177 {
178 this._sptodbMetaData = metadata;
179 }
180
181 /**
182 * Return the object id for the business object.
183 *
184 * @return The {@link #objectId} value.
185 */
186 public final K getObjectId()
187 {
188 return objectId;
189 }
190
191 /**
192 * Return the date at which this object was created. Note that the date
193 * will return different values until the object is initially persisted
194 * to the prevalent system.
195 *
196 * @return The date at which the object was persisted.
197 */
198 public final Date getCreationDate()
199 {
200 return ( _sptodbMetaData == null ) ? new Date() :
201 new Date( _sptodbMetaData.created );
202 }
203
204 /**
205 * Return the date at which this object was last updated in the prevalent
206 * system. Note that the date returned will return different values until
207 * the object has been persisted initially.
208 *
209 * @return The date at which the object was last updated.
210 */
211 public final Date getModificationDate()
212 {
213 return ( _sptodbMetaData == null ) ? new Date() :
214 new Date( _sptodbMetaData.modified );
215 }
216
217 /**
218 * Return a flag indicating whether this instance represents a persistent
219 * instance or not.
220 *
221 * @return Return <code>true</code> if the instance is perstent in the
222 * prevalent system.
223 */
224 public final boolean isPersistent()
225 {
226 return ( _sptodbMetaData != null );
227 }
228
229 /**
230 * Return the {@code objectId} value that may be used to retrieve the
231 * prevalent instance from the specified string representation. This is
232 * mandated by the necessity for storing the {@code objectId} values as
233 * {@link String} instances in the lucene index.
234 *
235 * <p><b>Note:</b> The string value of {@code objectId} stored in the
236 * lucene index is the value returned by {@link Object#toString()}. Your
237 * primary key class must return a meaningful value to be able to
238 * reconstruct the primary key instance.</p>
239 *
240 * @since Version 0.3
241 * @param oid The string value that is to be converted to the proper {@code
242 * objectId} value.
243 * @return The primary key instance.
244 */
245 public abstract K getObjectId( final String oid );
246 }