Repository: cayenne
Updated Branches:
  refs/heads/master 777b1d650 -> 77bd5b7f3


cleanup before refactoring .. mostly generics-related


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

Branch: refs/heads/master
Commit: 77bd5b7f321a6bacfbc75f00940902cdb02e212b
Parents: 777b1d6
Author: aadamchik <[email protected]>
Authored: Sun Nov 2 12:55:15 2014 +0300
Committer: aadamchik <[email protected]>
Committed: Sun Nov 2 12:55:29 2014 +0300

----------------------------------------------------------------------
 .../access/jdbc/SQLTemplateProcessor.java       |   52 +-
 .../org/apache/cayenne/query/SQLSelect.java     |    2 +-
 .../org/apache/cayenne/query/SQLTemplate.java   | 1217 +++++++++---------
 3 files changed, 628 insertions(+), 643 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/77bd5b7f/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessor.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessor.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessor.java
index 82b6dca..366e9a9 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessor.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessor.java
@@ -31,7 +31,7 @@ import org.apache.velocity.VelocityContext;
 import org.apache.velocity.context.InternalContextAdapterImpl;
 import org.apache.velocity.runtime.RuntimeConstants;
 import org.apache.velocity.runtime.RuntimeInstance;
-import org.apache.velocity.runtime.log.NullLogSystem;
+import org.apache.velocity.runtime.log.NullLogChute;
 import org.apache.velocity.runtime.parser.ParseException;
 import org.apache.velocity.runtime.parser.node.SimpleNode;
 
@@ -65,7 +65,7 @@ class SQLTemplateProcessor {
         // set null logger
         sharedRuntime.addProperty(
                 RuntimeConstants.RUNTIME_LOG_LOGSYSTEM,
-                new NullLogSystem());
+                new NullLogChute());
 
         sharedRuntime.addProperty(
                 RuntimeConstants.RESOURCE_MANAGER_CLASS,
@@ -107,33 +107,29 @@ class SQLTemplateProcessor {
      * parameters in the map, {@link SQLTemplateRenderingUtils} as a "helper" 
variable and
      * SQLStatement object as "statement" variable.
      */
-    SQLStatement processTemplate(String template, Map parameters) throws 
Exception {
-        // have to make a copy of parameter map since we are gonna modify it..
-        Map internalParameters = (parameters != null && !parameters.isEmpty())
-                ? new HashMap(parameters)
-                : new HashMap(3);
-
-        List<ParameterBinding> bindings = new ArrayList<ParameterBinding>();
-        List<ColumnDescriptor> results = new ArrayList<ColumnDescriptor>();
-        internalParameters.put(BINDINGS_LIST_KEY, bindings);
-        internalParameters.put(RESULT_COLUMNS_LIST_KEY, results);
-        internalParameters.put(HELPER_KEY, renderingUtils);
-
-        String sql = buildStatement(
-                new VelocityContext(internalParameters),
-                template,
-                parameters);
-
-        ParameterBinding[] bindingsArray = new 
ParameterBinding[bindings.size()];
-        bindings.toArray(bindingsArray);
-
-        ColumnDescriptor[] resultsArray = new ColumnDescriptor[results.size()];
-        results.toArray(resultsArray);
-
-        return new SQLStatement(sql, resultsArray, bindingsArray);
-    }
+       SQLStatement processTemplate(String template, Map<String, ?> 
parameters) throws Exception {
+               // have to make a copy of parameter map since we are gonna 
modify it..
+               Map<String, Object> internalParameters = (parameters != null && 
!parameters.isEmpty()) ? new HashMap<String, Object>(
+                               parameters) : new HashMap<String, Object>(5);
+
+               List<ParameterBinding> bindings = new 
ArrayList<ParameterBinding>();
+               List<ColumnDescriptor> results = new 
ArrayList<ColumnDescriptor>();
+               internalParameters.put(BINDINGS_LIST_KEY, bindings);
+               internalParameters.put(RESULT_COLUMNS_LIST_KEY, results);
+               internalParameters.put(HELPER_KEY, renderingUtils);
+
+               String sql = buildStatement(new 
VelocityContext(internalParameters), template, parameters);
+
+               ParameterBinding[] bindingsArray = new 
ParameterBinding[bindings.size()];
+               bindings.toArray(bindingsArray);
+
+               ColumnDescriptor[] resultsArray = new 
ColumnDescriptor[results.size()];
+               results.toArray(resultsArray);
+
+               return new SQLStatement(sql, resultsArray, bindingsArray);
+       }
 
-    String buildStatement(VelocityContext context, String template, Map 
parameters)
+    String buildStatement(VelocityContext context, String template, 
Map<String, ?> parameters)
             throws Exception {
         // Note: this method is a reworked version of
         // org.apache.velocity.app.Velocity.evaluate(..)

http://git-wip-us.apache.org/repos/asf/cayenne/blob/77bd5b7f/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java 
b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java
index 3f75291..de1c43c 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java
@@ -164,7 +164,7 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
        /**
         * Returns mutable map of parameters that will be bound to SQL. A 
caller is
         * free to add/remove parameters from the returned map as needed.
-        * Alternatively one should use chained {@link #params(String, Object)}
+        * Alternatively one may use chained {@link #params(String, Object)}
         */
        public Map<String, Object> getParameters() {
                return parameters;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/77bd5b7f/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java 
b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
index ee8e10e..8a4b787 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
@@ -72,618 +72,607 @@ import org.apache.commons.collections.Transformer;
  * @since 1.1
  */
 public class SQLTemplate extends AbstractQuery implements ParameterizedQuery,
-        XMLSerializable {
-
-    static final String COLUMN_NAME_CAPITALIZATION_PROPERTY = 
"cayenne.SQLTemplate.columnNameCapitalization";
-
-    private static final Transformer nullMapTransformer = new Transformer() {
-
-        public Object transform(Object input) {
-            return (input != null) ? input : Collections.EMPTY_MAP;
-        }
-    };
-
-    protected String defaultTemplate;
-    protected Map<String, String> templates;
-    protected Map<String, ?>[] parameters;
-    protected CapsStrategy columnNamesCapitalization;
-    protected SQLResult result;
-    private String dataNodeName;
-
-    SQLTemplateMetadata metaData = new SQLTemplateMetadata();
-
-    /**
-     * Creates an empty SQLTemplate. Note this constructor does not specify 
the "root" of
-     * the query, so a user must call "setRoot" later to make sure SQLTemplate 
can be
-     * executed.
-     * 
-     * @since 1.2
-     */
-    public SQLTemplate() {
-    }
-    
-    /**
-     * Creates a SQLTemplate without an explicit root.
-     * 
-     * @since 4.0
-     */
-    public SQLTemplate(String defaultTemplate, boolean isFetchingDataRows) {
-        setDefaultTemplate(defaultTemplate);
-        setRoot(null);
-        setFetchingDataRows(isFetchingDataRows);
-    }
-    
-    @Override
-    public void setRoot(Object value) {
-        // allow null root...
-        if (value == null) {
-            this.root = value;
-        } else {
-            super.setRoot(value);
-        }
-    }
-    
-    @Override
-    public void route(QueryRouter router, EntityResolver resolver, Query 
substitutedQuery) {
-        DataMap map = getMetaData(resolver).getDataMap();
-
-        QueryEngine engine;
-        if (map != null) {
-            engine = router.engineForDataMap(map);
-        } else {
-            engine = router.engineForName(getDataNodeName());
-        }
-
-        router.route(engine, this, substitutedQuery);
-    }
-
-    /**
-     * @since 3.1
-     */
-    public SQLTemplate(DataMap rootMap, String defaultTemplate, boolean 
isFetchingDataRows) {
-        setDefaultTemplate(defaultTemplate);
-        setRoot(rootMap);
-        setFetchingDataRows(isFetchingDataRows);
-    }
-
-    /**
-     * @since 1.2
-     */
-    public SQLTemplate(ObjEntity rootEntity, String defaultTemplate) {
-        setDefaultTemplate(defaultTemplate);
-        setRoot(rootEntity);
-    }
-
-    /**
-     * @since 1.2
-     */
-    public SQLTemplate(Class<?> rootClass, String defaultTemplate) {
-        setDefaultTemplate(defaultTemplate);
-        setRoot(rootClass);
-    }
-
-    /**
-     * @since 1.2
-     */
-    public SQLTemplate(DbEntity rootEntity, String defaultTemplate) {
-        setDefaultTemplate(defaultTemplate);
-        setRoot(rootEntity);
-    }
-
-    /**
-     * @since 1.2
-     */
-    public SQLTemplate(String objEntityName, String defaultTemplate) {
-        setRoot(objEntityName);
-        setDefaultTemplate(defaultTemplate);
-    }
-
-    /**
-     * @since 1.2
-     */
-    @Override
-    public QueryMetadata getMetaData(EntityResolver resolver) {
-        metaData.resolve(root, resolver, this);
-        return metaData;
-    }
-
-    /**
-     * Calls <em>sqlAction(this)</em> on the visitor.
-     * 
-     * @since 1.2
-     */
-    @Override
-    public SQLAction createSQLAction(SQLActionVisitor visitor) {
-        return visitor.sqlAction(this);
-    }
-
-    /**
-     * Prints itself as XML to the provided PrintWriter.
-     * 
-     * @since 1.1
-     */
-    public void encodeAsXML(XMLEncoder encoder) {
-        encoder.print("<query name=\"");
-        encoder.print(getName());
-        encoder.print("\" factory=\"");
-        encoder.print("org.apache.cayenne.map.SQLTemplateBuilder");
-
-        String rootString = null;
-        String rootType = null;
-
-        if (root instanceof String) {
-            rootType = MapLoader.OBJ_ENTITY_ROOT;
-            rootString = root.toString();
-        }
-        else if (root instanceof ObjEntity) {
-            rootType = MapLoader.OBJ_ENTITY_ROOT;
-            rootString = ((ObjEntity) root).getName();
-        }
-        else if (root instanceof DbEntity) {
-            rootType = MapLoader.DB_ENTITY_ROOT;
-            rootString = ((DbEntity) root).getName();
-        }
-        else if (root instanceof Procedure) {
-            rootType = MapLoader.PROCEDURE_ROOT;
-            rootString = ((Procedure) root).getName();
-        }
-        else if (root instanceof Class<?>) {
-            rootType = MapLoader.JAVA_CLASS_ROOT;
-            rootString = ((Class<?>) root).getName();
-        }
-        else if (root instanceof DataMap) {
-            rootType = MapLoader.DATA_MAP_ROOT;
-            rootString = ((DataMap) root).getName();
-        }
-
-        if (rootType != null) {
-            encoder.print("\" root=\"");
-            encoder.print(rootType);
-            encoder.print("\" root-name=\"");
-            encoder.print(rootString);
-        }
-
-        encoder.println("\">");
-
-        encoder.indent(1);
-
-        metaData.encodeAsXML(encoder);
-
-        if (getColumnNamesCapitalization() != CapsStrategy.DEFAULT) {
-            encoder.printProperty(
-                    COLUMN_NAME_CAPITALIZATION_PROPERTY,
-                    getColumnNamesCapitalization().name());
-        }
-
-        // encode default SQL
-        if (defaultTemplate != null) {
-            encoder.print("<sql><![CDATA[");
-            encoder.print(defaultTemplate);
-            encoder.println("]]></sql>");
-        }
-
-        // encode adapter SQL
-        if (templates != null && !templates.isEmpty()) {
-            
-            //sorting entries by adapter name
-            TreeSet<String> keys = new TreeSet<String>(templates.keySet());
-            for (String key : keys) {
-                String value = templates.get(key);
-
-                if (key != null && value != null) {
-                    String sql = value.trim();
-                    if (sql.length() > 0) {
-                        encoder.print("<sql adapter-class=\"");
-                        encoder.print(key);
-                        encoder.print("\"><![CDATA[");
-                        encoder.print(sql);
-                        encoder.println("]]></sql>");
-                    }
-                }
-            }
-        }
-
-        // TODO: support parameter encoding
-
-        encoder.indent(-1);
-        encoder.println("</query>");
-    }
-
-    /**
-     * Initializes query parameters using a set of properties.
-     * 
-     * @since 1.1
-     */
-    public void initWithProperties(Map<String, ?> properties) {
-        // must init defaults even if properties are empty
-        metaData.initWithProperties(properties);
-
-        if (properties == null) {
-            properties = Collections.EMPTY_MAP;
-        }
-
-        Object columnNamesCapitalization = properties
-                .get(COLUMN_NAME_CAPITALIZATION_PROPERTY);
-        this.columnNamesCapitalization = (columnNamesCapitalization != null)
-                ? CapsStrategy
-                        
.valueOf(columnNamesCapitalization.toString().toUpperCase())
-                : null;
-    }
-
-    /**
-     * Returns an iterator over parameter sets. Each element returned from the 
iterator is
-     * a java.util.Map.
-     */
-    public Iterator<?> parametersIterator() {
-        return (parameters == null || parameters.length == 0) ? IteratorUtils
-                .emptyIterator() : 
IteratorUtils.transformedIterator(IteratorUtils
-                .arrayIterator(parameters), nullMapTransformer);
-    }
-
-    /**
-     * Returns the number of parameter sets.
-     */
-    public int parametersSize() {
-        return (parameters != null) ? parameters.length : 0;
-    }
-
-    /**
-     * Returns a new query built using this query as a prototype and a new set 
of
-     * parameters.
-     */
-    public SQLTemplate queryWithParameters(Map<String, ?>... parameters) {
-        // create a query replica
-        SQLTemplate query = new SQLTemplate();
-
-        query.setRoot(root);
-        query.setDefaultTemplate(getDefaultTemplate());
-
-        if (templates != null) {
-            query.templates = new HashMap<String, String>(templates);
-        }
-
-        query.metaData.copyFromInfo(this.metaData);
-        query.setParameters(parameters);
-        
query.setColumnNamesCapitalization(this.getColumnNamesCapitalization());
-
-        return query;
-    }
-
-    /**
-     * Creates and returns a new SQLTemplate built using this query as a 
prototype and
-     * substituting template parameters with the values from the map.
-     * 
-     * @since 1.1
-     */
-    public Query createQuery(Map<String, ?> parameters) {
-        return queryWithParameters(parameters);
-    }
-
-    /**
-     * @since 3.0
-     */
-    public QueryCacheStrategy getCacheStrategy() {
-        return metaData.getCacheStrategy();
-    }
-
-    /**
-     * @since 3.0
-     */
-    public void setCacheStrategy(QueryCacheStrategy strategy) {
-        metaData.setCacheStrategy(strategy);
-    }
-
-    /**
-     * @since 3.0
-     */
-    public String[] getCacheGroups() {
-        return metaData.getCacheGroups();
-    }
-
-    /**
-     * @since 3.0
-     */
-    public void setCacheGroups(String... cacheGroups) {
-        this.metaData.setCacheGroups(cacheGroups);
-    }
-    
-    /**
-     * Instructs Cayenne to look for query results in the "local" cache when
-     * running the query. This is a short-hand notation for:
-     * 
-     * <pre>
-     * query.setCacheStrategy(QueryCacheStrategy.LOCAL_CACHE);
-     * query.setCacheGroups(&quot;group1&quot;, &quot;group2&quot;);
-     * </pre>
-     * 
-     * @since 4.0
-     */
-    public void useLocalCache(String... cacheGroups) {
-        setCacheStrategy(QueryCacheStrategy.LOCAL_CACHE);
-        setCacheGroups(cacheGroups);
-    }
-
-    /**
-     * Instructs Cayenne to look for query results in the "shared" cache when
-     * running the query. This is a short-hand notation for:
-     * 
-     * <pre>
-     * query.setCacheStrategy(QueryCacheStrategy.SHARED_CACHE);
-     * query.setCacheGroups(&quot;group1&quot;, &quot;group2&quot;);
-     * </pre>
-     * 
-     * @since 4.0
-     */
-    public void useSharedCache(String... cacheGroups) {
-        setCacheStrategy(QueryCacheStrategy.SHARED_CACHE);
-        setCacheGroups(cacheGroups);
-    }
-
-    public int getFetchLimit() {
-        return metaData.getFetchLimit();
-    }
-
-    public void setFetchLimit(int fetchLimit) {
-        this.metaData.setFetchLimit(fetchLimit);
-    }
-
-    /**
-     * @since 3.0
-     */
-    public int getFetchOffset() {
-        return metaData.getFetchOffset();
-    }
-
-    /**
-     * @since 3.0
-     */
-    public void setFetchOffset(int fetchOffset) {
-        metaData.setFetchOffset(fetchOffset);
-    }
-
-    public int getPageSize() {
-        return metaData.getPageSize();
-    }
-
-    public void setPageSize(int pageSize) {
-        metaData.setPageSize(pageSize);
-    }
-
-    public void setFetchingDataRows(boolean flag) {
-        metaData.setFetchingDataRows(flag);
-    }
-
-    public boolean isFetchingDataRows() {
-        return metaData.isFetchingDataRows();
-    }
-
-    /**
-     * Returns default SQL template for this query.
-     */
-    public String getDefaultTemplate() {
-        return defaultTemplate;
-    }
-
-    /**
-     * Sets default SQL template for this query.
-     */
-    public void setDefaultTemplate(String string) {
-        defaultTemplate = string;
-    }
-
-    /**
-     * Returns a template for key, or a default template if a template for key 
is not
-     * found.
-     */
-    public synchronized String getTemplate(String key) {
-        if (templates == null) {
-            return defaultTemplate;
-        }
-
-        String template = templates.get(key);
-        return (template != null) ? template : defaultTemplate;
-    }
-
-    /**
-     * Returns template for key, or null if there is no template configured 
for this key.
-     * Unlike {@link #getTemplate(String)}this method does not return a 
default template
-     * as a failover strategy, rather it returns null.
-     */
-    public synchronized String getCustomTemplate(String key) {
-        return (templates != null) ? templates.get(key) : null;
-    }
-
-    /**
-     * Adds a SQL template string for a given key. Note the the keys 
understood by Cayenne
-     * must be fully qualified adapter class names. This way the framework can 
related
-     * current DataNode to the right template. E.g.
-     * "org.apache.cayenne.dba.oracle.OracleAdapter" is a key that should be 
used to setup
-     * an Oracle-specific template.
-     * 
-     * @see #setDefaultTemplate(String)
-     */
-    public synchronized void setTemplate(String key, String template) {
-        if (templates == null) {
-            templates = new HashMap<String, String>();
-        }
-
-        templates.put(key, template);
-    }
-
-    public synchronized void removeTemplate(String key) {
-        if (templates != null) {
-            templates.remove(key);
-        }
-    }
-
-    /**
-     * Returns a collection of configured template keys.
-     */
-    public synchronized Collection<String> getTemplateKeys() {
-        return (templates != null) ? 
Collections.unmodifiableCollection(templates
-                .keySet()) : Collections.EMPTY_LIST;
-    }
-
-    /**
-     * Utility method to get the first set of parameters, since most queries 
will only
-     * have one.
-     */
-    public Map<String, ?> getParameters() {
-        Map<String, ?> map = (parameters != null && parameters.length > 0)
-                ? parameters[0]
-                : null;
-        return (map != null) ? map : Collections.EMPTY_MAP;
-    }
-
-    /**
-     * Utility method to initialize query with one or more sets of parameters.
-     */
-    public void setParameters(Map<String, ?>... parameters) {
-
-        if (parameters == null) {
-            this.parameters = null;
-        }
-        else {
-            // clone parameters to ensure that we don't have immutable maps 
that are not
-            // serializable with Hessian...
-            this.parameters = new Map[parameters.length];
-            for (int i = 0; i < parameters.length; i++) {
-                this.parameters[i] = parameters[i] != null ? new 
HashMap<String, Object>(
-                        parameters[i]) : new HashMap<String, Object>();
-            }
-        }
-    }
-
-    /**
-     * @since 1.2
-     */
-    public PrefetchTreeNode getPrefetchTree() {
-        return metaData.getPrefetchTree();
-    }
-
-    /**
-     * Adds a prefetch.
-     * 
-     * @since 1.2
-     */
-    public PrefetchTreeNode addPrefetch(String prefetchPath) {
-        // by default use JOINT_PREFETCH_SEMANTICS
-        return metaData.addPrefetch(
-                prefetchPath,
-                PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
-    }
-
-    /**
-     * @since 1.2
-     */
-    public void removePrefetch(String prefetch) {
-        metaData.removePrefetch(prefetch);
-    }
-
-    /**
-     * Adds all prefetches from a provided collection.
-     * 
-     * @since 1.2
-     */
-    public void addPrefetches(Collection<String> prefetches) {
-        metaData.addPrefetches(prefetches, 
PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
-    }
-
-    /**
-     * Clears all prefetches.
-     * 
-     * @since 1.2
-     */
-    public void clearPrefetches() {
-        metaData.clearPrefetches();
-    }
-
-    /**
-     * Returns a column name capitalization policy applied to selecting 
queries. This is
-     * used to simplify mapping of the queries like "SELECT * FROM ...", 
ensuring that a
-     * chosen Cayenne column mapping strategy (e.g. all column names in 
uppercase) is
-     * portable across database engines that can have varying default 
capitalization.
-     * Default (null) value indicates that column names provided in result set 
are used
-     * unchanged.
-     * 
-     * @since 3.0
-     */
-    public CapsStrategy getColumnNamesCapitalization() {
-        return columnNamesCapitalization != null
-                ? columnNamesCapitalization
-                : CapsStrategy.DEFAULT;
-    }
-
-    /**
-     * Sets a column name capitalization policy applied to selecting queries. 
This is used
-     * to simplify mapping of the queries like "SELECT * FROM ...", ensuring 
that a chosen
-     * Cayenne column mapping strategy (e.g. all column names in uppercase) is 
portable
-     * across database engines that can have varying default capitalization. 
Default
-     * (null) value indicates that column names provided in result set are 
used unchanged.
-     * <p>
-     * Note that while a non-default setting is useful for queries that do not 
rely on a
-     * #result directive to describe columns, it works for all SQLTemplates 
the same way.
-     * 
-     * @since 3.0
-     */
-    public void setColumnNamesCapitalization(CapsStrategy 
columnNameCapitalization) {
-        this.columnNamesCapitalization = columnNameCapitalization;
-    }
-
-    /**
-     * Sets an optional explicit mapping of the result set. If result set 
mapping is
-     * specified, the result of SQLTemplate may not be a normal list of 
Persistent objects
-     * or DataRows, instead it will follow the {@link SQLResult} rules.
-     * 
-     * @since 3.0
-     */
-    public void setResult(SQLResult resultSet) {
-        this.result = resultSet;
-    }
-
-    /**
-     * @since 3.0
-     */
-    public SQLResult getResult() {
-        return result;
-    }
-
-    /**
-     * Sets statement's fetch size (0 for no default size)
-     * 
-     * @since 3.0
-     */
-    public void setStatementFetchSize(int size) {
-        metaData.setStatementFetchSize(size);
-    }
-
-    /**
-     * @return statement's fetch size
-     * @since 3.0
-     */
-    public int getStatementFetchSize() {
-        return metaData.getStatementFetchSize();
-    }
-
-    /**
-     * Returns a name of the DataNode to use with this SQLTemplate. This
-     * information will be used during query execution if no other routing
-     * information is provided such as entity name or class, etc.
-     * 
-     * @since 4.0
-     */
-    public String getDataNodeName() {
-        return dataNodeName;
-    }
-
-    /**
-     * Sets a name of the DataNode to use with this SQLTemplate. This
-     * information will be used during query execution if no other routing
-     * information is provided such as entity name or class, etc.
-     * 
-     * @since 4.0
-     */
-    public void setDataNodeName(String dataNodeName) {
-        this.dataNodeName = dataNodeName;
-    }
+ XMLSerializable {
+
+       private static final long serialVersionUID = -3073521388289663641L;
+
+       static final String COLUMN_NAME_CAPITALIZATION_PROPERTY = 
"cayenne.SQLTemplate.columnNameCapitalization";
+
+       private static final Transformer nullMapTransformer = new Transformer() 
{
+
+               public Object transform(Object input) {
+                       return (input != null) ? input : Collections.EMPTY_MAP;
+               }
+       };
+
+       protected String defaultTemplate;
+       protected Map<String, String> templates;
+       protected Map<String, ?>[] parameters;
+       protected CapsStrategy columnNamesCapitalization;
+       protected SQLResult result;
+       private String dataNodeName;
+
+       SQLTemplateMetadata metaData = new SQLTemplateMetadata();
+
+       /**
+        * Creates an empty SQLTemplate. Note this constructor does not specify 
the
+        * "root" of the query, so a user must call "setRoot" later to make sure
+        * SQLTemplate can be executed.
+        * 
+        * @since 1.2
+        */
+       public SQLTemplate() {
+       }
+
+       /**
+        * Creates a SQLTemplate without an explicit root.
+        * 
+        * @since 4.0
+        */
+       public SQLTemplate(String defaultTemplate, boolean isFetchingDataRows) {
+               setDefaultTemplate(defaultTemplate);
+               setRoot(null);
+               setFetchingDataRows(isFetchingDataRows);
+       }
+
+       @Override
+       public void setRoot(Object value) {
+               // allow null root...
+               if (value == null) {
+                       this.root = value;
+               } else {
+                       super.setRoot(value);
+               }
+       }
+
+       @Override
+       public void route(QueryRouter router, EntityResolver resolver, Query 
substitutedQuery) {
+               DataMap map = getMetaData(resolver).getDataMap();
+
+               QueryEngine engine;
+               if (map != null) {
+                       engine = router.engineForDataMap(map);
+               } else {
+                       engine = router.engineForName(getDataNodeName());
+               }
+
+               router.route(engine, this, substitutedQuery);
+       }
+
+       /**
+        * @since 3.1
+        */
+       public SQLTemplate(DataMap rootMap, String defaultTemplate, boolean 
isFetchingDataRows) {
+               setDefaultTemplate(defaultTemplate);
+               setRoot(rootMap);
+               setFetchingDataRows(isFetchingDataRows);
+       }
+
+       /**
+        * @since 1.2
+        */
+       public SQLTemplate(ObjEntity rootEntity, String defaultTemplate) {
+               setDefaultTemplate(defaultTemplate);
+               setRoot(rootEntity);
+       }
+
+       /**
+        * @since 1.2
+        */
+       public SQLTemplate(Class<?> rootClass, String defaultTemplate) {
+               setDefaultTemplate(defaultTemplate);
+               setRoot(rootClass);
+       }
+
+       /**
+        * @since 1.2
+        */
+       public SQLTemplate(DbEntity rootEntity, String defaultTemplate) {
+               setDefaultTemplate(defaultTemplate);
+               setRoot(rootEntity);
+       }
+
+       /**
+        * @since 1.2
+        */
+       public SQLTemplate(String objEntityName, String defaultTemplate) {
+               setRoot(objEntityName);
+               setDefaultTemplate(defaultTemplate);
+       }
+
+       /**
+        * @since 1.2
+        */
+       @Override
+       public QueryMetadata getMetaData(EntityResolver resolver) {
+               metaData.resolve(root, resolver, this);
+               return metaData;
+       }
+
+       /**
+        * Calls <em>sqlAction(this)</em> on the visitor.
+        * 
+        * @since 1.2
+        */
+       @Override
+       public SQLAction createSQLAction(SQLActionVisitor visitor) {
+               return visitor.sqlAction(this);
+       }
+
+       /**
+        * Prints itself as XML to the provided PrintWriter.
+        * 
+        * @since 1.1
+        */
+       @Override
+       public void encodeAsXML(XMLEncoder encoder) {
+               encoder.print("<query name=\"");
+               encoder.print(getName());
+               encoder.print("\" factory=\"");
+               encoder.print("org.apache.cayenne.map.SQLTemplateBuilder");
+
+               String rootString = null;
+               String rootType = null;
+
+               if (root instanceof String) {
+                       rootType = MapLoader.OBJ_ENTITY_ROOT;
+                       rootString = root.toString();
+               } else if (root instanceof ObjEntity) {
+                       rootType = MapLoader.OBJ_ENTITY_ROOT;
+                       rootString = ((ObjEntity) root).getName();
+               } else if (root instanceof DbEntity) {
+                       rootType = MapLoader.DB_ENTITY_ROOT;
+                       rootString = ((DbEntity) root).getName();
+               } else if (root instanceof Procedure) {
+                       rootType = MapLoader.PROCEDURE_ROOT;
+                       rootString = ((Procedure) root).getName();
+               } else if (root instanceof Class<?>) {
+                       rootType = MapLoader.JAVA_CLASS_ROOT;
+                       rootString = ((Class<?>) root).getName();
+               } else if (root instanceof DataMap) {
+                       rootType = MapLoader.DATA_MAP_ROOT;
+                       rootString = ((DataMap) root).getName();
+               }
+
+               if (rootType != null) {
+                       encoder.print("\" root=\"");
+                       encoder.print(rootType);
+                       encoder.print("\" root-name=\"");
+                       encoder.print(rootString);
+               }
+
+               encoder.println("\">");
+
+               encoder.indent(1);
+
+               metaData.encodeAsXML(encoder);
+
+               if (getColumnNamesCapitalization() != CapsStrategy.DEFAULT) {
+                       
encoder.printProperty(COLUMN_NAME_CAPITALIZATION_PROPERTY, 
getColumnNamesCapitalization().name());
+               }
+
+               // encode default SQL
+               if (defaultTemplate != null) {
+                       encoder.print("<sql><![CDATA[");
+                       encoder.print(defaultTemplate);
+                       encoder.println("]]></sql>");
+               }
+
+               // encode adapter SQL
+               if (templates != null && !templates.isEmpty()) {
+
+                       // sorting entries by adapter name
+                       TreeSet<String> keys = new 
TreeSet<String>(templates.keySet());
+                       for (String key : keys) {
+                               String value = templates.get(key);
+
+                               if (key != null && value != null) {
+                                       String sql = value.trim();
+                                       if (sql.length() > 0) {
+                                               encoder.print("<sql 
adapter-class=\"");
+                                               encoder.print(key);
+                                               encoder.print("\"><![CDATA[");
+                                               encoder.print(sql);
+                                               encoder.println("]]></sql>");
+                                       }
+                               }
+                       }
+               }
+
+               // TODO: support parameter encoding
+
+               encoder.indent(-1);
+               encoder.println("</query>");
+       }
+
+       /**
+        * Initializes query parameters using a set of properties.
+        * 
+        * @since 1.1
+        */
+       public void initWithProperties(Map<String, ?> properties) {
+               // must init defaults even if properties are empty
+               metaData.initWithProperties(properties);
+
+               if (properties == null) {
+                       properties = Collections.emptyMap();
+               }
+
+               Object columnNamesCapitalization = 
properties.get(COLUMN_NAME_CAPITALIZATION_PROPERTY);
+               this.columnNamesCapitalization = (columnNamesCapitalization != 
null) ? CapsStrategy
+                               
.valueOf(columnNamesCapitalization.toString().toUpperCase()) : null;
+       }
+
+       /**
+        * Returns an iterator over parameter sets. Each element returned from 
the
+        * iterator is a java.util.Map.
+        */
+       public Iterator<?> parametersIterator() {
+               return (parameters == null || parameters.length == 0) ? 
IteratorUtils.emptyIterator() : IteratorUtils
+                               
.transformedIterator(IteratorUtils.arrayIterator(parameters), 
nullMapTransformer);
+       }
+
+       /**
+        * Returns the number of parameter sets.
+        */
+       public int parametersSize() {
+               return (parameters != null) ? parameters.length : 0;
+       }
+
+       /**
+        * Returns a new query built using this query as a prototype and a new 
set
+        * of parameters.
+        */
+       public SQLTemplate queryWithParameters(Map<String, ?>... parameters) {
+               // create a query replica
+               SQLTemplate query = new SQLTemplate();
+
+               query.setRoot(root);
+               query.setDefaultTemplate(getDefaultTemplate());
+
+               if (templates != null) {
+                       query.templates = new HashMap<String, 
String>(templates);
+               }
+
+               query.metaData.copyFromInfo(this.metaData);
+               query.setParameters(parameters);
+               
query.setColumnNamesCapitalization(this.getColumnNamesCapitalization());
+
+               return query;
+       }
+
+       /**
+        * Creates and returns a new SQLTemplate built using this query as a
+        * prototype and substituting template parameters with the values from 
the
+        * map.
+        * 
+        * @since 1.1
+        */
+       @Override
+       public Query createQuery(Map<String, ?> parameters) {
+               return queryWithParameters(parameters);
+       }
+
+       /**
+        * @since 3.0
+        */
+       public QueryCacheStrategy getCacheStrategy() {
+               return metaData.getCacheStrategy();
+       }
+
+       /**
+        * @since 3.0
+        */
+       public void setCacheStrategy(QueryCacheStrategy strategy) {
+               metaData.setCacheStrategy(strategy);
+       }
+
+       /**
+        * @since 3.0
+        */
+       public String[] getCacheGroups() {
+               return metaData.getCacheGroups();
+       }
+
+       /**
+        * @since 3.0
+        */
+       public void setCacheGroups(String... cacheGroups) {
+               this.metaData.setCacheGroups(cacheGroups);
+       }
+
+       /**
+        * Instructs Cayenne to look for query results in the "local" cache when
+        * running the query. This is a short-hand notation for:
+        * 
+        * <pre>
+        * query.setCacheStrategy(QueryCacheStrategy.LOCAL_CACHE);
+        * query.setCacheGroups(&quot;group1&quot;, &quot;group2&quot;);
+        * </pre>
+        * 
+        * @since 4.0
+        */
+       public void useLocalCache(String... cacheGroups) {
+               setCacheStrategy(QueryCacheStrategy.LOCAL_CACHE);
+               setCacheGroups(cacheGroups);
+       }
+
+       /**
+        * Instructs Cayenne to look for query results in the "shared" cache 
when
+        * running the query. This is a short-hand notation for:
+        * 
+        * <pre>
+        * query.setCacheStrategy(QueryCacheStrategy.SHARED_CACHE);
+        * query.setCacheGroups(&quot;group1&quot;, &quot;group2&quot;);
+        * </pre>
+        * 
+        * @since 4.0
+        */
+       public void useSharedCache(String... cacheGroups) {
+               setCacheStrategy(QueryCacheStrategy.SHARED_CACHE);
+               setCacheGroups(cacheGroups);
+       }
+
+       public int getFetchLimit() {
+               return metaData.getFetchLimit();
+       }
+
+       public void setFetchLimit(int fetchLimit) {
+               this.metaData.setFetchLimit(fetchLimit);
+       }
+
+       /**
+        * @since 3.0
+        */
+       public int getFetchOffset() {
+               return metaData.getFetchOffset();
+       }
+
+       /**
+        * @since 3.0
+        */
+       public void setFetchOffset(int fetchOffset) {
+               metaData.setFetchOffset(fetchOffset);
+       }
+
+       public int getPageSize() {
+               return metaData.getPageSize();
+       }
+
+       public void setPageSize(int pageSize) {
+               metaData.setPageSize(pageSize);
+       }
+
+       public void setFetchingDataRows(boolean flag) {
+               metaData.setFetchingDataRows(flag);
+       }
+
+       public boolean isFetchingDataRows() {
+               return metaData.isFetchingDataRows();
+       }
+
+       /**
+        * Returns default SQL template for this query.
+        */
+       public String getDefaultTemplate() {
+               return defaultTemplate;
+       }
+
+       /**
+        * Sets default SQL template for this query.
+        */
+       public void setDefaultTemplate(String string) {
+               defaultTemplate = string;
+       }
+
+       /**
+        * Returns a template for key, or a default template if a template for 
key
+        * is not found.
+        */
+       public synchronized String getTemplate(String key) {
+               if (templates == null) {
+                       return defaultTemplate;
+               }
+
+               String template = templates.get(key);
+               return (template != null) ? template : defaultTemplate;
+       }
+
+       /**
+        * Returns template for key, or null if there is no template configured 
for
+        * this key. Unlike {@link #getTemplate(String)}this method does not 
return
+        * a default template as a failover strategy, rather it returns null.
+        */
+       public synchronized String getCustomTemplate(String key) {
+               return (templates != null) ? templates.get(key) : null;
+       }
+
+       /**
+        * Adds a SQL template string for a given key. Note the the keys 
understood
+        * by Cayenne must be fully qualified adapter class names. This way the
+        * framework can related current DataNode to the right template. E.g.
+        * "org.apache.cayenne.dba.oracle.OracleAdapter" is a key that should be
+        * used to setup an Oracle-specific template.
+        * 
+        * @see #setDefaultTemplate(String)
+        */
+       public synchronized void setTemplate(String key, String template) {
+               if (templates == null) {
+                       templates = new HashMap<String, String>();
+               }
+
+               templates.put(key, template);
+       }
+
+       public synchronized void removeTemplate(String key) {
+               if (templates != null) {
+                       templates.remove(key);
+               }
+       }
+
+       /**
+        * Returns a collection of configured template keys.
+        */
+       public synchronized Collection<String> getTemplateKeys() {
+               return (templates != null) ? templates.keySet() : 
Collections.<String>emptyList();
+       }
+
+       /**
+        * Utility method to get the first set of parameters, since most queries
+        * will only have one.
+        */
+       public Map<String, ?> getParameters() {
+               Map<String, ?> map = (parameters != null && parameters.length > 
0) ? parameters[0] : null;
+               return (map != null) ? map : Collections.<String, Object> 
emptyMap();
+       }
+
+       /**
+        * Utility method to initialize query with one or more sets of 
parameters.
+        */
+       public void setParameters(Map<String, ?>... parameters) {
+
+               if (parameters == null) {
+                       this.parameters = null;
+               } else {
+                       // clone parameters to ensure that we don't have 
immutable maps that
+                       // are not serializable with Hessian...
+                       this.parameters = new Map[parameters.length];
+                       for (int i = 0; i < parameters.length; i++) {
+                               this.parameters[i] = parameters[i] != null ? 
new HashMap<String, Object>(parameters[i])
+                                               : new HashMap<String, Object>();
+                       }
+               }
+       }
+
+       /**
+        * @since 1.2
+        */
+       public PrefetchTreeNode getPrefetchTree() {
+               return metaData.getPrefetchTree();
+       }
+
+       /**
+        * Adds a prefetch.
+        * 
+        * @since 1.2
+        */
+       public PrefetchTreeNode addPrefetch(String prefetchPath) {
+               // by default use JOINT_PREFETCH_SEMANTICS
+               return metaData.addPrefetch(prefetchPath, 
PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+       }
+
+       /**
+        * @since 1.2
+        */
+       public void removePrefetch(String prefetch) {
+               metaData.removePrefetch(prefetch);
+       }
+
+       /**
+        * Adds all prefetches from a provided collection.
+        * 
+        * @since 1.2
+        */
+       public void addPrefetches(Collection<String> prefetches) {
+               metaData.addPrefetches(prefetches, 
PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+       }
+
+       /**
+        * Clears all prefetches.
+        * 
+        * @since 1.2
+        */
+       public void clearPrefetches() {
+               metaData.clearPrefetches();
+       }
+
+       /**
+        * Returns a column name capitalization policy applied to selecting 
queries.
+        * This is used to simplify mapping of the queries like "SELECT * FROM 
...",
+        * ensuring that a chosen Cayenne column mapping strategy (e.g. all 
column
+        * names in uppercase) is portable across database engines that can have
+        * varying default capitalization. Default (null) value indicates that
+        * column names provided in result set are used unchanged.
+        * 
+        * @since 3.0
+        */
+       public CapsStrategy getColumnNamesCapitalization() {
+               return columnNamesCapitalization != null ? 
columnNamesCapitalization : CapsStrategy.DEFAULT;
+       }
+
+       /**
+        * Sets a column name capitalization policy applied to selecting 
queries.
+        * This is used to simplify mapping of the queries like "SELECT * FROM 
...",
+        * ensuring that a chosen Cayenne column mapping strategy (e.g. all 
column
+        * names in uppercase) is portable across database engines that can have
+        * varying default capitalization. Default (null) value indicates that
+        * column names provided in result set are used unchanged.
+        * <p>
+        * Note that while a non-default setting is useful for queries that do 
not
+        * rely on a #result directive to describe columns, it works for all
+        * SQLTemplates the same way.
+        * 
+        * @since 3.0
+        */
+       public void setColumnNamesCapitalization(CapsStrategy 
columnNameCapitalization) {
+               this.columnNamesCapitalization = columnNameCapitalization;
+       }
+
+       /**
+        * Sets an optional explicit mapping of the result set. If result set
+        * mapping is specified, the result of SQLTemplate may not be a normal 
list
+        * of Persistent objects or DataRows, instead it will follow the
+        * {@link SQLResult} rules.
+        * 
+        * @since 3.0
+        */
+       public void setResult(SQLResult resultSet) {
+               this.result = resultSet;
+       }
+
+       /**
+        * @since 3.0
+        */
+       public SQLResult getResult() {
+               return result;
+       }
+
+       /**
+        * Sets statement's fetch size (0 for no default size)
+        * 
+        * @since 3.0
+        */
+       public void setStatementFetchSize(int size) {
+               metaData.setStatementFetchSize(size);
+       }
+
+       /**
+        * @return statement's fetch size
+        * @since 3.0
+        */
+       public int getStatementFetchSize() {
+               return metaData.getStatementFetchSize();
+       }
+
+       /**
+        * Returns a name of the DataNode to use with this SQLTemplate. This
+        * information will be used during query execution if no other routing
+        * information is provided such as entity name or class, etc.
+        * 
+        * @since 4.0
+        */
+       public String getDataNodeName() {
+               return dataNodeName;
+       }
+
+       /**
+        * Sets a name of the DataNode to use with this SQLTemplate. This
+        * information will be used during query execution if no other routing
+        * information is provided such as entity name or class, etc.
+        * 
+        * @since 4.0
+        */
+       public void setDataNodeName(String dataNodeName) {
+               this.dataNodeName = dataNodeName;
+       }
 }

Reply via email to