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

xml/soap/webservice

开发平台:

Java

  1. /*
  2.  * $Id: DataColumn.java,v 1.10 2005/10/10 17:00:57 rbair Exp $
  3.  *
  4.  * Copyright 2005 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.dataset;
  22. import java.beans.PropertyChangeListener;
  23. import java.beans.PropertyChangeSupport;
  24. import java.util.logging.Logger;
  25. import net.sf.jga.fn.UnaryFunctor;
  26. import net.sf.jga.parser.ParseException;
  27. /**
  28.  * <p>A <code>DataColumn</code> defines information for values in a single column of a {@link DataTable}. 
  29.  * The <code>DataColumn</code> doesn't contain an actual value for a column, but rather gives the data type, 
  30.  * and name, and tells us whether the column is required, whether it is writeable, and 
  31.  * whether it is the primary key column for the table. The data type for a value in a <code>DataColumn</code> 
  32.  * is always a Java Class. 
  33.  *
  34.  * <p>A <code>DataColumn</code> is always associated with a specific <code>DataTable</code>, usually the <code>DataTable</code> that 
  35.  * instantiated it.
  36.  *
  37.  * <p>If a <code>DataColumn</code> is marked as a primary key, this is for tables with a single
  38.  * column primary key; multiple-column keys are not supported.
  39.  *
  40.  * <p>Note as well that a <code>DataColumn</code> is purely passive and doesn't itself 
  41.  * validate actions against the <code>DataTable</code>. If the column is required, or if it
  42.  * is read-only, the <code>DataColumn</code> will not enforce this, nor will it enforce
  43.  * uniqueness on primary key columns.
  44.  *
  45.  * @author rbair
  46.  */
  47. public class DataColumn {
  48.     /**
  49.      * The Logger
  50.      */
  51.     private static final Logger LOG = Logger.getLogger(DataColumn.class.getName());
  52.     
  53.     //protected for testing
  54.     /** Used as a prefix for auto-generated DataColumn names. */
  55.     protected static final String DEFAULT_NAME_PREFIX = "DataColumn";
  56.     
  57.     /**
  58.      * Used to generate a name for the DataColumn, since each DataColumn must
  59.      * have a name.
  60.      */
  61.     private static final NameGenerator NAMEGEN = new NameGenerator(DEFAULT_NAME_PREFIX);
  62.     
  63.     //used for communicating changes to this JavaBean, especially necessary for
  64.     //IDE tools, but also handy for any other component listening to this column
  65.     private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
  66.     /**
  67.      * The <code>DataTable</code> that created this DataColumn. This is an immutable property
  68.      * that is set in the constructor.
  69.      */
  70.     private DataTable table;
  71.     /**
  72.      * The name of this DataColumn. The name cannot contain any whitespace.
  73.      * In general, it should conform to the same rules as an identifier
  74.      * in Java.
  75.      */
  76.     private String name = NAMEGEN.generateName(this);
  77.     /**
  78.      * The Class of the data values for this DataColumn. This cannot be null. If
  79.      * the type is unknown, then this should be Object.class.
  80.      */
  81.     private Class type = Object.class;
  82.     /**
  83.      * Flag indicating whether the fields within this column are readonly or
  84.      * not.
  85.      */
  86.     private boolean readOnly = false;
  87.     /**
  88.      * Flag indicating whether the fields within this column are required.
  89.      * If a column is required, then the field must be filled in prior to
  90.      * a save, or an exception occurs.<br>
  91.      * TODO constraint logic isn't specified yet. When it is, make sure to
  92.      * include this check.
  93.      */
  94.     private boolean required = false;
  95.     /**
  96.      * The default value for the column. When a new row is added, the various
  97.      * cells set their values to this default.
  98.      */
  99.     private Object defaultValue;
  100.     /**
  101.      * Indicates whether this DataColumn is a key column. Key Columns enforce
  102.      * a unique constraint on the DataColumn (no two values in the column can
  103.      * be the same, as determined by .equals()).
  104.      */
  105.     private boolean keyColumn;
  106.     /**
  107.      * Expression to be evaluated for computed columns
  108.      */
  109.     private String expression;
  110.     private UnaryFunctor<DataRow,?> expImpl;
  111.     /**
  112.      * Create a new DataColumn. To construct a DataColumn, do not call
  113.      * <code>new DataColumn(table)</code> directly. Rather, call
  114.      * <code>table.addColumn()</code>.<br>
  115.      * @param table cannot be null. The <code>DataTable</code> that created this
  116.      *        DataColumn.
  117.      */
  118.     protected DataColumn(DataTable table) {
  119.         assert table != null;
  120.         this.table = table;
  121.     }
  122.     
  123.     /**
  124.      * Returns the <code>DataTable</code> that this column belongs to.
  125.      */
  126.     public DataTable getTable() {
  127.         return table;
  128.     }
  129.     
  130.     /**
  131.      * Returns the name of the DataColumn.
  132.      */
  133.     public String getName() {
  134.         return name;
  135.     }
  136.     /**
  137.      * Sets the name of the DataColumn. The name must be valid., or the change
  138.      * will not be made. If the name is invalid, a warning will be posted. Validity
  139.      * for names is defined in {@link DataSetUtils#isValidName(java.lang.String)}.
  140.      */
  141.     public void setName(String name) {
  142.         if (this.name != name) {
  143.             assert DataSetUtils.isValidName(name);
  144.             assert !table.columns.containsKey(name) && !table.selectors.containsKey(name);
  145.             String oldName = this.name;
  146.             this.name = name;
  147.             pcs.firePropertyChange("name", oldName, name);
  148.         }
  149.     }
  150.     /**
  151.      * Returns the type of the values for this DataColumn as a Java Class.
  152.      */
  153.     public Class getType() {
  154.         return type;
  155.     }
  156.     /**
  157.      * Sets the type for the values of this DataColumn as a Java Class.
  158.      * @param type If null, then the type is set to Object.class.
  159.      */
  160.     public void setType(Class type) {
  161.         if (this.type != type) {
  162.             Class oldType = this.type;
  163.             this.type = type == null ? Object.class : type;
  164.             pcs.firePropertyChange("type", oldType, type);
  165.         }
  166.     }
  167.     /**
  168.      * @return true if this DataColumn is read-only.
  169.      */
  170.     public boolean isReadOnly() {
  171.         return readOnly;
  172.     }
  173.     /**
  174.      * Sets whether this column is read-only or not.
  175.      * @param readOnly If true, column is read-only.
  176.      */
  177.     public void setReadOnly(boolean readOnly) {
  178.         if (this.readOnly != readOnly) {
  179.             boolean oldValue = this.readOnly;
  180.             this.readOnly = readOnly;
  181.             pcs.firePropertyChange("readOnly", oldValue, readOnly);
  182.         }
  183.     }
  184.     /**
  185.      * @return true if the fields in this column need to have a value
  186.      * before they can be saved to the data store. The DataColumn is required
  187.      * if the required flag is set by the {@link #setRequired(boolean)} method, 
  188.      * or if the DataColumn is a keyColumn. <br>
  189.      * 
  190.      * TODO need to decide if that is true, or if it is always required!
  191.      */
  192.     public boolean isRequired() {
  193.         return required || keyColumn;
  194.     }
  195.     /**
  196.      * Specifies whether the fields in this column must have a value (cannot
  197.      * be null).
  198.      * @param required
  199.      */
  200.     public void setRequired(boolean required) {
  201.         if (this.required != required) {
  202.             boolean oldValue = this.required;
  203.             this.required = required;
  204.             pcs.firePropertyChange("required", oldValue, required);
  205.         }
  206.     }
  207.     /**
  208.      * @return the value to use as a default value when a new field for
  209.      * this column is created, such as when a new row is created.
  210.      */
  211.     public Object getDefaultValue() {
  212.         return defaultValue;
  213.     }
  214.     
  215.     /**
  216.      * Set the value to use as a default when a new field for
  217.      * this column is created, such as when a new row is created.
  218.      * @param defaultValue
  219.      */
  220.     public void setDefaultValue(Object defaultValue) {
  221.         if (this.defaultValue != defaultValue) {
  222.             Object oldVal = this.defaultValue;
  223.             this.defaultValue = defaultValue;
  224.             pcs.firePropertyChange("defaultValue", oldVal, defaultValue);
  225.         }
  226.     }
  227.     
  228.     /**
  229.      * Returns whether the column is a key column or not
  230.      */
  231.     public boolean isKeyColumn() {
  232.         return keyColumn;
  233.     }
  234.     
  235.     /**
  236.      * Sets this column to be a key column. This implicitly places a unique
  237.      * constraint on the column. When this flag is set, no checks are made to
  238.      * ensure correctness. However, the column will automatically be marked as
  239.      * being required.
  240.      *
  241.      * @param value
  242.      */
  243.     public void setKeyColumn(boolean value) {
  244.         if (value != keyColumn) {
  245.             boolean oldVal = keyColumn;
  246.             keyColumn = value;
  247.             pcs.firePropertyChange("keyColumn", oldVal, value);
  248.             // If the column is a key column, then it is also required
  249.             // by virtue of its key-column-ness. Hence, if the column was NOT
  250.             // required before and keyColumn WAS false but is now true, then
  251.             // everybody needs to be notified that required is now true.
  252.             // Conversly, if the keyColumn WAS true but is now false and
  253.             // required WAS (still is, technically) false, then everybody
  254.             // needs to be notified that required is now false.
  255.             if (!oldVal && value && !required) {
  256.                 pcs.firePropertyChange("required", required, true);
  257.             } else if (oldVal && !value && !required) {
  258.                 pcs.firePropertyChange("required", true, required);
  259.             }
  260.         }
  261.     }
  262.     /**
  263.      * @return the expression for calculating values in this column
  264.      */
  265.     public String getExpression() {
  266.         return expression;
  267.     }
  268.     /**
  269.      * Sets the expression that this column will use to calculate its values.
  270.      * If the <code>expression</code> property on this column is set, then
  271.      * the values for each row in the column are determined based on the expression.
  272.      *
  273.      * <p>This is currently unimplemented. TODO</p>
  274.      *
  275.      * @param expression the expression for calculating values in this column
  276.      */
  277.     public void setExpression(String expression) /*throws ParseException*/ {
  278.         if (expression == null) {
  279.             expression = "";
  280.         }
  281.             
  282.         try {
  283.             UnaryFunctor<DataRow,?> newExpImpl =
  284.                 getParser().parseComputedColumn(getTable(), expression);
  285.             if ( !(expression.equals(this.expression))) {
  286.                 UnaryFunctor<DataRow,?> oldExpImpl = expImpl;
  287.                 String oldExpression = this.expression;
  288.                 this.expression = expression;
  289.                 this.expImpl = newExpImpl;
  290.                 pcs.firePropertyChange("expression", oldExpression, expression);
  291.             }
  292.         } catch (ParseException pe) {
  293.             pe.printStackTrace();
  294.         }
  295.     }
  296.     public Object getValueForRow(DataRow row) {
  297.         return expImpl.fn(row);
  298.     }
  299.     Parser getParser() { return getTable().getDataSet().getParser(); }
  300.     /**
  301.      * Adds a PropertyChangeListener to this class for any changes to bean 
  302.      * properties.
  303.      *
  304.      * @param listener The PropertyChangeListener to notify of changes to this 
  305.      * instance.
  306.      */    
  307.     public void addPropertyChangeListener(PropertyChangeListener listener) {
  308.         pcs.addPropertyChangeListener(listener);
  309.     }
  310.     
  311.     /**
  312.      * Adds a PropertyChangeListener to this class for specific property changes.
  313.      *
  314.      * @param listener The PropertyChangeListener to notify of changes to this 
  315.      * instance.
  316.      * @param property The name of the property to listen to changes for.
  317.      */
  318.     public void addPropertyChangeListener(String property, PropertyChangeListener listener) {
  319.         pcs.addPropertyChangeListener(property,  listener);
  320.     }
  321.     
  322.     /**
  323.      * Stops notifying a specific listener of any changes to bean properties.
  324.      *
  325.      * @param listener The listener to stop receiving notifications.
  326.      */
  327.     public void removePropertyChangeListener(PropertyChangeListener listener) {
  328.         pcs.removePropertyChangeListener(listener);
  329.     }
  330.     
  331.     /**
  332.      * Stops notifying a specific listener of changes to a specific property.
  333.      *
  334.      * @param propertyName The name of the property to ignore from now on.
  335.      * @param listener The listener to stop receiving notifications.
  336.      */
  337.     public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
  338.         pcs.removePropertyChangeListener(propertyName,  listener);
  339.     }
  340. }