From 7a5b49275f351bb84a726dc8338f489c4847d928 Mon Sep 17 00:00:00 2001 From: Gunnar Hillert Date: Tue, 22 May 2012 11:11:02 -0400 Subject: [PATCH] INT-2271 - Add Dynamic Stored Proc Names (SpEL + Header) * Add support for Stored Procedure/Function Names via Message Header * Add support for Stored Procedure/Function Names via "stored-procedure-expression" parameter * Add support for cacheable *SimpleJdbcCallOperation* instances * Add Guava dependency for Cache Support * Convert white-spaces to tabs (where occurring) * Convert line-delimiters to Linux format (where occurring) For reference see: https://jira.springsource.org/browse/INT-2271 INT-2271 - Expose Cache Stats via JMX This includes the implementation of INT-2584 - Instantiate the StoredProcExecutor as a Spring Managed Bean for each Stored Procedure Component INT-2271 Made DataSource final in StoredProcExecutor INT-2271 - Code Review Changes INT-2271 Code Review Fixes * remove attribute *allowDynamicStoredProcedureNames* * remove JDBC Headers INT-2271 Polishing Use LiteralExpression when a simple stored procedure name is supplied. --- build.gradle | 7 +- ...BeanPropertySqlParameterSourceFactory.java | 12 +- ...onEvaluatingSqlParameterSourceFactory.java | 18 +- .../integration/jdbc/JdbcMessageHandler.java | 21 +- .../integration/jdbc/JdbcOutboundGateway.java | 24 +- .../jdbc/JdbcPollingChannelAdapter.java | 15 +- .../jdbc/SqlParameterSourceFactory.java | 4 +- .../integration/jdbc/StoredProcExecutor.java | 784 +++++++----- .../jdbc/StoredProcMessageHandler.java | 194 +-- .../jdbc/StoredProcOutboundGateway.java | 315 +++-- .../jdbc/StoredProcPollingChannelAdapter.java | 334 ++++-- .../jdbc/config/JdbcMessageHandlerParser.java | 147 +-- .../jdbc/config/JdbcMessageStoreParser.java | 13 +- .../jdbc/config/JdbcNamespaceHandler.java | 6 +- .../config/JdbcOutboundGatewayParser.java | 194 +-- .../JdbcPollingChannelAdapterParser.java | 4 +- .../jdbc/config/JdbcTypesEnum.java | 110 +- .../StoredProcMessageHandlerParser.java | 134 +-- .../StoredProcOutboundGatewayParser.java | 177 ++- .../jdbc/config/StoredProcParserUtils.java | 133 ++- ...StoredProcPollingChannelAdapterParser.java | 151 ++- .../integration/jdbc/package-info.java | 2 +- .../jdbc/storedproc/ProcedureParameter.java | 180 +-- .../config/spring-integration-jdbc-2.2.xsd | 1058 ++++++++--------- .../jdbc/StoredProcExecutorTests.java | 191 ++- .../StoredProcJmxManagedBeanTests-context.xml | 69 ++ .../jdbc/StoredProcJmxManagedBeanTests.java | 194 +++ ...ocMessageHandlerDerbyIntegrationTests.java | 189 ++- ...ChannelAdapterWithinChainTests-context.xml | 24 +- ...yWithNamespaceIntegrationTests-context.xml | 76 +- ...dGatewayWithNamespaceIntegrationTests.java | 96 +- ...atewayWithSpelIntegrationTests-context.xml | 45 + ...tboundGatewayWithSpelIntegrationTests.java | 156 +++ ...hSpringContextIntegrationTests-context.xml | 125 +- ...hSpringContextIntegrationTests-context.xml | 142 +-- ...edProcPollingChannelAdapterParserTest2.xml | 51 + .../StoredProcMessageHandlerParserTests.java | 199 ++-- .../StoredProcOutboundGatewayParserTests.java | 295 ++--- ...dProcPollingChannelAdapterParserTests.java | 317 ++--- .../storedProcOutboundGatewayParserTest.xml | 59 +- ...redProcPollingChannelAdapterParserTest.xml | 80 +- ...edProcPollingChannelAdapterParserTest2.xml | 52 + .../jdbc/storedproc/CreateUser.java | 7 +- .../jdbc/storedproc/PrimeMapper.java | 19 +- .../integration/jdbc/storedproc/User.java | 98 +- .../jdbc/storedproc/UserMapper.java | 19 +- .../jdbc/storedproc/derby/DerbyFunctions.java | 21 +- .../derby/DerbyStoredProcedures.java | 21 +- .../derby-stored-procedures-drops.sql | 4 + .../derby-stored-procedures-setup-context.xml | 25 + 50 files changed, 4023 insertions(+), 2588 deletions(-) create mode 100644 spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcJmxManagedBeanTests-context.xml create mode 100644 spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcJmxManagedBeanTests.java create mode 100644 spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithSpelIntegrationTests-context.xml create mode 100644 spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithSpelIntegrationTests.java create mode 100644 spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/Copy of storedProcPollingChannelAdapterParserTest2.xml create mode 100644 spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcPollingChannelAdapterParserTest2.xml create mode 100644 spring-integration-jdbc/src/test/resources/derby-stored-procedures-drops.sql create mode 100644 spring-integration-jdbc/src/test/resources/derby-stored-procedures-setup-context.xml diff --git a/build.gradle b/build.gradle index 5b690c1b4e..fbc2d4d4c0 100644 --- a/build.gradle +++ b/build.gradle @@ -418,12 +418,15 @@ project('spring-integration-jdbc') { compile "org.springframework:spring-aop:$springVersion" compile "org.springframework:spring-jdbc:$springVersion" compile "org.springframework:spring-tx:$springVersion" + compile "com.google.guava:guava:12.0" testCompile project(":spring-integration-test") testCompile "com.h2database:h2:1.3.160" testCompile "hsqldb:hsqldb:1.8.0.10" testCompile "org.apache.derby:derby:10.5.3.0_1" testCompile "org.aspectj:aspectjrt:$aspectjVersion" testCompile "org.aspectj:aspectjweaver:$aspectjVersion" + testCompile "org.powermock:powermock-module-junit4:1.4.12" + testCompile "org.powermock:powermock-api-mockito:1.4.12" } bundlor { bundleSymbolicName = 'org.springframework.integration.jdbc' @@ -433,7 +436,9 @@ project('spring-integration-jdbc') { 'org.apache.commons.logging;version="[1.1.1, 2.0.0)"', 'org.aopalliance.*;version="[1.0.0, 2.0.0)"', 'javax.sql.*;version="0"', - 'org.w3c.dom.*;version="0"' + 'org.w3c.dom.*;version="0"', + 'com.google.guava.*;version="[12.0.0,13.0.0)"', + 'com.google.common.*;version="[11.0.0, 12.0.0)"' ] } diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/BeanPropertySqlParameterSourceFactory.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/BeanPropertySqlParameterSourceFactory.java index 47eaac4895..ce199126f2 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/BeanPropertySqlParameterSourceFactory.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/BeanPropertySqlParameterSourceFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2002-2011 the original author or authors. - * + * Copyright 2002-2012 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. @@ -24,7 +24,7 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource; /** * A default implementation of {@link SqlParameterSourceFactory} which creates an {@link SqlParameterSource} to * reference bean properties in its input. - * + * * @author Dave Syer * @since 2.0 */ @@ -39,7 +39,7 @@ public class BeanPropertySqlParameterSourceFactory implements SqlParameterSource /** * If the input is a List or a Map, the output is a map parameter source, and in that case some static parameters * can be added (default is empty). If the input is not a List or a Map then this value is ignored. - * + * * @param staticParameters the static parameters to set */ public void setStaticParameters(Map staticParameters) { diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/ExpressionEvaluatingSqlParameterSourceFactory.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/ExpressionEvaluatingSqlParameterSourceFactory.java index 9b507d1c47..aacfd62bd3 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/ExpressionEvaluatingSqlParameterSourceFactory.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/ExpressionEvaluatingSqlParameterSourceFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2002-2011 the original author or authors. - * + * Copyright 2002-2012 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. @@ -28,7 +28,7 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource; /** * An implementation of {@link SqlParameterSourceFactory} which creates an {@link SqlParameterSource} that evaluates * Spring EL expressions. In addition the user can supply static parameters that always take precedence. - * + * * @author Dave Syer * @author Oleg Zhurakousky * @since 2.0 @@ -53,7 +53,7 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre * Define some static parameter values. These take precedence over those defined as expressions in the * {@link #setParameterExpressions(Map) parameterExpressions}, so a parameter in the query will be filled from here * first, and then from the expressions. - * + * * @param staticParameters the static parameters to set */ public void setStaticParameters(Map staticParameters) { @@ -68,7 +68,7 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre * context: generally in an outbound setting it is a Message, and in an inbound setting it is a result set row (a * Map or a domain object if a RowMapper has been provided). The {@link #setStaticParameters(Map) static parameters} * can be referred to in an expression using the variable #staticParameters, for example: - * + * * * * @@ -91,7 +91,7 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre * * * - * + * * @param parameterExpressions the parameter expressions to set */ public void setParameterExpressions(Map parameterExpressions) { @@ -104,7 +104,7 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre return toReturn; } - private class ExpressionEvaluatingSqlParameterSource extends AbstractSqlParameterSource { + private final class ExpressionEvaluatingSqlParameterSource extends AbstractSqlParameterSource { private final Object input; diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcMessageHandler.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcMessageHandler.java index e77d983d63..5e7988df45 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcMessageHandler.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcMessageHandler.java @@ -1,11 +1,11 @@ /* - * Copyright 2002-2011 the original author or authors. - * + * Copyright 2002-2012 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. @@ -29,7 +29,6 @@ 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; @@ -38,14 +37,14 @@ import org.springframework.util.LinkedCaseInsensitiveMap; * A message handler that executes an SQL update. Dynamic query parameters are supported through the * {@link SqlParameterSourceFactory} abstraction, the default implementation of which wraps the message so that its bean * properties can be referred to by name in the query string E.g. - * + * *
  * INSERT INTO FOOS (MESSAGE_ID, PAYLOAD) VALUES (:headers[id], :payload)
  * 
- * + * * N.B. do not use quotes to escape the header keys. The default SQL parameter source (from Spring JDBC) can also handle * headers with dotted names (e.g. business.id) - * + * * @author Dave Syer * @since 2.0 */ @@ -62,8 +61,8 @@ public class JdbcMessageHandler extends AbstractMessageHandler { /** * Constructor taking {@link DataSource} from which the DB Connection can be obtained and the select query to * execute to retrieve new rows. - * - * @param dataSource used to create a {@link SimpleJdbcTemplate} + * + * @param dataSource Must not be null * @param updateSql query to execute */ public JdbcMessageHandler(DataSource dataSource, String updateSql) { @@ -74,7 +73,7 @@ public class JdbcMessageHandler extends AbstractMessageHandler { /** * Constructor taking {@link JdbcOperations} instance to use for query execution and the select query to execute to * retrieve new rows. - * + * * @param jdbcOperations instance to use for query execution * @param updateSql query to execute */ diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcOutboundGateway.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcOutboundGateway.java index e8fa488f83..c45569c0da 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcOutboundGateway.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcOutboundGateway.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -45,8 +45,8 @@ public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler im private volatile boolean keysGenerated; - private volatile Integer maxRowsPerPoll; - + private volatile Integer maxRowsPerPoll; + public JdbcOutboundGateway(DataSource dataSource, String updateQuery) { this(new JdbcTemplate(dataSource), updateQuery, null); } @@ -73,15 +73,15 @@ public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler im /** * The maximum number of rows to pull out of the query results per poll (if * greater than zero, otherwise all rows will be packed into the outgoing - * message). - * + * message). + * * The value is ultimately set on the underlying {@link JdbcPollingChannelAdapter}. * If not specified this value will default to zero. - * + * * This parameter is only applicable if a selectQuery was provided. Null values - * are not permitted. - * - * @param maxRowsPerPoll Must not be null. + * are not permitted. + * + * @param maxRowsPerPoll Must not be null. */ public void setMaxRowsPerPoll(Integer maxRowsPerPoll) { Assert.notNull(maxRowsPerPoll, "MaxRowsPerPoll must not be null."); @@ -90,14 +90,14 @@ public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler im @Override protected void onInit() { - + if (this.maxRowsPerPoll != null) { Assert.notNull(poller, "If you want to set 'maxRowsPerPoll', then you must provide a 'selectQuery'."); - poller.setMaxRowsPerPoll(this.maxRowsPerPoll); + poller.setMaxRowsPerPoll(this.maxRowsPerPoll); } handler.afterPropertiesSet(); - + } @Override diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcPollingChannelAdapter.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcPollingChannelAdapter.java index 37dec868f5..f48587f40a 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcPollingChannelAdapter.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcPollingChannelAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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,13 +36,12 @@ 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 * executing a select query. Optionally an update can be executed after the * select in order to update processed rows. - * + * * @author Jonas Partner * @author Dave Syer * @since 2.0 @@ -68,8 +67,8 @@ public class JdbcPollingChannelAdapter extends IntegrationObjectSupport implemen /** * Constructor taking {@link DataSource} from which the DB Connection can be * obtained and the select query to execute to retrieve new rows. - * - * @param dataSource used to create a {@link SimpleJdbcTemplate} + * + * @param dataSource Must not be null * @param selectQuery query to execute */ public JdbcPollingChannelAdapter(DataSource dataSource, String selectQuery) { @@ -80,7 +79,7 @@ public class JdbcPollingChannelAdapter extends IntegrationObjectSupport implemen /** * Constructor taking {@link JdbcOperations} instance to use for query * execution and the select query to execute to retrieve new rows. - * + * * @param jdbcOperations instance to use for query execution * @param selectQuery query to execute */ @@ -107,7 +106,7 @@ public class JdbcPollingChannelAdapter extends IntegrationObjectSupport implemen /** * A source of parameters for the select query used for polling. - * + * * @param sqlQueryParameterSource the sql query parameter source to set */ public void setSelectSqlParameterSource(SqlParameterSource sqlQueryParameterSource) { @@ -118,7 +117,7 @@ public class JdbcPollingChannelAdapter extends IntegrationObjectSupport implemen * The maximum number of rows to pull out of the query results per poll (if * greater than zero, otherwise all rows will be packed into the outgoing * message). Default is zero. - * + * * @param maxRows the max rows to set */ public void setMaxRowsPerPoll(int maxRows) { diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/SqlParameterSourceFactory.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/SqlParameterSourceFactory.java index 8829257499..5e0427590b 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/SqlParameterSourceFactory.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/SqlParameterSourceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -21,7 +21,7 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource; /** * Collaborator for JDBC adapters which allows creation of * instances of {@link SqlParameterSource} for use in update operations. - * + * * @author Jonas Partner * @since 2.0 */ diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcExecutor.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcExecutor.java index c14fd8be78..e768640cb4 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcExecutor.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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 @@ -15,6 +15,7 @@ package org.springframework.integration.jdbc; import java.sql.ResultSet; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -22,9 +23,17 @@ import java.util.Map.Entry; import javax.sql.DataSource; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.context.expression.MapAccessor; +import org.springframework.expression.BeanResolver; import org.springframework.expression.Expression; +import org.springframework.expression.common.LiteralExpression; +import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.integration.Message; +import org.springframework.integration.MessageHeaders; import org.springframework.integration.jdbc.storedproc.ProcedureParameter; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; @@ -34,53 +43,48 @@ 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.jmx.export.annotation.ManagedAttribute; +import org.springframework.jmx.export.annotation.ManagedMetric; +import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.util.Assert; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.CacheStats; +import com.google.common.cache.LoadingCache; + + /** - * 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. - * + * This class is used by all Stored Procedure (Stored Function) components and + * provides the core functionality to execute those. * * @author Gunnar Hillert * @since 2.1 * */ -public class StoredProcExecutor implements InitializingBean { +@ManagedResource +public class StoredProcExecutor implements BeanFactoryAware, InitializingBean { - /** - * Uses the {@link SimpleJdbcCall} implementation for executing Stored Procedures. - */ - private final SimpleJdbcCall jdbcCallOperations; + private final StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); + private volatile BeanFactory beanFactory = null; - /** - * Name of the stored procedure or function to be executed. - */ - private volatile String storedProcedureName; + private volatile int jdbcCallOperationsCacheSize = 10; - /** - * For fully supported databases, the underlying {@link SimpleJdbcCall} can - * retrieve the parameter information for the to be invoked Stored Procedure - * or Function 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; + /** + * Uses the {@link SimpleJdbcCall} implementation for executing Stored Procedures. + */ + private volatile LoadingCache jdbcCallOperationsCache = null; + + private volatile Expression storedProcedureNameExpression; + + /** + * For fully supported databases, the underlying {@link SimpleJdbcCall} can + * retrieve the parameter information for the to be invoked Stored Procedure + * or Function 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 this variable is set to true then all results from a stored procedure call @@ -90,282 +94,414 @@ public class StoredProcExecutor implements InitializingBean { * * Value defaults to true. */ - private volatile boolean skipUndeclaredResults = true; + private volatile boolean skipUndeclaredResults = true; - /** - * If your 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. See also {@link SqlOutParameter} and - * {@link SqlInOutParameter}. - */ - private volatile List sqlParameters = new ArrayList(0); + /** + * If your 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. See also {@link SqlOutParameter} and + * {@link SqlInOutParameter}. + */ + private volatile List sqlParameters = new ArrayList(0); - /** - * By default bean properties of the passed in {@link Message} will be used - * as a source for the Stored Procedure's input parameters. By default a - * {@link BeanPropertySqlParameterSourceFactory} will be used. - * - * This may be sufficient for basic use cases. For more sophisticated options - * consider passing in one or more {@link ProcedureParameter}. - */ - private volatile SqlParameterSourceFactory sqlParameterSourceFactory = null; + /** + * By default bean properties of the passed in {@link Message} will be used + * as a source for the Stored Procedure's input parameters. By default a + * {@link BeanPropertySqlParameterSourceFactory} will be used. + * + * This may be sufficient for basic use cases. For more sophisticated options + * consider passing in one or more {@link ProcedureParameter}. + */ + private volatile SqlParameterSourceFactory sqlParameterSourceFactory = null; - /** - * 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 = null; + /** + * Indicates that whether only the payload of the passed-in {@link Message} + * shall be used as a source of parameters. + * + * @see #setUsePayloadAsParameterSource(boolean) + */ + private volatile Boolean usePayloadAsParameterSource = null; - /** - * Custom Stored Procedure parameters that may contain static values - * or Strings representing an {@link Expression}. - */ - private volatile ListprocedureParameters; + /** + * Custom Stored Procedure parameters that may contain static values + * or Strings representing an {@link Expression}. + */ + private volatile ListprocedureParameters; - private volatile boolean isFunction = false; - private volatile boolean returnValueRequired = false; - private volatile Map> returningResultSetRowMappers = new HashMap>(0); + private volatile boolean isFunction = false; + private volatile boolean returnValueRequired = false; + private volatile Map> returningResultSetRowMappers = new HashMap>(0); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + private final DataSource dataSource; - /** - * 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 or 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 == null) { - ExpressionEvaluatingSqlParameterSourceFactory expressionSourceFactory = - new ExpressionEvaluatingSqlParameterSourceFactory(); - - expressionSourceFactory.setStaticParameters(ProcedureParameter.convertStaticParameters(procedureParameters)); - expressionSourceFactory.setParameterExpressions(ProcedureParameter.convertExpressions(procedureParameters)); - - this.sqlParameterSourceFactory = expressionSourceFactory; - - } else { - - if (!(this.sqlParameterSourceFactory instanceof ExpressionEvaluatingSqlParameterSourceFactory)) { - throw new IllegalStateException("You are providing 'ProcedureParameters'. " - + "Was expecting the the provided sqlParameterSourceFactory " - + "to be an instance of 'ExpressionEvaluatingSqlParameterSourceFactory', " - + "however the provided one is of type '" + this.sqlParameterSourceFactory.getClass().getName() + "'"); - } - - } - - if (this.usePayloadAsParameterSource == null) { - this.usePayloadAsParameterSource = false; - } - - } else { - - if (this.sqlParameterSourceFactory == null) { - this.sqlParameterSourceFactory = new BeanPropertySqlParameterSourceFactory(); - } - - if (this.usePayloadAsParameterSource == null) { - this.usePayloadAsParameterSource = true; - } - - } - - if (this.ignoreColumnMetaData) { - this.jdbcCallOperations.withoutProcedureColumnMetaDataAccess(); - } - - this.jdbcCallOperations.declareParameters(this.sqlParameters.toArray(new SqlParameter[this.sqlParameters.size()])); + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - if (!this.returningResultSetRowMappers.isEmpty()) { + /** + * Constructor taking {@link DataSource} from which the DB Connection can be + * obtained. + * + * @param dataSource used to create a {@link SimpleJdbcCall} instance, must not be Null + */ + public StoredProcExecutor(DataSource dataSource) { - for (Entry> mapEntry : this.returningResultSetRowMappers.entrySet()) { - jdbcCallOperations.returningResultSet(mapEntry.getKey(), mapEntry.getValue()); - } - } + Assert.notNull(dataSource, "dataSource must not be null."); + this.dataSource = dataSource; - if (this.returnValueRequired) { - jdbcCallOperations.withReturnValue(); - } + } - if (this.isFunction) { - this.jdbcCallOperations.withFunctionName(this.storedProcedureName); - } else { - this.jdbcCallOperations.withProcedureName(this.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() { - this.jdbcCallOperations.getJdbcTemplate().setSkipUndeclaredResults(this.skipUndeclaredResults); + if (this.storedProcedureNameExpression == null) { + throw new IllegalArgumentException("You must either provide a " + + "Stored Procedure Name or a Stored Procedure Name Expression."); + } - } + if (this.procedureParameters != null ) { - /** - * Execute a Stored Procedure or Function - Use when no {@link Message} is - * available to extract {@link ProcedureParameter} values from it. - * - * @return Map containing the stored procedure results if any. - */ - public Map executeStoredProcedure() { - return executeStoredProcedureInternal(new Object()); - } + if (this.sqlParameterSourceFactory == null) { + ExpressionEvaluatingSqlParameterSourceFactory expressionSourceFactory = + new ExpressionEvaluatingSqlParameterSourceFactory(); - /** - * Execute a Stored Procedure or 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 executeStoredProcedure(Message message) { + expressionSourceFactory.setStaticParameters(ProcedureParameter.convertStaticParameters(procedureParameters)); + expressionSourceFactory.setParameterExpressions(ProcedureParameter.convertExpressions(procedureParameters)); - Assert.notNull(message, "The message parameter must not be null."); - Assert.notNull(usePayloadAsParameterSource, "Property usePayloadAsParameterSource " - + "was Null. Did you call afterPropertiesSet()?"); + this.sqlParameterSourceFactory = expressionSourceFactory; - if (usePayloadAsParameterSource) { - return executeStoredProcedureInternal(message.getPayload()); - } else { - return executeStoredProcedureInternal(message); - } + } + else { - } + if (!(this.sqlParameterSourceFactory instanceof ExpressionEvaluatingSqlParameterSourceFactory)) { + throw new IllegalStateException("You are providing 'ProcedureParameters'. " + + "Was expecting the the provided sqlParameterSourceFactory " + + "to be an instance of 'ExpressionEvaluatingSqlParameterSourceFactory', " + + "however the provided one is of type '" + this.sqlParameterSourceFactory.getClass().getName() + "'"); + } - /** - * 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 executeStoredProcedureInternal(Object input) { + } - Assert.notNull(sqlParameterSourceFactory, "Property sqlParameterSourceFactory " - + "was Null. Did you call afterPropertiesSet()?"); + if (this.usePayloadAsParameterSource == null) { + this.usePayloadAsParameterSource = false; + } - SqlParameterSource storedProcedureParameterSource = - sqlParameterSourceFactory.createParameterSource(input); + } + else { - return StoredProcExecutor.executeStoredProcedure(jdbcCallOperations, - storedProcedureParameterSource); - } + if (this.sqlParameterSourceFactory == null) { + this.sqlParameterSourceFactory = new BeanPropertySqlParameterSourceFactory(); + } - /** - */ - private static Map executeStoredProcedure(SimpleJdbcCallOperations simpleJdbcCallOperations, - SqlParameterSource storedProcedureParameterSource) { + if (this.usePayloadAsParameterSource == null) { + this.usePayloadAsParameterSource = true; + } - Map resultMap = simpleJdbcCallOperations.execute(storedProcedureParameterSource); + } - return resultMap; + jdbcCallOperationsCache = CacheBuilder.newBuilder() + .maximumSize(jdbcCallOperationsCacheSize) + .recordStats() + .build(new CacheLoader() { + @Override + public SimpleJdbcCall load(String storedProcedureName) { + return createSimpleJdbcCall(storedProcedureName); + } + }); - } + if (this.storedProcedureNameExpression instanceof LiteralExpression) { + String storedProcedureName = this.storedProcedureNameExpression.getValue(String.class); + final SimpleJdbcCall simpleJdbcCall = createSimpleJdbcCall(storedProcedureName); + this.jdbcCallOperationsCache.put(storedProcedureName, simpleJdbcCall); + } - //~~~~~Setters for Properties~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + this.evaluationContext.addPropertyAccessor(new MapAccessor()); - /** - * 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; - } + if (this.beanFactory != null) { + this.evaluationContext.setBeanResolver(new BeanFactoryResolver(this.beanFactory)); + } - /** - * Custom Stored Procedure parameters that may contain static values - * or Strings representing an {@link Expression}. - */ - public void setProcedureParameters(List procedureParameters) { + } - Assert.notEmpty(procedureParameters, "procedureParameters must not be null or empty."); + private SimpleJdbcCall createSimpleJdbcCall(String storedProcedureName) { - for (ProcedureParameter procedureParameter : procedureParameters) { - Assert.notNull(procedureParameter, "The provided list (procedureParameters) cannot contain null values."); - } + final SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(this.dataSource); - this.procedureParameters = procedureParameters; + if (this.ignoreColumnMetaData) { + simpleJdbcCall.withoutProcedureColumnMetaDataAccess(); + } - } + simpleJdbcCall.declareParameters(this.sqlParameters.toArray(new SqlParameter[this.sqlParameters.size()])); - /** - * 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 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."); - } + if (!this.returningResultSetRowMappers.isEmpty()) { - this.sqlParameters = sqlParameters; - } + for (Entry> mapEntry : this.returningResultSetRowMappers.entrySet()) { + simpleJdbcCall.returningResultSet(mapEntry.getKey(), mapEntry.getValue()); + } + } - /** - * 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; - } + if (this.returnValueRequired) { + simpleJdbcCall.withReturnValue(); + } - /** - * @return the name of the Stored Procedure or Function - * */ - public String getStoredProcedureName() { - return this.storedProcedureName; - } + if (this.isFunction) { + simpleJdbcCall.withFunctionName(storedProcedureName); + } + else { + simpleJdbcCall.withProcedureName(storedProcedureName); + } + + simpleJdbcCall.getJdbcTemplate().setSkipUndeclaredResults(this.skipUndeclaredResults); + + return simpleJdbcCall; + } + + /** + * Execute a Stored Procedure or Function - Use when no {@link Message} is + * available to extract {@link ProcedureParameter} values from it. + * + * @return Map containing the stored procedure results if any. + */ + public Map executeStoredProcedure() { + return executeStoredProcedureInternal(new Object(), this.evaluateExpression(null)); + } + + /** + * Execute a Stored Procedure or 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 executeStoredProcedure(Message message) { + + Assert.notNull(message, "The message parameter must not be null."); + Assert.notNull(usePayloadAsParameterSource, "Property usePayloadAsParameterSource " + + "was Null. Did you call afterPropertiesSet()?"); + + final Object input; + + if (usePayloadAsParameterSource) { + input = message.getPayload(); + } + else { + input = message; + } + + return executeStoredProcedureInternal(input, evaluateExpression(message)); + + } + + private String evaluateExpression(Message message) { + final String storedProcedureNameToUse = this.storedProcedureNameExpression.getValue(this.evaluationContext, + message, String.class); + + Assert.hasText(storedProcedureNameToUse, String.format( + "Unable to resolve Stored Procedure/Function name for the provided Expression '%s'.", + this.storedProcedureNameExpression.getExpressionString())); + return storedProcedureNameToUse; + } + + /** + * 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 executeStoredProcedureInternal(Object input, String storedProcedureName) { + + Assert.notNull(sqlParameterSourceFactory, "Property sqlParameterSourceFactory " + + "was Null. Did you call afterPropertiesSet()?"); + + SimpleJdbcCallOperations localSimpleJdbcCall = this.jdbcCallOperationsCache.getUnchecked(storedProcedureName); + + SqlParameterSource storedProcedureParameterSource = + sqlParameterSourceFactory.createParameterSource(input); + + return StoredProcExecutor.executeStoredProcedure(localSimpleJdbcCall, + storedProcedureParameterSource); + + } + + /** + */ + private static Map executeStoredProcedure(SimpleJdbcCallOperations simpleJdbcCallOperations, + SqlParameterSource storedProcedureParameterSource) { + + Map 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 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; + + } + + /** + * 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 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; + } + + /** + * @return the name of the Stored Procedure or Function if set. Null otherwise. + * */ + @ManagedAttribute(defaultValue="Null if not Set.") + public String getStoredProcedureName() { + return this.storedProcedureNameExpression instanceof LiteralExpression ? + storedProcedureNameExpression.getValue(String.class) : null; + } + + /** + * @return the Stored Procedure Name Expression as a String if set. Null otherwise. + * */ + @ManagedAttribute(defaultValue="Null if not Set.") + public String getStoredProcedureNameExpressionAsString() { + return this.storedProcedureNameExpression != null ? this.storedProcedureNameExpression.getExpressionString() : null; + } + + /** + * The name of the Stored Procedure or Stored Function to be executed. + * If {@link StoredProcExecutor#isFunction} is set to "true", then this + * property specifies the Stored Function name. + * + * Alternatively you can also specify the Stored Procedure name via + * {@link StoredProcExecutor#setStoredProcedureNameExpression(Expression)}. + * + * E.g., that way you can specify the name of the Stored Procedure or Stored Function + * through {@link MessageHeaders}. + * + * @param storedProcedureName Must not be null and must not be empty + * + * @see StoredProcExecutor#setStoredProcedureNameExpression(Expression) + */ + public void setStoredProcedureName(String storedProcedureName) { + Assert.hasText(storedProcedureName, "storedProcedureName must not be null and cannot be empty."); + this.storedProcedureNameExpression = new LiteralExpression(storedProcedureName); + } + + /** + * Using the {@link StoredProcExecutor#storedProcedureNameExpression} the + * {@link Message} can be used as source for the name of the + * Stored Procedure or Stored Function. + * + * If {@link StoredProcExecutor#isFunction} is set to "true", then this + * property specifies the Stored Function name. + * + * By providing a SpEL expression as value for this setter, a subset of the + * original payload, a header value or any other resolvable SpEL expression + * can be used as the basis for the Stored Procedure / Function. + * + * For the Expression evaluation the full message is available as the root object. + * + * For instance the following SpEL expressions (among others) are possible: + * + *
    + *
  • payload.foo
  • + *
  • headers.foobar
  • + *
  • new java.util.Date()
  • + *
  • 'foo' + 'bar'
  • + *
+ * + * Alternatively you can also specify the Stored Procedure name via + * {@link StoredProcExecutor#setStoredProcedureName(String)} + * + * @param storedProcedureNameExpression Must not be null. + * + */ + public void setStoredProcedureNameExpression(Expression storedProcedureNameExpression) { + Assert.notNull(storedProcedureNameExpression, "storedProcedureNameExpression must not be null."); + this.storedProcedureNameExpression = storedProcedureNameExpression; + } /** * If set to 'true', the payload of the Message will be used as a source for - * providing parameters. If false the entire Message will be available as a - * source for parameters. + * providing parameters. If false the entire {@link Message} will be available + * as a source for parameters. * * If no {@link ProcedureParameter} are passed in, this property will default to - * 'true'. This means that using a default {@link BeanPropertySqlParameterSourceFactory} - * the bean properties of the payload will be used as a source for parameter values for - * the to-be-executed Stored Procedure or Function. + * true. This means that using a default {@link BeanPropertySqlParameterSourceFactory} + * the bean properties of the payload will be used as a source for parameter + * values for the to-be-executed Stored Procedure or Function. * - * However, if {@link ProcedureParameter} are passed in, then this property - * will by default evaluate to 'false'. {@link ProcedureParameter} allow for - * SpEl Expressions to be provided and therefore it is highly beneficial to - * have access to the entire {@link Message}. + * However, if {@link ProcedureParameter}s are passed in, then this property + * will by default evaluate to false. {@link ProcedureParameter} + * allow for SpEl Expressions to be provided and therefore it is highly + * beneficial to have access to the entire {@link Message}. * * @param usePayloadAsParameterSource If false the entire {@link Message} is used as parameter source. */ - public void setUsePayloadAsParameterSource(boolean usePayloadAsParameterSource) { - this.usePayloadAsParameterSource = usePayloadAsParameterSource; - } + public void setUsePayloadAsParameterSource(boolean usePayloadAsParameterSource) { + this.usePayloadAsParameterSource = usePayloadAsParameterSource; + } + + /** + * 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. + * + * @deprecated Please use {@link #setIsFunction(boolean)} instead. + */ + @Deprecated + public void setFunction(boolean isFunction) { + this.isFunction = isFunction; + } /** * Indicates whether a Stored Procedure or a Function is being executed. @@ -373,19 +509,19 @@ public class StoredProcExecutor implements InitializingBean { * * @param isFunction If set to true an Sql Function is executed rather than a Stored Procedure. */ - public void setFunction(boolean isFunction) { - this.isFunction = isFunction; - } + public void setIsFunction(boolean isFunction) { + this.isFunction = isFunction; + } - /** - * Indicates the procedure's return value should be included in the results - * returned. - * - * @param returnValueRequired - */ - public void setReturnValueRequired(boolean returnValueRequired) { - this.returnValueRequired = returnValueRequired; - } + /** + * Indicates the procedure's return value should be included in the results + * returned. + * + * @param returnValueRequired + */ + public void setReturnValueRequired(boolean returnValueRequired) { + this.returnValueRequired = returnValueRequired; + } /** * If this variable is set to true then all results from a stored @@ -402,26 +538,92 @@ public class StoredProcExecutor implements InitializingBean { * the value defaults to true. * */ - public void setSkipUndeclaredResults(boolean skipUndeclaredResults) { + public void setSkipUndeclaredResults(boolean skipUndeclaredResults) { this.skipUndeclaredResults = skipUndeclaredResults; } /** - * 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> returningResultSetRowMappers) { + * 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> returningResultSetRowMappers) { - Assert.notNull(returningResultSetRowMappers, "returningResultSetRowMappers must not be null."); + Assert.notNull(returningResultSetRowMappers, "returningResultSetRowMappers must not be null."); - for (RowMapper rowMapper : returningResultSetRowMappers.values()) { - Assert.notNull(rowMapper, "The provided map cannot contain null values."); - } + for (RowMapper rowMapper : returningResultSetRowMappers.values()) { + Assert.notNull(rowMapper, "The provided map cannot contain null values."); + } - this.returningResultSetRowMappers = returningResultSetRowMappers; - } + this.returningResultSetRowMappers = returningResultSetRowMappers; + } + + /** + * Allows for the retrieval of metrics ({@link CacheStats}}) for the + * {@link StoredProcExecutor#jdbcCallOperationsCache}, which is used to store + * instances of {@link SimpleJdbcCallOperations}. + * + * @return Cache statistics for {@link StoredProcExecutor#jdbcCallOperationsCache} + */ + public CacheStats getJdbcCallOperationsCacheStatistics() { + return this.jdbcCallOperationsCache.stats(); + } + + /** + * Allows for the retrieval of metrics ({@link CacheStats}}) for the + * {@link StoredProcExecutor#jdbcCallOperationsCache}. + * + * Provides the properties of {@link CacheStats} as a {@link Map}. This allows + * for exposing the those properties easily via JMX. + * + * @return Map containing metrics of the JdbcCallOperationsCache + * + * @see StoredProcExecutor#getJdbcCallOperationsCacheStatistics() + */ + @ManagedMetric + public Map getJdbcCallOperationsCacheStatisticsAsMap() { + final CacheStats cacheStats = this.getJdbcCallOperationsCacheStatistics(); + final Map cacheStatistics = new HashMap(11); + cacheStatistics.put("averageLoadPenalty", cacheStats.averageLoadPenalty()); + cacheStatistics.put("evictionCount", cacheStats.evictionCount()); + cacheStatistics.put("hitCount", cacheStats.hitCount()); + cacheStatistics.put("hitRate", cacheStats.hitRate()); + cacheStatistics.put("loadCount", cacheStats.loadCount()); + cacheStatistics.put("loadExceptionCount", cacheStats.loadExceptionCount()); + cacheStatistics.put("loadExceptionRate", cacheStats.loadExceptionRate()); + cacheStatistics.put("loadSuccessCount", cacheStats.loadSuccessCount()); + cacheStatistics.put("missCount", cacheStats.missCount()); + cacheStatistics.put("missRate", cacheStats.missRate()); + cacheStatistics.put("totalLoadTime", cacheStats.totalLoadTime()); + return Collections.unmodifiableMap(cacheStatistics); + } + + /** + * Defines the maximum number of {@link SimpleJdbcCallOperations} + * ({@link SimpleJdbcCall}) instances to be held by + * {@link StoredProcExecutor#jdbcCallOperationsCache}. + * + * A value of zero will disable the cache. The default is 10. + * + * @see CacheBuilder#maximumSize(long) + * @param jdbcCallOperationsCacheSize Must not be negative. + */ + public void setJdbcCallOperationsCacheSize(int jdbcCallOperationsCacheSize) { + Assert.isTrue(jdbcCallOperationsCacheSize >= 0, "jdbcCallOperationsCacheSize must not be negative."); + this.jdbcCallOperationsCacheSize = jdbcCallOperationsCacheSize; + } + + /** + * Allows to set the optional {@link BeanFactory} which is used to add a + * {@link BeanResolver} to the {@link StandardEvaluationContext}. If not set + * this property defaults to null. + * + * @param beanFactory If set must not be null. + */ + public void setBeanFactory(BeanFactory beanFactory) { + Assert.notNull(returningResultSetRowMappers, "returningResultSetRowMappers must not be null."); + this.beanFactory = beanFactory; + } } diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcMessageHandler.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcMessageHandler.java index 19fa620abc..df007e5c6d 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcMessageHandler.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcMessageHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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 @@ -26,9 +26,9 @@ 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. * @@ -53,85 +53,135 @@ import org.springframework.util.Assert; */ public class StoredProcMessageHandler extends AbstractMessageHandler implements InitializingBean { - final StoredProcExecutor executor; + private 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) { + /** + * 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 Must not be null. + * @param storedProcedureName The name of the Stored Procedure or Function. Must not be null. + * + * @deprecated Since 2.2 use the constructor that expects a {@link StoredProcExecutor} instead + */ + @Deprecated + 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."); + 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 = new StoredProcExecutor(dataSource); + this.executor.setStoredProcedureName(storedProcedureName); - } + } - /** - * 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(); - }; + /** + * + * Constructor passing in the {@link StoredProcExecutor}. + * + * @param storedProcExecutor Must not be null. + * + */ + public StoredProcMessageHandler(StoredProcExecutor storedProcExecutor) { - /** - * 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) { + Assert.notNull(storedProcExecutor, "storedProcExecutor must not be null."); + this.executor = storedProcExecutor; - Map resultMap = executor.executeStoredProcedure(message); + } - if (logger.isDebugEnabled()) { + /** + * 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(); + }; - 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)); - } + /** + * 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) { - } + Map resultMap = executor.executeStoredProcedure(message); - } + if (logger.isDebugEnabled()) { - //~~~~~Setters for Properties~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + if (resultMap != null && !resultMap.isEmpty()) { + logger.debug(String.format("The StoredProcMessageHandler ignores return " + + "values, but the called Stored Procedure returned data: '%s'", executor.getStoredProcedureName(), resultMap)); + } - /** - * 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. - */ + } + + } + + /** + * The name of the Stored Procedure or Stored Function to be executed. + * If {@link StoredProcExecutor#isFunction} is set to "true", then this + * property specifies the Stored Function name. + * + * Alternatively you can also specify the Stored Procedure name via + * {@link StoredProcExecutor#setStoredProcedureNameExpression(Expression)}. + * + * @param storedProcedureName Must not be null and must not be empty + * + * @see StoredProcExecutor#setStoredProcedureNameExpression(Expression) + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setStoredProcedureName(String) + */ + @Deprecated + public void setStoredProcedureName(String storedProcedureName) { + this.executor.setStoredProcedureName(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. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setIgnoreColumnMetaData(boolean) + */ + @Deprecated public void setIgnoreColumnMetaData(boolean ignoreColumnMetaData) { this.executor.setIgnoreColumnMetaData(ignoreColumnMetaData); } - /** - * Custom Stored Procedure parameters that may contain static values - * or Strings representing an {@link Expression}. - */ + /** + * Custom Stored Procedure parameters that may contain static values + * or Strings representing an {@link Expression}. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setProcedureParameters(List) + */ + @Deprecated public void setProcedureParameters(List procedureParameters) { this.executor.setProcedureParameters(procedureParameters); } - /** - * If your 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. - */ + /** + * If your 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. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setSqlParameters(List) + */ + @Deprecated public void setSqlParameters(List sqlParameters) { this.executor.setSqlParameters(sqlParameters); } @@ -140,16 +190,21 @@ public class StoredProcMessageHandler extends AbstractMessageHandler implements * 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}. + * then you must provide an instance of {@link ExpressionEvaluatingSqlParameterSourceFactory}. * * If not the SqlParameterSourceFactory will be replaced by the default * {@link ExpressionEvaluatingSqlParameterSourceFactory}. * * @param sqlParameterSourceFactory + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setSqlParameterSourceFactory(SqlParameterSourceFactory) */ - public void setSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) { - this.executor.setSqlParameterSourceFactory(sqlParameterSourceFactory); - } + @Deprecated + public void setSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) { + this.executor.setSqlParameterSourceFactory(sqlParameterSourceFactory); + } /** * If set to 'true', the payload of the Message will be used as a source for @@ -167,9 +222,14 @@ public class StoredProcMessageHandler extends AbstractMessageHandler implements * have access to the entire {@link Message}. * * @param usePayloadAsParameterSource If false the entire {@link Message} is used as parameter source. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setUsePayloadAsParameterSource(boolean) */ - public void setUsePayloadAsParameterSource(boolean usePayloadAsParameterSource) { - this.executor.setUsePayloadAsParameterSource(usePayloadAsParameterSource); - } + @Deprecated + public void setUsePayloadAsParameterSource(boolean usePayloadAsParameterSource) { + this.executor.setUsePayloadAsParameterSource(usePayloadAsParameterSource); + } } diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcOutboundGateway.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcOutboundGateway.java index 282e0db931..e396e67fc3 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcOutboundGateway.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcOutboundGateway.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -33,8 +33,8 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.SqlOutParameter; 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; /** @@ -48,128 +48,193 @@ public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHand 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) { + /** + * 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 SimpleJdbcCall} instance + * @param storedProcedureName Must not be null. + * + * @deprecated Since 2.2 use the constructor that expects a {@link StoredProcExecutor} instead + */ + @Deprecated + 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."); + 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 = new StoredProcExecutor(dataSource); + this.executor.setStoredProcedureName(storedProcedureName); - } + } - /** - * 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(); - }; + /** + * Constructor taking {@link StoredProcExecutor}. + * + * @param storedProcExecutor Must not be null. + * + */ + public StoredProcOutboundGateway(StoredProcExecutor storedProcExecutor) { - @Override - protected Object handleRequestMessage(Message requestMessage) { + Assert.notNull(storedProcExecutor, "storedProcExecutor must not be null."); + this.executor = storedProcExecutor; - Map resultMap = executor.executeStoredProcedure(requestMessage); + } - final Object payload; + /** + * 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(); + }; - if (resultMap.isEmpty()) { - payload = null; - } else { + @Override + protected Object handleRequestMessage(Message requestMessage) { - if (this.expectSingleResult && resultMap.size() == 1) { - payload = resultMap.values().iterator().next(); - } else if (this.expectSingleResult && resultMap.size() > 1) { + Map resultMap = executor.executeStoredProcedure(requestMessage); - throw new MessageHandlingException(requestMessage, - "Stored Procedure/Function call returned more than " - + "1 result object and expectSingleResult was 'true'. "); + final Object payload; - } else { - payload = resultMap; - } + if (resultMap.isEmpty()) { + return null; + } + else { - } + if (this.expectSingleResult && resultMap.size() == 1) { + payload = resultMap.values().iterator().next(); + } + else if (this.expectSingleResult && resultMap.size() > 1) { - return MessageBuilder.withPayload(payload).copyHeaders(requestMessage.getHeaders()).build(); + throw new MessageHandlingException(requestMessage, + "Stored Procedure/Function call returned more than " + + "1 result object and expectSingleResult was 'true'. "); - } + } + else { + payload = resultMap; + } - /** - * 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: - * - *
    - *
  • Apache Derby
  • - *
  • DB2
  • - *
  • MySQL
  • - *
  • Microsoft SQL Server
  • - *
  • Oracle
  • - *
  • Sybase
  • - *
  • PostgreSQL
  • - *
- * , , - * We also support metadata lookup of stored functions for the following - * databases: - * - *
    - *
  • MySQL
  • - *
  • Microsoft SQL Server
  • - *
  • Oracle
  • - *
  • PostgreSQL
  • - *
- * - * See also: http://static.springsource.org/spring/docs/3.1.0.M2/spring-framework-reference/html/jdbc.html - */ - public void setSqlParameters(List 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> returningResultSetRowMappers) { - this.executor.setReturningResultSetRowMappers(returningResultSetRowMappers); - } + return MessageBuilder.withPayload(payload).copyHeaders(requestMessage.getHeaders()).build(); - /** - * If true, the JDBC parameter definitions for the stored procedure are not - * automatically derived from the underlying JDBC connection. In that case - * you must pass in {@link SqlParameter} explicitly.. - * - * @param ignoreColumnMetaData Defaults to false. - */ - public void setIgnoreColumnMetaData(boolean ignoreColumnMetaData) { - this.executor.setIgnoreColumnMetaData(ignoreColumnMetaData); - } + } - /** - * Indicates the procedure's return value should be included in the results - * returned. - * - * @param returnValueRequired - */ - public void setReturnValueRequired(boolean returnValueRequired) { - this.executor.setReturnValueRequired(returnValueRequired); - } + /** + * The name of the Stored Procedure or Stored Function to be executed. + * If {@link StoredProcExecutor#isFunction} is set to "true", then this + * property specifies the Stored Function name. + * + * Alternatively you can also specify the Stored Procedure name via + * {@link StoredProcExecutor#setStoredProcedureNameExpression(Expression)}. + * + * @param storedProcedureName Must not be null and must not be empty + * + * @see StoredProcExecutor#setStoredProcedureNameExpression(Expression) + * @see StoredProcExecutor#setStoredProcedureName(String) + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + */ + @Deprecated + public void setStoredProcedureName(String storedProcedureName) { + this.executor.setStoredProcedureName(storedProcedureName); + } - /** - * Custom Stored Procedure parameters that may contain static values - * or Strings representing an {@link Expression}. - */ + /** + * 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: + * + *
    + *
  • Apache Derby
  • + *
  • DB2
  • + *
  • MySQL
  • + *
  • Microsoft SQL Server
  • + *
  • Oracle
  • + *
  • Sybase
  • + *
  • PostgreSQL
  • + *
+ * , , + * We also support metadata lookup of stored functions for the following + * databases: + * + *
    + *
  • MySQL
  • + *
  • Microsoft SQL Server
  • + *
  • Oracle
  • + *
  • PostgreSQL
  • + *
+ * + * See also: http://static.springsource.org/spring/docs/3.1.0.M2/spring-framework-reference/html/jdbc.html + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setSqlParameters(List) + */ + @Deprecated + public void setSqlParameters(List 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. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setReturningResultSetRowMappers(Map) + */ + @Deprecated + public void setReturningResultSetRowMappers( + Map> returningResultSetRowMappers) { + this.executor.setReturningResultSetRowMappers(returningResultSetRowMappers); + } + + /** + * If true, the JDBC parameter definitions for the stored procedure are not + * automatically derived from the underlying JDBC connection. In that case + * you must pass in {@link SqlParameter} explicitly.. + * + * @param ignoreColumnMetaData Defaults to false. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setIgnoreColumnMetaData(boolean) + */ + @Deprecated + public void setIgnoreColumnMetaData(boolean ignoreColumnMetaData) { + this.executor.setIgnoreColumnMetaData(ignoreColumnMetaData); + } + + /** + * Indicates the procedure's return value should be included in the results + * returned. + * + * @param returnValueRequired + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setReturnValueRequired(boolean) + */ + @Deprecated + public void setReturnValueRequired(boolean returnValueRequired) { + this.executor.setReturnValueRequired(returnValueRequired); + } + + /** + * Custom Stored Procedure parameters that may contain static values + * or Strings representing an {@link Expression}. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setProcedureParameters(List) + */ + @Deprecated public void setProcedureParameters(List procedureParameters) { this.executor.setProcedureParameters(procedureParameters); } @@ -179,9 +244,14 @@ public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHand * The default value is false. * * @param isFunction If set to true an Sql Function is executed rather than a Stored Procedure. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setIsFunction(boolean) */ + @Deprecated public void setIsFunction(boolean isFunction) { - this.executor.setFunction(isFunction); + this.executor.setIsFunction(isFunction); } /** @@ -212,16 +282,21 @@ public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHand * 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}. + * then you must provide an instance of {@link ExpressionEvaluatingSqlParameterSourceFactory}. * * If not the SqlParameterSourceFactory will be replaced by the default * {@link ExpressionEvaluatingSqlParameterSourceFactory}. * * @param sqlParameterSourceFactory + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setSqlParameterSourceFactory(SqlParameterSourceFactory) */ - public void setSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) { - this.executor.setSqlParameterSourceFactory(sqlParameterSourceFactory); - } + @Deprecated + public void setSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) { + this.executor.setSqlParameterSourceFactory(sqlParameterSourceFactory); + } /** * If set to 'true', the payload of the Message will be used as a source for @@ -239,10 +314,15 @@ public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHand * have access to the entire {@link Message}. * * @param usePayloadAsParameterSource If false the entire {@link Message} is used as parameter source. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setUsePayloadAsParameterSource(boolean) */ - public void setUsePayloadAsParameterSource(boolean usePayloadAsParameterSource) { - this.executor.setUsePayloadAsParameterSource(usePayloadAsParameterSource); - } + @Deprecated + public void setUsePayloadAsParameterSource(boolean usePayloadAsParameterSource) { + this.executor.setUsePayloadAsParameterSource(usePayloadAsParameterSource); + } /** * If this variable is set to true then all results from a stored @@ -257,9 +337,14 @@ public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHand * * Only few developers will probably ever like to process update counts, thus * the value defaults to true. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setSkipUndeclaredResults(boolean) */ - public void setSkipUndeclaredResults(boolean skipUndeclaredResults) { - this.executor.setSkipUndeclaredResults(skipUndeclaredResults); + @Deprecated + public void setSkipUndeclaredResults(boolean skipUndeclaredResults) { + this.executor.setSkipUndeclaredResults(skipUndeclaredResults); } } diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapter.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapter.java index 7e9d7f3052..41d17800f3 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapter.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -46,167 +46,235 @@ import org.springframework.util.Assert; */ public class StoredProcPollingChannelAdapter extends IntegrationObjectSupport implements MessageSource { - private final StoredProcExecutor executor; + private 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 or Function to execute - */ - public StoredProcPollingChannelAdapter(DataSource dataSource, String storedProcedureName) { + /** + * 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 or Function to execute + * + * @deprecated Since 2.2 use the constructor that expects a {@link StoredProcExecutor} instead + */ + @Deprecated + 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."); + 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 = new StoredProcExecutor(dataSource); + this.executor.setStoredProcedureName(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 null. - */ - public Message receive() { - Object payload = poll(); - if (payload == null) { - return null; - } - return MessageBuilder.withPayload(payload).build(); - } + * Constructor taking {@link StoredProcExecutor}. + * + * @param storedProcExecutor Must not be null. + * + */ + public StoredProcPollingChannelAdapter(StoredProcExecutor storedProcExecutor) { - /** - * 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() { + Assert.notNull(storedProcExecutor, "storedProcExecutor must not be null."); + this.executor = storedProcExecutor; - final Object payload; + } - Map resultMap = doPoll(); + @Override + protected void onInit() throws Exception { + super.onInit(); + } - if (resultMap.isEmpty()) { - payload = null; - } else { + /** + * 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 null. + */ + public Message receive() { + Object payload = poll(); + if (payload == null) { + return null; + } + return MessageBuilder.withPayload(payload).build(); + } - if (this.expectSingleResult && resultMap.size() == 1) { - payload = resultMap.values().iterator().next(); - } else if (this.expectSingleResult && resultMap.size() > 1) { + /** + * 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() { - throw new MessagingException( - "Stored Procedure/Function call returned more than " - + "1 result object and expectSingleResult was 'true'. "); + final Object payload; - } else { - payload = resultMap; - } + Map resultMap = doPoll(); - } + if (resultMap.isEmpty()) { + payload = null; + } + else { - return payload; + 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'. "); - protected Map doPoll() { - return this.executor.executeStoredProcedure(); - } + } + else { + payload = resultMap; + } - public String getComponentType(){ - return "stored-proc:inbound-channel-adapter"; - } + } + + return payload; + + } + + protected Map doPoll() { + return this.executor.executeStoredProcedure(); + } + + public String getComponentType(){ + return "stored-proc:inbound-channel-adapter"; + } + + /** + * The name of the Stored Procedure or Stored Function to be executed. + * If {@link StoredProcExecutor#isFunction} is set to "true", then this + * property specifies the Stored Function name. + * + * Alternatively you can also specify the Stored Procedure name via + * {@link StoredProcExecutor#setStoredProcedureNameExpression(Expression)}. + * + * @param storedProcedureName Must not be null and must not be empty + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setStoredProcedureName(String) + */ + @Deprecated + public void setStoredProcedureName(String storedProcedureName) { + this.executor.setStoredProcedureName(storedProcedureName); + } /** * 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}. + * then you must provide an instance of {@link ExpressionEvaluatingSqlParameterSourceFactory}. * * If not the SqlParameterSourceFactory will be replaced by the default * {@link ExpressionEvaluatingSqlParameterSourceFactory}. * * @param sqlParameterSourceFactory + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setSqlParameterSourceFactory(SqlParameterSourceFactory) */ - public void setSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) { - this.executor.setSqlParameterSourceFactory(sqlParameterSourceFactory); - } + @Deprecated + 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: - * - *
    - *
  • Apache Derby
  • - *
  • DB2
  • - *
  • MySQL
  • - *
  • Microsoft SQL Server
  • - *
  • Oracle
  • - *
  • Sybase
  • - *
  • PostgreSQL
  • - *
- * , , - * We also support metadata lookup of stored functions for the following - * databases: - * - *
    - *
  • MySQL
  • - *
  • Microsoft SQL Server
  • - *
  • Oracle
  • - *
  • PostgreSQL
  • - *
- * - * See also: http://static.springsource.org/spring/docs/3.1.0.M2/spring-framework-reference/html/jdbc.html - */ - public void setSqlParameters(List sqlParameters) { - this.executor.setSqlParameters(sqlParameters); - } + /** + * 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: + * + *
    + *
  • Apache Derby
  • + *
  • DB2
  • + *
  • MySQL
  • + *
  • Microsoft SQL Server
  • + *
  • Oracle
  • + *
  • Sybase
  • + *
  • PostgreSQL
  • + *
+ * , , + * We also support metadata lookup of stored functions for the following + * databases: + * + *
    + *
  • MySQL
  • + *
  • Microsoft SQL Server
  • + *
  • Oracle
  • + *
  • PostgreSQL
  • + *
+ * + * See also: http://static.springsource.org/spring/docs/3.1.0.M2/spring-framework-reference/html/jdbc.html + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setSqlParameters(List) + */ + @Deprecated + public void setSqlParameters(List 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> returningResultSetRowMappers) { - this.executor.setReturningResultSetRowMappers(returningResultSetRowMappers); - } + /** + * Does your stored procedure return one or more result sets? If so, you + * can use the provided method for setting the respective Rowmappers. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setReturningResultSetRowMappers(Map) + */ + @Deprecated + public void setReturningResultSetRowMappers( + Map> returningResultSetRowMappers) { + this.executor.setReturningResultSetRowMappers(returningResultSetRowMappers); + } - /** - * If true, the JDBC parameter definitions for the stored procedure are not - * automatically derived from the underlying JDBC connection. In that case - * you must pass in {@link SqlParameter} explicitly.. - * - * @param ignoreColumnMetaData Defaults to false. - */ - public void setIgnoreColumnMetaData(boolean ignoreColumnMetaData) { - this.executor.setIgnoreColumnMetaData(ignoreColumnMetaData); - } + /** + * If true, the JDBC parameter definitions for the stored procedure are not + * automatically derived from the underlying JDBC connection. In that case + * you must pass in {@link SqlParameter} explicitly.. + * + * @param ignoreColumnMetaData Defaults to false. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setIgnoreColumnMetaData(boolean) + */ + @Deprecated + public void setIgnoreColumnMetaData(boolean ignoreColumnMetaData) { + this.executor.setIgnoreColumnMetaData(ignoreColumnMetaData); + } - /** - * Indicates the procedure's return value should be included in the results - * returned. - * - * @param returnValueRequired - */ - public void setReturnValueRequired(boolean returnValueRequired) { - this.executor.setReturnValueRequired(returnValueRequired); - } + /** + * Indicates the procedure's return value should be included in the results + * returned. + * + * @param returnValueRequired + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setReturnValueRequired(boolean) + */ + @Deprecated + public void setReturnValueRequired(boolean returnValueRequired) { + this.executor.setReturnValueRequired(returnValueRequired); + } - /** - * Custom Stored Procedure parameters that may contain static values - * or Strings representing an {@link Expression}. - */ + /** + * Custom Stored Procedure parameters that may contain static values + * or Strings representing an {@link Expression}. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setProcedureParameters(List) + */ + @Deprecated public void setProcedureParameters(List procedureParameters) { this.executor.setProcedureParameters(procedureParameters); } @@ -216,9 +284,14 @@ public class StoredProcPollingChannelAdapter extends IntegrationObjectSupport im * The default value is false. * * @param isFunction If set to true an Sql Function is executed rather than a Stored Procedure. + * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setIsFunction(boolean) */ + @Deprecated public void setFunction(boolean isFunction) { - this.executor.setFunction(isFunction); + this.executor.setIsFunction(isFunction); } /** @@ -259,9 +332,14 @@ public class StoredProcPollingChannelAdapter extends IntegrationObjectSupport im * Only few developers will probably ever like to process update counts, thus * the value defaults to true. * + * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} + * + * @see StoredProcExecutor#setSkipUndeclaredResults(boolean) + * */ - public void setSkipUndeclaredResults(boolean skipUndeclaredResults) { - this.executor.setSkipUndeclaredResults(skipUndeclaredResults); + @Deprecated + public void setSkipUndeclaredResults(boolean skipUndeclaredResults) { + this.executor.setSkipUndeclaredResults(skipUndeclaredResults); } } diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcMessageHandlerParser.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcMessageHandlerParser.java index 03c8f26abb..94f5c5371c 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcMessageHandlerParser.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcMessageHandlerParser.java @@ -1,73 +1,74 @@ -/* - * 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.BeanCreationException; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -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; - -/** - * @author Dave Syer - * @since 2.0 - * - */ -public class JdbcMessageHandlerParser extends AbstractOutboundChannelAdapterParser { - - protected boolean shouldGenerateId() { - return false; - } - - protected boolean shouldGenerateIdAsFallback() { - return true; - } - - @Override - protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) { - Object source = parserContext.extractSource(element); - BeanDefinitionBuilder builder = BeanDefinitionBuilder - .genericBeanDefinition(JdbcMessageHandler.class); - String dataSourceRef = element.getAttribute("data-source"); - String jdbcOperationsRef = element.getAttribute("jdbc-operations"); - boolean refToDataSourceSet = StringUtils.hasText(dataSourceRef); - boolean refToJdbcOperationsSet = StringUtils.hasText(jdbcOperationsRef); - if ((refToDataSourceSet && refToJdbcOperationsSet) - || (!refToDataSourceSet && !refToJdbcOperationsSet)) { - parserContext.getReaderContext().error( - "Exactly one of the attributes data-source or " - + "simple-jdbc-operations should be set for the JDBC outbound-channel-adapter", source); - } - String query = IntegrationNamespaceUtils.getTextFromAttributeOrNestedElement(element, "query", parserContext); - if (!StringUtils.hasText(query)) { - throw new BeanCreationException("The query attribute is required"); - } - if (!StringUtils.hasText(query)) { - throw new BeanCreationException("The query attribute is required"); - } - if (refToDataSourceSet) { - builder.addConstructorArgReference(dataSourceRef); - } else { - builder.addConstructorArgReference(jdbcOperationsRef); - } - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "sql-parameter-source-factory"); - builder.addConstructorArgValue(query); - return builder.getBeanDefinition(); - } - -} +/* + * Copyright 2002-2012 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.BeanCreationException; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +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; + +/** + * @author Dave Syer + * @since 2.0 + * + */ +public class JdbcMessageHandlerParser extends AbstractOutboundChannelAdapterParser { + + protected boolean shouldGenerateId() { + return false; + } + + protected boolean shouldGenerateIdAsFallback() { + return true; + } + + @Override + protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) { + Object source = parserContext.extractSource(element); + BeanDefinitionBuilder builder = BeanDefinitionBuilder + .genericBeanDefinition(JdbcMessageHandler.class); + String dataSourceRef = element.getAttribute("data-source"); + String jdbcOperationsRef = element.getAttribute("jdbc-operations"); + boolean refToDataSourceSet = StringUtils.hasText(dataSourceRef); + boolean refToJdbcOperationsSet = StringUtils.hasText(jdbcOperationsRef); + if ((refToDataSourceSet && refToJdbcOperationsSet) + || (!refToDataSourceSet && !refToJdbcOperationsSet)) { + parserContext.getReaderContext().error( + "Exactly one of the attributes data-source or " + + "simple-jdbc-operations should be set for the JDBC outbound-channel-adapter", source); + } + String query = IntegrationNamespaceUtils.getTextFromAttributeOrNestedElement(element, "query", parserContext); + if (!StringUtils.hasText(query)) { + throw new BeanCreationException("The query attribute is required"); + } + if (!StringUtils.hasText(query)) { + throw new BeanCreationException("The query attribute is required"); + } + if (refToDataSourceSet) { + builder.addConstructorArgReference(dataSourceRef); + } + else { + builder.addConstructorArgReference(jdbcOperationsRef); + } + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "sql-parameter-source-factory"); + builder.addConstructorArgValue(query); + return builder.getBeanDefinition(); + } + +} diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcMessageStoreParser.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcMessageStoreParser.java index 6f62280fa9..03e699436d 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcMessageStoreParser.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcMessageStoreParser.java @@ -1,11 +1,11 @@ /* - * Copyright 2002-2011 the original author or authors. - * + * Copyright 2002-2012 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. @@ -24,7 +24,7 @@ import org.w3c.dom.Element; /** * Parser for {@link org.springframework.integration.jdbc.JdbcMessageStore}. - * + * * @author Dave Syer * @since 2.0 */ @@ -51,7 +51,8 @@ public class JdbcMessageStoreParser extends AbstractBeanDefinitionParser { if (refToDataSourceSet) { builder.addPropertyReference("dataSource", dataSourceRef); - } else { + } + else { builder.addPropertyReference("jdbcTemplate", simpleJdbcOperationsRef); } diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcNamespaceHandler.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcNamespaceHandler.java index bb47940cf8..a8acb1e05c 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcNamespaceHandler.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcNamespaceHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -20,11 +20,11 @@ import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHa /** * Namespace handler for the integration JDBC schema. - * + * * @author Jonas Partner * @author Dave Syer * @author Gunnar Hillert - * + * * @since 2.0 */ public class JdbcNamespaceHandler extends AbstractIntegrationNamespaceHandler { diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java index b9f9a30c6e..5649771d34 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java @@ -1,97 +1,97 @@ -/* - * 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.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; - -/** - * @author Dave Syer - * @author Gunnar Hillert - * - * @since 2.0 - * - */ -public class JdbcOutboundGatewayParser extends AbstractConsumerEndpointParser { - - protected boolean shouldGenerateId() { - return false; - } - - protected boolean shouldGenerateIdAsFallback() { - return true; - } - - @Override - protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) { - String dataSourceRef = element.getAttribute("data-source"); - String jdbcOperationsRef = element.getAttribute("jdbc-operations"); - boolean refToDataSourceSet = StringUtils.hasText(dataSourceRef); - boolean refToJdbcOperationsSet = StringUtils.hasText(jdbcOperationsRef); - if ((refToDataSourceSet && refToJdbcOperationsSet) || (!refToDataSourceSet && !refToJdbcOperationsSet)) { - parserContext.getReaderContext().error( - "Exactly one of the attributes data-source or " - + "simple-jdbc-operations should be set for the JDBC outbound-gateway", element); - } - String selectQuery = IntegrationNamespaceUtils.getTextFromAttributeOrNestedElement(element, "query", - parserContext); - if (!StringUtils.hasText(selectQuery)) { - selectQuery = null; - } - String updateQuery = IntegrationNamespaceUtils.getTextFromAttributeOrNestedElement(element, "update", - parserContext); - if (!StringUtils.hasText(updateQuery)) { - parserContext.getReaderContext().error("The update attribute is required", element); - return null; - } - BeanDefinitionBuilder builder = BeanDefinitionBuilder - .genericBeanDefinition(JdbcOutboundGateway.class); - if (refToDataSourceSet) { - builder.addConstructorArgReference(dataSourceRef); - } - else { - builder.addConstructorArgReference(jdbcOperationsRef); - } - - builder.getRawBeanDefinition().getConstructorArgumentValues().addIndexedArgumentValue(1, updateQuery); - builder.getRawBeanDefinition().getConstructorArgumentValues().addIndexedArgumentValue(2, selectQuery); - - IntegrationNamespaceUtils - .setReferenceIfAttributeDefined(builder, element, "reply-sql-parameter-source-factory"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, - "request-sql-parameter-source-factory"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "row-mapper"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows-per-poll"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "keys-generated"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout"); - - String replyChannel = element.getAttribute("reply-channel"); - if (StringUtils.hasText(replyChannel)) { - builder.addPropertyReference("outputChannel", replyChannel); - } - - return builder; - - } - - @Override - protected String getInputChannelAttributeName() { - return "request-channel"; - } -} +/* + * Copyright 2002-2012 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.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; + +/** + * @author Dave Syer + * @author Gunnar Hillert + * + * @since 2.0 + * + */ +public class JdbcOutboundGatewayParser extends AbstractConsumerEndpointParser { + + protected boolean shouldGenerateId() { + return false; + } + + protected boolean shouldGenerateIdAsFallback() { + return true; + } + + @Override + protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) { + String dataSourceRef = element.getAttribute("data-source"); + String jdbcOperationsRef = element.getAttribute("jdbc-operations"); + boolean refToDataSourceSet = StringUtils.hasText(dataSourceRef); + boolean refToJdbcOperationsSet = StringUtils.hasText(jdbcOperationsRef); + if ((refToDataSourceSet && refToJdbcOperationsSet) || (!refToDataSourceSet && !refToJdbcOperationsSet)) { + parserContext.getReaderContext().error( + "Exactly one of the attributes data-source or " + + "simple-jdbc-operations should be set for the JDBC outbound-gateway", element); + } + String selectQuery = IntegrationNamespaceUtils.getTextFromAttributeOrNestedElement(element, "query", + parserContext); + if (!StringUtils.hasText(selectQuery)) { + selectQuery = null; + } + String updateQuery = IntegrationNamespaceUtils.getTextFromAttributeOrNestedElement(element, "update", + parserContext); + if (!StringUtils.hasText(updateQuery)) { + parserContext.getReaderContext().error("The update attribute is required", element); + return null; + } + BeanDefinitionBuilder builder = BeanDefinitionBuilder + .genericBeanDefinition(JdbcOutboundGateway.class); + if (refToDataSourceSet) { + builder.addConstructorArgReference(dataSourceRef); + } + else { + builder.addConstructorArgReference(jdbcOperationsRef); + } + + builder.getRawBeanDefinition().getConstructorArgumentValues().addIndexedArgumentValue(1, updateQuery); + builder.getRawBeanDefinition().getConstructorArgumentValues().addIndexedArgumentValue(2, selectQuery); + + IntegrationNamespaceUtils + .setReferenceIfAttributeDefined(builder, element, "reply-sql-parameter-source-factory"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, + "request-sql-parameter-source-factory"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "row-mapper"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows-per-poll"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "keys-generated"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout"); + + String replyChannel = element.getAttribute("reply-channel"); + if (StringUtils.hasText(replyChannel)) { + builder.addPropertyReference("outputChannel", replyChannel); + } + + return builder; + + } + + @Override + protected String getInputChannelAttributeName() { + return "request-channel"; + } +} diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcPollingChannelAdapterParser.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcPollingChannelAdapterParser.java index 044c771eab..6a7fb179ac 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcPollingChannelAdapterParser.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcPollingChannelAdapterParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -28,7 +28,7 @@ import org.w3c.dom.Element; /** * Parser for {@link org.springframework.integration.jdbc.JdbcPollingChannelAdapter}. - * + * * @author Jonas Partner * @since 2.0 */ diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcTypesEnum.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcTypesEnum.java index eb0690f44c..fabb61a7bd 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcTypesEnum.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcTypesEnum.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -20,50 +20,50 @@ 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 + * 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), + 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; @@ -74,34 +74,34 @@ public enum JdbcTypesEnum { } /** - * Get the numerical representation of the JDBC Type enum. The numerical value + * 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 + /** + * 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; - } - } - + if (jdbcType.name().equalsIgnoreCase(sqlTypeAsString)) { + return jdbcType; + } + } + return null; } -} \ No newline at end of file +} diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcMessageHandlerParser.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcMessageHandlerParser.java index c349b342eb..a442a0eaf3 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcMessageHandlerParser.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcMessageHandlerParser.java @@ -1,72 +1,62 @@ -/* - * 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"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "use-payload-as-parameter-source"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "sql-parameter-source-factory"); - - final ManagedList procedureParameterList = StoredProcParserUtils.getProcedureParameterBeanDefinitions(element, parserContext); - final ManagedList sqlParameterDefinitionList = StoredProcParserUtils.getSqlParameterDefinitionBeanDefinitions(element, parserContext); - - if (!procedureParameterList.isEmpty()) { - builder.addPropertyValue("procedureParameters", procedureParameterList); - } - - if (!sqlParameterDefinitionList.isEmpty()) { - builder.addPropertyValue("sqlParameters", sqlParameterDefinitionList); - } - - return builder.getBeanDefinition(); - - } - -} +/* + * Copyright 2002-2012 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.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +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.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) { + + final BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(StoredProcMessageHandler.class); + + final BeanDefinitionBuilder storedProcExecutorBuilder = StoredProcParserUtils.getStoredProcExecutorBuilder(element, parserContext); + + IntegrationNamespaceUtils.setValueIfAttributeDefined(storedProcExecutorBuilder, element, "use-payload-as-parameter-source"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(storedProcExecutorBuilder, element, "sql-parameter-source-factory"); + + final AbstractBeanDefinition storedProcExecutorBuilderBeanDefinition = storedProcExecutorBuilder.getBeanDefinition(); + final String messageHandlerId = this.resolveId(element, builder.getRawBeanDefinition(), parserContext); + final String storedProcExecutorBeanName = messageHandlerId + ".storedProcExecutor"; + + parserContext.registerBeanComponent(new BeanComponentDefinition(storedProcExecutorBuilderBeanDefinition, storedProcExecutorBeanName)); + + builder.addConstructorArgReference(storedProcExecutorBeanName); + + return builder.getBeanDefinition(); + + } + +} diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParser.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParser.java index 7a3a95eb7f..bb5d04407a 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParser.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParser.java @@ -1,90 +1,87 @@ -/* - * 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"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, gatewayElement, "use-payload-as-parameter-source"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, gatewayElement, "sql-parameter-source-factory"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, gatewayElement, "skip-undeclared-results"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, gatewayElement, "reply-timeout", "sendTimeout"); - - final ManagedList procedureParameterList = StoredProcParserUtils.getProcedureParameterBeanDefinitions(gatewayElement, parserContext); - final ManagedList sqlParameterDefinitionList = StoredProcParserUtils.getSqlParameterDefinitionBeanDefinitions(gatewayElement, parserContext); - final ManagedMap 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"; - } - -} +/* + * Copyright 2002-2012 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.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +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 element, ParserContext parserContext) { + + final BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(StoredProcOutboundGateway.class); + + final BeanDefinitionBuilder storedProcExecutorBuilder = StoredProcParserUtils.getStoredProcExecutorBuilder(element, parserContext); + + IntegrationNamespaceUtils.setValueIfAttributeDefined(storedProcExecutorBuilder, element, "is-function"); + + IntegrationNamespaceUtils.setValueIfAttributeDefined(storedProcExecutorBuilder, element, "return-value-required"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(storedProcExecutorBuilder, element, "use-payload-as-parameter-source"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(storedProcExecutorBuilder, element, "sql-parameter-source-factory"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(storedProcExecutorBuilder, element, "skip-undeclared-results"); + + final ManagedMap returningResultsetMap = StoredProcParserUtils.getReturningResultsetBeanDefinitions(element, parserContext); + + if (!returningResultsetMap.isEmpty()) { + storedProcExecutorBuilder.addPropertyValue("returningResultSetRowMappers", returningResultsetMap); + } + + final AbstractBeanDefinition storedProcExecutorBuilderBeanDefinition = storedProcExecutorBuilder.getBeanDefinition(); + final String gatewayId = this.resolveId(element, builder.getRawBeanDefinition(), parserContext); + final String storedProcExecutorBeanName = gatewayId + ".storedProcExecutor"; + + parserContext.registerBeanComponent(new BeanComponentDefinition(storedProcExecutorBuilderBeanDefinition, storedProcExecutorBeanName)); + + builder.addConstructorArgReference(storedProcExecutorBeanName); + + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "expect-single-result"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout"); + + String replyChannel = element.getAttribute("reply-channel"); + if (StringUtils.hasText(replyChannel)) { + builder.addPropertyReference("outputChannel", replyChannel); + } + + return builder; + } + + @Override + protected String getInputChannelAttributeName() { + return "request-channel"; + } + +} diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcParserUtils.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcParserUtils.java index 75096e9d4b..5f6d713b8d 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcParserUtils.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcParserUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -27,10 +27,15 @@ 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.expression.common.LiteralExpression; +import org.springframework.integration.config.ExpressionFactoryBean; +import org.springframework.integration.config.xml.IntegrationNamespaceUtils; +import org.springframework.integration.jdbc.StoredProcExecutor; 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.Assert; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; @@ -47,7 +52,7 @@ public final class StoredProcParserUtils { private StoredProcParserUtils() { throw new AssertionError(); } - + /** * @param storedProcComponent * @param parserContext @@ -56,54 +61,59 @@ public final class StoredProcParserUtils { Element storedProcComponent, ParserContext parserContext) { List sqlParameterDefinitionChildElements = DomUtils.getChildElementsByTagName(storedProcComponent, "sql-parameter-definition"); ManagedList sqlParameterList = new ManagedList(); - + 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)) { + } + else if ("INOUT".equalsIgnoreCase(direction)) { parameterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SqlInOutParameter.class); - } else { + } + else { parameterBuilder = BeanDefinitionBuilder.genericBeanDefinition(SqlParameter.class); } if (StringUtils.hasText(name)) { parameterBuilder.addConstructorArgValue(name); - } else { + } + 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 { + } + else { parameterBuilder.addConstructorArgValue(sqlType); } - - } else { + + } + else { parameterBuilder.addConstructorArgValue(Types.VARCHAR); } - + if (StringUtils.hasText(scale)) { parameterBuilder.addConstructorArgValue(new TypedStringValue(scale, Integer.class)); } - + sqlParameterList.add(parameterBuilder.getBeanDefinition()); } - return sqlParameterList; + return sqlParameterList; } - + /** * @param storedProcComponent * @param parserContext @@ -127,7 +137,7 @@ public final class StoredProcParserUtils { if (StringUtils.hasText(name)) { parameterBuilder.addPropertyValue("name", name); - } + } if (StringUtils.hasText(expression)) { parameterBuilder.addPropertyValue("expression", expression); @@ -136,18 +146,19 @@ public final class StoredProcParserUtils { if (StringUtils.hasText(value)) { if (!StringUtils.hasText(type)) { - + if (LOGGER.isInfoEnabled()) { LOGGER.info(String - .format("Type attribute not set for Store " - + "Procedure parameter '%s'. Defaulting to " - + "'java.lang.String'.", value)); + .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 { + } + else { parameterBuilder.addPropertyValue("value", new TypedStringValue(value, type)); } @@ -169,26 +180,26 @@ public final class StoredProcParserUtils { Element storedProcComponent, ParserContext parserContext) { List returningResultsetChildElements = DomUtils.getChildElementsByTagName(storedProcComponent, "returning-resultset"); - + ManagedMap returningResultsetMap = new ManagedMap(); 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()); } @@ -196,4 +207,62 @@ public final class StoredProcParserUtils { } + /** + * Create a new {@link BeanDefinitionBuilder} for the class {@link StoredProcExecutor}. + * Initialize the wrapped {@link StoredProcExecutor} with common properties. + * + * @param element Must not be Null + * @param parserContext Must not be Null + * @return The {@link BeanDefinitionBuilder} for the {@link StoredProcExecutor} + */ + public static BeanDefinitionBuilder getStoredProcExecutorBuilder(final Element element, + final ParserContext parserContext) { + + Assert.notNull(element, "The provided element must not be Null."); + Assert.notNull(parserContext, "The provided parserContext must not be Null."); + + final String dataSourceRef = element.getAttribute("data-source"); + + final BeanDefinitionBuilder storedProcExecutorBuilder = BeanDefinitionBuilder.genericBeanDefinition(StoredProcExecutor.class); + storedProcExecutorBuilder.addConstructorArgReference(dataSourceRef); + + final String storedProcedureName = element.getAttribute("stored-procedure-name"); + final String storedProcedureNameExpression = element.getAttribute("stored-procedure-name-expression"); + boolean hasStoredProcedureName = StringUtils.hasText(storedProcedureName); + boolean hasStoredProcedureNameExpression = StringUtils.hasText(storedProcedureNameExpression); + + if (!(hasStoredProcedureName ^ hasStoredProcedureNameExpression)) { + parserContext.getReaderContext() + .error("Exactly one of 'stored-procedure-name' or 'stored-procedure-name-expression' is required", + element); + } + + BeanDefinitionBuilder expressionBuilder; + if (hasStoredProcedureNameExpression) { + expressionBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class); + expressionBuilder.addConstructorArgValue(storedProcedureNameExpression); + } + else { + expressionBuilder = BeanDefinitionBuilder.genericBeanDefinition(LiteralExpression.class); + expressionBuilder.addConstructorArgValue(storedProcedureName); + } + storedProcExecutorBuilder.addPropertyValue("storedProcedureNameExpression", expressionBuilder.getBeanDefinition()); + + IntegrationNamespaceUtils.setValueIfAttributeDefined(storedProcExecutorBuilder, element, "ignore-column-meta-data"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(storedProcExecutorBuilder, element, "jdbc-call-operations-cache-size"); + + final ManagedList procedureParameterList = StoredProcParserUtils.getProcedureParameterBeanDefinitions(element, parserContext); + final ManagedList sqlParameterDefinitionList = StoredProcParserUtils.getSqlParameterDefinitionBeanDefinitions(element, parserContext); + + if (!procedureParameterList.isEmpty()) { + storedProcExecutorBuilder.addPropertyValue("procedureParameters", procedureParameterList); + } + if (!sqlParameterDefinitionList.isEmpty()) { + storedProcExecutorBuilder.addPropertyValue("sqlParameters", sqlParameterDefinitionList); + } + + return storedProcExecutorBuilder; + + } + } diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcPollingChannelAdapterParser.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcPollingChannelAdapterParser.java index 3b414726e8..715d33ef07 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcPollingChannelAdapterParser.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcPollingChannelAdapterParser.java @@ -1,77 +1,74 @@ -/* - * 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"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "skip-undeclared-results"); - - final ManagedList procedureParameterList = StoredProcParserUtils.getProcedureParameterBeanDefinitions(element, parserContext); - final ManagedList sqlParameterDefinitionList = StoredProcParserUtils.getSqlParameterDefinitionBeanDefinitions(element, parserContext); - final ManagedMap 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(); - - } - -} +/* + * Copyright 2002-2012 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.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +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); + + final BeanDefinitionBuilder storedProcExecutorBuilder = StoredProcParserUtils.getStoredProcExecutorBuilder(element, parserContext); + + IntegrationNamespaceUtils.setValueIfAttributeDefined(storedProcExecutorBuilder, element, "return-value-required"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(storedProcExecutorBuilder, element, "function"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(storedProcExecutorBuilder, element, "skip-undeclared-results"); + + final ManagedMap returningResultsetMap = StoredProcParserUtils.getReturningResultsetBeanDefinitions(element, parserContext); + + if (!returningResultsetMap.isEmpty()) { + storedProcExecutorBuilder.addPropertyValue("returningResultSetRowMappers", returningResultsetMap); + } + + final AbstractBeanDefinition storedProcExecutorBuilderBeanDefinition = storedProcExecutorBuilder.getBeanDefinition(); + final String storedProcPollingChannelAdapterId = this.resolveId(element, builder.getRawBeanDefinition(), parserContext); + final String storedProcExecutorBeanName = storedProcPollingChannelAdapterId + ".storedProcExecutor"; + + parserContext.registerBeanComponent(new BeanComponentDefinition(storedProcExecutorBuilderBeanDefinition, storedProcExecutorBeanName)); + + builder.addConstructorArgReference(storedProcExecutorBeanName); + + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "expect-single-result"); + + return builder.getBeanDefinition(); + + } + +} diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/package-info.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/package-info.java index af1bd87cd4..50d354a29e 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/package-info.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/package-info.java @@ -1,5 +1,5 @@ /** * Root package of the Spring Integration JDBC module, which contains various - * JDBC and Stored Procedure/Function supporting components. + * JDBC and Stored Procedure/Function supporting components. */ package org.springframework.integration.jdbc; \ No newline at end of file diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/storedproc/ProcedureParameter.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/storedproc/ProcedureParameter.java index f5a1692169..0d838ccbd1 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/storedproc/ProcedureParameter.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/storedproc/ProcedureParameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -22,8 +22,8 @@ import java.util.Map; import org.springframework.util.Assert; /** - * Abstraction of Procedure parameters allowing to provide static parameters - * and SpEl Expression based parameters. + * Abstraction of Procedure parameters allowing to provide static parameters + * and SpEl Expression based parameters. * * @author Gunnar Hillert * @since 2.1 @@ -31,113 +31,113 @@ import org.springframework.util.Assert; */ public class ProcedureParameter { - private String name; - private Object value; - private String expression; + 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; - } + 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, "'name' must not be empty."); + /** + * 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, "'name' must not be empty."); + + this.name = name; + this.value = value; + this.expression = expression; + } - 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(); - } + 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. + * + * @param procedureParameters Must not be null. * @return Map containing only the Expression bound parameters. Will never be null. */ - public static Map convertExpressions(Collection procedureParameters) { - - Assert.notNull(procedureParameters, "The Collection of procedureParameters must not be null."); - - for (ProcedureParameter parameter : procedureParameters) { - Assert.notNull(parameter, "'procedureParameters' must not contain null values."); - } - - Map staticParameters = new HashMap(); - - for (ProcedureParameter parameter : procedureParameters) { - if (parameter.getExpression() != null) { - staticParameters.put(parameter.getName(), parameter.getExpression()); - } - } - - return staticParameters; - } + public static Map convertExpressions(Collection procedureParameters) { + + Assert.notNull(procedureParameters, "The Collection of procedureParameters must not be null."); + + for (ProcedureParameter parameter : procedureParameters) { + Assert.notNull(parameter, "'procedureParameters' must not contain null values."); + } + + Map staticParameters = new HashMap(); + + 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. + * + * @param procedureParameters Must not be null. * @return Map containing only the static parameters. Will never be null. */ - public static Map convertStaticParameters(Collection procedureParameters) { - - Assert.notNull(procedureParameters, "The Collection of procedureParameters must not be null."); - - for (ProcedureParameter parameter : procedureParameters) { - Assert.notNull(parameter, "'procedureParameters' must not contain null values."); - } - - Map staticParameters = new HashMap(); - - for (ProcedureParameter parameter : procedureParameters) { - if (parameter.getValue() != null) { - staticParameters.put(parameter.getName(), parameter.getValue()); - } - } - - return staticParameters; - } - + public static Map convertStaticParameters(Collection procedureParameters) { + + Assert.notNull(procedureParameters, "The Collection of procedureParameters must not be null."); + + for (ProcedureParameter parameter : procedureParameters) { + Assert.notNull(parameter, "'procedureParameters' must not contain null values."); + } + + Map staticParameters = new HashMap(); + + for (ProcedureParameter parameter : procedureParameters) { + if (parameter.getValue() != null) { + staticParameters.put(parameter.getName(), parameter.getValue()); + } + } + + return staticParameters; + } + } diff --git a/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-2.2.xsd b/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-2.2.xsd index c50026a692..28a04ee98a 100644 --- a/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-2.2.xsd +++ b/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-2.2.xsd @@ -74,7 +74,7 @@ a clash with other tables). The default is "INT_". - + @@ -93,7 +93,8 @@ @@ -122,8 +123,7 @@ - Defines an inbound Channel Adapter for polling a - database. + Defines an inbound Channel Adapter for polling a database. @@ -136,8 +136,8 @@ An update query to execute when a message is polled. If the poll is in a transaction then the - update will - roll back if the transaction does. + update will roll back if the transaction + does. @@ -151,8 +151,8 @@ An update query to execute when a message is polled. If the poll is in a transaction then the - update will - roll back if the transaction does. The update can also be specified as a nested element. + update will roll back if the transaction does. + The update can also be specified as a nested element. @@ -163,8 +163,7 @@ Flag to indicate whether the update query should be executed per message, or per row (in the - case that a - message contains multiple rows). + case that a message contains multiple rows). @@ -182,8 +181,7 @@ - Channel to which polled messages will be - sent. + Channel to which polled messages will be sent. @@ -338,8 +336,7 @@ An update query to execute when a message is received. If this is in a transaction then the - update will - roll back when the transaction does. + update will roll back when the transaction does. @@ -353,24 +350,25 @@ An update query to execute when a message is received. If this is in a transaction then the - update will - roll back when the transaction does. The update can also be specified as a nested element. + update will roll back when the transaction does. + + The update can also be specified as a nested element. - - - - When using a select query, you can set a - custom limit regarding the number of rows - extracted. Otherwise by default only the first - row will be extracted into the outgoing message. + + + + When using a select query, you can set a + custom limit regarding the number of rows + extracted. Otherwise by default only the first + row will be extracted into the outgoing message. - If set to '0' all rows are extracted. - - - + If set to '0' all rows are extracted. + + + @@ -405,9 +403,9 @@ - - The receiving Message Channel of this endpoint. - + + The receiving Message Channel of this endpoint. + @@ -417,10 +415,10 @@ - - Message Channel to which replies should be sent, - after receiving the database response. - + + Message Channel to which replies should be sent, + after receiving the database response. + @@ -429,18 +427,18 @@ - - - - + + + + @@ -480,14 +478,10 @@ - Reference to a data source to use to access - the - database. Either this or the - simple-jdbc-operations - must be - specified + Reference to a data source to use to access the database. + Either this or the simple-jdbc-operations must be specified (but not both). - + @@ -499,11 +493,8 @@ - Reference to a JdbcOperations. Either - this or - the - data-source must be - specified (but not both). + Reference to a JdbcOperations. Either this or the + data-source must be specified (but not both). @@ -522,13 +513,10 @@ A select query to execute when a message is - polled. In general - the query can return multiple - rows, because - the result will be a List (of type determined by the - row - mapper). - + polled. In general the query can return multiple + rows, because the result will be a List (of + type determined by the row mapper). + @@ -543,7 +531,7 @@ the result will be a List (of type determined by the row mapper). The query can also be specified as a nested element. - + @@ -559,18 +547,13 @@ Reference to a row mapper to use to convert - JDBC result set rows to message payloads. - Optional - with default - that maps - result set row to a map (column name to column value). - Other simple - use cases can - be handled - with out-of-the box - implementations from Spring JDBC. Others require a custom row - mapper. - + JDBC result set rows to message payloads. Optional + with default that maps result set row to a map + (column name to column value). + Other simple use cases can be handled with + out-of-the box implementations from Spring JDBC. + Others require a custom row mapper. + @@ -590,42 +573,40 @@ - + + Fully Supported Databases (Functions) + + * MySQL + * Microsoft SQL Server + * Oracle + * PostgreSQL + ]]> @@ -633,40 +614,40 @@ type="parameterSubElementType"> - + - - - - - - - - - - + + + + + + + + + + @@ -675,8 +656,7 @@ Reference to a SqlParameterSourceFactory. - + @@ -691,8 +671,7 @@ to be executed. - + @@ -719,52 +698,51 @@ - - - - - - + + + + + + - + @@ -772,58 +750,56 @@ maxOccurs="unbounded" type="returningResultSetRowMappersType"> - + - - - - - - - - - - - - - - - - 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]. - - - - - - - + + + + + + + + + + + + + + + + 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]. + + + + + + + @@ -836,100 +812,98 @@ - - - + + - - - - - - - - - + + + + + + + + + - - - - - - + Therefore, even if you set expect-single-result = true, + you may end up with a collection being returned. + ]]> + + + + + + - - The receiving Message Channel of this endpoint. - + + The receiving Message Channel of this endpoint. + - + - - Message Channel to which replies should be sent, - after receiving the database response. - + + Message Channel to which replies should be sent, + after receiving the database response. + - + - - - - + + + + @@ -942,8 +916,8 @@ - Indicates the procedure's return value should be included - in the results returned. + Indicates the procedure's return value should be included + in the results returned. @@ -962,49 +936,48 @@ - - - - - + + + + - - - + If you use a database not listed above, you + MUST provide Sql Parameter Definitions. + ]]> + + + - + @@ -1012,9 +985,9 @@ maxOccurs="unbounded" type="returningResultSetRowMappersType"> - + @@ -1032,59 +1005,59 @@ - - - + + - - - - - - - - - + + + + + + + + + - - - - - - + Therefore, even if you set expect-single-result = true, + you may end up with a collection being returned. + ]]> + + + + + + @@ -1094,8 +1067,7 @@ - + @@ -1105,16 +1077,16 @@ - - - Identifies the underlying Spring bean definition, which is an - instance of either 'EventDrivenConsumer' or 'PollingConsumer', - depending on whether the component's input channel is a - 'SubscribableChannel' or 'PollableChannel'. - - + + + Identifies the underlying Spring bean definition, which is an + instance of either 'EventDrivenConsumer' or 'PollingConsumer', + depending on whether the component's input channel is a + 'SubscribableChannel' or 'PollableChannel'. + + - + The name of the stored procedure. If the "is-function" @@ -1123,6 +1095,32 @@ + + + + The name of the stored procedure provided as a SpEL expression. + Components that use a Message as source of parameters have + full access to the message and its headers, in order to + derive a stored procedure name. + + The expression must resolve to a String. + + + + + + + Defines the maximum number of cached SimpleJdbcCallOperations + instances. Basically, for each Stored Procedure Name a new + SimpleJdbcCallOperations instance is created that in return + is being cached. The default cache size is '10'. A value of + '0' disables caching. Negative values are not permitted. + + + + + + @@ -1159,147 +1157,147 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcExecutorTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcExecutorTests.java index 0aaea5d870..8d3e5945b7 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcExecutorTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcExecutorTests.java @@ -27,18 +27,35 @@ import java.util.Map; import javax.sql.DataSource; +import org.apache.log4j.Logger; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.springframework.expression.Expression; +import org.springframework.integration.config.ExpressionFactoryBean; 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 com.google.common.cache.CacheStats; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({StoredProcExecutor.class}) +@PowerMockIgnore ({"org.apache.log4j.*"}) public class StoredProcExecutorTests { + private static final Logger LOGGER = Logger.getLogger(StoredProcExecutorTests.class); + @Test public void testStoredProcExecutorWithNullDataSource() { try { - new StoredProcExecutor(null, "storedProcedureName"); + new StoredProcExecutor(null); } catch (IllegalArgumentException e) { assertEquals("dataSource must not be null.", e.getMessage()); return; @@ -53,9 +70,11 @@ public class StoredProcExecutorTests { DataSource datasource = mock(DataSource.class); try { - new StoredProcExecutor(datasource, null); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); + storedProcExecutor.afterPropertiesSet(); } catch (IllegalArgumentException e) { - assertEquals("storedProcedureName must not be null and cannot be empty.", e.getMessage()); + assertEquals("You must either provide a " + + "Stored Procedure Name or a Stored Procedure Name Expression.", e.getMessage()); return; } @@ -66,9 +85,10 @@ public class StoredProcExecutorTests { public void testStoredProcExecutorWithEmptyProcedureName() { DataSource datasource = mock(DataSource.class); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); try { - new StoredProcExecutor(datasource, " "); + storedProcExecutor.setStoredProcedureName(" "); } catch (IllegalArgumentException e) { assertEquals("storedProcedureName must not be null and cannot be empty.", e.getMessage()); return; @@ -77,11 +97,40 @@ public class StoredProcExecutorTests { fail("Exception expected."); } + @Test + public void testGetStoredProcedureNameExpressionAsString() throws Exception { + + DataSource datasource = mock(DataSource.class); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); + + final ExpressionFactoryBean efb = new ExpressionFactoryBean("headers['stored_procedure_name']"); + efb.afterPropertiesSet(); + final Expression expression = efb.getObject(); + + storedProcExecutor.setStoredProcedureNameExpression(expression); + storedProcExecutor.afterPropertiesSet(); + + assertEquals("headers['stored_procedure_name']", storedProcExecutor.getStoredProcedureNameExpressionAsString()); + } + + @Test + public void testGetStoredProcedureNameExpressionAsString2() throws Exception { + + DataSource datasource = mock(DataSource.class); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); + + storedProcExecutor.setStoredProcedureName("123"); + storedProcExecutor.afterPropertiesSet(); + + assertEquals("123", storedProcExecutor.getStoredProcedureName()); + assertEquals("123", storedProcExecutor.getStoredProcedureNameExpressionAsString()); + } + @Test public void testSetReturningResultSetRowMappersWithNullMap() { DataSource datasource = mock(DataSource.class); - StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource, "storedProcedureName"); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); try { storedProcExecutor.setReturningResultSetRowMappers(null); @@ -98,7 +147,7 @@ public class StoredProcExecutorTests { public void testSetReturningResultSetRowMappersWithMapContainingNullValues() { DataSource datasource = mock(DataSource.class); - StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource, "storedProcedureName"); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); Map> rowmappers = new HashMap>(); rowmappers.put("results", null); @@ -118,7 +167,7 @@ public class StoredProcExecutorTests { public void testSetReturningResultSetRowMappersWithEmptyMap() { DataSource datasource = mock(DataSource.class); - StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource, "storedProcedureName"); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); Map> rowmappers = new HashMap>(); @@ -131,7 +180,7 @@ public class StoredProcExecutorTests { @Test public void testSetSqlParameterSourceFactoryWithNullParameter() { DataSource datasource = mock(DataSource.class); - StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource, "storedProcedureName"); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); try { storedProcExecutor.setSqlParameterSourceFactory(null); @@ -148,7 +197,7 @@ public class StoredProcExecutorTests { public void testSetSqlParametersWithNullValueInList() { DataSource datasource = mock(DataSource.class); - StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource, "storedProcedureName"); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); List sqlParameters = new ArrayList(); sqlParameters.add(null); @@ -168,7 +217,7 @@ public class StoredProcExecutorTests { public void testSetSqlParametersWithEmptyList() { DataSource datasource = mock(DataSource.class); - StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource, "storedProcedureName"); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); List sqlParameters = new ArrayList(); @@ -187,7 +236,7 @@ public class StoredProcExecutorTests { public void testSetSqlParametersWithNullList() { DataSource datasource = mock(DataSource.class); - StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource, "storedProcedureName"); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); try { storedProcExecutor.setSqlParameters(null); @@ -204,7 +253,7 @@ public class StoredProcExecutorTests { public void testSetProcedureParametersWithNullValueInList() { DataSource datasource = mock(DataSource.class); - StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource, "storedProcedureName"); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); List procedureParameters = new ArrayList(); procedureParameters.add(null); @@ -224,7 +273,7 @@ public class StoredProcExecutorTests { public void testSetProcedureParametersWithEmptyList() { DataSource datasource = mock(DataSource.class); - StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource, "storedProcedureName"); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); List procedureParameters = new ArrayList(); @@ -243,7 +292,7 @@ public class StoredProcExecutorTests { public void testSetProcedureParametersWithNullList() { DataSource datasource = mock(DataSource.class); - StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource, "storedProcedureName"); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); try { storedProcExecutor.setProcedureParameters(null); @@ -256,4 +305,118 @@ public class StoredProcExecutorTests { } + @Test + public void testStoredProcExecutorWithNonResolvingExpression() throws Exception { + + final DataSource datasource = mock(DataSource.class); + + PowerMockito.mockStatic(StoredProcExecutor.class); + + PowerMockito.spy(StoredProcExecutor.class); + PowerMockito.doReturn(null).when(StoredProcExecutor.class, "executeStoredProcedure", Mockito.any(), Mockito.any()); + + final StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); + + final ExpressionFactoryBean efb = new ExpressionFactoryBean("headers['stored_procedure_name']"); + efb.afterPropertiesSet(); + final Expression expression = efb.getObject(); + + storedProcExecutor.setStoredProcedureNameExpression(expression); + + storedProcExecutor.afterPropertiesSet(); + + //This should work + + storedProcExecutor.executeStoredProcedure( + MessageBuilder.withPayload("test") + .setHeader("stored_procedure_name", "123") + .build()); + + //This should cause an exception + + try { + storedProcExecutor.executeStoredProcedure( + MessageBuilder.withPayload("test") + .setHeader("some_other_header", "123") + .build()); + } catch (IllegalArgumentException e) { + assertEquals("Unable to resolve Stored Procedure/Function name for the provided Expression 'headers['stored_procedure_name']'.", e.getMessage()); + return; + } + + fail("IllegalArgumentException expected."); + + } + + @Test + public void testStoredProcExecutorJdbcCallOperationsCache() throws Exception { + + final DataSource datasource = mock(DataSource.class); + + PowerMockito.mockStatic(StoredProcExecutor.class); + + PowerMockito.spy(StoredProcExecutor.class); + PowerMockito.doReturn(null).when(StoredProcExecutor.class, "executeStoredProcedure", Mockito.any(), Mockito.any()); + + final StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); + + final ExpressionFactoryBean efb = new ExpressionFactoryBean("headers['stored_procedure_name']"); + efb.afterPropertiesSet(); + final Expression expression = efb.getObject(); + + storedProcExecutor.setStoredProcedureNameExpression(expression); + + storedProcExecutor.afterPropertiesSet(); + + for (int i = 1; i <= 3; i++) { + storedProcExecutor.executeStoredProcedure( + MessageBuilder.withPayload("test") + .setHeader("stored_procedure_name", "123") + .build()); + } + + final CacheStats stats = storedProcExecutor.getJdbcCallOperationsCacheStatistics(); + LOGGER.info(stats); + LOGGER.info(stats.totalLoadTime() / 1000 / 1000); + + assertEquals(stats.hitCount(), 2); + assertEquals(stats.missCount(), 1); + assertEquals(stats.loadCount(), 1); + + } + + @Test + public void testSetJdbcCallOperationsCacheSize() throws Exception { + + final DataSource datasource = mock(DataSource.class); + + PowerMockito.mockStatic(StoredProcExecutor.class); + + PowerMockito.spy(StoredProcExecutor.class); + PowerMockito.doReturn(null).when(StoredProcExecutor.class, "executeStoredProcedure", Mockito.any(), Mockito.any()); + + final StoredProcExecutor storedProcExecutor = new StoredProcExecutor(datasource); + storedProcExecutor.setJdbcCallOperationsCacheSize(0); + + final ExpressionFactoryBean efb = new ExpressionFactoryBean("headers['stored_procedure_name']"); + efb.afterPropertiesSet(); + final Expression expression = efb.getObject(); + + storedProcExecutor.setStoredProcedureNameExpression(expression); + + storedProcExecutor.afterPropertiesSet(); + + for (int i = 1; i <= 10; i++) { + storedProcExecutor.executeStoredProcedure( + MessageBuilder.withPayload("test") + .setHeader("stored_procedure_name", "123") + .build()); + } + + final CacheStats stats = storedProcExecutor.getJdbcCallOperationsCacheStatistics(); + LOGGER.info(stats); + assertEquals("Expected a cache misscount of 10", 10, stats.missCount()); + + } + } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcJmxManagedBeanTests-context.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcJmxManagedBeanTests-context.xml new file mode 100644 index 0000000000..7ed5d47e6f --- /dev/null +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcJmxManagedBeanTests-context.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcJmxManagedBeanTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcJmxManagedBeanTests.java new file mode 100644 index 0000000000..1ad53c33e4 --- /dev/null +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcJmxManagedBeanTests.java @@ -0,0 +1,194 @@ +/* + * Copyright 2002-2012 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectName; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.integration.Message; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.jdbc.storedproc.CreateUser; +import org.springframework.integration.jdbc.storedproc.User; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Gunnar Hillert + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext +public class StoredProcJmxManagedBeanTests { + + @Autowired + private AbstractApplicationContext context; + + @Autowired + private Consumer consumer; + + @Autowired + CreateUser userService; + + @Test + @SuppressWarnings("unchecked") + public void testCollectJmxAttributes() throws Exception { + + final List servers = MBeanServerFactory.findMBeanServer(null); + assertEquals(1, servers.size()); + + final MBeanServer server = servers.iterator().next(); + + // MessageHandler + + final Set messageHandlerObjectNames = server.queryNames(ObjectName.getInstance("org.springframework.integration.jdbc.test:name=outboundChannelAdapter.adapter.storedProcExecutor,*"), null); + assertEquals(1, messageHandlerObjectNames.size()); + ObjectName messageHandlerObjectName = messageHandlerObjectNames.iterator().next(); + Map messageHandlerCacheStatistics = (Map) server.getAttribute(messageHandlerObjectName, "JdbcCallOperationsCacheStatisticsAsMap"); + + assertEquals(11, messageHandlerCacheStatistics.size()); + + assertEquals(Long.valueOf(0), messageHandlerCacheStatistics.get("hitCount")); + assertEquals(Long.valueOf(0), messageHandlerCacheStatistics.get("loadCount")); + assertEquals(Long.valueOf(0), messageHandlerCacheStatistics.get("loadExceptionCount")); + assertEquals(Long.valueOf(0), messageHandlerCacheStatistics.get("loadSuccessCount")); + assertEquals(Long.valueOf(0), messageHandlerCacheStatistics.get("missCount")); + + // StoredProcOutboundGateway + final Set storedProcOutboundGatewayObjectNames = server.queryNames(ObjectName.getInstance("org.springframework.integration.jdbc.test:name=my gateway.storedProcExecutor,*"), null); + assertEquals(1, storedProcOutboundGatewayObjectNames.size()); + ObjectName storedProcOutboundGatewayObjectName = storedProcOutboundGatewayObjectNames.iterator().next(); + Map storedProcOutboundGatewayCacheStatistics = (Map) server.getAttribute(storedProcOutboundGatewayObjectName, "JdbcCallOperationsCacheStatisticsAsMap"); + + assertEquals(11, messageHandlerCacheStatistics.size()); + + assertEquals(Long.valueOf(0), storedProcOutboundGatewayCacheStatistics.get("hitCount")); + assertEquals(Long.valueOf(0), storedProcOutboundGatewayCacheStatistics.get("loadCount")); + assertEquals(Long.valueOf(0), storedProcOutboundGatewayCacheStatistics.get("loadExceptionCount")); + assertEquals(Long.valueOf(0), storedProcOutboundGatewayCacheStatistics.get("loadSuccessCount")); + assertEquals(Long.valueOf(0), storedProcOutboundGatewayCacheStatistics.get("missCount")); + + // StoredProcPollingChannelAdapter + + final Set storedProcPollingChannelAdapterObjectNames = server.queryNames(ObjectName.getInstance("org.springframework.integration.jdbc.test:name=inbound-channel-adapter.storedProcExecutor,*"), null); + assertEquals(1, storedProcPollingChannelAdapterObjectNames.size()); + ObjectName storedProcPollingChannelAdapterObjectName = storedProcPollingChannelAdapterObjectNames.iterator().next(); + MapstoredProcPollingChannelAdapterCacheStatistics = (Map) server.getAttribute(storedProcPollingChannelAdapterObjectName, "JdbcCallOperationsCacheStatisticsAsMap"); + + assertEquals(11, storedProcPollingChannelAdapterCacheStatistics.size()); + + assertEquals(Long.valueOf(0), storedProcPollingChannelAdapterCacheStatistics.get("hitCount")); + assertEquals(Long.valueOf(0), storedProcPollingChannelAdapterCacheStatistics.get("loadCount")); + assertEquals(Long.valueOf(0), storedProcPollingChannelAdapterCacheStatistics.get("loadExceptionCount")); + assertEquals(Long.valueOf(0), storedProcPollingChannelAdapterCacheStatistics.get("loadSuccessCount")); + assertEquals(Long.valueOf(0), storedProcPollingChannelAdapterCacheStatistics.get("missCount")); + + } + + @Test + @SuppressWarnings("unchecked") + public void testOutboundGateWayJmxAttributes() throws Exception { + + final List servers = MBeanServerFactory.findMBeanServer(null); + assertEquals(1, servers.size()); + + final MBeanServer server = servers.iterator().next(); + + final Set objectNames = server.queryNames(ObjectName.getInstance("org.springframework.integration.jdbc.test:name=my gateway.storedProcExecutor,*"), null); + assertEquals(1, objectNames.size()); + ObjectName name = objectNames.iterator().next(); + Map cacheStatistics = (Map) server.getAttribute(name, "JdbcCallOperationsCacheStatisticsAsMap"); + + assertEquals(11, cacheStatistics.size()); + + assertEquals(Long.valueOf(0), cacheStatistics.get("hitCount")); + assertEquals(Long.valueOf(0), cacheStatistics.get("loadCount")); + assertEquals(Long.valueOf(0), cacheStatistics.get("loadExceptionCount")); + assertEquals(Long.valueOf(0), cacheStatistics.get("loadSuccessCount")); + assertEquals(Long.valueOf(0), cacheStatistics.get("missCount")); + + userService.createUser(new User("myUsername", "myPassword", "myEmail")); + + List>> received = new ArrayList>>(); + + received.add(consumer.poll(2000)); + + Message> message = received.get(0); + context.stop(); + + assertNotNull(message); + assertNotNull(message.getPayload()); + assertNotNull(message.getPayload() instanceof Collection); + + Map cacheStatistics2 = (Map) server.getAttribute(name, "JdbcCallOperationsCacheStatisticsAsMap"); + + assertEquals(11, cacheStatistics2.size()); + + assertEquals(Long.valueOf(1), cacheStatistics2.get("hitCount")); + assertEquals(Long.valueOf(0), cacheStatistics2.get("loadCount")); + assertEquals(Long.valueOf(0), cacheStatistics2.get("loadExceptionCount")); + assertEquals(Long.valueOf(0), cacheStatistics2.get("loadSuccessCount")); + assertEquals(Long.valueOf(0), cacheStatistics2.get("missCount")); + + } + + static class Counter { + + private final AtomicInteger count = new AtomicInteger(); + + public Integer next() throws InterruptedException { + if (count.get()>2){ + //prevent message overload + return null; + } + return Integer.valueOf(count.incrementAndGet()); + } + } + + + static class Consumer { + + private final BlockingQueue>> messages = new LinkedBlockingQueue>>(); + + @ServiceActivator + public void receive(Message> message) { + messages.add(message); + } + + Message> poll(long timeoutInMillis) throws InterruptedException { + return messages.poll(timeoutInMillis, TimeUnit.MILLISECONDS); + } + } +} diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcMessageHandlerDerbyIntegrationTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcMessageHandlerDerbyIntegrationTests.java index 0321618eb2..c34d8b949f 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcMessageHandlerDerbyIntegrationTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcMessageHandlerDerbyIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -26,7 +26,8 @@ import java.util.Map; import org.junit.After; import org.junit.Before; import org.junit.Test; - +import org.springframework.expression.Expression; +import org.springframework.integration.config.ExpressionFactoryBean; import org.springframework.integration.jdbc.storedproc.ProcedureParameter; import org.springframework.integration.jdbc.storedproc.User; import org.springframework.integration.support.MessageBuilder; @@ -40,90 +41,158 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; */ public class StoredProcMessageHandlerDerbyIntegrationTests { - private EmbeddedDatabase embeddedDatabase; + private EmbeddedDatabase embeddedDatabase; - private JdbcTemplate jdbcTemplate; + private JdbcTemplate jdbcTemplate; - @Before - public void setUp() throws SQLException { - EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); - builder.setType(EmbeddedDatabaseType.DERBY); + @Before + public void setUp() throws SQLException { + EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); + builder.setType(EmbeddedDatabaseType.DERBY); + builder.addScript("classpath:derby-stored-procedures.sql"); + this.embeddedDatabase = builder.build(); + this.jdbcTemplate = new JdbcTemplate(this.embeddedDatabase); + } - builder.addScript("classpath:derby-stored-procedures.sql"); - this.embeddedDatabase = builder.build(); - this.jdbcTemplate = new JdbcTemplate(this.embeddedDatabase); + @After + public void tearDown() { + this.embeddedDatabase.shutdown(); + } - } + @Test + public void testDerbyStoredProcedureInsertWithDefaultSqlSource() { - @After - public void tearDown() { - this.embeddedDatabase.shutdown(); - } + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(this.embeddedDatabase); + StoredProcMessageHandler messageHandler = new StoredProcMessageHandler(storedProcExecutor); - @Test - public void testDerbyStoredProcedureInsertWithDefaultSqlSource() { + storedProcExecutor.setStoredProcedureName("CREATE_USER"); - StoredProcMessageHandler messageHandler = new StoredProcMessageHandler(this.embeddedDatabase, "CREATE_USER"); - messageHandler.afterPropertiesSet(); - MessageBuilder message = MessageBuilder.withPayload(new User("username", "password", "email")); - messageHandler.handleMessage(message.build()); + storedProcExecutor.afterPropertiesSet(); + messageHandler.afterPropertiesSet(); - Map map = jdbcTemplate.queryForMap("SELECT * FROM USERS WHERE USERNAME=?", "username"); + MessageBuilder message = MessageBuilder.withPayload(new User("username", "password", "email")); + messageHandler.handleMessage(message.build()); - assertEquals("Wrong username", "username", map.get("USERNAME")); - assertEquals("Wrong password", "password", map.get("PASSWORD")); - assertEquals("Wrong email", "email", map.get("EMAIL")); + Map map = jdbcTemplate.queryForMap("SELECT * FROM USERS WHERE USERNAME=?", "username"); - } + assertEquals("Wrong username", "username", map.get("USERNAME")); + assertEquals("Wrong password", "password", map.get("PASSWORD")); + assertEquals("Wrong email", "email", map.get("EMAIL")); - @Test - public void testDerbyStoredProcedureInsertWithExpression() { + } - StoredProcMessageHandler messageHandler = new StoredProcMessageHandler(this.embeddedDatabase, "CREATE_USER"); + @Test + public void testDerbyStoredProcInsertWithDefaultSqlSourceAndDynamicProcName() throws Exception { - final List procedureParameters = new ArrayList(); - procedureParameters.add(new ProcedureParameter("username", null, "payload.username.toUpperCase()")); - procedureParameters.add(new ProcedureParameter("password", null, "payload.password.toUpperCase()")); - procedureParameters.add(new ProcedureParameter("email", null, "payload.email.toUpperCase()")); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(this.embeddedDatabase); + StoredProcMessageHandler messageHandler = new StoredProcMessageHandler(storedProcExecutor); - messageHandler.setProcedureParameters(procedureParameters); - messageHandler.afterPropertiesSet(); + final ExpressionFactoryBean efb = new ExpressionFactoryBean("headers['stored_procedure_name']"); + efb.afterPropertiesSet(); + final Expression expression = efb.getObject(); - MessageBuilder message = MessageBuilder.withPayload(new User("Eric.Cartman", "c4rtm4n", "eric@cartman.com")); - messageHandler.handleMessage(message.build()); + storedProcExecutor.setStoredProcedureNameExpression(expression); + + storedProcExecutor.afterPropertiesSet(); + messageHandler.afterPropertiesSet(); + + MessageBuilder message = MessageBuilder.withPayload(new User("username", "password", "email")); + message.setHeader("stored_procedure_name", "CREATE_USER"); + messageHandler.handleMessage(message.build()); + + Map map = jdbcTemplate.queryForMap("SELECT * FROM USERS WHERE USERNAME=?", "username"); + + assertEquals("Wrong username", "username", map.get("USERNAME")); + assertEquals("Wrong password", "password", map.get("PASSWORD")); + assertEquals("Wrong email", "email", map.get("EMAIL")); + + } + + @Test + public void testDerbyStoredProcInsertWithDefaultSqlSourceAndSpelProcName() throws Exception { + + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(this.embeddedDatabase); + StoredProcMessageHandler messageHandler = new StoredProcMessageHandler(storedProcExecutor); + ExpressionFactoryBean efb = new ExpressionFactoryBean("headers.headerWithProcedureName"); + efb.afterPropertiesSet(); + + Expression expression = efb.getObject(); + + storedProcExecutor.setStoredProcedureNameExpression(expression); + + storedProcExecutor.afterPropertiesSet(); + messageHandler.afterPropertiesSet(); + + MessageBuilder message = MessageBuilder.withPayload(new User("username", "password", "email")); + message.setHeader("headerWithProcedureName", "CREATE_USER"); + messageHandler.handleMessage(message.build()); + + Map map = jdbcTemplate.queryForMap("SELECT * FROM USERS WHERE USERNAME=?", "username"); + + assertEquals("Wrong username", "username", map.get("USERNAME")); + assertEquals("Wrong password", "password", map.get("PASSWORD")); + assertEquals("Wrong email", "email", map.get("EMAIL")); + + } + + @Test + public void testDerbyStoredProcedureInsertWithExpression() { + + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(this.embeddedDatabase); + StoredProcMessageHandler messageHandler = new StoredProcMessageHandler(storedProcExecutor); + + storedProcExecutor.setStoredProcedureName("CREATE_USER"); + + final List procedureParameters = new ArrayList(); + procedureParameters.add(new ProcedureParameter("username", null, "payload.username.toUpperCase()")); + procedureParameters.add(new ProcedureParameter("password", null, "payload.password.toUpperCase()")); + procedureParameters.add(new ProcedureParameter("email", null, "payload.email.toUpperCase()")); + + storedProcExecutor.setProcedureParameters(procedureParameters); + + storedProcExecutor.afterPropertiesSet(); + messageHandler.afterPropertiesSet(); + + MessageBuilder message = MessageBuilder.withPayload(new User("Eric.Cartman", "c4rtm4n", "eric@cartman.com")); + messageHandler.handleMessage(message.build()); - Map map = jdbcTemplate.queryForMap("SELECT * FROM USERS WHERE USERNAME=?", "ERIC.CARTMAN"); + Map map = jdbcTemplate.queryForMap("SELECT * FROM USERS WHERE USERNAME=?", "ERIC.CARTMAN"); - assertEquals("Wrong username", "ERIC.CARTMAN", map.get("USERNAME")); - assertEquals("Wrong password", "C4RTM4N", map.get("PASSWORD")); - assertEquals("Wrong email", "ERIC@CARTMAN.COM", map.get("EMAIL")); + assertEquals("Wrong username", "ERIC.CARTMAN", map.get("USERNAME")); + assertEquals("Wrong password", "C4RTM4N", map.get("PASSWORD")); + assertEquals("Wrong email", "ERIC@CARTMAN.COM", map.get("EMAIL")); - } + } - @Test - public void testDerbyStoredProcedureInsertWithHeaderExpression() { + @Test + public void testDerbyStoredProcedureInsertWithHeaderExpression() { - StoredProcMessageHandler messageHandler = new StoredProcMessageHandler(this.embeddedDatabase, "CREATE_USER"); + StoredProcExecutor storedProcExecutor = new StoredProcExecutor(this.embeddedDatabase); + StoredProcMessageHandler messageHandler = new StoredProcMessageHandler(storedProcExecutor); - final List procedureParameters = new ArrayList(); - procedureParameters.add(new ProcedureParameter("USERNAME", null, "headers[business_id] + '_' + payload.username")); - procedureParameters.add(new ProcedureParameter("password", "static_password", null)); - procedureParameters.add(new ProcedureParameter("email", "static_email" , null)); + storedProcExecutor.setStoredProcedureName("CREATE_USER"); - messageHandler.setProcedureParameters(procedureParameters); - messageHandler.afterPropertiesSet(); + final List procedureParameters = new ArrayList(); + procedureParameters.add(new ProcedureParameter("USERNAME", null, "headers[business_id] + '_' + payload.username")); + procedureParameters.add(new ProcedureParameter("password", "static_password", null)); + procedureParameters.add(new ProcedureParameter("email", "static_email" , null)); - MessageBuilder message = MessageBuilder.withPayload(new User("Eric.Cartman", "c4rtm4n", "eric@cartman.com")); - message.setHeader("business_id", "1234"); - messageHandler.handleMessage(message.build()); + storedProcExecutor.setProcedureParameters(procedureParameters); - Map map = jdbcTemplate.queryForMap("SELECT * FROM USERS WHERE USERNAME=?", "1234_Eric.Cartman"); + storedProcExecutor.afterPropertiesSet(); + messageHandler.afterPropertiesSet(); - assertEquals("Wrong username", "1234_Eric.Cartman", map.get("USERNAME")); - assertEquals("Wrong password", "static_password", map.get("PASSWORD")); - assertEquals("Wrong email", "static_email", map.get("EMAIL")); - } + MessageBuilder message = MessageBuilder.withPayload(new User("Eric.Cartman", "c4rtm4n", "eric@cartman.com")); + message.setHeader("business_id", "1234"); + messageHandler.handleMessage(message.build()); + + Map map = jdbcTemplate.queryForMap("SELECT * FROM USERS WHERE USERNAME=?", "1234_Eric.Cartman"); + + assertEquals("Wrong username", "1234_Eric.Cartman", map.get("USERNAME")); + assertEquals("Wrong password", "static_password", map.get("PASSWORD")); + assertEquals("Wrong email", "static_email", map.get("EMAIL")); + } } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundChannelAdapterWithinChainTests-context.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundChannelAdapterWithinChainTests-context.xml index 7df0ad45b2..037edc6342 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundChannelAdapterWithinChainTests-context.xml +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundChannelAdapterWithinChainTests-context.xml @@ -1,20 +1,15 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:int="http://www.springframework.org/schema/integration" + xmlns:jdbc="http://www.springframework.org/schema/jdbc" + xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc" + xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd + http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd + http://www.springframework.org/schema/integration/jdbc http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - - - - - - + @@ -28,5 +23,4 @@ - diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithNamespaceIntegrationTests-context.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithNamespaceIntegrationTests-context.xml index 067e3b3775..79e004e653 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithNamespaceIntegrationTests-context.xml +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithNamespaceIntegrationTests-context.xml @@ -1,53 +1,47 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:int="http://www.springframework.org/schema/integration" + xmlns:jdbc="http://www.springframework.org/schema/jdbc" + xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc" + xmlns:tx="http://www.springframework.org/schema/tx" + xmlns:util="http://www.springframework.org/schema/util" + xmlns:p="http://www.springframework.org/schema/p" + xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd + http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd + http://www.springframework.org/schema/integration/jdbc http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> - - - + - + - - - + - - - - - - + - + + + + + + - - + - + + - - - + diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithNamespaceIntegrationTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithNamespaceIntegrationTests.java index 56ffe96fc9..502d237620 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithNamespaceIntegrationTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithNamespaceIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -46,67 +46,67 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) public class StoredProcOutboundGatewayWithNamespaceIntegrationTests { - @Autowired - private AbstractApplicationContext context; + @Autowired + private AbstractApplicationContext context; - @Autowired - private Consumer consumer; + @Autowired + private Consumer consumer; + + @Autowired + CreateUser createUser; - @Autowired - CreateUser createUser; - @Test - public void test() throws Exception { - - createUser.createUser(new User("myUsername", "myPassword", "myEmail")); - - List>> received = new ArrayList>>(); + public void test() throws Exception { - received.add(consumer.poll(2000)); + createUser.createUser(new User("myUsername", "myPassword", "myEmail")); - Message> message = received.get(0); - context.stop(); - assertNotNull(message); - assertNotNull(message.getPayload()); - assertNotNull(message.getPayload() instanceof Collection); + List>> received = new ArrayList>>(); - Collection allUsers = message.getPayload(); + received.add(consumer.poll(2000)); - assertTrue(allUsers.size() == 1); - - User userFromDb = allUsers.iterator().next(); - - assertEquals("Wrong username", "myUsername", userFromDb.getUsername()); - assertEquals("Wrong password", "myPassword", userFromDb.getPassword()); - assertEquals("Wrong email", "myEmail", userFromDb.getEmail()); + Message> message = received.get(0); + context.stop(); + assertNotNull(message); + assertNotNull(message.getPayload()); + assertNotNull(message.getPayload() instanceof Collection); - } + Collection allUsers = message.getPayload(); - static class Counter { + assertTrue(allUsers.size() == 1); - private final AtomicInteger count = new AtomicInteger(); + User userFromDb = allUsers.iterator().next(); - public Integer next() throws InterruptedException { - if (count.get()>2){ - //prevent message overload - return null; - } - return Integer.valueOf(count.incrementAndGet()); - } - } + assertEquals("Wrong username", "myUsername", userFromDb.getUsername()); + assertEquals("Wrong password", "myPassword", userFromDb.getPassword()); + assertEquals("Wrong email", "myEmail", userFromDb.getEmail()); + + } + + static class Counter { + + private final AtomicInteger count = new AtomicInteger(); + + public Integer next() throws InterruptedException { + if (count.get()>2){ + //prevent message overload + return null; + } + return Integer.valueOf(count.incrementAndGet()); + } + } - static class Consumer { + static class Consumer { - private final BlockingQueue>> messages = new LinkedBlockingQueue>>(); + private final BlockingQueue>> messages = new LinkedBlockingQueue>>(); - @ServiceActivator - public void receive(Message> message) { - messages.add(message); - } + @ServiceActivator + public void receive(Message> message) { + messages.add(message); + } - Message> poll(long timeoutInMillis) throws InterruptedException { - return messages.poll(timeoutInMillis, TimeUnit.MILLISECONDS); - } - } + Message> poll(long timeoutInMillis) throws InterruptedException { + return messages.poll(timeoutInMillis, TimeUnit.MILLISECONDS); + } + } } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithSpelIntegrationTests-context.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithSpelIntegrationTests-context.xml new file mode 100644 index 0000000000..86c29a1bd4 --- /dev/null +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithSpelIntegrationTests-context.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithSpelIntegrationTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithSpelIntegrationTests.java new file mode 100644 index 0000000000..ed777e3dbe --- /dev/null +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithSpelIntegrationTests.java @@ -0,0 +1,156 @@ +/* + * Copyright 2002-2012 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 static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import junit.framework.Assert; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.integration.Message; +import org.springframework.integration.MessageHandlingException; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.jdbc.storedproc.User; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Gunnar Hillert + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class StoredProcOutboundGatewayWithSpelIntegrationTests { + + @Autowired + private AbstractApplicationContext context; + + @Autowired + private Consumer consumer; + + @Autowired + @Qualifier("startChannel") + DirectChannel channel; + + @Test + @DirtiesContext + public void executeStoredProcedureWithMessageHeader() throws Exception { + + User user1 = new User("First User", "my first password", "email1"); + User user2 = new User("Second User", "my second password", "email2"); + + Message user1Message = MessageBuilder.withPayload(user1) + .setHeader("my_stored_procedure", "CREATE_USER") + .build(); + Message user2Message = MessageBuilder.withPayload(user2) + .setHeader("my_stored_procedure", "CREATE_USER_RETURN_ALL") + .build(); + + channel.send(user1Message); + channel.send(user2Message); + + List>> received = new ArrayList>>(); + + received.add(consumer.poll(2000)); + + Assert.assertEquals(Integer.valueOf(1), Integer.valueOf(received.size())); + + Message> message = received.get(0); + + context.stop(); + assertNotNull(message); + + assertNotNull(message.getPayload()); + assertNotNull(message.getPayload() instanceof Collection); + + Collection allUsers = message.getPayload(); + + assertTrue(allUsers.size() == 2); + + } + + @Test + @DirtiesContext + public void testWithMissingMessageHeader() throws Exception { + + User user1 = new User("First User", "my first password", "email1"); + + Message user1Message = MessageBuilder.withPayload(user1).build(); + + try { + channel.send(user1Message); + } catch (MessageHandlingException e) { + + String expectedMessage = "Unable to resolve Stored Procedure/Function name " + + "for the provided Expression 'headers['my_stored_procedure']'."; + String actualMessage = e.getCause().getMessage(); + Assert.assertEquals(expectedMessage, actualMessage); + return; + } + + Assert.fail("Expected a MessageHandlingException to be thrown."); + + } + + static class Counter { + + private final AtomicInteger count = new AtomicInteger(); + + public Integer next() throws InterruptedException { + if (count.get()>2){ + //prevent message overload + return null; + } + return Integer.valueOf(count.incrementAndGet()); + } + } + + /** + * This class is called by the Service Activator and populates {@link Consumer#messages} + * with the Gateway's response message and is used by the Test to verify that + * the Gateway executed correctly. + */ + static class Consumer { + + private volatile BlockingQueue>> messages = new LinkedBlockingQueue>>(); + + @ServiceActivator + public void receive(Message> message) { + messages.add(message); + } + + Message> poll(long timeoutInMillis) throws InterruptedException { + return messages.poll(timeoutInMillis, TimeUnit.MILLISECONDS); + } + + } +} diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithSpringContextIntegrationTests-context.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithSpringContextIntegrationTests-context.xml index 898fd657d8..b7debeb155 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithSpringContextIntegrationTests-context.xml +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithSpringContextIntegrationTests-context.xml @@ -1,77 +1,74 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:int="http://www.springframework.org/schema/integration" + xmlns:jdbc="http://www.springframework.org/schema/jdbc" + xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc" + xmlns:tx="http://www.springframework.org/schema/tx" + xmlns:util="http://www.springframework.org/schema/util" + xmlns:p="http://www.springframework.org/schema/p" + xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd + http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd + http://www.springframework.org/schema/integration/jdbc http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + - - + + + + - + - - - + + + + + + diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapterWithSpringContextIntegrationTests-context.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapterWithSpringContextIntegrationTests-context.xml index bc4c83b079..24f67a0959 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapterWithSpringContextIntegrationTests-context.xml +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapterWithSpringContextIntegrationTests-context.xml @@ -1,82 +1,86 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:int="http://www.springframework.org/schema/integration" + xmlns:jdbc="http://www.springframework.org/schema/jdbc" + xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc" + xmlns:tx="http://www.springframework.org/schema/tx" + xmlns:util="http://www.springframework.org/schema/util" + xmlns:p="http://www.springframework.org/schema/p" + xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd + http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd + http://www.springframework.org/schema/integration/jdbc http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + - - - - - + - - + + + + + - - + + - + + - - - + + + + + diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/Copy of storedProcPollingChannelAdapterParserTest2.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/Copy of storedProcPollingChannelAdapterParserTest2.xml new file mode 100644 index 0000000000..b7fffe2f6e --- /dev/null +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/Copy of storedProcPollingChannelAdapterParserTest2.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcMessageHandlerParserTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcMessageHandlerParserTests.java index a01b381b21..5ef56e90a3 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcMessageHandlerParserTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcMessageHandlerParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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 @@ -26,6 +26,7 @@ import org.junit.Test; import org.springframework.beans.DirectFieldAccessor; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.expression.Expression; import org.springframework.integration.endpoint.EventDrivenConsumer; import org.springframework.integration.jdbc.storedproc.ProcedureParameter; import org.springframework.jdbc.core.SqlInOutParameter; @@ -39,125 +40,125 @@ import org.springframework.jdbc.core.SqlParameter; */ public class StoredProcMessageHandlerParserTests { - private ConfigurableApplicationContext context; + private ConfigurableApplicationContext context; - private EventDrivenConsumer consumer; + private EventDrivenConsumer consumer; - @Test - public void testProcedureNameIsSet() throws Exception { - setUp("basicStoredProcOutboundChannelAdapterTest.xml", getClass()); - - DirectFieldAccessor accessor = new DirectFieldAccessor(this.consumer); - Object handler = accessor.getPropertyValue("handler"); - accessor = new DirectFieldAccessor(handler); - - Object executor = accessor.getPropertyValue("executor"); - DirectFieldAccessor executorAccessor = new DirectFieldAccessor(executor); - - Object testProcedure1 = executorAccessor.getPropertyValue("storedProcedureName"); - assertEquals("Resolution Required should be 'testProcedure1' but was " + testProcedure1, "testProcedure1", testProcedure1); - } - - @SuppressWarnings("unchecked") @Test - public void testProcedurepParametersAreSet() throws Exception { - setUp("basicStoredProcOutboundChannelAdapterTest.xml", getClass()); + public void testProcedureNameIsSet() throws Exception { + setUp("basicStoredProcOutboundChannelAdapterTest.xml", getClass()); - DirectFieldAccessor accessor = new DirectFieldAccessor(this.consumer); - Object handler = accessor.getPropertyValue("handler"); - accessor = new DirectFieldAccessor(handler); + DirectFieldAccessor accessor = new DirectFieldAccessor(this.consumer); + Object handler = accessor.getPropertyValue("handler"); + accessor = new DirectFieldAccessor(handler); - Object executor = accessor.getPropertyValue("executor"); - DirectFieldAccessor executorAccessor = new DirectFieldAccessor(executor); + Object executor = accessor.getPropertyValue("executor"); + DirectFieldAccessor executorAccessor = new DirectFieldAccessor(executor); - Object procedureParameters = executorAccessor.getPropertyValue("procedureParameters"); - assertNotNull(procedureParameters); - assertTrue(procedureParameters instanceof List); + Expression testProcedure1 = (Expression) executorAccessor.getPropertyValue("storedProcedureNameExpression"); + assertEquals("Resolution Required should be 'testProcedure1' but was " + testProcedure1, "testProcedure1", testProcedure1.getValue()); + } - ListprocedureParametersAsList = (List) procedureParameters; - - assertTrue(procedureParametersAsList.size() == 4); - - ProcedureParameter parameter1 = procedureParametersAsList.get(0); - ProcedureParameter parameter2 = procedureParametersAsList.get(1); - ProcedureParameter parameter3 = procedureParametersAsList.get(2); - ProcedureParameter parameter4 = procedureParametersAsList.get(3); - - assertEquals("username", parameter1.getName()); - assertEquals("description", parameter2.getName()); - assertEquals("password", parameter3.getName()); - assertEquals("age", parameter4.getName()); - - assertEquals("kenny", parameter1.getValue()); - assertEquals("Who killed Kenny?", parameter2.getValue()); - assertNull(parameter3.getValue()); - assertEquals(Integer.valueOf(30), (Integer) parameter4.getValue()); - - assertNull(parameter1.getExpression()); - assertNull(parameter2.getExpression()); - assertEquals("payload.username", parameter3.getExpression()); - assertNull(parameter4.getExpression()); - - } - - @SuppressWarnings("unchecked") + @SuppressWarnings("unchecked") @Test - public void testSqlParametersAreSet() throws Exception { - setUp("basicStoredProcOutboundChannelAdapterTest.xml", getClass()); + public void testProcedurepParametersAreSet() throws Exception { + setUp("basicStoredProcOutboundChannelAdapterTest.xml", getClass()); - DirectFieldAccessor accessor = new DirectFieldAccessor(this.consumer); - Object handler = accessor.getPropertyValue("handler"); - accessor = new DirectFieldAccessor(handler); + DirectFieldAccessor accessor = new DirectFieldAccessor(this.consumer); + Object handler = accessor.getPropertyValue("handler"); + accessor = new DirectFieldAccessor(handler); - Object executor = accessor.getPropertyValue("executor"); - DirectFieldAccessor executorAccessor = new DirectFieldAccessor(executor); + Object executor = accessor.getPropertyValue("executor"); + DirectFieldAccessor executorAccessor = new DirectFieldAccessor(executor); - Object sqlParameters = executorAccessor.getPropertyValue("sqlParameters"); + Object procedureParameters = executorAccessor.getPropertyValue("procedureParameters"); + assertNotNull(procedureParameters); + assertTrue(procedureParameters instanceof List); - assertNotNull(sqlParameters); - assertTrue(sqlParameters instanceof List); + ListprocedureParametersAsList = (List) procedureParameters; - ListsqlParametersAsList = (List) sqlParameters; + assertTrue(procedureParametersAsList.size() == 4); - assertTrue(sqlParametersAsList.size() == 4); + ProcedureParameter parameter1 = procedureParametersAsList.get(0); + ProcedureParameter parameter2 = procedureParametersAsList.get(1); + ProcedureParameter parameter3 = procedureParametersAsList.get(2); + ProcedureParameter parameter4 = procedureParametersAsList.get(3); - SqlParameter parameter1 = sqlParametersAsList.get(0); - SqlParameter parameter2 = sqlParametersAsList.get(1); - SqlParameter parameter3 = sqlParametersAsList.get(2); - SqlParameter parameter4 = sqlParametersAsList.get(3); + assertEquals("username", parameter1.getName()); + assertEquals("description", parameter2.getName()); + assertEquals("password", parameter3.getName()); + assertEquals("age", parameter4.getName()); - assertEquals("username", parameter1.getName()); - assertEquals("password", parameter2.getName()); - assertEquals("age", parameter3.getName()); - assertEquals("description", parameter4.getName()); + assertEquals("kenny", parameter1.getValue()); + assertEquals("Who killed Kenny?", parameter2.getValue()); + assertNull(parameter3.getValue()); + assertEquals(Integer.valueOf(30), parameter4.getValue()); - assertNull("Expect that the scale is null.", parameter1.getScale()); - assertNull("Expect that the scale is null.", parameter2.getScale()); - assertEquals("Expect that the scale is 5.", Integer.valueOf(5), parameter3.getScale()); - assertNull("Expect that the scale is null.", parameter4.getScale()); + assertNull(parameter1.getExpression()); + assertNull(parameter2.getExpression()); + assertEquals("payload.username", parameter3.getExpression()); + assertNull(parameter4.getExpression()); - assertEquals("SqlType is ", Types.VARCHAR, parameter1.getSqlType()); - assertEquals("SqlType is ", Types.VARCHAR, parameter2.getSqlType()); - assertEquals("SqlType is ", Types.INTEGER, parameter3.getSqlType()); - assertEquals("SqlType is ", Types.VARCHAR, parameter4.getSqlType()); + } - assertTrue(parameter1 instanceof SqlParameter); - assertTrue(parameter2 instanceof SqlOutParameter); - assertTrue(parameter3 instanceof SqlInOutParameter); - assertTrue(parameter4 instanceof SqlParameter); + @SuppressWarnings("unchecked") + @Test + public void testSqlParametersAreSet() throws Exception { + setUp("basicStoredProcOutboundChannelAdapterTest.xml", getClass()); - } + DirectFieldAccessor accessor = new DirectFieldAccessor(this.consumer); + Object handler = accessor.getPropertyValue("handler"); + accessor = new DirectFieldAccessor(handler); - @After - public void tearDown(){ - if(context != null){ - context.close(); - } - } + Object executor = accessor.getPropertyValue("executor"); + DirectFieldAccessor executorAccessor = new DirectFieldAccessor(executor); - public void setUp(String name, Class cls){ - context = new ClassPathXmlApplicationContext(name, cls); - consumer = this.context.getBean("storedProcedureOutboundChannelAdapter", EventDrivenConsumer.class); - } + Object sqlParameters = executorAccessor.getPropertyValue("sqlParameters"); + + assertNotNull(sqlParameters); + assertTrue(sqlParameters instanceof List); + + ListsqlParametersAsList = (List) sqlParameters; + + assertTrue(sqlParametersAsList.size() == 4); + + SqlParameter parameter1 = sqlParametersAsList.get(0); + SqlParameter parameter2 = sqlParametersAsList.get(1); + SqlParameter parameter3 = sqlParametersAsList.get(2); + SqlParameter parameter4 = sqlParametersAsList.get(3); + + assertEquals("username", parameter1.getName()); + assertEquals("password", parameter2.getName()); + assertEquals("age", parameter3.getName()); + assertEquals("description", parameter4.getName()); + + assertNull("Expect that the scale is null.", parameter1.getScale()); + assertNull("Expect that the scale is null.", parameter2.getScale()); + assertEquals("Expect that the scale is 5.", Integer.valueOf(5), parameter3.getScale()); + assertNull("Expect that the scale is null.", parameter4.getScale()); + + assertEquals("SqlType is ", Types.VARCHAR, parameter1.getSqlType()); + assertEquals("SqlType is ", Types.VARCHAR, parameter2.getSqlType()); + assertEquals("SqlType is ", Types.INTEGER, parameter3.getSqlType()); + assertEquals("SqlType is ", Types.VARCHAR, parameter4.getSqlType()); + + assertTrue(parameter1 instanceof SqlParameter); + assertTrue(parameter2 instanceof SqlOutParameter); + assertTrue(parameter3 instanceof SqlInOutParameter); + assertTrue(parameter4 instanceof SqlParameter); + + } + + @After + public void tearDown(){ + if(context != null){ + context.close(); + } + } + + public void setUp(String name, Class cls){ + context = new ClassPathXmlApplicationContext(name, cls); + consumer = this.context.getBean("storedProcedureOutboundChannelAdapter", EventDrivenConsumer.class); + } } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParserTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParserTests.java index b03fb23012..027be53dbe 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParserTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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.junit.Test; import org.springframework.beans.DirectFieldAccessor; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.expression.Expression; import org.springframework.integration.core.MessagingTemplate; import org.springframework.integration.endpoint.EventDrivenConsumer; import org.springframework.integration.jdbc.storedproc.PrimeMapper; @@ -45,176 +46,176 @@ import org.springframework.jdbc.core.SqlParameter; */ public class StoredProcOutboundGatewayParserTests { - private ConfigurableApplicationContext context; + private ConfigurableApplicationContext context; - private EventDrivenConsumer outboundGateway; + private EventDrivenConsumer outboundGateway; - @Test - public void testProcedureNameIsSet() throws Exception { - setUp("storedProcOutboundGatewayParserTest.xml", getClass()); - - DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway); - Object source = accessor.getPropertyValue("handler"); - accessor = new DirectFieldAccessor(source); - source = accessor.getPropertyValue("executor"); - accessor = new DirectFieldAccessor(source); - Object storedProcedureName = accessor.getPropertyValue("storedProcedureName"); - assertEquals("Wrong stored procedure name", "GET_PRIME_NUMBERS", storedProcedureName); - } - - @Test - public void testReplyTimeoutIsSet() throws Exception { - setUp("storedProcOutboundGatewayParserTest.xml", getClass()); - - DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway); - Object source = accessor.getPropertyValue("handler"); - accessor = new DirectFieldAccessor(source); - source = accessor.getPropertyValue("messagingTemplate"); - - MessagingTemplate messagingTemplate = (MessagingTemplate) source; - - accessor = new DirectFieldAccessor(messagingTemplate); - - Long sendTimeout = (Long) accessor.getPropertyValue("sendTimeout"); - assertEquals("Wrong sendTimeout", Long.valueOf(555L), sendTimeout); - - } - - - @Test - public void testSkipUndeclaredResultsAttributeSet() throws Exception { - setUp("storedProcOutboundGatewayParserTest.xml", getClass()); - - DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway); - Object source = accessor.getPropertyValue("handler"); - accessor = new DirectFieldAccessor(source); - source = accessor.getPropertyValue("executor"); - accessor = new DirectFieldAccessor(source); - boolean skipUndeclaredResults = (Boolean) accessor.getPropertyValue("skipUndeclaredResults"); - assertFalse(skipUndeclaredResults); - } - - @SuppressWarnings("unchecked") @Test - public void testProcedurepParametersAreSet() throws Exception { - setUp("storedProcOutboundGatewayParserTest.xml", getClass()); + public void testProcedureNameIsSet() throws Exception { + setUp("storedProcOutboundGatewayParserTest.xml", getClass()); - DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway); - Object source = accessor.getPropertyValue("handler"); - accessor = new DirectFieldAccessor(source); - source = accessor.getPropertyValue("executor"); - accessor = new DirectFieldAccessor(source); - Object procedureParameters = accessor.getPropertyValue("procedureParameters"); - assertNotNull(procedureParameters); - assertTrue(procedureParameters instanceof List); + DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway); + Object source = accessor.getPropertyValue("handler"); + accessor = new DirectFieldAccessor(source); + source = accessor.getPropertyValue("executor"); + accessor = new DirectFieldAccessor(source); + Expression storedProcedureName = (Expression) accessor.getPropertyValue("storedProcedureNameExpression"); + assertEquals("Wrong stored procedure name", "GET_PRIME_NUMBERS", storedProcedureName.getValue()); + } - ListprocedureParametersAsList = (List) procedureParameters; - - assertTrue(procedureParametersAsList.size() == 4); - - ProcedureParameter parameter1 = procedureParametersAsList.get(0); - ProcedureParameter parameter2 = procedureParametersAsList.get(1); - ProcedureParameter parameter3 = procedureParametersAsList.get(2); - ProcedureParameter parameter4 = procedureParametersAsList.get(3); - - assertEquals("username", parameter1.getName()); - assertEquals("description", parameter2.getName()); - assertEquals("password", parameter3.getName()); - assertEquals("age", parameter4.getName()); - - assertEquals("kenny", parameter1.getValue()); - assertEquals("Who killed Kenny?", parameter2.getValue()); - assertNull(parameter3.getValue()); - assertEquals(Integer.valueOf(30), (Integer) parameter4.getValue()); - - assertNull(parameter1.getExpression()); - assertNull(parameter2.getExpression()); - assertEquals("payload.username", parameter3.getExpression()); - assertNull(parameter4.getExpression()); - - } - - @SuppressWarnings("unchecked") @Test - public void testReturningResultSetRowMappersAreSet() throws Exception { - setUp("storedProcOutboundGatewayParserTest.xml", getClass()); + public void testReplyTimeoutIsSet() throws Exception { + setUp("storedProcOutboundGatewayParserTest.xml", getClass()); - DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway); - Object source = accessor.getPropertyValue("handler"); - accessor = new DirectFieldAccessor(source); - source = accessor.getPropertyValue("executor"); - accessor = new DirectFieldAccessor(source); - Object returningResultSetRowMappers = accessor.getPropertyValue("returningResultSetRowMappers"); - assertNotNull(returningResultSetRowMappers); - assertTrue(returningResultSetRowMappers instanceof Map); + DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway); + Object source = accessor.getPropertyValue("handler"); + accessor = new DirectFieldAccessor(source); + source = accessor.getPropertyValue("messagingTemplate"); - Map> returningResultSetRowMappersAsMap = (Map>) returningResultSetRowMappers; + MessagingTemplate messagingTemplate = (MessagingTemplate) source; - assertTrue("The rowmapper was not set. Expected returningResultSetRowMappersAsMap.size() == 1", returningResultSetRowMappersAsMap.size() == 1); + accessor = new DirectFieldAccessor(messagingTemplate); - Entry mapEntry1 = returningResultSetRowMappersAsMap.entrySet().iterator().next(); + Long sendTimeout = (Long) accessor.getPropertyValue("sendTimeout"); + assertEquals("Wrong sendTimeout", Long.valueOf(555L), sendTimeout); - assertEquals("out", mapEntry1.getKey()); - assertTrue(mapEntry1.getValue() instanceof PrimeMapper); - - } + } - @SuppressWarnings("unchecked") @Test - public void testSqlParametersAreSet() throws Exception { - setUp("storedProcOutboundGatewayParserTest.xml", getClass()); + public void testSkipUndeclaredResultsAttributeSet() throws Exception { + setUp("storedProcOutboundGatewayParserTest.xml", getClass()); - DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway); - Object source = accessor.getPropertyValue("handler"); - accessor = new DirectFieldAccessor(source); - source = accessor.getPropertyValue("executor"); - accessor = new DirectFieldAccessor(source); - Object sqlParameters = accessor.getPropertyValue("sqlParameters"); - assertNotNull(sqlParameters); - assertTrue(sqlParameters instanceof List); + DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway); + Object source = accessor.getPropertyValue("handler"); + accessor = new DirectFieldAccessor(source); + source = accessor.getPropertyValue("executor"); + accessor = new DirectFieldAccessor(source); + boolean skipUndeclaredResults = (Boolean) accessor.getPropertyValue("skipUndeclaredResults"); + assertFalse(skipUndeclaredResults); + } - ListsqlParametersAsList = (List) sqlParameters; + @SuppressWarnings("unchecked") + @Test + public void testProcedurepParametersAreSet() throws Exception { + setUp("storedProcOutboundGatewayParserTest.xml", getClass()); - assertTrue(sqlParametersAsList.size() == 4); + DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway); + Object source = accessor.getPropertyValue("handler"); + accessor = new DirectFieldAccessor(source); + source = accessor.getPropertyValue("executor"); + accessor = new DirectFieldAccessor(source); + Object procedureParameters = accessor.getPropertyValue("procedureParameters"); + assertNotNull(procedureParameters); + assertTrue(procedureParameters instanceof List); - SqlParameter parameter1 = sqlParametersAsList.get(0); - SqlParameter parameter2 = sqlParametersAsList.get(1); - SqlParameter parameter3 = sqlParametersAsList.get(2); - SqlParameter parameter4 = sqlParametersAsList.get(3); + ListprocedureParametersAsList = (List) procedureParameters; - assertEquals("username", parameter1.getName()); - assertEquals("password", parameter2.getName()); - assertEquals("age", parameter3.getName()); - assertEquals("description", parameter4.getName()); + assertTrue(procedureParametersAsList.size() == 4); - assertNull("Expect that the scale is null.", parameter1.getScale()); - assertNull("Expect that the scale is null.", parameter2.getScale()); - assertEquals("Expect that the scale is 5.", Integer.valueOf(5), parameter3.getScale()); - assertNull("Expect that the scale is null.", parameter4.getScale()); + ProcedureParameter parameter1 = procedureParametersAsList.get(0); + ProcedureParameter parameter2 = procedureParametersAsList.get(1); + ProcedureParameter parameter3 = procedureParametersAsList.get(2); + ProcedureParameter parameter4 = procedureParametersAsList.get(3); - assertEquals("SqlType is ", Types.VARCHAR, parameter1.getSqlType()); - assertEquals("SqlType is ", Types.VARCHAR, parameter2.getSqlType()); - assertEquals("SqlType is ", Types.INTEGER, parameter3.getSqlType()); - assertEquals("SqlType is ", Types.VARCHAR, parameter4.getSqlType()); + assertEquals("username", parameter1.getName()); + assertEquals("description", parameter2.getName()); + assertEquals("password", parameter3.getName()); + assertEquals("age", parameter4.getName()); - assertTrue(parameter1 instanceof SqlParameter); - assertTrue(parameter2 instanceof SqlOutParameter); - assertTrue(parameter3 instanceof SqlInOutParameter); - assertTrue(parameter4 instanceof SqlParameter); + assertEquals("kenny", parameter1.getValue()); + assertEquals("Who killed Kenny?", parameter2.getValue()); + assertNull(parameter3.getValue()); + assertEquals(Integer.valueOf(30), parameter4.getValue()); - } + assertNull(parameter1.getExpression()); + assertNull(parameter2.getExpression()); + assertEquals("payload.username", parameter3.getExpression()); + assertNull(parameter4.getExpression()); - @After - public void tearDown(){ - if(context != null){ - context.close(); - } - } + } - public void setUp(String name, Class cls){ - this.context = new ClassPathXmlApplicationContext(name, cls); - this.outboundGateway = this.context.getBean("storedProcedureOutboundGateway", EventDrivenConsumer.class); - } + @SuppressWarnings("unchecked") + @Test + public void testReturningResultSetRowMappersAreSet() throws Exception { + setUp("storedProcOutboundGatewayParserTest.xml", getClass()); + + DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway); + Object source = accessor.getPropertyValue("handler"); + accessor = new DirectFieldAccessor(source); + source = accessor.getPropertyValue("executor"); + accessor = new DirectFieldAccessor(source); + Object returningResultSetRowMappers = accessor.getPropertyValue("returningResultSetRowMappers"); + assertNotNull(returningResultSetRowMappers); + assertTrue(returningResultSetRowMappers instanceof Map); + + Map> returningResultSetRowMappersAsMap = (Map>) returningResultSetRowMappers; + + assertTrue("The rowmapper was not set. Expected returningResultSetRowMappersAsMap.size() == 1", returningResultSetRowMappersAsMap.size() == 1); + + Entry mapEntry1 = returningResultSetRowMappersAsMap.entrySet().iterator().next(); + + assertEquals("out", mapEntry1.getKey()); + assertTrue(mapEntry1.getValue() instanceof PrimeMapper); + + } + + + @SuppressWarnings("unchecked") + @Test + public void testSqlParametersAreSet() throws Exception { + setUp("storedProcOutboundGatewayParserTest.xml", getClass()); + + DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway); + Object source = accessor.getPropertyValue("handler"); + accessor = new DirectFieldAccessor(source); + source = accessor.getPropertyValue("executor"); + accessor = new DirectFieldAccessor(source); + Object sqlParameters = accessor.getPropertyValue("sqlParameters"); + assertNotNull(sqlParameters); + assertTrue(sqlParameters instanceof List); + + ListsqlParametersAsList = (List) sqlParameters; + + assertTrue(sqlParametersAsList.size() == 4); + + SqlParameter parameter1 = sqlParametersAsList.get(0); + SqlParameter parameter2 = sqlParametersAsList.get(1); + SqlParameter parameter3 = sqlParametersAsList.get(2); + SqlParameter parameter4 = sqlParametersAsList.get(3); + + assertEquals("username", parameter1.getName()); + assertEquals("password", parameter2.getName()); + assertEquals("age", parameter3.getName()); + assertEquals("description", parameter4.getName()); + + assertNull("Expect that the scale is null.", parameter1.getScale()); + assertNull("Expect that the scale is null.", parameter2.getScale()); + assertEquals("Expect that the scale is 5.", Integer.valueOf(5), parameter3.getScale()); + assertNull("Expect that the scale is null.", parameter4.getScale()); + + assertEquals("SqlType is ", Types.VARCHAR, parameter1.getSqlType()); + assertEquals("SqlType is ", Types.VARCHAR, parameter2.getSqlType()); + assertEquals("SqlType is ", Types.INTEGER, parameter3.getSqlType()); + assertEquals("SqlType is ", Types.VARCHAR, parameter4.getSqlType()); + + assertTrue(parameter1 instanceof SqlParameter); + assertTrue(parameter2 instanceof SqlOutParameter); + assertTrue(parameter3 instanceof SqlInOutParameter); + assertTrue(parameter4 instanceof SqlParameter); + + } + + @After + public void tearDown(){ + if(context != null){ + context.close(); + } + } + + public void setUp(String name, Class cls){ + this.context = new ClassPathXmlApplicationContext(name, cls); + this.outboundGateway = this.context.getBean("storedProcedureOutboundGateway", EventDrivenConsumer.class); + } } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcPollingChannelAdapterParserTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcPollingChannelAdapterParserTests.java index 0b1971f62e..9bff31f868 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcPollingChannelAdapterParserTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcPollingChannelAdapterParserTests.java @@ -29,6 +29,7 @@ import org.junit.Test; import org.springframework.beans.DirectFieldAccessor; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.expression.Expression; import org.springframework.integration.MessageChannel; import org.springframework.integration.endpoint.SourcePollingChannelAdapter; import org.springframework.integration.jdbc.storedproc.PrimeMapper; @@ -47,165 +48,205 @@ import org.springframework.jdbc.core.SqlParameter; */ public class StoredProcPollingChannelAdapterParserTests { - private ConfigurableApplicationContext context; + private ConfigurableApplicationContext context; - private SourcePollingChannelAdapter pollingAdapter; + private SourcePollingChannelAdapter pollingAdapter; - @Test - public void testProcedureNameIsSet() throws Exception { - setUp("storedProcPollingChannelAdapterParserTest.xml", getClass()); - - DirectFieldAccessor accessor = new DirectFieldAccessor(this.pollingAdapter); - Object source = accessor.getPropertyValue("source"); - accessor = new DirectFieldAccessor(source); - source = accessor.getPropertyValue("executor"); - accessor = new DirectFieldAccessor(source); - Object storedProcedureName = accessor.getPropertyValue("storedProcedureName"); - assertEquals("Wrong stored procedure name", "GET_PRIME_NUMBERS", storedProcedureName); - } - - @Test - public void testSkipUndeclaredResultsAttributeSet() throws Exception { - setUp("storedProcPollingChannelAdapterParserTest.xml", getClass()); - - DirectFieldAccessor accessor = new DirectFieldAccessor(this.pollingAdapter); - Object source = accessor.getPropertyValue("source"); - accessor = new DirectFieldAccessor(source); - source = accessor.getPropertyValue("executor"); - accessor = new DirectFieldAccessor(source); - boolean skipUndeclaredResults = (Boolean) accessor.getPropertyValue("skipUndeclaredResults"); - assertTrue("skipUndeclaredResults was not set and should default to 'true'", skipUndeclaredResults); - } - - @SuppressWarnings("unchecked") @Test - public void testProcedurepParametersAreSet() throws Exception { - setUp("storedProcPollingChannelAdapterParserTest.xml", getClass()); + public void testProcedureNameIsSet() throws Exception { + setUp("storedProcPollingChannelAdapterParserTest.xml", getClass()); - DirectFieldAccessor accessor = new DirectFieldAccessor(this.pollingAdapter); - Object source = accessor.getPropertyValue("source"); - accessor = new DirectFieldAccessor(source); - source = accessor.getPropertyValue("executor"); - accessor = new DirectFieldAccessor(source); - Object procedureParameters = accessor.getPropertyValue("procedureParameters"); - assertNotNull(procedureParameters); - assertTrue(procedureParameters instanceof List); + DirectFieldAccessor accessor = new DirectFieldAccessor(this.pollingAdapter); + Object source = accessor.getPropertyValue("source"); + accessor = new DirectFieldAccessor(source); + source = accessor.getPropertyValue("executor"); + accessor = new DirectFieldAccessor(source); + Expression storedProcedureName = (Expression) accessor.getPropertyValue("storedProcedureNameExpression"); + assertEquals("Wrong stored procedure name", "GET_PRIME_NUMBERS", storedProcedureName.getValue()); + } - ListprocedureParametersAsList = (List) procedureParameters; - - assertTrue(procedureParametersAsList.size() == 4); - - ProcedureParameter parameter1 = procedureParametersAsList.get(0); - ProcedureParameter parameter2 = procedureParametersAsList.get(1); - ProcedureParameter parameter3 = procedureParametersAsList.get(2); - ProcedureParameter parameter4 = procedureParametersAsList.get(3); - - assertEquals("username", parameter1.getName()); - assertEquals("description", parameter2.getName()); - assertEquals("password", parameter3.getName()); - assertEquals("age", parameter4.getName()); - - assertEquals("kenny", parameter1.getValue()); - assertEquals("Who killed Kenny?", parameter2.getValue()); - assertNull(parameter3.getValue()); - assertEquals(Integer.valueOf(30), (Integer) parameter4.getValue()); - - assertNull(parameter1.getExpression()); - assertNull(parameter2.getExpression()); - assertEquals("payload.username", parameter3.getExpression()); - assertNull(parameter4.getExpression()); - - } - - @SuppressWarnings("unchecked") @Test - public void testReturningResultSetRowMappersAreSet() throws Exception { - setUp("storedProcPollingChannelAdapterParserTest.xml", getClass()); + public void testProcedureNameExpressionIsSet() throws Exception { + setUp("storedProcPollingChannelAdapterParserTest2.xml", getClass()); - DirectFieldAccessor accessor = new DirectFieldAccessor(this.pollingAdapter); - Object source = accessor.getPropertyValue("source"); - accessor = new DirectFieldAccessor(source); - source = accessor.getPropertyValue("executor"); - accessor = new DirectFieldAccessor(source); - Object returningResultSetRowMappers = accessor.getPropertyValue("returningResultSetRowMappers"); - assertNotNull(returningResultSetRowMappers); - assertTrue(returningResultSetRowMappers instanceof Map); + Expression storedProcedureNameExpression = + TestUtils.getPropertyValue(this.pollingAdapter, + "source.executor.storedProcedureNameExpression", + Expression.class); - Map> returningResultSetRowMappersAsMap = (Map>) returningResultSetRowMappers; + assertEquals("Wrong stored procedure name", "'GET_PRIME_NUMBERS'", + storedProcedureNameExpression.getExpressionString()); + } - assertTrue("The rowmapper was not set. Expected returningResultSetRowMappersAsMap.size() == 1", returningResultSetRowMappersAsMap.size() == 1); - - Entry mapEntry1 = returningResultSetRowMappersAsMap.entrySet().iterator().next(); - - assertEquals("out", mapEntry1.getKey()); - assertTrue(mapEntry1.getValue() instanceof PrimeMapper); - - } - - - @SuppressWarnings("unchecked") @Test - public void testSqlParametersAreSet() throws Exception { - setUp("storedProcPollingChannelAdapterParserTest.xml", getClass()); + public void testDefaultJdbcCallOperationsCacheSizeIsSet() { + setUp("storedProcPollingChannelAdapterParserTest.xml", getClass()); - DirectFieldAccessor accessor = new DirectFieldAccessor(this.pollingAdapter); - Object source = accessor.getPropertyValue("source"); - accessor = new DirectFieldAccessor(source); - source = accessor.getPropertyValue("executor"); - accessor = new DirectFieldAccessor(source); - Object sqlParameters = accessor.getPropertyValue("sqlParameters"); - assertNotNull(sqlParameters); - assertTrue(sqlParameters instanceof List); + Integer cacheSize = + TestUtils.getPropertyValue(this.pollingAdapter, + "source.executor.jdbcCallOperationsCacheSize", + Integer.class); - ListsqlParametersAsList = (List) sqlParameters; + assertEquals("Wrong Default JdbcCallOperations Cache Size", Integer.valueOf(10), + cacheSize); + } - assertTrue(sqlParametersAsList.size() == 4); - SqlParameter parameter1 = sqlParametersAsList.get(0); - SqlParameter parameter2 = sqlParametersAsList.get(1); - SqlParameter parameter3 = sqlParametersAsList.get(2); - SqlParameter parameter4 = sqlParametersAsList.get(3); + @Test + public void testJdbcCallOperationsCacheSizeIsSet() { + setUp("storedProcPollingChannelAdapterParserTest2.xml", getClass()); - assertEquals("username", parameter1.getName()); - assertEquals("password", parameter2.getName()); - assertEquals("age", parameter3.getName()); - assertEquals("description", parameter4.getName()); + Integer cacheSize = + TestUtils.getPropertyValue(this.pollingAdapter, + "source.executor.jdbcCallOperationsCacheSize", + Integer.class); - assertNull("Expect that the scale is null.", parameter1.getScale()); - assertNull("Expect that the scale is null.", parameter2.getScale()); - assertEquals("Expect that the scale is 5.", Integer.valueOf(5), parameter3.getScale()); - assertNull("Expect that the scale is null.", parameter4.getScale()); + assertEquals("Wrong JdbcCallOperations Cache Size", Integer.valueOf(77), + cacheSize); + } - assertEquals("SqlType is ", Types.VARCHAR, parameter1.getSqlType()); - assertEquals("SqlType is ", Types.VARCHAR, parameter2.getSqlType()); - assertEquals("SqlType is ", Types.INTEGER, parameter3.getSqlType()); - assertEquals("SqlType is ", Types.VARCHAR, parameter4.getSqlType()); + @Test + public void testSkipUndeclaredResultsAttributeSet() throws Exception { + setUp("storedProcPollingChannelAdapterParserTest.xml", getClass()); - assertTrue(parameter1 instanceof SqlParameter); - assertTrue(parameter2 instanceof SqlOutParameter); - assertTrue(parameter3 instanceof SqlInOutParameter); - assertTrue(parameter4 instanceof SqlParameter); + DirectFieldAccessor accessor = new DirectFieldAccessor(this.pollingAdapter); + Object source = accessor.getPropertyValue("source"); + accessor = new DirectFieldAccessor(source); + source = accessor.getPropertyValue("executor"); + accessor = new DirectFieldAccessor(source); + boolean skipUndeclaredResults = (Boolean) accessor.getPropertyValue("skipUndeclaredResults"); + assertTrue("skipUndeclaredResults was not set and should default to 'true'", skipUndeclaredResults); + } - } + @SuppressWarnings("unchecked") + @Test + public void testProcedurepParametersAreSet() throws Exception { + setUp("storedProcPollingChannelAdapterParserTest.xml", getClass()); - @Test - public void testAutoChannel() throws Exception { - setUp("storedProcPollingChannelAdapterParserTest.xml", getClass()); - MessageChannel autoChannel = context.getBean("autoChannel", MessageChannel.class); - SourcePollingChannelAdapter autoChannelAdapter = context.getBean("autoChannel.adapter", SourcePollingChannelAdapter.class); - assertSame(autoChannel, TestUtils.getPropertyValue(autoChannelAdapter, "outputChannel")); - } + DirectFieldAccessor accessor = new DirectFieldAccessor(this.pollingAdapter); + Object source = accessor.getPropertyValue("source"); + accessor = new DirectFieldAccessor(source); + source = accessor.getPropertyValue("executor"); + accessor = new DirectFieldAccessor(source); + Object procedureParameters = accessor.getPropertyValue("procedureParameters"); + assertNotNull(procedureParameters); + assertTrue(procedureParameters instanceof List); - @After - public void tearDown(){ - if(context != null){ - context.close(); - } - } + ListprocedureParametersAsList = (List) procedureParameters; - public void setUp(String name, Class cls){ - this.context = new ClassPathXmlApplicationContext(name, cls); - this.pollingAdapter = this.context.getBean("storedProcedurePollingChannelAdapter", SourcePollingChannelAdapter.class); - } + assertTrue(procedureParametersAsList.size() == 4); + + ProcedureParameter parameter1 = procedureParametersAsList.get(0); + ProcedureParameter parameter2 = procedureParametersAsList.get(1); + ProcedureParameter parameter3 = procedureParametersAsList.get(2); + ProcedureParameter parameter4 = procedureParametersAsList.get(3); + + assertEquals("username", parameter1.getName()); + assertEquals("description", parameter2.getName()); + assertEquals("password", parameter3.getName()); + assertEquals("age", parameter4.getName()); + + assertEquals("kenny", parameter1.getValue()); + assertEquals("Who killed Kenny?", parameter2.getValue()); + assertNull(parameter3.getValue()); + assertEquals(Integer.valueOf(30), parameter4.getValue()); + + assertNull(parameter1.getExpression()); + assertNull(parameter2.getExpression()); + assertEquals("payload.username", parameter3.getExpression()); + assertNull(parameter4.getExpression()); + + } + + @SuppressWarnings("unchecked") + @Test + public void testReturningResultSetRowMappersAreSet() throws Exception { + setUp("storedProcPollingChannelAdapterParserTest.xml", getClass()); + + DirectFieldAccessor accessor = new DirectFieldAccessor(this.pollingAdapter); + Object source = accessor.getPropertyValue("source"); + accessor = new DirectFieldAccessor(source); + source = accessor.getPropertyValue("executor"); + accessor = new DirectFieldAccessor(source); + Object returningResultSetRowMappers = accessor.getPropertyValue("returningResultSetRowMappers"); + assertNotNull(returningResultSetRowMappers); + assertTrue(returningResultSetRowMappers instanceof Map); + + Map> returningResultSetRowMappersAsMap = (Map>) returningResultSetRowMappers; + + assertTrue("The rowmapper was not set. Expected returningResultSetRowMappersAsMap.size() == 1", returningResultSetRowMappersAsMap.size() == 1); + + Entry mapEntry1 = returningResultSetRowMappersAsMap.entrySet().iterator().next(); + + assertEquals("out", mapEntry1.getKey()); + assertTrue(mapEntry1.getValue() instanceof PrimeMapper); + + } + + + @SuppressWarnings("unchecked") + @Test + public void testSqlParametersAreSet() throws Exception { + setUp("storedProcPollingChannelAdapterParserTest.xml", getClass()); + + DirectFieldAccessor accessor = new DirectFieldAccessor(this.pollingAdapter); + Object source = accessor.getPropertyValue("source"); + accessor = new DirectFieldAccessor(source); + source = accessor.getPropertyValue("executor"); + accessor = new DirectFieldAccessor(source); + Object sqlParameters = accessor.getPropertyValue("sqlParameters"); + assertNotNull(sqlParameters); + assertTrue(sqlParameters instanceof List); + + ListsqlParametersAsList = (List) sqlParameters; + + assertTrue(sqlParametersAsList.size() == 4); + + SqlParameter parameter1 = sqlParametersAsList.get(0); + SqlParameter parameter2 = sqlParametersAsList.get(1); + SqlParameter parameter3 = sqlParametersAsList.get(2); + SqlParameter parameter4 = sqlParametersAsList.get(3); + + assertEquals("username", parameter1.getName()); + assertEquals("password", parameter2.getName()); + assertEquals("age", parameter3.getName()); + assertEquals("description", parameter4.getName()); + + assertNull("Expect that the scale is null.", parameter1.getScale()); + assertNull("Expect that the scale is null.", parameter2.getScale()); + assertEquals("Expect that the scale is 5.", Integer.valueOf(5), parameter3.getScale()); + assertNull("Expect that the scale is null.", parameter4.getScale()); + + assertEquals("SqlType is ", Types.VARCHAR, parameter1.getSqlType()); + assertEquals("SqlType is ", Types.VARCHAR, parameter2.getSqlType()); + assertEquals("SqlType is ", Types.INTEGER, parameter3.getSqlType()); + assertEquals("SqlType is ", Types.VARCHAR, parameter4.getSqlType()); + + assertTrue(parameter1 instanceof SqlParameter); + assertTrue(parameter2 instanceof SqlOutParameter); + assertTrue(parameter3 instanceof SqlInOutParameter); + assertTrue(parameter4 instanceof SqlParameter); + + } + + @Test + public void testAutoChannel() throws Exception { + setUp("storedProcPollingChannelAdapterParserTest.xml", getClass()); + MessageChannel autoChannel = context.getBean("autoChannel", MessageChannel.class); + SourcePollingChannelAdapter autoChannelAdapter = context.getBean("autoChannel.adapter", SourcePollingChannelAdapter.class); + assertSame(autoChannel, TestUtils.getPropertyValue(autoChannelAdapter, "outputChannel")); + } + + @After + public void tearDown(){ + if(context != null){ + context.close(); + } + } + + public void setUp(String name, Class cls){ + this.context = new ClassPathXmlApplicationContext(name, cls); + this.pollingAdapter = this.context.getBean("storedProcedurePollingChannelAdapter", SourcePollingChannelAdapter.class); + } } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcOutboundGatewayParserTest.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcOutboundGatewayParserTest.xml index 0ed853c7f4..812244a4d6 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcOutboundGatewayParserTest.xml +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcOutboundGatewayParserTest.xml @@ -1,41 +1,36 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc" + xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc" + xmlns:int="http://www.springframework.org/schema/integration" + xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd + http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd + http://www.springframework.org/schema/integration/jdbc http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - - + + - + - + - - - - - - - - - + + + + + + + + + - + - + diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcPollingChannelAdapterParserTest.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcPollingChannelAdapterParserTest.xml index c451bb6589..b7fffe2f6e 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcPollingChannelAdapterParserTest.xml +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcPollingChannelAdapterParserTest.xml @@ -1,51 +1,51 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:jdbc="http://www.springframework.org/schema/jdbc" + xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc" + xmlns:int="http://www.springframework.org/schema/integration" + xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd + http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd + http://www.springframework.org/schema/integration/jdbc http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - - + + - - - - - - - - - - + + + + + + + + + + - + - + - - - - - - - - - - + + + + + + + + + + - + - + diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcPollingChannelAdapterParserTest2.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcPollingChannelAdapterParserTest2.xml new file mode 100644 index 0000000000..da5324c722 --- /dev/null +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcPollingChannelAdapterParserTest2.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/CreateUser.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/CreateUser.java index 6cf87e74f8..cd45d3ee93 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/CreateUser.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/CreateUser.java @@ -15,6 +15,11 @@ */ package org.springframework.integration.jdbc.storedproc; +/** + * + * @author Gunnar Hillert + * + */ public interface CreateUser { - void createUser(User user); + void createUser(User user); } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/PrimeMapper.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/PrimeMapper.java index 80ade75553..6e13b3a1f7 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/PrimeMapper.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/PrimeMapper.java @@ -1,11 +1,11 @@ /* - * Copyright 2002-2011 the original author or authors. - * + * Copyright 2002-2012 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. @@ -17,8 +17,13 @@ import java.sql.SQLException; import org.springframework.jdbc.core.RowMapper; +/** + * + * @author Gunnar Hillert + * + */ public class PrimeMapper implements RowMapper { - public Integer mapRow(ResultSet rs, int rowNum) throws SQLException { - return rs.getInt("PRIME"); - } + public Integer mapRow(ResultSet rs, int rowNum) throws SQLException { + return rs.getInt("PRIME"); + } } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/User.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/User.java index 991b6556c1..eaf2f4fa4d 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/User.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/User.java @@ -1,38 +1,92 @@ /* - * Copyright 2002-2011 the original author or authors. - * + * Copyright 2002-2012 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; +/** + * + * @author Gunnar Hillert + * + */ public class User { - private String username; - private String password; - private String email; + private String username; + private String password; + private String email; - public User(String username, String password, String email) { - super(); - this.username = username; - this.password = password; - this.email = email; - } + public User(String username, String password, String email) { + super(); + this.username = username; + this.password = password; + this.email = email; + } - public String getUsername() { - return this.username; - } + public String getUsername() { + return this.username; + } - public String getPassword() { - return this.password; - } + public String getPassword() { + return this.password; + } + + public String getEmail() { + return this.email; + } + + @Override + public String toString() { + return "User [username=" + username + ", password=" + password + + ", email=" + email + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((email == null) ? 0 : email.hashCode()); + result = prime * result + + ((password == null) ? 0 : password.hashCode()); + result = prime * result + + ((username == null) ? 0 : username.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + User other = (User) obj; + if (email == null) { + if (other.email != null) + return false; + } + else if (!email.equals(other.email)) + return false; + if (password == null) { + if (other.password != null) + return false; + } + else if (!password.equals(other.password)) + return false; + if (username == null) { + if (other.username != null) + return false; + } + else if (!username.equals(other.username)) + return false; + return true; + } - public String getEmail() { - return this.email; - } } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/UserMapper.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/UserMapper.java index 2eb1559899..17c81a8fe3 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/UserMapper.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/UserMapper.java @@ -1,11 +1,11 @@ /* - * Copyright 2002-2011 the original author or authors. - * + * Copyright 2002-2012 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. @@ -17,8 +17,13 @@ import java.sql.SQLException; import org.springframework.jdbc.core.RowMapper; +/** + * + * @author Gunnar Hillert + * + */ public class UserMapper implements RowMapper { - public User mapRow(ResultSet rs, int rowNum) throws SQLException { - return new User(rs.getString("username"), rs.getString("password"), rs.getString("email")); - } + public User mapRow(ResultSet rs, int rowNum) throws SQLException { + return new User(rs.getString("username"), rs.getString("password"), rs.getString("email")); + } } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/derby/DerbyFunctions.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/derby/DerbyFunctions.java index 59f8ae8af6..b5283192aa 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/derby/DerbyFunctions.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/derby/DerbyFunctions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2002-2012 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.derby; import java.util.Locale; @@ -9,8 +24,8 @@ import java.util.Locale; */ public final class DerbyFunctions { - public static String convertStringToUpperCase( String invalue ) { - return invalue.toUpperCase(Locale.ENGLISH); - } + public static String convertStringToUpperCase( String invalue ) { + return invalue.toUpperCase(Locale.ENGLISH); + } } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/derby/DerbyStoredProcedures.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/derby/DerbyStoredProcedures.java index b0dda9e308..ff293b1058 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/derby/DerbyStoredProcedures.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/storedproc/derby/DerbyStoredProcedures.java @@ -1,3 +1,18 @@ +/* + * Copyright 2002-2012 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.derby; import java.sql.Connection; @@ -9,9 +24,9 @@ import java.sql.SQLException; import org.springframework.jdbc.support.JdbcUtils; /** - * + * * @author Gunnar Hillert - * + * */ public final class DerbyStoredProcedures { @@ -49,7 +64,7 @@ public final class DerbyStoredProcedures { stmt.setString(2, password); stmt.setString(3, email); stmt.executeUpdate(); - + stmt2 = conn.prepareStatement("select * from USERS"); returnedData[0] = stmt2.executeQuery(); diff --git a/spring-integration-jdbc/src/test/resources/derby-stored-procedures-drops.sql b/spring-integration-jdbc/src/test/resources/derby-stored-procedures-drops.sql new file mode 100644 index 0000000000..a6f98b4504 --- /dev/null +++ b/spring-integration-jdbc/src/test/resources/derby-stored-procedures-drops.sql @@ -0,0 +1,4 @@ +DROP FUNCTION CONVERT_STRING_TO_UPPER_CASE; +DROP TABLE USERS; +DROP PROCEDURE CREATE_USER; +DROP PROCEDURE CREATE_USER_RETURN_ALL; diff --git a/spring-integration-jdbc/src/test/resources/derby-stored-procedures-setup-context.xml b/spring-integration-jdbc/src/test/resources/derby-stored-procedures-setup-context.xml new file mode 100644 index 0000000000..bf013ecc16 --- /dev/null +++ b/spring-integration-jdbc/src/test/resources/derby-stored-procedures-setup-context.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + +
Keyselect * from items where name=:key