Initial draft of the stored proc. adapters

The following 3 components are provided:

* stored-proc-outbound-channel-adapter
* stored-proc-outbound-gateway
* stored-proc-inbound-channel-adapter
This commit is contained in:
Gunnar Hillert
2011-10-04 00:42:21 -04:00
committed by Mark Fisher
parent 3e1b0596bb
commit b018ea84c8
68 changed files with 4667 additions and 63 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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
@@ -20,7 +20,6 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.expression.ExpressionException;
import org.springframework.integration.util.AbstractExpressionEvaluator;
import org.springframework.jdbc.core.namedparam.AbstractSqlParameterSource;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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
@@ -29,6 +29,7 @@ import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.util.LinkedCaseInsensitiveMap;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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.
@@ -36,6 +36,7 @@ import org.springframework.jdbc.core.RowMapperResultSetExtractor;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
/**
* A polling channel adapter that creates messages from the payload returned by

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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.

View File

@@ -0,0 +1,335 @@
/*
* Copyright 2002-2011 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.integration.jdbc;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.sql.DataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.expression.Expression;
import org.springframework.integration.Message;
import org.springframework.integration.jdbc.storedproc.ProcedureParameter;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.jdbc.core.simple.SimpleJdbcCallOperations;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.util.Assert;
/**
* A message handler that executes Stored Procedures for update purposes.
*
* Stored procedure parameter value are by default automatically extracted from
* the Payload if the payload's bean properties match the parameters of the Stored
* Procedure.
*
* This may be sufficient for basic use cases. For more sophisticated options
* consider passing in one or more {@link ProcedureParameter}.
*
* If you need to handle the return parameters of the called stored procedure
* explicitly, please consider using a {@link StoredProcOutboundGateway} instead.
*
* Also, if you need to execute SQL Functions, please also use the
* {@link StoredProcOutboundGateway}. As functions are typically used to look up
* values, only, the Stored Procedure message handler does purposefully not support
* SQL function calls. If you believe there are valid use-cases for that, please file a
* feature request at http://jira.springsource.org.
*
*
* @author Gunnar Hillert
* @since 2.1
*
*/
public class StoredProcExecutor implements InitializingBean {
/**
* Uses the {@link SimpleJdbcCall} implementation for executing Stored Procedures.
* For more details please see:
*/
private final SimpleJdbcCallOperations jdbcCallOperations;
/**
* Name of the stored procedure to execute.
*/
private volatile String storedProcedureName;
/**
* For fully supported databases, the underlying {@link SimpleJdbcCall} can
* retrieve the parameter information for the to be invoked Stored Procedure
* from the JDBC Meta-data. However, if the used database does not support
* meta data lookups or if you like to provide customized parameter definitions,
* this flag can be set to 'true'. It defaults to 'false'.
*/
private volatile boolean ignoreColumnMetaData = false;
/**
* If you database system is not fully supported by Spring and thus obtaining
* parameter definitions from the JDBC Meta-data is not possible, you must define
* the {@link SqlParameter} explicitly.
*/
private volatile List<SqlParameter> sqlParameters = new ArrayList<SqlParameter>(0);
/**
* By default bean properties of the passed in {@link Message} will be used
* as a source for the Stored Procedure's input parameters.
*
* This may be sufficient for basic use cases. For more sophisticated options
* consider passing in one or more {@link ProcedureParameter}.
*/
private volatile SqlParameterSourceFactory sqlParameterSourceFactory = new BeanPropertySqlParameterSourceFactory();
/**
* Indicates that whether only the payload of the passed in {@link Message}
* will be used as a source of parameters. The is 'true' by default because as a
* default a {@link BeanPropertySqlParameterSourceFactory} implementation is
* used for the sqlParameterSourceFactory property.
*/
private volatile boolean usePayloadAsParameterSource = false;
/**
* Custom Stored Procedure parameters that may contain static values
* or Strings representing an {@link Expression}.
*/
private volatile List<ProcedureParameter>procedureParameters;
private volatile boolean isFunction = false;
private volatile boolean returnValueRequired = false;
private volatile Map<String, RowMapper<?>> returningResultSetRowMappers = new HashMap<String, RowMapper<?>>(0);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Constructor taking {@link DataSource} from which the DB Connection can be
* obtained and the select query to execute the stored procedure.
*
* @param dataSource used to create a {@link SimpleJdbcTemplate}, must not be Null
* @param storedProcedureName Name of the Stored Procedure of function, must not be empty
*/
public StoredProcExecutor(DataSource dataSource, String storedProcedureName) {
Assert.notNull(dataSource, "dataSource must not be null.");
Assert.hasText(storedProcedureName, "storedProcedureName must not be null and cannot be empty.");
this.jdbcCallOperations = new SimpleJdbcCall(dataSource);
this.storedProcedureName = storedProcedureName;
}
/**
* Verifies parameters, sets the parameters on {@link SimpleJdbcCallOperations}
* and ensures the appropriate {@link SqlParameterSourceFactory} is defined
* when {@link ProcedureParameter} are passed in.
*/
public void afterPropertiesSet() {
if (this.procedureParameters != null) {
if (!(this.sqlParameterSourceFactory instanceof ExpressionEvaluatingSqlParameterSourceFactory)) {
this.sqlParameterSourceFactory = new ExpressionEvaluatingSqlParameterSourceFactory();
}
ExpressionEvaluatingSqlParameterSourceFactory expressionSourceFactory
= (ExpressionEvaluatingSqlParameterSourceFactory) this.sqlParameterSourceFactory;
expressionSourceFactory.setStaticParameters(ProcedureParameter.convertStaticParameters(procedureParameters));
expressionSourceFactory.setParameterExpressions(ProcedureParameter.convertExpressions(procedureParameters));
}
if (this.ignoreColumnMetaData) {
this.jdbcCallOperations.withoutProcedureColumnMetaDataAccess();
}
this.jdbcCallOperations.declareParameters(this.sqlParameters.toArray(new SqlParameter[this.sqlParameters.size()]));
if (!this.returningResultSetRowMappers.isEmpty()) {
for (Entry<String, RowMapper<?>> mapEntry : this.returningResultSetRowMappers.entrySet()) {
jdbcCallOperations.returningResultSet(mapEntry.getKey(), mapEntry.getValue());
}
}
if (this.returnValueRequired) {
jdbcCallOperations.withReturnValue();
}
if (this.isFunction) {
this.jdbcCallOperations.withFunctionName(this.storedProcedureName);
} else {
this.jdbcCallOperations.withProcedureName(this.storedProcedureName);
}
}
/**
* Execute a Stored Procedure of Function - Use when not {@link Message} is
* available to extract {@link ProcedureParameter} values from it.
*
* @return Map containing the stored procedure results if any.
*/
public Map<String, Object> executeStoredProcedure() {
return executeStoredProcedureInternal(new Object());
}
/**
* Execute a Stored Procedure of Function - Use with {@link Message} is
* available to extract {@link ProcedureParameter} values from it.
*
* @return Map containing the stored procedure results if any.
*/
public Map<String, Object> executeStoredProcedure(Message<?> message) {
Assert.notNull(message, "The message parameter must not be null.");
if (usePayloadAsParameterSource) {
return executeStoredProcedureInternal(message.getPayload());
} else {
return executeStoredProcedureInternal(message);
}
}
/**
* Execute the Stored Procedure using the passed in {@link Message} as a source
* for parameters.
*
* @param message The message is used to extract parameters for the stored procedure.
* @return A map containing the return values from the Stored Procedure call if any.
*/
private Map<String, Object> executeStoredProcedureInternal(Object input) {
SqlParameterSource storedProcedureParameterSource =
sqlParameterSourceFactory.createParameterSource(input);
return StoredProcExecutor.executeStoredProcedure(jdbcCallOperations,
storedProcedureParameterSource);
}
/**
*/
private static Map<String, Object> executeStoredProcedure(SimpleJdbcCallOperations simpleJdbcCallOperations,
SqlParameterSource storedProcedureParameterSource) {
Map<String, Object> resultMap = simpleJdbcCallOperations.execute(storedProcedureParameterSource);
return resultMap;
}
//~~~~~Setters for Properties~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* For fully supported databases, the underlying {@link SimpleJdbcCall} can
* retrieve the parameter information for the to be invoked Stored Procedure
* from the JDBC Meta-data. However, if the used database does not support
* meta data lookups or if you like to provide customized parameter definitions,
* this flag can be set to 'true'. It defaults to 'false'.
*/
public void setIgnoreColumnMetaData(boolean ignoreColumnMetaData) {
this.ignoreColumnMetaData = ignoreColumnMetaData;
}
/**
* Custom Stored Procedure parameters that may contain static values
* or Strings representing an {@link Expression}.
*/
public void setProcedureParameters(List<ProcedureParameter> procedureParameters) {
Assert.notEmpty(procedureParameters, "procedureParameters must not be null or empty.");
for (ProcedureParameter procedureParameter : procedureParameters) {
Assert.notNull(procedureParameter, "The provided list (procedureParameters) cannot contain null values.");
}
this.procedureParameters = procedureParameters;
this.usePayloadAsParameterSource = false;
}
/**
* If you database system is not fully supported by Spring and thus obtaining
* parameter definitions from the JDBC Meta-data is not possible, you must define
* the {@link SqlParameter} explicitly.
*/
public void setSqlParameters(List<SqlParameter> sqlParameters) {
Assert.notEmpty(sqlParameters, "sqlParameters must not be null or empty.");
for (SqlParameter sqlParameter : sqlParameters) {
Assert.notNull(sqlParameter, "The provided list (sqlParameters) cannot contain null values.");
}
this.sqlParameters = sqlParameters;
}
/**
* Provides the ability to set a custom {@link SqlParameterSourceFactory}.
* Keep in mind that if {@link ProcedureParameter} are set explicitly and
* you would like to provide a custom {@link SqlParameterSourceFactory},
* then you must provide an instance of {@link ExpressionEvaluatingSqlParameterSourceFactory}.
*
* If not the SqlParameterSourceFactory will be replaced the default
* {@link ExpressionEvaluatingSqlParameterSourceFactory}.
*
* @param sqlParameterSourceFactory
*/
public void setSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) {
Assert.notNull(sqlParameterSourceFactory, "sqlParameterSourceFactory must not be null.");
this.sqlParameterSourceFactory = sqlParameterSourceFactory;
this.usePayloadAsParameterSource = false;
}
/**
* @return the name of the Stored Procedure or Function
* */
public String getStoredProcedureName() {
return this.storedProcedureName;
}
public void setUsePayloadAsParameterSource(boolean usePayloadAsParameterSource) {
this.usePayloadAsParameterSource = usePayloadAsParameterSource;
}
public void setFunction(boolean isFunction) {
this.isFunction = isFunction;
}
public void setReturnValueRequired(boolean returnValueRequired) {
this.returnValueRequired = returnValueRequired;
}
/**
* If the Stored Procedure returns ResultSets you may provide a map of
* {@link RowMapper} to convert the {@link ResultSet} to meaningful objects.
*
* @param returningResultSetRowMappers The map may not be null and must not contain null values.
*/
public void setReturningResultSetRowMappers(
Map<String, RowMapper<?>> returningResultSetRowMappers) {
Assert.notNull(returningResultSetRowMappers, "returningResultSetRowMappers must not be null.");
for (RowMapper<?> rowMapper : returningResultSetRowMappers.values()) {
Assert.notNull(rowMapper, "The provided map cannot contain null values.");
}
this.returningResultSetRowMappers = returningResultSetRowMappers;
}
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright 2002-2011 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.integration.jdbc;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.expression.Expression;
import org.springframework.integration.Message;
import org.springframework.integration.MessageDeliveryException;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.MessageRejectedException;
import org.springframework.integration.handler.AbstractMessageHandler;
import org.springframework.integration.jdbc.storedproc.ProcedureParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.jdbc.core.simple.SimpleJdbcCallOperations;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.util.Assert;
/**
* A message handler that executes Stored Procedures for update purposes.
*
* Stored procedure parameter value are by default automatically extracted from
* the Payload if the payload's bean properties match the parameters of the Stored
* Procedure.
*
* This may be sufficient for basic use cases. For more sophisticated options
* consider passing in one or more {@link ProcedureParameter}.
*
* If you need to handle the return parameters of the called stored procedure
* explicitly, please consider using a {@link StoredProcOutboundGateway} instead.
*
* Also, if you need to execute SQL Functions, please also use the
* {@link StoredProcOutboundGateway}. As functions are typically used to look up
* values, only, the Stored Procedure message handler does purposefully not support
* SQL function calls. If you believe there are valid use-cases for that, please file a
* feature request at http://jira.springsource.org.
*
*
* @author Gunnar Hillert
* @since 2.1
*
*/
public class StoredProcMessageHandler extends AbstractMessageHandler implements InitializingBean {
final StoredProcExecutor executor;
/**
* Constructor taking {@link DataSource} from which the DB Connection can be
* obtained and the name of the stored procedure or function to
* execute to retrieve new rows.
*
* @param dataSource used to create a {@link SimpleJdbcTemplate}. Must not be null.
* @param storedProcedureName The name of the Stored Procedure or Function. Must not be null.
*/
public StoredProcMessageHandler(DataSource dataSource, String storedProcedureName) {
Assert.notNull(dataSource, "dataSource must not be null.");
Assert.hasText(storedProcedureName, "storedProcedureName must not be null and cannot be empty.");
this.executor = new StoredProcExecutor(dataSource, storedProcedureName);
this.executor.setUsePayloadAsParameterSource(true);
}
/**
* Verifies parameters, sets the parameters on {@link SimpleJdbcCallOperations}
* and ensures the appropriate {@link SqlParameterSourceFactory} is defined
* when {@link ProcedureParameter} are passed in.
*/
@Override
protected void onInit() throws Exception {
super.onInit();
this.executor.afterPropertiesSet();
};
/**
* Executes the Stored procedure, delegates to executeStoredProcedure(...).
* Any return values from the Stored procedure are ignored.
*
* Return values are logged at debug level, though.
*/
@Override
protected void handleMessageInternal(Message<?> message) throws MessageRejectedException, MessageHandlingException,
MessageDeliveryException {
Map<String, Object> resultMap = executor.executeStoredProcedure(message);
if (logger.isDebugEnabled()) {
if (resultMap != null && !resultMap.isEmpty()) {
logger.debug(String.format("The StoredProcMessageHandler ignores return "
+ "values, but the called Stored Procedure '%s' returned the "
+ "following data: '%s'", executor.getStoredProcedureName(), resultMap));
}
}
}
//~~~~~Setters for Properties~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* For fully supported databases, the underlying {@link SimpleJdbcCall} can
* retrieve the parameter information for the to be invoked Stored Procedure
* from the JDBC Meta-data. However, if the used database does not support
* meta data lookups or if you like to provide customized parameter definitions,
* this flag can be set to 'true'. It defaults to 'false'.
*/
public void setIgnoreColumnMetaData(boolean ignoreColumnMetaData) {
this.executor.setIgnoreColumnMetaData(ignoreColumnMetaData);
}
/**
* Custom Stored Procedure parameters that may contain static values
* or Strings representing an {@link Expression}.
*/
public void setProcedureParameters(List<ProcedureParameter> procedureParameters) {
this.executor.setProcedureParameters(procedureParameters);
}
/**
* If you database system is not fully supported by Spring and thus obtaining
* parameter definitions from the JDBC Meta-data is not possible, you must define
* the {@link SqlParameter} explicitly.
*/
public void setSqlParameters(List<SqlParameter> sqlParameters) {
this.executor.setSqlParameters(sqlParameters);
}
/**
* Provides the ability to set a custom {@link SqlParameterSourceFactory}.
* Keep in mind that if {@link ProcedureParameter} are set explicitly and
* you would like to provide a custom {@link SqlParameterSourceFactory},
* then you must provide an instance of {@link ExpressionEvaluatingSqlParameterSourceFactory}.
*
* If not the SqlParameterSourceFactory will be replaced the default
* {@link ExpressionEvaluatingSqlParameterSourceFactory}.
*
* @param sqlParameterSourceFactory
*/
public void setSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) {
this.executor.setSqlParameterSourceFactory(sqlParameterSourceFactory);
}
}

View File

@@ -0,0 +1,192 @@
/*
* Copyright 2002-2011 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.integration.jdbc;
import java.sql.CallableStatement;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.Message;
import org.springframework.integration.MessagingException;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.jdbc.storedproc.ProcedureParameter;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.simple.SimpleJdbcCallOperations;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.util.Assert;
/**
* @author Gunnar Hillert
*
* @since 2.1
*/
public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHandler implements InitializingBean {
private final StoredProcExecutor executor;
private volatile boolean expectSingleResult = false;
/**
* Constructor taking {@link DataSource} from which the DB Connection can be
* obtained and the name of the stored procedure or function to
* execute to retrieve new rows.
*
* @param dataSource used to create a {@link SimpleJdbcTemplate}
* @param storedProcedureName
*/
public StoredProcOutboundGateway(DataSource dataSource, String storedProcedureName) {
Assert.notNull(dataSource, "dataSource must not be null.");
Assert.hasText(storedProcedureName, "storedProcedureName must not be null and cannot be empty.");
this.executor = new StoredProcExecutor(dataSource, storedProcedureName);
this.executor.setUsePayloadAsParameterSource(true);
}
/**
* Verifies parameters, sets the parameters on {@link SimpleJdbcCallOperations}
* and ensures the appropriate {@link SqlParameterSourceFactory} is defined
* when {@link ProcedureParameter} are passed in.
*/
@Override
protected void onInit() {
super.onInit();
this.executor.afterPropertiesSet();
};
@Override
protected Object handleRequestMessage(Message<?> requestMessage) {
Map<String, Object> resultMap = executor.executeStoredProcedure(requestMessage);
final Object payload;
if (resultMap.isEmpty()) {
payload = null;
} else {
if (this.expectSingleResult && resultMap.size() == 1) {
payload = resultMap.values().iterator().next();
} else if (this.expectSingleResult && resultMap.size() > 1) {
throw new MessagingException(
"Stored Procedure/Function call returned more than "
+ "1 result object and expectSingleResult was 'true'. ");
} else {
payload = resultMap;
}
}
return MessageBuilder.withPayload(payload).copyHeaders(requestMessage.getHeaders()).build();
}
/**
* Explicit declarations are necessary if the database you use is not a
* Spring-supported database. Currently Spring supports metadata lookup of
* stored procedure calls for the following databases:
*
* <ul>
* <li>Apache Derby</li>
* <li>DB2</li>
* <li>MySQL</li>
* <li>Microsoft SQL Server</li>
* <li>Oracle</li>
* <li>Sybase</li>
* <li>PostgreSQL</li>
* </ul>
* , ,
* We also support metadata lookup of stored functions for the following
* databases:
*
* <ul>
* <li>MySQL</li>
* <li>Microsoft SQL Server</li>
* <li>Oracle</li>
* <li>PostgreSQL</li>
* </ul>
*
* See also: {@link http://static.springsource.org/spring/docs/3.1.0.M2/spring-framework-reference/html/jdbc.html}
*/
public void setSqlParameters(List<SqlParameter> sqlParameters) {
this.executor.setSqlParameters(sqlParameters);
}
/**
* Does your stored procedure return one or more result sets? If so, you
* can use the provided method for setting the respective Rowmappers.
*/
public void setReturningResultSetRowMappers(
Map<String, RowMapper<?>> returningResultSetRowMappers) {
this.executor.setReturningResultSetRowMappers(returningResultSetRowMappers);
}
/**
*
* @param ignoreColumnMetaData
*/
public void setIgnoreColumnMetaData(boolean ignoreColumnMetaData) {
this.executor.setIgnoreColumnMetaData(ignoreColumnMetaData);
}
/**
*
* @param returnValueRequired
*/
public void setReturnValueRequired(boolean returnValueRequired) {
this.executor.setReturnValueRequired(returnValueRequired);
}
public void setProcedureParameters(List<ProcedureParameter> procedureParameters) {
this.executor.setProcedureParameters(procedureParameters);
}
public void setIsFunction(boolean isFunction) {
this.executor.setFunction(isFunction);
}
/**
* This parameter indicates that only one result object shall be returned from
* the Stored Procedure/Function Call. If set to true, a resultMap that contains
* only 1 element, will have that 1 element extracted and returned as payload.
*
* If the resultMap contains more than 1 element and expectSingleResult is true,
* then a {@link MessagingException} is thrown.
*
* Otherwise the complete resultMap is returned as the {@link Message} payload.
*
* Important Note: Several databases such as H2 are not fully supported.
* The H2 database, for example, does not fully support the {@link CallableStatement}
* semantics and when executing function calls against H2, a result list is
* returned rather than a single value.
*
* Therefore, even if you set expectSingleResult = true, you may end up with
* a collection being returned.
*
* @param expectSingleResult
*/
public void setExpectSingleResult(boolean expectSingleResult) {
this.expectSingleResult = expectSingleResult;
}
}

View File

@@ -0,0 +1,230 @@
/*
* Copyright 2002-2011 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.integration.jdbc;
import java.sql.CallableStatement;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.integration.Message;
import org.springframework.integration.MessagingException;
import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.jdbc.storedproc.ProcedureParameter;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.util.Assert;
/**
* A polling channel adapter that creates messages from the payload returned by
* executing a stored procedure or Sql function. Optionally an update can be executed
* after the execution of the Stored Procedure or Function in order to update
* processed rows.
*
* @author Gunnar Hillert
* @since 2.1
*/
public class StoredProcPollingChannelAdapter extends IntegrationObjectSupport implements MessageSource<Object> {
final StoredProcExecutor executor;
private volatile boolean expectSingleResult = false;
/**
* Constructor taking {@link DataSource} from which the DB Connection can be
* obtained and the stored procedure name to execute.
*
* @param dataSource used to create a {@link SimpleJdbcCall}
* @param storedProcedureName Name of the Stored Procedure of Function to execute
*/
public StoredProcPollingChannelAdapter(DataSource dataSource, String storedProcedureName) {
Assert.notNull(dataSource, "dataSource must not be null.");
Assert.hasText(storedProcedureName, "storedProcedureName must not be null and cannot be empty.");
this.executor = new StoredProcExecutor(dataSource, storedProcedureName);
}
@Override
protected void onInit() throws Exception {
super.onInit();
this.executor.afterPropertiesSet();
}
/**
* Executes the query. If a query result set contains one or more rows, the
* Message payload will contain either a List of Maps for each row or, if a
* RowMapper has been provided, the values mapped from those rows. If the
* query returns no rows, this method will return <code>null</code>.
*/
public Message<Object> receive() {
Object payload = poll();
if (payload == null) {
return null;
}
return MessageBuilder.withPayload(payload).build();
}
/**
* Execute the select query and the update query if provided. Returns the
* rows returned by the select query. If a RowMapper has been provided, the
* mapped results are returned.
*/
private Object poll() {
final Object payload;
Map<String, ?> resultMap = doPoll();
if (resultMap.isEmpty()) {
payload = null;
} else {
if (this.expectSingleResult && resultMap.size() == 1) {
payload = resultMap.values().iterator().next();
} else if (this.expectSingleResult && resultMap.size() > 1) {
throw new MessagingException(
"Stored Procedure/Function call returned more than "
+ "1 result object and expectSingleResult was 'true'. ");
} else {
payload = resultMap;
}
}
return payload;
}
protected Map<String, ?> doPoll() {
Map<String, Object> payload = this.executor.executeStoredProcedure();
return payload;
}
public String getComponentType(){
return "stored-proc:inbound-channel-adapter";
}
/**
*
* @param sqlParameterSourceFactory
*/
public void setSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) {
this.executor.setSqlParameterSourceFactory(sqlParameterSourceFactory);
}
/**
* Explicit declarations are necessary if the database you use is not a
* Spring-supported database. Currently Spring supports metadata lookup of
* stored procedure calls for the following databases:
*
* <ul>
* <li>Apache Derby</li>
* <li>DB2</li>
* <li>MySQL</li>
* <li>Microsoft SQL Server</li>
* <li>Oracle</li>
* <li>Sybase</li>
* <li>PostgreSQL</li>
* </ul>
* , ,
* We also support metadata lookup of stored functions for the following
* databases:
*
* <ul>
* <li>MySQL</li>
* <li>Microsoft SQL Server</li>
* <li>Oracle</li>
* <li>PostgreSQL</li>
* </ul>
*
* See also: {@link http://static.springsource.org/spring/docs/3.1.0.M2/spring-framework-reference/html/jdbc.html}
*/
public void setSqlParameters(List<SqlParameter> sqlParameters) {
this.executor.setSqlParameters(sqlParameters);
}
/**
* Does your stored procedure return one or more result sets? If so, you
* can use the provided method for setting the respective Rowmappers.
*/
public void setReturningResultSetRowMappers(
Map<String, RowMapper<?>> returningResultSetRowMappers) {
this.executor.setReturningResultSetRowMappers(returningResultSetRowMappers);
}
/**
*
* @param ignoreColumnMetaData
*/
public void setIgnoreColumnMetaData(boolean ignoreColumnMetaData) {
this.executor.setIgnoreColumnMetaData(ignoreColumnMetaData);
}
/**
*
* @param returnValueRequired
*/
public void setReturnValueRequired(boolean returnValueRequired) {
this.executor.setReturnValueRequired(returnValueRequired);
}
public void setProcedureParameters(List<ProcedureParameter> procedureParameters) {
this.executor.setProcedureParameters(procedureParameters);
}
/**
* Indicates whether a Stored Procedure or a Function is being executed.
* The default value is false.
*
* @param isFunction If set to true an Sql Function is executed rather than a Stored Procedure.
*/
public void setFunction(boolean isFunction) {
this.executor.setFunction(isFunction);
}
/**
* This parameter indicates that only one result object shall be returned from
* the Stored Procedure/Function Call. If set to true, a resultMap that contains
* only 1 element, will have that 1 element extracted and returned as payload.
*
* If the resultMap contains more than 1 element and expectSingleResult is true,
* then a {@link MessagingException} is thrown.
*
* Otherwise the complete resultMap is returned as the {@link Message} payload.
*
* Important Note: Several databases such as H2 are not fully supported.
* The H2 database, for example, does not fully support the {@link CallableStatement}
* semantics and when executing function calls against H2, a result list is
* returned rather than a single value.
*
* Therefore, even if you set expectSingleResult = true, you may end up with
* a collection being returned.
*
* @param expectSingleResult
*/
public void setExpectSingleResult(boolean expectSingleResult) {
this.expectSingleResult = expectSingleResult;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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
@@ -19,6 +19,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jdbc.JdbcMessageHandler;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -41,7 +42,7 @@ public class JdbcMessageHandlerParser extends AbstractOutboundChannelAdapterPars
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition("org.springframework.integration.jdbc.JdbcMessageHandler");
.genericBeanDefinition(JdbcMessageHandler.class);
String dataSourceRef = element.getAttribute("data-source");
String jdbcOperationsRef = element.getAttribute("jdbc-operations");
boolean refToDataSourceSet = StringUtils.hasText(dataSourceRef);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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
@@ -18,6 +18,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jdbc.JdbcMessageStore;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -35,7 +36,7 @@ public class JdbcMessageStoreParser extends AbstractBeanDefinitionParser {
Object source = parserContext.extractSource(element);
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition("org.springframework.integration.jdbc.JdbcMessageStore");
.genericBeanDefinition(JdbcMessageStore.class);
String dataSourceRef = element.getAttribute("data-source");
String simpleJdbcOperationsRef = element.getAttribute("jdbc-operations");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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.
@@ -23,6 +23,8 @@ import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHa
*
* @author Jonas Partner
* @author Dave Syer
* @author Gunnar Hillert
*
* @since 2.0
*/
public class JdbcNamespaceHandler extends AbstractIntegrationNamespaceHandler {
@@ -32,6 +34,9 @@ public class JdbcNamespaceHandler extends AbstractIntegrationNamespaceHandler {
registerBeanDefinitionParser("outbound-channel-adapter", new JdbcMessageHandlerParser());
registerBeanDefinitionParser("outbound-gateway", new JdbcOutboundGatewayParser());
registerBeanDefinitionParser("message-store", new JdbcMessageStoreParser());
registerBeanDefinitionParser("stored-proc-outbound-channel-adapter", new StoredProcMessageHandlerParser());
registerBeanDefinitionParser("stored-proc-inbound-channel-adapter", new StoredProcPollingChannelAdapterParser());
registerBeanDefinitionParser("stored-proc-outbound-gateway", new StoredProcOutboundGatewayParser());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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
@@ -17,6 +17,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractConsumerEndpointParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jdbc.JdbcOutboundGateway;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -58,7 +59,7 @@ public class JdbcOutboundGatewayParser extends AbstractConsumerEndpointParser {
return null;
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition("org.springframework.integration.jdbc.JdbcOutboundGateway");
.genericBeanDefinition(JdbcOutboundGateway.class);
if (refToDataSourceSet) {
builder.addConstructorArgReference(dataSourceRef);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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.
@@ -16,15 +16,15 @@
package org.springframework.integration.jdbc.config;
import org.w3c.dom.Element;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jdbc.JdbcPollingChannelAdapter;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Parser for {@link org.springframework.integration.jdbc.JdbcPollingChannelAdapter}.
@@ -46,7 +46,7 @@ public class JdbcPollingChannelAdapterParser extends AbstractPollingInboundChann
protected BeanMetadataElement parseSource(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition("org.springframework.integration.jdbc.JdbcPollingChannelAdapter");
.genericBeanDefinition(JdbcPollingChannelAdapter.class);
String dataSourceRef = element.getAttribute("data-source");
String jdbcOperationsRef = element.getAttribute("jdbc-operations");
boolean refToDataSourceSet = StringUtils.hasText(dataSourceRef);

View File

@@ -0,0 +1,107 @@
/*
* Copyright 2002-2011 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.integration.jdbc.config;
import java.sql.Types;
import org.springframework.util.Assert;
/**
* This Enumeration provides a handy wrapper around {@link Types}. This makes it
* possible to look up String representation of the enum constant's name, and thus
* looking up the respective JDBC Type (int-value).
*
* @author Gunnar Hillert
* @since 2.1
*
*/
public enum JdbcTypesEnum {
BIT(Types.BIT),
TINYINT(Types.TINYINT),
SMALLINT(Types.SMALLINT),
INTEGER(Types.INTEGER),
BIGINT(Types.BIGINT),
FLOAT(Types.FLOAT),
REAL(Types.REAL),
DOUBLE(Types.DOUBLE),
NUMERIC(Types.NUMERIC),
DECIMAL(Types.DECIMAL),
CHAR(Types.CHAR),
VARCHAR(Types.VARCHAR),
LONGVARCHAR(Types.LONGVARCHAR),
DATE(Types.DATE),
TIME(Types.TIME),
TIMESTAMP(Types.TIMESTAMP),
BINARY(Types.BINARY),
VARBINARY(Types.VARBINARY),
LONGVARBINARY(Types.LONGVARBINARY),
NULL(Types.NULL),
OTHER(Types.OTHER),
JAVA_OBJECT(Types.JAVA_OBJECT),
DISTINCT(Types.DISTINCT),
STRUCT(Types.STRUCT),
ARRAY(Types.ARRAY),
BLOB(Types.BLOB),
CLOB(Types.CLOB),
REF(Types.REF),
DATALINK(Types.DATALINK),
BOOLEAN(Types.BOOLEAN),
ROWID(Types.ROWID),
NCHAR(Types.NCHAR),
NVARCHAR(Types.NVARCHAR),
LONGNVARCHAR(Types.LONGNVARCHAR),
NCLOB(Types.NCLOB),
SQLXML(Types.SQLXML);
private int code;
/** Constructor */
JdbcTypesEnum(int code) {
this.code = code;
}
/**
* Get the numerical representation of the JDBC Type enum. The numerical value
* matches exactly the equivalent value in {@link Types}
*
* @return The numerical representation of the constant.
*/
public int getCode() {
return this.code;
}
/**
* Retrieves the matching enum constant for a provided String representation
* of the SQL Types. The provided name must match exactly the identifier as
* used to declare the enum constant.
*
* @param sqlTypeAsString Name of the enum to convert. Must be not null and not empty.
* @return The enumeration that matches. Returns Null of no match was found.
*
*/
public static JdbcTypesEnum convertToJdbcTypesEnum(String sqlTypeAsString) {
Assert.hasText(sqlTypeAsString, "Parameter sqlTypeAsString, must not be null nor empty");
for (JdbcTypesEnum jdbcType : JdbcTypesEnum.values()) {
if (jdbcType.name().equalsIgnoreCase(sqlTypeAsString)) {
return jdbcType;
}
}
return null;
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2002-2011 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.integration.jdbc.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jdbc.StoredProcMessageHandler;
import org.w3c.dom.Element;
/**
* @author Gunnar Hillert
* @since 2.1
*
*/
public class StoredProcMessageHandlerParser extends AbstractOutboundChannelAdapterParser {
protected boolean shouldGenerateId() {
return false;
}
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(StoredProcMessageHandler.class);
String dataSourceRef = element.getAttribute("data-source");
String storedProcedureName = element.getAttribute("stored-procedure-name");
builder.addConstructorArgReference(dataSourceRef);
builder.addConstructorArgValue(storedProcedureName);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "ignore-column-meta-data");
final ManagedList<BeanDefinition> procedureParameterList = StoredProcParserUtils.getProcedureParameterBeanDefinitions(element, parserContext);
final ManagedList<BeanDefinition> sqlParameterDefinitionList = StoredProcParserUtils.getSqlParameterDefinitionBeanDefinitions(element, parserContext);
if (!procedureParameterList.isEmpty()) {
builder.addPropertyValue("procedureParameters", procedureParameterList);
}
if (!sqlParameterDefinitionList.isEmpty()) {
builder.addPropertyValue("sqlParameters", sqlParameterDefinitionList);
}
return builder.getBeanDefinition();
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2002-2011 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.integration.jdbc.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractConsumerEndpointParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jdbc.StoredProcOutboundGateway;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* @author Gunnar Hillert
* @since 2.1
*
*/
public class StoredProcOutboundGatewayParser extends AbstractConsumerEndpointParser {
protected boolean shouldGenerateId() {
return false;
}
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected BeanDefinitionBuilder parseHandler(Element gatewayElement, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(StoredProcOutboundGateway.class);
String dataSourceRef = gatewayElement.getAttribute("data-source");
String storedProcedureName = gatewayElement.getAttribute("stored-procedure-name");
builder.addConstructorArgReference(dataSourceRef);
builder.addConstructorArgValue(storedProcedureName);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, gatewayElement, "is-function");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, gatewayElement, "ignore-column-meta-data");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, gatewayElement, "expect-single-result");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, gatewayElement, "return-value-required");
final ManagedList<BeanDefinition> procedureParameterList = StoredProcParserUtils.getProcedureParameterBeanDefinitions(gatewayElement, parserContext);
final ManagedList<BeanDefinition> sqlParameterDefinitionList = StoredProcParserUtils.getSqlParameterDefinitionBeanDefinitions(gatewayElement, parserContext);
final ManagedMap<String, BeanDefinition> returningResultsetMap = StoredProcParserUtils.getReturningResultsetBeanDefinitions(gatewayElement, parserContext);
if (!procedureParameterList.isEmpty()) {
builder.addPropertyValue("procedureParameters", procedureParameterList);
}
if (!sqlParameterDefinitionList.isEmpty()) {
builder.addPropertyValue("sqlParameters", sqlParameterDefinitionList);
}
if (!returningResultsetMap.isEmpty()) {
builder.addPropertyValue("returningResultSetRowMappers", returningResultsetMap);
}
String replyChannel = gatewayElement.getAttribute("reply-channel");
if (StringUtils.hasText(replyChannel)) {
builder.addPropertyReference("outputChannel", replyChannel);
}
return builder;
}
@Override
protected String getInputChannelAttributeName() {
return "request-channel";
}
}

View File

@@ -0,0 +1,208 @@
/*
* Copyright 2002-2011 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.integration.jdbc.config;
import java.sql.Types;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.jdbc.storedproc.ProcedureParameter;
import org.springframework.jdbc.core.SqlInOutParameter;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
*
*
* @author Gunnar Hillert
* @since 2.1
*
*/
public final class StoredProcParserUtils {
private static final Log logger = LogFactory
.getLog(StoredProcParserUtils.class);
/** Prevent instantiation. */
private StoredProcParserUtils() {
throw new AssertionError();
}
/**
*
* @param gatewayElement
* @param parserContext
* @return
*/
public static ManagedList<BeanDefinition> getSqlParameterDefinitionBeanDefinitions(
Element storedProcComponent, ParserContext parserContext) {
List<Element> sqlParameterDefinitionChildElements = DomUtils.getChildElementsByTagName(storedProcComponent, "sql-parameter-definition");
ManagedList<BeanDefinition> sqlParameterList = new ManagedList<BeanDefinition>();
for (Element childElement : sqlParameterDefinitionChildElements) {
String name = childElement.getAttribute("name");
String sqlType = childElement.getAttribute("type");
String direction = childElement.getAttribute("direction");
String scale = childElement.getAttribute("scale");
final BeanDefinitionBuilder parameterBuilder;
if ("OUT".equalsIgnoreCase(direction)) {
parameterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SqlOutParameter.class);
} else if ("INOUT".equalsIgnoreCase(direction)) {
parameterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SqlInOutParameter.class);
} else {
parameterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SqlParameter.class);
}
if (StringUtils.hasText(name)) {
parameterBuilder.addConstructorArgValue(name);
} else {
parserContext.getReaderContext().error(
"The 'name' attribute must be set for the Sql parameter element.", storedProcComponent);
}
if (StringUtils.hasText(sqlType)) {
JdbcTypesEnum jdbcTypeEnum = JdbcTypesEnum.convertToJdbcTypesEnum(sqlType);
if (jdbcTypeEnum != null) {
parameterBuilder.addConstructorArgValue(jdbcTypeEnum.getCode());
} else {
parameterBuilder.addConstructorArgValue(sqlType);
}
} else {
parameterBuilder.addConstructorArgValue(Types.VARCHAR);
}
if (StringUtils.hasText(scale)) {
parameterBuilder.addConstructorArgValue(new TypedStringValue(scale, Integer.class));
}
sqlParameterList.add(parameterBuilder.getBeanDefinition());
}
return sqlParameterList;
}
/**
*
* @param gatewayElement
* @param parserContext
* @return
*/
public static ManagedList<BeanDefinition> getProcedureParameterBeanDefinitions(
Element storedProcComponent, ParserContext parserContext) {
ManagedList<BeanDefinition> procedureParameterList = new ManagedList<BeanDefinition>();
List<Element> parameterChildElements = DomUtils
.getChildElementsByTagName(storedProcComponent, "parameter");
for (Element childElement : parameterChildElements) {
BeanDefinitionBuilder parameterBuilder = BeanDefinitionBuilder.genericBeanDefinition(ProcedureParameter.class);
String name = childElement.getAttribute("name");
String expression = childElement.getAttribute("expression");
String value = childElement.getAttribute("value");
String type = childElement.getAttribute("type");
if (StringUtils.hasText(name)) {
parameterBuilder.addPropertyValue("name", name);
} else {
parserContext
.getReaderContext()
.error("The 'name' attribute must be set for the Stored Procedure parameter element.",
storedProcComponent);
}
if (StringUtils.hasText(expression)) {
parameterBuilder.addPropertyValue("expression", expression);
}
if (StringUtils.hasText(value)) {
if (!StringUtils.hasText(type)) {
logger.info(String
.format("Type attribute not set for Store Procedure parameter '%s'. Defaulting to 'java.lang.String'.",
value));
parameterBuilder.addPropertyValue("value",
new TypedStringValue(value, String.class));
} else {
parameterBuilder.addPropertyValue("value",
new TypedStringValue(value, type));
}
}
procedureParameterList.add(parameterBuilder.getBeanDefinition());
}
return procedureParameterList;
}
/**
*
* @param gatewayElement
* @param parserContext
* @return
*/
public static ManagedMap<String, BeanDefinition> getReturningResultsetBeanDefinitions(
Element storedProcComponent, ParserContext parserContext) {
List<Element> returningResultsetChildElements = DomUtils.getChildElementsByTagName(storedProcComponent, "returning-resultset");
ManagedMap<String, BeanDefinition> returningResultsetMap = new ManagedMap<String, BeanDefinition>();
for (Element childElement : returningResultsetChildElements) {
String name = childElement.getAttribute("name");
String rowMapperAsString = childElement.getAttribute("row-mapper");
if (!StringUtils.hasText(name)) {
parserContext.getReaderContext().error(
"The 'name' attribute must be set for the 'returning-resultset' element.", storedProcComponent);
}
if (!StringUtils.hasText(rowMapperAsString)) {
parserContext.getReaderContext().error(
"The 'row-mapper' attribute must be set for the 'returning-resultset' element.", storedProcComponent);
}
BeanDefinitionBuilder rowMapperBuilder = BeanDefinitionBuilder.genericBeanDefinition(rowMapperAsString);
returningResultsetMap.put(name, rowMapperBuilder.getBeanDefinition());
}
return returningResultsetMap;
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2002-2011 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.integration.jdbc.config;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jdbc.StoredProcPollingChannelAdapter;
import org.w3c.dom.Element;
/**
* @author Gunnar Hillert
* @since 2.1
*
*/
public class StoredProcPollingChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser {
protected boolean shouldGenerateId() {
return false;
}
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected BeanMetadataElement parseSource(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(StoredProcPollingChannelAdapter.class);
String dataSourceRef = element.getAttribute("data-source");
String storedProcedureName = element.getAttribute("stored-procedure-name");
builder.addConstructorArgReference(dataSourceRef);
builder.addConstructorArgValue(storedProcedureName);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "ignore-column-meta-data");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "return-value-required");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "expect-single-result");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "function");
final ManagedList<BeanDefinition> procedureParameterList = StoredProcParserUtils.getProcedureParameterBeanDefinitions(element, parserContext);
final ManagedList<BeanDefinition> sqlParameterDefinitionList = StoredProcParserUtils.getSqlParameterDefinitionBeanDefinitions(element, parserContext);
final ManagedMap<String, BeanDefinition> returningResultsetMap = StoredProcParserUtils.getReturningResultsetBeanDefinitions(element, parserContext);
if (!procedureParameterList.isEmpty()) {
builder.addPropertyValue("procedureParameters", procedureParameterList);
}
if (!sqlParameterDefinitionList.isEmpty()) {
builder.addPropertyValue("sqlParameters", sqlParameterDefinitionList);
}
if (!returningResultsetMap.isEmpty()) {
builder.addPropertyValue("returningResultSetRowMappers", returningResultsetMap);
}
return builder.getBeanDefinition();
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright 2002-2011 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.integration.jdbc.storedproc;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.springframework.util.Assert;
/**
* Abstraction of Procedure parameters allowing to provide static parameters
* and SpEl Expression based parameters.
*
* @author Gunnar Hillert
* @since 2.1
*
*/
public class ProcedureParameter {
private String name;
private Object value;
private String expression;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Object getValue() {
return this.value;
}
public void setValue(Object value) {
this.value = value;
}
public String getExpression() {
return this.expression;
}
public void setExpression(String expression) {
this.expression = expression;
}
/**
* Instantiates a new Procedure Parameter.
*
* @param name Name of the procedure parameter, must not be null or empty
* @param value If null, the expression property must be set
* @param expression If null, the value property must be set
*/
public ProcedureParameter(String name, Object value, String expression) {
super();
Assert.hasText(name, "Please provide a name.");
this.name = name;
this.value = value;
this.expression = expression;
}
/**
* Default constructor.
*/
public ProcedureParameter() {
super();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("ProcedureParameter [name=").append(this.name)
.append(", value=").append(this.value)
.append(", expression=").append(this.expression)
.append("]");
return builder.toString();
}
/**
* Utility method that converts a Collection of {@link ProcedureParameter} to
* a Map containing only expression parameters.
*
* @param procedureParameters Must not be null.
* @return Map containing only the Expression bound parameters. Will never be null.
*/
public static Map<String, String> convertExpressions(Collection<ProcedureParameter> procedureParameters) {
Assert.notNull(procedureParameters, "The Collection of procedureParameters must not be null.");
Map<String, String> staticParameters = new HashMap<String, String>();
for (ProcedureParameter parameter : procedureParameters) {
if (parameter.getExpression() != null) {
staticParameters.put(parameter.getName(), parameter.getExpression());
}
}
return staticParameters;
}
/**
* Utility method that converts a Collection of {@link ProcedureParameter} to
* a Map containing only static parameters.
*
* @param procedureParameters Must not be null.
* @return Map containing only the static parameters. Will never be null.
*/
public static Map<String, Object> convertStaticParameters(Collection<ProcedureParameter> procedureParameters) {
Map<String, Object> staticParameters = new HashMap<String, Object>();
for (ProcedureParameter parameter : procedureParameters) {
if (parameter.getValue() != null) {
staticParameters.put(parameter.getName(), parameter.getValue());
}
}
return staticParameters;
}
}

View File

@@ -551,4 +551,609 @@
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="stored-proc-outbound-channel-adapter">
<xsd:annotation>
<xsd:documentation>
Defines an outbound Channel Adapter for updating a
database using stored procedures.
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0"
maxOccurs="1" />
<xsd:element name="sql-parameter-definition" minOccurs="0"
maxOccurs="unbounded" type="sqlParameterDefinitionType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
For fully supported database these parameters
need not be declared as for those database the
type information can be retrieved from the
JDBC Metadata.
Fully Supported Databases (Stored Procedures):
* Apache Derby
* DB2
* MySQL
* Microsoft SQL Server
* Oracle
* PostgreSQL
* Sybase
Fully Supported Databases (Functions)
* MySQL
* Microsoft SQL Server
* Oracle
* PostgreSQL
If you use a database not listed above, you
MUST provide Sql Parameter Definitions.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="parameter" minOccurs="0" maxOccurs="unbounded"
type="parameterSubElementType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Provides a mechanism to provide stored procedure
parameters.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attributeGroup ref="coreStoredProcComponentAttributes"/>
<xsd:attribute name="sql-parameter-source-factory"
type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<xsd:documentation>
Reference to a SqlParameterSourceFactory. The input is the whole
outgoing message. The
default factory creates a bean
property parameter source so the query can specify named
parameters like :payload and :headers[foo].
</xsd:documentation>
<tool:annotation kind="ref">
<tool:expected-type
type="org.springframework.integration.jdbc.SqlParameterSourceFactory" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="channel" type="xsd:string" use="required">
<xsd:annotation>
<xsd:appinfo>
<xsd:documentation>
Channel from which messages will be output.
When a message is sent to this channel it will
cause the query
to be executed.
</xsd:documentation>
<tool:annotation kind="ref">
<tool:expected-type
type="org.springframework.integration.core.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="order">
<xsd:annotation>
<xsd:documentation>
Specifies the order for invocation when this endpoint is connected as a
subscriber to a SubscribableChannel.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="return-value-required" default="false">
<xsd:annotation>
<xsd:appinfo>
<xsd:documentation>
</xsd:documentation>
</xsd:appinfo>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="stored-proc-outbound-gateway">
<xsd:annotation>
<xsd:documentation>
Defines an Outbound Channel Gateway for updating a database using
a stored procedure. The response of the stored procedure is used
to populate the Message for the reply channel.
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:sequence>
<xsd:element name="sql-parameter-definition" minOccurs="0"
maxOccurs="unbounded" type="sqlParameterDefinitionType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
For fully supported database these parameters
generally need not be declared as for those
databases the type information can be
retrieved from the JDBC Metadata.
Fully Supported Databases (Stored Procedures):
* Apache Derby
* DB2
* MySQL
* Microsoft SQL Server
* Oracle
* PostgreSQL
* Sybase
Fully Supported Databases (Functions)
* MySQL
* Microsoft SQL Server
* Oracle
* PostgreSQL
If you use a database not listed above, you
MUST provide Sql Parameter Definitions.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="parameter" minOccurs="0" maxOccurs="unbounded"
type="parameterSubElementType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Provides a mechanism to provide stored procedure
parameters. Parameters can be either static
or provided using a SpEL Expression.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="returning-resultset" minOccurs="0"
maxOccurs="unbounded" type="returningResultSetRowMappersType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Storeed procedured may return multiple resultsets.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:sequence>
<xsd:attributeGroup ref="coreStoredProcComponentAttributes"/>
<xsd:attribute name="sql-parameter-source-factory"
type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<xsd:documentation>
Reference to a SqlParameterSourceFactory. The input is the whole
outgoing message. The
default factory creates a bean
property parameter source so the query can specify named
parameters like :payload and :headers[foo].
</xsd:documentation>
<tool:annotation kind="ref">
<tool:expected-type
type="org.springframework.integration.jdbc.SqlParameterSourceFactory" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="is-function" default="false">
<xsd:annotation>
<xsd:documentation>
If "true", a SQL Function is called. In that case
the "stored-procedure-name" attribute defines
the name of the called function.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="expect-single-result" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
This parameter indicates that only one result object shall be returned from
the Stored Procedure/Function Call. If set to true and the result map
from the Stored Procedure/Function Call contains only 1 element,
then that 1 element is extracted and returned as payload.
If the result map contains more than 1 element and
expect-single-result is true, then a MessagingException
is thrown.
Otherwise the complete result map is returned as the
payload.
Important Note: Several databases such as H2 are not
fully supported for Stored Procedure and/oir Function calls.
The H2 database, for example, does not fully support the CallableStatement
semantics and when executing function calls against H2, a result list is
returned, rather than a single value.
Therefore, even if you set expect-single-result = true,
you may end up with a collection being returned.
]]>
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="request-channel" type="xsd:string"
use="required">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type
type="org.springframework.integration.core.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reply-channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type
type="org.springframework.integration.core.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="request-timeout" type="xsd:string" />
<xsd:attribute name="order">
<xsd:annotation>
<xsd:documentation>
Specifies the order for invocation when this endpoint is connected as a
subscriber to a SubscribableChannel.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="return-value-required" default="false">
<xsd:annotation>
<xsd:documentation>
Indicates whether this procedure's return value
should be included.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="stored-proc-inbound-channel-adapter">
<xsd:annotation>
<xsd:documentation>
Defines an inbound Channel Adapter for polling a
database using a stored procedure or function.
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0"
maxOccurs="1" />
<xsd:element name="sql-parameter-definition" minOccurs="0"
maxOccurs="unbounded" type="sqlParameterDefinitionType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
For fully supported database these parameters
need not be declared as for those database the
type information can be retrieved from the
JDBC Metadata.
Fully Supported Databases (Stored Procedures):
* Apache Derby
* DB2
* MySQL
* Microsoft SQL Server
* Oracle
* PostgreSQL
* Sybase
Fully Supported Databases (Functions)
* MySQL
* Microsoft SQL Server
* Oracle
* PostgreSQL
If you use a database not listed above, you
MUST provide Sql Parameter Definitions.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="parameter" minOccurs="0" maxOccurs="unbounded"
type="parameterSubElementType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Provides a mechanism to provide stored procedure
parameters.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="returning-resultset" minOccurs="0"
maxOccurs="unbounded" type="returningResultSetRowMappersType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Storeed procedured may return multiple resultsets.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attributeGroup ref="coreStoredProcComponentAttributes"/>
<xsd:attribute name="is-function" default="false">
<xsd:annotation>
<xsd:documentation>
If "true", a SQL Function is called. In that case
the "stored-procedure-name" attribute defines
the name of the called function.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="expect-single-result" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
This parameter indicates that only one result object shall be returned from
the Stored Procedure/Function Call. If set to true and the result map
from the Stored Procedure/Function Call contains only 1 element,
then that 1 element is extracted and returned as payload.
If the result map contains more than 1 element and
expect-single-result is true, then a MessagingException
is thrown.
Otherwise the complete result map is returned as the
payload.
Important Note: Several databases such as H2 are not
fully supported for Stored Procedure and/oir Function calls.
The H2 database, for example, does not fully support the CallableStatement
semantics and when executing function calls against H2, a result list is
returned, rather than a single value.
Therefore, even if you set expect-single-result = true,
you may end up with a collection being returned.
]]>
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="channel" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>
Channel to which polled messages will be send. If the stored
procedure or function does not return any data, the payload
of the Message will be Null.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type
type="org.springframework.integration.core.MessageChannel" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:attributeGroup name="coreStoredProcComponentAttributes">
<xsd:attribute name="id" type="xsd:string" use="optional" />
<xsd:attribute name="stored-procedure-name" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>
The name of the stored procedure. If the "is-function"
attribute is "true", this attributes specifies the
function name.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="data-source" type="xsd:string" use="required" >
<xsd:annotation>
<xsd:documentation>
Reference to a data source to use to access
the database.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="javax.sql.DataSource" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-startup" type="xsd:string" default="true" use="optional">
<xsd:annotation>
<xsd:documentation>
Flag to indicate that the poller should start automatically
on startup (default true).
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="ignore-column-meta-data" default="false" use="optional">
<xsd:annotation>
<xsd:documentation>
If true, the JDBC parameter definitions for the stored procedure
are not automatically derived from the underlying JDBC connection. In
that case you must specify all Sql parameter definitions explicitly
using the 'sql-parameter-definition' sub-element.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
</xsd:attributeGroup>
<xsd:complexType name="parameterSubElementType">
<xsd:attribute name="name" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of stored procedure or function parameter.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="value" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The value of the parameter. Either this or the 'expression'
attribute must be provided.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="type" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The type of the value used. If nothing is provided this attribute
will default to java.lang.String. This attribute is not used
when the 'expression' attribute is used instead.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="expression" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Expression to be evaluated to produce a value for the header.
Either this or the 'value' attribute must be provided.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="returningResultSetRowMappersType">
<xsd:attribute name="name" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the under which the resultset will be returned.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="row-mapper" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation source="java:java.lang.Class"><![CDATA[
The fully qualified class name of the row mapper.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="sqlParameterDefinitionType">
<xsd:attribute name="name" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the Sql parameter.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="direction" use="optional" default="IN">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies the direction of the Sql parameter definition. Defaults
to 'IN'. If your procedure is returning ResultSets, please
use the 'returning-resultset' element.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="sqlTypeDirection xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="type">
<xsd:annotation>
<xsd:documentation><![CDATA[
The Sql type used for this Sql parameter defintion. Will translate
into the integer value as defined by java.sql.Types. Alternatively
you can provide the integer value as well. If this attribute is
not explicitly set, then it will default to 'VARCHAR'.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="sqlType xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="scale" type="xsd:integer" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The scale of the Sql parameter. Only used for numeric and decimal
parameters.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:simpleType name="sqlType">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="VARCHAR"/>
<xsd:enumeration value="ARRAY"/>
<xsd:enumeration value="BIGINT"/>
<xsd:enumeration value="BINARY"/>
<xsd:enumeration value="BIT"/>
<xsd:enumeration value="BLOB"/>
<xsd:enumeration value="BOOLEAN"/>
<xsd:enumeration value="CHAR"/>
<xsd:enumeration value="CLOB"/>
<xsd:enumeration value="DATALINK"/>
<xsd:enumeration value="DATE"/>
<xsd:enumeration value="DECIMAL"/>
<xsd:enumeration value="DISTINCT"/>
<xsd:enumeration value="DOUBLE"/>
<xsd:enumeration value="FLOAT"/>
<xsd:enumeration value="INTEGER"/>
<xsd:enumeration value="JAVA_OBJECT"/>
<xsd:enumeration value="LONGVARBINARY"/>
<xsd:enumeration value="LONGNVARCHAR"/>
<xsd:enumeration value="LONGVARCHAR"/>
<xsd:enumeration value="NCHAR"/>
<xsd:enumeration value="NCLOB"/>
<xsd:enumeration value="NULL"/>
<xsd:enumeration value="NUMERIC"/>
<xsd:enumeration value="NVARCHAR"/>
<xsd:enumeration value="OTHER"/>
<xsd:enumeration value="REAL"/>
<xsd:enumeration value="REF"/>
<xsd:enumeration value="ROWID"/>
<xsd:enumeration value="SMALLINT"/>
<xsd:enumeration value="SQLXML"/>
<xsd:enumeration value="STRUCT"/>
<xsd:enumeration value="TIME"/>
<xsd:enumeration value="TIMESTAMP"/>
<xsd:enumeration value="TINYINT"/>
<xsd:enumeration value="VARBINARY"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="sqlTypeDirection">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="IN"/>
<xsd:enumeration value="OUT"/>
<xsd:enumeration value="INOUT"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>