MetaData.java
上传用户:zhengdagz
上传日期:2014-03-06
资源大小:1956k
文件大小:21k
源码类别:

xml/soap/webservice

开发平台:

Java

  1. /*
  2.  * $Id: MetaData.java,v 1.3 2005/10/10 17:01:09 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.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  * 
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  * 
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  20.  */
  21. package org.jdesktop.binding.metadata;
  22. import java.beans.PropertyChangeListener;
  23. import java.beans.PropertyChangeSupport;
  24. import java.util.ArrayList;
  25. import java.util.HashMap;
  26. import java.util.Map;
  27. /**
  28.  * <p>
  29.  * Class for representing the meta-data for an field in a data model.
  30.  * A &quot;field&quot; may map to a column on a RowSet, a property on a JavaBean,
  31.  * or some other discrete data element on a data model.
  32.  * The meta-data describes aspects of a data field such as it's name,
  33.  * type, and edit constraints.  This class may be used when such information
  34.  * isn't encapsulated in the data model object itself and thus must be represented
  35.  * in an external object.  Meta-data is intended only for holding state about
  36.  * a data model element and is not intended for implementing application semantics.</p>
  37.  * <p>
  38.  * A meta-data object should be initialized at a minimum with a name, class,
  39.  * and label.  Additional meta-data properties can be set as necessary.
  40.  * For example:<br>
  41.  * <pre><code>
  42.  *     MetaData metaData = new MetaData(&quot;firstname&quot;, String.class,
  43.  *                                      &quot;First Name&quot;);
  44.  *     metaData.setRequired(true);
  45.  * </code></pre>
  46.  * If the associated data model field requires application-specific validation
  47.  * logic to verify the correctness of a potential value, one or more Validator
  48.  * instances can be added to the meta-data object.  Example:<br>
  49.  * <pre><code>
  50.  *     MetaData metaData = new MetaData(&quot;creditcard&quot;, String.class,
  51.  *                                      &quot;Credit Card Number&quot;
  52.  *     metaData.setRequired(true);
  53.  *     metaData.addValidator(new MyCreditCardValidator());
  54.  * </code></pre>
  55.  * </p>
  56.  *
  57.  * @author Amy Fowler
  58.  * @author Rich Bair
  59.  * @version 1.0
  60.  */
  61. public class MetaData {
  62.     protected String name;
  63.     protected Class klass = String.class;
  64.     protected String label;
  65.     protected Converter converter = null;
  66.     protected Object decodeFormat = null;
  67.     protected Object encodeFormat = null;
  68.     protected boolean readOnly = false;
  69.     protected int minValueCount = 0; // null value okay
  70.     protected int maxValueCount = 1; // only one value allowed
  71.     protected int displayWidth = 24;
  72.     protected ArrayList validators = null;
  73.     protected Map customProps = new HashMap();
  74.     protected PropertyChangeSupport pcs;
  75.     /**
  76.      * Instantiates a meta-data object with a default name &quot;value&quot; and
  77.      * a default field class equal to <code>java.lang.String</code>.
  78.      * This provides the no-argument constructor required for JavaBeans.
  79.      * It is recommended that the program explicitly set a meaningful
  80.      * &quot;name&quot; property.
  81.      */
  82.     public MetaData() {
  83.         this("value");
  84.     }
  85.     /**
  86.      * Instantiates a meta-data object with the specified name and
  87.      * a default field class equal to <code>java.lang.String</code>.
  88.      * @param name String containing the name of the data field
  89.      */
  90.     public MetaData(String name) {
  91.         this.name = name;
  92.     }
  93.     /**
  94.      * Instantiates a meta-data object with the specified name and
  95.      * field class.
  96.      * @param name String containing the name of the data field
  97.      * @param klass Class indicating type of data field
  98.      */
  99.     public MetaData(String name, Class klass) {
  100.         this(name);
  101.         this.klass = klass;
  102.     }
  103.     /**
  104.      * Instantiates a meta-data object with the specified name,
  105.      * field class, and label.
  106.      * @param name String containing the name of the data field
  107.      * @param klass Class indicating type of data field
  108.      * @param label String containing the user-displayable label for the
  109.      *        data field
  110.      */
  111.     public MetaData(String name, Class klass, String label) {
  112.         this(name, klass);
  113.         this.label = label;
  114.     }
  115.     /**
  116.      * Gets the meta-data &quot;name&quot; property which indicates
  117.      * the logical name of the associated data field.
  118.      * @see #setName
  119.      * @return String containing the name of the data field.
  120.      */
  121.     public String getName() {
  122.         return name;
  123.     }
  124.     /**
  125.      * Sets the meta-data &quot;name&quot; property.
  126.      * @see #getName
  127.      * @param name String containing the name of the data field
  128.      */
  129.     public void setName(String name) {
  130.         String oldName = this.name;
  131.         this.name = name;
  132.         firePropertyChange("name", oldName, name);
  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 getElementClass() {
  142.         return klass;
  143.     }
  144.     /**
  145.      * Sets the meta-data's &quot;elementClass&quot; property.
  146.      * This <code>set</code> method is provided for meta-data bean initialization
  147.      * only; the field class is not intended to be modified after initialization,
  148.      * since other aspects of a meta-data object may depend on this type setting.
  149.      * @see #getElementClass
  150.      * @param klass Class indicating type of data field
  151.      */
  152.     public void setElementClass(Class klass) {
  153.         Class oldClass = this.klass;
  154.         this.klass = klass;
  155.         firePropertyChange("elementClass", oldClass, klass);
  156.     }
  157.     /**
  158.      * Gets the meta-data's &quot;label&quot; property, which provides
  159.      * a label for the associated data field.  The label is intended
  160.      * for display to the end-user and may be localized.
  161.      * If no label has been explicitly set, then the meta-data's name is
  162.      * returned.
  163.      * @see #setLabel
  164.      * @return String containing the user-displayable label for the
  165.      *         data field
  166.      */
  167.     public String getLabel() {
  168.         return label == null? name : label;
  169.     }
  170.     /**
  171.      * Sets the meta-data's &quot;label&quot; property.
  172.      * @todo Rename to setTitle
  173.      *
  174.      * @see #getLabel
  175.      * @param label String containing the user-displable label for the
  176.      *        data field
  177.      */
  178.     public void setLabel(String label) {
  179.         String oldLabel = this.label;
  180.         this.label = label;
  181.         firePropertyChange("label", oldLabel, label);
  182.     }
  183.     /**
  184.      * Gets the meta-data's converter, which performs conversions between
  185.      * string values and objects of the associated data field's type.
  186.      * If no converter was explicitly set on this meta-data object,
  187.      * this method will retrieve a default converter for this data
  188.      * field's type from the converter registry.  If no default converter
  189.      * is registered, this method will return <code>null</code>.
  190.      * @see Converters#get
  191.      * @see #setConverter
  192.      * @see #getElementClass
  193.      * @return Converter used to perform conversions between string values
  194.      *         and objects of this field's type
  195.      */
  196.     public Converter getConverter() {
  197.         if (converter == null) {
  198.             return Converters.get(klass);
  199.         }
  200.         return converter;
  201.     }
  202.     /**
  203.      * Sets the meta-data's converter.
  204.      *
  205.      * @see #getConverter
  206.      * @param converter Converter used to perform conversions between string values
  207.      *         and objects of this field's type
  208.      */
  209.     public void setConverter(Converter converter) {
  210.         Converter oldConverter = this.converter;
  211.         this.converter = converter;
  212.         firePropertyChange("converter", oldConverter, converter);
  213.     }
  214.     /**
  215.      * Gets the meta-data's decode format which is used when converting
  216.      * values from a string representation.  This property must be used when
  217.      * conversion requires format information on how the string representation
  218.      * is structured.  For example, a decode format should be used when decoding
  219.      * date values.  The default decode format is <code>null</code>.
  220.      * @see #setDecodeFormat
  221.      * @return format object used to describe format for string-to-object conversion
  222.      */
  223.     public Object getDecodeFormat() {
  224.         return decodeFormat;
  225.     }
  226.     /**
  227.      * Sets the meta-data's decode format which is used when converting
  228.      * values from a string representation.
  229.      * @see #getDecodeFormat
  230.      * @see java.text.DateFormat
  231.      * @param format object used to describe format for string-to-object conversion
  232.      */
  233.     public void setDecodeFormat(Object format) {
  234.         Object oldDecodeFormat = this.decodeFormat;
  235.         this.decodeFormat = format;
  236.         firePropertyChange("decodeFormat", oldDecodeFormat, format);
  237.     }
  238.     /**
  239.      * Gets the meta-data's encode format which is used when converting
  240.      * values to a string representation.  This property must be used when
  241.      * conversion requires format information on how the string representation
  242.      * should be generated.  For example, an encode format should be used when
  243.      * encoding date values.  The default encode format is <code>null</code>.
  244.      * @see #setEncodeFormat
  245.      * @return format object used to describe format for object-to-string conversion
  246.      */
  247.     public Object getEncodeFormat() {
  248.         return encodeFormat;
  249.     }
  250.     /**
  251.      * Sets the meta-data's encode format which is used when converting
  252.      * values to a string representation.
  253.      * @see #getEncodeFormat
  254.      * @see java.text.DateFormat
  255.      * @param format object used to describe format for object-to-string conversion
  256.      */
  257.     public void setEncodeFormat(Object format) {
  258.         Object oldEncodeFormat = this.encodeFormat;
  259.         this.encodeFormat = format;
  260.         firePropertyChange("encodeFormat", oldEncodeFormat, format);
  261.     }
  262.     /**
  263.      * @return integer containing the number of characters required to
  264.      *        display the value
  265.      */
  266.     public int getDisplayWidth() {
  267.         return displayWidth;
  268.     }
  269.     /**
  270.      * Sets the meta-data's &quot;displayWidth&quot; property which provides
  271.      * a hint as to the number of characters typically required to display the value.
  272.      * The default is 24.
  273.      * @see #getDisplayWidth
  274.      * @param displayWidth integer containing the number of characters required to
  275.      *        display the value
  276.      * @throws IllegalArgumentException if displayWidth < 0
  277.      */
  278.     public void setDisplayWidth(int displayWidth) {
  279.         if (displayWidth < 0) {
  280.             throw new IllegalArgumentException("displayWidth must be >= 0");
  281.         }
  282.         int oldDisplayWidth = this.displayWidth;
  283.         this.displayWidth = displayWidth;
  284.         firePropertyChange("displayWidth", oldDisplayWidth, displayWidth);
  285.     }
  286.     /**
  287.      * Gets the meta-data's &quot;readOnly&quot; property which indicates
  288.      * whether or not the associated data field's value cannot be modified.
  289.      * The default is <code>false</code>.
  290.      * @see #setReadOnly
  291.      * @return boolean indicating whether the data field is read-only
  292.      */
  293.     public boolean isReadOnly() {
  294.         return readOnly;
  295.     }
  296.     /**
  297.      * Sets the meta-data's &quot;readOnly&quot; property.
  298.      * @see #isReadOnly
  299.      * @param readOnly boolean indicating whether the data field is read-only
  300.      */
  301.     public void setReadOnly(boolean readOnly) {
  302.         boolean oldReadOnly = this.readOnly;
  303.         this.readOnly = readOnly;
  304.         firePropertyChange("readOnly", oldReadOnly, readOnly);
  305.     }
  306.     /**
  307.      * Gets the meta-data's &quot;minValueCount&quot; property, which indicates
  308.      * the minimum number of values required for the data field.  The default
  309.      * is 0, which means a null value is permitted.  This property should be set
  310.      * to 1 if the field requires a non-null value.
  311.      * @see #setMinValueCount
  312.      * @return integer indicating the minimum number of values required for
  313.      *         the data field
  314.      */
  315.     public int getMinValueCount() {
  316.         return minValueCount;
  317.     }
  318.    /**
  319.     * Sets the meta-data's &quot;minValueCount&quot; property.
  320.     * @param minValueCount integer indicating the minimum number of values required for
  321.     *         the data field
  322.     */
  323.    public void setMinValueCount(int minValueCount) {
  324.        int oldMinValueCount = this.minValueCount;
  325.        this.minValueCount = minValueCount;
  326.        firePropertyChange("minValueCount", oldMinValueCount, minValueCount);
  327.    }
  328.    /**
  329.     * Convenience method for calculating whether the &quot;minValueCount&quot;
  330.     * property is greater than 0.
  331.     * @return boolean indicating whether at least one non-null value must
  332.     *         be set for the data field
  333.     */
  334.    public boolean isRequired() {
  335.        return getMinValueCount() > 0;
  336.    }
  337.    public void setRequired(boolean required) {
  338.        if (required) {
  339.            if (getMinValueCount() <= 0) {
  340.                setMinValueCount(1);
  341.            }
  342.        }
  343.        else { /* not required */
  344.            if (getMinValueCount() > 0) {
  345.                setMinValueCount(0);
  346.            }
  347.        }
  348.    }
  349.    /**
  350.     * Gets the meta-data's &quot;maxValueCount&quot; property, which indicates
  351.     * the maximum number of values permitted for the data field.  The default
  352.     * is 1, which means a single value is permitted.  If this property is set
  353.     * to a value greater than 1, then the values will be contained in a
  354.     * <code>List</code> collection.
  355.     * @see java.util.List
  356.     * @see #setMaxValueCount
  357.     * @return integer indicating the maximum number of values permitted for
  358.     *         the data field
  359.     */
  360.    public int getMaxValueCount() {
  361.        return maxValueCount;
  362.    }
  363.    /**
  364.     * Sets the meta-data's &quot;maxValueCount&quot; property.
  365.     * @param maxValueCount integer indicating the maximum number of values permitted for
  366.     *         the data field
  367.     */
  368.    public void setMaxValueCount(int maxValueCount) {
  369.        int oldMaxValueCount = this.maxValueCount;
  370.        this.maxValueCount = maxValueCount;
  371.        firePropertyChange("maxValueCount", oldMaxValueCount, maxValueCount);
  372.    }
  373.    /**
  374.     * Places a custom property into this meta-data's custom properties map.
  375.     *
  376.     * @param propertyName   A non-null string of the form
  377.     *                       com.mydomain.packagename.PropertyName
  378.     * @param value The value for the named property
  379.     */
  380.    public void setCustomProperty(String propertyName, Object value) {
  381.        if (propertyName == null) {
  382.            throw new NullPointerException("The propertyName for a custom property " +
  383.                                               "on MetaData cannot be null");
  384.        }
  385.        Object oldValue = customProps.get(propertyName);
  386.        customProps.put(propertyName, value);
  387.        firePropertyChange(propertyName, oldValue, value);
  388.    }
  389.    /**
  390.     * @param propertyName A non-null string of the form
  391.     *            com.mydomain.packagename.PropertyName
  392.     * @return The value for the given propertyName in the custom properties map.
  393.     */
  394.    public Object getCustomProperty(String propertyName) {
  395.        if (propertyName == null) {
  396.            throw new NullPointerException("The propertyName for a custom property " +
  397.                                               "on MetaData cannot be null");
  398.        }
  399.        return customProps.get(propertyName);
  400.    }
  401.    /**
  402.     * @param propertyName A non-null string of the form com.mydomain.packagename.PropertyName
  403.     * @param defaultValue The default value to return if the custom properties map
  404.     *            does not contain they specified propertyName
  405.     * @return The value at the given propertyName in the customProps map.
  406.     */
  407.    public Object getCustomProperty(String propertyName, Object defaultValue) {
  408.        if (propertyName == null) {
  409.            throw new NullPointerException("The propertyName for a custom property " +
  410.                                               "on MetaData cannot be null");
  411.        }
  412.        return customProps.containsKey(propertyName) ?
  413.            customProps.get(propertyName) : defaultValue;
  414.    }
  415.    /**
  416.     * Removes the custom property from the custom properties map.
  417.     * @param propertyName A non-null string of the form com.mydomain.packagename.PropertyName
  418.     */
  419.    public void removeCustomProperty(String propertyName) {
  420.        if (propertyName == null) {
  421.            throw new NullPointerException("The propertyName for a custom property " +
  422.                                               "on MetaData cannot be null");
  423.        }
  424.        Object oldValue = customProps.get(propertyName);
  425.        customProps.remove(propertyName);
  426.        firePropertyChange(propertyName, oldValue, null);
  427.    }
  428.    /**
  429.     *
  430.     * @return array containing the existing propertyNames in the custom properties map.
  431.     */
  432.    public String[] getCustomPropertyKeys() {
  433.        Object keys[] = customProps.keySet().toArray();
  434.        String propertyNames[] = new String[keys.length];
  435.        System.arraycopy(keys, 0, propertyNames, 0, keys.length);
  436.        return propertyNames;
  437.    }
  438.     /**
  439.      * Adds the specified validator for this meta-data.  A validator object is
  440.      * used to determine whether a particular object is a valid value for
  441.      * the associated data field.  A data field may have 0 or more validators.
  442.      * @see #removeValidator
  443.      * @see #getValidators
  444.      * @param validator Validator object which performs validation checks on
  445.      *        values being set on the associated data field
  446.      */
  447.     public void addValidator(Validator validator) {
  448.         if (validators == null) {
  449.             validators = new ArrayList();
  450.         }
  451.         validators.add(validator);
  452.     }
  453.     /**
  454.      * Removes the specified validator for this meta-data.
  455.      * @see #addValidator
  456.      * @param validator Validator object which performs validation checks on
  457.      *        values being set on the associated data field
  458.      */
  459.     public void removeValidator(Validator validator) {
  460.         if (validators != null) {
  461.             validators.remove(validator);
  462.             if (validators.size() == 0) {
  463.                 validators = null;
  464.             }
  465.         }
  466.     }
  467.     /**
  468.      * @see #addValidator
  469.      * @return array containing 0 or more validators set on this meta-data
  470.      */
  471.     public Validator[] getValidators() {
  472.         if (validators != null) {
  473.             return (Validator[])validators.toArray(new Validator[1]);
  474.         }
  475.         return new Validator[0];
  476.     }
  477.     /**
  478.      * Adds the specified property change listener to this meta-data object.
  479.      * @param pcl PropertyChangeListener object to receive events when meta-data
  480.      *        properties change
  481.      */
  482.     public void addPropertyChangeListener(PropertyChangeListener pcl) {
  483.         if (pcs == null) {
  484.             pcs = new PropertyChangeSupport(this);
  485.         }
  486.         pcs.addPropertyChangeListener(pcl);
  487.     }
  488.     /**
  489.      * Removes the specified property change listener from this meta-data object.
  490.      * @param pcl PropertyChangeListener object to receive events when meta-data
  491.      *        properties change
  492.      */
  493.     public void removePropertyChangeListener(PropertyChangeListener pcl) {
  494.         if (pcs != null) {
  495.             pcs.removePropertyChangeListener(pcl);
  496.         }
  497.     }
  498.     /**
  499.      *
  500.      * @return array containing the PropertyChangeListener objects registered
  501.      *         on this meta-data object
  502.      */
  503.     public PropertyChangeListener[] getPropertyChangeListeners() {
  504.         if (pcs != null) {
  505.             return pcs.getPropertyChangeListeners();
  506.         }
  507.         return new PropertyChangeListener[0];
  508.     }
  509.     protected void firePropertyChange(String propertyName,
  510.                                       int oldValue, int newValue) {
  511.         if (newValue != oldValue) {
  512.             firePropertyChange(propertyName,
  513.                                new Integer(oldValue), new Integer(newValue));
  514.         }
  515.     }
  516.     protected void firePropertyChange(String propertyName,
  517.                                       boolean oldValue, boolean newValue) {
  518.         if (newValue != oldValue) {
  519.             firePropertyChange(propertyName,
  520.                                Boolean.valueOf(oldValue),
  521.                                Boolean.valueOf(newValue));
  522.         }
  523.     }
  524.     protected void firePropertyChange(String propertyName, Object oldValue,
  525.                                       Object newValue) {
  526.         if (pcs != null) {
  527.             pcs.firePropertyChange(propertyName, oldValue, newValue);
  528.         }
  529.     }
  530. }