# Spring BlazeDS Integration Test Drive

In this Test Drive, you run a series of short sample applications that demonstrate the key features of Spring BlazeDS Integration. This Test Drive is a continual work in progress and will be updated with each release of the project. Please submit your feedback to the Spring BlazeDS Integration team via the project forum.

These samples have been developed in collaboration between Adobe and SpringSource, with contributions from:

- Christophe Coenraets
- Jeremy Grelle
- Mark Fisher

## Spring Architecture

This version of the Test Drive uses a layered Spring configuration, with the core domain services and supporting infrastructure loaded in a root application context via the ContextLoaderListener, and both the Flex integration and the Spring MVC RESTful @Controllers configured separately via the DispatcherServlet's child application context. This layered approach with explicit separation of concerns is by no means required, but it does have some benefits over a non-layered approach such as opening up the option of writing out-of-container integration tests for the core domain services without having to load the web infrastructure.

## Samples Index

#### Remoting

- Spring BlazeDS Integration 101: The basics
- inSync Contact Management Application: A simple CRUD application built in 6 steps
- RESTful inSync Contact Management Application: An alternate version of inSync app that uses RESTful AMF Spring MVC endpoints instead of BlazeDS Remoting.
- Company Manager: Similar to inSync, but using annotation-based configuration. Also demonstrates object associations.

#### Messaging

- Chat: Messaging basics
- Simple Data Push: A simple data push example
- Traderdesktop: A more sophisticated data push example showing how to use subtopics
- JMS Chat: A chat application using a JMS topic and exchanging messages with a Swing-based client
- POJO Messaging: An example of passing Messages between a Flex client and a server-side POJO using Spring Integration MessageChannels
- Collaboration: A simple example showing how to use messaging to remotely drive another client's application

#### Security

- Security integration 101

## Source code:

This guide assumes you have built and imported all of the Eclipse projects from {Spring BlazeDS Integration Distribution Root}/projects/spring-flex-samples/spring-flex-testdrive (See the reference docs for instructions on building and running the samples)

- The Flex source code is in {project}/src/main/flex/ of each individual flex project
- The Java source code is in testdrive/src/main/java/
- The root Spring configuration (including setup of the core services, security, and supporting infrastructure) is in testdrive/src/main/webapp/WEB-INF/spring/
- The BlazeDS integration support is configured in the 'flex' DispatcherServlet's configuration file (testdrive/src/main/webapp/WEB-INF/flex-servlet.xml)

## Remoting Samples

### Spring BlazeDS Integration 101

#### Run the sample:

1. Click here to run the application
2. Click "Get Data": The DataGrid is populated with data returned by the findAll() method of the ProductDAO Java class.

#### Code walkthrough:

Open main.mxml in the spring-blazeds-101/src/main/flex directory to look at the source code of the client.

Open the following files to look at the source code for the server side of the application:

- testdrive/src/main/webapp/WEB-INF/spring/app-config.xml
- testdrive/src/main/webapp/WEB-INF/flex-servlet.xml
- testdrive/src/main/java/flex/spring/samples/product/ProductDAO.java

Note that in this first sample, we use a simplistic DAO implementation with low level JDBC code and no real abstraction. This was done intentionally to provide a bare-bones example that focuses exclusively on the Spring/BlazeDS Integration plumbing. In all the other examples of this Test Drive, we use the JdbcTemplate abstraction of the Spring framework to build the data access objects.

Using RemoteObject, you can directly invoke methods of Java objects deployed in your application server, and consume the return value. The return value can be a value of a primitive data type, an object, a collection of objects, an object graph, etc.

Using Spring BlazeDS Integration, Spring beans are exposed using the `<flex:remoting-destination />` configuration tag. See the "product" bean definition in app-config.xml and the remoting destination that references it in flex-servlet.xml

Java objects returned by server-side methods are deserialized into either dynamic or typed ActionScript objects. In this example, we don't have an explicit ActionScript version of the Product Java class. Product objects are therefore deserialized into dynamic objects. In InSync03 below, we start working with strongly typed model objects.

### InSync01: Searching Contacts

#### Run the sample:

1. Click here to run the application
2. Click the Search button to retrieve all the contacts in the database
3. Enter a few characters in the Search input field before clicking the Search button in order to search by name

#### Code walkthrough:

Open insync01.mxml in the insync01/src/main/flex directory to look at the source code of the application.

Open the following files to look at the source code for the server side of the application:

- testdrive/src/main/webapp/WEB-INF/spring/app-config.xml
- testdrive/src/main/webapp/WEB-INF/flex-servlet.xml
- testdrive/src/main/java/flex/spring/samples/contact/ContactDAO.java

### InSync02: Using the RemoteObject Events

#### Run the sample:

Click here to run the application

#### Code walkthrough:

Open insync02.mxml in the insync02/src/main/flex directory to look at the source code of the application.

This version is similar to InSync01, but demonstrates how to use the ResultEvent and FaultEvent to have a finer control over RemoteObject calls.

### InSync03: Strong Typing

#### Run the sample:

1. Click here to run the application
2. Click the Search button to retrieve all the contacts in the database
3. Enter a few characters in the Search input field before clicking the Search button to search by name
4. Select a contact in the DataGrid
5. Edit the contact in the Contact form and click "Save" to persist your changes

#### Code walkthrough:

Open insync03.mxml, Contact.as, and ContactForm.mxml in the insync03/src/main/flex directory to look at the source code of the application.

In this version, we work with strongly typed contact objects. The Contact.as class is the ActionScript representation of org.springframework.flex.samples.contact.Contact.java. The [RemoteClass(alias="org.springframework.flex.samples.contact.Contact")] annotation in Contact.as is used to indicate that instances of Contact.as sent to the server should be deserialized as instances of org.springframework.flex.samples.contact.Contact at the server side, and that similarly, instances of org.springframework.flex.samples.contact.Contact retrieved from the server should be deserialized as instances of Contact.as.

### InSync04: Opening Multiple Contacts

#### Run the sample:

1. Click here to run the application
2. Click the Search button to retrieve all the contacts in the database
3. Enter a few characters in the Search input field before clicking the Search button to search by name
4. Double-click a contact in the DataGrid to open it in a separate Tab
5. Edit the contact in the Contact form and click "Save" to persist your changes

#### Code walkthrough:

Open insync04.mxml in the insync04/src/main/flex directory to look at the source code of the application.

### InSync05: Adding New Contacts

#### Run the sample:

1. Click here to run the application
2. Click the Search button to retrieve all the contacts in the database
3. Click the New Contact button
4. Edit the new contact in the Contact form and click "Save" to create the contact

#### Code walkthrough:

Open insync05.mxml and ContactForm.mxml in the insync05/src/main/flex directory to look at the source code of the application.

This version enables the user of the application to add contacts. In ContactForm, we remotely invoke the create() method of ContactDAO when dealing with a new contact, and the update() method when updating an existing contact.

### InSync06: Adding Event Notification for "Loosely Coupled" UI Synchronization

#### Run the sample:

1. Click here to run the application
2. Click the Search button to retrieve all the contacts in the database
3. Enter a few characters in the Search input field before clicking the Search button to search by name
4. Double-click a contact in the DataGrid to open it in a separate Tab
5. Modify the first name or last name of the contact and click "Save". Notice that the DataGrid is updated to reflect your changes.
6. Add a new contact and click "Save" to create the contact. Notice that the contact appears in the DataGrid.
7. Delete a contact and notice that the contact is removed from the DataGrid.

#### Code walkthrough:

Open insync06.mxml, ContactForm.mxml, and ContactEvent.as in the insync06/src/main/flex directory to look at the source code of the application.

In this version, ContactForm dispatches events when a contact has been created, updated, or deleted. Other components of the application can register as listeners to these events to perform a specific task when a contact is created, updated or deleted. In this case, the main application registers as a listener to these events and refreshes the contact DataGrid to make sure it reflects the changes made in ContactForm.

### RESTful inSync: Communicating with Spring MVC REST endpoints using AMF

#### Run the sample (functionally equivalent to inSync06):

1. Click here to run the application
2. Click the Search button to retrieve all the contacts in the database
3. Enter a few characters in the Search input field before clicking the Search button to search by name
4. Double-click a contact in the DataGrid to open it in a separate Tab
5. Modify the first name or last name of the contact and click "Save". Notice that the DataGrid is updated to reflect your changes.
6. Add a new contact and click "Save" to create the contact. Notice that the contact appears in the DataGrid.
7. Delete a contact and notice that the contact is removed from the DataGrid.

#### Code walkthrough:

Open rest.mxml, ContactForm.mxml, ContactEvent.as, and RestInvoker.as in the insync-rest/src/main/flex directory to look at the source code of the application.

Open the following files to look at the source code for the server side of the application:

- testdrive/src/main/webapp/WEB-INF/spring/app-config.xml
- testdrive/src/main/webapp/WEB-INF/flex-servlet.xml
- testdrive/src/main/java/flex/spring/samples/contact/ContactDAO.java
- testdrive/src/main/java/flex/spring/samples/rest/ContactsController.java
- testdrive/src/main/java/flex/spring/samples/rest/HandlerAdapterPostProcessor.java

Just as in inSync06, ContactForm dispatches events when a contact has been created, updated, or deleted. Other components of the application can register as listeners to these events to perform a specific task when a contact is created, updated or deleted. The main application registers as a listener to these events and refreshes the contact DataGrid to make sure it reflects the changes made in ContactForm.

The major difference in this version is that the server side interface consists of RESTful HTTP endpoints, rather than direct RPC interfaces. The RestInvoker object abstracts away the details of communication. It uses URLStream instead of RemoteObject for marshalling data to and from the REST URLs. Note that there are several workarounds due to the Flash player's inability to set the Accept header or to use the PUT and DELETE HTTP methods. These workarounds take advantage of existing Spring MVC facilities such as HiddenHttpMethodFilter and ContentNegotiatingViewResolver.

The RESTful HTTP calls are handled by ContactsController. The results of each request are written back as AMF thanks to the configuration of the AmfView, and the "create" and "update" methods are able to take a Contact as a method parameter thanks to the use of @RequestBody in conjunction with AmfHttpMessageConverter.

### Company Manager

#### Run the sample:

1. Click here to run the application
2. Click the Search button to retrieve all the contacts in the database
3. Enter a few characters in the Search input field before clicking the Search button to search by name

#### Code walkthrough:

Open companymgr.mxml, Company.as, Industry.as, and CompanyForm.mxml in the companymgr/src/main/flex directory to look at the source code of the application.

Open the following files to look at the source code for the server side of the application:

- testdrive/src/main/webapp/WEB-INF/spring/app-config.xml
- testdrive/src/main/webapp/WEB-INF/flex-servlet.xml
- testdrive/src/main/java/flex/spring/samples/company/CompanyDAO.java
- testdrive/src/main/java/flex/spring/samples/company/IndustryDAO.java
- testdrive/src/main/java/flex/spring/samples/company/Company.java
- testdrive/src/main/java/flex/spring/samples/company/Industry.java

Note that the CompanyDAO and IndustryDAO beans are not defined in web-application-config.xml but are configured using annotations (`@Service`, `@RemotingDestination`, `@Autowired`, `@RemotingInclude`, and `@RemotingExclude`). This application is similar to inSync, but demonstrates object associations: the Company class has a property of type Industry.

## Messaging Samples

### Chat

#### Run the sample:

1. Click here to run the application
2. Access the same URL in another browser window to open a second instance of the chat application
3. Type a message in one of the chat clients and click "Send": the message appears in the two chat clients

#### Code walkthrough:

Open chat.mxml in the chat/src/main/flex directory to look at the source code of the application. The Message Service manages a set of destinations that Flex clients can publish and subscribe to. Flex provides two components, Producer and Consumer, that you use to publish and subscribe to a destination. To subscribe to a destination, you use the `subscribe()` method of the Consumer class. When a message is published to a destination that you subscribed to, the `message` event is triggered on the Consumer.

Open testdrive/src/main/webapp/WEB-INF/flex-servlet.xml to look at the message service configuration. The message service is configured using `<flex:message-service />` inside `<flex:message-broker />`. The "chat" destination is configured using `<flex:message-destination id="chat" />`

### Simple Data Push

#### Run the sample

This example demonstrates how to use the message service to push data from the server to the client. At the server-side, a Java component publishes simulated real time values to a message destination. The Flex client subscribes to that destination and displays the values in real time.

1. To start the feed at the server-side, run the Feed Starter application and start the "Simple Feed".
2. Click here to run the client application.
3. Click the Subscribe button. Pushed values appear in the text field. You can click the Unsubscribe button to unsubscribe from the destination.
4. To stop the feed when you are done experimenting with the application, access the Feed Starter application and stop the "Simple Feed".

#### Code walk through

Open simplepush.mxml in the simplepush/src/main/flex directory to look at the source code of the application.

Open the following files in a text editor to look at the source code for the server side of the application:

- testdrive/src/main/java/flex/spring/samples/simplefeed/SimpleFeed.Java
- testdrive/src/main/webapp/WEB-INF/flex-servlet.xml

In SimpleFeed.java, the MessageTemplate class is used to publish messages to the "simple-feed" destination.

### Traderdesktop

#### Run the sample

Traderdesktop is a more sophisticated data push example showing how to use subtopics to selectively subscribe to specific messages. In this case, the user can subscribe to updates for specific stocks only. At the server side, a Java component publishes simulated market data to a messaging destination.

1. To start the feed at the server-side, run the Feed Starter application and start the "Market Feed".
2. Click here to run the client application.
3. To stop the feed when you are done experimenting with the application, access the Feed Starter application and stop the "Market Feed".

#### Code walk through

Open traderdesktop.mxml in the traderdesktop/src/main/flex directory to look at the source code of the application.

Open the following files in a text editor to look at the source code for the server side of the application:

- testdrive/src/main/java/flex/spring/samples/marketfeed/MarketFeed.Java
- testdrive/src/main/webapp/WEB-INF/flex-servlet.xml

### JMS Chat

#### Run the sample:

This application is identical to the regular chat application above. The only difference is the destination: "jms-chat". At the server-side, the "jms-chat" destination is mapped to a JMS topic.

1. Click here to run the application
2. Access the same URL in another browser window to open a second instance of the chat application
3. Type a message in one of the chat clients and click "Send": the message appears in the two chat clients
4. You can also start the Java (Swing) client: Import and execute the Eclipse launch configuration from testdrive/jmschat.launch. This is an axample of how you can exchange messages between Flex and Java apps through JMS topics.

#### Code walkthrough:

Open jmschat.mxml in the jmschat/src/main/flex directory to look at the source code of the application.

Open testdrive/src/main/webapp/WEB-INF/flex-servlet.xml to look at the message service configuration. Note that the "jms-chat" destination is mapped to the "chatTopic" (sampletopic.flex.jms.chat) JMS topic that is configured in testdrive/src/main/webapp/WEB-INF/spring/infrastructure-config.xml. In this application, we use an embedded ActiveMQ message broker configured by the connectionFactory bean. You don't have to start ActiveMQ in a separate process.

### POJO Messaging

#### Run the sample:

This application uses the same frontend as the two chat applications. However, in this case messages are sent between the client and a server-side POJO. There are separate inbound and outbound destinations, and these are mapped to Spring Integration channels.

1. Click here to run the application
2. Type "start" in the text field and click "Send"
3. Incremental values should display in the upper text area every 5 seconds
4. You can send a "stop" message as well or any integer value to set the counter
5. Any other message text will trigger log output in the console

#### Code walkthrough:

Open messaging.mxml in the spring-messaging/src/main/flex directory to look at the source code of the client.

Open testdrive/src/main/webapp/WEB-INF/flex-servlet.xml to look at the message service configuration. Note that the "si-receive" and "si-send" destinations are mapped to the "toFlex" and "fromFlex" Message Channels respectively. Those are configured in testdrive/src/main/webapp/WEB-INF/spring/integration-config.xml. Also, in that configuration file you will see the "inbound-channel-adapter" and "service-activator" Spring Integration components and the "counter" bean definition they reference. The Counter source code is located within testdrive/src/main/java in the "org.springframework.flex.samples.integration" package.

### Collaboration

#### Run the sample:

1. Click here to run the application
2. Access the same URL in another browser window to open a second instance of the chat application
3. Enter some data in one browser and notice that the data appears in the other browser as well.
4. Select another tab in the accordion in one broswer, and notice that the other client's user interface is synchronized accordingly.

#### Code walkthrough:

Open collaboration.mxml in the collaboration/src/main/flex directory to look at the source code of the application.

Open testdrive/src/main/webapp/WEB-INF/flex-servlet.xml to look at the message service configuration.

## Security Samples

### Security Integration 101

#### Run the sample and login as various users to see the effect of the security settings:

1. Click here to run the application
2. Log in (use UserId: john / Password: john), and click "Get Data" again: you should now get the data
3. Expand the "Chat" panel and enter a message. You should see the message published to the main chat window.
4. Log out and then log in as the admin user (use UserId: admin / Password: admin). You should now see an additional column in the table that is conditionally displayed based on the user's permissions.
5. Log out and then log in as the guest user (use UserId: guest / Password: guest). If you click "Get Data" an "Access Denied" error will be displayed as this user does not have sufficient permissions.
6. As the "guest" user, again expand the "Chat" panel and attempt to enter a message. You should receive an error due to not having sufficient permissions.
7. The sample also demonstrates detection of a user that's already been authenticated, and the loading of that user's information. For example, log out and then access http://localhost:8080/testdrive/login.jsp, and logon using john / john. You will then be redirected into the secured sample. Notice that the user information has been populated and you can access data as if you'd logged in through the Flex UI.

#### Code walkthrough:

Open secured.mxml in the secured/src/main/flex directory to look at the source code of the application.

Open the following files in a text editor to look at the the server side configuration:

- testdrive/src/main/webapp/WEB-INF/flex-servlet.xml
- testdrive/src/main/webapp/WEB-INF/spring/security-config.xml
- testdrive/src/main/webapp/WEB-INF/spring/app-config.xml

Note that the "find*" methods of securedProductService are secured in app-config.xml. A basic authentication provider is defined in security-config.xml, and the BlazeDS support is enabled by the `<flex:secured>` tag in flex-servlet.xml.