Open Source Repository

Home /spring/spring-jdbc-3.0.5 | Repository Home



org/springframework/jdbc/object/StoredProcedure.java
/*
 * Copyright 2002-2008 the original author or authors.
 *
 * Licensed 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.springframework.jdbc.object;

import java.util.Map;
import java.util.HashMap;
import javax.sql.DataSource;

import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ParameterMapper;
import org.springframework.jdbc.core.SqlParameter;

/**
 * Superclass for object abstractions of RDBMS stored procedures.
 * This class is abstract and it is intended that subclasses will provide
 * a typed method for invocation that delegates to the supplied
 {@link #execute} method.
 *
 <p>The inherited <code>sql</code> property is the name of the stored
 * procedure in the RDBMS. Note that JDBC 3.0 introduces named parameters,
 * although the other features provided by this class are still necessary
 * in JDBC 3.0.
 *
 @author Rod Johnson
 @author Thomas Risberg
 @see #setSql
 */
public abstract class StoredProcedure extends SqlCall {

  /**
   * Allow use as a bean.
   */
  protected StoredProcedure() {
  }

  /**
   * Create a new object wrapper for a stored procedure.
   @param ds DataSource to use throughout the lifetime
   * of this object to obtain connections
   @param name name of the stored procedure in the database
   */
  protected StoredProcedure(DataSource ds, String name) {
    setDataSource(ds);
    setSql(name);
  }
  
  /**
   * Create a new object wrapper for a stored procedure.
   @param jdbcTemplate JdbcTemplate which wraps DataSource
   @param name name of the stored procedure in the database
   */
  protected StoredProcedure(JdbcTemplate jdbcTemplate, String name) {
    setJdbcTemplate(jdbcTemplate);
    setSql(name);
  }


  /**
   * StoredProcedure parameter Maps are by default allowed to contain
   * additional entries that are not actually used as parameters.
   */
  @Override
  protected boolean allowsUnusedParameters() {
    return true;
  }

  /**
   * Declare a parameter. Overridden method.
   * Parameters declared as <code>SqlParameter</code> and <code>SqlInOutParameter</code>
   * will always be used to provide input values.  In addition to this any parameter declared
   * as <code>SqlOutParameter</code> where an non-null input value is provided will also be used
   * as an input paraneter.
   <b>Note: Calls to declareParameter must be made in the same order as
   * they appear in the database's stored procedure parameter list.</b>
   * Names are purely used to help mapping.
   @param param parameter object
   */
  @Override
  public void declareParameter(SqlParameter paramthrows InvalidDataAccessApiUsageException {
    if (param.getName() == null) {
      throw new InvalidDataAccessApiUsageException("Parameters to stored procedures must have names as well as types");
    }
    super.declareParameter(param);
  }

  /**
   * Execute the stored procedure with the provided parameter values. This is
   * a convenience method where the order of the passed in parameter values
   * must match the order that the parameters where declared in.
   @param inParams variable number of input parameters. Output parameters should
   * not be included in this map.
   * It is legal for values to be <code>null</code>, and this will produce the
   * correct behavior using a NULL argument to the stored procedure.
   @return map of output params, keyed by name as in parameter declarations.
   * Output parameters will appear here, with their values after the
   * stored procedure has been called.
   */
  public Map<String, Object> execute(Object... inParams) {
    Map<String, Object> paramsToUse = new HashMap<String, Object>();
    validateParameters(inParams);
    int i = 0;
    for (SqlParameter sqlParameter : getDeclaredParameters()) {
      if (sqlParameter.isInputValueProvided()) {
        if (i < inParams.length) {
          paramsToUse.put(sqlParameter.getName(), inParams[i++]);
        }
      }
    }
    return getJdbcTemplate().call(newCallableStatementCreator(paramsToUse), getDeclaredParameters());
  }

  /**
   * Execute the stored procedure. Subclasses should define a strongly typed
   * execute method (with a meaningful name) that invokes this method, populating
   * the input map and extracting typed values from the output map. Subclass
   * execute methods will often take domain objects as arguments and return values.
   * Alternatively, they can return void.
   @param inParams map of input parameters, keyed by name as in parameter
   * declarations. Output parameters need not (but can) be included in this map.
   * It is legal for map entries to be <code>null</code>, and this will produce the
   * correct behavior using a NULL argument to the stored procedure.
   @return map of output params, keyed by name as in parameter declarations.
   * Output parameters will appear here, with their values after the
   * stored procedure has been called.
   */
  public Map<String, Object> execute(Map<String, ?> inParamsthrows DataAccessException {
    validateParameters(inParams.values().toArray());
    return getJdbcTemplate().call(newCallableStatementCreator(inParams), getDeclaredParameters());
  }

  /**
   * Execute the stored procedure. Subclasses should define a strongly typed
   * execute method (with a meaningful name) that invokes this method, passing in
   * a ParameterMapper that will populate the input map.  This allows mapping database 
   * specific features since the ParameterMapper has access to the Connection object.
   * The execute method is also responsible for extracting typed values from the output map. 
   * Subclass execute methods will often take domain objects as arguments and return values.
   * Alternatively, they can return void.
   @param inParamMapper map of input parameters, keyed by name as in parameter
   * declarations. Output parameters need not (but can) be included in this map.
   * It is legal for map entries to be <code>null</code>, and this will produce the correct
   * behavior using a NULL argument to the stored procedure.
   @return map of output params, keyed by name as in parameter declarations.
   * Output parameters will appear here, with their values after the
   * stored procedure has been called.
   */
  public Map<String, Object> execute(ParameterMapper inParamMapperthrows DataAccessException {
    checkCompiled();
    return getJdbcTemplate().call(newCallableStatementCreator(inParamMapper), getDeclaredParameters());
  }

}