⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 abstractcolumnspec.java

📁 把java对象映射成数据库表中的一条记录
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 *
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations under
 * the License.
 *
 * The Original Code is jRelationalFramework.
 *
 * The Initial Developer of the Original Code is is.com.
 * Portions created by is.com are Copyright (C) 2000 is.com.
 * All Rights Reserved.
 *
 * Contributor(s): Jonathan Carlson (joncrlsn@users.sf.net)
 * Contributor(s): ____________________________________
 *
 * Alternatively, the contents of this file may be used under the terms of
 * the GNU General Public License (the "GPL") or the GNU Lesser General
 * Public license (the "LGPL"), in which case the provisions of the GPL or
 * LGPL are applicable instead of those above.  If you wish to allow use of
 * your version of this file only under the terms of either the GPL or LGPL
 * and not to allow others to use your version of this file under the MPL,
 * indicate your decision by deleting the provisions above and replace them
 * with the notice and other provisions required by either the GPL or LGPL
 * License.  If you do not delete the provisions above, a recipient may use
 * your version of this file under either the MPL or GPL or LGPL License.
 *
 */
package com.is.jrf;


import com.is.util.sql.JDBCHelper;
import com.is.util.KeyPathHelper;

import java.lang.reflect.Method;

import java.sql.SQLException;
import java.sql.Timestamp;

import java.util.StringTokenizer;

import org.apache.log4j.Category;


/**
 *
 *  Subclass instances of this abstract class represent columns in the table
 *  represented by the domain class.
 *
 *  This abstract class is subclassed for different java data types (like
 *  Integer, String, Boolean, Timestamp, etc).  Adding another data type is
 *  as simple as subclassing, reimplementing the constructors, and
 *  implementing the formatForSql(anObject,aDatabasePolicy),
 *  getColumnClass(), and getColumnValueFrom(aJDBCHelper) methods.<p>
 *
 *  <b>Options that can go together..</b><br>
 *
 *  <ol>
 *  <li>The PRIMARY_KEY options should be used by themselves.
 *  <li>The OPTIMISTIC_LOCK option should be used by itself on a
 *      TimestampColumnSpec or IntegerColumnSpec only.
 *  <li>The REQUIRED and UNIQUE options can be used together or separately.
 *  </ol>
 *
 *  <p><b>Examples:</b><p>
 *
 *  For an Integer sequenced primary key use something like this: (REQUIRED
 *  and UNIQUE are ignored when SEQUENCED_PRIMARY_KEY is present so don't
 *  use them)<br>
 *
 *  <code><pre>
 *        new IntegerColumnSpec(
 *             "PersonId",
 *             "getPersonId",
 *             "setPersonId",
 *             DEFAULT_TO_NULL,
 *             SEQUENCED_PRIMARY_KEY);
 *  </pre></code>
 *
 *  For a String natural primary key use something like this: (As opposed
 *  to SEQUENCED_PRIMARY_KEY, the REQUIRED and UNIQUE options are implied
 *  when NATURAL_PRIMARY_KEY is present so you don't need to specify them)<br>
 *
 *  <code><pre>
 *        new StringColumnSpec(
 *             "PersonCode",
 *             "getPersonCode",
 *             "setPersonCode",
 *             DEFAULT_TO_NULL,
 *             NATURAL_PRIMARY_KEY);
 *  </pre></code>
 *
 *  For a String attribute that is required and unique use something like
 *  this:<br>
 *
 *  <code><pre>
 *        new StringColumnSpec(
 *              "Name",
 *              "getName",
 *              "setName",
 *              DEFAULT_TO_NULL,
 *              REQUIRED,
 *              UNIQUE);
 *  </pre></code>
 *
 *  For an attribute that has a non-null default, use something like
 *  this:<br>
 *
 *  <code><pre>
 *        new IntegerColumnSpec(
 *              "Age",
 *              "getAge",
 *              "setAge",
 *              DEFAULT_TO_ZERO);
 *  </pre></code>
 *
 *  or any Integer:<br>
 *
 *  <code><pre>
 *        new IntegerColumnSpec(
 *              "Age",
 *              "getAge",
 *              "setAge",
 *              new Integer(99));
 *  </pre></code>
 *
 *  For a Timestamp that is used as an optimistic lock, use something like
 *  this: (REQUIRED and UNIQUE are ignored when OPTIMISTIC_LOCK is present
 *  so don't use them)<br>
 *
 *  <code><pre>
 *        new TimestampColumnSpec(
 *              "UpdatedOn",
 *              "getUpdatedOn",
 *              "setUpdatedOn",
 *              DEFAULT_TO_NOW,
 *              OPTIMISTIC_LOCK);
 *  </pre></code>
 *
 * Here is an example of an AbstractDomain#buildColumnSpecs() method
 * for a table with a compound primary key.  ColumnSpecs in a compound
 * primary key do not need any options (REQUIRED or UNIQUE) specified.
 *
 * <code><pre>
 * public List buildColumnSpecs()
 *     {
 *     List returnValue = new ArrayList();
 *     returnValue.add(
 *         new CompoundPrimaryKeyColumnSpec(
 *             new IntegerColumnSpec(
 *                 "Id",
 *                  "getId",
 *                 "setId",
 *                 DEFAULT_TO_NULL),
 *             new StringColumnSpec(
 *                 "Code",
 *                 "getCode",
 *                 "setCode",
 *                 DEFAULT_TO_NULL)));
 *     returnValue.add(
 *         new StringColumnSpec(
 *             "Name",
 *             "getName",
 *             "setName",
 *             DEFAULT_TO_NULL,
 *             REQUIRED,
 *             UNIQUE));
 *     return returnValue;
 *     }
 *  </pre></code>
 */
public abstract class AbstractColumnSpec
    implements ColumnSpec
  {

  /* ===============  Static Final Variables  =============== */
  private static final Category LOG =
                Category.getInstance(AbstractColumnSpec.class.getName());

  // Use these in arguements to buildNameValuePair()
  protected static final String EQUALS = "=";
  protected static final String NOT_EQUALS = "<>";

  /* ===============  Instance Variables  =============== */

  protected String  i_columnName;
  protected String  i_getter;
  protected String  i_setter;
  protected Object  i_default = null;
  protected boolean i_required = false;
  protected boolean i_sequencedPrimaryKey = false;
  protected boolean i_naturalPrimaryKey = false;
  protected boolean i_unique = false;
  protected boolean i_subtypeIdentifier = false;
  protected boolean i_optimisticLock = false;


  /* ===============  Constructors  =============== */


  public AbstractColumnSpec(
      String  columnName,
      String  getter,
      String  setter,
      Object  defaultValue,
      int     option1,
      int     option2,
      int     option3)
    {
    int option = 0;

    i_columnName = columnName;
    i_getter = getter;
    i_setter = setter;
    i_default = defaultValue;

    for (int i=1; i<=3; i++)
        {
        switch (i)
            {
            case 1: option = option1; break;
            case 2: option = option2; break;
            case 3: option = option3; break;
            }
        if (!i_sequencedPrimaryKey &&
            !i_naturalPrimaryKey &&
            !i_optimisticLock)
            {
            switch (option)
                {
                case ColumnSpec.SEQUENCED_PRIMARY_KEY:
                    i_sequencedPrimaryKey = true;
                    i_required = false;
                    i_unique = false;
                    i_optimisticLock = false;
                    break;
                case ColumnSpec.NATURAL_PRIMARY_KEY:
                    i_naturalPrimaryKey = true;
                    i_required = true;
                    i_unique = true;
                    i_optimisticLock = false;
                    break;
                case ColumnSpec.OPTIMISTIC_LOCK:
                    i_optimisticLock = true;
                    i_required = false;
                    i_unique = false;
                    break;
                case ColumnSpec.SUBTYPE_IDENTIFIER:
                    i_subtypeIdentifier = true;
                    break;
                case ColumnSpec.REQUIRED:
                    i_required = true;
                    break;
                case ColumnSpec.UNIQUE:
                    i_unique = true;
                    break;
                }
            } // if not primary key or optimistic lock
        } // for

    if (this.isOptimisticLock() &&
        i_default == null)
        {
        i_default = this.optimisticLockDefaultValue();
        }
    }

  public AbstractColumnSpec(
      String  columnName,
      String  getter,
      String  setter,
      Object  defaultValue)
    {
    this(columnName,
         getter,
         setter,
         defaultValue,
         0,
         0,
         0);
    }

  public AbstractColumnSpec(
      String  columnName,
      String  getter,
      String  setter,
      Object  defaultValue,
      int     option1)
    {
    this(columnName,
         getter,
         setter,
         defaultValue,
         option1,
         0,
         0);
    }

  public AbstractColumnSpec(
      String  columnName,
      String  getter,
      String  setter,
      Object  defaultValue,
      int     option1,
      int     option2)
    {
    this(columnName,
         getter,
         setter,
         defaultValue,
         option1,
         option2,
         0);
    }


  /* ===============  Abstract Method Definitions  =============== */

  /**
   * Returns a string representing the given attribute value. The string
   * will be used in an SQL expression.
   *
   * @param obj a value of type 'Object'
   * @return a value of type 'String'
   */
  public abstract String formatForSql(Object obj,
                                      DatabasePolicy dbPolicy);


  /**
   * See IntegerColumnSpec for example of how to implement:
   */
  public abstract Class getColumnClass();


  /**
   * See IntegerColumnSpec for example of how to implement:
   */
  public abstract Object getColumnValueFrom(JDBCHelper helper)
          throws SQLException;

  /**
   * See IntegerColumnSpec for example of how to implement:
   */
  protected abstract Object decode(String aString);

  /**
   * Return the type of column to be used in a CREATE TABLE or ALTER TABLE
   * statement.
   *
   * @param dbPolicy a value of type 'DatabasePolicy'
   * @return a value of type 'String'
   */
  public abstract String getSQLColumnType(DatabasePolicy dbPolicy);


  /* ==========  Static Methods  ========== */


  /**
   * Sets the attribute value of a given persistent object using reflection.
   * This is static so it can be used by the JoinColumn subclasses.
   *
   * @param aValue a value of type 'Object'
   * @param aPO a value of type 'PersistentObject'
   * @param setter a value of type 'String'
   * @param valueClass a value of type 'Class'
   */
  public static void setValueTo (Object aValue,
                                 PersistentObject aPO,
                                 String setter,
                                 Class valueClass)
    {
    Method setMethod = null;

    // Create the parameter list array
    try
        {
        Class[] parms = new Class[]
            {valueClass};
        // Create the args object
        Object args[] = new Object[]
            {aValue};
        Class poClass = aPO.getClass();
        setMethod = poClass.getMethod(setter, parms);
        setMethod.invoke(aPO, args);
        }
    catch (Exception e)
        {
        LOG.error(
            "Reflection Error: " + e
            + " in com.is.jrf.AbstractColumnSpec.setValueTo(...)"
            + "\nObject: " + aPO
            + " setter: " + setter
            + " arg class: " + valueClass
            + " arg value: " + aValue,
            e);
        throw new ConfigurationException(e.fillInStackTrace().toString());
        }
    } // setValueTo(value, aPO, setter, valueClass)


  /**
   * Get the value of this attribute from aPO.  If the value is null, the
   * default will be returned.  This could be done in the persistent object
   * when the variable is initialized, but the developer might forget to do
   * that.  More importantly, an attribute read from the database might be
   * null which would override the variable initialization.  When the save is
   * executed, this assures that the new default value will be put into the
   * database.
   *
   * <p>Note: The getter can be of the form: "getCustomer.getId"
   *
   * @param aPO a value of type 'PersistentObject'
   * @param getter a value of type 'String' - can be of the form:
   *               "getCustomer.getId"
   * @param defaultValue a value of type 'Object'
   * @return a value of type 'Object'
   */
  public static Object getValueFrom(PersistentObject aPO,
                                    String getter,
                                    Object defaultValue)
    {
    Object result = null;
    try
        {
        result = KeyPathHelper.getValueForKeyPath(aPO, getter);
        }
    catch (KeyPathHelper.KeyPathException e)
        {
        LOG.error(
            "Reflection Error: " + e.getOriginalException()
            + " in com.is.jrf.AbstractColumnSpec.getValueFrom(...)"
            + "\nObject: " + aPO
            + " getter: " + getter,
            e);
        throw new DatabaseException(e);
        }

    // Set the default (which may be null) if result is null.
    if (result == null)
        {
        if (defaultValue != null)
            {
            LOG.debug(
                "AbstractColumnSpec.getValueFrom(...) returning default "
                + " value of " + defaultValue
                + " for getter " + getter);
            }
        result = defaultValue;
        }

    return result;
    } // getValueFrom(...)



  /**
   * If Column is declared UNIQUE, make sure it doesn't already exist in the
   * table.  This is static so that the CompoundPrimaryKeyColumnSpec can use
   * it too.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -