论坛首页 Java企业应用论坛

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

浏览 3153 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-03-29   最后修改:2009-03-29
关于适配器模式的介绍:
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>, [&lt;offset&gt;]</code>
     *  @deprecated This should not be exposed to the outside
     */
    int LIMIT_STYLE_POSTGRES = 1;

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

    /** <code>SET ROWCOUNT &lt;offset&gt; 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;
    }
}


论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics