Skip to content

Commit

Permalink
INTSAMPLES-60 - Add JMS-backed Cafe Application Sample
Browse files Browse the repository at this point in the history
* Add idea folder to .gitignore
* Add an embedded ActiveMQ
* Add activemq data to ignore list
* Use JMS-backed channels
* Add the sample description to README.md
  • Loading branch information
christian-posta authored and ghillert committed Oct 3, 2012
1 parent 23ed55d commit a46d0a3
Show file tree
Hide file tree
Showing 50 changed files with 746 additions and 52 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ derby.log
.idea
activemq-data
.settings/


4 changes: 2 additions & 2 deletions applications/cafe-scripted/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@
<arguments>
<argument>-classpath</argument>
<classpath />
<argument>org.springframework.integration.samples.cafe.demo.CafeDemoApp</argument>
<argument>org.springframework.integration.samples.org.springframework.integration.samples.cafe.demo.CafeDemoApp</argument>
<argument>${lang}</argument>
</arguments>
<successCodes>
Expand Down Expand Up @@ -181,7 +181,7 @@
<arguments>
<argument>-classpath</argument>
<classpath />
<argument>org.springframework.integration.samples.cafe.demo.ControlBusMain</argument>
<argument>org.springframework.integration.samples.org.springframework.integration.samples.cafe.demo.ControlBusMain</argument>

</arguments>
<successCodes>
Expand Down
43 changes: 18 additions & 25 deletions applications/cafe/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Cafe Sample Application
=======================

The Cafe sample emulates a simple operation of the Coffee shop when modeled using Enterprise Integration Patterns (EIP). It is inspired by one of the samples featured in Gregor Hohpe's Ramblings. The domain is that of a Cafe, and the basic flow is depicted in the following diagram:
The Cafe sample emulates a simple operation of the Coffee shop when modeled using Enterprise Integration Patterns (EIP). It is inspired by one of the samples featured in Gregor Hohpe's Ramblings (see Starbucks Does Not Use Two-Phase Commit: http://www.eaipatterns.com/ramblings/18_starbucks.html). The domain is that of a Cafe, and the basic flow is depicted in the following diagram:


Barista
Expand All @@ -23,43 +23,36 @@ The Order object may contain multiple OrderItems. Once the order is placed, a **

The prepared drinks are then sent to the Waiter where they are aggregated into a Delivery object.

## Instructions for running the CafeDemo sample
## Cafe Sample Implementations
There are currently three implementations of the cafe sample:

1. The example comes with two identical configurations. One is ANNOTATION-based another is XML-based
1. Using Spring Integration channels and components
2. Using AMQP/RabbitMQ to demonstrate a distributed architecture
3. Using JMS/ActiveMQ to demonstrate jms-backed queues and a distributed architecture

2. To run this sample simply execute the CafeDemoApp test classes in the **org.springframework.integration.samples.cafe.xml** or **org.springframework.integration.samples.cafe.annotation** package.
All three implementations follow the same flow described above. See each one's README.md file for more details about the respective implementations.

3. The example also provides an alternative configuration that uses AMQP channels to distribute the components in the **CafeDemo** sample. To run this alternative configuration of the sample, be sure to have a RabbitMQ broker started on localhost:5672 configured with the default guest|guest client credentials on the / vHost, then execute the following test classes in order:

1. **cafeDemoAppBaristaColdAmqp** - starts the Cold Drink Barista
2. **cafeDemoAppBaristaHotAmqp** - starts the Hot Drink Barista
3. **cafeDemoAppAmqp** - starts the Cafe Storefront (Places 100 orders on the orders queue)
4. **cafeDemoAppOperationsAmqp** - starts the Cafe Operations (OrderSplitter, DrinkRouter, PreparedDrinkAggregator)

**Note**: All AMQP exchanges, queues, and bindings needed for this sample are defined within the different xml config files that support the above test classes.

Upon running any of the alternatives, you should see the output similar to this:

INFO : org.springframework.integration.samples.cafe.annotation.Barista - task-scheduler-1 prepared cold drink #1 for order #1: iced 3 shot MOCHA
INFO : org.springframework.integration.samples.cafe.annotation.Barista - task-scheduler-1 prepared cold drink #2 for order #2: iced 3 shot MOCHA
INFO : org.springframework.integration.samples.cafe.annotation.Barista - task-scheduler-1 prepared cold drink #3 for order #3: iced 3 shot MOCHA
INFO : org.springframework.integration.samples.cafe.annotation.Barista - task-scheduler-1 prepared cold drink #4 for order #4: iced 3 shot MOCHA
INFO : org.springframework.integration.samples.cafe.annotation.Barista - task-scheduler-2 prepared hot drink #1 for order #1: hot 2 shot LATTE
INFO : Barista - task-scheduler-1 prepared cold drink #1 for order #1: iced 3 shot MOCHA
INFO : Barista - task-scheduler-1 prepared cold drink #2 for order #2: iced 3 shot MOCHA
INFO : Barista - task-scheduler-1 prepared cold drink #3 for order #3: iced 3 shot MOCHA
INFO : Barista - task-scheduler-1 prepared cold drink #4 for order #4: iced 3 shot MOCHA
INFO : Barista - task-scheduler-2 prepared hot drink #1 for order #1: hot 2 shot LATTE
-----------------------
Order #1
Iced MOCHA, 3 shots.
Hot LATTE, 2 shots.
-----------------------
INFO : org.springframework.integration.samples.cafe.annotation.Barista - task-scheduler-1 prepared cold drink #5 for order #5: iced 3 shot MOCHA
INFO : org.springframework.integration.samples.cafe.annotation.Barista - task-scheduler-1 prepared cold drink #6 for order #6: iced 3 shot MOCHA
INFO : org.springframework.integration.samples.cafe.annotation.Barista - task-scheduler-1 prepared cold drink #7 for order #7: iced 3 shot MOCHA
INFO : org.springframework.integration.samples.cafe.annotation.Barista - task-scheduler-1 prepared cold drink #8 for order #8: iced 3 shot MOCHA
INFO : org.springframework.integration.samples.cafe.annotation.Barista - task-scheduler-1 prepared cold drink #9 for order #9: iced 3 shot MOCHA
INFO : org.springframework.integration.samples.cafe.annotation.Barista - task-scheduler-2 prepared hot drink #2 for order #2: hot 2 shot LATTE
INFO : Barista - task-scheduler-1 prepared cold drink #5 for order #5: iced 3 shot MOCHA
INFO : Barista - task-scheduler-1 prepared cold drink #6 for order #6: iced 3 shot MOCHA
INFO : Barista - task-scheduler-1 prepared cold drink #7 for order #7: iced 3 shot MOCHA
INFO : Barista - task-scheduler-1 prepared cold drink #8 for order #8: iced 3 shot MOCHA
INFO : Barista - task-scheduler-1 prepared cold drink #9 for order #9: iced 3 shot MOCHA
INFO : Barista - task-scheduler-2 prepared hot drink #2 for order #2: hot 2 shot LATTE
-----------------------
Order #2
Iced MOCHA, 3 shots.
Hot LATTE, 2 shots.
-----------------------

Happy integration :-)
29 changes: 29 additions & 0 deletions applications/cafe/cafe-amqp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
Cafe Sample Application - AMQP Implementation
=======================

See the parent-level README.md for more details, but the flow of the implementation should follow this diagram:


Barista
hotDrinks ____________________
|==========| -->| |
orders drinks / | prepareHotDrink() |
Place Order ->Cafe->|======|->OrderSplitter->|======|->DrinkRouter | |
\ coldDrinks | prepareColdDrink() |
|==========| -->| |
|____________________|

Legend: |====| - channels


## Instructions for running the CafeDemo AMQP sample

### Distributed components
To run this alternative configuration of the sample, be sure to have a RabbitMQ broker started on localhost:5672 configured with the default guest|guest client credentials on the / vHost, then execute the following test classes in order:

1. **cafeDemoAppBaristaColdAmqp** - starts the Cold Drink Barista
2. **cafeDemoAppBaristaHotAmqp** - starts the Hot Drink Barista
3. **cafeDemoAppAmqp** - starts the Cafe Storefront (Places 100 orders on the orders queue)
4. **cafeDemoAppOperationsAmqp** - starts the Cafe Operations (OrderSplitter, DrinkRouter, PreparedDrinkAggregator)

**Note**: All AMQP exchanges, queues, and bindings needed for this sample are defined within the different xml config files that support the above test classes.
35 changes: 35 additions & 0 deletions applications/cafe/cafe-amqp/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>cafe</artifactId>
<groupId>org.springframework.integration.samples</groupId>
<version>2.1.0.BUILD-SNAPSHOT</version>
</parent>

<artifactId>cafe-amqp</artifactId>

<name>Cafe - With AMQP Message Broker</name>
<description>
This module implements the cafe sample using spring-integration components backed
by an AMQP message broker for message persistence and component distribution. This
sample uses RabbitMQ broker, but any AMQP message broker can be used. For an example
using JMS, see the JMS implemenation of the cafe sample.
</description>

<dependencies>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>cafe-si</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-amqp</artifactId>
<version>${spring.integration.version}</version>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public static void order(AbstractApplicationContext context, int count){
public static void main(String[] args) {
AbstractApplicationContext context =
CafeDemoAppUtilities.loadProfileContext(
"/META-INF/spring/integration/amqp/cafeDemo-amqp-xml.xml",
"/META-INF/spring/integration/amqp/cafeDemo-amqp-xml.xml",
CafeDemoAppAmqp.class,CafeDemoAppUtilities.DEV);
order(context, 100);
context.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class CafeDemoAppBaristaColdAmqp {
public static void main(String[] args) {
AbstractApplicationContext context =
CafeDemoAppUtilities.loadProfileContext(
"/META-INF/spring/integration/amqp/cafeDemo-amqp-baristaCold-xml.xml",
"/META-INF/spring/integration/amqp/cafeDemo-amqp-baristaCold-xml.xml",
CafeDemoAppBaristaColdAmqp.class,CafeDemoAppUtilities.DEV);

System.out.println("Press Enter/Return in the console to exit the Barista Cold App");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class CafeDemoAppBaristaHotAmqp {
public static void main(String[] args) {
AbstractApplicationContext context =
CafeDemoAppUtilities.loadProfileContext(
"/META-INF/spring/integration/amqp/cafeDemo-amqp-baristaHot-xml.xml",
"/META-INF/spring/integration/amqp/cafeDemo-amqp-baristaHot-xml.xml",
CafeDemoAppBaristaHotAmqp.class,CafeDemoAppUtilities.DEV);

System.out.println("Press Enter/Return in the console to exit the Barista Hot App");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class CafeDemoAppOperationsAmqp {
public static void main(String[] args) {
AbstractApplicationContext context =
CafeDemoAppUtilities.loadProfileContext(
"/META-INF/spring/integration/amqp/cafeDemo-amqp-operations-xml.xml",
"/META-INF/spring/integration/amqp/cafeDemo-amqp-operations-xml.xml",
CafeDemoAppOperationsAmqp.class,CafeDemoAppUtilities.DEV);

System.out.println("Press Enter/Return in the console to exit the Cafe Operations App");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
xmlns:int-amqp="http://www.springframework.org/schema/integration/amqp"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xmlns:stream="http://www.springframework.org/schema/integration/stream"
xmlns:cloud="http://schema.cloudfoundry.org/spring"
xmlns:cloud="http://schema.cloudfoundry.org /spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://schema.cloudfoundry.org/spring
Expand Down
31 changes: 31 additions & 0 deletions applications/cafe/cafe-jms/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Cafe Sample Application - JMS Implementation
=======================

See the parent-level README.md for more details, but the flow of the implementation should follow this diagram:


Barista
hotDrinks ____________________
|==========| -->| |
orders drinks / | prepareHotDrink() |
Place Order ->Cafe->|======|->OrderSplitter->|======|->DrinkRouter | |
\ coldDrinks | prepareColdDrink() |
|==========| -->| |
|____________________|
Legend: |====| - channels


## Instructions for running the CafeDemo JMS sample

### Distributed components
To run this configuration, start an instance of ActiveMQ with the openwire/TCP connector available on the default port (61616). There are no credentials of which to be aware. Please execute the following classes in order:

1. **CafeDemoAppBaristaColdActiveMQ - starts the ColdDrink Barista
2. **CafeDemoAppBaristaHotActiveMQ - starts the HotDrink Barista
3. **CafeDemoAppOperationsActiveMQ - starts the Cafe Operations (order splitter, drink router, etc).
4. **CafeDemoAppAcitveMQ - places the orders

### JMS backed components

See **CafeDemoActiveMQBackedChannels** for an example of how to use the JMS-backed channels. No need to start an external ActiveMQ because one is started internally
48 changes: 48 additions & 0 deletions applications/cafe/cafe-jms/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.integration.samples</groupId>
<artifactId>cafe</artifactId>
<version>2.1.0.BUILD-SNAPSHOT</version>
</parent>

<artifactId>cafe-jms</artifactId>

<name>Cafe - With JMS Message Broker</name>
<description>
This module implements the cafe sample using spring-integration components backed
by a JMS broker for persistent messaging as well as component distribution. This
sample uses ActiveMQ as the JMS broker, but any JMS-compliant broker can be
used. For an example using AMQP, see the AMQP implementation of the cafe sample.
</description>

<properties>
<activemq.version>5.4.3</activemq.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>${activemq.version}</version>
</dependency>
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jms</artifactId>
<version>${spring.integration.version}</version>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>cafe-si</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.springframework.integration.samples.cafe.xml;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.samples.cafe.Cafe;
import org.springframework.integration.samples.cafe.DrinkType;
import org.springframework.integration.samples.cafe.Order;

import java.io.IOException;

/**
* Main class for running the Cafe sample with JMS-backed (ActiveMQ) channels. Once the application
* is running, simply press <return> or any other key to end the application. To fully experience the
* benefits of this solution, try halting/exiting the program in the middle of running it, comment out the
* call to place new orders (the order() function call) and watch that the processing still continues
* where it left off when you halted it. This is because the messages are persisted in the ActiveMQ queues
*
* @author ceposta
*/
public class CafeDemoActiveMQBackedChannels {

/**
* place some orders
* @param context spring context
* @param count the number of standard orders
*/
public static void order(AbstractApplicationContext context, int count){
Cafe cafe = (Cafe) context.getBean("cafe");
for (int i = 1; i <= count; i++) {
Order order = new Order(i);
order.addItem(DrinkType.LATTE, 2, false);
order.addItem(DrinkType.MOCHA, 3, true);
cafe.placeOrder(order);
}
}

public static void main(String[] args) throws InterruptedException, IOException {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("/META-INF/spring/integration/activemq/cafeDemo-amq-config.xml",
"/META-INF/spring/integration/activemq/cafeDemo-amq-jms-backed.xml");

// comment this out to run the sample without placing any new orders on the queue
order(context, 25);

System.in.read();
context.close();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.springframework.integration.samples.cafe.xml;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.samples.cafe.Cafe;
import org.springframework.integration.samples.cafe.DrinkType;
import org.springframework.integration.samples.cafe.Order;

import java.io.IOException;

/**
* Main class for sending orders that will be handled in separate, distributed
* processes. See the README.md file for more information on the order in which
* to start the processes
*
* @author ceposta
*/
public class CafeDemoAppActiveMQ {

/**
* place some orders
* @param context spring context
* @param count the number of standard orders
*/
public static void order(AbstractApplicationContext context, int count){
Cafe cafe = (Cafe) context.getBean("cafe");
for (int i = 1; i <= count; i++) {
Order order = new Order(i);
order.addItem(DrinkType.LATTE, 2, false);
order.addItem(DrinkType.MOCHA, 3, true);
cafe.placeOrder(order);
}
}

public static void main(String[] args) throws InterruptedException, IOException {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("/META-INF/spring/integration/activemq/cafeDemo-amq-config.xml",
"/META-INF/spring/integration/activemq/cafeDemo-amq-xml.xml");
order(context, 25);
context.close();
}
}
Loading

0 comments on commit a46d0a3

Please sign in to comment.