From 8fdc57ecbd4dc08744f18b0edea3f7c0c2720c24 Mon Sep 17 00:00:00 2001 From: Thomas Risberg Date: Wed, 11 Mar 2009 23:01:22 +0000 Subject: [PATCH] added a concrete GenericStoredProcedure class to make it possible to configure using application context (SPR-3987) --- org.springframework.jdbc/jdbc.iml | 184 +++++++++--------- .../jdbc/object/GenericSqlQuery.java | 58 ++++++ .../jdbc/object/GenericStoredProcedure.java | 32 +++ .../datasource/TestDataSourceWrapper.java | 23 +++ .../object/GenericStoredProcedureTests.java | 114 +++++++++++ .../GenericStoredProcedureTests-context.xml | 36 ++++ 6 files changed, 355 insertions(+), 92 deletions(-) create mode 100644 org.springframework.jdbc/src/main/java/org/springframework/jdbc/object/GenericSqlQuery.java create mode 100644 org.springframework.jdbc/src/main/java/org/springframework/jdbc/object/GenericStoredProcedure.java create mode 100644 org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/TestDataSourceWrapper.java create mode 100644 org.springframework.jdbc/src/test/java/org/springframework/jdbc/object/GenericStoredProcedureTests.java create mode 100644 org.springframework.jdbc/src/test/resources/org/springframework/jdbc/support/GenericStoredProcedureTests-context.xml diff --git a/org.springframework.jdbc/jdbc.iml b/org.springframework.jdbc/jdbc.iml index 67d245b6852..5a700a05e84 100644 --- a/org.springframework.jdbc/jdbc.iml +++ b/org.springframework.jdbc/jdbc.iml @@ -1,92 +1,92 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/object/GenericSqlQuery.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/object/GenericSqlQuery.java new file mode 100644 index 00000000000..a9848a884ab --- /dev/null +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/object/GenericSqlQuery.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.object; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Map; + +import org.springframework.jdbc.core.RowMapper; +import org.springframework.util.Assert; +import org.springframework.dao.InvalidDataAccessApiUsageException; + +public class GenericSqlQuery extends SqlQuery { + + Class rowMapperClass; + + RowMapper rowMapper; + + public void setRowMapperClass(Class rowMapperClass) + throws IllegalAccessException, InstantiationException { + this.rowMapperClass = rowMapperClass; + if (!RowMapper.class.isAssignableFrom(rowMapperClass)) + throw new IllegalStateException("The specified class '" + + rowMapperClass.getName() + " is not a sub class of " + + "'org.springframework.jdbc.core.RowMapper'"); + } + + public void afterPropertiesSet() { + super.afterPropertiesSet(); + Assert.notNull(rowMapperClass, "The 'rowMapperClass' property is required"); + } + + protected RowMapper newRowMapper(Object[] parameters, Map context) { + try { + return (RowMapper) rowMapperClass.newInstance(); + } + catch (InstantiationException e) { + throw new InvalidDataAccessApiUsageException("Unable to instantiate RowMapper", e); + } + catch (IllegalAccessException e) { + throw new InvalidDataAccessApiUsageException("Unable to instantiate RowMapper", e); + } + } +} diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/object/GenericStoredProcedure.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/object/GenericStoredProcedure.java new file mode 100644 index 00000000000..1944c6a31ea --- /dev/null +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/object/GenericStoredProcedure.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.object; + +/** + * Concrete implementation making it possible to define the RDBMS stored procedures + * in an application context without writing a custom Java implementation class. + *

+ * This implementation does not provide a typed method for invocation so executions + * must use one of the generic {@link StoredProcedure#execute(java.util.Map)} or + * {@link StoredProcedure#execute(org.springframework.jdbc.core.ParameterMapper)} methods. + * + * @author Thomas Risberg + * @see org.springframework.jdbc.object.StoredProcedure + */ +public class GenericStoredProcedure extends StoredProcedure { + +} diff --git a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/TestDataSourceWrapper.java b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/TestDataSourceWrapper.java new file mode 100644 index 00000000000..a8c3a79b79b --- /dev/null +++ b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/datasource/TestDataSourceWrapper.java @@ -0,0 +1,23 @@ +package org.springframework.jdbc.datasource; + +import java.sql.Connection; +import java.sql.SQLException; +import javax.sql.DataSource; + +public class TestDataSourceWrapper extends AbstractDataSource { + + private DataSource target; + + public void setTarget(DataSource target) { + this.target = target; + } + + public Connection getConnection() throws SQLException { + return target.getConnection(); + } + + public Connection getConnection(String username, String password) throws SQLException { + return target.getConnection(username, password); + } + +} diff --git a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/object/GenericStoredProcedureTests.java b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/object/GenericStoredProcedureTests.java new file mode 100644 index 00000000000..581543a5c11 --- /dev/null +++ b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/object/GenericStoredProcedureTests.java @@ -0,0 +1,114 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.object; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.verify; + +import java.sql.CallableStatement; +import java.sql.Types; +import java.util.HashMap; +import java.util.Map; + +import org.easymock.EasyMock; +import org.apache.commons.logging.LogFactory; +import org.junit.Test; +import org.junit.After; +import org.junit.Before; + +import org.springframework.jdbc.AbstractJdbcTests; +import org.springframework.jdbc.datasource.TestDataSourceWrapper; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Thomas Risberg + */ +public class GenericStoredProcedureTests extends AbstractJdbcTests { + + private final boolean debugEnabled = LogFactory.getLog(JdbcTemplate.class).isDebugEnabled(); + + private CallableStatement mockCallable; + + private BeanFactory bf; + + @Before + protected void setUp() throws Exception { + super.setUp(); + mockCallable = createMock(CallableStatement.class); + bf = new XmlBeanFactory( + new ClassPathResource("org/springframework/jdbc/support/GenericStoredProcedureTests-context.xml")); + TestDataSourceWrapper testDataSource = (TestDataSourceWrapper) bf.getBean("dataSource"); + testDataSource.setTarget(mockDataSource); + } + + @After + protected void tearDown() throws Exception { + super.tearDown(); + if (shouldVerify()) { + verify(mockCallable); + } + } + + protected void replay() { + super.replay(); + EasyMock.replay(mockCallable); + } + + @Test + public void testAddInvoices() throws Exception { + + mockCallable.setObject(1, new Integer(1106), Types.INTEGER); + expectLastCall(); + mockCallable.setObject(2, new Integer(3), Types.INTEGER); + expectLastCall(); + mockCallable.registerOutParameter(3, Types.INTEGER); + expectLastCall(); + expect(mockCallable.execute()).andReturn(false); + expect(mockCallable.getUpdateCount()).andReturn(-1); + expect(mockCallable.getObject(3)).andReturn(new Integer(4)); + if (debugEnabled) { + expect(mockCallable.getWarnings()).andReturn(null); + } + mockCallable.close(); + expectLastCall(); + + mockConnection.prepareCall("{call " + "add_invoice" + "(?, ?, ?)}"); + ctrlConnection.setReturnValue(mockCallable); + + replay(); + + testAddInvoice(1106, 3); + } + + private void testAddInvoice(final int amount, final int custid) + throws Exception { + + StoredProcedure adder = (StoredProcedure) bf.getBean("genericProcedure"); + Map in = new HashMap(2); + in.put("amount", amount); + in.put("custid", custid); + Map out = adder.execute(in); + Integer id = (Integer) out.get("newid"); + assertEquals(4, id.intValue()); + } + +} \ No newline at end of file diff --git a/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/support/GenericStoredProcedureTests-context.xml b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/support/GenericStoredProcedureTests-context.xml new file mode 100644 index 00000000000..71f72a8f35b --- /dev/null +++ b/org.springframework.jdbc/src/test/resources/org/springframework/jdbc/support/GenericStoredProcedureTests-context.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file