KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jdesktop > swing > data > MetaData


1 /*
2  * $Id: MetaData.java,v 1.7 2004/12/07 02:12:14 rbair Exp $
3  *
4  * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
5  * Santa Clara, California 95054, U.S.A. All rights reserved.
6  */

7
8 package org.jdesktop.swing.data;
9
10 import java.beans.PropertyChangeEvent JavaDoc;
11 import java.beans.PropertyChangeListener JavaDoc;
12 import java.beans.PropertyChangeSupport JavaDoc;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Map JavaDoc;
17
18 /**
19  * <p>
20  * Class for representing the meta-data for an field in a data model.
21  * A &quot;field&quot; may map to a column on a RowSet, a property on a JavaBean,
22  * or some other discrete data element on a data model.
23  * The meta-data describes aspects of a data field such as it's name,
24  * type, and edit constraints. This class may be used when such information
25  * isn't encapsulated in the data model object itself and thus must be represented
26  * in an external object. Meta-data is intended only for holding state about
27  * a data model element and is not intended for implementing application semantics.</p>
28  * <p>
29  * A meta-data object should be initialized at a minimum with a name, class,
30  * and label. Additional meta-data properties can be set as necessary.
31  * For example:<br>
32  * <pre><code>
33  * MetaData metaData = new MetaData(&quot;firstname&quot;, String.class,
34  * &quot;First Name&quot;);
35  * metaData.setRequired(true);
36  * </code></pre>
37  * If the associated data model field requires application-specific validation
38  * logic to verify the correctness of a potential value, one or more Validator
39  * instances can be added to the meta-data object. Example:<br>
40  * <pre><code>
41  * MetaData metaData = new MetaData(&quot;creditcard&quot;, String.class,
42  * &quot;Credit Card Number&quot;
43  * metaData.setRequired(true);
44  * metaData.addValidator(new MyCreditCardValidator());
45  * </code></pre>
46  * </p>
47  *
48  * @author Amy Fowler
49  * @author Rich Bair
50  * @version 1.0
51  */

52
53 public class MetaData {
54     protected String JavaDoc name;
55     protected Class JavaDoc klass = String JavaDoc.class;
56     protected String JavaDoc label;
57     protected Converter converter = null;
58     protected Object JavaDoc decodeFormat = null;
59     protected Object JavaDoc encodeFormat = null;
60     protected boolean readOnly = false;
61     protected int minValueCount = 0; // null value okay
62
protected int maxValueCount = 1; // only one value allowed
63
protected int displayWidth = 24;
64     protected ArrayList JavaDoc validators = null;
65
66     protected Map JavaDoc customProps = new HashMap JavaDoc();
67     protected PropertyChangeSupport JavaDoc pcs;
68
69     /**
70      * Instantiates a meta-data object with a default name &quot;value&quot; and
71      * a default field class equal to <code>java.lang.String</code>.
72      * This provides the no-argument constructor required for JavaBeans.
73      * It is recommended that the program explicitly set a meaningful
74      * &quot;name&quot; property.
75      */

76     public MetaData() {
77         this("value");
78     }
79
80     /**
81      * Instantiates a meta-data object with the specified name and
82      * a default field class equal to <code>java.lang.String</code>.
83      * @param name String containing the name of the data field
84      */

85     public MetaData(String JavaDoc name) {
86         this.name = name;
87     }
88
89     /**
90      * Instantiates a meta-data object with the specified name and
91      * field class.
92      * @param name String containing the name of the data field
93      * @param klass Class indicating type of data field
94      */

95     public MetaData(String JavaDoc name, Class JavaDoc klass) {
96         this(name);
97         this.klass = klass;
98     }
99
100     /**
101      * Instantiates a meta-data object with the specified name,
102      * field class, and label.
103      * @param name String containing the name of the data field
104      * @param klass Class indicating type of data field
105      * @param label String containing the user-displayable label for the
106      * data field
107      */

108     public MetaData(String JavaDoc name, Class JavaDoc klass, String JavaDoc label) {
109         this(name, klass);
110         this.label = label;
111     }
112
113     /**
114      * Gets the meta-data &quot;name&quot; property which indicates
115      * the logical name of the associated data field.
116      * @see #setName
117      * @return String containing the name of the data field.
118      */

119     public String JavaDoc getName() {
120         return name;
121     }
122
123     /**
124      * Sets the meta-data &quot;name&quot; property.
125      * @see #getName
126      * @param name String containing the name of the data field
127      */

128     public void setName(String JavaDoc name) {
129         String JavaDoc oldName = this.name;
130         this.name = name;
131         firePropertyChange("name", oldName, name);
132     }
133
134     /**
135      * Gets the meta-data's &quot;elementClass&quot; property which
136      * indicates the type of the associated data field.
137      * The default field class is <code>java.lang.String</code>.
138      * @see #setElementClass
139      * @return Class indicating type of data field
140      */

141     public Class JavaDoc getElementClass() {
142         return klass;
143     }
144
145     /**
146      * Sets the meta-data's &quot;elementClass&quot; property.
147      * This <code>set</code> method is provided for meta-data bean initialization
148      * only; the field class is not intended to be modified after initialization,
149      * since other aspects of a meta-data object may depend on this type setting.
150      * @see #getElementClass
151      * @param klass Class indicating type of data field
152      */

153     public void setElementClass(Class JavaDoc klass) {
154         Class JavaDoc oldClass = this.klass;
155         this.klass = klass;
156         firePropertyChange("elementClass", oldClass, klass);
157     }
158
159     /**
160      * Gets the meta-data's &quot;label&quot; property, which provides
161      * a label for the associated data field. The label is intended
162      * for display to the end-user and may be localized.
163      * If no label has been explicitly set, then the meta-data's name is
164      * returned.
165      * @see #setLabel
166      * @return String containing the user-displayable label for the
167      * data field
168      */

169     public String JavaDoc getLabel() {
170         return label == null? name : label;
171     }
172
173     /**
174      * Sets the meta-data's &quot;label&quot; property.
175      * @todo Rename to setTitle
176      *
177      * @see #getLabel
178      * @param label String containing the user-displable label for the
179      * data field
180      */

181     public void setLabel(String JavaDoc label) {
182         String JavaDoc oldLabel = this.label;
183         this.label = label;
184         firePropertyChange("label", oldLabel, label);
185     }
186
187     /**
188      * Gets the meta-data's converter, which performs conversions between
189      * string values and objects of the associated data field's type.
190      * If no converter was explicitly set on this meta-data object,
191      * this method will retrieve a default converter for this data
192      * field's type from the converter registry. If no default converter
193      * is registered, this method will return <code>null</code>.
194      * @see Converters#get
195      * @see #setConverter
196      * @see #getElementClass
197      * @return Converter used to perform conversions between string values
198      * and objects of this field's type
199      */

200     public Converter getConverter() {
201         if (converter == null) {
202             return Converters.get(klass);
203         }
204         return converter;
205     }
206
207     /**
208      * Sets the meta-data's converter.
209      *
210      * @see #getConverter
211      * @param converter Converter used to perform conversions between string values
212      * and objects of this field's type
213      */

214     public void setConverter(Converter converter) {
215         Converter oldConverter = this.converter;
216         this.converter = converter;
217         firePropertyChange("converter", oldConverter, converter);
218     }
219
220     /**
221      * Gets the meta-data's decode format which is used when converting
222      * values from a string representation. This property must be used when
223      * conversion requires format information on how the string representation
224      * is structured. For example, a decode format should be used when decoding
225      * date values. The default decode format is <code>null</code>.
226      * @see #setDecodeFormat
227      * @return format object used to describe format for string-to-object conversion
228      */

229     public Object JavaDoc getDecodeFormat() {
230         return decodeFormat;
231     }
232
233     /**
234      * Sets the meta-data's decode format which is used when converting
235      * values from a string representation.
236      * @see #getDecodeFormat
237      * @see java.text.DateFormat
238      * @param format object used to describe format for string-to-object conversion
239      */

240     public void setDecodeFormat(Object JavaDoc format) {
241         Object JavaDoc oldDecodeFormat = this.decodeFormat;
242         this.decodeFormat = format;
243         firePropertyChange("decodeFormat", oldDecodeFormat, format);
244     }
245
246     /**
247      * Gets the meta-data's encode format which is used when converting
248      * values to a string representation. This property must be used when
249      * conversion requires format information on how the string representation
250      * should be generated. For example, an encode format should be used when
251      * encoding date values. The default encode format is <code>null</code>.
252      * @see #setEncodeFormat
253      * @return format object used to describe format for object-to-string conversion
254      */

255     public Object JavaDoc getEncodeFormat() {
256         return encodeFormat;
257     }
258
259     /**
260      * Sets the meta-data's encode format which is used when converting
261      * values to a string representation.
262      * @see #getEncodeFormat
263      * @see java.text.DateFormat
264      * @param format object used to describe format for object-to-string conversion
265      */

266     public void setEncodeFormat(Object JavaDoc format) {
267         Object JavaDoc oldEncodeFormat = this.encodeFormat;
268         this.encodeFormat = format;
269         firePropertyChange("encodeFormat", oldEncodeFormat, format);
270     }
271
272     /**
273      * @return integer containing the number of characters required to
274      * display the value
275      */

276     public int getDisplayWidth() {
277         return displayWidth;
278     }
279
280     /**
281      * Sets the meta-data's &quot;displayWidth&quot; property which provides
282      * a hint as to the number of characters typically required to display the value.
283      * The default is 24.
284      * @see #getDisplayWidth
285      * @param displayWidth integer containing the number of characters required to
286      * display the value
287      * @throws IllegalArgumentException if displayWidth < 0
288      */

289     public void setDisplayWidth(int displayWidth) {
290         if (displayWidth < 0) {
291             throw new IllegalArgumentException JavaDoc("displayWidth must be >= 0");
292         }
293         int oldDisplayWidth = this.displayWidth;
294         this.displayWidth = displayWidth;
295         firePropertyChange("displayWidth", oldDisplayWidth, displayWidth);
296     }
297
298
299     /**
300      * Gets the meta-data's &quot;readOnly&quot; property which indicates
301      * whether or not the associated data field's value cannot be modified.
302      * The default is <code>false</code>.
303      * @see #setReadOnly
304      * @return boolean indicating whether the data field is read-only
305      */

306     public boolean isReadOnly() {
307         return readOnly;
308     }
309
310     /**
311      * Sets the meta-data's &quot;readOnly&quot; property.
312      * @see #isReadOnly
313      * @param readOnly boolean indicating whether the data field is read-only
314      */

315     public void setReadOnly(boolean readOnly) {
316         boolean oldReadOnly = this.readOnly;
317         this.readOnly = readOnly;
318         firePropertyChange("readOnly", oldReadOnly, readOnly);
319     }
320
321     /**
322      * Gets the meta-data's &quot;minValueCount&quot; property, which indicates
323      * the minimum number of values required for the data field. The default
324      * is 0, which means a null value is permitted. This property should be set
325      * to 1 if the field requires a non-null value.
326      * @see #setMinValueCount
327      * @return integer indicating the minimum number of values required for
328      * the data field
329      */

330     public int getMinValueCount() {
331         return minValueCount;
332     }
333
334    /**
335     * Sets the meta-data's &quot;minValueCount&quot; property.
336     * @param minValueCount integer indicating the minimum number of values required for
337     * the data field
338     */

339    public void setMinValueCount(int minValueCount) {
340        int oldMinValueCount = this.minValueCount;
341        this.minValueCount = minValueCount;
342        firePropertyChange("minValueCount", oldMinValueCount, minValueCount);
343    }
344
345    /**
346     * Convenience method for calculating whether the &quot;minValueCount&quot;
347     * property is greater than 0.
348     * @return boolean indicating whether at least one non-null value must
349     * be set for the data field
350     */

351    public boolean isRequired() {
352        return getMinValueCount() > 0;
353    }
354
355    public void setRequired(boolean required) {
356        if (required) {
357            if (getMinValueCount() <= 0) {
358                setMinValueCount(1);
359            }
360        }
361        else { /* not required */
362            if (getMinValueCount() > 0) {
363                setMinValueCount(0);
364            }
365        }
366    }
367
368    /**
369     * Gets the meta-data's &quot;maxValueCount&quot; property, which indicates
370     * the maximum number of values permitted for the data field. The default
371     * is 1, which means a single value is permitted. If this property is set
372     * to a value greater than 1, then the values will be contained in a
373     * <code>List</code> collection.
374     * @see java.util.List
375     * @see #setMaxValueCount
376     * @return integer indicating the maximum number of values permitted for
377     * the data field
378     */

379    public int getMaxValueCount() {
380        return maxValueCount;
381    }
382
383    /**
384     * Sets the meta-data's &quot;maxValueCount&quot; property.
385     * @param maxValueCount integer indicating the maximum number of values permitted for
386     * the data field
387     */

388    public void setMaxValueCount(int maxValueCount) {
389        int oldMaxValueCount = this.maxValueCount;
390        this.maxValueCount = maxValueCount;
391        firePropertyChange("maxValueCount", oldMaxValueCount, maxValueCount);
392    }
393
394    /**
395     * Places a custom property into this meta-data's custom properties map.
396     *
397     * @param propertyName A non-null string of the form
398     * com.mydomain.packagename.PropertyName
399     * @param value The value for the named property
400     */

401    public void setCustomProperty(String JavaDoc propertyName, Object JavaDoc value) {
402        if (propertyName == null) {
403            throw new NullPointerException JavaDoc("The propertyName for a custom property " +
404                                               "on MetaData cannot be null");
405        }
406        Object JavaDoc oldValue = customProps.get(propertyName);
407        customProps.put(propertyName, value);
408        firePropertyChange(propertyName, oldValue, value);
409    }
410
411    /**
412     * @param propertyName A non-null string of the form
413     * com.mydomain.packagename.PropertyName
414     * @return The value for the given propertyName in the custom properties map.
415     */

416    public Object JavaDoc getCustomProperty(String JavaDoc propertyName) {
417        if (propertyName == null) {
418            throw new NullPointerException JavaDoc("The propertyName for a custom property " +
419                                               "on MetaData cannot be null");
420        }
421        return customProps.get(propertyName);
422    }
423
424    /**
425     * @param propertyName A non-null string of the form com.mydomain.packagename.PropertyName
426     * @param defaultValue The default value to return if the custom properties map
427     * does not contain they specified propertyName
428     * @return The value at the given propertyName in the customProps map.
429     */

430    public Object JavaDoc getCustomProperty(String JavaDoc propertyName, Object JavaDoc defaultValue) {
431        if (propertyName == null) {
432            throw new NullPointerException JavaDoc("The propertyName for a custom property " +
433                                               "on MetaData cannot be null");
434        }
435        return customProps.containsKey(propertyName) ?
436            customProps.get(propertyName) : defaultValue;
437    }
438
439    /**
440     * Removes the custom property from the custom properties map.
441     * @param propertyName A non-null string of the form com.mydomain.packagename.PropertyName
442     */

443    public void removeCustomProperty(String JavaDoc propertyName) {
444        if (propertyName == null) {
445            throw new NullPointerException JavaDoc("The propertyName for a custom property " +
446                                               "on MetaData cannot be null");
447        }
448        Object JavaDoc oldValue = customProps.get(propertyName);
449        customProps.remove(propertyName);
450        firePropertyChange(propertyName, oldValue, null);
451    }
452
453    /**
454     *
455     * @return array containing the existing propertyNames in the custom properties map.
456     */

457    public String JavaDoc[] getCustomPropertyKeys() {
458        Object JavaDoc keys[] = customProps.keySet().toArray();
459        String JavaDoc propertyNames[] = new String JavaDoc[keys.length];
460        System.arraycopy(keys, 0, propertyNames, 0, keys.length);
461        return propertyNames;
462    }
463
464     /**
465      * Adds the specified validator for this meta-data. A validator object is
466      * used to determine whether a particular object is a valid value for
467      * the associated data field. A data field may have 0 or more validators.
468      * @see #removeValidator
469      * @see #getValidators
470      * @param validator Validator object which performs validation checks on
471      * values being set on the associated data field
472      */

473     public void addValidator(Validator validator) {
474         if (validators == null) {
475             validators = new ArrayList JavaDoc();
476         }
477         validators.add(validator);
478     }
479
480     /**
481      * Removes the specified validator for this meta-data.
482      * @see #addValidator
483      * @param validator Validator object which performs validation checks on
484      * values being set on the associated data field
485      */

486     public void removeValidator(Validator validator) {
487         if (validators != null) {
488             validators.remove(validator);
489             if (validators.size() == 0) {
490                 validators = null;
491             }
492         }
493     }
494
495     /**
496      * @see #addValidator
497      * @return array containing 0 or more validators set on this meta-data
498      */

499     public Validator[] getValidators() {
500         if (validators != null) {
501             return (Validator[])validators.toArray(new Validator[1]);
502         }
503         return new Validator[0];
504     }
505
506     /**
507      * Adds the specified property change listener to this meta-data object.
508      * @param pcl PropertyChangeListener object to receive events when meta-data
509      * properties change
510      */

511     public void addPropertyChangeListener(PropertyChangeListener JavaDoc pcl) {
512         if (pcs == null) {
513             pcs = new PropertyChangeSupport JavaDoc(this);
514         }
515         pcs.addPropertyChangeListener(pcl);
516     }
517
518     /**
519      * Removes the specified property change listener from this meta-data object.
520      * @param pcl PropertyChangeListener object to receive events when meta-data
521      * properties change
522      */

523     public void removePropertyChangeListener(PropertyChangeListener JavaDoc pcl) {
524         if (pcs != null) {
525             pcs.removePropertyChangeListener(pcl);
526         }
527     }
528
529     /**
530      *
531      * @return array containing the PropertyChangeListener objects registered
532      * on this meta-data object
533      */

534     public PropertyChangeListener JavaDoc[] getPropertyChangeListeners() {
535         if (pcs != null) {
536             return pcs.getPropertyChangeListeners();
537         }
538         return new PropertyChangeListener JavaDoc[0];
539     }
540
541     protected void firePropertyChange(String JavaDoc propertyName,
542                                       int oldValue, int newValue) {
543         if (newValue != oldValue) {
544             firePropertyChange(propertyName,
545                                new Integer JavaDoc(oldValue), new Integer JavaDoc(newValue));
546         }
547     }
548
549     protected void firePropertyChange(String JavaDoc propertyName,
550                                       boolean oldValue, boolean newValue) {
551         if (newValue != oldValue) {
552             firePropertyChange(propertyName,
553                                Boolean.valueOf(oldValue),
554                                Boolean.valueOf(newValue));
555         }
556     }
557
558     protected void firePropertyChange(String JavaDoc propertyName, Object JavaDoc oldValue,
559                                       Object JavaDoc newValue) {
560         if (pcs != null) {
561             pcs.firePropertyChange(propertyName, oldValue, newValue);
562         }
563     }
564 }
565
Popular Tags