diff --git a/.gitignore b/.gitignore index fe5e0208..8a0da337 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ log.roo *.iml *.ipr *.iws +derby.log diff --git a/README.md b/README.md index 81c293db..2283550e 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ This category targets developers who are already more familiar with the Spring I * **file-processing** - Sample demonstrates how to wire a message flow to process files either sequentially (maintain the order) or concurrently (no order). * **multipart-http** - Demonstrates the sending of HTTP multipart requests using Spring's **RestTemplate** and a Spring Integration **Http Outbound Gateway** * **travel** - More sophisticated example showing the retrieval of weather (SOAP Web Service) and traffic (HTTP Service) reports using real services +* **stored-procedures-derby** Provides an example of the stored procedure Outbound Gateway using *[Apache Derby](http://db.apache.org/derby/)* +* **stored-procedures-oracle** Provides an example of the stored procedure Outbound Gateway using *ORACLE XE* ## Advanced diff --git a/intermediate/pom.xml b/intermediate/pom.xml index 216a102e..400acb90 100644 --- a/intermediate/pom.xml +++ b/intermediate/pom.xml @@ -15,6 +15,7 @@ file-processing multipart-http travel + stored-procedures-derby diff --git a/intermediate/stored-procedures-derby/README.md b/intermediate/stored-procedures-derby/README.md new file mode 100644 index 00000000..b7e17953 --- /dev/null +++ b/intermediate/stored-procedures-derby/README.md @@ -0,0 +1,30 @@ +Spring Integration - Stored Procedure Example - Derby +================================================================================ + +# Overview + +This example provides a simple example using the stored procedure Outbound Gateway +adapter. This example will call 2 Derby Stored Procedures. + +One procedure uses an **Out** Parameter to return values and the second procedure +returns a **ResultSet**. + +# Setup + +Just make sure you have Maven set up and that the project builds successfully. + +# Run the Sample + +* running the "Main" class from within STS (Right-click on Main class --> Run As --> Java Application) +* or from the command line: + - mvn package + - mvn exec:java + +* Follow the screen (command line) instructions. + +-------------------------------------------------------------------------------- + +For help please take a look at the Spring Integration documentation: + +http://www.springsource.org/spring-integration + diff --git a/intermediate/stored-procedures-derby/pom.xml b/intermediate/stored-procedures-derby/pom.xml new file mode 100644 index 00000000..73565810 --- /dev/null +++ b/intermediate/stored-procedures-derby/pom.xml @@ -0,0 +1,122 @@ + + 4.0.0 + + org.springframework.integration.samples + derby-stored-procedures + 1.0-SNAPSHOT + jar + + stored-procedures-derby + http://www.springsource.org/spring-integration + + + UTF-8 + 2.1.0.BUILD-SNAPSHOT + 1.6.1 + 4.7 + + + + + repository.springframework.maven.release + Spring Framework Maven Release Repository + http://maven.springframework.org/release + + + + + + + maven-eclipse-plugin + 2.8 + + + org.springframework.ide.eclipse.core.springnature + + + org.springframework.ide.eclipse.core.springbuilder + + true + true + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + -Xlint:all + true + true + + + + org.codehaus.mojo + exec-maven-plugin + 1.2 + + org.springframework.integration.Main + + + + + + + + + + + junit + junit + ${junit.version} + test + + + + + + org.springframework.integration + spring-integration-core + ${spring.integration.version} + + + + org.springframework.integration + spring-integration-jdbc + ${spring.integration.version} + + + + + + ch.qos.logback + logback-classic + 0.9.28 + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + log4j-over-slf4j + ${slf4j.version} + + + org.slf4j + jcl-over-slf4j + ${slf4j.version} + + + + org.apache.derby + derby + 10.8.2.2 + + + + diff --git a/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/Main.java b/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/Main.java new file mode 100644 index 00000000..e206d857 --- /dev/null +++ b/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/Main.java @@ -0,0 +1,107 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.integration; + +import java.util.List; +import java.util.Scanner; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import org.springframework.integration.model.CoffeeBeverage; +import org.springframework.integration.service.CoffeeService; + + +/** + * Starts the Spring Context and will initialize the Spring Integration routes. + * + * @author Gunnar Hillert + * @since 2.1 + * + */ +public final class Main { + + private static final Logger LOGGER = LoggerFactory.getLogger(Main.class); + + private static final String LINE = "\n========================================================="; + private static final String NEWLINE = "\n "; + + private Main() { } + + /** + * Load the Spring Integration Application Context + * + * @param args - command line arguments + */ + public static void main(final String... args) { + + LOGGER.info(LINE + + LINE + + "\n Welcome to Spring Integration Coffee Database! " + + NEWLINE + + "\n For more information please visit: " + + "\n http://www.springsource.org/spring-integration " + + NEWLINE + + LINE ); + + final AbstractApplicationContext context = + new ClassPathXmlApplicationContext("classpath:META-INF/spring/integration/*-context.xml"); + + context.registerShutdownHook(); + + final Scanner scanner = new Scanner(System.in); + + final CoffeeService service = context.getBean(CoffeeService.class); + + LOGGER.info(LINE + + NEWLINE + + "\n Please press 'q + Enter' to quit the application. " + + NEWLINE + + LINE); + + System.out.print("Please enter 'list' and press to get a list of coffees."); + System.out.print("Enter a coffee id, e.g. '1' and press to get a description.\n\n"); + + while (!scanner.hasNext("q")) { + + String input = scanner.nextLine(); + + if ("list".equalsIgnoreCase(input)) { + List coffeeBeverages = service.findAllCoffeeBeverages(); + + for (CoffeeBeverage coffeeBeverage : coffeeBeverages) { + System.out.println(String.format("%s - %s", coffeeBeverage.getId(), + coffeeBeverage.getName())); + } + + } else { + System.out.println("Retrieving coffee information..."); + String coffeeDescription = service.findCoffeeBeverage(Integer.valueOf(input)); + + System.out.println(String.format("Searched for '%s' - Found: '%s'.", input, coffeeDescription)); + System.out.print("To try again, please enter another coffee beaverage and press :\n\n"); + } + + } + + LOGGER.info("Exiting application...bye."); + + System.exit(0); + + } +} diff --git a/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/jdbc/storedproc/derby/DerbyStoredProcedures.java b/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/jdbc/storedproc/derby/DerbyStoredProcedures.java new file mode 100644 index 00000000..f44180d3 --- /dev/null +++ b/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/jdbc/storedproc/derby/DerbyStoredProcedures.java @@ -0,0 +1,71 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.integration.jdbc.storedproc.derby; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.springframework.jdbc.support.JdbcUtils; + +/** + * + * @author Gunnar Hillert + * @since 2.1 + * + */ +public final class DerbyStoredProcedures { + + private DerbyStoredProcedures() { + } + + public static void findCoffee(int coffeeId, String[] coffeeDescription) + throws SQLException { + Connection connection = null; + PreparedStatement statement = null; + + try { + connection = DriverManager.getConnection("jdbc:default:connection"); + String sql = "SELECT * FROM COFFEE_BEVERAGES WHERE ID = ? "; + statement = connection.prepareStatement(sql); + statement.setLong(1, coffeeId); + + ResultSet resultset = statement.executeQuery(); + resultset.next(); + coffeeDescription[0] = resultset.getString("COFFEE_DESCRIPTION"); + + } finally { + JdbcUtils.closeStatement(statement); + JdbcUtils.closeConnection(connection); + } + + } + + public static void findAllCoffeeBeverages(ResultSet[] coffeeBeverages) + throws SQLException { + + Connection connection = null; + PreparedStatement statement = null; + + connection = DriverManager.getConnection("jdbc:default:connection"); + String sql = "SELECT * FROM COFFEE_BEVERAGES"; + statement = connection.prepareStatement(sql); + coffeeBeverages[0] = statement.executeQuery(); + + } +} diff --git a/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/model/CoffeeBeverage.java b/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/model/CoffeeBeverage.java new file mode 100644 index 00000000..74440472 --- /dev/null +++ b/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/model/CoffeeBeverage.java @@ -0,0 +1,131 @@ +/* + * 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.model; + +/** + * + * @author Gunnar Hillert + * @since 2.1 + * + */ +public class CoffeeBeverage { + + private Integer id; + private String name; + private String description; + + /** Default Constructor */ + public CoffeeBeverage() { + super(); + } + + /** + * @param id + * @param name + * @param description + */ + public CoffeeBeverage(Integer id, String name, String description) { + super(); + this.id = id; + this.name = name; + this.description = description; + } + + public Integer getId() { + return this.id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return this.description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime + * result + + ((this.description == null) ? 0 : this.description.hashCode()); + result = prime * result + + ((this.name == null) ? 0 : this.name.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; + } + + CoffeeBeverage other = (CoffeeBeverage) obj; + + if (this.description == null) { + + if (other.description != null) { + return false; + } + + } else if (!this.description.equals(other.description)) { + return false; + } + + if (this.name == null) { + + if (other.name != null) { + return false; + } + + } else if (!this.name.equals(other.name)) { + return false; + } + + return true; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("CoffeeBeverage [id=").append(this.id).append(", name=") + .append(this.name).append(", description=") + .append(this.description).append("]"); + return builder.toString(); + } + +} diff --git a/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/service/CoffeeService.java b/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/service/CoffeeService.java new file mode 100644 index 00000000..efbb978b --- /dev/null +++ b/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/service/CoffeeService.java @@ -0,0 +1,48 @@ +/* + * 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.service; + +import java.util.List; + +import org.springframework.integration.annotation.Payload; +import org.springframework.integration.model.CoffeeBeverage; + + +/** + * Provides access to the Coffee Database Services. + * + * @author Gunnar Hillert + * @since 2.1 + */ +public interface CoffeeService { + + /** + * Find the description for a provided coffee beverage. + * + * @param Id of the coffee beverage + * @return The the description of the coffee beverage + */ + String findCoffeeBeverage(Integer input); + + /** + * Find the description for a provided coffee beverage. + * + * @return Collection of coffee beverages + */ + @Payload("new java.util.Date()") + List findAllCoffeeBeverages(); + +} diff --git a/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/support/CoffeBeverageMapper.java b/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/support/CoffeBeverageMapper.java new file mode 100644 index 00000000..582d5559 --- /dev/null +++ b/intermediate/stored-procedures-derby/src/main/java/org/springframework/integration/support/CoffeBeverageMapper.java @@ -0,0 +1,33 @@ +/* + * 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.support; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.springframework.integration.model.CoffeeBeverage; +import org.springframework.jdbc.core.RowMapper; + +/** + * + * @author Gunnar Hillert + * @since 2.1 + * + */ +public class CoffeBeverageMapper implements RowMapper { + + public CoffeeBeverage mapRow(ResultSet rs, int rowNum) throws SQLException { + return new CoffeeBeverage(rs.getInt("ID"), rs.getString("COFFEE_NAME"), rs.getString("COFFEE_DESCRIPTION")); + } + +} diff --git a/intermediate/stored-procedures-derby/src/main/resources/META-INF/spring/integration/spring-integration-context.xml b/intermediate/stored-procedures-derby/src/main/resources/META-INF/spring/integration/spring-integration-context.xml new file mode 100644 index 00000000..cc7ffcf6 --- /dev/null +++ b/intermediate/stored-procedures-derby/src/main/resources/META-INF/spring/integration/spring-integration-context.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intermediate/stored-procedures-derby/src/main/resources/derby-stored-procedures.sql b/intermediate/stored-procedures-derby/src/main/resources/derby-stored-procedures.sql new file mode 100644 index 00000000..f9232408 --- /dev/null +++ b/intermediate/stored-procedures-derby/src/main/resources/derby-stored-procedures.sql @@ -0,0 +1,14 @@ +drop table COFFEE_BEVERAGES; +drop PROCEDURE FIND_COFFEE; +drop PROCEDURE FIND_ALL_COFFEE_BEVERAGES; + +create table COFFEE_BEVERAGES(ID INTEGER NOT NULL CONSTRAINT COFFEE_BEVERAGES_PK PRIMARY KEY, COFFEE_NAME varchar(100), COFFEE_DESCRIPTION varchar(200)); + +INSERT INTO COFFEE_BEVERAGES (ID, COFFEE_NAME, COFFEE_DESCRIPTION) VALUES (1, 'Espresso', 'Espressos keep developers going in the morning. There are never enough of them.'); +INSERT INTO COFFEE_BEVERAGES (ID, COFFEE_NAME, COFFEE_DESCRIPTION) VALUES (2, 'Cappuccino', 'For the finer moments. Wrap your espresso in a tasty layer of foam.'); +INSERT INTO COFFEE_BEVERAGES (ID, COFFEE_NAME, COFFEE_DESCRIPTION) VALUES (3, 'Mocha', 'Mmmmh, chocolate.'); +INSERT INTO COFFEE_BEVERAGES (ID, COFFEE_NAME, COFFEE_DESCRIPTION) VALUES (4, 'Latte', 'If you are more into milk than into foam.'); + +CREATE PROCEDURE FIND_COFFEE( IN COFFEE_NAME INTEGER, OUT COFFEE_DESCRIPTION VARCHAR(100)) PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME 'org.springframework.integration.jdbc.storedproc.derby.DerbyStoredProcedures.findCoffee'; +CREATE PROCEDURE FIND_ALL_COFFEE_BEVERAGES() PARAMETER STYLE JAVA LANGUAGE JAVA MODIFIES SQL DATA DYNAMIC RESULT SETS 1 EXTERNAL NAME 'org.springframework.integration.jdbc.storedproc.derby.DerbyStoredProcedures.findAllCoffeeBeverages'; + diff --git a/intermediate/stored-procedures-derby/src/main/resources/logback.xml b/intermediate/stored-procedures-derby/src/main/resources/logback.xml new file mode 100644 index 00000000..eee6b966 --- /dev/null +++ b/intermediate/stored-procedures-derby/src/main/resources/logback.xml @@ -0,0 +1,24 @@ + + + + + + + %d %5p | %t | %-55logger{55} | %m %n + + + + + + + + + + + + + + + + + diff --git a/intermediate/stored-procedures-derby/src/test/java/org/springframework/integration/CoffeeServiceFindAllTest.java b/intermediate/stored-procedures-derby/src/test/java/org/springframework/integration/CoffeeServiceFindAllTest.java new file mode 100644 index 00000000..4ed29597 --- /dev/null +++ b/intermediate/stored-procedures-derby/src/test/java/org/springframework/integration/CoffeeServiceFindAllTest.java @@ -0,0 +1,48 @@ +/* + * 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; + +import java.util.List; + +import org.junit.Test; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.integration.model.CoffeeBeverage; +import org.springframework.integration.service.CoffeeService; +import static org.junit.Assert.assertTrue; + +/** + * @author Gunnar Hillert + * @since 2.1 + */ +public class CoffeeServiceFindAllTest { + + @Test + public void testFindCoffee() { + final ApplicationContext context + = new ClassPathXmlApplicationContext("/META-INF/spring/integration/spring-integration-context.xml", + CoffeeServiceFindAllTest.class); + + final CoffeeService service = context.getBean(CoffeeService.class); + + List coffeeBeverages = service.findAllCoffeeBeverages(); + + assertTrue(coffeeBeverages.size() == 4); + + } + +} diff --git a/intermediate/stored-procedures-derby/src/test/java/org/springframework/integration/CoffeeServiceFindCoffeeTest.java b/intermediate/stored-procedures-derby/src/test/java/org/springframework/integration/CoffeeServiceFindCoffeeTest.java new file mode 100644 index 00000000..b3a116cc --- /dev/null +++ b/intermediate/stored-procedures-derby/src/test/java/org/springframework/integration/CoffeeServiceFindCoffeeTest.java @@ -0,0 +1,45 @@ +/* + * 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; + +import org.junit.Test; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.integration.service.CoffeeService; +import static org.junit.Assert.assertEquals; + +/** + * @author Gunnar Hillert + * @since 2.1 + */ +public class CoffeeServiceFindCoffeeTest { + + @Test + public void testFindCoffee() { + final ApplicationContext context + = new ClassPathXmlApplicationContext("/META-INF/spring/integration/spring-integration-context.xml", + CoffeeServiceFindCoffeeTest.class); + + final CoffeeService service = context.getBean(CoffeeService.class); + + String description = service.findCoffeeBeverage(3); + + assertEquals("Mmmmh, chocolate.", description); + + } + +} diff --git a/intermediate/stored-procedures-derby/src/test/java/org/springframework/integration/CoffeeServiceStartupTest.java b/intermediate/stored-procedures-derby/src/test/java/org/springframework/integration/CoffeeServiceStartupTest.java new file mode 100644 index 00000000..1db43575 --- /dev/null +++ b/intermediate/stored-procedures-derby/src/test/java/org/springframework/integration/CoffeeServiceStartupTest.java @@ -0,0 +1,36 @@ +/* + * 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; + +import org.junit.Test; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Verify that the Spring Integration Application Context starts successfully. + */ +public class CoffeeServiceStartupTest { + + @Test + public void testStartupOfSpringInegrationContext() throws Exception{ + final ApplicationContext context + = new ClassPathXmlApplicationContext("/META-INF/spring/integration/spring-integration-context.xml", + CoffeeServiceStartupTest.class); + Thread.sleep(2000); + } + +}