diff --git a/intermediate/stored-procedures-oracle/README.md b/intermediate/stored-procedures-oracle/README.md index c8eac2c8..9876b001 100644 --- a/intermediate/stored-procedures-oracle/README.md +++ b/intermediate/stored-procedures-oracle/README.md @@ -1,85 +1,78 @@ Spring Integration - Stored Procedure Example - Oracle -================================================================================ +====================================================== -# Overview +## Overview -This example provides a simple example using the stored procedure outbound gateway -adapter. This example will call an Oracle Stored Procedure as well as an Oracle Function using the StoredProc Outbound Gateway. +This sample application illustrates the usage of the *Spring Integration* Stored Procedure components using an Oracleâ„¢ database as a backend. +Actually 2 samples are provided: + +* **Sample 1** Capitalizes Strings +* **Sample 2** Retrieves Coffee Data + - This is sample is similar to the [Stored Procedure Sample for PostgreSql][] + +## Running the Sample + +### Pre-requisites This sample was tested against: **Oracle Database Express Edition 11g Release 2** (which can be downloaded and used for free). Nevertheless, the example should work with other versions as well. -# Setup - -##Pre-requisites - - Access to a Oracle or Oracle XE database instance - Install Oracle JDBC Driver to your local Maven repository (~/.m2) -##JDBC Driver installation +### JDBC Driver Installation for Oracle - Go to [http://www.oracle.com/technetwork/indexes/downloads/index.html](http://www.oracle.com/technetwork/indexes/downloads/index.html) -- Under "JDBC Drivers", download the appropriate driver relevant to your Oracle and JDK version (This sample was tested using -"Oracle Database 11g Release 2 JDBC Drivers") +- Under "JDBC Drivers", download the appropriate driver relevant to your Oracle and JDK version (This sample was tested using "Oracle Database 11g Release 2 JDBC Drivers") - Once downloaded, install the driver to your local Maven repository: $ mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.3 -Dpackaging=jar -Dfile=~/dev/ojdbc6.jar -DgeneratePom=true - Now you can add the dependency to the Maven pom.xml file. Please check the pom.xml for this project and verify that it matches your installed Oracle JDBC driver +```XML com.oracle ojdbc6 11.2.0.3 +``` -## Setting Up Oracle +### Common Oracle Setup -### Create Tablespace +#### Create Tablespace +```SQL CREATE TABLESPACE procedure_test DATAFILE 'c:/data/procedure_test.dbf' - SIZE 10M + SIZE 10M AUTOEXTEND ON NEXT 10M MAXSIZE 100M; +``` -### Create User +#### Create User +```SQL CREATE USER storedproc IDENTIFIED BY storedproc DEFAULT TABLESPACE procedure_test - TEMPORARY TABLESPAC temp; + TEMPORARY TABLESPACE temp; +``` -### Grant Rights +#### Grant Rights - GRANT CREATE SESSION,CREATE TABLE,CREATE VIEW,CREATE SEQUENCE TO storedproc; +```SQL + GRANT CREATE SESSION, CREATE TABLE, CREATE VIEW, CREATE SEQUENCE, CREATE PROCEDURE TO storedproc; ALTER USER storedproc QUOTA unlimited ON procedure_test; +``` -### Creating the Stored Procedure - -create or replace -PROCEDURE CAPITALIZE_STRING(inoutString IN OUT VARCHAR) IS -BEGIN - SELECT upper(inoutString) INTO inoutString from dual ; -END; - -### Creating the Function - -create or replace -FUNCTION GET_COOL_NUMBER - RETURN NUMBER - IS cool_number NUMBER(11,2); -BEGIN - cool_number := 12345; - RETURN cool_number; -END; - -## Setting Up Oracle +### Setting up the Spring Application Context You may have to update the Oracle DB properties in: /src/main/resources/META-INF/spring/integration/spring-integration-context.xml +```XML @@ -92,17 +85,171 @@ You may have to update the Oracle DB properties in: +``` -# Run the Sample +## Running Sample 1 - Capitalizes Strings + +This example provides a simple example using the stored procedure outbound gateway +adapter. This example will call an Oracle Stored Procedure as well as an Oracle Function using the StoredProc Outbound Gateway. + +### Creating the Stored Procedure + +```SQL +create or replace +PROCEDURE CAPITALIZE_STRING(inoutString IN OUT VARCHAR) IS +BEGIN + SELECT upper(inoutString) INTO inoutString from dual ; +END; +``` + +### Creating the Stored Function + +```SQL +create or replace +FUNCTION GET_COOL_NUMBER + RETURN NUMBER + IS cool_number NUMBER(11,2); +BEGIN + cool_number := 12345; + RETURN cool_number; +END; +``` + +### Execute 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 + +You should see the following output: + + 16:05:19.556 INFO [main][org.springframework.integration.Main] + ========================================================= + + Welcome to Spring Integration's + Stored Procedure/Function Sample for Oracle + + For more information please visit: + http://www.springsource.org/spring-integration + + ========================================================= + Please enter a choice and press : + 1. Execute Sample 1 (Capitalize String) + 2. Execute Sample 2 (Coffee Service) + q. Quit the application + +Select **Opion 1**. + + ========================================================= + + Please press 'q + Enter' to quit the application. + + ========================================================= + Please enter a string and press : hello world + Converting String to Uppcase using Stored Procedure... + Retrieving Numeric value via Sql Function... + Converted 'hello world' - End Result: 'HELLO WORLD_12345'. + +When you enter a text, the text will be converted into upper-case using the Oracle Stored Procedure named `CAPITALIZE_STRING`. Afterwards, the String is concatenated with the result from calling the Oracle Stored Function `GET_COOL_NUMBER`. + +## Running Sample 2 - Coffee Service + +### Create Table COFFEE_BEVERAGES + +```SQL +CREATE TABLE "COFFEE_BEVERAGES"( + "ID" NUMBER(10,0) NOT NULL, + "COFFEE_NAME" VARCHAR2(50 CHAR) NOT NULL, + "COFFEE_DESCRIPTION" VARCHAR2(500 CHAR) NOT NULL, + CONSTRAINT "COFFEE_BEVERAGES_PK" PRIMARY KEY ("ID")); +``` +### Add Sample Data to Table COFFEE_BEVERAGES + +```SQL +REM INSERTING into COFFEE_BEVERAGES +SET DEFINE OFF; +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.'); +``` + +### Creating the Stored Functions + +Please create the following Stored Functions: + +#### Find All Coffee Beverages + +```SQL +create or replace +package types +as + type cursorType is ref cursor; +end; +``` + +```SQL +create or replace +FUNCTION find_all_coffee_beverages return types.cursortype +AS + l_cursor types.cursorType; +BEGIN + OPEN l_cursor FOR SELECT "ID", "COFFEE_NAME", "COFFEE_DESCRIPTION" FROM "COFFEE_BEVERAGES"; + RETURN l_cursor; +END; +``` +#### Find Specific Coffee Beverage + +```SQL +create or replace +FUNCTION find_coffee(coffee_id IN integer) + RETURN VARCHAR2 is description VARCHAR2(1000); +begin + SELECT COFFEE_DESCRIPTION into description from COFFEE_BEVERAGES where ID=coffee_id; + return description; +end; +``` +### Execute 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 +You should see the following output: + + 16:05:19.556 INFO [main][org.springframework.integration.Main] + ========================================================= + + Welcome to Spring Integration's + Stored Procedure/Function Sample for Oracle + + For more information please visit: + http://www.springsource.org/spring-integration + + ========================================================= + Please enter a choice and press : + 1. Execute Sample 1 (Capitalize String) + 2. Execute Sample 2 (Coffee Service) + q. Quit the application + +Select **Opion 2**. + +This should result in the following output: + + * Please enter 'list' and press to get a list of coffees. + * Enter a coffee id, e.g. '1' and press to get a description. + * Please press 'q + Enter' to quit the application. + +This sample also periodically polls the Oracle database using a **Stored Procedure Inbound Channel Adapter**: + + 16:06:46.669 INFO [task-scheduler-1][org.springframework.integration.handler.LoggingHandler] [Payload=[CoffeeBeverage [id=1,... + -------------------------------------------------------------------------------- For help please take a look at the Spring Integration documentation: http://www.springsource.org/spring-integration +[Stored Procedure Sample for PostgreSql]: https://github.com/ghillert/spring-integration-samples/tree/master/intermediate/stored-procedures-postgresql diff --git a/intermediate/stored-procedures-oracle/pom.xml b/intermediate/stored-procedures-oracle/pom.xml index ca923cfe..697b47f4 100644 --- a/intermediate/stored-procedures-oracle/pom.xml +++ b/intermediate/stored-procedures-oracle/pom.xml @@ -16,7 +16,7 @@ UTF-8 - 2.2.0.RELEASE + 2.2.2.RELEASE 1.2.17 4.10 diff --git a/intermediate/stored-procedures-oracle/src/main/java/org/springframework/integration/Main.java b/intermediate/stored-procedures-oracle/src/main/java/org/springframework/integration/Main.java index e28f88cc..eade4937 100644 --- a/intermediate/stored-procedures-oracle/src/main/java/org/springframework/integration/Main.java +++ b/intermediate/stored-procedures-oracle/src/main/java/org/springframework/integration/Main.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2013 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. @@ -15,12 +15,13 @@ */ package org.springframework.integration; +import java.util.List; import java.util.Scanner; import org.apache.log4j.Logger; -import org.springframework.context.support.AbstractApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - +import org.springframework.context.support.GenericXmlApplicationContext; +import org.springframework.integration.model.CoffeeBeverage; +import org.springframework.integration.service.CoffeeService; import org.springframework.integration.service.StringConversionService; @@ -33,59 +34,139 @@ import org.springframework.integration.service.StringConversionService; */ public final class Main { - private static final Logger LOGGER = Logger.getLogger(Main.class); + private static final Logger LOGGER = Logger.getLogger(Main.class); - private Main() { } + private Main() { } - /** - * Load the Spring Integration Application Context - * - * @param args - command line arguments - */ - public static void main(final String... args) { + /** + * Load the Spring Integration Application Context + * + * @param args - command line arguments + */ + public static void main(final String... args) { - LOGGER.info("\n=========================================================" - + "\n " - + "\n Welcome to Spring Integration! " - + "\n " - + "\n For more information please visit: " - + "\n http://www.springsource.org/spring-integration " - + "\n " - + "\n=========================================================" ); + final Scanner scanner = new Scanner(System.in); - final AbstractApplicationContext context = - new ClassPathXmlApplicationContext("classpath:META-INF/spring/integration/*-context.xml"); + LOGGER.info("\n=========================================================" + + "\n " + + "\n Welcome to Spring Integration's " + + "\n Stored Procedure/Function Sample for Oracle " + + "\n " + + "\n For more information please visit: " + + "\n http://www.springsource.org/spring-integration " + + "\n " + + "\n=========================================================" ); - context.registerShutdownHook(); + while (true) { - final Scanner scanner = new Scanner(System.in); + System.out.println("Please enter a choice and press : "); + System.out.println("\t1. Execute Sample 1 (Capitalize String)"); + System.out.println("\t2. Execute Sample 2 (Coffee Service)"); + System.out.println("\tq. Quit the application"); - final StringConversionService service = context.getBean(StringConversionService.class); + final String input = scanner.nextLine(); - LOGGER.info("\n=========================================================" - + "\n " - + "\n Please press 'q + Enter' to quit the application. " - + "\n " - + "\n=========================================================" ); + if("1".equals(input.trim())) { + executeSample1(); + continue; + } else if("2".equals(input.trim())) { + executeSample2(); + continue; + } else if("q".equals(input.trim())) { + break; + } else { + System.out.println("Invalid choice\n\n"); + System.out.print("Enter you choice: "); + } + } - System.out.print("Please enter a string and press : "); + System.out.println("Exiting application."); + System.exit(0); - while (!scanner.hasNext("q")) { - String input = scanner.nextLine(); + } - System.out.println("Converting String to Uppcase using Stored Procedure..."); - String inputUpperCase = service.convertToUpperCase(input); + private static void executeSample1() { - System.out.println("Retrieving Numeric value via Sql Function..."); - Integer number = service.getNumber(); + final Scanner scanner = new Scanner(System.in); - System.out.println(String.format("Converted '%s' - End Result: '%s_%s'.", input, inputUpperCase, number)); - System.out.print("To try again, please enter a string and press :"); - } + final GenericXmlApplicationContext context = new GenericXmlApplicationContext(); + context.load("classpath:META-INF/spring/integration/spring-integration-sample1-context.xml"); + context.registerShutdownHook(); + context.refresh(); - LOGGER.info("Exiting application...bye."); + final StringConversionService service = context.getBean(StringConversionService.class); - System.exit(0); + final String message = + "\n=========================================================" + + "\n " + + "\n Please press 'q + Enter' to quit the application. " + + "\n " + + "\n=========================================================" + + "\n\n Please enter a string and press : "; + + System.out.print(message); + + while (!scanner.hasNext("q")) { + String input = scanner.nextLine(); + + System.out.println("Converting String to Uppcase using Stored Procedure..."); + String inputUpperCase = service.convertToUpperCase(input); + + System.out.println("Retrieving Numeric value via Sql Function..."); + Integer number = service.getNumber(); + + System.out.println(String.format("Converted '%s' - End Result: '%s_%s'.", input, inputUpperCase, number)); + System.out.print("To try again, please enter a string and press :"); + } + + context.close(); + System.out.println("Back to main menu."); + + } + + private static void executeSample2() { + + final Scanner scanner = new Scanner(System.in); + + final GenericXmlApplicationContext context = new GenericXmlApplicationContext(); + context.load("classpath:META-INF/spring/integration/spring-integration-sample2-context.xml"); + context.registerShutdownHook(); + context.refresh(); + + final CoffeeService service = context.getBean(CoffeeService.class); + + final String message = "\n\n" + + "* Please enter 'list' and press to get a list of coffees.\n" + + "* Enter a coffee id, e.g. '1' and press to get a description.\n" + + "* Please press 'q + Enter' to quit the application.\n"; + + System.out.println(message); + + 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 beverage and press :\n\n"); + } + + } + + context.close(); + + System.out.println("Back to main menu."); + } - } } diff --git a/intermediate/stored-procedures-oracle/src/main/java/org/springframework/integration/model/CoffeeBeverage.java b/intermediate/stored-procedures-oracle/src/main/java/org/springframework/integration/model/CoffeeBeverage.java new file mode 100644 index 00000000..b752537f --- /dev/null +++ b/intermediate/stored-procedures-oracle/src/main/java/org/springframework/integration/model/CoffeeBeverage.java @@ -0,0 +1,131 @@ +/* + * 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.model; + +/** + * + * @author Gunnar Hillert + * @since 2.2 + * + */ +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-oracle/src/main/java/org/springframework/integration/service/CoffeeService.java b/intermediate/stored-procedures-oracle/src/main/java/org/springframework/integration/service/CoffeeService.java new file mode 100644 index 00000000..da648bd8 --- /dev/null +++ b/intermediate/stored-procedures-oracle/src/main/java/org/springframework/integration/service/CoffeeService.java @@ -0,0 +1,50 @@ +/* + * 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.service; + +import java.util.List; + +import org.springframework.integration.annotation.Payload; +import org.springframework.integration.model.CoffeeBeverage; +import org.springframework.transaction.annotation.Transactional; + + +/** + * Provides access to the Coffee Database Services. + * + * @author Gunnar Hillert + * @since 2.2 + */ +@Transactional +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-oracle/src/main/java/org/springframework/integration/support/CoffeBeverageMapper.java b/intermediate/stored-procedures-oracle/src/main/java/org/springframework/integration/support/CoffeBeverageMapper.java new file mode 100644 index 00000000..3f246061 --- /dev/null +++ b/intermediate/stored-procedures-oracle/src/main/java/org/springframework/integration/support/CoffeBeverageMapper.java @@ -0,0 +1,33 @@ +/* + * 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.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.2 + * + */ +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-oracle/src/main/resources/META-INF/spring/integration/spring-integration-context.xml b/intermediate/stored-procedures-oracle/src/main/resources/META-INF/spring/integration/spring-integration-context.xml deleted file mode 100644 index d14f58d2..00000000 --- a/intermediate/stored-procedures-oracle/src/main/resources/META-INF/spring/integration/spring-integration-context.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - 3 - 20 - - - - - - - - - - - - - - - - - - - - - diff --git a/intermediate/stored-procedures-oracle/src/main/resources/META-INF/spring/integration/spring-integration-database-context.xml b/intermediate/stored-procedures-oracle/src/main/resources/META-INF/spring/integration/spring-integration-database-context.xml new file mode 100644 index 00000000..2de20700 --- /dev/null +++ b/intermediate/stored-procedures-oracle/src/main/resources/META-INF/spring/integration/spring-integration-database-context.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + 3 + 20 + + + + + diff --git a/intermediate/stored-procedures-oracle/src/main/resources/META-INF/spring/integration/spring-integration-sample1-context.xml b/intermediate/stored-procedures-oracle/src/main/resources/META-INF/spring/integration/spring-integration-sample1-context.xml new file mode 100644 index 00000000..c7decc01 --- /dev/null +++ b/intermediate/stored-procedures-oracle/src/main/resources/META-INF/spring/integration/spring-integration-sample1-context.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/intermediate/stored-procedures-oracle/src/main/resources/META-INF/spring/integration/spring-integration-sample2-context.xml b/intermediate/stored-procedures-oracle/src/main/resources/META-INF/spring/integration/spring-integration-sample2-context.xml new file mode 100644 index 00000000..54cc1dca --- /dev/null +++ b/intermediate/stored-procedures-oracle/src/main/resources/META-INF/spring/integration/spring-integration-sample2-context.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intermediate/stored-procedures-oracle/src/main/resources/log4j.xml b/intermediate/stored-procedures-oracle/src/main/resources/log4j.xml index 40d94ca5..c80a153b 100644 --- a/intermediate/stored-procedures-oracle/src/main/resources/log4j.xml +++ b/intermediate/stored-procedures-oracle/src/main/resources/log4j.xml @@ -12,7 +12,7 @@ - +