KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jcorporate > expresso > core > dataobjects > DefaultDataField


1 /* ====================================================================
2  * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
3  *
4  * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * 3. The end-user documentation included with the redistribution,
19  * if any, must include the following acknowledgment:
20  * "This product includes software developed by Jcorporate Ltd.
21  * (http://www.jcorporate.com/)."
22  * Alternately, this acknowledgment may appear in the software itself,
23  * if and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. "Jcorporate" and product names such as "Expresso" must
26  * not be used to endorse or promote products derived from this
27  * software without prior written permission. For written permission,
28  * please contact info@jcorporate.com.
29  *
30  * 5. Products derived from this software may not be called "Expresso",
31  * or other Jcorporate product names; nor may "Expresso" or other
32  * Jcorporate product names appear in their name, without prior
33  * written permission of Jcorporate Ltd.
34  *
35  * 6. No product derived from this software may compete in the same
36  * market space, i.e. framework, without prior written permission
37  * of Jcorporate Ltd. For written permission, please contact
38  * partners@jcorporate.com.
39  *
40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
41  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43  * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
44  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
46  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
47  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
48  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * ====================================================================
53  *
54  * This software consists of voluntary contributions made by many
55  * individuals on behalf of the Jcorporate Ltd. Contributions back
56  * to the project(s) are encouraged when you make modifications.
57  * Please send them to support@jcorporate.com. For more information
58  * on Jcorporate Ltd. and its products, please see
59  * <http://www.jcorporate.com/>.
60  *
61  * Portions of this software are based upon other open source
62  * products and are subject to their respective licenses.
63  */

64 package com.jcorporate.expresso.core.dataobjects;
65
66 import com.jcorporate.expresso.core.db.DBException;
67 import com.jcorporate.expresso.core.misc.Base64;
68 import com.jcorporate.expresso.core.misc.ConfigJdbc;
69 import com.jcorporate.expresso.core.misc.ConfigManager;
70 import com.jcorporate.expresso.core.misc.ConfigurationException;
71 import com.jcorporate.expresso.core.misc.DateTime;
72 import com.jcorporate.expresso.core.misc.StringUtil;
73 import com.jcorporate.expresso.core.security.CryptoManager;
74 import com.jcorporate.expresso.kernel.exception.ChainedException;
75 import com.jcorporate.expresso.kernel.util.FastStringBuffer;
76 import org.apache.commons.collections.LRUMap;
77 import org.apache.log4j.Logger;
78 import org.apache.oro.text.regex.Pattern;
79 import org.apache.oro.text.regex.PatternMatcher;
80 import org.apache.oro.text.regex.Perl5Matcher;
81
82 import java.io.ByteArrayInputStream JavaDoc;
83 import java.io.ByteArrayOutputStream JavaDoc;
84 import java.io.IOException JavaDoc;
85 import java.io.InputStream JavaDoc;
86 import java.io.ObjectOutputStream JavaDoc;
87 import java.io.Serializable JavaDoc;
88 import java.math.BigDecimal JavaDoc;
89 import java.text.ParseException JavaDoc;
90 import java.text.SimpleDateFormat JavaDoc;
91 import java.util.Collections JavaDoc;
92 import java.util.Date JavaDoc;
93 import java.util.HashMap JavaDoc;
94 import java.util.Map JavaDoc;
95
96
97 /**
98  * Default implementation of the DataField interface. This class provides some
99  * basic conversion capabilities between different Java types as well as provides
100  * all use change logging capabilities.
101  *
102  * @author Michael Rimov
103  * @since Expresso 5.0
104  */

105 public class DefaultDataField implements DataField, Serializable JavaDoc {
106     private static final BigDecimal JavaDoc zeroDecimal = new BigDecimal JavaDoc("0.00");
107     private static final Integer JavaDoc zeroInteger = new Integer JavaDoc(0);
108     private static final Double JavaDoc zeroDouble = new Double JavaDoc(0.00);
109
110     /**
111      * It takes quite a bit of horsepower to create a SimpleDateFormat object.
112      * By caching the most recent 30 patterns, we can save a lot of CPU time.
113      */

114     static private Map dateConvertFormatMap = new LRUMap(30);
115
116     /**
117      * Log4j Logger
118      */

119     private static transient Logger log = Logger.getLogger(DefaultDataField.class);
120
121     /**
122      * Attribute String for if there's an error with the field.
123      */

124     public static final String JavaDoc ATTRIBUTE_ERROR = "error";
125
126     /**
127      * Attribute String for what message to display if there's an error with
128      * thie field.
129      */

130     public static final String JavaDoc ATTRIBUTE_ERROR_MESSAGE = "error-message";
131
132     /**
133      * A Pattern Matcher for examining fields vs validation regular expressions
134      * It has been modified for thead local instantiation to reduce
135      * synchronization.
136      */

137     private static transient ThreadLocal JavaDoc patternMatcher = new ThreadLocal JavaDoc() {
138         protected synchronized Object JavaDoc initialValue() {
139             return new Perl5Matcher();
140         }
141     };
142
143     /**
144      * A link to my metadata.
145      */

146     protected transient DataFieldMetaData myMetaData;
147
148     /**
149      * A link to the DataObject that contains me.
150      */

151     protected transient DataObject owner;
152
153     /**
154      * A generic map of attribute keys to attribute values
155      */

156     protected Map attributes = null;
157
158     /**
159      * The Current Value
160      */

161     protected Object JavaDoc currentValue = null;
162
163     /**
164      * The original value, used in comparison tests for 'isChanged' calculation; set by first retrieve(); reset after add() or update()
165      */

166     protected Object JavaDoc originalValue = null;
167
168     /**
169      * Flag to signify if the field is changed
170      */

171     protected boolean isChanged = false;
172
173     /**
174      * Flag to signify if the field value has been set - the retrieved value may be null
175      */

176     protected boolean isValueSet = false;
177
178     /**
179      * Creates a new DefaultDataField object.
180      *
181      * @param metaData
182      * @param parentObject
183      */

184     protected DefaultDataField(DataFieldMetaData metaData,
185                                DataObject parentObject) {
186         myMetaData = metaData;
187         owner = parentObject;
188     }
189
190     /**
191      * create new object for this field
192      *
193      * @param metaData
194      * @param parentObject
195      * @return new instance of this field
196      */

197     public static DefaultDataField getInstance(DataFieldMetaData metaData,
198                                                DataObject parentObject) {
199         return new DefaultDataField(metaData, parentObject);
200     }
201
202     /**
203      * set all internal data members to null;
204      */

205     public void release() {
206         currentValue = null;
207         originalValue = null;
208         attributes = null;
209         myMetaData = null;
210         owner = null;
211         isChanged = false;
212     }
213
214     /**
215      * Used for setting raw data from a JDBC connection. Allows for special
216      * processing such as decryption.
217      *
218      * @param o the object to set.
219      */

220     public void setSerializedForm(Object JavaDoc o) {
221         currentValue = o;
222         originalValue = null;
223     }
224
225     /**
226      * Returns the form in a way suitable for storage in a database or
227      * other data source.
228      *
229      * @return java.lang.Object
230      * @throws DataException upon error
231      */

232     public Object JavaDoc getSerializedForm() throws DataException {
233         try {
234             if (currentValue == null) {
235                 return null;
236             }
237
238             if (myMetaData.isEncrypted()) {
239                 if (!(currentValue instanceof String JavaDoc)) {
240                     throw new IllegalArgumentException JavaDoc("Field "
241                             + myMetaData.getName()
242                             + " must be a string value to be encrypted");
243                 }
244 // return Base64.encodeNoPadding(cryptoManager.getStringEncryption()
245
// .encryptString((String)currentValue));
246
return currentValue;
247             } else {
248
249                 String JavaDoc result = currentValue.toString();
250
251                 if (myMetaData.isBooleanType()) {
252                     // do we have to convert from true/false to 'Y'/'N' ??
253
try {
254                         boolean nativeBoolean = ConfigManager.getContext(owner.getDataContext())
255                                 .getJdbc().isNativeBool();
256                         if (!nativeBoolean) {
257                             // fix up a true/false into what we expect to serialize
258
if ("true".equalsIgnoreCase(result)) {
259                                 result = "Y";
260                             }
261                             if ("false".equalsIgnoreCase(result)) {
262                                 result = "N";
263                             }
264                         }
265                     } catch (ConfigurationException ce) {
266                         throw new DataException(ce);
267                     }
268                 }
269                 return result;
270             }
271         } catch (ChainedException e) {
272             throw new DataException(e);
273         }
274     }
275
276     /**
277      * retrieve value object for this field
278      *
279      * @return Object which contains value
280      */

281     public Object JavaDoc getValue() {
282         if ((currentValue != null) && currentValue instanceof String JavaDoc &&
283                 myMetaData.isEncrypted()) {
284             try {
285                 return CryptoManager.getInstance().getStringEncryption()
286                         .decryptString((Base64.decodeNoPadding((String JavaDoc) currentValue)));
287             } catch (ChainedException ce) {
288                 return currentValue;
289             }
290         }
291
292         return currentValue;
293     }
294
295     /**
296      * Retrieves the wrapped object as a String
297      *
298      * @return a String value representing the object as a string
299      */

300     public String JavaDoc asString() {
301         Object JavaDoc o = getValue();
302         if (o == null) {
303             return null;
304         }
305
306         if (o instanceof String JavaDoc) {
307             return (String JavaDoc) o;
308         }
309
310         if (o instanceof Boolean JavaDoc) {
311             return getBooleanFieldValue((Boolean JavaDoc) o);
312         }
313
314         if (o instanceof Date JavaDoc) {
315             try {
316                 return DateTime.getDateTimeForDB((Date JavaDoc) o, this.getOwner().getDataContext());
317             } catch (DBException ex) {
318             }
319         }
320
321         return o.toString();
322     }
323
324
325     /**
326      * Retrieve the field as a InputStream. If the object's native type is
327      * an input stream, it returns that. If it is a serializable object,
328      * it returns a ByteArrayInputStream that was created using a
329      * ByteArrayOutputStream as well as a ObjectOutputStream.
330      *
331      * @return java.io.InputSTream or null if there was an IO Exception getting
332      * the value, the value was null, of if the native object is not serializable
333      */

334     public InputStream JavaDoc asStream() {
335         Object JavaDoc o = getValue();
336         if (o == null) {
337             return null;
338         }
339
340         if (o instanceof InputStream JavaDoc) {
341             return (InputStream JavaDoc) o;
342         }
343
344         if (!(o instanceof Serializable JavaDoc)) {
345             log.error("Object: " + o.getClass().getName()
346                     + " is not serializable. Cannot retrieve as stream");
347             return null;
348         }
349
350         try {
351             ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
352             ObjectOutputStream JavaDoc oos = new ObjectOutputStream JavaDoc(bos);
353             oos.writeObject(o);
354             oos.flush();
355             oos.close();
356             bos.flush();
357             ByteArrayInputStream JavaDoc bis = new ByteArrayInputStream JavaDoc(bos.toByteArray());
358             bos.close();
359             return bis;
360         } catch (IOException JavaDoc ex) {
361             log.error("Error writing object ot memory stream", ex);
362             return null;
363         }
364     }
365
366
367     /**
368      * Retrieves the wrapped object as an <code>Integer</code> or zero if it's an invalid format.
369      *
370      * @return a java.lang.Integer object, or null if the object is null.
371      */

372     public Integer JavaDoc asInteger() {
373         Object JavaDoc o = getValue();
374         if (o == null) {
375             return null;
376         }
377         if (o instanceof Integer JavaDoc) {
378             return (Integer JavaDoc) o;
379         }
380
381         if (o instanceof String JavaDoc) {
382             try {
383                 return new Integer JavaDoc((String JavaDoc) o);
384             } catch (Exception JavaDoc ex) {
385                 return zeroInteger;
386             }
387         }
388
389         return zeroInteger;
390     }
391
392     /**
393      * Retrieve the wrapped object as a <code>Date</code> object or possibly null if we
394      * can't convert it or the object is null.
395      *
396      * @return a properly instantiated <code>Date</code> Object if we're able to convert it.
397      */

398     public Date JavaDoc asDate() {
399         Object JavaDoc o = getValue();
400         if (o == null) {
401             return null;
402         }
403
404         if (o instanceof Date JavaDoc) {
405             return (Date JavaDoc) o;
406         }
407
408         if (o instanceof String JavaDoc) {
409             java.util.Date JavaDoc returnDate = null;
410             String JavaDoc convertFormat = null;
411             ConfigJdbc myConfig = null;
412             String JavaDoc strVal = (String JavaDoc) o;
413
414             try {
415                 myConfig = ConfigManager.getJdbcRequired(this.getOwner().getDataContext());
416             } catch (ConfigurationException ce) {
417                 log.error("Error getting data context: " + getOwner().getDataContext());
418                 return null;
419             }
420
421             if (this.getFieldMetaData().isDateOnlyType()) {
422                 if (!StringUtil.notNull(myConfig.getDateSelectFormat()).equals("")) {
423                     convertFormat = myConfig.getDateSelectFormat();
424                 } else {
425                     convertFormat = "yyyy-MM-dd";
426                 }
427             } else if (this.getFieldMetaData().isDateTimeType()) {
428                 if (!StringUtil.notNull(myConfig.getDateTimeSelectFormat()).equals("")) {
429                     convertFormat = myConfig.getDateTimeSelectFormat();
430                 } else {
431                     convertFormat = "yyyy-MM-dd HH:mm:ss";
432                 }
433             } else if (this.getFieldMetaData().isTimeType()) {
434                 if (!StringUtil.notNull(myConfig.getTimeSelectFormat()).equals("")) {
435                     convertFormat = myConfig.getTimeSelectFormat();
436                 } else {
437                     convertFormat = "HH:mm:ss";
438                 }
439             } else {
440                 log.warn("Unable to find convert type for class " + o.getClass().getName());
441                 return null;
442             }
443
444             try {
445                 //We have to lock the whole map because we don't want somebody
446
//else to call parse while we're working on the value.
447
synchronized (dateConvertFormatMap) {
448                     SimpleDateFormat JavaDoc formatter = getSimpleDateFormat(convertFormat);
449                     returnDate = formatter.parse(strVal);
450                 }
451             } catch (ParseException JavaDoc pe) {
452                 log.warn("Error parsing string to date", pe);
453                 return null;
454             }
455             if (returnDate != null) {
456                 return returnDate;
457             }
458
459
460         }
461
462         log.warn("Unable to find conversion for object " + o.getClass().getName() + " to Date");
463         return null;
464     }
465
466     /**
467      * Get a SimpleDateFormat object that is cached. Make sure you have
468      * dateConvertFormatMap already locked before calling this function or you'll
469      * have a race condition.
470      *
471      * @param pattern the format pattern to look up
472      * @return an instantiated SimpleDateFormat object. SimpleDateFormat is NOT
473      * threadsafe, so make sure you do your parsing while still in the synchronized
474      * block. Perhaps in the future a keyed Object pool will be better.
475      */

476     protected SimpleDateFormat JavaDoc getSimpleDateFormat(String JavaDoc pattern) {
477         SimpleDateFormat JavaDoc aFormat = null;
478         aFormat = (SimpleDateFormat JavaDoc) dateConvertFormatMap.get(pattern);
479
480         if (aFormat == null) {
481             aFormat = new SimpleDateFormat JavaDoc(pattern);
482             dateConvertFormatMap.put(pattern, aFormat);
483         }
484
485         return aFormat;
486     }
487
488
489     /**
490      * Retrieve the wrapped object as a <code>BigDecimal</code> object or zero if we're unable
491      * to convert it.
492      *
493      * @return a properly instantiated <code>BigDecimal</code> Object if we're able to convert it.
494      */

495     public BigDecimal JavaDoc asBigDecimal() {
496         Object JavaDoc o = getValue();
497         if (o == null) {
498             return null;
499         }
500
501         if (o instanceof BigDecimal JavaDoc) {
502             return (BigDecimal JavaDoc) o;
503         }
504
505         if (o instanceof String JavaDoc) {
506             try {
507
508                 BigDecimal JavaDoc returnValue = new BigDecimal JavaDoc((String JavaDoc) o);
509
510                 return returnValue.setScale(this.getFieldMetaData().getPrecision());
511             } catch (NumberFormatException JavaDoc ex) {
512                 return zeroDecimal.setScale(this.getFieldMetaData().getPrecision());
513             }
514         }
515
516         return zeroDecimal;
517     }
518
519     /**
520      * Retrieve the wrapped object as a <code>Double</code> object or zero if we
521      * can't convert i
522      *
523      * @return a properly instantiated <code>Double</code> Object if we're able to convert it.
524      */

525     public Double JavaDoc asDouble() {
526         Object JavaDoc o = getValue();
527         if (o == null) {
528             return null;
529         }
530
531         if (o instanceof Double JavaDoc) {
532             return (Double JavaDoc) o;
533         }
534
535         try {
536             return new Double JavaDoc(o.toString());
537         } catch (NumberFormatException JavaDoc ex) {
538             return zeroDouble;
539         }
540
541     }
542
543
544     /**
545      * Retrieve the boolean object value.
546      *
547      * @return Boolean object. Null if the object's value is null
548      */

549     public Boolean JavaDoc asBoolean() {
550         Object JavaDoc o = getValue();
551         if (o == null) {
552             return null;
553         }
554
555         if (o instanceof Boolean JavaDoc) {
556             return (Boolean JavaDoc) o;
557         }
558
559         if (o instanceof String JavaDoc) {
560             String JavaDoc s = (String JavaDoc) o;
561             if ("y".equalsIgnoreCase(s)) {
562                 return Boolean.TRUE;
563             } else if ("true".equalsIgnoreCase(s)) {
564                 return Boolean.TRUE;
565             }
566         }
567
568         return Boolean.FALSE;
569     }
570
571     /**
572      * Retrieve the last original value if the data has changed. Will return
573      * null if isChanged() is false
574      *
575      * @return the original object or null
576      */

577     public Object JavaDoc getOriginalValue() {
578         return originalValue;
579     }
580
581     /**
582      * Used for change logging and updating only changed fields.
583      * change is true IF the field has been set once (after object is born or reset), and
584      * subsequently the value is changed in the field.
585      *
586      * @return true if the field has changed since the last reset (i.e. since object was constructed or reset)
587      */

588     public boolean isChanged() {
589         return isChanged;
590 // return (originalValue != null);
591
}
592
593     /**
594      * Used for change logging.
595      *
596      * @return true if the field has had the value set since the last reset
597      */

598     public boolean isValueSet() {
599         return isValueSet;
600     }
601
602     /**
603      * Make sure the value of the field is valid. Checks mask and for null.
604      *
605      * @throws DataException if the field value is not valid
606      */

607     public void checkValue()
608             throws DataException {
609         DataObjectMetaData ownerMetaData = owner.getMetaData();
610
611         String JavaDoc fieldDescription;
612         try {
613             fieldDescription = ownerMetaData.getDescription(myMetaData.getName());
614         } catch (DBException dbe) {
615             throw new DataException(dbe);
616         }
617
618         //Allow autoinc fields through since they're added last minute.
619
if (myMetaData.isAutoIncremented()) {
620             return;
621         }
622
623         // check for null when not allowed
624
if ((!myMetaData.allowsNull()) && isNull()) {
625             myMetaData.setAttribute(ATTRIBUTE_ERROR, "Y");
626             String JavaDoc msg = (String JavaDoc) myMetaData.getAttribute(ATTRIBUTE_ERROR_MESSAGE);
627             if (msg == null) {
628                 FastStringBuffer fsb = FastStringBuffer.getInstance();
629                 try {
630                     fsb.append("Field '");
631                     // TODO not i18n
632
fsb.append(fieldDescription);
633                     fsb.append("' cannot accept a null value ");
634                     msg = fsb.toString();
635                 } finally {
636                     fsb.release();
637                     fsb = null;
638                 }
639             }
640
641             myMetaData.setAttribute(ATTRIBUTE_ERROR_MESSAGE, msg);
642             throw new DataException(msg);
643         }
644
645         /**
646          * Modification done for avoid empty content check for read only
647          * field in Add state when you use DBMaint or sevlet like DBMaint to fill table
648          * The field is checked before it's filled in add method within it's own DBObject.
649          * @author Yves Henri AMAIZO
650          */

651         /* Check for null and not read only conlumn*/
652         if ((!myMetaData.allowsNull() && !myMetaData.isReadOnly()) && asString().length() == 0) {
653             myMetaData.setAttribute(ATTRIBUTE_ERROR, "Y");
654             String JavaDoc msg = (String JavaDoc) myMetaData.getAttribute(ATTRIBUTE_ERROR_MESSAGE);
655             if (msg == null) {
656                 FastStringBuffer fsb = FastStringBuffer.getInstance();
657                 try {
658                     fsb.append("Field '");
659                     // TODO not i18n
660
fsb.append(fieldDescription);
661                     fsb.append("' cannot be empty ");
662                     msg = fsb.toString();
663                 } finally {
664                     fsb.release();
665                     fsb = null;
666                 }
667             }
668
669             myMetaData.setAttribute(ATTRIBUTE_ERROR_MESSAGE, msg);
670             throw new DataException(msg);
671         }
672
673         // check mask
674
if (!isNull() && asString().length() > 0) {
675             Pattern mask = myMetaData.getMask();
676
677             if (mask != null) {
678                 if (!getPatternMatcher().matches(asString(), mask)) {
679                     myMetaData.setAttribute(ATTRIBUTE_ERROR, "Y");
680                     String JavaDoc msg = (String JavaDoc) myMetaData.getAttribute(ATTRIBUTE_ERROR_MESSAGE);
681                     if (msg == null) {
682                         FastStringBuffer fsb = FastStringBuffer.getInstance();
683                         try {
684                             fsb.append("Value '");
685                             fsb.append(asString());
686                             fsb.append("' supplied for field '");
687                             // TODO not i18n
688
fsb.append(fieldDescription);
689                             fsb.append("' does not match the regular expression specified for this field.");
690                             msg = fsb.toString();
691                         } finally {
692                             fsb.release();
693                             fsb = null;
694                         }
695
696                     }
697                     myMetaData.setAttribute(ATTRIBUTE_ERROR_MESSAGE, msg);
698                     msg = msg + " " + asString();
699                     throw new DataException(msg);
700                 }
701             }
702         }
703     }
704
705     /**
706      * Resets the isChanged and isValueSet flags and sets the original value field to null
707      */

708     public void resetChanged() {
709         originalValue = null;
710         isChanged = false;
711         isValueSet = false;
712     }
713
714     /**
715      * Sets the wrapped object for the data field; also updates values for isValueSet and isChanged flags
716      *
717      * @param newValue a new Object to set the value to
718      */

719     public void setValue(Object JavaDoc newValue) {
720         if (originalValue == null) {
721             // we preserve the very first, original value, for use as 'baseline' in computing 'isChanged'
722
originalValue = currentValue;
723         }
724
725         // consider the case for the first time
726
// that a field is populated by retrieval from the DB.
727
// Retrieval will call setValue here, and this setValue is NOT *changing*
728
// an *existing* value. we keep a boolean isValueSet to determine if
729
// this is the first setting (the retrieval) of this fielddata
730
if (isValueSet) {
731             // are we changing the value?
732
if (newValue == null) {
733                 // no change if both are null
734
isChanged = (currentValue != null);
735             } else {
736                 // ok, we just use a comparison now that we know one of them is non-null
737
isChanged = !newValue.equals(originalValue);
738             }
739         }
740
741         currentValue = newValue;
742         isValueSet = true;
743
744         if (getOwner().getStatus().equals(DataObject.STATUS_CURRENT)) {
745             this.getOwner().setStatus(DataObject.STATUS_UPDATED);
746         }
747     }
748
749     /**
750      * Returns true if the object is null.
751      *
752      * @return true if the object is null
753      */

754     public boolean isNull() {
755         return (currentValue == null);
756     }
757
758     /**
759      * Sets an attribute for this particular instance of the Data field
760      *
761      * @param attributeName the name of the attribute to set
762      * @param value the value to set it to
763      */

764     public void setAttribute(String JavaDoc attributeName, Object JavaDoc value) {
765         if (attributes == null) {
766             attributes = new HashMap JavaDoc();
767         }
768         attributes.put(attributeName, value);
769     }
770
771     /**
772      * Removes an attribute
773      *
774      * @param attribute The attribute key to remove
775      */

776     public void removeAttribute(String JavaDoc attribute) {
777         if (attributes == null) {
778             return;
779         }
780
781         attributes.remove(attribute);
782     }
783
784     /**
785      * Retrieves any user defined attributes for this field.
786      *
787      * @param attributeName the name of the attribute to retrieve
788      * @return an object or null if the attribute doesn't exist
789      */

790     public Object JavaDoc getAttribute(String JavaDoc attributeName) {
791         if (attributes == null) {
792             return null;
793         }
794
795         return attributes.get(attributeName);
796     }
797
798     /**
799      * Returns a Read Only <code>Map</code> of all attributes in name-value pairs. If there are no
800      * attributes then getAllAttributes will return a null map.
801      *
802      * @return java.util.map
803      */

804     public Map getAllAttributes() {
805         if (attributes == null) {
806             return new HashMap JavaDoc();
807         } else {
808             return Collections.unmodifiableMap(attributes);
809         }
810     }
811
812     /**
813      * Returns a handle to the DataObject that is the container for this
814      * Data Field
815      *
816      * @return DataObject the containing data object.
817      */

818     public DataObject getOwner() {
819         return this.owner;
820     }
821
822     /**
823      * Sets the owner of a given DataObject
824      *
825      * @param newOwner The new parent object.
826      */

827     public void setOwner(DataObject newOwner) {
828         this.owner = newOwner;
829     }
830
831
832     /**
833      * Returns a handle to the Field MetaData object.
834      *
835      * @return DataFieldMetaData
836      */

837     public DataFieldMetaData getFieldMetaData() {
838         return this.myMetaData;
839     }
840
841     /**
842      * Sets the metadata object for this field.
843      *
844      * @param newMetadata the new Field Meta data object... for example <code>DBField</code>
845      */

846     public void setFieldMetaData(DataFieldMetaData newMetadata) {
847         this.myMetaData = newMetadata;
848     }
849
850     /**
851      * Internal refactoring for getting what a boolean field should be set to.
852      *
853      * @param theFieldValue The target value
854      * @return the string value
855      * @throws IllegalArgumentException If we can't get the data context
856      */

857     protected String JavaDoc getBooleanFieldValue(Boolean JavaDoc theFieldValue) {
858         try {
859             boolean fieldValue = theFieldValue.booleanValue();
860             boolean nativeBoolean = ConfigManager.getContext(this.getOwner()
861                     .getDataContext())
862                     .getJdbc().isNativeBool();
863
864             if (fieldValue == true) {
865                 if (nativeBoolean) {
866                     return "true";
867                 } else {
868                     return "Y";
869                 }
870             } else {
871                 if (nativeBoolean) {
872                     return "false";
873                 } else {
874                     return "N";
875                 }
876             }
877         } catch (ConfigurationException ce) {
878             log.error("Error getting data context.", ce);
879             throw new IllegalArgumentException JavaDoc("Error getting datacontext " +
880                     this.getOwner().getDataContext());
881         }
882     }
883
884     /**
885      * Retrieve a thread local instance of the Perl5 pattern matcher. Allows
886      * for optimization of # of instances of pattern matcher vs
887      * synchronization.
888      *
889      * @return PatternMatcher
890      */

891     protected PatternMatcher getPatternMatcher() {
892         return (PatternMatcher) patternMatcher.get();
893     }
894
895     /**
896      * reset 'original' value and isChanged flags;
897      * call when add(), retrieve() or update() has occurred, and currentValue of data fields should be considered 'original value' for purposes of determining 'isChanged'
898      */

899     public void cacheIsChangedComparison() {
900         originalValue = currentValue;
901         isChanged = false;
902     }
903
904 }
905
906
Popular Tags