org.apache.cayenne.query.ProcedureQuery Maven / Gradle / Ivy
Show all versions of cayenne-client-nodeps
/*****************************************************************
* 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.query;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.cayenne.access.jdbc.ColumnDescriptor;
import org.apache.cayenne.access.jdbc.RowDescriptor;
import org.apache.cayenne.map.EntityResolver;
import org.apache.cayenne.map.Procedure;
import org.apache.cayenne.map.QueryBuilder;
import org.apache.cayenne.util.XMLEncoder;
import org.apache.cayenne.util.XMLSerializable;
/**
* A query based on Procedure. Can be used as a select query, or as a query of an
* arbitrary complexity, performing data modification, selecting data (possibly with
* multiple result sets per call), returning values via OUT parameters.
* Execution with DataContext
* Reading OUT parameters
*
* If a ProcedureQuery has OUT parameters, they are wrapped in a separate List in the
* query result. Such list will contain a single Map with OUT parameter values.
*
* Using ProcedureQuery as a GenericSelectQuery
*
* Executing ProcedureQuery via
* {@link org.apache.cayenne.access.DataContext#performQuery(Query)} makes sense only
* if the stored procedure returns a single result set (or alternatively returns a result
* via OUT parameters and no other result sets). It is still OK if data modification
* occurs as a side effect. However if the query returns more then one result set, a more
* generic form should be used:
* {@link org.apache.cayenne.access.DataContext#performGenericQuery(Query)}.
*
*
* @author Andrus Adamchik
*/
public class ProcedureQuery extends AbstractQuery implements GenericSelectQuery,
ParameterizedQuery, XMLSerializable {
/**
* If set, allows to fetch results as DataObjects.
*
* @since 1.1
* @deprecated since 1.2 'resultEntityName' must be used.
*/
protected String resultClassName;
/**
* @since 1.2
*/
protected String resultEntityName;
/**
* @since 1.2
*/
protected Class resultClass;
protected Map parameters = new HashMap();
/**
* @deprecated since 1.2 as this information is no longer relavant to Cayenne
*/
protected boolean selecting;
ProcedureQueryMetadata metaData = new ProcedureQueryMetadata();
// TODO: ColumnDescriptor is not XMLSerializable so we can't store
// it in a DataMap
/**
* @since 1.2
*/
protected List resultDescriptors;
/**
* Creates an empty procedure query.
*/
public ProcedureQuery() {
// for backwards compatibility we go against usual default...
metaData.setFetchingDataRows(true);
}
/**
* Creates a ProcedureQuery based on a Procedure object.
*/
public ProcedureQuery(Procedure procedure) {
// for backwards compatibility we go against usual default...
metaData.setFetchingDataRows(true);
setRoot(procedure);
}
/**
* Creates a ProcedureQuery based on a stored procedure.
*
* Performance Note: with current EntityResolver implementation it is preferrable to
* use Procedure object instead of String as a query root. String root can cause
* unneeded EntityResolver reindexing on every call. See this mailing list thread:
* http://objectstyle.org/cayenne/lists/cayenne-user/2005/01/0109.html
*
*
* @param procedureName A name of the stored procedure. For this query to work, a
* procedure with this name must be mapped in Cayenne.
*/
public ProcedureQuery(String procedureName) {
// for backwards compatibility we go against usual default...
metaData.setFetchingDataRows(true);
setRoot(procedureName);
}
/**
* @since 1.1
*/
public ProcedureQuery(Procedure procedure, Class resultType) {
setRoot(procedure);
this.resultClass = resultType;
// call this for backwards compatibility
setResultClassName(resultType != null ? resultType.getName() : null);
}
/**
*
* Performance Note: with current EntityResolver implementation it is preferrable to
* use Procedure object instead of String as a query root. String root can cause
* unneeded EntityResolver reindexing on every call. See this mailing list thread:
* http://objectstyle.org/cayenne/lists/cayenne-user/2005/01/0109.html
*
*
* @since 1.1
*/
public ProcedureQuery(String procedureName, Class resultType) {
setRoot(procedureName);
this.resultClass = resultType;
setResultClassName(resultType != null ? resultType.getName() : null);
}
/**
* @since 1.2
*/
public QueryMetadata getMetaData(EntityResolver resolver) {
metaData.resolve(root, resultClass != null
? (Object) resultClass
: resultEntityName, resolver, getName());
return metaData;
}
/**
* Returns a List of #{@link RowDescriptor} objects describing query ResultSets in
* the order they are returned by the stored procedure.
*
* Note that if a procedure returns ResultSet in an OUT parameter, it is returned
* prior to any other result sets (though in practice database engines usually support
* only one mechanism for returning result sets.
*
*
* @since 1.2
*/
public List getResultDescriptors() {
return resultDescriptors != null ? resultDescriptors : Collections.EMPTY_LIST;
}
/**
* Adds a descriptor for a single ResultSet. More than one descriptor can be added by
* calling this method multiple times in the order of described ResultSet appearance
* in the procedure results.
*
* @since 1.2
*/
public synchronized void addResultDescriptor(ColumnDescriptor[] descriptor) {
if (resultDescriptors == null) {
resultDescriptors = new ArrayList(2);
}
resultDescriptors.add(descriptor);
}
/**
* Removes result descriptor from the list of descriptors.
*
* @since 1.2
*/
public void removeResultDescriptor(ColumnDescriptor[] descriptor) {
if (resultDescriptors != null) {
resultDescriptors.remove(descriptor);
}
}
/**
* Calls "makeProcedure" on the visitor.
*
* @since 1.2
*/
public SQLAction createSQLAction(SQLActionVisitor visitor) {
return visitor.procedureAction(this);
}
/**
* Initializes query parameters using a set of properties.
*
* @since 1.1
*/
public void initWithProperties(Map properties) {
// must init defaults even if properties are empty
if (properties == null) {
properties = Collections.EMPTY_MAP;
}
metaData.initWithProperties(properties);
}
/**
* Prints itself as XML to the provided PrintWriter.
*
* @since 1.1
*/
public void encodeAsXML(XMLEncoder encoder) {
encoder.print("");
encoder.indent(1);
metaData.encodeAsXML(encoder);
encoder.indent(-1);
encoder.println(" ");
}
/**
* Creates and returns a new ProcedureQuery built using this query as a prototype and
* substituting template parameters with the values from the map.
*
* @since 1.1
*/
public Query createQuery(Map parameters) {
// create a query replica
ProcedureQuery query = new ProcedureQuery();
if (root != null) {
query.setRoot(root);
}
query.setResultClassName(resultClassName);
query.setResultEntityName(resultEntityName);
query.metaData.copyFromInfo(this.metaData);
query.setParameters(parameters);
// TODO: implement algorithm for building the name based on the original name and
// the hashcode of the map of parameters. This way query clone can take advantage
// of caching.
return query;
}
public String getCachePolicy() {
return metaData.getCachePolicy();
}
public void setCachePolicy(String policy) {
this.metaData.setCachePolicy(policy);
}
public int getFetchLimit() {
return metaData.getFetchLimit();
}
public void setFetchLimit(int fetchLimit) {
this.metaData.setFetchLimit(fetchLimit);
}
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();
}
public boolean isRefreshingObjects() {
return metaData.isRefreshingObjects();
}
public void setRefreshingObjects(boolean flag) {
metaData.setRefreshingObjects(flag);
}
public boolean isResolvingInherited() {
return metaData.isResolvingInherited();
}
public void setResolvingInherited(boolean b) {
metaData.setResolvingInherited(b);
}
/**
* Adds a named parameter to the internal map of parameters.
*
* @since 1.1
*/
public synchronized void addParameter(String name, Object value) {
parameters.put(name, value);
}
/**
* @since 1.1
*/
public synchronized void removeParameter(String name) {
parameters.remove(name);
}
/**
* Returns a map of procedure parameters.
*
* @since 1.1
*/
public Map getParameters() {
return parameters;
}
/**
* Sets a map of parameters.
*
* @since 1.1
*/
public synchronized void setParameters(Map parameters) {
this.parameters.clear();
if (parameters != null) {
this.parameters.putAll(parameters);
}
}
/**
* Cleans up all configured parameters.
*
* @since 1.1
*/
public synchronized void clearParameters() {
this.parameters.clear();
}
/**
* Returns an optional result type of the query.
*
* @since 1.1
* @deprecated since 1.2 use {@link #getResultEntityName()}
*/
public String getResultClassName() {
return resultClassName;
}
/**
* Returns Java class of the DataObjects returned by this query.
*
* @deprecated since 1.2
* @since 1.1
*/
public Class getResultClass(ClassLoader classLoader) {
return resultClass;
}
/**
* Sets optional result type of the query. A Class of the result type must be a
* DataObject implementation mapped in Cayenne.
*
* @since 1.1
* @deprecated since 1.2 use {@link #setResultEntityName(String)}
*/
public void setResultClassName(String resultClassName) {
this.resultClassName = resultClassName;
}
/**
* Returns true if ProcedureQuery is expected to return a ResultSet.
*
* @since 1.1
* @deprecated since 1.2 as this information is no longer relavant to Cayenne
*/
public boolean isSelecting() {
return selecting;
}
/**
* Sets whether ProcedureQuery is expected to return a ResultSet.
*
* @since 1.1
* @deprecated since 1.2 as this information is no longer relavant to Cayenne
*/
public void setSelecting(boolean b) {
selecting = b;
}
/**
* @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 prefetches) {
metaData.addPrefetches(prefetches, PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
}
/**
* Clears all prefetches.
*
* @since 1.2
*/
public void clearPrefetches() {
metaData.clearPrefetches();
}
/**
* @since 1.2
*/
public String getResultEntityName() {
return resultEntityName;
}
/**
* @since 1.2
*/
public void setResultEntityName(String resultEntityName) {
this.resultEntityName = resultEntityName;
}
}