A Complete Application with RPC Communications...

This is a book excerpt from the book RIch Internet applications with Adobe Flex and Java.

Configuring the Server-Side Destination and Proxy

For security reasons (similar to the Java sandbox concept), Flash clients can only access the domains they come from, unless other servers declare, explicitly or implicitly, trust to SWF files downloaded from our domain by a corresponding record in a crossdomain.xml file. But our portfolio SWF wasn't loaded from finance.yahoo.com, and we aren't allowed to install crossdomain.xml on the Yahoo! servers. We'll use another technique called Flex proxy. When the user clicks on the News link in the data grid, the portfolio client will connect to our FDS Web application deployed under Tomcat (JRun, WebLogic), which will proxy our communication with Yahoo!. To configure the Flex proxy service, use the following section of the proxy-config.xml located in the \WEB-INF\flex directory:

   <destination id="YahooFinancialNews">
     <properties>
       <url>http://finance.yahoo.com/rss/headline</url>
     </properties>
   </destination>

Now Flex will contact http://finance.yahoo.com, get the news for the symbol specified, and return it back to the Flash client.

Processing the News Feed
The HTTPService converts the received data according to the value of the resultFormat property: e4x, flashvars, object (this is default), text, or xml.

If we knew that the results were coming back as name/value pairs concatenated with an ampersand, we could have picked the flashvars format. The text format is suitable for any raw text, but it's not easy to parse. The XML format is maintained for compatibility with pre-E4X versions of the ActionScript, so we'll pass on this one as well. Considering the other formats listed above, for our application, we prefer e4X XML. An e4X expression newsFeed.lastResult.channel.item is all you need to populate the XMLListCollection with news headlines. This XMLListCollection will be used as the dataProvider of the news DataGrid.

As usual, we'll separate the code that merely starts the application from the FinancialNews view ( see Listing 1).

<?xml version="1.0" encoding="utf-8"?>
<!--news1.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" >
     <FinancialNews1 id="fn"/>
</mx:Application>

Our newsFeed will initiate the following request from the creationComplete event:

     newsFeed.send({s:"ADBE"});

As part of the send method, Flex converts the object's property into a GET URL parameter using the object's properties as parameter names. Here s:"ADBE" will be concatenated in the form of "?s=ADBE" to the http://finance.yahoo.com/rss/headline specified by the news destination. Since RSS data can be verbose, we'll set the relevant columns of the grid with wordWrap="true" and the height of the Grid row to be flexible:
variableRowHeight="true".

Introducing Item Renderers
To make the data grid's column Link open a news story in a separate browser window, we need to customize the way of displaying (rendering) the cells of this column. We will use the so-called itemRenderer in the <mx:DataGridColumn> tag (see more samples of using item renderers in Chapters 8 and 9). There are two major kinds of item renderers:

•  drop-in, which is an ActionScript class that you specify as the value of the itemRenderer of any list-derived control.

•  inline, where you use an <mx:Component> tag to define a renderer component inside the <mx:itemRenderer> element.

To create an inline renderer, we'd need to change:

<mx:DataGridColumn headerText="Link" width="130" dataField="link" wordWrap="true"/>

into the following code:

<mx:DataGridColumn headerText="Link" width="130">
   <mx:itemRenderer>
     <mx:Component>
       <mx:LinkButton label="{data.link}" click="navigateToURL(new
         URLRequest(data.link), '_blank')"/>
     </mx:Component>
   </mx:itemRenderer>
</mx:DataGridColumn>

The ActionScript function flash.net.navigateToURL opens or replaces a window in the Flash Player's container application - opens it, in our case, in a blank browser.

While inline renderers excel in readability, drop-in renderers are reusable. If you expect to have links with similar presentation and functionality you may decide to create a class out of it.

Let us introduce the write-only security property for the FinancialView2 class. Please note that we provide a setter method to send a newsFeed request every time the security (stock symbol) is updated:

public function set security(value:String):void {
     newsFeed.send({s:value});
}


A bit later in this chapter, the value of the selected security will be passed to the news data grid based on the selected row in the portfolio data grid or the selected slice of the pie. At this point let's remove the creationComplete event handler in FinancialNews and hard-code the stock symbol ADBE as a valve of security for the FinancialNews2 tag:

<?xml version="1.0" encoding="utf-8"?>
<!--news2.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" >
     <FinancialNews2 id="fn" security="ADBE"/>
</mx:Application>

The FinancialNews2 tag is spelled out in Listing 2. Another minor modification in Listing 2 is that the XML received with Yahoo! Financial news is now a source property of the <mx:XMLListCollection>. The data grid's dataProvider is populated from this collection. You don't have to use a collection as the middleman between the data and the GUI component, but it does become handy for customization. In particular you can apply a sort or set a filter on the collection.

Programming Master-Detail Relationships
It's time to start thinking about connecting the portfolio and news data grids, which represent typical master-detail relationships. The user selects one security in the grid or the pie, and the news data grid has to be repopulated with potentially multiple rows representing the latest financial news on selected security. Or, technically speaking, we are planning to convert the line:

<FinancialNews2 id="fn" security="ADBE"/>

into a security bound to portfolioView.selectedSecurity. So in the scripting section of PorfolioView5.mxml we'll declare a bindable variable selectedSecurity:

[Bindable]
public var selectedSecurity:String;

The metatag [Bindable] provides an elegant two-line solution for our master-detail parameter passing. The tag PortfolioView5 will go by the ID pv, hence a simple {pv.selectedSecurity} represents the value of this bindable property (see Listing 3).

To be precise, the curly braces denote binding between the FinancialNews2.security, the target of the binding, and the Portfolio5.selectedSecurity as the binding source.

Here is the short explanation of how it works. When Flex compiles PortfolioView5.mxml with the bindable selectedSecurity (see Listing 4), it will produce code that dispatches an event on every change of that property. Then, while compiling our application, Flex will notice that FinancialNews2.security depends on the binding expression. But the expression, in turn, depends on the value of PortfolioView5.selectedSecurity, doesn't it? Accordingly, Flex will add a listener to the change event associated with pv.selectedSecurity. The task of this listener will be to keep the expression recalculated at every change of PortfolioView5.selectedSecurity. Following the same logic, Flex will keep FinancialNews2.security recalculated on every change of the expression. You can read more about binding in the Flex documentation.

Our application keeps the Portfolio on top of the financial news in a vertical box. To facilitate resizing between the two parts, we've used the VDividedBox container instead of the VBox because it has a divider between the parts (similar to Java Swing split panes).

Each click on a wedge of the pieChart will generate an itemClick event (the sole parameter of this event will be of type CharItemEvent) that will include the attribute event.hitData.item corresponding to the selected item (an XML object) in the underlying data provider. That's why, to populate the variable selectedSecurity we can write:

<mx:PieChart id="portfolioPie" itemClick="selectedSecurity=event.hitData.item.Symbol ..."/>

In the case of the DataGrid, we'll be intercepting the change event, which is dispatched when the selectedIndex or selectedItem property changes as a result of the user's actions. Note the selectable="true" in Listing 4. This is done to enable highlighting of the selected row.

The following fragment from PortfolioView5.mxml shows the changes/additions that we've made to PortfolioView4. A complete listing is included with the source code in the book samples.

Finally, to add a visual effect of the selected security in the pie we will explode the clicked wedge a bit more (see Figure 1 and Listing 5).

This concludes our series of Stock Portfolio applications based on Flex remoting.

Adding the JMS Feed to the Stock Portfolio
Now will reuse the POJO that we used to remote to - Portfolio.java see Listing 6 from Part 1 (CFDJ, Vol. 9 issue 5). This time, however, we will invoke it from inside a Java program, which will publish the quotes to a topic available to the Flex application. But first, let's take a look at the Java techniques we will be relying on.

Introduction to the Java Naming and Directory Interface
The Flex applications in the second part of our chapter will be subscribing to the messages published to a certain destination by the JMS-based Java program; hence the Flex Data Services have to be able to find the proper destination. In the Java world, the location of the objects is facilitated by JNDI, which exposes and locates objects via their names. JNDI decouples the physical implementation of the naming services from the client API.

JNDI has one or more contexts, which comprise a naming tree similar to directories/sub-directories in a PC file system. The "root directory" in JNDI vocabulary is called the initial context. The Tomcat server that we will use in our illustration supports it own JNDI tree. So does the ActiveMQ implementation of the JMS that we will use to complement Tomcat. (When this was written ActiveMQ was available under the Apache 2.0 license at www.activemq.org/.)

Let's consider an example that shows how to obtain and use the appropriate naming context.

A client program JndiExample creates an instance of the InitialContext class passing it hard-coded properties relevant to the specific JNDI provider. In particular, the settings of tcp://localhost:61616 as the value of PROVIDER_URL and ActiveMQInitialContextFactory as the value of the INITIAL_CONTEXT_FACTORY are unique to ActiveMQ. (There is an alternative technique for keeping these settings in the jndi.properties on the execution classpath, but it is entirely up to the JNDI provider to make use of this file.) (see Listing 6).

In this program we assume that the ActiveMQ creates the JNDI tree and binds TopicConnectionFactory some time prior to the name lookup. Your program also can programmatically bind the object to the JNDI tree, provided you have enough access privileges to run the following line of code:

     ctx.bind(someName, someObject);

This concludes our short introduction to JNDI, but you can find a more detailed JNDI tutorial at http://java.sun.com/products/jndi/tutorial.


Introduction to the Java Messaging Service
People are sending messages to each other via e-mail and applications can send messages to each other using Message-Oriented-Middleware (MOM). One of the major advantages of MOM is that it provides asynchronous communication between the applications. It's somewhat similar to e-mail operations - you don't have to be online when someone sends you a message - you can read it later.

JMS is the standard API to work with MOM. JMS does not transport messages. JMS-to-MOM is the same as JDBC-to-a-database management system. Java applications could use the same JMS classes with any MOM vendor.

Two Modes of Message Delivery
A program could either send a message to the queue or publish a message to the topic. The first scenario is called Point-to-Point (P2P) messaging. In this mode a message is deleted from the queue as soon as it is successfully received. The second scenario is called Publish/Subscribe (Pub/Sub) messaging. With Pub/Sub many recipients can get the same message as long as they stay subscribed to it.

Here we'll use the Pub/Sub mode for publishing the stock quotes. Do we need to persist our messages so the subscribers who are not online at the moment can eventually get them? Apparently not, since it does not make sense to store the price of MSFT as of 11:53:59a.m. and show it an hour later when the subscriber decides to go online. So our subscribers (and topics) will be non-durable. Do we need to guarantee the successful delivery of each and every quote, given their frequency? Again, the answer is, most likely, no. So our publishing will not be transacted.

JMS Classes and Terms
Below are the names and a short description of the relevant JMS classes:

Types of Messages
Every message created by the JMS provider contains a header, a body (aka payload), and properties. The header contains standard message identification such as message ID, destination, etc. Properties and body are optional.

In a typical scenario, properties - name/value pairs - can be used as a "mark" to filter messages by business purpose. Accordingly, body is best suited to deliver the content. JMS offers the following message types:

When you're configuring Flex messaging destinations specific to JMS, keep in mind that at the time of writting, Flex only supported TextMessage and ObjectMessage types.

How to Publish a Message
Programs publish messages to topics. For a given topic, multiple subscribers can get messages published in a "one-to-many" mode (as opposed to "one-to-someone" mode for a queue).

The snippet of code in Listing 7 illustrates the steps that will be included in our TickerFeed Java program: look up the topic factory, create the topic connection, session, and publisher and, finally, publish a serialized object:

How to Subscribe for a Topic
In our scenario, the Java TickerFeed program will do the publishing and the Flex application, via the mx:Consumer tag, will act as the subscriber. The code in the section, therefore, is purely educational. And yet, you may find it useful, particularly to unit-test your publisher without leaving the confines of the Java side of the wire.

Subscribers can be durable and non-durable. A durable topic subscriber gets all of the messages sent to a destination, including those sent while the consumer is inactive. A non-durable message consumer gets messages from its chosen destination only if the messages are available while the consumer is active. This mode is similar to the way the chat rooms operate - you must be online to get the messages. Please be aware that you cannot possibly create a durable subscriber on the non-durable transport. In the case of Flex, you'd have to declare your messaging destination (more on that later in this chapter) as durable.

The code snippet in Listing 8 creates a non-durable subscriber.

Now that we've touched on the subject of JMS, let's look at the integration of JMS and native Flex messaging.

Integrating Flex and Java Messaging Services
Flex provides a Messaging Service of its own, which enables messaging between many clients via a Flex server component. Unlike JMS, Flex Messaging Services are not simply an API, but a full implementation as well. Flex Messaging Services in and of itself are completely sufficient to establish messaging between clients in your enterprise application. Flex Messaging integrates with external messaging via an adapter architecture. In particular, Flex provides a specific adapter class for JMS. This adapter acts as a middleman between the two messaging components, translating message flows from the Java destinations to Flex ones and vice versa.

An important point here is that Flex and Java have separate message destinations. The mapping between the Flex destinations and external messaging destinations has to be configured in the XML configuration file (under the default configuration scenario - WEB-INF/flex/messaging-config.xml). Figure 2 shows an integration between Flex and Java Messaging using a JMS adapter.

Flex clients can connect to servers using different transport protocols: the Real-Time Messaging Protocol (RTMP) and the Action Message Format (AMF) that runs over HTTP (you'd need polling in the latter case). When you configure a destination in the messaging-config.xml, you can specify more than one channel and Flex will try to access the destination using the protocols in the order specified. We'd like to emphasize that Flex clients just need to know the names of the FDS destinations. They are decoupled from MOM servers and JMS names. All features of the Flex messaging are described in the Flex manual called the Flex Developer's Guide. Now we'll get back to our stock portfolio application, but this time we'll make it JMS-enabled.


Configuring Flex Messaging Destination
Let's start by configuring the topic on the Flex side. We will modify the file messaging-config.xml in /WEB-INF/flex, and create the destination for the "ticker-topic-jms" as in Listing 9. Please note the difference between the destination ID "ticker-topic-jms," which will be used by the Flex client, and the jndi-name "ticker," which the Flex JMS adapter will use for look up in the JNDI tree. The middleman subscriber created by the Flex JMS adapter won't be durable; it's okay to lose the quote if you aren't online.

Note the channel tags. The RTMP channel is listed first, and the AMF polling is the second option. This means the following: try the push first, but if it doesn't work (because of firewalls), start polling.

Configuring ActiveMQ JMS
There are different ways to start ActiveMQ. For purposes of this chapter it's convenient to start ActiveMQ with the same process that's running the Tomcat when the Web application starts. Accordingly, we use a Web application context listener and start the ActiveMQ broker from the contextInitialized() method:

public void contextInitialized(ServletContextEvent arg0) {
     try{
       broker.addConnector("tcp://localhost:61616?trace=true");
       broker.start();
     }catch(Exception e){
       e.printStackTrace();
       throw new RuntimeException(e);
     }
   }

Naturally, we have to guarantee the availability of the ActiveMQ classes on the Web application class path. To that end we dropped activemq-4.0-M4.jar into the common/lib folder off the Tomcat root. Listing 10 is the application listener.

To register the listener with the Web application we modify the web.xml file and add the following XML snippet (according to the DTD it should go right after the filter mappings. If your app does not have a filter, the placement is right after the application context parameters):

<listener>
     <listener-class>com.theriabook.jms.ActiveMQBrokerListener</listener-class>
</listener>

Writing the TickerFeed Java Program
In our data feeding program the quotes will be published to a JMS topic, but we are still going to reuse the class Porfolio.java, which we used to pull quotes via the RemoteObject. When it comes to sending the message, we will be putting the return of the Portofolio getQuotes() method into the serializable QuotesHolder:

      Portfolio port = new Portfolio();
      . . . .
      StockQuoteDTO[] quotes = port.getQuotes();
      QuotesHolder holder = new QuotesHolder();

The listing for the QuotesHolder class is below:

package com.theriabook.jms;
import java.io.Serializable;
import com.theriabook.jms.dto.StockQuoteDTO;

public class QuotesHolder implements Serializable{
     private static final long serialVersionUID = -8823588238987890758L;
     public StockQuoteDTO[] quotes;
}

To avoid hard-coding the JNDI properties in the TickerFeed program, we will make sure that the file jndi.properties as shown in Listing 11 belongs to the application classpath.

Now we're ready to complete our TickerFeed.java program. It continuously publishes the QuotesHolder objects to the JMS topic called "ticker." On your console you should see output similar to this one:

Publishing quotes...
Publishing quotes...

The complete code for TickerFeed.java is in Listing 12

Modifying the Flex Client to Consume Messages
The final part is to make changes to the Flex client. We will use the last version of PortfolioView from the remoting series and make the following modifications.

First, we will replace the <mx:RemoteObject> tag with the following <mx:Consumer> tag:

<mx:Consumer id="consumer" destination="ticker-topic-jms" message="applyQuotes(event.message.body.quotes)" />

This is an example of decoupling the application components. If you need to change the MOM provider, or you decide to use message queues instead of topics, no code modification is needed. Just change the destination parameter and you're set.

The second change is to actually start consuming messages. The modified startQuotes will look as follows:

private function startQuotes():void{
     consumer.subscribe();
}

The third and last change is in the processFault method, due to the differences in mx.messaging.events.ChannelFaultEvent instead of mx.rpc.events.FaultEvent:

   private function processFault(evt:ChannelFaultEvent):void{
       errorText = "Server Error";
       errorTip = evt.faultDetail;
       startQuotes();
     }

In all other respects the JMS code specific to the PortfolioView is the same as in its remoting counterpart (see Listing 13).

Summary
In this excerpt we went through different ways of establishing RPC communications between Flex and Java. In particular, we've been using RemoteObject, HTTPService, and Flex JMS adapters to establish communications.

© 2008 SYS-CON Media