Pages

Tuesday, May 11, 2010

Using Remote Development Services in Flash Builder 4 and BlazeDS

In Adobe Flex Builder 3 it could be hard to map the data of a remote object or a web service to a FLEX component like a datagrid. With the help of a RDS Servlet in combination with BlazeDS or LifeCycle Data Services you can connect from Flash Builder 4 to your Back End Web Application and generate the required client side code and map this to a Flex component. This also works for a XML file or a Rest Service ( need crossdomain security configured ).

Before you can use it in FB4  you need to download BlazeDS 4 ( Binary Distribution ) and Adobe LifeCycle Data Services ( you only need the flex-rds-lcds.jar ) Add these jars to the WEB-INF/lib folder and provide the BlazeDS configuration files. It will look like this..
 Configure the web.xml with the required RDS and BlazeDS servlets and mappings.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xmlns="http://java.sun.com/xml/ns/javaee" 
   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
   id="WebApp_ID" version="2.5">
  <display-name>FlashBuilderWeb</display-name>
    <servlet>
        <servlet-name>MessageBrokerServlet</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>1</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>RDSDispatchServlet</servlet-name>
        <servlet-class>flex.rds.server.servlet.FrontEndServlet</servlet-class>
  <init-param>
   <param-name>useAppserverSecurity</param-name>
   <param-value>false</param-value>
  </init-param>        
        <load-on-startup>10</load-on-startup>
    </servlet>

    <servlet-mapping id="RDS_DISPATCH_MAPPING">
        <servlet-name>RDSDispatchServlet</servlet-name>
        <url-pattern>/CFIDE/main/ide.cfm</url-pattern>
    </servlet-mapping>
    
    <servlet-mapping>
        <servlet-name>MessageBrokerServlet</servlet-name>
        <url-pattern>/messagebroker/*</url-pattern>
    </servlet-mapping>
    
    <listener>
        <listener-class>flex.messaging.HttpFlexSession</listener-class>
    </listener>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
</web-app>

As a demo I created simple  getCities JAX-WS service and added this as a destination in the proxy-config.xml of BlazeDS.
package nl.whitehorses.ws;

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

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.WebResult;

@WebService(name   = "CitiesService", 
            serviceName = "CitiesService",
            portName    = "CitiesServicePort")
public class Cities {
    public Cities() {
    }
    
    @WebMethod
    @WebResult(name = "result")
    public List<City> getCities( @WebParam(name = "countryCode" ) String countryCode) {
        List<City> result = new ArrayList<City>();
        if ( countryCode.equalsIgnoreCase("nl") ) {
          City  c = new City();
          c.setCountry("NL");
          c.setName("PUTTEN");
          result.add(c);
          City  c2 = new City();
          c2.setCountry("NL");
          c2.setName("AMSTERDAM");
          result.add(c2);
        } else if ( countryCode.equalsIgnoreCase("de") ) {
            City  c = new City();
            c.setCountry("DE");
            c.setName("BERLIN");
            result.add(c);
            City  c2 = new City();
            c2.setCountry("DE");
            c2.setName("FRANKFURT");
            result.add(c2);
        } else {
            City  c = new City();
            c.setCountry(countryCode);
            c.setName("NOT FOUND");
            result.add(c);
        }
        return result;
    }
}

package nl.whitehorses.ws;

public class City {

    private String name;
    private String country;

    public City() {
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getCountry() {
        return country;
    }
}
Now it is time to do some work in Flash Builder 4. Go to the Data menu and select in this case Connect to Web Service. This works the same for a Remote Object

Select Through a LCDS/BlazeDS proxy destination and select your WS destination. Configured in the proxy-config.xml

Press finish and this will generate the client side code of this WS in your FB4 project.
Go to the Data / Services window and select the getCities WS Operation and press Generate Service Call

This will generate some code in the mxml to call this getCities Operation and handle the result.
Add a datagrid and Bind this to the GetCities Data provider.
Use the Existing call result.
FB4 will now change the DataGrid with the right columns.
That was the hard part and now you can finish this by Adding a Combobox to provide the input for a getCities operation.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx" 
      xmlns:wscities="services.wscities.*"> 

 <s:applicationComplete>
  <![CDATA[
      initApp();
  ]]>
 </s:applicationComplete>
 
 <fx:Script>
  <![CDATA[
   import mx.controls.Alert;

   public function initApp():void 
   { 
    getCities(country.selectedItem.data);
   } 
   
   protected function getCities(countryCode:String):void
   {
    getCitiesResult.token = wsCities.getCities(countryCode);
   }

   private function changeComboBoxEvt(e:Event):void {
    getCities(e.currentTarget.selectedItem.data);
   }
   
  ]]>
 </fx:Script>

 <fx:Declarations>
  <s:CallResponder id="getCitiesResult"/>
  <wscities:WsCities id="wsCities" fault="Alert.show(event.fault.faultString +
         '\n' + event.fault.faultDetail)" showBusyCursor="true"/>
 </fx:Declarations>

 <s:Panel title="RDC with FB4 &amp; BlazeDS">
  <s:VGroup>
   <mx:ComboBox id="country" width="150" change="changeComboBoxEvt(event)">
    <mx:ArrayList>
     <fx:Object label="Netherlands" data="NL"/>
     <fx:Object label="Germany" data="DE"/>
    </mx:ArrayList>
   </mx:ComboBox>
   
   <mx:DataGrid x="53" y="36" id="dataGrid" dataProvider="{getCitiesResult.lastResult}">
    <mx:columns>
     <mx:DataGridColumn headerText="country" dataField="country"/>
     <mx:DataGridColumn headerText="name" dataField="name"/>
    </mx:columns>
   </mx:DataGrid>
  </s:VGroup>
 </s:Panel>
</s:Application>
If you don't like these mouse clicks you can always do it manually in actionscript.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx" 
      xmlns:wscities="services.wscities.*"> 

 
 <s:applicationComplete>
  <![CDATA[
  initApp();
  ]]>
 </s:applicationComplete>
 
 <fx:Script>
  <![CDATA[
   import mx.controls.Alert;
   import mx.events.FlexEvent;
   import mx.rpc.AsyncToken;
   import mx.rpc.events.FaultEvent;
   import mx.rpc.events.ResultEvent;
   
   import services.wscities.WsCities;
   
   public var ws:WsCities; 
   
   public function initApp():void 
   { 
    ws = new WsCities(); 
    var token:AsyncToken = ws.getCities(country.selectedItem.data);
    token.addResponder(new mx.rpc.Responder(onCitiesResult, onCitiesFault));
   } 
   
   private function onCitiesResult(e:ResultEvent):void {
    dataGrid.dataProvider=e.result;
   }
   
   private function onCitiesFault(e:FaultEvent):void {
    Alert.show(e.fault.faultString, "Fault");
   }
   
   private function changeComboBoxEvt(e:Event):void {
    var token:AsyncToken = ws.getCities(e.currentTarget.selectedItem.data);
    token.addResponder(new mx.rpc.Responder(onCitiesResult, onCitiesFault));
    
    
   }
  ]]>
 </fx:Script>
 
 <s:Panel title="RDC with FB4 &amp; BlazeDS">
  <s:VGroup>
   <mx:ComboBox id="country" width="150" change="changeComboBoxEvt(event)">
    <mx:ArrayList>
     <fx:Object label="Netherlands" data="NL"/>
     <fx:Object label="Germany" data="DE"/>
    </mx:ArrayList>
   </mx:ComboBox>
   
   <mx:DataGrid x="53" y="36" id="dataGrid" >
    <mx:columns>
     <mx:DataGridColumn headerText="country" dataField="country"/>
     <mx:DataGridColumn headerText="name" dataField="name"/>
    </mx:columns>
   </mx:DataGrid>
  </s:VGroup>
 </s:Panel> 
</s:Application> 

No comments:

Post a Comment