Best practices for integrating flex into Java EE applications

Source: Internet
Author: User

Http://www.ibm.com/developerworks/cn/java/j-lo-jeeflex? S_tact = 105agx52 & s_cmp = tec-csdn

 

August 05, 2009

Traditional Java EE applications usually use some MVC framework (such as struts) as front-end user interfaces. With the rise of FLEX, RIA-based clients can bring users a cooler interface, shorter response times and closer to the desktop application experience. This article describes how to integrate flex into an existing Java EE application and how to efficiently develop Java EE and flex in parallel using best practices.

Development Environment

The development environment in this article is Windows 7 Ultimate, eclipse 3.4, flex builder 3 (get the download link from the reference resources ). The Java EE server uses resin 3.2. Of course, you can also use Tomcat and other Java EE servers.



Back to Top

Existing Java EE applications

Suppose we already have a Java EE application that manages employee information, named employeemgmt-server. The structure is shown in Figure 1:

Figure 1. Java EE Project Structure

This is a typical Java EE application that uses the popular spring framework. To simplify database operations, we use the memory database HSQLDB. Dao is omitted for this simple application, and the database is operated directly through spring jdbctemplate in Fa C Ade. Finally, the employeemgmt application provides users with a front-end interface through Servlet and JSP pages:

Figure 2. employeemgmt Web Interface

This interface is a traditional HTML page. Every time you click a link, you need to refresh the page. As the employee management system is closer to traditional desktop applications, re-writing interfaces with Flex will bring a better user experience.



Back to Top

Integrate blazeds

How can I integrate flex into this Java EE application? Now, if we want to replace the original Servlet and JSP pages with Flex, We need to enable the backend communication between flex and Java ee. Flex supports multiple remote calling methods, including HTTP, Web Services, and AMF. However, server applications developed for Java EE can be integrated with blazeds to make full use of the AMF protocol and easily exchange data with the flex front-end, this method is the preferred choice for Java EE applications to integrate flex.

Blazeds is an open-source version of Adobe lifecycle data services. It complies with lgpl V3 authorization and is free of charge. Blazeds provides flex with remote calling support based on the AMF binary protocol, which is equivalent to Java RMI. With blazeds, a Java interface can be exposed to flex as a service through simple configuration for remote calls.

Although the existing employeemgmt application already has the fa c Ade interface, this interface is exposed to Servlet and it is best to define another flexservice interface for flex, and hide specific Java objects (as shown in Listing 1 ):

Listing 1. flexservice Interface

 public interface FlexService {     Employee createEmployee(String name, String title, boolean gender, Date birth);     void deleteEmployee(String id);     Employee[] queryByName(String name);     Employee[] queryAll(); } 

Now, the interfaces between the Java EE backend and the flex front-end have been defined. It is very easy to complete the Java EE back-end interface implementation class and use the powerful dependency injection function of spring, you can use several lines of simple code:

Listing 2. flexserviceimpl class

 public class FlexServiceImpl implements FlexService {     private static final Employee[] EMPTY_EMPLOYEE_ARRAY = new Employee[0];     private Facade facade;     public void setFacade(Facade facade) {         this.facade = facade;     }     public Employee createEmployee(String name, String title, boolean gender,         Date birth) {         return facade.createEmployee(name, title, gender, birth);     }     public void deleteEmployee(String id) {         facade.deleteEmployee(id);     }     public Employee[] queryAll() {         return facade.queryAll().toArray(EMPTY_EMPLOYEE_ARRAY);     }     public Employee[] queryByName(String name) {         return facade.queryByName(name).toArray(EMPTY_EMPLOYEE_ARRAY);     } } 

Then, we put the jar package required by blazeds/WEB-INF/lib/. The following jar is required for blazeds:

Listing 3. Jar dependent on blazeds

 backport-util-concurrent.jar commons-httpclient.jar commons-logging.jar flex-messaging-common.jar flex-messaging-core.jar flex-messaging-proxy.jar flex-messaging-remoting.jar 

Add httpflexsession and Servlet ing to Web. xml. Httpflexsession is a listener provided by blazeds. It monitors flex Remote Call requests and performs initialization settings:

Listing 4. Defining flex listener

 <listener>     <listener-class>flex.messaging.HttpFlexSession</listener-class> </listener> 

Messagebrokerservlet is the servlet that truly processes the flex Remote Call request. We need to map it to the specified URL:

Listing 5. Defining flex Servlet

 <servlet>     <servlet-name>messageBroker</servlet-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>0</load-on-startup> </servlet> <servlet-mapping>     <servlet-name>messageBroker</servlet-name>     <url-pattern>/messagebroker/*</url-pattern> </servlet-mapping> 

All configuration files required by blazeds are stored in the/WEB-INF/flex/directory. Blazeds will read the services-config.xml configuration file, which references the remoting-config.xml, proxy-config.xml, and messaging-config.xml configuration files, so a total of 4 configuration files are required.

Since blazeds needs to expose the Java interface flexservice to the flex front-end, we declare the flexservice interface as a service in the profile remoting-config.xml:

Listing 6. Defining flexservice

 <destination id="flexService">     <properties>         <source>org.expressme.employee.mgmt.flex.FlexServiceImpl</source>         <scope>application</scope>     </properties> </destination> 

The service name is specified through the ID attribute of destination, and the flex frontend uses this service name for remote calls. Scope is specified as application, indicating that this object is a global object.

However, according to the default declaration, blazeds will instantiate the flexservice object. For a Java EE application, these service objects are usually managed by containers (such as spring containers or EJB containers). A more appropriate method is to find the service object rather than directly instantiate it. Therefore, you need to tell blazeds to use factory to find the specified flexservice object. modify the configuration as follows:

Listing 7. Using factory to define flexservice

 <destination id="flexService">     <properties>         <factory>flexFactory</factory>         <source>flexService</source>         <scope>application</scope>     </properties> </destination> 

Now, how can flex call the flexservice interface through blazeds? Since flexservice objects have been managed by spring, we need to compile a flexfactory to tell blazeds how to find the flexservice instance managed by spring. Flexfactory specifies in services-config.xml:

Listing 8. Defining flexfactory

 <factories>     <factory id="flexFactory" class="org.expressme.employee.mgmt.flex.FlexFactoryImpl"/> </factories> 

Flexfactoryimpl implements the flexfactory interface, which completes two tasks:

  1. Create a factoryinstance object;
  2. Use the factoryinstance object to find the flexservice we need.

Therefore, we need an implementation class of factoryinstance. We compile a springfactoryinstance to search for flexservice from the spring container:

Listing 9. springfactoryinstance class

 class SpringFactoryInstance extends FactoryInstance {     private Log log = LogFactory.getLog(getClass());     SpringFactoryInstance(FlexFactory factory, String id, ConfigMap properties) {         super(factory, id, properties);     }     public Object lookup() {         ApplicationContext appContext = WebApplicationContextUtils.                 getRequiredWebApplicationContext(                     FlexContext.getServletConfig().getServletContext()         );         String beanName = getSource();         try {             log.info("Lookup bean from Spring ApplicationContext: " + beanName);             return appContext.getBean(beanName);         }         catch (NoSuchBeanDefinitionException nex) {             ...         }         catch (BeansException bex) {             ...         }         catch (Exception ex) {             ...         }     } } 

Flexfactoryimpl is responsible for instantiating springfactoryinstance andlookup()Method To find flexservice interface objects:

Listing 10. flexfactoryimpl class

 public class FlexFactoryImpl implements FlexFactory {     private Log log = LogFactory.getLog(getClass());     public FactoryInstance createFactoryInstance(String id, ConfigMap properties) {         log.info("Create FactoryInstance.");         SpringFactoryInstance instance = new SpringFactoryInstance(this, id, properties);         instance.setSource(properties.getPropertyAsString(SOURCE, instance.getId()));         return instance;     }     public Object lookup(FactoryInstance instanceInfo) {         log.info("Lookup service object.");         return instanceInfo.lookup();     }     public void initialize(String id, ConfigMap configMap) {     } } 

The following describes how to find the flexservice interface in blazeds:

  1. Blazeds will first create a flexfactory instance -- flexfactoryimpl;
  2. When receiving a remote call request from the flex frontend, blazeds creates a factoryinstance object through flexfactory and passes in the requested service ID. In this application, the actual object of the created factoryinstance is springfactoryinstance;
  3. The Lookup () method of factoryinstance is called. In springfactoryinstance, first find the spring container, and then find the bean through the bean ID. Finally, the instance of the flexservice interface is returned.

Note that the destination ID is not written to the code, but obtained through the following statement:

Listing 11. Get the destination ID

 properties.getPropertyAsString(SOURCE, instance.getId()) 

The source attribute of property is obtained by reading the xml configuration file from blazeds:

Listing 12. Configure the destination ID

 <destination id="flexService">     <properties>         <factory>flexFactory</factory>         <source>flexService</source>         <scope>application</scope>     </properties> </destination> 

If you do not use the Spring framework, you only need to modify the Lookup () method of factoryinstance. For example, for an EJB, The Lookup () method should return a remote interface through the JNDI lookup. Regardless of the application structure, our ultimate goal is to return a flexservice instance object to blazeds.



Back to Top

Develop a flex Client

First install flex builder 3 and get a 30-day free trial on Adobe's official website. Open flex builder 3 and create a new Flex project named employeemgmt-Flex:

Figure 3. Create a flex project-Step 1

In the flex project, you must specify the server configuration file address:

Figure 4. Create a flex project-Step 2

Therefore, you must enter the web root directory of the employeemgmt-server project, which must exist/WEB-INF/flex/. Click "Validate configuration" to verify that the configuration file is correct. The configuration file can continue only after it passes verification. By default, flex builder places the generated FLASH file toweb/EmployeeMgmt-Flex-debugDirectory.

The directory structure of a flex project is as follows:

Figure 5. directory structure of the Flex Project

Using flex builder to make beautiful user interfaces is very easy. Flex Builder provides a visual editor that allows an experienced developer to design beautiful la s through simple drag and drop operations. If you are familiar with XML, it is not difficult to edit mxml. The final result of the employee management system interface we designed is as follows:

Figure 6. visual editor design interface using Flex Builder

This article does not discuss how to compile the flex interface, but focuses on how to implement remote calls.

To implement remote calls in flex, we need to define a remoteobject object. You can create this object by using ActionScript encoding or define a remoteobject object in mxml and list all its methods:

Listing 13. Defining flexservicero

 <mx:RemoteObject id="flexServiceRO" destination="flexService">     <mx:method name="queryAll" result="handleQueryAll(result : ResultEvent)"/> </mx:RemoteObject> 

Now, you can call the remoteobject method named flexservicero:

Listing 14. Call flexservicero. queryall ()

  flexServiceRO.queryAll(function(result : ResultEvent) {     var employees = result.result as Array;  }); 

Run the flex application. The employee information has been correctly obtained:

Figure 7. Run the flex application in the browser



Back to Top

Enhance remoteobject

Although the call through remoteobject is simple, there are many problems: first, remoteobject is a dynamic class, And the compiler of flex Builder cannot check the parameter type and number of parameters for us. In this way, it is easy to make errors when writing The ActionScript code. In addition, when the interface changes (this often happens), you need to modify the definition of remoteobject again. In addition, the flex team needs a complete flexservice interface Document revised at any time to work.

Therefore, it is best to use a strong remoteobject interface to enable the compiler of flex builder to detect errors early. This strong type of remoteobject should be automatically generated through the flexservice interface of the Java EE application, so that the definition of remoteobject does not need to be maintained.

To automatically generate the remoteobject object, I wrote a java2actionscript ant task to automatically convert the flexservice interface and all related JavaBean. Javainterface2remoteobjecttask converts a Java interface object to a remoteobject object. Use the following ant script:

Listing 15. Generate the ant script for The ActionScript class

 <taskdef name="genactionscript" classname="org.expressme.ant.JavaBean2ActionScriptTask">     <classpath refid="build-classpath" /> </taskdef> <taskdef name="genremoteobject"     classname="org.expressme.ant.JavaInterface2RemoteObjectTask">     <classpath refid="build-classpath" /> </taskdef> <genactionscript     packageName="org.expressme.employee.mgmt"    includes="Employee"    orderByName="true"    encoding="UTF-8"    outputDir="${gen.dir}"/> <genremoteobject     interfaceClass="org.expressme.employee.mgmt.flex.FlexService"    encoding="UTF-8"    outputDir="${gen.dir}"    destination="flexService"/> 

The converted flexservicero class has all the methods corresponding to the Java interface. Each method is a strongly typed signature, and an additional two optional functions are added to process the result and fault events. For example, the querybyname method:

Listing 16. automatically generated querybyname () method

 public function queryByName(arg1 : String, result : Function = null,     fault : Function = null) : void {     var op : AbstractOperation = ro.getOperation("queryByName");     if (result!=null) {         op.addEventListener(ResultEvent.RESULT, result);     }     if (fault!=null) {         op.addEventListener(FaultEvent.FAULT, fault);     }     var f : Function = function() : void {         op.removeEventListener(ResultEvent.RESULT, f);         op.removeEventListener(FaultEvent.FAULT, f);         if (result!=null) {             op.removeEventListener(ResultEvent.RESULT, result);         }         if (fault!=null) {             op.addEventListener(FaultEvent.FAULT, fault);         }     }     op.addEventListener(ResultEvent.RESULT, f);     op.addEventListener(FaultEvent.FAULT, f);     op.send(arg1); } 

The Java interface is converted through the interface. as and interfacemethod. as two template files are completed. In addition, all the JavaBean objects passed between the Java EE backend and flex are automatically converted to the corresponding ActionScript class through javabean2actionscripttask, which is implemented through bean. the as template is complete.

With the automatic conversion from a Java class to an ActionScript class, we can enjoy the automatic prompts of the compiler check and The ActionScript class methods when writing The ActionScript:

Figure 8. Auto-completion of flex builder code

The only drawback is that when we read the flexservice interface through reflection, we lose the method parameter name. Therefore, the flexservicero method parameter name can only be changed to arg1, arg2 ...... To read the method parameter name of the flexservice interface, you can only parse the Java source code.

Now, the back-end development team of Java EE and the front-end development team of flex only need to negotiate and define the flexservice interface. Then, using java2actionscript, the flex team gets a strong flexservicero class, the Java EE team only needs to focus on implementing the flexservice interface.

In the early stage of development, you can even use a hardcoded flexservice implementation class. Whenever flexservice changes, you only need to run the ant script again to obtain the latest flexservicero class. In this way, both teams can start working immediately, and they can work together perfectly through the flexservice interface.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.