BlazeDS Data push with Remote Objects
Now a days, BlazeDS is a pretty well known framework for retrieving data for a flex application. It has even been integrated into a recently released package of Spring. It is an open source, scaled down version of Life Cycle Data Services. It doesn’t have all the glamor as LCDS, but its still 100% useful in most applications.
One of the great features it has taken from LCDS is the ability to support data push. Namely, data push with remote objects, which is great. No more having the client continuously call the server to see if there is new data to be shown. The server is the one who lets the client knows via an httpchannel. So now not only do you get to not have to keep polling, checking for data, but you also get to have remote objects integrated into your application.
This tutorial/how-to is going to include both the serverside of this, as well as the flex side of this. Lets start at the server/environment level. I am going to be honest. I did jack this build.xml (ant is not my strong point right now), everything else is good
. So, first things first. You are going to need a server. I suggest tomcat 6.0x, which can be found here.
I suggest the windows installer to make life easier,but pick which ever works for you. After you install that, download blazeDs:
We are only concerned with the war file in there.

BlazeDs war file
You are going to unzip this into your java web project. The files of concern are going to be the xml files in the Flex directory and the web.xml file. Go ahead and open up the web-inf/web.xml just to clean it up. This isn’t necessary but I get picky sometimes. If you want, rename the display-name and description to whatever you want. After that, you can delete the commented out code. It’s not necessary to keep it there.
Next open up the web-inf/flex/service-config.xml file.
First, in your java project, create a directory called ‘Template’, and make a copy of this file there. Rename it server-config-template.xml. On something like this, I feel its good to have a template you edit and have a build script copy it over. One of those “just in case” things. After you copy it over, I hardcoded the localhost:8080/BlazeDsServer for the server.name:server.port/contextroot part. More importantly, you are going to add this to it.
<channel-definition id="my-streaming-amf" class="mx.messaging.channels.StreamingAMFChannel"> <endpoint url="https://localhost:8080/BlazeDsServer/messagebroker/amfsecure/streamingamf" class="flex.messaging.endpoints.StreamingAMFEndpoint" /> <properties> <idle-timeout-minutes>0</idle-timeout-minutes> <max-streaming-clients>10</max-streaming-clients> <server-to-client-heartbeat-millis>5000</server-to-client-heartbeat-millis> <user-agent-settings> <user-agent match-on="MSIE" kickstart-bytes="2048" max-streaming-connections-per-session="3" /> <user-agent match-on="Firefox" kickstart-bytes="2048" max-streaming-connections-per-session="3" /> </user-agent-settings> </properties> </channel-definition>
This is going to add steaming to our service. Pretty straight forward. After you have added that, go ahead and save it. Our service-config-template.xml should look like this now:
<?xml version="1.0" encoding="UTF-8"?> <services-config> <services> <service-include file-path="remoting-config.xml" /> <service-include file-path="proxy-config.xml" /> <service-include file-path="messaging-config.xml" /> </services> <security> <login-command class="flex.messaging.security.TomcatLoginCommand" server="Tomcat"/> </security> <channels> <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel"> <endpoint url="http://localhost:8080/BlazeDsServer/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/> </channel-definition> <channel-definition id="my-secure-amf" class="mx.messaging.channels.SecureAMFChannel"> <endpoint url="https://localhost:8080/BlazeDsServer/messagebroker/amfsecure" class="flex.messaging.endpoints.SecureAMFEndpoint"/> <properties> <add-no-cache-headers>false</add-no-cache-headers> </properties> </channel-definition> <channel-definition id="my-streaming-amf" class="mx.messaging.channels.StreamingAMFChannel"> <endpoint url="https://localhost:8080/BlazeDsServer/messagebroker/amfsecure/streamingamf" class="flex.messaging.endpoints.StreamingAMFEndpoint" /> <properties> <idle-timeout-minutes>0</idle-timeout-minutes> <max-streaming-clients>10</max-streaming-clients> <server-to-client-heartbeat-millis>5000</server-to-client-heartbeat-millis> <user-agent-settings> <user-agent match-on="MSIE" kickstart-bytes="2048" max-streaming-connections-per-session="3" /> <user-agent match-on="Firefox" kickstart-bytes="2048" max-streaming-connections-per-session="3" /> </user-agent-settings> </properties> </channel-definition> <channel-definition id="my-polling-amf" class="mx.messaging.channels.AMFChannel"> <endpoint url="http://localhost:8080/BlazeDsServer/messagebroker/amfpolling" class="flex.messaging.endpoints.AMFEndpoint"/> <properties> <polling-enabled>true</polling-enabled> <polling-interval-seconds>4</polling-interval-seconds> </properties> </channel-definition> </channels> <logging> <target class="flex.messaging.log.ConsoleTarget" level="Error"> <properties> <prefix>[BlazeDS] </prefix> <includeDate>false</includeDate> <includeTime>false</includeTime> <includeLevel>false</includeLevel> <includeCategory>false</includeCategory> </properties> <filters> <pattern>Endpoint.*</pattern> <pattern>Service.*</pattern> <pattern>Configuration</pattern> </filters> </target> </logging> <system> <redeploy> <enabled>false</enabled> </redeploy> </system> </services-config>
Next, open up messaging-config.xml. Now, we are going to create this adapter soon, but lets go ahead and add the reference while we are here. Add the following line to the top but within the service tag.
<adapters> <adapter-definition id="BlazeDsServicePushAdapter" class="com.codeofdoom.BlazeDsServiceAdapter"/> </adapters>
This is going to be the adapter that retrieves the data for us. You are allowed to leave the other adapter in there if you want, but its not necessary.
Next we are going to add our destination. This is what our flex application will be pointing to in order to consume the data. Add this to the messaging-config.xml:
<destination id="BlazeDsServicePush"> <channels> <channel ref="my-streaming-amf" /> </channels> <adapter ref="BlazeDsServicePushAdapter"/> </destination>
Here we give our destination a channel. Our channel was added in our services-config.xml and we are telling our destination to use the my-streaming-amf channel. Next we then tell it to use the adapter we just defined at the top. After you have added, go ahead and save that file.
Since this is a tutorial about remote-objects, we are going to have to create those too. So I created this:
package com.codeofdoom; public class Person { private String firstName; private String lastName; private Integer age; public Person(String firstName, String lastName, Integer age){ this.firstName = firstName; this.lastName = lastName; this.age = age; } public Person(){} public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }
Just a standard pojo and nothing more. We are going to create something similar on the flex side soon, but lets create out service adapter next. Check it out.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | package com.codeofdoom; import java.util.ArrayList; import java.util.List; import java.util.Random; import flex.messaging.MessageBroker; import flex.messaging.messages.AsyncMessage; import flex.messaging.messages.Message; import flex.messaging.services.MessageService; import flex.messaging.services.ServiceAdapter; import flex.messaging.util.UUIDUtils; public class BlazeDsServiceAdapter extends ServiceAdapter { Random random; PersonGenerator thread; public BlazeDsServiceAdapter(){ random = new Random(); System.out.println("Adapter initilized"); } public void start(){ if(thread == null){ System.out.println("Adapter started"); thread = new PersonGenerator(); thread.start(); } } public void stop(){ System.out.println("Adapter stopped"); thread.running = false; thread=null; } private List<Person> generatePersons(){ List<Person> arr = new ArrayList<Person>(); for (int x=0;x<5;x++){ Person p = new Person(); p.setFirstName("FirstPerson"+x); p.setLastName("LastPerson"+x); p.setAge(random.nextInt(80)); arr.add(p); } return arr; } public class PersonGenerator extends Thread { public boolean running = true; public void run(){ String clientId = UUIDUtils.createUUID(); MessageBroker msgBroker = MessageBroker.getMessageBroker(null); while (running){ AsyncMessage msg = new AsyncMessage(); msg.setDestination("BlazeDsServicePush"); msg.setClientId(clientId); List <Person>a= generatePersons(); msg.setMessageId(UUIDUtils.createUUID()); msg.setBody(a); msgBroker.routeMessageToService(msg,null); try{ Thread.sleep(5000); }catch(InterruptedException e){ System.out.println("Exception"); e.printStackTrace(); } } } } @Override public Object invoke(Message msg) { if(msg.getBody().equals("New")){ System.out.println("Adapter received new"); return generatePersons(); }else{ System.out.println("Adapter sending message"); AsyncMessage newMessage = (AsyncMessage)msg; MessageService msgService = (MessageService)getDestination().getService(); msgService.pushMessageToClients(newMessage, true); } return null; } } |
Few key things about this class. First, it extends ServiceAdapter. This is part of the flex messaging service. The part this affects is the invoke method. This is where our messages get sent out to our front end. To see where its getting this data from, look at the PersonGenerator class. This is the thread that is running that will create new data for us every 5 seconds. Most important part of this class is where you are setting the messages destination. Once again, the destination is what our flex side has the open httpservice on.
After that is called and its sent to the message broker, the invoke method picks that up and then fires it off to the front end. So, after that lovely explanation, lets make sure it actually builds and deploys. Right click on the build.xml file and select run as > ant build. It should create a dist directory in your java project, and in there is a war file called BlazeDsServer.war. Once tomcat is running, take that war file and drop it into your webapps directory. You should see a BlazeDsServer directory get created. Also if you look to your logs, you should see something like this, indicated the application has started.

Application starting in tomcat
Now lets setup our flexproject. After creating a standard Flex project, we need to point our flex compile options to point to the services-confg.xml file. If you right click your flex project and go to properties, then flex compiler. Under additional compiler arguments, add this line
-compiler.services “%SERVICES-CONFIG-PATH% \services-config.xml”
Of course, you are going to want to set your %SERVICES-CONFIG-PATH% to whatever directory your file is residing.

Flex Compiler
After that, we need to create our mirrored remote object. All properties must be the same.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package com.codeofdoom.dto { [Bindable] [RemoteClass(alias="com.codeofdoom.Person")] public class Person { private var _firstName:String; private var _lastName:String; private var _age:Number; public function Person(){ } public function get firstName():String{ return _firstName; } public function get lastName():String{ return _lastName; } public function get age():Number{ return _age; } public function set firstName(firstName:String):void{ _firstName = firstName; } public function set lastName(lastName:String):void{ _lastName = lastName; } public function set age(age:Number):void{ _age = age; } } } |
There you go. PLEASE NOTE SOMETHING. I ran into a horrible snag while learning this. Maybe this is a work around, maybe there isn’t, but I ran into horrible problems with this trying to have a constructor with arguments. Normally it would just tell you it expected 3 arguments, got 0. However, in this instance, it swallowed the error and I wouldn’t get my objects back. So PLEASE be careful!. Also you must declare the object as both Bindable and as a RemoteClass, pointing to the fully qualified name (path+classname).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()"> <mx:Script> <![CDATA[ import mx.collections.ArrayCollection; import mx.messaging.messages.IMessage; import mx.messaging.events.MessageAckEvent; import mx.messaging.messages.AsyncMessage; import mx.messaging.events.MessageEvent; import com.codeofdoom.dto.Person; private function init():void{ var message:AsyncMessage = new AsyncMessage(); message.body = "New"; producer.send(message); consumer.subscribe(); } private function onMsg(event:MessageEvent):void{ grid.dataProvider = event.message.body as ArrayCollection; } private function pub():void { var message:AsyncMessage = new AsyncMessage(); message.body = "New"; producer.send(message); } private function ack(event:MessageAckEvent):void{ grid.dataProvider = event.message.body as ArrayCollection; } ]]> </mx:Script> <mx:Producer id="producer" destination="BlazeDsServicePush" acknowledge="ack(event)"/> <mx:Consumer id="consumer" destination="BlazeDsServicePush" message="onMsg(event)"/> <mx:VBox> <mx:DataGrid id="grid"> <mx:columns> <mx:DataGridColumn dataField="firstName" headerText="First Name"/> <mx:DataGridColumn dataField="lastName" headerText="Last Name"/> <mx:DataGridColumn dataField="age" headerText="Age"/> </mx:columns> </mx:DataGrid> </mx:VBox> </mx:Application> |
As for our mxml, its just going to be a simple grid that will display the first name, last name and the age of the person. The key parts are the producer and consumer. Normally we would only need a consumer, but I wanted to put the producer in there for a reason. Lets say that our interval for new data was 5 minutes vs 5 seconds. With our thread running, we might log in 1 second after the last one was fired off. However, we first send have our producer request new data. This is only a 1 time thing in our application, but in a real world situation, you aren’t going to let your customers wait 5 minutes for data.
Both our consumer and our producer are pointed to BlazeDsServicePush. Lastly, our init function fires off. Here we send the service our initial “give me data” message from the producer. Then our consumer subscribes to that destination. After that, you are ready to retrieve data
. Your output should look something like this:

There are many applications where time sensitive data is important to the end user. In this scenario, you have two choices. Have the client continuously poll the server, saying ‘new data yet? New data yet? New data yet?’ OR you can just have the client sitting pretty and just have the back end tell it when the new data is there. If you arent getting data, a good place to check is your tomcat logs. When you start up your flex application, you should see a line that says “Adapter received new”
If you do run into any snagging getting your backend to compile or run or build or whatever, please feel free to leave questions. It can definitely be something tricky. Luckily for you, I have included the source. Enjoy!
Here is the source.
I tried this example.
The only thing I get is a NPE on the message broker instance when
sending the routeMessageToService method. The static method
MessageBroker.getMessageBroker(null), always returns null.