
org.skyway.spring.util.dao.call.AdvancedCallMetaDataContext Maven / Gradle / Ivy
The newest version!
/**
* Copyright 2007 - 2011 Skyway Software, Inc.
*/
package org.skyway.spring.util.dao.call;
import java.sql.DatabaseMetaData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.sql.DataSource;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.SqlReturnResultSet;
import org.springframework.jdbc.core.metadata.CallMetaDataContext;
import org.springframework.jdbc.core.metadata.CallMetaDataProvider;
import org.springframework.jdbc.core.metadata.CallParameterMetaData;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
import org.springframework.jdbc.support.JdbcUtils;
@SuppressWarnings("nls")
public class AdvancedCallMetaDataContext extends CallMetaDataContext {
/** List of SqlParameter objects to be used in call execution */
private List callParameters = new ArrayList();
/** the provider of call meta data */
private CallMetaDataProvider metaDataProvider;
/** Set of in parameter names to exclude use for any not listed */
private Set limitedInParameterNames = new HashSet();
/**
* Initialize this class with metadata from the database
* @param dataSource the DataSource used to retrieve metadata
*/
@Override
public void initializeMetaData(DataSource dataSource) {
this.metaDataProvider = VendorTypeHandlerFactory.createMetaDataProvider(dataSource, this);
}
public CallMetaDataProvider getMetaDataProvider() {
return metaDataProvider;
}
public void setMetaDataProvider(CallMetaDataProvider metaDataProvider) {
this.metaDataProvider = metaDataProvider;
}
/**
* Create a ReturnResultSetParameter/SqlOutParameter depending on the support provided
* by the JDBC driver used for the database in use.
* @param parameterName the name of the parameter (also used as the name of the List returned in the output)
* @param rowMapper a RowMapper implementation used to map the data retuned in the result set
* @return the appropriate SqlParameter
*/
@Override
public SqlParameter createReturnResultSetParameter(String parameterName, RowMapper rowMapper) {
if (this.metaDataProvider.isReturnResultSetSupported()) {
return new SqlReturnResultSet(parameterName, rowMapper);
}
else {
if (this.metaDataProvider.isRefCursorSupported()) {
return new SqlOutParameter(parameterName, this.metaDataProvider.getRefCursorSqlType(), rowMapper);
}
else {
throw new InvalidDataAccessApiUsageException("Return of a ResultSet from a stored procedure is not supported.");
}
}
}
/**
* Process the list of parameters provided and if procedure column metedata is used the
* parameters will be matched against the metadata information and any missing ones will
* be automatically included
* @param parameters the list of parameters to use as a base
*/
@Override
public void processParameters(List parameters) {
this.callParameters = reconcileParameters(parameters);
}
/**
* Reconcile the provided parameters with available metadata and add new ones where appropriate
*/
private List reconcileParameters(List parameters) {
final List declaredReturnParameters = new ArrayList();
final Map declaredParameters = new LinkedHashMap();
boolean returnDeclared = false;
List outParameterNames = new ArrayList();
// Separate implicit return parameters from explicit parameters...
for (SqlParameter parameter : parameters) {
if (parameter.isResultsParameter()) {
declaredReturnParameters.add(parameter);
}
else {
String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameter.getName()).toLowerCase();
declaredParameters.put(parameterNameToMatch, parameter);
if (parameter instanceof SqlOutParameter) {
outParameterNames.add(parameter.getName());
if (this.isFunction()) {
if (!returnDeclared)
this.setFunctionReturnName(parameter.getName());
returnDeclared = true;
}
}
}
}
this.setOutParameterNames(outParameterNames);
final List workParameters = new ArrayList();
workParameters.addAll(declaredReturnParameters);
if (!this.metaDataProvider.isProcedureColumnMetaDataUsed()) {
workParameters.addAll(declaredParameters.values());
return workParameters;
}
Map limitedInParamNamesMap = new HashMap(this.limitedInParameterNames.size());
for (String limitedParameterName : this.limitedInParameterNames) {
limitedInParamNamesMap.put(
this.metaDataProvider.parameterNameToUse(limitedParameterName).toLowerCase(), limitedParameterName);
}
for (CallParameterMetaData meta : metaDataProvider.getCallParameterMetaData()) {
String parNameToCheck = null;
if (meta.getParameterName() != null) {
parNameToCheck = this.metaDataProvider.parameterNameToUse(meta.getParameterName()).toLowerCase();
}
String parNameToUse = this.metaDataProvider.parameterNameToUse(meta.getParameterName());
if (declaredParameters.containsKey(parNameToCheck) ||
(meta.getParameterType() == DatabaseMetaData.procedureColumnReturn && returnDeclared)) {
SqlParameter parameter;
if (meta.getParameterType() == DatabaseMetaData.procedureColumnReturn) {
parameter = declaredParameters.get(this.getFunctionReturnName());
if (parameter == null && this.getOutParameterNames().size() > 0) {
parameter = declaredParameters.get(this.getOutParameterNames().get(0).toLowerCase());
}
if (parameter == null) {
throw new InvalidDataAccessApiUsageException(
"Unable to locate declared parameter for function return value - " +
" add an SqlOutParameter with name \"" + getFunctionReturnName() +"\"");
}
else {
this.setFunctionReturnName(parameter.getName());
}
}
else {
parameter = declaredParameters.get(parNameToCheck);
}
if (parameter != null) {
workParameters.add(parameter);
}
}
else {
if (meta.getParameterType() == DatabaseMetaData.procedureColumnReturn) {
if (!isFunction() && !isReturnValueRequired() &&
this.metaDataProvider.byPassReturnParameter(meta.getParameterName())) {
}
else {
String returnNameToUse =
( meta.getParameterName() == null || meta.getParameterName().length() < 1 ) ?
this.getFunctionReturnName() : parNameToUse;
workParameters.add(new SqlOutParameter(returnNameToUse, meta.getSqlType()));
if (this.isFunction())
outParameterNames.add(returnNameToUse);
}
}
else {
if (meta.getParameterType() == DatabaseMetaData.procedureColumnOut) {
workParameters.add(this.metaDataProvider.createDefaultOutParameter(parNameToUse, meta));
outParameterNames.add(parNameToUse);
}
else if (meta.getParameterType() == DatabaseMetaData.procedureColumnInOut) {
workParameters.add(this.metaDataProvider.createDefaultInOutParameter(parNameToUse, meta));
outParameterNames.add(parNameToUse);
}
else {
if (this.limitedInParameterNames.size() == 0 ||
limitedInParamNamesMap.containsKey(parNameToUse.toLowerCase())) {
workParameters.add(this.metaDataProvider.createDefaultInParameter(parNameToUse, meta));
}
}
}
}
}
return workParameters;
}
/**
* Match input parameter values with the parameters declared to be used in the call.
* @param parameterSource the input values
* @return a Map containing the matched parameter names with the value taken from the input
*/
@SuppressWarnings("unchecked")
@Override
public Map matchInParameterValuesWithCallParameters(SqlParameterSource parameterSource) {
// For parameter source lookups we need to provide case-insensitive lookup support
// since the database metadata is not necessarily providing case sensitive parameter names.
Map caseInsensitiveParameterNames =
SqlParameterSourceUtils.extractCaseInsensitiveParameterNames(parameterSource);
Map callParameterNames = new HashMap(this.callParameters.size());
Map matchedParameters = new HashMap(this.callParameters.size());
for (SqlParameter parameter : this.callParameters) {
if (parameter.isInputValueProvided()) {
String parameterName = parameter.getName();
String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
if (parameterNameToMatch != null) {
callParameterNames.put(parameterNameToMatch.toLowerCase(), parameterName);
}
if (parameterName != null) {
if (parameterSource.hasValue(parameterName)) {
matchedParameters.put(parameterName, SqlParameterSourceUtils.getTypedValue(parameterSource, parameterName));
}
else {
String lowerCaseName = parameterName.toLowerCase();
if (parameterSource.hasValue(lowerCaseName)) {
matchedParameters.put(parameterName, SqlParameterSourceUtils.getTypedValue(parameterSource, lowerCaseName));
}
else {
String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(parameterName);
if (parameterSource.hasValue(propertyName)) {
matchedParameters.put(parameterName, SqlParameterSourceUtils.getTypedValue(parameterSource, propertyName));
}
else {
if (caseInsensitiveParameterNames.containsKey(lowerCaseName)) {
String sourceName = (String) caseInsensitiveParameterNames.get(lowerCaseName);
matchedParameters.put(parameterName, SqlParameterSourceUtils.getTypedValue(parameterSource, sourceName));
}
}
}
}
}
}
}
return matchedParameters;
}
/**
* Match input parameter values with the parameters declared to be used in the call.
* @param inParameters the input values
* @return a Map containing the matched parameter names with the value taken from the input
*/
@Override
public Map matchInParameterValuesWithCallParameters(Map inParameters) {
if (!this.metaDataProvider.isProcedureColumnMetaDataUsed()) {
return inParameters;
}
Map callParameterNames = new HashMap(this.callParameters.size());
for (SqlParameter parameter : this.callParameters) {
if (parameter.isInputValueProvided()) {
String parameterName = parameter.getName();
String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
if (parameterNameToMatch != null) {
callParameterNames.put(parameterNameToMatch.toLowerCase(), parameterName);
}
}
}
Map matchedParameters = new HashMap(inParameters.size());
for (String parameterName : inParameters.keySet()) {
String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
String callParameterName = callParameterNames.get(parameterNameToMatch.toLowerCase());
if (callParameterName != null) {
matchedParameters.put(callParameterName, inParameters.get(parameterName));
}
}
if (matchedParameters.size() < callParameterNames.size()) {
for (String parameterName : callParameterNames.keySet()) {
String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
@SuppressWarnings("unused")
String callParameterName = callParameterNames.get(parameterNameToMatch.toLowerCase());
}
}
return matchedParameters;
}
/**
* Get the List of SqlParameter objects to be used in call execution
*/
@Override
public List getCallParameters() {
return this.callParameters;
}
/**
* Build the call string based on configuration and metadata information.
* @return the call string to be used
*/
@Override
public String createCallString() {
String callString;
int parameterCount = 0;
String catalogNameToUse = null;
String schemaNameToUse = null;
// For Oracle where catalogs are not supported we need to reverse the schema name
// and the catalog name since the cataog is used for the package name
if (this.metaDataProvider.isSupportsSchemasInProcedureCalls() &&
!this.metaDataProvider.isSupportsCatalogsInProcedureCalls()) {
schemaNameToUse = this.metaDataProvider.catalogNameToUse(this.getCatalogName());
catalogNameToUse = this.metaDataProvider.schemaNameToUse(this.getSchemaName());
}
else {
catalogNameToUse = this.metaDataProvider.catalogNameToUse(this.getCatalogName());
schemaNameToUse = this.metaDataProvider.schemaNameToUse(this.getSchemaName());
}
String procedureNameToUse = this.metaDataProvider.procedureNameToUse(this.getProcedureName());
if (this.isFunction() || this.isReturnValueRequired()) {
callString = "{? = call " +
(catalogNameToUse != null && catalogNameToUse.length() > 0 ? catalogNameToUse + "." : "") +
(schemaNameToUse != null && schemaNameToUse.length() > 0 ? schemaNameToUse + "." : "") +
procedureNameToUse + "(";
parameterCount = -1;
}
else {
callString = "{call " +
(catalogNameToUse != null && catalogNameToUse.length() > 0 ? catalogNameToUse + "." : "") +
(schemaNameToUse != null && schemaNameToUse.length() > 0 ? schemaNameToUse + "." : "") +
procedureNameToUse + "(";
}
for (SqlParameter parameter : this.callParameters) {
if (!(parameter.isResultsParameter())) {
if (parameterCount > 0) {
callString += ", ";
}
if (parameterCount >= 0) {
callString += "?";
}
parameterCount++;
}
}
callString += ")}";
return callString;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy