📄 abstractdomain.java
字号:
/*
*
* 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.sql.JDBCHelperPool;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.lang.reflect.Field;
import org.apache.log4j.Category;
/**
* Subclasses of AbstractDomain are generally table-specific objects.<p>
*
* If you have questions, make sure you read the documentation. (see
* Package.html).
*
* <p> Note: The "current date/time" function will be inserted into the
* update SQL whenever a JRFConstants.CURRENT_TIMESTAMP is encountered for
* an attribute.<p>
*
* Note: For an example of how to use the executeSQLQuery() method, see the
* implementation of the findCustom(sqlString,jdbcHelper) method. <p>
*
* Note: If any of the superclass methods should never be used, you can
* override them with a method that throws an exception.<p>
*
* JDBCHelperPool is now supported (version 1.5). Find methods handle the
* pools differently than the Update (save,delete) methods. The find
* methods "manually" return the JDBCHelper to the pool (if the JDBCHelper
* is not part of a transaction). The update methods depend upon the
* endTransaction and rollback methods to return the connection to the pool.
*
*/
public abstract class AbstractDomain
implements JRFConstants
{
// These variables must be set (using their setters) from the setup()
// method of the subclass.
private DatabasePolicy i_databasePolicy = null;
private JDBCHelper i_jdbcHelper = null;
private JDBCHelperPool i_jdbcHelperPool = null;
private String i_jdbcHelperPoolName = null;
private String i_tableName = null;
private String i_tableAlias = null;
private String i_subtypeTableName = null;
private String i_subtypeTableAlias = null;
private JoinTable i_subtypeTable = null;
private ArrayList i_subtypeColumnSpecs = new ArrayList();
// These variables are set by the default constructor of this superclass.
private ArrayList i_columnSpecs = new ArrayList();
private ArrayList i_joinTables = new ArrayList();
private ColumnSpec i_primaryKeyColumnSpec = null;
private ColumnSpec i_subtypeIdentifierColumnSpec = null;
// Following are some attributes that can be turned off when looking for
// better performance when saving many objects. To turn these off, set
// them to false in the setup() method of the subclass.
private boolean i_validateBeforeSaving = true;
private boolean i_returnSavedObject = true;
private boolean i_useANSIJoins = true;
private boolean i_usePostFind = true;
private boolean i_shouldAutoCommit = false;
/** This is the index of the first row to be converted to an object and
* returned. The index numbers start at 1 (not 0) */
private int i_startingIndex = -1;
/** This is the index of the last row to be converted to an object and
* returned. The index numbers start at 1 (not 0) */
private int i_endingIndex = -1;
static final Category LOG = Category.getInstance(AbstractDomain.class.getName());
static final Map s_subtypeDomains = new HashMap();
/* =============== Constructors =============== */
/**
* The option argument affects the behavior of this framework. This was
* added for the NO_POST_FIND option, but others may be added.
*
* @param option a value of type 'int'
*/
public AbstractDomain(int option)
{
this();
if (option == NO_POST_FIND)
{
this.setUsePostFind(false);
}
}
/**
* This constructor must be executed whether implicitly or explicitly. If
* the subclass setup() method does not set the database policy, table
* name or JDBCHelper properly, then a NullPointerException is thrown with
* a helpful error message rather than having it happen deep in the stack
* where it is hard to figure out what went wrong.
*/
public AbstractDomain()
{
this.setup();
if (i_tableName == null ||
i_tableName.trim().length()==0)
{
throw new ConfigurationException(
"The table name was not set properly in the setup() method "
+ "of this class: " + this.getClass());
}
if (i_columnSpecs.size() == 0)
{
throw new ConfigurationException(
"No column specs defined in " + this.getClass());
}
// Set i_primaryKeyColumnSpec and i_subtypeIdentifierColumnSpec
this.categorizeColumnSpecs();
// Determine the appropriate Join behavior
// The default is to use ANSI joins
String joinProperty = JRFProperties.getProperty("useANSIJoins");
if (joinProperty != null &&
(joinProperty.equalsIgnoreCase("false") ||
joinProperty.equalsIgnoreCase("no")))
{
i_useANSIJoins = false;
}
this.setupSubtypeObjects();
} // AbstractDomain()
/* =============== Static Methods =============== */
/**
* Inform this supertype domain class of a subtype domain class
* @param subtypeIdentifierValue - value of the SUBTYPE_IDENTIFIER field
* @param domainClass - value of the SUBTYPE_IDENTIFIER field
*/
public static synchronized void addSubtypeDomain(Object subtypeIdentifierValue,
Class domainClass)
{
// Make sure the SUBTYPE_CODE field exists.
Field subtypeCodeField = null;
try
{
subtypeCodeField = domainClass.getField("SUBTYPE_CODE");
}
catch (Exception e)
{
String msg =
"There is no public static SUBTYPE_CODE field defined "
+ "in subtype class: " + domainClass.getName();
LOG.error(msg, e);
throw new ConfigurationException(e, msg);
}
Object codeValue = null;
try
{
codeValue = subtypeCodeField.get(domainClass);
}
catch (Exception e)
{
String msg =
"There was a problem accessing the static SUBTYPE_CODE field "
+ "in subtype class: " + domainClass.getName();
LOG.error(msg, e);
throw new ConfigurationException(e, msg);
}
// compare
s_subtypeDomains.put(codeValue, domainClass);
}
/* =============== Getters and Setters =============== */
/**
* If false, no validation will be done on this object before saving it.
* Validating a UNIQUE attribute requires doing an SQL call so this might
* improve performance in some cases.
* @see AbstractDomain#setValidateBeforeSaving
*/
public boolean getValidateBeforeSaving()
{
return i_validateBeforeSaving;
}
/** @see AbstractDomain#getValidateBeforeSaving */
public void setValidateBeforeSaving(boolean b)
{
i_validateBeforeSaving = b;
}
/**
* If true, the object is retrieved from the database and is returned to
* the user at the end of the save operation. This is important to be
* true when using an optimisitic lock, a sequenced primary key, or a
* current timestamp and you intend to make more updates to the object.
*
* @return a value of type 'boolean'
* @see AbstractDomain#setReturnSavedObject
*/
public boolean getReturnSavedObject()
{
return i_returnSavedObject;
}
/** @see AbstractDomain#getReturnSavedObject */
public void setReturnSavedObject(boolean b)
{
i_returnSavedObject = b;
}
/**
* If true, ANSI JOIN clauses will be used
* @see AbstractDomain#setUseANSIJoins
*/
public boolean useANSIJoins()
{
return i_useANSIJoins;
}
/** @see AbstractDomain#useANSIJoins */
public void setUseANSIJoins(boolean b)
{
i_useANSIJoins = b;
}
/**
* If true, the postFind() method will be called.
* @see AbstractDomain#setUsePostFind
* @return a value of type 'boolean'
*/
public boolean usePostFind()
{
return i_usePostFind;
}
/** @see AbstractDomain#usePostFind */
public void setUsePostFind(boolean b)
{
i_usePostFind = b;
}
/**
* The default is false. This value is sent to the JDBCHelper
* whenever it is set.
*/
public boolean getShouldAutoCommit()
{
return i_shouldAutoCommit;
}
public void setShouldAutoCommit(boolean b)
{
i_shouldAutoCommit = b;
}
public String getTableName()
{
return i_tableName;
}
/**
* If the name looks like this: 'Customer c', then 'Customer' will be the
* tableName and 'c' will be the tableAlias.
*
* @param s a value of type 'String'
*/
public void setTableName(String s)
{
StringTokenizer st = new StringTokenizer(s, " ");
if (st.hasMoreTokens())
{
i_tableName = st.nextToken();
}
else
{
throw new ConfigurationException("Invalid table name in " + this);
}
if (st.hasMoreTokens())
{
i_tableAlias = st.nextToken();
}
else
{
i_tableAlias = i_tableName;
}
} // setTableName(aString)
public String getSubtypeTableName()
{
return i_subtypeTableName;
}
/**
* If the name looks like this: 'Customer c', then 'Customer' will be the
* tableName and 'c' will be the tableAlias.
*
* @param s a value of type 'String'
*/
public void setSubtypeTableName(String s)
{
StringTokenizer st = new StringTokenizer(s, " ");
if (st.hasMoreTokens())
{
i_subtypeTableName = st.nextToken();
}
else
{
throw new ConfigurationException("Invalid subtype table name: '" + s + "'");
}
if (st.hasMoreTokens())
{
i_subtypeTableAlias = st.nextToken();
}
else
{
i_subtypeTableAlias = i_subtypeTableName;
}
} // setSubtypeTableName(aString)
public JoinTable getSubtypeTable()
{
return i_subtypeTable;
}
/** This is called by the constructor after setup() is called */
private void setupSubtypeObjects()
{
if (i_subtypeColumnSpecs.size() == 0)
{
return;
}
if (i_subtypeTableName == null)
{
throw new ConfigurationException("Subtype table name was not set.");
}
// Subtype table will be treated as a join table for 'select'ing.
i_subtypeTable =
new JoinTable(
i_subtypeTableName + " " + i_subtypeTableAlias,
i_primaryKeyColumnSpec.getColumnName(), // super (left) table columns
i_primaryKeyColumnSpec.getColumnName()); // sub table columns
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -