CAY-2007 Refactoring SelectTranslator for better extensibility

SelectTranslator factory


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/741ad3be
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/741ad3be
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/741ad3be

Branch: refs/heads/master
Commit: 741ad3be2b8c5fb75698fabedfe95330ea3e7e78
Parents: 51ce4ce
Author: aadamchik <aadamc...@apache.org>
Authored: Sun May 10 15:09:10 2015 -0400
Committer: aadamchik <aadamc...@apache.org>
Committed: Sun May 10 15:49:55 2015 -0400

----------------------------------------------------------------------
 .../org/apache/cayenne/access/DataNode.java     |  921 ++++++-------
 .../cayenne/access/jdbc/SelectAction.java       |    7 +-
 .../select/DefaultSelectTranslatorFactory.java  |   37 +
 .../select/SelectTranslatorFactory.java         |   37 +
 .../server/DefaultDataNodeFactory.java          |    5 +
 .../configuration/server/ServerModule.java      |  305 +++--
 .../org/apache/cayenne/dba/AutoAdapter.java     |  432 ++++---
 .../java/org/apache/cayenne/dba/DbAdapter.java  |  360 +++---
 .../org/apache/cayenne/dba/JdbcAdapter.java     | 1212 +++++++++---------
 .../dba/frontbase/FrontBaseActionBuilder.java   |   45 -
 .../cayenne/dba/frontbase/FrontBaseAdapter.java |  327 +++--
 .../cayenne/dba/hsqldb/HSQLDBAdapter.java       |  339 ++---
 .../cayenne/dba/hsqldb/HSQLSelectAction.java    |    6 -
 .../cayenne/dba/ingres/IngresAdapter.java       |  206 +--
 .../cayenne/dba/ingres/IngresSelectAction.java  |   20 +-
 .../apache/cayenne/dba/mysql/MySQLAdapter.java  |  671 +++++-----
 .../cayenne/dba/mysql/MySQLSelectAction.java    |    6 -
 .../dba/openbase/OpenBaseActionBuilder.java     |   48 -
 .../cayenne/dba/openbase/OpenBaseAdapter.java   |  523 ++++----
 .../dba/oracle/Oracle8ActionBuilder.java        |   54 +-
 .../cayenne/dba/oracle/Oracle8Adapter.java      |  135 +-
 .../cayenne/dba/oracle/Oracle8SelectAction.java |   38 -
 .../cayenne/dba/oracle/OracleAdapter.java       |  568 ++++----
 .../cayenne/dba/oracle/OracleSelectAction.java  |    6 -
 .../cayenne/dba/postgres/PostgresAdapter.java   |  421 +++---
 .../dba/postgres/PostgresSelectAction.java      |    6 -
 .../dba/sqlserver/SQLServerActionBuilder.java   |   52 +-
 .../cayenne/dba/sqlserver/SQLServerAdapter.java |  130 +-
 .../dba/sqlserver/SQLServerSelectAction.java    |   37 -
 .../server/DataDomainProviderTest.java          |    3 +
 .../cayenne/unit/di/server/SchemaBuilder.java   |    2 +
 .../di/server/ServerCaseDataNodeFactory.java    |   57 +-
 32 files changed, 3454 insertions(+), 3562 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/access/DataNode.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/access/DataNode.java 
b/cayenne-server/src/main/java/org/apache/cayenne/access/DataNode.java
index 4d1b5f0..84c72f5 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataNode.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DataNode.java
@@ -41,6 +41,8 @@ import org.apache.cayenne.access.jdbc.reader.RowReader;
 import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
 import org.apache.cayenne.access.translator.batch.BatchTranslator;
 import org.apache.cayenne.access.translator.batch.BatchTranslatorFactory;
+import org.apache.cayenne.access.translator.select.SelectTranslator;
+import org.apache.cayenne.access.translator.select.SelectTranslatorFactory;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.dba.JdbcAdapter;
 import org.apache.cayenne.log.JdbcEventLogger;
@@ -51,6 +53,7 @@ import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.query.BatchQuery;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.QueryMetadata;
+import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.tx.BaseTransaction;
 import org.apache.cayenne.tx.Transaction;
 import org.apache.cayenne.util.ToStringBuilder;
@@ -62,454 +65,462 @@ import org.apache.cayenne.util.ToStringBuilder;
  */
 public class DataNode implements QueryEngine {
 
-    protected String name;
-    protected DataSource dataSource;
-    protected DbAdapter adapter;
-    protected String dataSourceLocation;
-    protected String dataSourceFactory;
-    protected String schemaUpdateStrategyName;
-    protected EntityResolver entityResolver;
-    protected SchemaUpdateStrategy schemaUpdateStrategy;
-    protected Map<String, DataMap> dataMaps;
-
-    private JdbcEventLogger jdbcEventLogger;
-    private RowReaderFactory rowReaderFactory;
-    private BatchTranslatorFactory batchTranslatorFactory;
-    private SQLTemplateProcessor sqlTemplateProcessor;
-
-    TransactionDataSource readThroughDataSource;
-
-    /**
-     * Creates a new unnamed DataNode.
-     */
-    public DataNode() {
-        this(null);
-    }
-
-    /**
-     * Creates a new DataNode, assigning it a name.
-     */
-    public DataNode(String name) {
-
-        this.name = name;
-        this.dataMaps = new HashMap<String, DataMap>();
-        this.readThroughDataSource = new TransactionDataSource();
-
-        // make sure logger is not null
-        this.jdbcEventLogger = NoopJdbcEventLogger.getInstance();
-    }
-
-    /**
-     * @since 3.0
-     */
-    public String getSchemaUpdateStrategyName() {
-        if (schemaUpdateStrategyName == null) {
-            schemaUpdateStrategyName = 
SkipSchemaUpdateStrategy.class.getName();
-        }
-        return schemaUpdateStrategyName;
-    }
-
-    /**
-     * @since 3.0
-     */
-    public void setSchemaUpdateStrategyName(String schemaUpdateStrategyName) {
-        this.schemaUpdateStrategyName = schemaUpdateStrategyName;
-    }
-
-    /**
-     * @since 3.0
-     */
-    public SchemaUpdateStrategy getSchemaUpdateStrategy() {
-        return schemaUpdateStrategy;
-    }
-
-    /**
-     * @since 3.0
-     */
-    public void setSchemaUpdateStrategy(SchemaUpdateStrategy 
schemaUpdateStrategy) {
-        this.schemaUpdateStrategy = schemaUpdateStrategy;
-    }
-
-    /**
-     * @since 3.1
-     */
-    public JdbcEventLogger getJdbcEventLogger() {
-        if (jdbcEventLogger == null && adapter instanceof JdbcAdapter) {
-            jdbcEventLogger = ((JdbcAdapter) adapter).getJdbcEventLogger();
-        }
-
-        return jdbcEventLogger;
-    }
-
-    /**
-     * @since 3.1
-     */
-    public void setJdbcEventLogger(JdbcEventLogger logger) {
-        this.jdbcEventLogger = logger;
-    }
-
-    /**
-     * Returns node name. Name is used to uniquely identify DataNode within a
-     * DataDomain.
-     */
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * Returns a location of DataSource of this node. Depending on how this 
node
-     * was created, location is either a JNDI name, or a location of node XML
-     * file, etc.
-     */
-    public String getDataSourceLocation() {
-        return dataSourceLocation;
-    }
-
-    public void setDataSourceLocation(String dataSourceLocation) {
-        this.dataSourceLocation = dataSourceLocation;
-    }
-
-    /**
-     * Returns a name of DataSourceFactory class for this node.
-     */
-    public String getDataSourceFactory() {
-        return dataSourceFactory;
-    }
-
-    public void setDataSourceFactory(String dataSourceFactory) {
-        this.dataSourceFactory = dataSourceFactory;
-    }
-
-    /**
-     * Returns an unmodifiable collection of DataMaps handled by this DataNode.
-     */
-    public Collection<DataMap> getDataMaps() {
-        return Collections.unmodifiableCollection(dataMaps.values());
-    }
-
-    /**
-     * Returns datamap with specified name, null if none present
-     */
-    public DataMap getDataMap(String name) {
-        return dataMaps.get(name);
-    }
-
-    public void setDataMaps(Collection<DataMap> dataMaps) {
-        for (DataMap map : dataMaps) {
-            this.dataMaps.put(map.getName(), map);
-        }
-    }
-
-    /**
-     * Adds a DataMap to be handled by this node.
-     */
-    public void addDataMap(DataMap map) {
-        this.dataMaps.put(map.getName(), map);
-    }
-
-    public void removeDataMap(DataMap map) {
-        removeDataMap(map.getName());
-    }
-
-    public void removeDataMap(String mapName) {
-        dataMaps.remove(mapName);
-    }
-
-    /**
-     * Returns DataSource used by this DataNode to obtain connections.
-     */
-    public DataSource getDataSource() {
-        return dataSource != null ? readThroughDataSource : null;
-    }
-
-    public void setDataSource(DataSource dataSource) {
-        this.dataSource = dataSource;
-    }
-
-    /**
-     * Returns DbAdapter object. This is a plugin that handles RDBMS
-     * vendor-specific features.
-     */
-    public DbAdapter getAdapter() {
-        return adapter;
-    }
-
-    public void setAdapter(DbAdapter adapter) {
-        this.adapter = adapter;
-    }
-
-    /**
-     * Returns a DataNode that should handle queries for all DataMap 
components.
-     * 
-     * @since 1.1
-     */
-    public DataNode lookupDataNode(DataMap dataMap) {
-        // we don't know any better than to return ourselves...
-        return this;
-    }
-
-    /**
-     * Runs queries using Connection obtained from internal DataSource.
-     * 
-     * @since 1.1
-     */
-    @Override
-    public void performQueries(Collection<? extends Query> queries, 
OperationObserver callback) {
-
-        int listSize = queries.size();
-        if (listSize == 0) {
-            return;
-        }
-
-        if (callback.isIteratedResult() && listSize > 1) {
-            throw new CayenneRuntimeException("Iterated queries are not 
allowed in a batch. Batch size: " + listSize);
-        }
-
-        // do this meaningless inexpensive operation to trigger AutoAdapter 
lazy
-        // initialization before opening a connection. Otherwise we may end up
-        // with two
-        // connections open simultaneously, possibly hitting connection pool
-        // upper limit.
-        getAdapter().getExtendedTypes();
-
-        Connection connection = null;
-
-        try {
-            connection = this.getDataSource().getConnection();
-        } catch (Exception globalEx) {
-            getJdbcEventLogger().logQueryError(globalEx);
-
-            Transaction transaction = BaseTransaction.getThreadTransaction();
-            if (transaction != null) {
-                transaction.setRollbackOnly();
-            }
-
-            callback.nextGlobalException(globalEx);
-            return;
-        }
-
-        try {
-            DataNodeQueryAction queryRunner = new DataNodeQueryAction(this, 
callback);
-
-            for (Query nextQuery : queries) {
-
-                // catch exceptions for each individual query
-                try {
-                    queryRunner.runQuery(connection, nextQuery);
-                } catch (Exception queryEx) {
-                    getJdbcEventLogger().logQueryError(queryEx);
-
-                    // notify consumer of the exception,
-                    // stop running further queries
-                    callback.nextQueryException(nextQuery, queryEx);
-
-                    Transaction transaction = 
BaseTransaction.getThreadTransaction();
-                    if (transaction != null) {
-                        transaction.setRollbackOnly();
-                    }
-                    break;
-                }
-            }
-        } finally {
-            try {
-                connection.close();
-            } catch (SQLException e) {
-                // ignore closing exceptions...
-            }
-        }
-    }
-
-    /**
-     * Returns EntityResolver that handles DataMaps of this node.
-     */
-    @Override
-    public EntityResolver getEntityResolver() {
-        return entityResolver;
-    }
-
-    /**
-     * Sets EntityResolver. DataNode relies on externally set EntityResolver, 
so
-     * if the node is created outside of DataDomain stack, a valid
-     * EntityResolver must be provided explicitly.
-     * 
-     * @since 1.1
-     */
-    public void setEntityResolver(EntityResolver entityResolver) {
-        this.entityResolver = entityResolver;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this).append("name", getName()).toString();
-    }
-
-    // a read-through DataSource that ensures returning the same connection
-    // within
-    // transaction.
-    final class TransactionDataSource implements DataSource {
-
-        final String CONNECTION_RESOURCE_PREFIX = "DataNode.Connection.";
-
-        public Connection getConnection() throws SQLException {
-            if (schemaUpdateStrategy != null) {
-                schemaUpdateStrategy.updateSchema(DataNode.this);
-            }
-            Transaction t = BaseTransaction.getThreadTransaction();
-
-            if (t != null) {
-                String key = CONNECTION_RESOURCE_PREFIX + name;
-                Connection c = t.getConnection(key);
-
-                if (c == null || c.isClosed()) {
-                    c = dataSource.getConnection();
-                    t.addConnection(key, c);
-                }
-
-                // wrap transaction-attached connections in a decorator that
-                // prevents them
-                // from being closed by callers, as transaction should take 
care
-                // of them
-                // on commit or rollback.
-                return new TransactionConnectionDecorator(c);
-            }
-
-            return dataSource.getConnection();
-        }
-
-        public Connection getConnection(String username, String password) 
throws SQLException {
-            if (schemaUpdateStrategy != null) {
-                schemaUpdateStrategy.updateSchema(DataNode.this);
-            }
-            Transaction t = BaseTransaction.getThreadTransaction();
-            if (t != null) {
-                String key = CONNECTION_RESOURCE_PREFIX + name;
-                Connection c = t.getConnection(key);
-
-                if (c == null || c.isClosed()) {
-                    c = dataSource.getConnection();
-                    t.addConnection(key, c);
-                }
-
-                // wrap transaction-attached connections in a decorator that
-                // prevents them
-                // from being closed by callers, as transaction should take 
care
-                // of them
-                // on commit or rollback.
-                return new TransactionConnectionDecorator(c);
-            }
-
-            return dataSource.getConnection(username, password);
-        }
-
-        public int getLoginTimeout() throws SQLException {
-            return dataSource.getLoginTimeout();
-        }
-
-        public PrintWriter getLogWriter() throws SQLException {
-            return dataSource.getLogWriter();
-        }
-
-        public void setLoginTimeout(int seconds) throws SQLException {
-            dataSource.setLoginTimeout(seconds);
-        }
-
-        public void setLogWriter(PrintWriter out) throws SQLException {
-            dataSource.setLogWriter(out);
-        }
-
-        /**
-         * @since 3.0
-         */
-        // JDBC 4 compatibility under Java 1.5
-        public boolean isWrapperFor(Class<?> iface) throws SQLException {
-            return iface.isAssignableFrom(dataSource.getClass());
-        }
-
-        /**
-         * @since 3.0
-         */
-        // JDBC 4 compatibility under Java 1.5
-        public <T> T unwrap(Class<T> iface) throws SQLException {
-            try {
-                return iface.cast(dataSource);
-            } catch (ClassCastException e) {
-                throw new SQLException("Not a DataSource: " + e.getMessage());
-            }
-        }
-
-        /**
-         * @since 3.1
-         * 
-         *        JDBC 4.1 compatibility under Java 1.5
-         */
-        public Logger getParentLogger() throws SQLFeatureNotSupportedException 
{
-            // don't throw SQLFeatureNotSupported - this will break JDK 1.5
-            // runtime
-            throw new UnsupportedOperationException();
-        }
-    }
-
-    /**
-     * Creates a {@link RowReader} using internal {@link RowReaderFactory}.
-     * 
-     * @since 4.0
-     */
-    public RowReader<?> rowReader(RowDescriptor descriptor, QueryMetadata 
queryMetadata) {
-        return rowReader(descriptor, queryMetadata, Collections.<ObjAttribute, 
ColumnDescriptor> emptyMap());
-    }
-
-    /**
-     * Creates a {@link RowReader} using internal {@link RowReaderFactory}.
-     * 
-     * @since 4.0
-     */
-    public RowReader<?> rowReader(RowDescriptor descriptor, QueryMetadata 
queryMetadata,
-            Map<ObjAttribute, ColumnDescriptor> attributeOverrides) {
-        return rowReaderFactory.rowReader(descriptor, queryMetadata, 
getAdapter(), attributeOverrides);
-    }
-    
-    /**
-     * @since 4.0
-     */
-    public BatchTranslator batchTranslator(BatchQuery query, String 
trimFunction) {
-        return batchTranslatorFactory.translator(query, getAdapter(), 
trimFunction);
-    }
-
-    /**
-     * @since 4.0
-     */
-    public RowReaderFactory getRowReaderFactory() {
-        return rowReaderFactory;
-    }
-
-    /**
-     * @since 4.0
-     */
-    public void setRowReaderFactory(RowReaderFactory rowReaderFactory) {
-        this.rowReaderFactory = rowReaderFactory;
-    }
-
-    /**
-     * @since 4.0
-     */
-    public BatchTranslatorFactory getBatchTranslatorFactory() {
-        return batchTranslatorFactory;
-    }
-
-    /**
-     * @since 4.0
-     */
-    public void setBatchTranslatorFactory(BatchTranslatorFactory 
batchTranslatorFactory) {
-        this.batchTranslatorFactory = batchTranslatorFactory;
-    }
-
-    /**
-     * @since 4.0
-     */
+       protected String name;
+       protected DataSource dataSource;
+       protected DbAdapter adapter;
+       protected String dataSourceLocation;
+       protected String dataSourceFactory;
+       protected String schemaUpdateStrategyName;
+       protected EntityResolver entityResolver;
+       protected SchemaUpdateStrategy schemaUpdateStrategy;
+       protected Map<String, DataMap> dataMaps;
+
+       private JdbcEventLogger jdbcEventLogger;
+       private RowReaderFactory rowReaderFactory;
+       private BatchTranslatorFactory batchTranslatorFactory;
+       private SelectTranslatorFactory selectTranslatorFactory;
+       private SQLTemplateProcessor sqlTemplateProcessor;
+
+       TransactionDataSource readThroughDataSource;
+
+       /**
+        * Creates a new unnamed DataNode.
+        */
+       public DataNode() {
+               this(null);
+       }
+
+       /**
+        * Creates a new DataNode, assigning it a name.
+        */
+       public DataNode(String name) {
+
+               this.name = name;
+               this.dataMaps = new HashMap<String, DataMap>();
+               this.readThroughDataSource = new TransactionDataSource();
+
+               // make sure logger is not null
+               this.jdbcEventLogger = NoopJdbcEventLogger.getInstance();
+       }
+
+       /**
+        * @since 3.0
+        */
+       public String getSchemaUpdateStrategyName() {
+               if (schemaUpdateStrategyName == null) {
+                       schemaUpdateStrategyName = 
SkipSchemaUpdateStrategy.class.getName();
+               }
+               return schemaUpdateStrategyName;
+       }
+
+       /**
+        * @since 3.0
+        */
+       public void setSchemaUpdateStrategyName(String 
schemaUpdateStrategyName) {
+               this.schemaUpdateStrategyName = schemaUpdateStrategyName;
+       }
+
+       /**
+        * @since 3.0
+        */
+       public SchemaUpdateStrategy getSchemaUpdateStrategy() {
+               return schemaUpdateStrategy;
+       }
+
+       /**
+        * @since 3.0
+        */
+       public void setSchemaUpdateStrategy(SchemaUpdateStrategy 
schemaUpdateStrategy) {
+               this.schemaUpdateStrategy = schemaUpdateStrategy;
+       }
+
+       /**
+        * @since 3.1
+        */
+       public JdbcEventLogger getJdbcEventLogger() {
+               if (jdbcEventLogger == null && adapter instanceof JdbcAdapter) {
+                       jdbcEventLogger = ((JdbcAdapter) 
adapter).getJdbcEventLogger();
+               }
+
+               return jdbcEventLogger;
+       }
+
+       /**
+        * @since 3.1
+        */
+       public void setJdbcEventLogger(JdbcEventLogger logger) {
+               this.jdbcEventLogger = logger;
+       }
+
+       /**
+        * Returns node name. Name is used to uniquely identify DataNode within 
a
+        * DataDomain.
+        */
+       public String getName() {
+               return name;
+       }
+
+       public void setName(String name) {
+               this.name = name;
+       }
+
+       /**
+        * Returns a location of DataSource of this node. Depending on how this 
node
+        * was created, location is either a JNDI name, or a location of node 
XML
+        * file, etc.
+        */
+       public String getDataSourceLocation() {
+               return dataSourceLocation;
+       }
+
+       public void setDataSourceLocation(String dataSourceLocation) {
+               this.dataSourceLocation = dataSourceLocation;
+       }
+
+       /**
+        * Returns a name of DataSourceFactory class for this node.
+        */
+       public String getDataSourceFactory() {
+               return dataSourceFactory;
+       }
+
+       public void setDataSourceFactory(String dataSourceFactory) {
+               this.dataSourceFactory = dataSourceFactory;
+       }
+
+       /**
+        * Returns an unmodifiable collection of DataMaps handled by this 
DataNode.
+        */
+       public Collection<DataMap> getDataMaps() {
+               return Collections.unmodifiableCollection(dataMaps.values());
+       }
+
+       /**
+        * Returns datamap with specified name, null if none present
+        */
+       public DataMap getDataMap(String name) {
+               return dataMaps.get(name);
+       }
+
+       public void setDataMaps(Collection<DataMap> dataMaps) {
+               for (DataMap map : dataMaps) {
+                       this.dataMaps.put(map.getName(), map);
+               }
+       }
+
+       /**
+        * Adds a DataMap to be handled by this node.
+        */
+       public void addDataMap(DataMap map) {
+               this.dataMaps.put(map.getName(), map);
+       }
+
+       public void removeDataMap(DataMap map) {
+               removeDataMap(map.getName());
+       }
+
+       public void removeDataMap(String mapName) {
+               dataMaps.remove(mapName);
+       }
+
+       /**
+        * Returns DataSource used by this DataNode to obtain connections.
+        */
+       public DataSource getDataSource() {
+               return dataSource != null ? readThroughDataSource : null;
+       }
+
+       public void setDataSource(DataSource dataSource) {
+               this.dataSource = dataSource;
+       }
+
+       /**
+        * Returns DbAdapter object. This is a plugin that handles RDBMS
+        * vendor-specific features.
+        */
+       public DbAdapter getAdapter() {
+               return adapter;
+       }
+
+       public void setAdapter(DbAdapter adapter) {
+               this.adapter = adapter;
+       }
+
+       /**
+        * Returns a DataNode that should handle queries for all DataMap 
components.
+        * 
+        * @since 1.1
+        */
+       public DataNode lookupDataNode(DataMap dataMap) {
+               // we don't know any better than to return ourselves...
+               return this;
+       }
+
+       /**
+        * Runs queries using Connection obtained from internal DataSource.
+        * 
+        * @since 1.1
+        */
+       @Override
+       public void performQueries(Collection<? extends Query> queries, 
OperationObserver callback) {
+
+               int listSize = queries.size();
+               if (listSize == 0) {
+                       return;
+               }
+
+               if (callback.isIteratedResult() && listSize > 1) {
+                       throw new CayenneRuntimeException("Iterated queries are 
not allowed in a batch. Batch size: " + listSize);
+               }
+
+               // do this meaningless inexpensive operation to trigger 
AutoAdapter lazy
+               // initialization before opening a connection. Otherwise we may 
end up
+               // with two
+               // connections open simultaneously, possibly hitting connection 
pool
+               // upper limit.
+               getAdapter().getExtendedTypes();
+
+               Connection connection = null;
+
+               try {
+                       connection = this.getDataSource().getConnection();
+               } catch (Exception globalEx) {
+                       getJdbcEventLogger().logQueryError(globalEx);
+
+                       Transaction transaction = 
BaseTransaction.getThreadTransaction();
+                       if (transaction != null) {
+                               transaction.setRollbackOnly();
+                       }
+
+                       callback.nextGlobalException(globalEx);
+                       return;
+               }
+
+               try {
+                       DataNodeQueryAction queryRunner = new 
DataNodeQueryAction(this, callback);
+
+                       for (Query nextQuery : queries) {
+
+                               // catch exceptions for each individual query
+                               try {
+                                       queryRunner.runQuery(connection, 
nextQuery);
+                               } catch (Exception queryEx) {
+                                       
getJdbcEventLogger().logQueryError(queryEx);
+
+                                       // notify consumer of the exception,
+                                       // stop running further queries
+                                       callback.nextQueryException(nextQuery, 
queryEx);
+
+                                       Transaction transaction = 
BaseTransaction.getThreadTransaction();
+                                       if (transaction != null) {
+                                               transaction.setRollbackOnly();
+                                       }
+                                       break;
+                               }
+                       }
+               } finally {
+                       try {
+                               connection.close();
+                       } catch (SQLException e) {
+                               // ignore closing exceptions...
+                       }
+               }
+       }
+
+       /**
+        * Returns EntityResolver that handles DataMaps of this node.
+        */
+       @Override
+       public EntityResolver getEntityResolver() {
+               return entityResolver;
+       }
+
+       /**
+        * Sets EntityResolver. DataNode relies on externally set 
EntityResolver, so
+        * if the node is created outside of DataDomain stack, a valid
+        * EntityResolver must be provided explicitly.
+        * 
+        * @since 1.1
+        */
+       public void setEntityResolver(EntityResolver entityResolver) {
+               this.entityResolver = entityResolver;
+       }
+
+       @Override
+       public String toString() {
+               return new ToStringBuilder(this).append("name", 
getName()).toString();
+       }
+
+       // a read-through DataSource that ensures returning the same connection
+       // within
+       // transaction.
+       final class TransactionDataSource implements DataSource {
+
+               final String CONNECTION_RESOURCE_PREFIX = 
"DataNode.Connection.";
+
+               public Connection getConnection() throws SQLException {
+                       if (schemaUpdateStrategy != null) {
+                               
schemaUpdateStrategy.updateSchema(DataNode.this);
+                       }
+                       Transaction t = BaseTransaction.getThreadTransaction();
+
+                       if (t != null) {
+                               String key = CONNECTION_RESOURCE_PREFIX + name;
+                               Connection c = t.getConnection(key);
+
+                               if (c == null || c.isClosed()) {
+                                       c = dataSource.getConnection();
+                                       t.addConnection(key, c);
+                               }
+
+                               // wrap transaction-attached connections in a 
decorator that
+                               // prevents them
+                               // from being closed by callers, as transaction 
should take care
+                               // of them
+                               // on commit or rollback.
+                               return new TransactionConnectionDecorator(c);
+                       }
+
+                       return dataSource.getConnection();
+               }
+
+               public Connection getConnection(String username, String 
password) throws SQLException {
+                       if (schemaUpdateStrategy != null) {
+                               
schemaUpdateStrategy.updateSchema(DataNode.this);
+                       }
+                       Transaction t = BaseTransaction.getThreadTransaction();
+                       if (t != null) {
+                               String key = CONNECTION_RESOURCE_PREFIX + name;
+                               Connection c = t.getConnection(key);
+
+                               if (c == null || c.isClosed()) {
+                                       c = dataSource.getConnection();
+                                       t.addConnection(key, c);
+                               }
+
+                               // wrap transaction-attached connections in a 
decorator that
+                               // prevents them
+                               // from being closed by callers, as transaction 
should take care
+                               // of them
+                               // on commit or rollback.
+                               return new TransactionConnectionDecorator(c);
+                       }
+
+                       return dataSource.getConnection(username, password);
+               }
+
+               public int getLoginTimeout() throws SQLException {
+                       return dataSource.getLoginTimeout();
+               }
+
+               public PrintWriter getLogWriter() throws SQLException {
+                       return dataSource.getLogWriter();
+               }
+
+               public void setLoginTimeout(int seconds) throws SQLException {
+                       dataSource.setLoginTimeout(seconds);
+               }
+
+               public void setLogWriter(PrintWriter out) throws SQLException {
+                       dataSource.setLogWriter(out);
+               }
+
+               /**
+                * @since 3.0
+                */
+               // JDBC 4 compatibility under Java 1.5
+               public boolean isWrapperFor(Class<?> iface) throws SQLException 
{
+                       return iface.isAssignableFrom(dataSource.getClass());
+               }
+
+               /**
+                * @since 3.0
+                */
+               // JDBC 4 compatibility under Java 1.5
+               public <T> T unwrap(Class<T> iface) throws SQLException {
+                       try {
+                               return iface.cast(dataSource);
+                       } catch (ClassCastException e) {
+                               throw new SQLException("Not a DataSource: " + 
e.getMessage());
+                       }
+               }
+
+               /**
+                * @since 3.1
+                * 
+                *        JDBC 4.1 compatibility under Java 1.5
+                */
+               public Logger getParentLogger() throws 
SQLFeatureNotSupportedException {
+                       // don't throw SQLFeatureNotSupported - this will break 
JDK 1.5
+                       // runtime
+                       throw new UnsupportedOperationException();
+               }
+       }
+
+       /**
+        * Creates a {@link RowReader} using internal {@link RowReaderFactory}.
+        * 
+        * @since 4.0
+        */
+       public RowReader<?> rowReader(RowDescriptor descriptor, QueryMetadata 
queryMetadata) {
+               return rowReader(descriptor, queryMetadata, 
Collections.<ObjAttribute, ColumnDescriptor> emptyMap());
+       }
+
+       /**
+        * Creates a {@link RowReader} using internal {@link RowReaderFactory}.
+        * 
+        * @since 4.0
+        */
+       public RowReader<?> rowReader(RowDescriptor descriptor, QueryMetadata 
queryMetadata,
+                       Map<ObjAttribute, ColumnDescriptor> attributeOverrides) 
{
+               return rowReaderFactory.rowReader(descriptor, queryMetadata, 
getAdapter(), attributeOverrides);
+       }
+
+       /**
+        * @since 4.0
+        */
+       public BatchTranslator batchTranslator(BatchQuery query, String 
trimFunction) {
+               return batchTranslatorFactory.translator(query, getAdapter(), 
trimFunction);
+       }
+
+       /**
+        * @since 4.0
+        */
+       public SelectTranslator selectTranslator(SelectQuery<?> query) {
+               return selectTranslatorFactory.translator(query, getAdapter(), 
getEntityResolver());
+       }
+
+       /**
+        * @since 4.0
+        */
+       public RowReaderFactory getRowReaderFactory() {
+               return rowReaderFactory;
+       }
+
+       /**
+        * @since 4.0
+        */
+       public void setRowReaderFactory(RowReaderFactory rowReaderFactory) {
+               this.rowReaderFactory = rowReaderFactory;
+       }
+
+       /**
+        * @since 4.0
+        */
+       public BatchTranslatorFactory getBatchTranslatorFactory() {
+               return batchTranslatorFactory;
+       }
+
+       /**
+        * @since 4.0
+        */
+       public void setBatchTranslatorFactory(BatchTranslatorFactory 
batchTranslatorFactory) {
+               this.batchTranslatorFactory = batchTranslatorFactory;
+       }
+
+       /**
+        * @since 4.0
+        */
        public SQLTemplateProcessor getSqlTemplateProcessor() {
                return sqlTemplateProcessor;
        }
@@ -520,4 +531,18 @@ public class DataNode implements QueryEngine {
        public void setSqlTemplateProcessor(SQLTemplateProcessor 
sqlTemplateProcessor) {
                this.sqlTemplateProcessor = sqlTemplateProcessor;
        }
+
+       /**
+        * @since 4.0
+        */
+       public SelectTranslatorFactory getSelectTranslatorFactory() {
+               return selectTranslatorFactory;
+       }
+
+       /**
+        * @since 4.0
+        */
+       public void setSelectTranslatorFactory(SelectTranslatorFactory 
selectTranslatorFactory) {
+               this.selectTranslatorFactory = selectTranslatorFactory;
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java 
b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java
index 00785c9..f5ff8d1 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java
@@ -31,7 +31,6 @@ import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.access.OperationObserver;
 import org.apache.cayenne.access.jdbc.reader.RowReader;
 import org.apache.cayenne.access.translator.ParameterBinding;
-import org.apache.cayenne.access.translator.select.DefaultSelectTranslator;
 import org.apache.cayenne.access.translator.select.SelectTranslator;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.log.JdbcEventLogger;
@@ -82,10 +81,6 @@ public class SelectAction extends BaseSQLAction {
                this.queryMetadata = 
query.getMetaData(dataNode.getEntityResolver());
        }
 
-       protected SelectTranslator createTranslator() {
-               return new DefaultSelectTranslator(query, 
dataNode.getAdapter(), dataNode.getEntityResolver());
-       }
-
        @SuppressWarnings({ "unchecked", "rawtypes", "resource" })
        @Override
        public void performAction(Connection connection, OperationObserver 
observer) throws SQLException, Exception {
@@ -93,7 +88,7 @@ public class SelectAction extends BaseSQLAction {
                final long t1 = System.currentTimeMillis();
 
                JdbcEventLogger logger = dataNode.getJdbcEventLogger();
-               SelectTranslator translator = createTranslator();
+               SelectTranslator translator = dataNode.selectTranslator(query);
                final String sql = translator.getSql();
 
                ParameterBinding[] bindings = translator.getBindings();

http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslatorFactory.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslatorFactory.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslatorFactory.java
new file mode 100644
index 0000000..eec4e1c
--- /dev/null
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslatorFactory.java
@@ -0,0 +1,37 @@
+/*****************************************************************
+ *   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.
+ ****************************************************************/
+package org.apache.cayenne.access.translator.select;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.query.SelectQuery;
+
+/**
+ * A {@link SelectTranslator} factory that delegates translator creation to
+ * DbAdapter.
+ * 
+ * @since 4.0
+ */
+public class DefaultSelectTranslatorFactory implements SelectTranslatorFactory 
{
+
+       @Override
+       public SelectTranslator translator(SelectQuery<?> query, DbAdapter 
adapter, EntityResolver entityResolver) {
+               return adapter.getSelectTranslator(query, entityResolver);
+       }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/SelectTranslatorFactory.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/SelectTranslatorFactory.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/SelectTranslatorFactory.java
new file mode 100644
index 0000000..4c306b5
--- /dev/null
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/SelectTranslatorFactory.java
@@ -0,0 +1,37 @@
+/*****************************************************************
+ *   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.
+ ****************************************************************/
+package org.apache.cayenne.access.translator.select;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.query.SelectQuery;
+
+/**
+ * A factory for {@link SelectTranslator} objects.
+ * 
+ * @since 4.0
+ */
+public interface SelectTranslatorFactory {
+
+       /**
+        * Creates a proper translator for a BatchQuery
+        */
+       SelectTranslator translator(SelectQuery<?> query, DbAdapter adapter, 
EntityResolver entityResolver);
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DefaultDataNodeFactory.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DefaultDataNodeFactory.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DefaultDataNodeFactory.java
index 4acaa9e..07c7fdf 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DefaultDataNodeFactory.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DefaultDataNodeFactory.java
@@ -25,6 +25,7 @@ import org.apache.cayenne.access.dbsync.SchemaUpdateStrategy;
 import org.apache.cayenne.access.jdbc.SQLTemplateProcessor;
 import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
 import org.apache.cayenne.access.translator.batch.BatchTranslatorFactory;
+import org.apache.cayenne.access.translator.select.SelectTranslatorFactory;
 import org.apache.cayenne.configuration.DataNodeDescriptor;
 import org.apache.cayenne.di.AdhocObjectFactory;
 import org.apache.cayenne.di.Inject;
@@ -46,6 +47,9 @@ public class DefaultDataNodeFactory implements 
DataNodeFactory {
 
     @Inject
     protected BatchTranslatorFactory batchTranslatorFactory;
+    
+    @Inject
+    protected SelectTranslatorFactory selectTranslatorFactory;
 
     @Inject
     protected DbAdapterFactory adapterFactory;
@@ -67,6 +71,7 @@ public class DefaultDataNodeFactory implements 
DataNodeFactory {
         dataNode.setJdbcEventLogger(jdbcEventLogger);
         dataNode.setRowReaderFactory(rowReaderFactory);
         dataNode.setBatchTranslatorFactory(batchTranslatorFactory);
+        dataNode.setSelectTranslatorFactory(selectTranslatorFactory);
         dataNode.setSqlTemplateProcessor(sqlTemplateProcessor);
 
         dataNode.setDataSourceLocation(nodeDescriptor.getParameters());

http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
index 8119982..7b0a520 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
@@ -32,6 +32,8 @@ import 
org.apache.cayenne.access.jdbc.reader.DefaultRowReaderFactory;
 import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
 import org.apache.cayenne.access.translator.batch.BatchTranslatorFactory;
 import 
org.apache.cayenne.access.translator.batch.DefaultBatchTranslatorFactory;
+import 
org.apache.cayenne.access.translator.select.DefaultSelectTranslatorFactory;
+import org.apache.cayenne.access.translator.select.SelectTranslatorFactory;
 import org.apache.cayenne.access.types.BigDecimalType;
 import org.apache.cayenne.access.types.BigIntegerType;
 import org.apache.cayenne.access.types.BooleanType;
@@ -108,166 +110,145 @@ import 
org.apache.cayenne.velocity.VelocitySQLTemplateProcessor;
  */
 public class ServerModule implements Module {
 
-    private static final int DEFAULT_MAX_ID_QUALIFIER_SIZE = 10000;
-
-    protected String[] configurationLocations;
-
-    /**
-     * Creates a ServerModule with at least one configuration location. For 
multi-module
-     * projects additional locations can be specified as well.
-     */
-    public ServerModule(String... configurationLocations) {
-
-        if (configurationLocations == null) {
-            configurationLocations = new String[0];
-        }
-
-        this.configurationLocations = configurationLocations;
-    }
-
-    public void configure(Binder binder) {
-
-        // configure global stack properties
-        binder.bindMap(Constants.PROPERTIES_MAP)
-            .put(Constants.SERVER_MAX_ID_QUALIFIER_SIZE_PROPERTY, 
String.valueOf(DEFAULT_MAX_ID_QUALIFIER_SIZE));
-
-        binder.bind(JdbcEventLogger.class).to(CommonsJdbcEventLogger.class);  
-        
binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class);
-        
binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
-
-        // configure known DbAdapter detectors in reverse order of popularity. 
Users can
-        // add their own to install custom adapters automatically
-        
-        // a bit ugly - need to bind all sniffers explicitly first before 
placing then in a list
-        binder.bind(FirebirdSniffer.class).to(FirebirdSniffer.class);
-        binder.bind(OpenBaseSniffer.class).to(OpenBaseSniffer.class);
-        binder.bind(FrontBaseSniffer.class).to(FrontBaseSniffer.class);
-        binder.bind(IngresSniffer.class).to(IngresSniffer.class);
-        binder.bind(SQLiteSniffer.class).to(SQLiteSniffer.class);
-        binder.bind(DB2Sniffer.class).to(DB2Sniffer.class);
-        binder.bind(H2Sniffer.class).to(H2Sniffer.class);
-        binder.bind(HSQLDBSniffer.class).to(HSQLDBSniffer.class);
-        binder.bind(SybaseSniffer.class).to(SybaseSniffer.class);
-        binder.bind(DerbySniffer.class).to(DerbySniffer.class);
-        binder.bind(SQLServerSniffer.class).to(SQLServerSniffer.class);
-        binder.bind(OracleSniffer.class).to(OracleSniffer.class);
-        binder.bind(PostgresSniffer.class).to(PostgresSniffer.class);
-        binder.bind(MySQLSniffer.class).to(MySQLSniffer.class);
-        
-        binder.bindList(Constants.SERVER_ADAPTER_DETECTORS_LIST)
-                .add(FirebirdSniffer.class)
-                .add(OpenBaseSniffer.class)
-                .add(FrontBaseSniffer.class)
-                .add(IngresSniffer.class)
-                .add(SQLiteSniffer.class)
-                .add(DB2Sniffer.class)
-                .add(H2Sniffer.class)
-                .add(HSQLDBSniffer.class)
-                .add(SybaseSniffer.class)
-                .add(DerbySniffer.class)
-                .add(SQLServerSniffer.class)
-                .add(OracleSniffer.class)
-                .add(PostgresSniffer.class)
-                .add(MySQLSniffer.class);
-
-        // configure an empty filter chain
-        binder.bindList(Constants.SERVER_DOMAIN_FILTERS_LIST);
-        
-        // configure extended types
-        binder
-                .bindList(Constants.SERVER_DEFAULT_TYPES_LIST)
-                .add(new VoidType())
-                .add(new BigDecimalType())
-                .add(new BigIntegerType())
-                .add(new BooleanType())
-                .add(new ByteArrayType(false, true))
-                .add(new ByteType(false))
-                .add(new CharType(false, true))
-                .add(new DateType())
-                .add(new DoubleType())
-                .add(new FloatType())
-                .add(new IntegerType())
-                .add(new LongType())
-                .add(new ShortType(false))
-                .add(new TimeType())
-                .add(new TimestampType())
-                .add(new UtilDateType())
-                .add(new 
CalendarType<GregorianCalendar>(GregorianCalendar.class))
-                .add(new CalendarType<Calendar>(Calendar.class))
-                .add(new UUIDType()); 
-        binder.bindList(Constants.SERVER_USER_TYPES_LIST);
-        binder.bindList(Constants.SERVER_TYPE_FACTORIES_LIST);
-
-        // configure explicit configurations
-        ListBuilder<Object> locationsListBuilder = binder
-                .bindList(Constants.SERVER_PROJECT_LOCATIONS_LIST);
-        for (String location : configurationLocations) {
-            locationsListBuilder.add(location);
-        }
-
-        binder.bind(ConfigurationNameMapper.class).to(
-                DefaultConfigurationNameMapper.class);
-
-        binder.bind(EventManager.class).to(DefaultEventManager.class);
-
-        binder.bind(QueryCache.class).toProvider(MapQueryCacheProvider.class);
-
-        // a service to provide the main stack DataDomain
-        binder.bind(DataDomain.class).toProvider(DataDomainProvider.class);
-        
-        binder.bind(DataNodeFactory.class).to(DefaultDataNodeFactory.class);
-
-        // will return DataDomain for request for a DataChannel
-        
binder.bind(DataChannel.class).toProvider(DomainDataChannelProvider.class);
-
-        binder.bind(ObjectContextFactory.class).to(DataContextFactory.class);
-        
-        
binder.bind(TransactionFactory.class).to(DefaultTransactionFactory.class);
-        
-        // a service to load project XML descriptors
-        binder.bind(DataChannelDescriptorLoader.class).to(
-                XMLDataChannelDescriptorLoader.class);
-        binder.bind(DataChannelDescriptorMerger.class).to(
-                DefaultDataChannelDescriptorMerger.class);
-
-        // a service to load DataMap XML descriptors
-        binder.bind(DataMapLoader.class).to(XMLDataMapLoader.class);
-
-        // a locator of resources, such as XML descriptors
-        
binder.bind(ResourceLocator.class).to(ClassLoaderResourceLocator.class);
-
-        // a global properties object
-        
binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
-
-        // a service to load DataSourceFactories. DelegatingDataSourceFactory 
will attempt
-        // to find the actual worker factory dynamically on each call 
depending on
-        // DataNodeDescriptor data and the environment
-        
binder.bind(DataSourceFactory.class).to(DelegatingDataSourceFactory.class);
-
-        // a default SchemaUpdateStrategy (used when no explicit strategy is 
specified in
-        // XML)
-        
binder.bind(SchemaUpdateStrategy.class).to(SkipSchemaUpdateStrategy.class);
-
-        // a default DBAdapterFactory used to load custom and automatic 
DbAdapters
-        binder.bind(DbAdapterFactory.class).to(DefaultDbAdapterFactory.class);
-
-        // binding AshwoodEntitySorter without scope, as this is a stateful 
object and is
-        // configured by the owning domain
-        
binder.bind(EntitySorter.class).to(AshwoodEntitySorter.class).withoutScope();
-
-        binder.bind(BatchTranslatorFactory.class).to(
-                DefaultBatchTranslatorFactory.class);
-
-        // a default ObjectMapRetainStrategy used to create objects map for 
ObjectStore
-        binder.bind(ObjectMapRetainStrategy.class).to(
-                DefaultObjectMapRetainStrategy.class);
-
-        // a default ObjectStoreFactory used to create ObjectStores for 
contexts
-        
binder.bind(ObjectStoreFactory.class).to(DefaultObjectStoreFactory.class);
-        
-        
binder.bind(TransactionManager.class).to(DefaultTransactionManager.class);
-        binder.bind(RowReaderFactory.class).to(DefaultRowReaderFactory.class);
-        
-        
binder.bind(SQLTemplateProcessor.class).to(VelocitySQLTemplateProcessor.class);
-    }
+       private static final int DEFAULT_MAX_ID_QUALIFIER_SIZE = 10000;
+
+       protected String[] configurationLocations;
+
+       /**
+        * Creates a ServerModule with at least one configuration location. For
+        * multi-module projects additional locations can be specified as well.
+        */
+       public ServerModule(String... configurationLocations) {
+
+               if (configurationLocations == null) {
+                       configurationLocations = new String[0];
+               }
+
+               this.configurationLocations = configurationLocations;
+       }
+
+       public void configure(Binder binder) {
+
+               // configure global stack properties
+               
binder.bindMap(Constants.PROPERTIES_MAP).put(Constants.SERVER_MAX_ID_QUALIFIER_SIZE_PROPERTY,
+                               String.valueOf(DEFAULT_MAX_ID_QUALIFIER_SIZE));
+
+               
binder.bind(JdbcEventLogger.class).to(CommonsJdbcEventLogger.class);
+               
binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class);
+               
binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
+
+               // configure known DbAdapter detectors in reverse order of 
popularity.
+               // Users can
+               // add their own to install custom adapters automatically
+
+               // a bit ugly - need to bind all sniffers explicitly first 
before
+               // placing then in a list
+               binder.bind(FirebirdSniffer.class).to(FirebirdSniffer.class);
+               binder.bind(OpenBaseSniffer.class).to(OpenBaseSniffer.class);
+               binder.bind(FrontBaseSniffer.class).to(FrontBaseSniffer.class);
+               binder.bind(IngresSniffer.class).to(IngresSniffer.class);
+               binder.bind(SQLiteSniffer.class).to(SQLiteSniffer.class);
+               binder.bind(DB2Sniffer.class).to(DB2Sniffer.class);
+               binder.bind(H2Sniffer.class).to(H2Sniffer.class);
+               binder.bind(HSQLDBSniffer.class).to(HSQLDBSniffer.class);
+               binder.bind(SybaseSniffer.class).to(SybaseSniffer.class);
+               binder.bind(DerbySniffer.class).to(DerbySniffer.class);
+               binder.bind(SQLServerSniffer.class).to(SQLServerSniffer.class);
+               binder.bind(OracleSniffer.class).to(OracleSniffer.class);
+               binder.bind(PostgresSniffer.class).to(PostgresSniffer.class);
+               binder.bind(MySQLSniffer.class).to(MySQLSniffer.class);
+
+               
binder.bindList(Constants.SERVER_ADAPTER_DETECTORS_LIST).add(FirebirdSniffer.class).add(OpenBaseSniffer.class)
+                               
.add(FrontBaseSniffer.class).add(IngresSniffer.class).add(SQLiteSniffer.class).add(DB2Sniffer.class)
+                               
.add(H2Sniffer.class).add(HSQLDBSniffer.class).add(SybaseSniffer.class).add(DerbySniffer.class)
+                               
.add(SQLServerSniffer.class).add(OracleSniffer.class).add(PostgresSniffer.class)
+                               .add(MySQLSniffer.class);
+
+               // configure an empty filter chain
+               binder.bindList(Constants.SERVER_DOMAIN_FILTERS_LIST);
+
+               // configure extended types
+               binder.bindList(Constants.SERVER_DEFAULT_TYPES_LIST).add(new 
VoidType()).add(new BigDecimalType())
+                               .add(new BigIntegerType()).add(new 
BooleanType()).add(new ByteArrayType(false, true))
+                               .add(new ByteType(false)).add(new 
CharType(false, true)).add(new DateType()).add(new DoubleType())
+                               .add(new FloatType()).add(new 
IntegerType()).add(new LongType()).add(new ShortType(false))
+                               .add(new TimeType()).add(new 
TimestampType()).add(new UtilDateType())
+                               .add(new 
CalendarType<GregorianCalendar>(GregorianCalendar.class))
+                               .add(new 
CalendarType<Calendar>(Calendar.class)).add(new UUIDType());
+               binder.bindList(Constants.SERVER_USER_TYPES_LIST);
+               binder.bindList(Constants.SERVER_TYPE_FACTORIES_LIST);
+
+               // configure explicit configurations
+               ListBuilder<Object> locationsListBuilder = 
binder.bindList(Constants.SERVER_PROJECT_LOCATIONS_LIST);
+               for (String location : configurationLocations) {
+                       locationsListBuilder.add(location);
+               }
+
+               
binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
+
+               binder.bind(EventManager.class).to(DefaultEventManager.class);
+
+               
binder.bind(QueryCache.class).toProvider(MapQueryCacheProvider.class);
+
+               // a service to provide the main stack DataDomain
+               
binder.bind(DataDomain.class).toProvider(DataDomainProvider.class);
+
+               
binder.bind(DataNodeFactory.class).to(DefaultDataNodeFactory.class);
+
+               // will return DataDomain for request for a DataChannel
+               
binder.bind(DataChannel.class).toProvider(DomainDataChannelProvider.class);
+
+               
binder.bind(ObjectContextFactory.class).to(DataContextFactory.class);
+
+               
binder.bind(TransactionFactory.class).to(DefaultTransactionFactory.class);
+
+               // a service to load project XML descriptors
+               
binder.bind(DataChannelDescriptorLoader.class).to(XMLDataChannelDescriptorLoader.class);
+               
binder.bind(DataChannelDescriptorMerger.class).to(DefaultDataChannelDescriptorMerger.class);
+
+               // a service to load DataMap XML descriptors
+               binder.bind(DataMapLoader.class).to(XMLDataMapLoader.class);
+
+               // a locator of resources, such as XML descriptors
+               
binder.bind(ResourceLocator.class).to(ClassLoaderResourceLocator.class);
+
+               // a global properties object
+               
binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
+
+               // a service to load DataSourceFactories. 
DelegatingDataSourceFactory
+               // will attempt
+               // to find the actual worker factory dynamically on each call 
depending
+               // on
+               // DataNodeDescriptor data and the environment
+               
binder.bind(DataSourceFactory.class).to(DelegatingDataSourceFactory.class);
+
+               // a default SchemaUpdateStrategy (used when no explicit 
strategy is
+               // specified in
+               // XML)
+               
binder.bind(SchemaUpdateStrategy.class).to(SkipSchemaUpdateStrategy.class);
+
+               // a default DBAdapterFactory used to load custom and automatic
+               // DbAdapters
+               
binder.bind(DbAdapterFactory.class).to(DefaultDbAdapterFactory.class);
+
+               // binding AshwoodEntitySorter without scope, as this is a 
stateful
+               // object and is
+               // configured by the owning domain
+               
binder.bind(EntitySorter.class).to(AshwoodEntitySorter.class).withoutScope();
+
+               
binder.bind(BatchTranslatorFactory.class).to(DefaultBatchTranslatorFactory.class);
+               
binder.bind(SelectTranslatorFactory.class).to(DefaultSelectTranslatorFactory.class);
+
+               // a default ObjectMapRetainStrategy used to create objects map 
for
+               // ObjectStore
+               
binder.bind(ObjectMapRetainStrategy.class).to(DefaultObjectMapRetainStrategy.class);
+
+               // a default ObjectStoreFactory used to create ObjectStores for 
contexts
+               
binder.bind(ObjectStoreFactory.class).to(DefaultObjectStoreFactory.class);
+
+               
binder.bind(TransactionManager.class).to(DefaultTransactionManager.class);
+               
binder.bind(RowReaderFactory.class).to(DefaultRowReaderFactory.class);
+
+               
binder.bind(SQLTemplateProcessor.class).to(VelocitySQLTemplateProcessor.class);
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/dba/AutoAdapter.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/AutoAdapter.java 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/AutoAdapter.java
index 4e16194..0976763 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/AutoAdapter.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/AutoAdapter.java
@@ -19,245 +19,241 @@
 
 package org.apache.cayenne.dba;
 
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Collection;
+
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.access.translator.ejbql.EJBQLTranslatorFactory;
 import org.apache.cayenne.access.translator.select.QualifierTranslator;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
+import org.apache.cayenne.access.translator.select.SelectTranslator;
 import org.apache.cayenne.access.types.ExtendedTypeMap;
 import org.apache.cayenne.di.Provider;
 import org.apache.cayenne.log.JdbcEventLogger;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.merge.MergerFactory;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.SQLAction;
-
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.util.Collection;
+import org.apache.cayenne.query.SelectQuery;
 
 /**
- * A DbAdapter that automatically detects the kind of database it is running 
on and
- * instantiates an appropriate DB-specific adapter, delegating all subsequent 
method calls
- * to this adapter.
+ * A DbAdapter that automatically detects the kind of database it is running on
+ * and instantiates an appropriate DB-specific adapter, delegating all
+ * subsequent method calls to this adapter.
  * 
  * @since 1.2
  */
 public class AutoAdapter implements DbAdapter {
 
-    protected Provider<DbAdapter> adapterProvider;
-    protected PkGenerator pkGenerator;
-    protected JdbcEventLogger logger;
-
-    /**
-     * The actual adapter that is delegated methods execution.
-     */
-    volatile DbAdapter adapter;
-
-    /**
-     * Creates an {@link AutoAdapter} based on a delegate adapter obtained via
-     * "adapterProvider".
-     * 
-     * @since 3.1
-     */
-    public AutoAdapter(Provider<DbAdapter> adapterProvider, JdbcEventLogger 
logger) {
-
-        if (adapterProvider == null) {
-            throw new CayenneRuntimeException("Null adapterProvider");
-        }
-
-        this.adapterProvider = adapterProvider;
-        this.logger = logger;
-    }
-
-    /**
-     * Returns a proxied DbAdapter, lazily creating it on first invocation.
-     */
-    protected DbAdapter getAdapter() {
-        if (adapter == null) {
-            synchronized (this) {
-                if (adapter == null) {
-                    this.adapter = loadAdapter();
-                }
-            }
-        }
-
-        return adapter;
-    }
-
-    /**
-     * Loads underlying DbAdapter delegate.
-     */
-    protected DbAdapter loadAdapter() {
-        return adapterProvider.get();
-    }
-
-    @Override
-    public String getBatchTerminator() {
-        return getAdapter().getBatchTerminator();
-    }
-
-    @Override
-    public QualifierTranslator getQualifierTranslator(QueryAssembler 
queryAssembler) {
-        return getAdapter().getQualifierTranslator(queryAssembler);
-    }
-
-    @Override
-    public SQLAction getAction(Query query, DataNode node) {
-        return getAdapter().getAction(query, node);
-    }
-
-    @Override
-    public boolean supportsUniqueConstraints() {
-        return getAdapter().supportsUniqueConstraints();
-    }
-
-    @Override
-    public boolean supportsCatalogsOnReverseEngineering() {
-        return getAdapter().supportsCatalogsOnReverseEngineering();
-    }
-
-    @Override
-    public boolean supportsGeneratedKeys() {
-        return getAdapter().supportsGeneratedKeys();
-    }
-
-    @Override
-    public boolean supportsBatchUpdates() {
-        return getAdapter().supportsBatchUpdates();
-    }
+       protected Provider<DbAdapter> adapterProvider;
+       protected PkGenerator pkGenerator;
+       protected JdbcEventLogger logger;
+
+       /**
+        * The actual adapter that is delegated methods execution.
+        */
+       volatile DbAdapter adapter;
+
+       /**
+        * Creates an {@link AutoAdapter} based on a delegate adapter obtained 
via
+        * "adapterProvider".
+        * 
+        * @since 3.1
+        */
+       public AutoAdapter(Provider<DbAdapter> adapterProvider, JdbcEventLogger 
logger) {
+
+               if (adapterProvider == null) {
+                       throw new CayenneRuntimeException("Null 
adapterProvider");
+               }
+
+               this.adapterProvider = adapterProvider;
+               this.logger = logger;
+       }
+
+       /**
+        * Returns a proxied DbAdapter, lazily creating it on first invocation.
+        */
+       protected DbAdapter getAdapter() {
+               if (adapter == null) {
+                       synchronized (this) {
+                               if (adapter == null) {
+                                       this.adapter = loadAdapter();
+                               }
+                       }
+               }
+
+               return adapter;
+       }
+
+       /**
+        * Loads underlying DbAdapter delegate.
+        */
+       protected DbAdapter loadAdapter() {
+               return adapterProvider.get();
+       }
+       
+       /**
+        * @since 4.0
+        */
+       @Override
+       public SelectTranslator getSelectTranslator(SelectQuery<?> query, 
EntityResolver entityResolver) {
+               return getAdapter().getSelectTranslator(query, entityResolver);
+       }
+
+       @Override
+       public String getBatchTerminator() {
+               return getAdapter().getBatchTerminator();
+       }
+
+       @Override
+       public QualifierTranslator getQualifierTranslator(QueryAssembler 
queryAssembler) {
+               return getAdapter().getQualifierTranslator(queryAssembler);
+       }
+
+       @Override
+       public SQLAction getAction(Query query, DataNode node) {
+               return getAdapter().getAction(query, node);
+       }
+
+       @Override
+       public boolean supportsUniqueConstraints() {
+               return getAdapter().supportsUniqueConstraints();
+       }
+
+       @Override
+       public boolean supportsCatalogsOnReverseEngineering() {
+               return getAdapter().supportsCatalogsOnReverseEngineering();
+       }
+
+       @Override
+       public boolean supportsGeneratedKeys() {
+               return getAdapter().supportsGeneratedKeys();
+       }
+
+       @Override
+       public boolean supportsBatchUpdates() {
+               return getAdapter().supportsBatchUpdates();
+       }
+
+       @Override
+       public boolean typeSupportsLength(int type) {
+               return getAdapter().typeSupportsLength(type);
+       }
+
+       @Override
+       public Collection<String> dropTableStatements(DbEntity table) {
+               return getAdapter().dropTableStatements(table);
+       }
+
+       @Override
+       public String createTable(DbEntity entity) {
+               return getAdapter().createTable(entity);
+       }
+
+       @Override
+       public String createUniqueConstraint(DbEntity source, 
Collection<DbAttribute> columns) {
+               return getAdapter().createUniqueConstraint(source, columns);
+       }
+
+       @Override
+       public String createFkConstraint(DbRelationship rel) {
+               return getAdapter().createFkConstraint(rel);
+       }
+
+       @Override
+       public String[] externalTypesForJdbcType(int type) {
+               return getAdapter().externalTypesForJdbcType(type);
+       }
+
+       @Override
+       public ExtendedTypeMap getExtendedTypes() {
+               return getAdapter().getExtendedTypes();
+       }
+
+       /**
+        * Returns a primary key generator.
+        */
+       @Override
+       public PkGenerator getPkGenerator() {
+               return (pkGenerator != null) ? pkGenerator : 
getAdapter().getPkGenerator();
+       }
+
+       /**
+        * Sets a PK generator override. If set to non-null value, such PK 
generator
+        * will be used instead of the one provided by wrapped adapter.
+        */
+       public void setPkGenerator(PkGenerator pkGenerator) {
+               this.pkGenerator = pkGenerator;
+       }
+
+       @Override
+       public DbAttribute buildAttribute(String name, String typeName, int 
type, int size, int precision,
+                       boolean allowNulls) {
+
+               return getAdapter().buildAttribute(name, typeName, type, size, 
precision, allowNulls);
+       }
+
+       @Override
+       public void bindParameter(PreparedStatement statement, Object object, 
int pos, int sqlType, int precision)
+                       throws SQLException, Exception {
+               getAdapter().bindParameter(statement, object, pos, sqlType, 
precision);
+       }
+
+       @Override
+       public String tableTypeForTable() {
+               return getAdapter().tableTypeForTable();
+       }
+
+       @Override
+       public String tableTypeForView() {
+               return getAdapter().tableTypeForView();
+       }
+
+       @Override
+       public MergerFactory mergerFactory() {
+               return getAdapter().mergerFactory();
+       }
+
+       @Override
+       public void createTableAppendColumn(StringBuffer sqlBuffer, DbAttribute 
column) {
+               getAdapter().createTableAppendColumn(sqlBuffer, column);
+       }
+
+       /**
+        * @deprecated since 4.0
+        */
+       @Deprecated
+       @Override
+       public QuotingStrategy getQuotingStrategy(boolean isQuoteStrategy) {
+               return getAdapter().getQuotingStrategy(isQuoteStrategy);
+       }
+
+       /**
+        * @since 4.0
+        */
+       @Override
+       public QuotingStrategy getQuotingStrategy() {
+               return getAdapter().getQuotingStrategy();
+       }
+
+       /**
+        * @since 4.0
+        */
+       @Override
+       public DbAdapter unwrap() {
+               return getAdapter();
+       }
 
+       /**
+        * @since 4.0
+        */
        @Override
-    public boolean typeSupportsLength(int type) {
-       return getAdapter().typeSupportsLength(type);
-    }
-    
-    @Override
-    public Collection<String> dropTableStatements(DbEntity table) {
-        return getAdapter().dropTableStatements(table);
-    }
-
-    @Override
-    public String createTable(DbEntity entity) {
-        return getAdapter().createTable(entity);
-    }
-
-    @Override
-    public String createUniqueConstraint(DbEntity source, 
Collection<DbAttribute> columns) {
-        return getAdapter().createUniqueConstraint(source, columns);
-    }
-
-    @Override
-    public String createFkConstraint(DbRelationship rel) {
-        return getAdapter().createFkConstraint(rel);
-    }
-
-    @Override
-    public String[] externalTypesForJdbcType(int type) {
-        return getAdapter().externalTypesForJdbcType(type);
-    }
-
-    @Override
-    public ExtendedTypeMap getExtendedTypes() {
-        return getAdapter().getExtendedTypes();
-    }
-
-    /**
-     * Returns a primary key generator.
-     */
-    @Override
-    public PkGenerator getPkGenerator() {
-        return (pkGenerator != null) ? pkGenerator : 
getAdapter().getPkGenerator();
-    }
-
-    /**
-     * Sets a PK generator override. If set to non-null value, such PK 
generator will be
-     * used instead of the one provided by wrapped adapter.
-     */
-    public void setPkGenerator(PkGenerator pkGenerator) {
-        this.pkGenerator = pkGenerator;
-    }
-
-    @Override
-    public DbAttribute buildAttribute(
-            String name,
-            String typeName,
-            int type,
-            int size,
-            int precision,
-            boolean allowNulls) {
-
-        return getAdapter().buildAttribute(
-                name,
-                typeName,
-                type,
-                size,
-                precision,
-                allowNulls);
-    }
-
-    @Override
-    public void bindParameter(
-            PreparedStatement statement,
-            Object object,
-            int pos,
-            int sqlType,
-            int precision) throws SQLException, Exception {
-        getAdapter().bindParameter(statement, object, pos, sqlType, precision);
-    }
-
-    @Override
-    public String tableTypeForTable() {
-        return getAdapter().tableTypeForTable();
-    }
-
-    @Override
-    public String tableTypeForView() {
-        return getAdapter().tableTypeForView();
-    }
-
-    @Override
-    public MergerFactory mergerFactory() {
-        return getAdapter().mergerFactory();
-    }
-
-    @Override
-    public void createTableAppendColumn(StringBuffer sqlBuffer, DbAttribute 
column) {
-        getAdapter().createTableAppendColumn(sqlBuffer, column);
-    }
-
-    /**
-     * @deprecated since 4.0
-     */
-    @Deprecated
-    @Override
-    public QuotingStrategy getQuotingStrategy(boolean isQuoteStrategy) {
-        return getAdapter().getQuotingStrategy(isQuoteStrategy);
-    }
-    
-    /**
-     * @since 4.0
-     */
-    @Override
-    public QuotingStrategy getQuotingStrategy() {
-        return getAdapter().getQuotingStrategy();
-    }
-
-    /**
-     * @since 4.0
-     */
-    @Override
-    public DbAdapter unwrap() {
-        return getAdapter();
-    }
-
-    /**
-     * @since 4.0
-     */
-    @Override
-    public EJBQLTranslatorFactory getEjbqlTranslatorFactory() {
-        return getAdapter().getEjbqlTranslatorFactory();
-    }
+       public EJBQLTranslatorFactory getEjbqlTranslatorFactory() {
+               return getAdapter().getEjbqlTranslatorFactory();
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/741ad3be/cayenne-server/src/main/java/org/apache/cayenne/dba/DbAdapter.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/DbAdapter.java 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/DbAdapter.java
index 5d6c4d9..b71a741 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/DbAdapter.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/DbAdapter.java
@@ -22,13 +22,16 @@ import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.access.translator.ejbql.EJBQLTranslatorFactory;
 import org.apache.cayenne.access.translator.select.QualifierTranslator;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
+import org.apache.cayenne.access.translator.select.SelectTranslator;
 import org.apache.cayenne.access.types.ExtendedTypeMap;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.merge.MergerFactory;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.SQLAction;
+import org.apache.cayenne.query.SelectQuery;
 
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
@@ -42,179 +45,186 @@ import java.util.Collection;
  */
 public interface DbAdapter {
 
-    /**
-     * Returns a String used to terminate a batch in command-line tools. E.g.
-     * ";" on Oracle or "go" on Sybase.
-     * 
-     * @since 1.0.4
-     */
-    String getBatchTerminator();
-
-    // TODO: deprecate and move into SQLAction implementation
-    QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler);
-
-    /**
-     * Returns an instance of SQLAction that should handle the query.
-     * 
-     * @since 1.2
-     */
-    SQLAction getAction(Query query, DataNode node);
-
-    /**
-     * Returns true if a target database supports UNIQUE constraints.
-     *
-     * @since 1.1
-     */
-    boolean supportsUniqueConstraints();
-
-    /**
-     * Returns true if a target database supports catalogs on reverse 
engineering.
-     *
-     * @since 4.0
-     */
-    boolean supportsCatalogsOnReverseEngineering();
-
-    /**
-     * Returns true if a target database supports key autogeneration. This
-     * feature also requires JDBC3-compliant driver.
-     * 
-     * @since 1.2
-     */
-    boolean supportsGeneratedKeys();
-
-    /**
-     * Returns <code>true</code> if the target database supports batch updates.
-     */
-    boolean supportsBatchUpdates();
-
-    boolean typeSupportsLength(int type);
-    
-    /**
-     * Returns a collection of SQL statements needed to drop a database table.
-     * 
-     * @since 3.0
-     */
-    Collection<String> dropTableStatements(DbEntity table);
-
-    /**
-     * Returns a SQL string that can be used to create database table
-     * corresponding to <code>entity</code> parameter.
-     */
-    String createTable(DbEntity entity);
-
-    /**
-     * Returns a DDL string to create a unique constraint over a set of 
columns,
-     * or null if the unique constraints are not supported.
-     * 
-     * @since 1.1
-     */
-    String createUniqueConstraint(DbEntity source, Collection<DbAttribute> 
columns);
-
-    /**
-     * Returns a SQL string that can be used to create a foreign key constraint
-     * for the relationship, or null if foreign keys are not supported.
-     */
-    String createFkConstraint(DbRelationship rel);
-
-    /**
-     * Returns an array of RDBMS types that can be used with JDBC
-     * <code>type</code>. Valid JDBC types are defined in java.sql.Types.
-     */
-    String[] externalTypesForJdbcType(int type);
-
-    /**
-     * Returns a map of ExtendedTypes that is used to translate values between
-     * Java and JDBC layer.
-     */
-    ExtendedTypeMap getExtendedTypes();
-
-    /**
-     * Returns primary key generator associated with this DbAdapter.
-     */
-    PkGenerator getPkGenerator();
-
-    /**
-     * Creates and returns a DbAttribute based on supplied parameters (usually
-     * obtained from database meta data).
-     * 
-     * @param name
-     *            database column name
-     * @param typeName
-     *            database specific type name, may be used as a hint to
-     *            determine the right JDBC type.
-     * @param type
-     *            JDBC column type
-     * @param size
-     *            database column size (ignored if less than zero)
-     * @param scale
-     *            database column scale, i.e. the number of decimal digits
-     *            (ignored if less than zero)
-     * @param allowNulls
-     *            database column nullable parameter
-     */
-    DbAttribute buildAttribute(String name, String typeName, int type, int 
size, int scale, boolean allowNulls);
-
-    /**
-     * Binds an object value to PreparedStatement's numbered parameter.
-     */
-    void bindParameter(PreparedStatement statement, Object object, int pos, 
int sqlType, int scale)
-            throws SQLException, Exception;
-
-    /**
-     * Returns the name of the table type (as returned by
-     * <code>DatabaseMetaData.getTableTypes</code>) for a simple user table.
-     */
-    String tableTypeForTable();
-
-    /**
-     * Returns the name of the table type (as returned by
-     * <code>DatabaseMetaData.getTableTypes</code>) for a view table.
-     */
-    String tableTypeForView();
-
-    /**
-     * @since 3.0
-     */
-    MergerFactory mergerFactory();
-
-    /**
-     * Append the column type part of a "create table" to the given
-     * {@link StringBuffer}
-     * 
-     * @param sqlBuffer
-     *            the {@link StringBuffer} to append the column type to
-     * @param column
-     *            the {@link DbAttribute} defining the column to append type 
for
-     * @since 3.0
-     */
-    void createTableAppendColumn(StringBuffer sqlBuffer, DbAttribute column);
-
-    /**
-     * @since 3.0
-     * @deprecated since 4.0 use {@link #getQuotingStrategy()}.
-     */
-    @Deprecated
-    QuotingStrategy getQuotingStrategy(boolean needQuotes);
-
-    /**
-     * Returns SQL identifier quoting strategy object
-     * 
-     * @since 4.0
-     */
-    QuotingStrategy getQuotingStrategy();
-
-    /**
-     * Allows the users to get access to the adapter decorated by a given
-     * adapter.
-     * 
-     * @since 4.0
-     */
-    DbAdapter unwrap();
-
-    /**
-     * Returns a translator factory for EJBQL to SQL translation.
-     * 
-     * @since 4.0
-     */
-    EJBQLTranslatorFactory getEjbqlTranslatorFactory();
+       /**
+        * Returns a String used to terminate a batch in command-line tools. 
E.g.
+        * ";" on Oracle or "go" on Sybase.
+        * 
+        * @since 1.0.4
+        */
+       String getBatchTerminator();
+
+       /**
+        * Returns a SelectTranslator that works with the adapter target 
database.
+        * 
+        * @since 4.0
+        */
+       SelectTranslator getSelectTranslator(SelectQuery<?> query, 
EntityResolver entityResolver);
+
+       QualifierTranslator getQualifierTranslator(QueryAssembler 
queryAssembler);
+
+       /**
+        * Returns an instance of SQLAction that should handle the query.
+        * 
+        * @since 1.2
+        */
+       SQLAction getAction(Query query, DataNode node);
+
+       /**
+        * Returns true if a target database supports UNIQUE constraints.
+        *
+        * @since 1.1
+        */
+       boolean supportsUniqueConstraints();
+
+       /**
+        * Returns true if a target database supports catalogs on reverse
+        * engineering.
+        *
+        * @since 4.0
+        */
+       boolean supportsCatalogsOnReverseEngineering();
+
+       /**
+        * Returns true if a target database supports key autogeneration. This
+        * feature also requires JDBC3-compliant driver.
+        * 
+        * @since 1.2
+        */
+       boolean supportsGeneratedKeys();
+
+       /**
+        * Returns <code>true</code> if the target database supports batch 
updates.
+        */
+       boolean supportsBatchUpdates();
+
+       boolean typeSupportsLength(int type);
+
+       /**
+        * Returns a collection of SQL statements needed to drop a database 
table.
+        * 
+        * @since 3.0
+        */
+       Collection<String> dropTableStatements(DbEntity table);
+
+       /**
+        * Returns a SQL string that can be used to create database table
+        * corresponding to <code>entity</code> parameter.
+        */
+       String createTable(DbEntity entity);
+
+       /**
+        * Returns a DDL string to create a unique constraint over a set of 
columns,
+        * or null if the unique constraints are not supported.
+        * 
+        * @since 1.1
+        */
+       String createUniqueConstraint(DbEntity source, Collection<DbAttribute> 
columns);
+
+       /**
+        * Returns a SQL string that can be used to create a foreign key 
constraint
+        * for the relationship, or null if foreign keys are not supported.
+        */
+       String createFkConstraint(DbRelationship rel);
+
+       /**
+        * Returns an array of RDBMS types that can be used with JDBC
+        * <code>type</code>. Valid JDBC types are defined in java.sql.Types.
+        */
+       String[] externalTypesForJdbcType(int type);
+
+       /**
+        * Returns a map of ExtendedTypes that is used to translate values 
between
+        * Java and JDBC layer.
+        */
+       ExtendedTypeMap getExtendedTypes();
+
+       /**
+        * Returns primary key generator associated with this DbAdapter.
+        */
+       PkGenerator getPkGenerator();
+
+       /**
+        * Creates and returns a DbAttribute based on supplied parameters 
(usually
+        * obtained from database meta data).
+        * 
+        * @param name
+        *            database column name
+        * @param typeName
+        *            database specific type name, may be used as a hint to
+        *            determine the right JDBC type.
+        * @param type
+        *            JDBC column type
+        * @param size
+        *            database column size (ignored if less than zero)
+        * @param scale
+        *            database column scale, i.e. the number of decimal digits
+        *            (ignored if less than zero)
+        * @param allowNulls
+        *            database column nullable parameter
+        */
+       DbAttribute buildAttribute(String name, String typeName, int type, int 
size, int scale, boolean allowNulls);
+
+       /**
+        * Binds an object value to PreparedStatement's numbered parameter.
+        */
+       void bindParameter(PreparedStatement statement, Object object, int pos, 
int sqlType, int scale)
+                       throws SQLException, Exception;
+
+       /**
+        * Returns the name of the table type (as returned by
+        * <code>DatabaseMetaData.getTableTypes</code>) for a simple user table.
+        */
+       String tableTypeForTable();
+
+       /**
+        * Returns the name of the table type (as returned by
+        * <code>DatabaseMetaData.getTableTypes</code>) for a view table.
+        */
+       String tableTypeForView();
+
+       /**
+        * @since 3.0
+        */
+       MergerFactory mergerFactory();
+
+       /**
+        * Append the column type part of a "create table" to the given
+        * {@link StringBuffer}
+        * 
+        * @param sqlBuffer
+        *            the {@link StringBuffer} to append the column type to
+        * @param column
+        *            the {@link DbAttribute} defining the column to append 
type for
+        * @since 3.0
+        */
+       void createTableAppendColumn(StringBuffer sqlBuffer, DbAttribute 
column);
+
+       /**
+        * @since 3.0
+        * @deprecated since 4.0 use {@link #getQuotingStrategy()}.
+        */
+       @Deprecated
+       QuotingStrategy getQuotingStrategy(boolean needQuotes);
+
+       /**
+        * Returns SQL identifier quoting strategy object
+        * 
+        * @since 4.0
+        */
+       QuotingStrategy getQuotingStrategy();
+
+       /**
+        * Allows the users to get access to the adapter decorated by a given
+        * adapter.
+        * 
+        * @since 4.0
+        */
+       DbAdapter unwrap();
+
+       /**
+        * Returns a translator factory for EJBQL to SQL translation.
+        * 
+        * @since 4.0
+        */
+       EJBQLTranslatorFactory getEjbqlTranslatorFactory();
 }

Reply via email to