001: /*
002: * Copyright 2002-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.jdbc.object;
018:
019: import java.util.List;
020: import java.util.Map;
021:
022: import javax.sql.DataSource;
023:
024: import org.springframework.jdbc.core.CallableStatementCreator;
025: import org.springframework.jdbc.core.CallableStatementCreatorFactory;
026: import org.springframework.jdbc.core.ParameterMapper;
027: import org.springframework.jdbc.core.SqlParameter;
028: import org.springframework.jdbc.core.SqlReturnResultSet;
029:
030: /**
031: * RdbmsOperation using a JdbcTemplate and representing a SQL-based
032: * call such as a stored procedure or a stored function.
033: *
034: * <p>Configures a CallableStatementCreatorFactory based on the declared
035: * parameters.
036: *
037: * @author Rod Johnson
038: * @author Thomas Risberg
039: * @see CallableStatementCreatorFactory
040: */
041: public abstract class SqlCall extends RdbmsOperation {
042:
043: /**
044: * Object enabling us to create CallableStatementCreators
045: * efficiently, based on this class's declared parameters.
046: */
047: private CallableStatementCreatorFactory callableStatementFactory;
048:
049: /**
050: * Flag used to indicate that this call is for a function and to
051: * use the {? = call get_invoice_count(?)} syntax.
052: */
053: private boolean function = false;
054:
055: /**
056: * Flag used to indicate that the sql for this call should be used exactly as it is
057: * defined. No need to add the escape syntax and parameter place holders.
058: */
059: private boolean sqlReadyForUse = false;
060:
061: /**
062: * Call string as defined in java.sql.CallableStatement.
063: * String of form {call add_invoice(?, ?, ?)}
064: * or {? = call get_invoice_count(?)} if isFunction is set to true
065: * Updated after each parameter is added.
066: */
067: private String callString;
068:
069: /**
070: * Constructor to allow use as a JavaBean.
071: * A DataSource, SQL and any parameters must be supplied before
072: * invoking the <code>compile</code> method and using this object.
073: * @see #setDataSource
074: * @see #setSql
075: * @see #compile
076: */
077: public SqlCall() {
078: }
079:
080: /**
081: * Create a new SqlCall object with SQL, but without parameters.
082: * Must add parameters or settle with none.
083: * @param ds DataSource to obtain connections from
084: * @param sql SQL to execute
085: */
086: public SqlCall(DataSource ds, String sql) {
087: setDataSource(ds);
088: setSql(sql);
089: }
090:
091: /**
092: * Set whether this call is for a function.
093: */
094: public void setFunction(boolean function) {
095: this .function = function;
096: }
097:
098: /**
099: * Return whether this call is for a function.
100: */
101: public boolean isFunction() {
102: return function;
103: }
104:
105: /**
106: * Set whether the SQL can be used as is.
107: */
108: public void setSqlReadyForUse(boolean sqlReadyForUse) {
109: this .sqlReadyForUse = sqlReadyForUse;
110: }
111:
112: /**
113: * Return whether the SQL can be used as is.
114: */
115: public boolean isSqlReadyForUse() {
116: return sqlReadyForUse;
117: }
118:
119: /**
120: * Overridden method to configure the CallableStatementCreatorFactory
121: * based on our declared parameters.
122: * @see RdbmsOperation#compileInternal()
123: */
124: protected final void compileInternal() {
125: if (isSqlReadyForUse()) {
126: this .callString = getSql();
127: } else {
128: List parameters = getDeclaredParameters();
129: int parameterCount = 0;
130: if (isFunction()) {
131: this .callString = "{? = call " + getSql() + "(";
132: parameterCount = -1;
133: } else {
134: this .callString = "{call " + getSql() + "(";
135: }
136: for (int i = 0; i < parameters.size(); i++) {
137: SqlParameter parameter = (SqlParameter) parameters
138: .get(i);
139: if (!(parameter instanceof SqlReturnResultSet)) {
140: if (parameterCount > 0) {
141: this .callString += ", ";
142: }
143: if (parameterCount >= 0) {
144: this .callString += "?";
145: }
146: parameterCount++;
147: }
148: }
149: this .callString += ")}";
150: }
151: if (logger.isDebugEnabled()) {
152: logger.debug("Compiled stored procedure. Call string is ["
153: + getCallString() + "]");
154: }
155:
156: this .callableStatementFactory = new CallableStatementCreatorFactory(
157: getCallString(), getDeclaredParameters());
158: this .callableStatementFactory
159: .setResultSetType(getResultSetType());
160: this .callableStatementFactory
161: .setUpdatableResults(isUpdatableResults());
162: this .callableStatementFactory
163: .setNativeJdbcExtractor(getJdbcTemplate()
164: .getNativeJdbcExtractor());
165:
166: onCompileInternal();
167: }
168:
169: /**
170: * Hook method that subclasses may override to react to compilation.
171: * This implementation does nothing.
172: */
173: protected void onCompileInternal() {
174: }
175:
176: /**
177: * Get the call string.
178: */
179: public String getCallString() {
180: return this .callString;
181: }
182:
183: /**
184: * Return a CallableStatementCreator to perform an operation
185: * with this parameters.
186: * @param inParams parameters. May be <code>null</code>.
187: */
188: protected CallableStatementCreator newCallableStatementCreator(
189: Map inParams) {
190: return this .callableStatementFactory
191: .newCallableStatementCreator(inParams);
192: }
193:
194: /**
195: * Return a CallableStatementCreator to perform an operation
196: * with the parameters returned from this ParameterMapper.
197: * @param inParamMapper parametermapper. May not be <code>null</code>.
198: */
199: protected CallableStatementCreator newCallableStatementCreator(
200: ParameterMapper inParamMapper) {
201: return this.callableStatementFactory
202: .newCallableStatementCreator(inParamMapper);
203: }
204:
205: }
|