关于适配器模式的介绍以及torque中的实现

关于适配器模式的介绍:
1、Java接口和Java抽象类最大的一个区别,就在于Java抽象类可以提供某些方法的部分实现,而Java接口不可以,这是Java抽象类唯一的优点吧,但这个优点非常有用。如果向一个抽象类里加入一个公共的具体方法时,那么它所有的子类都会自动拥有了这个新方法,而Java接口做不到这一点,如果向一个Java接口里加入一个新方法,所有实现这个接口的类就无法成功进行编译了,因为你必须让每一个类都要再实现这个方法。
2、由于Java语言的单继承性,所以抽象类作为类型定义工具的效能大打折扣,一个抽象类的实现只能由这个抽象类的子类给出。在这一点上,Java接口的优势就出来了,任何一个实现了一个Java接口所规定的方法的类都可以具有这个接口的类型,而一个类可以实现任意多个Java接口,从而这个类就有了多种类型。
3、从第2点不难看出,Java接口是定义混合类型的理想工具,混合类表明一个类不仅仅具有某个主类型的行为,而且具有其他的次要行为。这里也可以理解为,混合类可以有共同的业务逻辑,也可以有很多特定的业务逻辑。
4、结合1、2点中抽象类和Java接口的各自优势,最精典的设计模式就出来了:声明类型的工作仍然由Java接口承担,但是同时给出一个Java 抽象类,且实现了这个接口,而其他同属于这个抽象类型的具体类可以选择实现这个Java接口,也可以选择继承这个抽象类,也就是说在层次结构中,Java 接口在最上面,然后紧跟着抽象类。这个模式就是“缺省适配模式”。
在Java语言API中用了这种模式,而且全都遵循一定的命名规范:Abstract +接口名。
Java接口和Java抽象类的存在就是为了用于具体类的实现和继承的,如果你准备写一个具体类去继承另一个具体类的话,那你的设计就有很大问题了。Java抽象类就是为了继承而存在的,它的抽象方法就是为了强制子类必须去实现的。
具体例子:torque3.3
一、 Torque多数据库支持的实现方式:
接口类:DB.java
抽象类:AbstractDBAdapter.java
部分遵循了java语言的命名规范:Abstract +接口名
具体实现类:DBOracle.java 连接oracle
DBMSSQL.java 连接SQL Server
DBSybase.java 连接Sysbase
上述类均继承:AbstractDBAdapter.java
配置文件torque.properties
torque.database.default=yf
torque.database.yf.adapter=sqlserver
torque.dsfactory.yf.factory=org.apache.torque.dsfactory.SharedPoolDataSourceFactory
torque.dsfactory.yf.pool.maxWait = 10000
torque.dsfactory.yf.pool.maxIdle=8
torque.dsfactory.yf.pool.maxActive=20
torque.dsfactory.yf.pool.minEvictableIdleTimeMillis = 3600000
torque.dsfactory.yf.connection.driver = com.microsoft.jdbc.sqlserver.SQLServerDriver
torque.dsfactory.yf.connection.url = jdbc:sqlserver://10.7.14.14:1433;databaseName=AuthCenter
torque.dsfactory.yf.connection.user = sa
torque.dsfactory.yf.connection.password = shdxgwzf
当我们更换为数据库时,修改配置文件(红色字体部分),即可。
package org.apache.torque.adapter;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Date;

import org.apache.torque.TorqueException;
import org.apache.torque.util.Query;

/**
* <code>DB</code> defines the interface for a Torque database
* adapter. Support for new databases is added by implementing this
* interface. A couple of default settings is provided by
* subclassing <code>AbstractDBAdapter</code>. The new database adapter
* and its corresponding JDBC driver need to be registered in the service
* configuration file.
*
* <p>The Torque database adapters exist to present a uniform
* interface to database access across all available databases. Once
* the necessary adapters have been written and configured,
* transparent swapping of databases is theoretically supported with
* <i>zero code changes</i> and minimal configuration file
* modifications.
*
* All database adapters need to be thread safe, as they are instantiated
* only once fore a given configured database and may be accessed
* simultaneously from several threads.
*
* <p>Torque uses the driver class name to find the right adapter.
* A JDBC driver corresponding to your adapter must be added to the properties
* file, using the fully-qualified class name of the driver. If no driver is
* specified for your database, <code>driver.default</code> is used.
*
* <pre>
* #### MySQL MM Driver
* database.default.driver=org.gjt.mm.mysql.Driver
* database.default.url=jdbc:mysql://localhost/DATABASENAME
* </pre>
*
* @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
* @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
* @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
* @author <a href="mailto:vido@ldh.org">Augustin Vidovic</a>
* @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
* @version $Id: DB.java 476550 2006-11-18 16:08:37Z tfischer $
*/
public interface DB extends Serializable, IDMethod
{
/** Database does not support limiting result sets.
* @deprecated This should not be exposed to the outside
*/
int LIMIT_STYLE_NONE = 0;

/** <code>SELECT ... LIMIT <limit>, [<offset>]</code>
* @deprecated This should not be exposed to the outside
*/
int LIMIT_STYLE_POSTGRES = 1;

/** <code>SELECT ... LIMIT [<offset>, ] <offset></code>
* @deprecated This should not be exposed to the outside
*/
int LIMIT_STYLE_MYSQL = 2;

/** <code>SET ROWCOUNT <offset> SELECT ... SET ROWCOUNT 0</code>
* @deprecated This should not be exposed to the outside
*/
int LIMIT_STYLE_SYBASE = 3;

/** <code><pre>SELECT ... WHERE ... AND ROWNUM < <limit></pre></code>
* @deprecated This should not be exposed to the outside
*/
int LIMIT_STYLE_ORACLE = 4;

/** <code><pre>SELECT ... WHERE ... AND ROW_NUMBER() OVER() < <limit></pre></code>
* @deprecated This should not be exposed to the outside
*/
int LIMIT_STYLE_DB2 = 5;

/**
* Key for the configuration which contains database adapters.
*/
String ADAPTER_KEY = "adapter";

/**
* Key for the configuration which contains database drivers.
*/
String DRIVER_KEY = "driver";

/**
* This method is used to ignore case.
*
* @param in The string to transform to upper case.
* @return The upper case string.
*/
String toUpperCase(String in);

/**
* Returns the character used to indicate the beginning and end of
* a piece of text used in a SQL statement (generally a single
* quote).
*
* @return The text delimeter.
*/
char getStringDelimiter();

/**
* Returns the constant from the {@link
* org.apache.torque.adapter.IDMethod} interface denoting which
* type of primary key generation method this type of RDBMS uses.
*
* @return IDMethod constant
*/
String getIDMethodType();

/**
* Returns SQL used to get the most recently inserted primary key.
* Databases which have no support for this return
* <code>null</code>.
*
* @param obj Information used for key generation.
* @return The most recently inserted database key.
*/
String getIDMethodSQL(Object obj);

/**
* Locks the specified table.
*
* @param con The JDBC connection to use.
* @param table The name of the table to lock.
* @throws SQLException No Statement could be created or executed.
*/
void lockTable(Connection con, String table)
throws SQLException;

/**
* Unlocks the specified table.
*
* @param con The JDBC connection to use.
* @param table The name of the table to unlock.
* @throws SQLException No Statement could be created or executed.
*/
void unlockTable(Connection con, String table)
throws SQLException;

/**
* Modifies a SQL snippet such that its case is ignored by the database.
* The SQL snippet can be a column name (like AURHOR.NAME), an
* quoted explicit sql string (like 'abc') or any other sql value (like a
* number etc.).
*
* @param in The SQL snippet whose case to ignore.
* @return The string in a case that can be ignored.
*/
String ignoreCase(String in);

/**
* This method is used to ignore case in an ORDER BY clause.
* Usually it is the same as ignoreCase, but some databases
* (Interbase for example) does not use the same SQL in ORDER BY
* and other clauses.
*
* @param in The string whose case to ignore.
* @return The string in a case that can be ignored.
*/
String ignoreCaseInOrderBy(String in);

/**
* This method is used to check whether the database natively
* supports limiting the size of the resultset.
*
* @return True if the database natively supports limiting the
* size of the resultset.
*/
boolean supportsNativeLimit();

/**
* This method is used to check whether the database natively
* supports returning results starting at an offset position other
* than 0.
*
* @return True if the database natively supports returning
* results starting at an offset position other than 0.
*/
boolean supportsNativeOffset();

/**
* This method is used to generate the database specific query
* extension to limit the number of record returned.
*
* @param query The query to modify
* @param offset the offset Value
* @param limit the limit Value
*
* @throws TorqueException if any error occurs when building the query
*/
void generateLimits(Query query, int offset, int limit)
throws TorqueException;

/**
* Whether backslashes (\) should be escaped in explicit SQL strings.
* If true is returned, a BACKSLASH will be changed to "\\". If false
* is returned, a BACKSLASH will be left as "\".
*
* @return true if the database needs to escape backslashes
* in SqlExpressions.
*/

boolean escapeText();

/**
* This method is used to check whether the database supports
* limiting the size of the resultset.
*
* @return The limit style for the database.
* @deprecated This should not be exposed to the outside
*/
int getLimitStyle();

/**
* This method is used to format any date string.
* Database can use different default date formats.
*
* @param date the Date to format
* @return The proper date formatted String.
*/
String getDateString(Date date);

/**
* This method is used to format a boolean string.
*
* @param b the Boolean to format
* @return The proper date formatted String.
*/
String getBooleanString(Boolean b);

/**
* Whether ILIKE should be used for case insensitive like clauses.
*
* @return true if ilike should be used for case insensitive likes,
* false if ignoreCase should be applied to the compared strings.
*/
boolean useIlike();

/**
* Whether an escape clause in like should be used.
* Example : select * from AUTHOR where AUTHOR.NAME like '\_%' ESCAPE '\';
*
* @return whether the escape clause should be appended or not.
*/
boolean useEscapeClauseForLike();
}

package org.apache.torque.adapter;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;

import org.apache.torque.TorqueException;
import org.apache.torque.util.Query;

/**
* This class is the abstract base for any database adapter
* Support for new databases is added by subclassing this
* class and implementing its abstract methods, and by
* registering the new database adapter and its corresponding
* JDBC driver in the service configuration file.
*
* <p>The Torque database adapters exist to present a uniform
* interface to database access across all available databases. Once
* the necessary adapters have been written and configured,
* transparent swapping of databases is theoretically supported with
* <i>zero code changes</i> and minimal configuration file
* modifications.
*
* <p>Torque uses the driver class name to find the right adapter.
* A JDBC driver corresponding to your adapter must be added to the properties
* file, using the fully-qualified class name of the driver. If no driver is
* specified for your database, <code>driver.default</code> is used.
*
* <pre>
* #### MySQL MM Driver
* database.default.driver=org.gjt.mm.mysql.Driver
* database.default.url=jdbc:mysql://localhost/DATABASENAME
* </pre>
*
* @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
* @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
* @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
* @author <a href="mailto:vido@ldh.org">Augustin Vidovic</a>
* @version $Id: DB.java 393063 2006-04-10 20:59:16Z tfischer $
*/
public abstract class AbstractDBAdapter implements DB
{
/**
* Empty constructor.
*/
protected AbstractDBAdapter()
{
}

/**
* This method is used to ignore case.
*
* @param in The string to transform to upper case.
* @return The upper case string.
*/
public abstract String toUpperCase(String in);

/**
* Returns the character used to indicate the beginning and end of
* a piece of text used in a SQL statement (generally a single
* quote).
*
* @return The text delimeter.
*/
public char getStringDelimiter()
{
return '\'';
}

/**
* Returns the constant from the {@link
* org.apache.torque.adapter.IDMethod} interface denoting which
* type of primary key generation method this type of RDBMS uses.
*
* @return IDMethod constant
*/
public abstract String getIDMethodType();

/**
* Returns SQL used to get the most recently inserted primary key.
* Databases which have no support for this return
* <code>null</code>.
*
* @param obj Information used for key generation.
* @return The most recently inserted database key.
*/
public abstract String getIDMethodSQL(Object obj);

/**
* Locks the specified table.
*
* @param con The JDBC connection to use.
* @param table The name of the table to lock.
* @throws SQLException No Statement could be created or executed.
*/
public abstract void lockTable(Connection con, String table)
throws SQLException;

/**
* Unlocks the specified table.
*
* @param con The JDBC connection to use.
* @param table The name of the table to unlock.
* @throws SQLException No Statement could be created or executed.
*/
public abstract void unlockTable(Connection con, String table)
throws SQLException;

/**
* This method is used to ignore case.
*
* @param in The string whose case to ignore.
* @return The string in a case that can be ignored.
*/
public abstract String ignoreCase(String in);

/**
* This method is used to ignore case in an ORDER BY clause.
* Usually it is the same as ignoreCase, but some databases
* (Interbase for example) does not use the same SQL in ORDER BY
* and other clauses.
*
* @param in The string whose case to ignore.
* @return The string in a case that can be ignored.
*/
public String ignoreCaseInOrderBy(String in)
{
return ignoreCase(in);
}

/**
* This method is used to check whether the database natively
* supports limiting the size of the resultset.
*
* @return True if the database natively supports limiting the
* size of the resultset.
*/
public boolean supportsNativeLimit()
{
return false;
}

/**
* This method is used to check whether the database natively
* supports returning results starting at an offset position other
* than 0.
*
* @return True if the database natively supports returning
* results starting at an offset position other than 0.
*/
public boolean supportsNativeOffset()
{
return false;
}

/**
* This method is used to generate the database specific query
* extension to limit the number of record returned.
*
* @param query The query to modify
* @param offset the offset Value
* @param limit the limit Value
*
* @throws TorqueException if any error occurs when building the query
*/
public void generateLimits(Query query, int offset, int limit)
throws TorqueException
{
if (supportsNativeLimit())
{
query.setLimit(String.valueOf(limit));
}
}

/**
* This method is for the SqlExpression.quoteAndEscape rules. The rule is,
* any string in a SqlExpression with a BACKSLASH will either be changed to
* "\\" or left as "\". SapDB does not need the escape character.
*
* @return true if the database needs to escape text in SqlExpressions.
*/

public boolean escapeText()
{
return true;
}

/**
* This method is used to check whether the database supports
* limiting the size of the resultset.
*
* @return The limit style for the database.
* @deprecated This should not be exposed to the outside
*/
public int getLimitStyle()
{
return LIMIT_STYLE_NONE;
}

/**
* This method is used to format any date string.
* Database can use different default date formats.
*
* @param date the Date to format
* @return The proper date formatted String.
*/
public String getDateString(Date date)
{
Timestamp ts = null;
if (date instanceof Timestamp)
{
ts = (Timestamp) date;
}
else
{
ts = new Timestamp(date.getTime());
}

return ("{ts '" + ts + "'}");
}

/**
* This method is used to format a boolean string.
*
* @param b the Boolean to format
* @return The proper date formatted String.
*/
public String getBooleanString(Boolean b)
{
return (Boolean.TRUE.equals(b) ? "1" : "0");
}

/**
* Whether ILIKE should be used for case insensitive like clauses.
*
* As most databases do not use ILIKE, this implementation returns false.
* This behaviour may be overwritten in subclasses.
*
* @return true if ilike should be used for case insensitive likes,
* false if ignoreCase should be applied to the compared strings.
*/
public boolean useIlike()
{
return false;
}

/**
* Whether an escape clause in like should be used.
* Example : select * from AUTHOR where AUTHOR.NAME like '\_%' ESCAPE '\';
*
* As most databases do not need the escape clause, this implementation
* always returns <code>false</code>. This behaviour can be overwritten
* in subclasses.
*
* @return whether the escape clause should be appended or not.
*/
public boolean useEscapeClauseForLike()
{
return false;
}
}

package org.apache.torque.adapter;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.ListIterator;
import java.util.Set;

import org.apache.torque.util.Query;
import org.apache.torque.util.UniqueList;

/**
* This code should be used for an Oracle database pool.
*
* @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a>
* @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
* @author <a href="mailto:bschneider@vecna.com">Bill Schneider</a>
* @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
* @version $Id: DBOracle.java 476550 2006-11-18 16:08:37Z tfischer $
*/
public class DBOracle extends AbstractDBAdapter
{
/**
* Serial version
*/
private static final long serialVersionUID = 8966976210230241194L;

/** date format used in getDateString() */
private static final String DATE_FORMAT = "dd-MM-yyyy HH:mm:ss";

/**
* Empty constructor.
*/
protected DBOracle()
{
}

/**
* This method is used to ignore case.
*
* @param in The string to transform to upper case.
* @return The upper case string.
*/
public String toUpperCase(String in)
{
return new StringBuffer("UPPER(").append(in).append(")").toString();
}

/**
* This method is used to ignore case.
*
* @param in The string whose case to ignore.
* @return The string in a case that can be ignored.
*/
public String ignoreCase(String in)
{
return new StringBuffer("UPPER(").append(in).append(")").toString();
}

/**
* This method is used to format any date string.
*
* @param date the Date to format
* @return The date formatted String for Oracle.
*/
public String getDateString(Date date)
{
return "TO_DATE('" + new SimpleDateFormat(DATE_FORMAT).format(date)
+ "', 'DD-MM-YYYY HH24:MI:SS')";
}

/**
* @see org.apache.torque.adapter.DB#getIDMethodType()
*/
public String getIDMethodType()
{
return SEQUENCE;
}

/**
* Returns the next key from a sequence. Uses the following
* implementation:
*
* <blockquote><code><pre>
* select sequenceName.nextval from dual
* </pre></code></blockquote>
*
* @param sequenceName The name of the sequence (should be of type
* <code>String</code>).
* @return SQL to retreive the next database key.
* @see org.apache.torque.adapter.DB#getIDMethodSQL(Object)
*/
public String getIDMethodSQL(Object sequenceName)
{
return ("select " + sequenceName + ".nextval from dual");
}

/**
* Locks the specified table.
*
* @param con The JDBC connection to use.
* @param table The name of the table to lock.
* @exception SQLException No Statement could be created or executed.
*/
public void lockTable(Connection con, String table) throws SQLException
{
Statement statement = con.createStatement();

StringBuffer stmt = new StringBuffer();
stmt.append("SELECT next_id FROM ")
.append(table)
.append(" FOR UPDATE");

statement.executeQuery(stmt.toString());
}

/**
* Unlocks the specified table.
*
* @param con The JDBC connection to use.
* @param table The name of the table to unlock.
* @exception SQLException No Statement could be created or executed.
*/
public void unlockTable(Connection con, String table) throws SQLException
{
// Tables in Oracle are unlocked when a commit is issued. The
// user may have issued a commit but do it here to be sure.
con.commit();
}

/**
* This method is used to check whether the database supports
* limiting the size of the resultset.
*
* @return LIMIT_STYLE_ORACLE.
* @deprecated This should not be exposed to the outside
*/
public int getLimitStyle()
{
return DB.LIMIT_STYLE_ORACLE;
}

/**
* Return true for Oracle
* @see org.apache.torque.adapter.AbstractDBAdapter#supportsNativeLimit()
*/
public boolean supportsNativeLimit()
{
return true;
}

/**
* Return true for Oracle
* @see org.apache.torque.adapter.AbstractDBAdapter#supportsNativeOffset()
*/
public boolean supportsNativeOffset()
{
return true;
}

/**
* Build Oracle-style query with limit or offset.
* If the original SQL is in variable: query then the requlting
* SQL looks like this:
* <pre>
* SELECT B.* FROM (
* SELECT A.*, rownum as TORQUE$ROWNUM FROM (
* query
* ) A
* ) B WHERE B.TORQUE$ROWNUM > offset AND B.TORQUE$ROWNUM
* <= offset + limit
* </pre>
*
* @param query The query to modify
* @param offset the offset Value
* @param limit the limit Value
*/
public void generateLimits(Query query, int offset, int limit)
{
StringBuffer preLimit = new StringBuffer()
.append("SELECT B.* FROM ( ")
.append("SELECT A.*, rownum AS TORQUE$ROWNUM FROM ( ");

StringBuffer postLimit = new StringBuffer()
.append(" ) A ")
.append(" ) B WHERE ");

if (offset > 0)
{
postLimit.append(" B.TORQUE$ROWNUM > ")
.append(offset);

if (limit >= 0)
{
postLimit.append(" AND B.TORQUE$ROWNUM <= ")
.append(offset + limit);
}
}
else
{
postLimit.append(" B.TORQUE$ROWNUM <= ")
.append(limit);
}

query.setPreLimit(preLimit.toString());
query.setPostLimit(postLimit.toString());
query.setLimit(null);

// the query must not contain same column names or aliases.
// Find double column names and aliases and create unique aliases
// TODO: does not work for functions yet
UniqueList selectColumns = query.getSelectClause();
int replacementSuffix = 0;
Set columnNames = new HashSet();
// first pass: only remember aliased columns
// No replacements need to take place because double aliases
// are not allowed anyway
// So alias names will be retained
for (ListIterator columnIt = selectColumns.listIterator();
columnIt.hasNext();)
{
String selectColumn = (String) columnIt.next();

// check for sql function
if ((selectColumn.indexOf('(') != -1)
|| (selectColumn.indexOf(')') != -1))
{
// Sql function. Disregard.
continue;
}

// check if alias name exists
int spacePos = selectColumn.lastIndexOf(' ');
if (spacePos == -1)
{
// no alias, disregard for now
continue;
}

String aliasName = selectColumn.substring(spacePos + 1);
columnNames.add(aliasName);
}

// second pass. Regard ordinary columns only
for (ListIterator columnIt = selectColumns.listIterator();
columnIt.hasNext();)
{
String selectColumn = (String) columnIt.next();

// check for sql function
if ((selectColumn.indexOf('(') != -1)
|| (selectColumn.indexOf(')') != -1))
{
// Sql function. Disregard.
continue;
}

{
int spacePos = selectColumn.lastIndexOf(' ');
if (spacePos != -1)
{
// alias, already processed in first pass
continue;
}
}
// split into column name and tableName
String column;
{
int dotPos = selectColumn.lastIndexOf('.');
if (dotPos != -1)
{
column = selectColumn.substring(dotPos + 1);
}
else
{
column = selectColumn;
}
}
if (columnNames.contains(column))
{
// column needs to be aliased
// get replacement name
String aliasName;
do
{
aliasName = "a" + replacementSuffix;
++replacementSuffix;
}
while (columnNames.contains(aliasName));

selectColumn = selectColumn + " " + aliasName;
columnIt.set(selectColumn);
columnNames.add(aliasName);
}
else
{
columnNames.add(column);
}
}
}

/**
* This method is for the SqlExpression.quoteAndEscape rules. The rule is,
* any string in a SqlExpression with a BACKSLASH will either be changed to
* "\\" or left as "\". SapDB does not need the escape character.
*
* @return false.
*/
public boolean escapeText()
{
return false;
}

/**
* Whether an escape clause in like should be used.
* Example : select * from AUTHOR where AUTHOR.NAME like '\_%' ESCAPE '\';
*
* Oracle needs this, so this implementation always returns
* <code>true</code>.
*
* @return whether the escape clause should be appended or not.
*/
public boolean useEscapeClauseForLike()
{
return true;
}
}



二、关于torque数据源工厂类的实现方式:
接口类:DataSourceFactory.java
抽象类:AbstractDataSourceFactory.java
遵循了java语言的命名规范:Abstract +接口名
具体实现类:C3P0DataSourceFactory.java
SharedPoolDataSourceFactory.java
JndiDataSourceFactory.java
上述类均继承:AbstractDataSourceFactory.java

配置文件torque.properties
torque.dsfactory.yf.factory=org.apache.torque.dsfactory.SharedPoolDataSourceFactory
torque.dsfactory.yf.pool.maxWait = 10000
torque.dsfactory.yf.pool.maxIdle=8
torque.dsfactory.yf.pool.maxActive=20
torque.dsfactory.yf.pool.minEvictableIdleTimeMillis = 3600000
torque.dsfactory.yf.connection.driver = com.microsoft.jdbc.sqlserver.SQLServerDriver
torque.dsfactory.yf.connection.url = jdbc:sqlserver://10.7.14.14:1433;databaseName=AuthCenter
torque.dsfactory.yf.connection.user = sa
torque.dsfactory.yf.connection.password = shdxgwzf
其中C3P0DataSourceFactory.java 是我为将hibernate使用的C3P0数据库连接池作为一种可以使用的数据库连接池而实现的。当我们更换为C3P0数据库连接池,修改配置文件(红色字体部分),即可。

package org.apache.torque.dsfactory;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import javax.sql.DataSource;
import org.apache.commons.configuration.Configuration;
import org.apache.torque.TorqueException;

/**
* A factory that returns a DataSource.
*
* @author <a href="mailto:jmcnally@apache.org">John McNally</a>
* @author <a href="mailto:fischer@seitenbau.de">Thomas Fischer</a>
* @version $Id: DataSourceFactory.java 473821 2006-11-11 22:37:25Z tv $
*/
public interface DataSourceFactory
{
/**
* Key for the configuration which contains DataSourceFactories
*/
String DSFACTORY_KEY = "dsfactory";

/**
* Key for the configuration which contains the fully qualified name
* of the factory implementation class
*/
String FACTORY_KEY = "factory";

/**
* @return the <code>DataSource</code> configured by the factory.
* @throws TorqueException if the source can't be returned
*/
DataSource getDataSource() throws TorqueException;

/**
* Initialize the factory.
*
* @param configuration where to load the factory settings from
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*/
void initialize(Configuration configuration)
throws TorqueException;

/**
* Sets the current schema for the database connection
*
* @param schema The current schema name
* @deprecated use DatabaseInfo.setSchema() instead. Will be removed
* in a future version of Torque.
*/
void setSchema(String schema);

/**
* This method returns the current schema for the database connection
*
* @return The current schema name. Null means, no schema has been set.
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
* @deprecated use DatabaseInfo.getSchema() instead. Will be removed
* in a future version of Torque.
*/
String getSchema();

/**
* A hook which is called when the resources of the associated DataSource
* can be released.
* After close() is called, the other methods may not work any more
* (e.g. getDataSource() might return null).
* It is not guaranteed that this method does anything. For example,
* we do not want to close connections retrieved via JNDI, so the
* JndiDataSouurceFactory does not close these connections
*
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*/
void close()
throws TorqueException;
}

package org.apache.torque.dsfactory;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import java.util.Iterator;

import javax.sql.ConnectionPoolDataSource;
import javax.sql.DataSource;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.MappedPropertyDescriptor;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.dbcp.cpdsadapter.DriverAdapterCPDS;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.torque.Torque;
import org.apache.torque.TorqueException;
import org.apache.torque.TorqueRuntimeException;

/**
* A class that contains common functionality of the factories in this
* package.
*
* @author <a href="mailto:jmcnally@apache.org">John McNally</a>
* @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
* @version $Id: AbstractDataSourceFactory.java 473821 2006-11-11 22:37:25Z tv $
*/
public abstract class AbstractDataSourceFactory
implements DataSourceFactory
{
/** "pool" Key for the configuration */
public static final String POOL_KEY = "pool";

/** "connection" Key for the configuration */
public static final String CONNECTION_KEY = "connection";

/** "schema" Key for the configuration */
public static final String SCHEMA_KEY = "schema";

/** "defaults" Key for the configuration */
public static final String DEFAULTS_KEY = "defaults";

/** "defaults.pool" Key for the configuration */
public static final String DEFAULT_POOL_KEY
= DEFAULTS_KEY + "." + POOL_KEY;

/** "defaults.connection" Key for the configuration */
public static final String DEFAULT_CONNECTION_KEY
= DEFAULTS_KEY + "." + CONNECTION_KEY;

/** default schema name for the configuration */
public static final String DEFAULT_SCHEMA_KEY
= DEFAULTS_KEY + "." + SCHEMA_KEY;


/** The log */
private static Log log = LogFactory.getLog(AbstractDataSourceFactory.class);

/** Internal Marker for the Schema name of this database connection */
private String schema = null;

/**
* Encapsulates setting configuration properties on
* <code>DataSource</code> objects.
*
* @param property the property to read from the configuration
* @param c the configuration to read the property from
* @param ds the <code>DataSource</code> instance to write the property to
* @throws Exception if anything goes wrong
*/
protected void setProperty(String property, Configuration c, Object ds)
throws Exception
{
if (c == null || c.isEmpty())
{
return;
}

String key = property;
Class dsClass = ds.getClass();
int dot = property.indexOf('.');
try
{
if (dot > 0)
{
property = property.substring(0, dot);

MappedPropertyDescriptor mappedPD =
new MappedPropertyDescriptor(property, dsClass);
Class propertyType = mappedPD.getMappedPropertyType();
Configuration subProps = c.subset(property);
// use reflection to set properties
Iterator j = subProps.getKeys();
while (j.hasNext())
{
String subProp = (String) j.next();
String propVal = subProps.getString(subProp);
Object value = ConvertUtils.convert(propVal, propertyType);
PropertyUtils
.setMappedProperty(ds, property, subProp, value);

if (log.isDebugEnabled())
{
log.debug("setMappedProperty("
+ ds + ", "
+ property + ", "
+ subProp + ", "
+ value
+ ")");
}
}
}
else
{
if ("password".equals(key))
{
// do not log value of password
// for this, ConvertUtils.convert cannot be used
// as it also logs the value of the converted property
// so it is assumed here that the password is a String
String value = c.getString(property);
PropertyUtils.setSimpleProperty(ds, property, value);
if (log.isDebugEnabled())
{
log.debug("setSimpleProperty("
+ ds + ", "
+ property + ", "
+ " (value not logged)"
+ ")");
}
log.error(property + " == "
+ value
);
}
else
{

Class propertyType =
PropertyUtils.getPropertyType(ds, property);
Object value =
ConvertUtils.convert(c.getString(property), propertyType);
PropertyUtils.setSimpleProperty(ds, property, value);

if (log.isDebugEnabled())
{
log.debug("setSimpleProperty("
+ ds + ", "
+ property + ", "
+ value
+ ")");
}
else
{
if("user".equals(key) || "url".equals(key) || "driver".equals(key))
log.error(property + " == "
+ value
);
}

}
}
}
catch (RuntimeException e)
{
throw new TorqueRuntimeException(
"Runtime error setting property " + property, e);
}
catch (Exception e)
{
log.error(
"Property: "
+ property
+ " value: "
+ c.getString(key)
+ " is not supported by DataSource: "
+ ds.getClass().getName());
}
}

/**
* Iterate over a Configuration subset and apply all
* properties to a passed object which must contain Bean
* setter and getter
*
* @param c The configuration subset
* @param o The object to apply the properties to
* @throws TorqueException if a property set fails
*/
protected void applyConfiguration(Configuration c, Object o)
throws TorqueException
{
log.debug("applyConfiguration(" + c + ", " + o + ")");

if (c != null)
{
try
{
for (Iterator i = c.getKeys(); i.hasNext();)
{
String key = (String) i.next();
setProperty(key, c, o);
}
}
catch (Exception e)
{
log.error(e);
throw new TorqueException(e);
}
}
}

/**
* Initializes the ConnectionPoolDataSource.
*
* @param configuration where to read the settings from
* @throws TorqueException if a property set fails
* @return a configured <code>ConnectionPoolDataSource</code>
*/
protected ConnectionPoolDataSource initCPDS(Configuration configuration)
throws TorqueException
{
log.debug("Starting initCPDS");
ConnectionPoolDataSource cpds = new DriverAdapterCPDS();
Configuration c = Torque.getConfiguration();

if (c == null || c.isEmpty())
{
log.warn("Global Configuration not set,"
+ " no Default connection pool data source configured!");
}
else
{
Configuration conf = c.subset(DEFAULT_CONNECTION_KEY);
applyConfiguration(conf, cpds);
}

Configuration conf = configuration.subset(CONNECTION_KEY);
applyConfiguration(conf, cpds);

return cpds;
}

/**
* Sets the current schema for the database connection
*
* @param schema The current schema name
*/
public void setSchema(String schema)
{
this.schema = schema;
}

/**
* This method returns the current schema for the database connection
*
* @return The current schema name. Null means, no schema has been set.
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
* @deprecated use DatabaseInfo.setSchema() instead. Will be removed
* in a future version of Torque.
*/
public String getSchema()
{
return schema;
}

/**
* @return the <code>DataSource</code> configured by the factory.
* @throws TorqueException if the source can't be returned
*/
public abstract DataSource getDataSource()
throws TorqueException;

/**
* Initialize the factory.
*
* @param configuration where to load the factory settings from
* @throws TorqueException Any exceptions caught during processing will be
* rethrown wrapped into a TorqueException.
*/
public void initialize(Configuration configuration)
throws TorqueException
{
if (configuration == null)
{
throw new TorqueException(
"Torque cannot be initialized without "
+ "a valid configuration. Please check the log files "
+ "for further details.");
}

schema = configuration.getString(SCHEMA_KEY, null);

if (StringUtils.isEmpty(schema))
{
Configuration conf = Torque.getConfiguration();
schema = conf.getString(DEFAULT_SCHEMA_KEY, null);
}
}
}

package org.apache.torque.dsfactory;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import javax.sql.ConnectionPoolDataSource;
import javax.sql.DataSource;

import org.apache.commons.configuration.Configuration;

import org.apache.commons.dbcp.datasources.SharedPoolDataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.torque.Torque;
import org.apache.torque.TorqueException;

/**
* A factory that looks up the DataSource using the JDBC2 pool methods.
*
* @author <a href="mailto:jmcnally@apache.org">John McNally</a>
* @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
* @version $Id: SharedPoolDataSourceFactory.java 476550 2006-11-18 16:08:37Z tfischer $
*/
public class SharedPoolDataSourceFactory
extends AbstractDataSourceFactory
{

/** The log. */
private static Log log
= LogFactory.getLog(SharedPoolDataSourceFactory.class);

/** The wrapped <code>DataSource</code>. */
private SharedPoolDataSource ds = null;

/**
* @see org.apache.torque.dsfactory.DataSourceFactory#getDataSource
*/
public DataSource getDataSource()
{
return ds;
}

/**
* @see org.apache.torque.dsfactory.DataSourceFactory#initialize
*/
public void initialize(Configuration configuration) throws TorqueException
{
super.initialize(configuration);

ConnectionPoolDataSource cpds = initCPDS(configuration);
SharedPoolDataSource dataSource = initJdbc2Pool(configuration);
dataSource.setConnectionPoolDataSource(cpds);
this.ds = dataSource;
}

/**
* Initializes the Jdbc2PoolDataSource.
*
* @param configuration where to read the settings from
* @throws TorqueException if a property set fails
* @return a configured <code>Jdbc2PoolDataSource</code>
*/
private SharedPoolDataSource initJdbc2Pool(Configuration configuration)
throws TorqueException
{
log.debug("Starting initJdbc2Pool");
SharedPoolDataSource dataSource = new SharedPoolDataSource();
Configuration c = Torque.getConfiguration();

if (c == null || c.isEmpty())
{
log.warn("Global Configuration not set,"
+ " no Default pool data source configured!");
}
else
{
Configuration conf = c.subset(DEFAULT_POOL_KEY);
applyConfiguration(conf, dataSource);
}

Configuration conf = configuration.subset(POOL_KEY);
applyConfiguration(conf, dataSource);
return dataSource;
}


/**
* Closes the pool associated with this factory and releases it.
* @throws TorqueException if the pool cannot be closed properly
*/
public void close() throws TorqueException
{
try
{
ds.close();
}
catch (Exception e)
{
log.error("Exception caught during close()", e);
throw new TorqueException(e);
}
ds = null;
}
}

package org.apache.torque.dsfactory;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import javax.sql.ConnectionPoolDataSource;
import javax.sql.DataSource;

import org.apache.commons.configuration.Configuration;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.torque.Torque;
import org.apache.torque.TorqueException;

/**
* A factory that looks up the DataSource using the JDBC2 pool methods.
*
* @author <a href="mailto:jmcnally@apache.org">John McNally</a>
* @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
* @version $Id: C3P0DataSourceFactory.java 476550 2006-11-18 16:08:37Z tfischer $
*/
public class C3P0DataSourceFactory
extends AbstractDataSourceFactory
{

/** The log. */
private static Log log
= LogFactory.getLog(C3P0DataSourceFactory.class);

/** The wrapped <code>DataSource</code>. */
private ComboPooledDataSource ds = null;

/**
* @see org.apache.torque.dsfactory.DataSourceFactory#getDataSource
*/
public DataSource getDataSource()
{
return ds;
}

/**
* @see org.apache.torque.dsfactory.DataSourceFactory#initialize
*/
public void initialize(Configuration configuration) throws TorqueException
{
log.debug("Starting initialize ----------- ");
super.initialize(configuration);

ComboPooledDataSource dataSource = initJdbc2Pool(configuration);

this.ds = dataSource;
}

/**
* Initializes the Jdbc2PoolDataSource.
*
* @param configuration where to read the settings from
* @throws TorqueException if a property set fails
* @return a configured <code>Jdbc2PoolDataSource</code>
*/
private ComboPooledDataSource initJdbc2Pool(Configuration configuration)
throws TorqueException
{
log.debug("Starting initJdbc2Pool");
Configuration c = Torque.getConfiguration();
ComboPooledDataSource dataSource = new ComboPooledDataSource();

if (c == null || c.isEmpty())
{
log.warn("Global Configuration not set,"
+ " no Default pool data source configured!");
}
else
{
Configuration conf = c.subset(DEFAULT_POOL_KEY);

applyConfiguration(conf, dataSource);
}
//init 数据库连接
Configuration connConf = configuration.subset(CONNECTION_KEY);
applyConfiguration(connConf, dataSource);
//init 数据库连接池
Configuration conf = configuration.subset(POOL_KEY);
applyConfiguration(conf, dataSource);

return dataSource;
}


/**
* Closes the pool associated with this factory and releases it.
* @throws TorqueException if the pool cannot be closed properly
*/
public void close() throws TorqueException
{
try
{
ds.close();
}
catch (Exception e)
{
log.error("Exception caught during close()", e);
throw new TorqueException(e);
}
ds = null;
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值