001/* 002 * Copyright 2002-2014 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 * https://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 017package org.springframework.jdbc.object; 018 019import java.util.HashMap; 020import java.util.Map; 021import javax.sql.DataSource; 022 023import org.springframework.dao.DataAccessException; 024import org.springframework.dao.InvalidDataAccessApiUsageException; 025import org.springframework.jdbc.core.JdbcTemplate; 026import org.springframework.jdbc.core.ParameterMapper; 027import org.springframework.jdbc.core.SqlParameter; 028 029/** 030 * Superclass for object abstractions of RDBMS stored procedures. 031 * This class is abstract and it is intended that subclasses will provide 032 * a typed method for invocation that delegates to the supplied 033 * {@link #execute} method. 034 * 035 * <p>The inherited {@code sql} property is the name of the stored 036 * procedure in the RDBMS. 037 * 038 * @author Rod Johnson 039 * @author Thomas Risberg 040 * @see #setSql 041 */ 042public abstract class StoredProcedure extends SqlCall { 043 044 /** 045 * Allow use as a bean. 046 */ 047 protected StoredProcedure() { 048 } 049 050 /** 051 * Create a new object wrapper for a stored procedure. 052 * @param ds DataSource to use throughout the lifetime 053 * of this object to obtain connections 054 * @param name name of the stored procedure in the database 055 */ 056 protected StoredProcedure(DataSource ds, String name) { 057 setDataSource(ds); 058 setSql(name); 059 } 060 061 /** 062 * Create a new object wrapper for a stored procedure. 063 * @param jdbcTemplate JdbcTemplate which wraps DataSource 064 * @param name name of the stored procedure in the database 065 */ 066 protected StoredProcedure(JdbcTemplate jdbcTemplate, String name) { 067 setJdbcTemplate(jdbcTemplate); 068 setSql(name); 069 } 070 071 072 /** 073 * StoredProcedure parameter Maps are by default allowed to contain 074 * additional entries that are not actually used as parameters. 075 */ 076 @Override 077 protected boolean allowsUnusedParameters() { 078 return true; 079 } 080 081 /** 082 * Declare a parameter. Overridden method. 083 * Parameters declared as {@code SqlParameter} and {@code SqlInOutParameter} 084 * will always be used to provide input values. In addition to this any parameter declared 085 * as {@code SqlOutParameter} where an non-null input value is provided will also be used 086 * as an input paraneter. 087 * <b>Note: Calls to declareParameter must be made in the same order as 088 * they appear in the database's stored procedure parameter list.</b> 089 * Names are purely used to help mapping. 090 * @param param parameter object 091 */ 092 @Override 093 public void declareParameter(SqlParameter param) throws InvalidDataAccessApiUsageException { 094 if (param.getName() == null) { 095 throw new InvalidDataAccessApiUsageException("Parameters to stored procedures must have names as well as types"); 096 } 097 super.declareParameter(param); 098 } 099 100 /** 101 * Execute the stored procedure with the provided parameter values. This is 102 * a convenience method where the order of the passed in parameter values 103 * must match the order that the parameters where declared in. 104 * @param inParams variable number of input parameters. Output parameters should 105 * not be included in this map. 106 * It is legal for values to be {@code null}, and this will produce the 107 * correct behavior using a NULL argument to the stored procedure. 108 * @return map of output params, keyed by name as in parameter declarations. 109 * Output parameters will appear here, with their values after the 110 * stored procedure has been called. 111 */ 112 public Map<String, Object> execute(Object... inParams) { 113 Map<String, Object> paramsToUse = new HashMap<String, Object>(); 114 validateParameters(inParams); 115 int i = 0; 116 for (SqlParameter sqlParameter : getDeclaredParameters()) { 117 if (sqlParameter.isInputValueProvided()) { 118 if (i < inParams.length) { 119 paramsToUse.put(sqlParameter.getName(), inParams[i++]); 120 } 121 } 122 } 123 return getJdbcTemplate().call(newCallableStatementCreator(paramsToUse), getDeclaredParameters()); 124 } 125 126 /** 127 * Execute the stored procedure. Subclasses should define a strongly typed 128 * execute method (with a meaningful name) that invokes this method, populating 129 * the input map and extracting typed values from the output map. Subclass 130 * execute methods will often take domain objects as arguments and return values. 131 * Alternatively, they can return void. 132 * @param inParams map of input parameters, keyed by name as in parameter 133 * declarations. Output parameters need not (but can) be included in this map. 134 * It is legal for map entries to be {@code null}, and this will produce the 135 * correct behavior using a NULL argument to the stored procedure. 136 * @return map of output params, keyed by name as in parameter declarations. 137 * Output parameters will appear here, with their values after the 138 * stored procedure has been called. 139 */ 140 public Map<String, Object> execute(Map<String, ?> inParams) throws DataAccessException { 141 validateParameters(inParams.values().toArray()); 142 return getJdbcTemplate().call(newCallableStatementCreator(inParams), getDeclaredParameters()); 143 } 144 145 /** 146 * Execute the stored procedure. Subclasses should define a strongly typed 147 * execute method (with a meaningful name) that invokes this method, passing in 148 * a ParameterMapper that will populate the input map. This allows mapping database 149 * specific features since the ParameterMapper has access to the Connection object. 150 * The execute method is also responsible for extracting typed values from the output map. 151 * Subclass execute methods will often take domain objects as arguments and return values. 152 * Alternatively, they can return void. 153 * @param inParamMapper map of input parameters, keyed by name as in parameter 154 * declarations. Output parameters need not (but can) be included in this map. 155 * It is legal for map entries to be {@code null}, and this will produce the correct 156 * behavior using a NULL argument to the stored procedure. 157 * @return map of output params, keyed by name as in parameter declarations. 158 * Output parameters will appear here, with their values after the 159 * stored procedure has been called. 160 */ 161 public Map<String, Object> execute(ParameterMapper inParamMapper) throws DataAccessException { 162 checkCompiled(); 163 return getJdbcTemplate().call(newCallableStatementCreator(inParamMapper), getDeclaredParameters()); 164 } 165 166}