msgbartop
Just a little about development! Think before you write!
msgbarbottom

31 Oct 07 Java + Flex = Cool application and reliable back end!

Probably you have already heard about Adobe Flex.
Flex is a SDK to develop Rich Internet Applications that will run within the Flash Player, and Flash Player is present in almost all browser and all desktop platforms today.
Flex applications generate an SWF file and this file will communicate with a back end server, this backend server can be a Flash Lifecycle Server, but you can use java and open source for it too.

This two/tree examples work without any paid software, you will need only:
Flex SDK – that is free, and the version 3 will be open source.
A servlet container – I’m using Tomcat
– For the first example that is all
And for the other two examples you’ll need to download
OpenAMF – A flex remoting implementation in Java
RemoteObjectAMF0 – an implementation of the RemoteObject tag that supports the version 0 of AMF protocol (OpenAMF does not supports the version 3 yet)

So, lets start, create a java web project with your favorite IDE, and create a Servlet named TestServlet, I’ll use jaxb to render XML from the servlet, but you can use anything else, if you want to use jaxb too, the schema I created for this example is the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.com/example" xmlns:tns="http://www.example.com/example" elementFormDefault="qualified">
    <element name="TestSVo" type="tns:TestList"></element>
        <complexType name="TestSVoType">
    	<attribute name="id" type="int"></attribute>
    	<attribute name="name" type="string"></attribute>
    	<attribute name="other" type="string"></attribute>
    </complexType>
    <complexType name="TestList">
    	<sequence minOccurs="1" maxOccurs="unbounded">
    		<element name="all" type="tns:TestSVoType"></element>
    	</sequence>
    </complexType>
</schema>

This schema is for a XML like the following:

1
2
3
4
5
<TestSVo>
<all id="0" name="foo" other="bar"/>
<all id="1" name="foo1" other="bar1"/>
...
</TestSVo>

Generate the stubs for the XML generation using JaxB or use any other tool to generate a XML with this schema.

Like any other Java application, I’ll start with my web.xml

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
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd ">
	<servlet>
		<servlet-name>testServlet</servlet-name>
		<servlet-class>....servlet.TestServlet</servlet-class>
	</servlet>
	<servlet>
		<servlet-name>AdvancedGateway</servlet-name>
		<servlet-class>org.openamf.AdvancedGateway</servlet-class>
		<init-param>
			<description>
				Location of the OpenAMF config file.
			</description>
			<param-name>OPENAMF_CONFIG</param-name>
			<param-value>/WEB-INF/openamf-config.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>AdvancedGateway</servlet-name>
		<url-pattern>/gateway2</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>testServlet</servlet-name>
		<url-pattern>/TestServlet</url-pattern>
	</servlet-mapping>
	<session-config>
		<session-timeout>30</session-timeout>
	</session-config>
	<welcome-file-list>
		<welcome-file>teste.html</welcome-file>
	</welcome-file-list>
</web-app>

for the first example, the only needed servlet is the test servlet, for the other examples the AdvancedGateway servlet is used …

Now write the following code in the servlet:

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
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
 
/**
 * Servlet implementation class for Servlet: TestServlet
 * 
 */
public class TestServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet
{
	static final long serialVersionUID = 1L;
	private JAXBContext jc;
	private Marshaller marc;
	private Unmarshaller unmarc;
	private ObjectFactory factory;
 
	public TestServlet()
	{
		super();
		factory = new ObjectFactory();
		try {
			jc = JAXBContext.newInstance("....servlet");
			marc = jc.createMarshaller();
			unmarc = jc.createUnmarshaller();
		} catch (JAXBException e) {
			e.printStackTrace();
		}
 
	}
 
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		float v = Float.parseFloat(request.getParameter("v"));
		float v1 = Float.parseFloat(request.getParameter("v1"));
		response.getWriter().print(v * v1);
	}
 
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
		IOException
	{
		System.out.println("List called");
		TestList res = new TestList();
		for(int i=0;i<40;i++){
			res.getAll().add(new TestSVoType(i,"Téste ã " + i));
		}
		JAXBElement<TestList> elem = factory.createTestSVo(res);
		System.out.println(elem.toString());
		try {
			marc.marshal(elem, response.getWriter());
		} catch (JAXBException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

the doGet method of this servlet is a calculator, it just multiply the two parameters and prints out the result.
The doPost prints a XML like the one above, automatically generated using the JAXB API.

Now the flex part:
Create a file named xmltest.mxml in the home folder of your webapp with the following content.

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
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	 layout="vertical"	backgroundColor="#F4F4F4">
	 <mx:HTTPService id="calc" method="GET" url="http://localhost:8080/teste/TestServlet" >
	 </mx:HTTPService>
	 <mx:HTTPService id="list" method="POST" url="http://localhost:8080/teste/TestServlet" >
	 </mx:HTTPService>
	<mx:Script>
		<![CDATA[
			import mx.controls.DataGrid;
            import mx.controls.Alert;
        ]]>
	</mx:Script>
	<mx:Panel width="80%" height="531" title="Teste">
		<mx:Label width="100%" color="blue"
			text="Type two numbers and press calculate." />
		<mx:TextInput id="v1" text="3" />
		<mx:TextInput id="v2" text="5" />
		<mx:Label id="lbl"  text="{calc.lastResult}"/>
		<mx:Button label="Calculate" click="calc.send({v:v1.text,v1:v2.text});" />
		<mx:DataGrid dataProvider="{list.lastResult.TestSVo.all}" width="100%" height="195" change="Alert.show(DataGrid(event.currentTarget).selectedItem.other)">
			<mx:columns>
				<mx:DataGridColumn headerText="Id" dataField="id" />
				<mx:DataGridColumn headerText="Nome" dataField="name" />
			</mx:columns>
		</mx:DataGrid>
		<mx:Button label="List" click="list.send({v:v1.text,v1:v2.text})" />
	</mx:Panel>
</mx:Application>

The interface with the java code is in the two mx:HTTPService lines, the first one invokes the URL with a GET request, calling the calculator method
Then the first button (Calculate) is activated, the fist service is called [calc.send(parameters)] and the text on the first label will be updated because of the value binding on the last result …
When the seccond button (List) fires a post [list.send(params)] and the data grid will process the returned XML and display the lines …
That is all!
Gotcha: if you call list.send without parameters the HTTPService tag fires a GET method, this is the reason for the unused parameters there, at least with Flex 2 this happened every time

This aproach is very simple and does not need much code from any side, but it does not looks like OOP very much …

And flex has a great remoting support, so what do you think agout creating a POJO in Java and use it as a “remote object” from your flex code?
Like the idea?
So let’s create the TestService bellow with the same two operations (calc and list)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.ArrayList;
import java.util.List;
 
public class TestService
{
	public float calc(float v, float v1){
		System.out.format("%f X %f\n", v, v1);
		return v * v1;
	}
 
	public List<TestVo> list(){
		System.out.println("List called");
		ArrayList<TestVo> res = new ArrayList<TestVo>();
		for(int i=0;i<40;i++){
			res.add(new TestVo(i,"Testé  ã " + i));
		}
		return res;
	}
}

And now, we do not need all that XML stuf, a plain old VO will do the JOB …

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
public class TestVo
{
	private String name;
	private int id;
	public TestVo(int id, String name)
	{
		this.id = id;
		this.name = name;
	}
	public String getName()
	{
		return name;
	}
	public int getId()
	{
		return id;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public void setId(int id)
	{
		this.id = id;
	}
}

To use this service from Flash, we need to configure the OpenAMF framework using the file WEB-INF/openamf-config.xml, the name and location of this file was configured as a parameter to the AdvancedGateway in web.xml file …

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
<?xml version="1.0" encoding="UTF-8"?>
<config>
	<amf-serializer>
			<force-lower-case-keys>false</force-lower-case-keys>
	</amf-serializer>
	<invoker>
		<name>Java</name>
		<class>org.openamf.invoker.JavaServiceInvoker</class>
	</invoker>
	<custom-class-mapping>
		<java-class>....TestVo</java-class>
		<custom-class>TestVo</custom-class>
	</custom-class-mapping>
	<service>
		<name>TestService</name>
		<service-location>....TestService</service-location>
		<invoker-ref>Java</invoker-ref>
		<method>
			<name>calc</name>
			<parameter>
				<type>*</type>
			</parameter>
		</method>
		<method>
			<name>list</name>
			<parameter>
				<type>*</type>
			</parameter>
		</method>
	</service>
</config>

I have removed almost all the code from this file
There is the Serializer/Deserializer configured, the only registered invoker is the Java invoker, there is one custom-class-mapping for the VO and a Service definition for the service.
If you do not want to declare all methods for each service, you can use * as the name, and it will match any method …
The OpenAMF frameworks has many more configuration options, you can call EJBs, WebServices, any java class, JMX beans and Spring Beans from your flex code without any problem …

We can not use the standard mx:RemoteObject to call this service, because OpenAMF does not support AMF3, only AMF0 and I do not know how to configure the AMF protocol version for the mx:RemoteObject tag …
So the first example, uses only a NetConnection instance:

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
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="vertical"
	backgroundColor="#F4F4F4"
	initialize="init()">
	<mx:Script>
		<![CDATA[
            import mx.controls.Alert;
            import mx.rpc.events.ResultEvent;
            import mx.collections.ArrayCollection;   
            [Bindable]
            public var lista:ArrayCollection; 
            public var nc : NetConnection;
 
            function init() : void{
            	nc = new NetConnection();
            	nc.objectEncoding = ObjectEncoding.AMF3;
            	nc.addEventListener(NetStatusEvent.NET_STATUS,netStatus);
            	nc.connect("http://localhost:8080/teste/gateway2");
            }
            function netStatus(event : NetStatusEvent) : void {
            	Alert.show(event.info.code);
            }
            function onRetornaLista(event):void{
            	var e : Array = event;
            	lista = new ArrayCollection(e);
            }       
            function onRetornaCalc(event):void{
            	lbl.text = String(event);
            }
            function calc(v1 : Number, v2 : Number) : void {
            	var r : Responder = new Responder(onRetornaCalc);
            	nc.call("TestService.calc",r,v1,v2);
            }
            function list() : void{
            	var r : Responder = new Responder(onRetornaLista);
            	nc.call("TestService.list",r);
            }
 
        ]]>
	</mx:Script>
	<mx:Panel width="80%" height="531" title="Teste">
		<mx:Label width="100%" color="blue"
			text="Type two numbers and press calculate." />
		<mx:TextInput id="v1" text="3" />
		<mx:TextInput id="v2" text="5" />
		<mx:Label id="lbl"  />
		<mx:Button label="Calculate" click="calc(Number(v1.text),Number(v2.text))" />
		<mx:DataGrid dataProvider="{lista}" width="100%" height="195">
			<mx:columns>
				<mx:DataGridColumn headerText="Id" dataField="id" />
				<mx:DataGridColumn headerText="Nome" dataField="name" />
			</mx:columns>
		</mx:DataGrid>
		<mx:Button label="List" click="list()" />
	</mx:Panel>
</mx:Application>

the init method just initialized the NetConnection object (nc).
When the first button is called (Calculate) the calc method is called, in this method we call the TestService.calc method in the server, using the NetConnection object.

The new thing here is that we need the Responders to process the result from the server call …
I think this approach is better than the last one, but still not looking very good for me.

So I looked a little around and found the RemoteObjectAMF0 library …
It is a little ActionScript library, that enables you to use tags to call your service from flex using the AMF0 protocol like this:

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
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	xmlns:renaun="com.renaun.rpc.*" layout="vertical"
	backgroundColor="#F4F4F4">
	<mx:Script>
		<![CDATA[
            import mx.controls.Alert;
            import mx.rpc.events.ResultEvent;
            import mx.collections.ArrayCollection;   
            [Bindable]
            public var lista:ArrayCollection; 
 
            NetConnection.defaultObjectEncoding = ObjectEncoding.AMF0;
 
            function onRetornaLista(event:ResultEvent):void{
            	lista = ArrayCollection(event.result);
            }       
            function onRetornaCalc(event:ResultEvent):void{
            	lbl.text = String(event.result);
            }
        ]]>
	</mx:Script>
	<renaun:RemoteObjectAMF0
		endpoint="http://localhost:8080/teste/gateway2" id="TST"
		source="....TestService" showBusyCursor="true"
		makeObjectsBindable="true"
		fault="Alert.show(String(event.fault)), 'Error'">
		<renaun:methods>
			<renaun:method name="list" result="onRetornaLista(event)"></renaun:method>
			<renaun:method name="calc" result="onRetornaCalc(event)"></renaun:method>
		</renaun:methods>
	</renaun:RemoteObjectAMF0>
	<mx:Panel width="80%" height="531" title="Teste">
		<mx:Label width="100%" color="blue"
			text="Type two numbers and press calculate." />
		<mx:TextInput id="v1" text="3" />
		<mx:TextInput id="v2" text="5" />
		<mx:Label id="lbl"  />
		<mx:Button label="Calculate" click="TST.calc(Number(v1.text),Number(v2.text))" />
		<mx:DataGrid dataProvider="{lista}" width="100%" height="195">
			<mx:columns>
				<mx:DataGridColumn headerText="Id" dataField="id" />
				<mx:DataGridColumn headerText="Nome" dataField="name" />
			</mx:columns>
		</mx:DataGrid>
		<mx:Button label="List" click="TST.list()" />
	</mx:Panel>
</mx:Application>

Still not perfect, since I did not liked the idea of using the full file name to call a service, I think my final solution will be to create an dynamic proxy for the services, but this last one looks good enought for me :D

I hope this post helps some one, I spend two days looking for solutions for this problem, because the current project does not have enought cash for a Life Cycle Server license …

PS.: to compile the mxml files you can use the mxmlc command from the free flex SDK
PS2.: you need to fix the URLs to the full path for your context, and your flex app must be downloaded from the same domain
PS3.: the é and ã letters are not encoding problems, I put it there to test if there would be any encoding problems and there were none :D

If you enjoyed this post, make sure you subscribe to my RSS feed!

Tags: , , , , , ,

Reader's Comments

  1. |

    Um… where’s the finished product?

    Reply to this comment
  2. |

    Thanks for blogging about Flex! I work on the Flex product marketing team and would be happy to send you some books and a DVD to help you with your Flex development. Feel free to email me with your address (email address submitted to this form).

    Thanks!

    Mike

    Reply to this comment
  3. |

    vb, do you want a zip file with the complete example for downloading? I can not put a working online example here because I do not have java on this server :D

    Reply to this comment
  4. |

    [...] Matt says not to believe evangelists, like myself. But he does say to “believe developers that are experienced with the framework and have used it in production”. Hmmm… I’m both. I was a developer who successfully built a production Flex based customer service portal on Oracle Portal and Oracle CRM. Since then I was hired as an evangelist to help companies like Salesforce, Intuit, Oracle, BEA and many others successfully build production Flex applications. I also still get to build production applications on Flex like my Census RIA Benchmark, the buni.org webmail client, and numerous others. So if you think my view is untrustworthy that’s ok, there are plenty of others who hold the same views. [...]

    Reply to this comment
  5. |

    [...] Matt says not to believe evangelists, like myself. But he does say to “believe developers that are experienced with the framework and have used it in production”. Hmmm… I’m both. I was a developer who successfully built a production Flex based customer service portal on Oracle Portal and Oracle CRM. Since then I was hired as an evangelist to help companies like Salesforce, Intuit, Oracle, BEA and many others successfully build production Flex applications. I also still get to build production applications on Flex like my Census RIA Benchmark, the buni.org webmail client, and numerous others. So if you think my view is untrustworthy that’s ok, there are plenty of others who hold the same views. [...]

    Reply to this comment
  6. |

    Great example, thanks! Did you post a zip file with the final source? Thanks!

    Reply to this comment
  7. |

    Does the newer Flex Remote and alias stuff supplant AMF? It seems to do the same thing (map server-side data objects to client-side data objects) but I cannot find many real examples about it. Thanks for the article, Tim Jowers, http://www.gouno.com/

    Reply to this comment
  8. |

    Hey,

    Would it be possible to get a zip file with the final solution?

    Cheers,
    Derm

    Reply to this comment
  9. |

    I am looking to develop Flex dashboard and use Flex in a Portal environment.

    However still not clear about building components like

    Rich Internet Application (using DataGrids, Trees, Charting
    Components, Drag and Drop behaviors,

    If you any thoughts or information, kindly let me know.
    Where do I start if I want to achieve Flex dashboard in a portal environment.

    If anyone has any information, kindly email me at ponicpool at gmail dot com

    Thanks

    Reply to this comment
  10. |

    Hi,
    I’m Trying to put your example in lotus Domino. It’s not a formely J2EE server. I have some problems with the file path. what does this mean ?
    “….TestService”
    The four point is for ../../TestService ?
    Thanks for this excelent post !

    Reply to this comment
  11. |

    This one is the good example , could you give me source code’s zip file?

    Reply to this comment
  12. |

    Hi,

    Mike i would like to develop flex application, if you have any material please sens me the Following Address:

    Dhayalan B
    Fountainhead
    189,Aarthi Chambers
    Mountroad
    Chennai-6
    Tamilnadu
    India.

    Reply to this comment
  13. |

    Hi,

    i have seen your article, very nice one,
    here you are saying that, we can connect the Java with Flex using OpenAMF,

    but the Code is not clear to me, is it possible to send the code to my mail id (areef.on@gmail.com).

    i went one article , please gothrough it, its useful one.
    http://www.onjava.com/pub/a/onjava/2004/12/01/flexjava.html

    i am new Flex Development, in my application, i have EJB -> Struts -> JSP to display the Data for UI, but i would like change it to Flex like, EJB -> Struts -> Flex. is it possible, please let me know your suggestion.

    thanks in advance…
    areef

    Reply to this comment
  14. |

    Hi,
    I have an issue.
    I have created an application front end using flex builder which makes a http service call to a servlet..what i dont understand is that when i run the application in flex builder it makess successful http call and retreieves data but when i copy the project to some where else and try to run the swf file , i dont get it making http call. I need to use the html, swf for my java project..so kindly tell me how it could be done

    Thanks in advance..

    Reply to this comment
  15. |

    probably you are having problems with flex “rights”.
    Flex can only make HTTP calls to the same host it was loaded.
    FlexBuilder changes it configuration allowing the flash movie to call anything.
    so if you load the movie from the same host you are calling, it will probably work.

    Reply to this comment
  16. |

    Hi,
    Good blog for understanding the communication between flex-servlet using HttpService method.
    Thanks

    Reply to this comment
  17. |

    Hi, i m new to flex world. this article seems to be quite informative. I wud be glad if u ppl can help me in the below mentioned scenario, i have a server-based servlet component which will be be sending array of images to the client side.

    Also if u can send me the source zip to understand the concept better.

    Thanx.

    Reply to this comment
  18. |

    very good example great article, please give me a source If possible send me laxman.mca2007 at gmail.com

    Reply to this comment
  19. |

    I am new to flex. This article is good. Please help me by sending the source code of the above example.

    Thanks in advance.

    Reply to this comment
  20. |

    There are many possibilities in flex to java communications:

    http://programmaremobile.blogspot.com/2009/10/java-flash-actionscript-and-amf.html

    With OpenAMF you can only in AMF0 communications.

    BlazeDS is a powerful framework but I want to have the full control in my application without install an external war.

    Webservice is a good solution, In server side you have the max scalability, perhaps the performance isn’t the better.

    There is also a communications by xml server side with JAXB marshalling and client side with ASAXB.

    for a simple communications a simple http talk is also a solution.

    All depends from what you wish to do.

    Reply to this comment

Leave a Comment