Sunday, July 19, 2009

Integrate Adobe Flex and JBOSS using BlazeDS - Part I

In this tutorial I will give you step by step instructions on how to integrate Adobe Flex and JBOSS using BlazeDS.
Although in this tutorial I am addressing BlazeDS, the steps in this tutorial should also apply to Adobe Flex LiveCycle Data Services. The only difference are the jars that you copy to your WEB-INF/lib directory. For those who want to integrate BlazeDS with Struts 2, the instructions in this tutorial should also be helpful.

In the Java Backend:

Step 1

Download blazeds.war from http://opensource.adobe.com/wiki/display/blazeds/Downloads

Step 2

Unzip blazeds.war. Copy the files in WEB-INF/lib and WEB-INF/flex to your web project under the same path in your web app.

Step 3

Edit web.xml and add the following lines:

<!-- Http Flex Session attribute and binding listener support -->
<listener>
<listener-class>flex.messaging.HttpFlexSession</listener-class>
</listener>

<!-- MessageBroker Servlet -->
<servlet>
<servlet-name>MessageBrokerServlet</servlet-name>
<display-name>MessageBrokerServlet</display-name>
<servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
<init-param>
<param-name>services.configuration.file</param-name>
<param-value>/WEB-INF/flex/services-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>MessageBrokerServlet</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>


Step 4

Create a simple java class with a simple method that we will invoke from Adobe Flex:

package uk.co.spltech.remote;

import java.util.ArrayList;
import java.util.List;

/**
* This remote service is called using BlazeDS/LiveCycle DS from Flex
*
* @author Armindo Cachada
*
*/
public class RemoteService {
/**
* I am not doing anything useful except to just show that I can be invoked remotely
* from Adobe Flex using RemoteObject.
*
*/
public List<String> callMe() {
System.out.println("I am being invoked!");
List<String> result = new ArrayList<String>();
result.add("Michael Jackson");
result.add("Beatles");
result.add("Tina Turner");
return result;
}
}

Step 5

Create a new destination in remoting-config.xml:

<destination id="remoteService" >
<properties>
<source>uk.co.spltech.remote.RemoteService</source>
<scope>application</scope>
</properties>
</destination>


The source of the destination can be a fully qualified class name, a jndi reference or a spring bean. We will discuss that in a later post. For this example we just specify a class name.

The scope of the destination can be one of:
  • application - there is only one instance of the class for the entire application(i.e. global in atg, singleton in spring)

  • session - there is one instance per user session

  • request - for each http request a new instance of the class is created

In Adobe Flex:

Step 1

Create a new project in Adobe Flex. Please make sure that the Application Server type is set to none.
Why? Fair question to ask since most instructions say to do exactly the opposite. I found those instructions not really helpful in the case of JBOSS since they assume I can provide the directory containing the application after it is deployed to JBOSS. That works quite well for tomcat because it simply extracts the war file under webapps. The path is always the same. In the case of JBOSS the path to the application changes after each deployment...

Step 2

The only reason Adobe Flex asks you for the path to the root folder of your web application is so that it can provide two arguments to the flex compiler:

  • services - The path to the Adobe flex data services configuration file

  • context-root - The context root of your web application

After you create your web application add the following arguments to the flex compiler:

-services "/usr/java/eclipse/workspace/example6/resources/flex/services-config.xml" -context-root "/example6"


Step 3

Let's create a very simple flex application that invokes the callMe() method in uk.co.spltech.remote.RemoteService. This method returns an ArrayList with a list of items:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" >
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.rpc.events.ResultEvent;
import flash.utils.getQualifiedClassName;


/**
* Populates the data list using the results returned by callMe()
*/
private function populateList(event:ResultEvent):void {
var result:ArrayCollection= ArrayCollection(event.result);
singerList.dataProvider= result;
}
]]>
</mx:Script>
<mx:RemoteObject id="myService" destination="remoteService" result="populateList(event)"/>
<mx:List id="singerList" >

</mx:List>
<mx:Button click="myService.callMe();" label="Call Remote Function" />
</mx:Application>

Step 4

Compile the flex app and copy all the generated swf/html/js to your jboss web app.

Step 5

Deploy the war file to JBOSS and test it under http://localhost:8080/example6

If you click in the "Call Remote Function" button you should see a list of results returned by the method callMe().

Download source code for JBOSS+Adobe Flex+BlazeDS project

Note that, in order to make the zip smaller, I didn't include the BlazeDS jar files. You need to manually copy them to the lib directory before generating the war file.

Click here to read Part II

20 comments:

Сергей said...

Thanx!!! Work perfect!How I can debug my flex part of application?

Armindo Cachada said...

Great to know that it worked for you. Are you using Flex Builder? It allows you to debug a flex application. Did you not try to use it?

Сергей said...

Hello! Yes, I'm using FB3. When I try debug as flex appl I get exception "RPC Fault faultString="Send failed" faultCode="Client.Error.MessageSend" faultDetail="Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Failed: url: 'http://localhost/messagebroker/amf'".
After I defined Output Folder URL in Properties by my flex project. But this way I can debug only flex, which alredy deployed on server. I want try debug my flex appl before

Armindo Cachada said...

If you are running the example I provided you with then your messagebroker should be located at http://localhost:8080/example6/messagebroker/amf

Have you checked if the flex compiler settings are correct?


You need to provide the path to services-config.xml and indicate the correct context root:

e.g.

-services "/usr/java/eclipse/workspace/example7/resources/flex/services-config.xml" -context-root "/example7" -locale en_US

Since your application server is running at port 8080, and flex tries to access port 80 by default, there are two ways around that:

1.Change the services-config.xml channel definition for "my-amf" and hardcode the port to 8080. That worked for me.

2. Another simple solution is to change your application server to run in port 80 or to run a web server.

Let me know if this works for you.

Сергей said...

Thanx!!! First way works well!It will make my job easier! I try this way before, but something work wrong. Now all is right.Your blog is most correctly for jboss. I checked much blogs before your.

Armindo Cachada said...

Glad it worked for you :)
Good luck with your flex+jboss integration.

Сергей said...

Thank you for help! :)

Сергей said...

Hello, Armindo! How I can use in BlazeDS java session what created when server start?When I use remoting I get object from new session

Сергей said...

Don't worry! I fixed it! :)

Armindo Cachada said...

Great to know. Java sessions are basically created for each new browser session. if you want components that are global you need to use the application scope I believe. Was that your problem?

Сергей said...

I just have to use FlexContext in java to get session. Now I have problem: I dynamically created my .jsp and dynamically write html code for my flex object and in this way don't work all initialize method in mx:Application tag. When I run flex application in usual way it works well.

Сергей said...

I fixed it again! :)

Сергей said...

I have question about arguments to the flex compiler: we have to define
-services use the absolute path. Can we use relative path(inside j2ee project) ?

steven said...
This comment has been removed by a blog administrator.
steven said...
This comment has been removed by a blog administrator.
Armindo Cachada said...

The answer seems to be no. I tried to provide a relative path and it didn't work.

That shouldn't be a problem though as the services-config.xml is only needed at compile time. So once you export your project into your war file, it should all just work.
P.S. Worked for me

Сергей said...

You rigth, Armindo. I met this problem when one more man began work with me on my project. I had to adjust project for him apart.But it's only way.Thanx!

Anonymous said...

Good Afternoon!!! simplyolaf.blogspot.com is one of the most outstanding resourceful websites of its kind. I take advantage of reading it every day. Keep it that way.

Anonymous said...

Hello,

I am working on a project with ATG and Flex 3. Is there any way to use Flash remoting (AMF) rather than the REST services?

The client has LCDS and prefers that.

Thanks!

David LaTour
davidDOTlatourATthinkelevenDOTcom

Armindo Cachada said...

Hi David. I definitely think it is possible to use BlazeDS/LCDS. But someone needs to create a factory for nucleus components. There are instructions on the internet on how to do this, however they are not specific to ATG.

 
Software