001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064:
065: package com.jcorporate.expresso.core.dataobjects;
066:
067: import com.jcorporate.expresso.core.db.DBException;
068: import org.apache.oro.text.regex.Pattern;
069:
070: import java.util.ArrayList;
071: import java.util.Iterator;
072: import java.util.Map;
073:
074: /**
075: * This class provides a threadsafe access to a dataobject. To be able to more
076: * safely share your dataobjects acrossed multiple threads, simple call.
077: * <p>Typical Usage:<code><pre>
078: * DataObject myobj = SynchronizedDataObject.newInstance(new MimeTypes(SecuredDBObject.SYSTEM_ACCOUNT));
079: * <p/>
080: * //We now have a wrapped MimeTypes data object
081: * myobj.setField("MimeNumber",new Integer(1));
082: * <p/>
083: * //Retrieves a set of cloned records.
084: * ArrayList records = myobj.searchAndRetrieveList();
085: * </pre></code></p>
086: *
087: * @author Michael Rimov
088: */
089:
090: public class SynchronizedDataObject implements DataObject {
091: DataObject target;
092:
093: SynchronizedDataObject(DataObject _target) {
094: target = _target;
095: }
096:
097: /**
098: * Call this to wrap your data object in a threadsafe wrapper.
099: *
100: * @param wrappedObject the object to wrap.
101: * @return a DataObject who's implementation is threadsafe.
102: */
103: public static synchronized DataObject newInstance(
104: DataObject wrappedObject) {
105: return new SynchronizedDataObject(wrappedObject);
106: }
107:
108: /**
109: * Returns the object embedded within the field keyed by the fieldName
110: * parameter
111: *
112: * @param fieldName The name of the field to get
113: * @return The object if it isn't null for the data value or null.
114: * @throws DBException upon error
115: */
116: public synchronized DataField getDataField(String fieldName)
117: throws DBException {
118: return target.getDataField(fieldName);
119: }
120:
121: /**
122: * Returna a list of all field names available to this class in order.
123: *
124: * @return java.util.Iterator
125: */
126: public synchronized Iterator getFieldListIterator() {
127: return (new ArrayList(target.getMetaData().getFieldListArray()))
128: .iterator();
129: }
130:
131: /**
132: * Retrieve iterator of all keys
133: *
134: * @return java.util.Itaerator Each iteration will return the name of
135: * the next key in the list.
136: * @throws DBException upon error
137: * @todo Change DBException to DataException as soon as possible
138: */
139: public synchronized Iterator getKeyFieldListIterator()
140: throws DBException {
141: return (new ArrayList(target.getMetaData()
142: .getKeyFieldListArray())).iterator();
143: }
144:
145: /**
146: * Retrieve the database object's metadata. Metadata is a description of the
147: * database object, so it contains static information such as as description,
148: * field names, field types. Etc.
149: * <p>For implementers of this interface: It is best to store the metadata
150: * somewhere rather than recreating it each and every time. For low-memory
151: * requirements, a WeakHashMap is recommended</p>
152: *
153: * @return a built DataObjectMetaData for this database object
154: */
155: public synchronized DataObjectMetaData getMetaData() {
156: return target.getMetaData();
157: }
158:
159: /**
160: * Retrieves the metadata for a particular field name
161: *
162: * @param fieldName The name of the field to retrieve the metadata for.
163: * @return <\u0441ode>DataFieldMetaData</code> the metadata associated with this
164: * field.
165: * @throws IllegalArgumentException if the fieldName does not exist.
166: */
167: public synchronized DataFieldMetaData getFieldMetaData(
168: String fieldName) {
169: return target.getFieldMetaData(fieldName);
170: }
171:
172: /**
173: * Directly sets the field value without getting the datafield object
174: *
175: * @param fieldName the name of the field to set
176: * @param o the object value to set it to.
177: */
178: public synchronized void set(String fieldName, Object o)
179: throws DataException {
180: target.set(fieldName, o);
181: }
182:
183: /**
184: * Checks to see if two data objects are equal. This is extremely important
185: * in conflict resolution.
186: *
187: * @param otherObject the other object to compare to.
188: * @return true if the two objects are considered equal
189: */
190: public synchronized boolean equals(Object otherObject) {
191: return target.equals(otherObject);
192: }
193:
194: /**
195: * Adds the record to the defined data source.
196: */
197: public synchronized void add() throws DBException {
198: target.add();
199: }
200:
201: /**
202: * Updates the record to the defined datasource
203: */
204: public synchronized void update() throws DBException {
205: target.update();
206: }
207:
208: /**
209: * Deletes this defined record.
210: */
211: public synchronized void delete() throws DBException {
212: target.delete();
213: }
214:
215: /**
216: * Clears all currently loaded fields
217: */
218: public synchronized void clear() throws DBException {
219: target.clear();
220: }
221:
222: /**
223: * Sets the data context that this object is residing in. This is identical
224: * to the pre-Expresso 5.0 <code>setDBName()</code>
225: *
226: * @param newContext the new name of the data context.
227: * @throws IllegalArgumentException if the DataContext does not exist
228: */
229: public synchronized void setDataContext(String newContext) {
230: target.setDataContext(newContext);
231: }
232:
233: /**
234: * Returns the name of the currently set DataContext
235: *
236: * @return java.lang.String
237: */
238: public synchronized String getDataContext() {
239: return target.getDataContext();
240: }
241:
242: /**
243: * {@inheritDoc}
244: *
245: * @throws DataException upon setField error.
246: */
247: public synchronized void setFieldsWithDefaults()
248: throws DataException {
249: target.setFieldsWithDefaults();
250: }
251:
252: /**
253: * Returns the name of the physical database that we're talking with. This
254: * is opposed to getDataContext() which returns the security context as well.
255: * getMappedDataContext() is strictly used to get at the low level database
256: * connection.
257: *
258: * @return java.lang.String... the context we've mapped to.
259: */
260: public synchronized String getMappedDataContext() {
261: return target.getMappedDataContext();
262: }
263:
264: /**
265: * Set an attribute. Attributes are temporary (e.g. not stored in the DBMS) values
266: * associated with this particular DB object instance.
267: *
268: * @param attributeName The name of the attribute being defined
269: * @param attributeValue The object to store under this attribute name
270: */
271: public synchronized void setAttribute(String attributeName,
272: Object attributeValue) {
273: target.setAttribute(attributeName, attributeValue);
274: }
275:
276: /**
277: * Return an "attribute". Attributes are temporary (e.g. not stored in the DBMS)
278: * values associated with this particular DB object instance.
279: *
280: * @param attributeName The attribute name to check
281: * @return the object associated with this attribute
282: */
283: public synchronized Object getAttribute(String attributeName) {
284: return target.getAttribute(attributeName);
285: }
286:
287: /**
288: * Returns a <b>Read Only</b> Map containing all the current attributes set
289: * for this particular data object instance.
290: *
291: * @return Read Only <code>java.util.Map</code>
292: */
293: public synchronized Map getAllAttributes() {
294: return java.util.Collections.unmodifiableMap(target
295: .getAllAttributes());
296: }
297:
298: /**
299: * Use this function to acquire the Executor interface that is associated
300: * with this data object
301: *
302: * @return DataExecutorInterface or null if no Executor has been associated
303: * with this object
304: */
305: public synchronized DataExecutorInterface getExecutor() {
306: return target.getExecutor();
307: }
308:
309: /**
310: * Use this function to acquire the DataQueryInterface that is associated
311: * with this data object
312: *
313: * @return DataQueryInterface or null if no QueryInterface has been
314: * associated with this object
315: */
316: public synchronized DataQueryInterface getQueryInterface() {
317: return target.getQueryInterface();
318: }
319:
320: /**
321: * Check that a given value is valid for a given field.
322: * This method is overriden by specific DBObjects to do their own field-level
323: * validations - they should also call super in order to do the
324: * standard stuff. Every field is automatically checked by this method before the
325: * database is updated.
326: *
327: * @param fieldName Name of the field to verify
328: * @param fieldValue Value of the field to be evaluated
329: * @throws DBException If the value is not valid
330: */
331: public synchronized void checkField(String fieldName,
332: String fieldValue) throws DBException {
333: target.checkField(fieldName, fieldValue);
334: }
335:
336: /**
337: * Retrieve the status code of the dataobject.
338: *
339: * @return java.lang.String
340: */
341: public synchronized String getStatus() {
342: return target.getStatus();
343: }
344:
345: /**
346: * Retrieve a list of valid value object for this particular dbobject
347: *
348: * @param fieldName name of the field to retrieve the list for.
349: * @return java.util.List of valid values
350: * @throws DBException upon error
351: */
352: public synchronized java.util.List getValidValuesList(
353: String fieldName) throws DBException {
354: return java.util.Collections.unmodifiableList(target
355: .getValidValuesList(fieldName));
356: }
357:
358: /**
359: * Sets the DataObject's locale
360: *
361: * @param newLocale the New locale object
362: */
363: public synchronized void setLocale(java.util.Locale newLocale) {
364: target.setLocale(newLocale);
365: }
366:
367: /**
368: * Retrieve the DBObject's current locale
369: *
370: * @return java.util.Locale
371: */
372: public synchronized java.util.Locale getLocale() {
373: return target.getLocale();
374: }
375:
376: /**
377: * Specify a maximum number of records to be retrieved in any subsequent
378: * searchAndRetrieve() call. Records will be retrieved (in the specified
379: * sort order) until the specified maximum is reached, then the remainder
380: * of the result set is discarded. Specifying zero indicates that all
381: * records are to be retrieved.
382: *
383: * @param newMax The maximum number of records to retrieve.
384: * @throws DBException If the max number is less than 0
385: */
386: public synchronized void setMaxRecords(int newMax)
387: throws DBException {
388: target.setMaxRecords(newMax);
389: }
390:
391: /**
392: * A DB Object can be told to only retrieve a certain number of records. If a
393: * "max records" value has been specified, this method provides access to it.
394: *
395: * @return The maximum number of records that should be retrieved, or zero
396: * if no max has been set
397: */
398: public synchronized int getMaxRecords() {
399: return target.getMaxRecords();
400: }
401:
402: /**
403: * Specifies the number of records that should be skipped over
404: * before any data from the <code>ResultSet</code>
405: * is retrieved in any subsequent
406: * searchAndRetrieve() call. Records will be skipped over (in the specified
407: * sort order) until the record counts is equal to or greater
408: * than the offset record. Specifying zero indicates that no
409: * records should be skipped over and the
410: * <code>ResultSet</code> immediately from the start.
411: *
412: * @param newOffset The maximum number of records to retrieve.
413: * @throws DBException If the max number is less than 0
414: * <p/>
415: * author Peter Pilgrim <peterp at xenonsoft dot demon dot co dot uk>
416: */
417: public synchronized void setOffsetRecord(int newOffset)
418: throws DBException {
419: target.setOffsetRecord(newOffset);
420: }
421:
422: /**
423: * Gets the number of records that be skipped. The offset records.
424: * A DB Object can be told to skip a certain number of
425: * records, before reading records from the <code>ResultSet</code>.
426: * <p/>
427: * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
428: *
429: * @return The maximum number of records that should be
430: * skipped over before reading the data records.
431: * @see #setOffsetRecord(int)
432: */
433: public synchronized int getOffsetRecord() {
434: return target.getOffsetRecord();
435: }
436:
437: /**
438: * Performs a datasource search so that the criteria set in the DataObject
439: * is used.
440: * <p>Note: This particular implementation, to be threadsafe, returns a new
441: * array instance, so it is particularly slow and memory intensive. However, for
442: * the scope of the class, it is at least threadsafe.</p>
443: *
444: * @param sortOrder A pipe delimited string specifying the field(s) to be sorted upon.
445: * May be a single field without any pipes.
446: * @return <code>java.util.List</code> of objects. May be an empty list if no
447: * objects were found.
448: * @throws DBException upon error performing the search
449: */
450: public ArrayList searchAndRetrieveList(String sortOrder)
451: throws DBException {
452: return new ArrayList(target.searchAndRetrieveList(sortOrder));
453: }
454:
455: /**
456: * Performs a datasource search so that the criteria set in the DataObject
457: * is used. There is no specified sort order for this version of the method
458: * <p>Note: This particular implementation, to be threadsafe, returns a new
459: * array instance, so it is particularly slow and memory intensive. However, for
460: * the scope of the class, it is at least threadsafe.</p>
461: *
462: * @return <code>java.util.List</code> of objects. May be an empty list if no
463: * objects were found.
464: * @throws DBException upon error performing the search
465: */
466: public ArrayList searchAndRetrieveList() throws DBException {
467: return new ArrayList(target.searchAndRetrieveList());
468: }
469:
470: /**
471: * Finds a single record based upon the criteria specified by the <code>DataTransferObject</code>
472: *
473: * @return boolean true if a record was found, and the <i>criteria</i> parameter
474: * is filled with the first data object found.
475: * @throws DBException upon error performing the search
476: */
477: public synchronized boolean find() throws DBException {
478: return target.find();
479: }
480:
481: /**
482: * Just like find, but only retrieves the count, not the records themselves.
483: *
484: * @return integer Count of the records matching the criteria
485: * @throws DBException If the search could not be completed
486: */
487: public synchronized int count() throws DBException {
488: return target.count();
489: }
490:
491: /**
492: * Every class that can stay in the system cache must define a way to get
493: * a <b>unique</b> key
494: *
495: * @return The cache key for this item.
496: */
497: public String getKey() {
498: return target.getKey();
499: }
500:
501: /**
502: * Sets the status of the object.
503: *
504: * @param statusValue
505: */
506: public synchronized void setStatus(String statusValue) {
507: target.setStatus(statusValue);
508: }
509:
510: /**
511: * Retrieve the native object type for the given field name.
512: *
513: * @param fieldName the name of the field to retrieve
514: * @return Object or null if the field was null
515: * @throws DataException upon error
516: * @throws IllegalArgumentException if fieldname is invalid
517: */
518: public synchronized Object get(String fieldName)
519: throws DataException {
520: return target.get(fieldName);
521: }
522:
523: /**
524: * Retrieve the field value as a String
525: *
526: * @param fieldName the name of the field to retrieve
527: * @return Object or null if the field was null
528: * @throws DBException upon error
529: * @throws IllegalArgumentException if fieldname is invalid
530: */
531: public synchronized String getField(String fieldName)
532: throws DBException {
533: return target.getField(fieldName);
534: }
535:
536: /**
537: * Set a regular expression "mask" for this base data object that specifies it's
538: * valid values. The mask should already be compiled by the regular
539: * expression compiler
540: *
541: * @param newMask The compiled regular expression mask
542: */
543: public void setGlobalMask(Pattern newMask) {
544: target.setGlobalMask(newMask);
545: }
546:
547: /**
548: * Get the compiled regular expression for this base data object.
549: *
550: * @return the precompiled regular expression mask
551: */
552: public Pattern getGlobalMask() {
553: return target.getGlobalMask();
554: }
555:
556: /**
557: * Return boolean if the data object has a mask set
558: *
559: * @return True if the data object mask is set, else false if it is not
560: */
561: public boolean isGlobalMasked() {
562: return target.isGlobalMasked();
563: } /* isMasked() */
564:
565: /**
566: * Returns a hash code value for the object.
567: *
568: * @return a hash code value for this object.
569: * @todo Implement this java.lang.Object method
570: */
571: public int hashCode() {
572: return target.hashCode();
573: }
574:
575: }
|