Course registration workflow components

Một phần của tài liệu Manning spring roo in action (Trang 381 - 389)

Before you can start creating the workflow components required for implementing the use case, you first need to set up the Spring Integration flow.

14.5.1 Spring Integration flow setup

Let’s create a new project to see how the add-on sets up a Spring Integration project.

Change your directory to a new folder called coursemanager-spring-int and run the following command to set up the project:

integration project --name coursemanager-spring-int --rootDomain ➥

org.rooinaction.coursemanager

This creates a new project called coursemanager-spring-int that’s similar to how Roo creates a new Java project when you run the project command.

You can now type integration flow and press TAB twice to see what command options are available. It will show the following output on the command shell window:

integration flow read integration flow start

Because you didn’t create an existing Spring Integration flow yet, you need to use the start option with the integration flow command:

roo> integration flow start --name course-mgmt-int

The output should say

Started new flow: course-mgmt-int

If you want to edit an existing Spring Integration workflow, use the command integration flow edit, specifying the name of the flow, as this example shows:

roo> integration flow edit --name course-mgmt-int

The output will say that the flow is ready for edits:

Flow 'course-mgmt-int' is ready for modification

To see all of the available Spring Integration commands at this time, you can press TAB twice and it will display the following list of commands:

coursemanager-spring-int[course-mgmt-int] roo>

aggregate enrich filter produce route ➥

send service

stop transform validate

349 Course registration workflow components

As you can see in the previous output example, there are several commands to create the different Spring Integration components that you need in your use case.

Note that the available commands are context sensitive, meaning that you see only the commands that are relevant to the Spring Integration component that’s currently in focus.

Another interesting feature to note is that the new add-on has support for main­

taining the state of the project between Roo restarts.

14.5.2 Configuring Spring Integration components

Now that the base Spring Integration flow is set up, you’re ready to start adding the integration components you need to implement the course registration use case requirements. These components include the following:

 Input channel adapter (message queue)

 Transformer

 Router

 Output channel adapter

Let’s look at how to implement each of these components using Roo commands. First, start with the input channel adapter, which is based on a JMS queue. Post the course reg­

istration details to the message queue and the channel adapter helps with receiving the message from the queue for further processing in the subsequent steps of the workflow.

INPUT CHANNEL ADAPTER

The input channel adapter in this case is acting as a producer, so you need to run the produce command to set up the adapter component. Type produce and press TAB twice to see the available options for the produce command. If you do this a couple of times, you’ll see the command for setting up the channel adapter. Here’s the example of this command:

coursemanager-spring-int[course-mgmt-int] roo> produce via ➥

channel-adapter

As you can see from the output in the following listing, a number of different adapter options are available, from ftp, jdbc, and jms to some new adapters that were added in recent releases of Roo, such as twitter and xmpp.

Listing 14.5 Variations of produce command for creating channel adapter component produce via channel-adapter bean produce via channel-adapter event

produce via channel-adapter feed produce via channel-adapter file produce via channel-adapter ftp produce via channel-adapter http produce via channel-adapter jdbc produce via channel-adapter jms produce via channel-adapter mail produce via channel-adapter sftp produce via channel-adapter tcp produce via channel-adapter ➥

twitter

produce via channel-adapter udp produce via channel-adapter xmpp

You’ll use the jms option for your requirements. Here’s the full command to config- ure the JMS channel adapter:

coursemanager-spring-int[course-mgmt-int] roo> produce via channel-adapter jms

You can now use the previously mentioned focus command to switch to a specific component in the workflow. Let’s run the focus command with the --name parameter to see the list of different components available. Here’s the output of this command:

channel_fffa channel_valueA channel_valueB ➥

inbound-adapter_e57b

The channel adapter’s ID is inbound-adapter_e57b. You can now use the focus com- mand with the component ID to switch the focus to the inbound channel adapter.

After running the focus command, if you press TAB twice, it will display the list of available commands:

coursemanager-spring-int[course-mgmt-int] ...inbound-adapter_e57b roo>

aggregate config diagram enrich filter focus

produce route send

service stop transform validate TRANSFORMER

One of the commands listed is transform, which can be used to define a transformer component in the workflow. It’s useful for data transformation requirements. Let’s run the transform command, which creates a data transformer and sets the focus to this new component. Here’s output of the command after a transformer component has been added to the workflow:

coursemanager-spring-int[course-mgmt-int] ...trnsfmr_6054 roo>

aggregate config diagram enrich filter

focus produce

route send service stop transform

validate

Another command that’s available is the diagram command, which you can use for viewing Spring Integration workflow details, such as what Spring Integration compo- nents are defined and assembled so far in your use case. Type the diagram command and press Enter. The output of the diagram command showing the FLOW details with the channel adapter, message channel, and transformer components is shown here:

========================================

FLOW: -> inbound-adapter_e496(JMS) -> channel_6054 -> trnsfmr_6054

========================================

You only have two components defined so far in the process, so the diagram doesn’t have a lot of components. You’ll run this command again later in this section after cre- ating all of the components to show how the FLOW diagram will look after all of the workflow components are in place.

ROUTER

The next workflow component you need to define is a router that can be used to send the incoming messages to different steps in the process based on the predefined

351 Course registration workflow components

business rules. The command to define a router component is route. After you create the router component, you can run another command, validate, to perform a vali­

dation of the Spring Integration flow you’ve created so far. Here’s the output of the validate command:

Validating Flow: course-mgmt-int

The last component you’ll create for your use case is the output channel adapter. It’ll send the email notifications to customers after performing all of the steps in the course registration workflow.

OUTPUT CHANNEL ADAPTER

Similar to the produce command you used earlier in this section to create an inbound adapter, now you’ll run the send command to define the outbound channel adapter.

You’ll also specify that you need an email-based adapter by including the mail param­

eter in the send command. Here’s the command for defining the output channel adapter component:

coursemanager-spring-int[course-mgmt-int] ...router_9a29 roo> send via ➥

adapter mail --name course-reg-email

When the final workflow component has been defined, you can run the diagram com­

mand one more time to see the final version of the Spring Integration flow details.

Here’s the command output:

========================================

FLOW: -> inbound-adapter_302d(JMS) -> channel_302d -> ➥

trnsfmr_33b4 -> channel_9a29 -> router_9a29(HVR)[channel_valueB, channel_valueA] -> channel_course-reg-email -> course-reg-email(MAIL) FLOW: -> channel_valueA

FLOW: -> channel_valueB

========================================

coursemanager-spring-int[course-mgmt-int] ...course-reg-email roo>

Also, when you’re finished creating and configuring all of the Spring Integration com­

ponents you need for your use case, you can run the stop command to exit the course-mgmt-int workflow.

14.5.3 Spring Integration configuration details

Let’s add the Spring configuration file and Maven dependencies to test the Spring Integration components.

First you start with the Spring configuration file. The following listing shows the contents of the applicationContext-integration.xml file.

Listing 14.6 Configuration details for JMS components in course registration use case

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:integration="http://www.springframework.org/schema/integration"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration

http://www.springframework.org/schema/integration/ ➥

spring-integration.xsd">

<bean id="connectionFactory" class="org.springframework.jms. ➥

connection.CachingConnectionFactory">

<property name="targetConnectionFactory">

<bean class="org.apache.activemq. ➥

ActiveMQConnectionFactory">

<property name="brokerURL" value="vm://localhost"/>

</bean>

</property>

<property name="sessionCacheSize" value="10"/>

<property name="cacheProducers" value="false"/>

</bean>

<bean id="courseRegistrationRequestQueue" class="org.apache. ➥

activemq.command.ActiveMQQueue">

<constructor-arg value="jms.queue. ➥

CourseRegistrationRequestQueue"/>

</bean>

<integration:poller id="poller" default="true" fixed-delay="1000"/>

</beans>

This configuration file defines the JMS queue-related Spring beans using the ActiveMQ server as the messaging container. A second configuration file, coursemanager-spring­

int-config.xml, contains the Spring bean configuration for the integration compo­

nents. This is shown in the following listing.

Listing 14.7 Spring configuration for course registration workflow components

<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/integration"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:beans="http://www.springframework.org/schema/beans"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:jms="http://www.springframework.org/schema/integration/jms"

xmlns:jmx="http://www.springframework.org/schema/integration/jmx"

xmlns:stream="http://www.springframework.org/schema/➥

integration/stream"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/➥

spring-context.xsd

http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/➥

spring-integration.xsd

http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/➥

spring-integration-jms.xsd

http://www.springframework.org/schema/integration/jmx http://www.springframework.org/schema/integration/jmx/➥

spring-integration-jmx.xsd

353 Course registration workflow components

http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/➥

spring-integration-stream.xsd">

<!-- Test Outbound Adapter for Unit Testing -->

<channel id="stdinToJmsoutChannel"/>

<stream:stdin-channel-adapter id="stdin" ➥

channel="stdinToJmsoutChannel"/>

<jms:outbound-channel-adapter id="jmsout"

channel="stdinToJmsoutChannel"

destination="courseRegistrationRequestQueue"/>

<!-- Inbound Adapter -->

<jms:message-driven-channel-adapter id="coursemanager-jms-input-adapter"

destination="courseRegistrationRequestQueue"

channel="jmsInToTransformerChannel"/>

<channel id="jmsInToTransformerChannel"/>

<!-- Transformer -->

<transformer input-channel="jmsInToTransformerChannel"

output-channel="transformerToRouterChannel"

expression="payload.toUpperCase() + '- [' + ➥

T(java.lang.System).currentTimeMillis() + ']'"/>

<channel id="transformerToRouterChannel"/>

<recipient-list-router id="coursemanager-router" input-channel=➥

"transformerToRouterChannel">

<recipient channel="jmsinToStdoutChannel"

selector-expression=➥

"payload.contains('12345')"/>

<recipient channel="jmsinToWaitListChannel" ➥

selector-expression="payload.contains('99999')"/>

</recipient-list-router>

<channel id="jmsinToStdoutChannel"/>

<channel id="jmsinToWaitListChannel"/>

<stream:stdout-channel-adapter id="courseRegSuccess" ➥

channel="jmsinToStdoutChannel" append-newline="true"/>

<stream:stdout-channel-adapter id="courseRegWaitList" ➥

channel="jmsinToWaitListChannel" append-newline="true"/>

<!-- Mail Output Channel Adapter -->

<!-- replace 'userid and 'password' wit the real values -->

<mail:inbound-channel-adapter id="pop3ShouldDeleteTrue"

store-uri="pop3://[userid]:[password]@pop.gmail.com/INBOX"

channel="routerToOutputAdapterChannel"

should-delete-messages="true"

auto-startup="true"

java-mail-properties="javaMailProperties">

<poller fixed-rate="20000"/>

</mail:inbound-channel-adapter>

<util:properties id="javaMailProperties">

<beans:prop key="mail.pop3.socketFactory.fallback">

false</beans:prop>

<beans:prop key="mail.debug">true</beans:prop>

<beans:prop key="mail.pop3.port">995</beans:prop>

<beans:prop key="mail.pop3.socketFactory.class">

javax.net.ssl.SSLSocketFactory</beans:prop>

<beans:prop key="mail.pop3.socketFactory.port">

995</beans:prop>

</util:properties>

</beans:beans>

There are some additional Maven build dependencies for the Spring Integration classes. These dependencies are shown in the next listing. We’re using Spring Integra­

tion framework version 2.0.5 in this code example. The version is specified as

<spring.integration.version>2.0.5.RELEASE</spring.integration.version> in the Maven pom.xml file.

Listing 14.8 Maven build dependencies for Spring Integration

<!-- Spring Integration Dependencies -->

<dependency>

<groupId>org.apache.activemq</groupId>

<artifactId>activemq-core</artifactId>

<version>${activemq.version}</version>

</dependency>

<dependency>

<groupId>org.springframework.integration</groupId>

<artifactId>spring-integration-jms</artifactId>

<version>${spring.integration.version}</version>

</dependency>

<dependency>

<groupId>org.springframework.integration</groupId>

<artifactId>spring-integration-jmx</artifactId>

<version>${spring.integration.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-jms</artifactId>

<version>${spring.version}</version>

<scope>compile</scope>

</dependency>

<dependency>

<groupId>org.springframework.integration</groupId>

<artifactId>spring-integration-core</artifactId>

<version>${spring.integration.version}</version>

</dependency>

<dependency>

<groupId>org.springframework.integration</groupId>

<artifactId>spring-integration-stream</artifactId>

<version>${spring.integration.version}</version>

</dependency>

<dependency>

<groupId>org.springframework.integration</groupId>

355 Course registration workflow components

<artifactId>spring-integration-mail</artifactId>

<version>${spring.integration.version}</version>

</dependency>

14.5.4 Testing Spring Integration flow

To test the course registration use case with Spring Integration, you’ll write a test cli­

ent class called CourseRegistrationSpringIntegrationTestClient. Because most of the workflow details are captured in the configuration file, all you need to do in the test client is to post a course registration request message to the JMS queue‚ course- RegistrationRequestQueue. To make it easier to test, use the stream support pro­

vided by the Spring Integration framework. Instead of writing the code to create and post a message to the JMS queue, use a stdout-channel-adapter component, which allows you to type in the course registration test message at the console to trigger the course registration workflow. The following listing shows the test client class.

Listing 14.9 Test client for testing course registration with Spring Integration

package org.rooinaction.coursemanager.integration;

import java.io.File;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.springframework.context.support.➥

ClassPathXmlApplicationContext;

/**

* @author *

* Test Data:

* Successful Registration Text Message:

* Test Course Registration # 12345 *

* Waitlist Registration Text Message:

* Test Course Registration # - 99999 *

*/

public class CourseRegistrationSpringIntegrationTestClient { private static final Log log = LogFactory.➥

getLog(CourseRegistrationSpringIntegrationTestClient.class);

private final static String[] configFiles = { "/META-INF/spring/integration/➥

applicationContext-integration.xml",

"/META-INF/spring/integration/coursemanager-spring-int-config.xml"

};

public static void main(String[] args) {

CourseRegistrationSpringIntegrationTestClient client = ➥

new CourseRegistrationSpringIntegrationTestClient();

client.verifyThatCourseRegistrationIsSuccessful();

}

public void verifyThatCourseRegistrationIsSuccessful() { log.debug("verifyThatCourseRegistrationIsSuccessful() ➥

method is called.");

log.debug("Cleaning up the ActiveMQ Test Data.");

File tmpDirAMQ = new File("activemq-data");

cleanupActiveMQDatabase(tmpDirAMQ);

log.debug("Loading Spring Application Context.");

new ClassPathXmlApplicationContext(configFiles, ➥

CourseRegistrationSpringIntegrationTest.class);

log.debug("[For testing purposes, Successful Registration ➥

message should contain " +

"the number 12345 and the Waitlist should ➥

contain 99999].");

System.out.println("Type the Course Registration Test ➥

Message and press the Enter key.");

}

private void cleanupActiveMQDatabase(File dirAMQ) { if (dirAMQ.exists()) {

String[] children = dirAMQ.list();

if (children != null) {

for (int i = 0; i < children.length; i++) { cleanupActiveMQDatabase(new File(dirAMQ, ➥

children[i]));

} } }

dirAMQ.delete();

} }

Một phần của tài liệu Manning spring roo in action (Trang 381 - 389)

Tải bản đầy đủ (PDF)

(406 trang)