001: /*
002: * Copyright (c) 2001 - 2005 ivata limited.
003: * All rights reserved.
004: * -----------------------------------------------------------------------------
005: * ivata groupware may be redistributed under the GNU General Public
006: * License as published by the Free Software Foundation;
007: * version 2 of the License.
008: *
009: * These programs are free software; you can redistribute them and/or
010: * modify them under the terms of the GNU General Public License
011: * as published by the Free Software Foundation; version 2 of the License.
012: *
013: * These programs are distributed in the hope that they will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: *
017: * See the GNU General Public License in the file LICENSE.txt for more
018: * details.
019: *
020: * If you would like a copy of the GNU General Public License write to
021: *
022: * Free Software Foundation, Inc.
023: * 59 Temple Place - Suite 330
024: * Boston, MA 02111-1307, USA.
025: *
026: *
027: * To arrange commercial support and licensing, contact ivata at
028: * http://www.ivata.com/contact.jsp
029: * -----------------------------------------------------------------------------
030: * $Log: BaseDO.java,v $
031: * Revision 1.8 2005/10/11 18:51:38 colinmacleod
032: * Fixed some checkstyle and javadoc issues.
033: *
034: * Revision 1.7 2005/10/03 10:21:14 colinmacleod
035: * Fixed some style and javadoc issues.
036: *
037: * Revision 1.6 2005/10/02 14:08:56 colinmacleod
038: * Added/improved log4j logging.
039: *
040: * Revision 1.5 2005/09/29 13:22:46 colinmacleod
041: * Added read-only functionality to data object classes (with a check on each
042: * setter).
043: *
044: * Revision 1.4 2005/04/29 02:48:15 colinmacleod
045: * Data bugfixes.
046: * Changed primary key back to Integer.
047: *
048: * Revision 1.3 2005/04/10 20:09:42 colinmacleod
049: * Added new themes.
050: * Changed id type to String.
051: * Changed i tag to em and b tag to strong.
052: * Improved PicoContainerFactory with NanoContainer scripts.
053: *
054: * Revision 1.2 2005/04/09 17:19:37 colinmacleod
055: * Changed copyright text to GPL v2 explicitly.
056: *
057: * Revision 1.1 2005/03/10 19:23:03 colinmacleod
058: * Moved to ivata groupware.
059: *
060: * Revision 1.2 2004/11/12 15:57:10 colinmacleod
061: * Removed dependencies on SSLEXT.
062: * Moved Persistence classes to ivata masks.
063: *
064: * Revision 1.1 2004/07/13 19:42:44 colinmacleod
065: * Moved project to POJOs from EJBs.
066: * Applied PicoContainer to services layer (replacing session EJBs).
067: * Applied Hibernate to persistence layer (replacing entity EJBs).
068: * -----------------------------------------------------------------------------
069: */
070: package com.ivata.groupware.container.persistence;
071:
072: import org.apache.log4j.Logger;
073:
074: import java.io.IOException;
075: import java.io.ObjectInputStream;
076: import java.io.ObjectOutputStream;
077: import java.io.Serializable;
078:
079: import com.ivata.mask.util.StringHandling;
080: import com.ivata.mask.valueobject.ValueObject;
081:
082: /**
083: * <p>
084: * This data object class is inherited by all others.
085: * </p>
086: *
087: * @author Colin MacLeod
088: * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
089: * @since Mar 27, 2004
090: * @version $Revision: 1.8 $
091: */
092: public abstract class BaseDO implements Serializable, ValueObject {
093: /**
094: * Used in {@link #hashCode()}.
095: */
096: private static final int HASH_CODE_1 = 17;
097:
098: /**
099: * Used in {@link #hashCode()}.
100: */
101: private static final int HASH_CODE_2 = 37;
102: /**
103: * Logger for this class.
104: */
105: private static final Logger logger = Logger.getLogger(BaseDO.class);
106:
107: /**
108: * <p>
109: * Unique identifier of this data object.
110: * </p>
111: */
112: private Integer id;
113:
114: /**
115: * <p>Stores whether users can simply view this value object, or may amend
116: * its contents too.</p>
117: */
118: private boolean readOnly = false;
119:
120: /**
121: * <p>
122: * Safety mechanism to check that the user has the rights to invokve setters
123: * on this object. Throws a <code>RuntimeException</code> if the object is
124: * read-only.
125: * </p>
126: * <p>
127: * You should call this method in all setters of subclasses.
128: * </p>
129: */
130: protected void checkSetter() {
131: if (logger.isDebugEnabled()) {
132: logger.debug("checkSetter() - start");
133: }
134:
135: if (isReadOnly()) {
136: throw new RuntimeException(
137: "Setter called on read-only object (" + toString()
138: + ").");
139: }
140:
141: if (logger.isDebugEnabled()) {
142: logger.debug("checkSetter() - end");
143: }
144: }
145:
146: /**
147: * {@inheritDoc}
148: *
149: * @param compare {@inheritDoc}
150: * @return {@inheritDoc}
151: */
152: public boolean equals(final Object compare) {
153: if (logger.isDebugEnabled()) {
154: logger.debug("equals(Object compare = " + compare
155: + ") - start");
156: }
157:
158: boolean returnboolean = hashCode() == compare.hashCode();
159: if (logger.isDebugEnabled()) {
160: logger.debug("equals(Object) - end - return value = "
161: + returnboolean);
162: }
163: return returnboolean;
164: }
165:
166: /**
167: * <p>
168: * This default implementation simply throws an exception.
169: * </p>
170: *
171: * <p>
172: * This implementation always throws {@link UnsupportedOperationException},
173: * with a description of the subclass for which <code>getDisplayValue</code>
174: * was not overridden.
175: *
176: * @see com.ivata.mask.valueobject.ValueObject#getDisplayValue()
177: */
178: public String getDisplayValue() {
179: if (logger.isDebugEnabled()) {
180: logger.debug("getDisplayValue() - start");
181: }
182:
183: throw new UnsupportedOperationException(
184: "ERROR: getDisplayValue not implemented for "
185: + this .getClass());
186: }
187:
188: /**
189: * <p>
190: * Override this method to return <code>getIdImpl</code> and set the
191: * sequence name for hibernate.
192: * </p>
193: *
194: * @hibernate.id
195: * generator-class = "native"
196: * @return current value of the unique identifier of this dependent value
197: * object.
198: */
199: public Integer getId() {
200: if (logger.isDebugEnabled()) {
201: logger.debug("getId() - start");
202: }
203:
204: if (logger.isDebugEnabled()) {
205: logger.debug("getId() - end - return value = " + id);
206: }
207: return id;
208: }
209:
210: /**
211: * <p>
212: * Implementation for ivata masks interface <code>ValueObject</code>.
213: * </p>
214: *
215: * <p>
216: * Identifies this value object uniquely. This value may only be
217: * <code>null</code> for a new value object.
218: * </p>
219: *
220: * @return unique identifier for this value object.
221: */
222: public final String getIdString() {
223: if (logger.isDebugEnabled()) {
224: logger.debug("getIdString() - start");
225: }
226:
227: String returnString = StringHandling.getNotNull(id, null);
228: if (logger.isDebugEnabled()) {
229: logger.debug("getIdString() - end - return value = "
230: + returnString);
231: }
232: return returnString;
233: }
234:
235: /**
236: * {@inheritDoc}
237: *
238: * @return {@inheritDoc}
239: */
240: public int hashCode() {
241: if (logger.isDebugEnabled()) {
242: logger.debug("hashCode() - start");
243: }
244:
245: String modifier = getClass().getName();
246: int result = HASH_CODE_1;
247: if (getId() == null) {
248: result = HASH_CODE_2 * result;
249: } else {
250: result = HASH_CODE_2 * result + (int) getId().hashCode();
251: }
252: result = HASH_CODE_2 * result + (int) modifier.hashCode();
253:
254: if (logger.isDebugEnabled()) {
255: logger.debug("hashCode() - end - return value = " + result);
256: }
257: return result;
258: }
259:
260: /**
261: * <p>Stores whether users can simply view this value object, or may amend
262: * its contents too.</p>
263: *
264: * @return Returns <code>true</code> if users are only allowed to view
265: * this object, not change it.
266: */
267: public boolean isReadOnly() {
268: if (logger.isDebugEnabled()) {
269: logger.debug("isReadOnly() - start");
270: }
271:
272: if (logger.isDebugEnabled()) {
273: logger.debug("isReadOnly() - end - return value = "
274: + readOnly);
275: }
276: return readOnly;
277: }
278:
279: /**
280: * <p>Serialize the object from the input stream provided.</p>
281: *
282: * @param ois the input stream to serialize the object from
283: * @throws IOException thrown by
284: * <code>ObjectInputStream.defaultReadObject()</code>.
285: * @throws ClassNotFoundException thrown by
286: * <code>ObjectInputStream.defaultReadObject()</code>.
287: */
288: private void readObject(final ObjectInputStream ois)
289: throws ClassNotFoundException, IOException {
290: if (logger.isDebugEnabled()) {
291: logger.debug("readObject(ObjectInputStream ois = " + ois
292: + ") - start");
293: }
294:
295: ois.defaultReadObject();
296:
297: if (logger.isDebugEnabled()) {
298: logger.debug("readObject(ObjectInputStream) - end");
299: }
300: }
301:
302: /**
303: * <p>
304: * Unique identifier of this data object.
305: * </p>
306: *
307: * @param idParam current value of the unique identifier of this data
308: * object.
309: */
310: public final void setId(final Integer idParam) {
311: if (logger.isDebugEnabled()) {
312: logger.debug("setId(Integer id = " + idParam + ") - start");
313: }
314:
315: checkSetter();
316: this .id = idParam;
317:
318: if (logger.isDebugEnabled()) {
319: logger.debug("setId(Integer) - end");
320: }
321: }
322:
323: /**
324: * Set the value as a string. The string must represent a number or a
325: * <code>RuntimeException</code> will be thrown.
326: *
327: * @param idString string representing the id of this object.
328: */
329: public final void setIdString(final String idString) {
330: if (logger.isDebugEnabled()) {
331: logger.debug("setIdString(String idString = " + idString
332: + ") - start");
333: }
334:
335: checkSetter();
336: id = StringHandling.integerValue(idString);
337:
338: if (logger.isDebugEnabled()) {
339: logger.debug("setIdString(String) - end");
340: }
341: }
342:
343: /**
344: * <p>Stores whether users can simply view this value object, or may amend
345: * its contents too.</p>
346: *
347: * <copyDoc>Refer to {@link #isReadOnly}.</copyDoc>
348: * @param readOnlyParam <copyDoc>Refer to {@link #isReadOnly}.</copyDoc>
349: */
350: public void setReadOnly(final boolean readOnlyParam) {
351: if (logger.isDebugEnabled()) {
352: logger.debug("setReadOnly(boolean readOnlyParam = "
353: + readOnlyParam + ") - start");
354: }
355:
356: checkSetter();
357: readOnly = readOnlyParam;
358:
359: if (logger.isDebugEnabled()) {
360: logger.debug("setReadOnly(boolean) - end");
361: }
362: }
363:
364: /**
365: * <p>
366: * Provide helpful debugging info about this data object.
367: * </p>
368: *
369: * @return clear text describing this object.
370: */
371: public String toString() {
372: if (logger.isDebugEnabled()) {
373: logger.debug("toString() - start");
374: }
375:
376: String className = getClass().getName();
377: // don't output package - just the class name
378: if (className.lastIndexOf('.') >= 0) {
379: className = className
380: .substring(className.lastIndexOf('.') + 1);
381: }
382: String returnString = className + "(id " + getId() + ")";
383: if (logger.isDebugEnabled()) {
384: logger.debug("toString() - end - return value = "
385: + returnString);
386: }
387: return returnString;
388: }
389:
390: /**
391: * <p>Serialize the object to the output stream provided.</p>
392: *
393: * @param oos the output stream to serialize the object to
394: * @throws IOException thrown by
395: * <code>ObjectOutputStream.defaultWriteObject( )</code>
396: */
397: private void writeObject(final ObjectOutputStream oos)
398: throws IOException {
399: if (logger.isDebugEnabled()) {
400: logger.debug("writeObject(ObjectOutputStream oos = " + oos
401: + ") - start");
402: }
403:
404: oos.defaultWriteObject();
405:
406: if (logger.isDebugEnabled()) {
407: logger.debug("writeObject(ObjectOutputStream) - end");
408: }
409: }
410: }
|