Recently in FDS/LCDS Category

Demo for LCDS 3

| No Comments

Accessing Spring beans from flex (FDS)

| 187 Comments

1. What is Spring? Why do we care about Spring?
Christophe Coenraets  ‘ s 30 minute test drive provides good answer to these questions. See details here.

2. Spring Configuration
You can follow the steps described by Christophe or Jeff Vroom, or you can follow the steps below which provide easier access to the required jars.
1). Download spring.jar and flex-spring-factory.jar to your machine, and put them into your flex app’s WEB-INF/lib directory.
2). Add the following into your flex app’s WEB-INF/web.xml file, inside <web-app> tag.

<context-param>
   <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
 <listener>
    <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class>
</listener>

3). Add the following into to WEB-INF\flex\services-config.xml inside <services-config> tag:
          <factories>
               <factory id="spring" class="flex.samples.factories.SpringFactory"/>
          </factories>
4). If you are using JRun as app server, set the following in WEB-INF\jrun-web.xml to avoid parser conflicting:
          <jrun-web-app>
              <load-system-classes-first> true</load-system-classes-first>
          </jrun-web-app> 
Now you are ready to use flex to access Spring beans. 

3. Create Spring beans

We are going to use the sample code in singleManagedObject.zip. To understand the code and configuration, see ""How to get Single Managed Objects from a specified remote destination". In that example, we access data from DataService using an Assembler MyAssembler.java.  With the Assembler, we should be able to access Spring beans, right? Well, we are just a couple of steps away.

1). Create an interface (MyDAO.java)

Because we are trying to access Spring beans, we need to add an interface that represents all the methods we are going to use. From MyService.java we can see that there are only two methods for this sample, so MyDAO.java is going to be very simple: 

package myfds; 

import java.util.Collection;

import java.util.List;

import org.springframework.dao.DataAccessException; 

public interface MyDAO {       

            public List getProducts()  throws DataAccessException ;

             public MyBean getProduct(int myid)  throws DataAccessException ;

}

 

2). Modify MyService.java and MyAssembler.java

--- copy MyService.java and save it as MyServiceSpring.java

Change the class to extends JdbcDaoSupport and implements the interface:

import org.springframework.dao.DataAccessException;

import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.jdbc.core.RowMapper;

import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;

import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import org.springframework.jdbc.core.namedparam.SqlParameterSource;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class MyServiceSpring extends JdbcDaoSupport implements MyDAO {

......

--- copy MyAssembler.java and save it as MyAssemblerSpring.java

Change the class with setMyDAO():

import flex.data.assemblers.AbstractAssembler;

public class MyAssemblerSpring extends AbstractAssembler {

        private MyDAO myDAO;

        public void setMyDAO(MyDAO myDAO) {

                this.myDAO = myDAO;

        }

........

3). Compile your java code

Remember to include spring.jar and flex-messaging.jar in the classpath,

C:\flex\jrun4\servers\default\samples2\WEB-INF\classes>javac -classpath ./;C:\fl
ex\jrun4\servers\default\samples2\WEB-INF\lib\spring.jar;C:\flex\jrun4\servers\d
efault\samples2\WEB-INF\lib\flex-messaging.jar  -Xlint myfds/*.java

Now we have the spring bean that we can access from flex, we need to register it with our flex app, and configure flex destination to point to the Spring factory.


4. Spring beans registration and flex destination configuration

1). Create applicationContext.xml and put it under your flex app’s WEB-INF directory. Here is the applicationContext.xml for this example:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<!--define a data source to connect to your database -->

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">

    <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>

    <property name="url" value="jdbc:hsqldb:hsql://localhost/flexdemodb"/>

    <property name="username" value="sa"/>

    <property name="password" value=""/>

</bean>

<!-- define your service (methods) with a reference to dataSource -->

        <bean id="myServiceSpring" class="myfds.MyServiceSpring">

        <property name="dataSource" ref="dataSource"/>

        </bean>

<!-- define assembler with reference (dependency) to myServiceSpring -->

<bean id="myAssemblerSpring" class="myfds.MyAssemblerSpring" singleton="true">

        <!--the property name myDAO should match the variable for interface MyDAO defined in MyAssemblerSpring-->

        <property name="myDAO" ref="myServiceSpring"/>

 </bean>

</beans>

 Note, myServiceSpring will be the soruce name you use in the destination you define below.

2). Configure destination

We have registered Spring factory in WEB-INF\flex\services-config.xml in step 2 #3).

 <factory id="spring" class="flex.samples.factories.SpringFactory"/>

Therefore we need to point the destination to spring factory. Add the following into WEF-INF\flex\Data-management-config.xml:

<destination id="myfds-spring">

          <adapter ref="java-dao" />

         <properties>

        <factory>spring</factory>

        <source>myAssemblerSpring</source>

                    <metadata>

                <identity property="myid"/>

            </metadata>

    </properties>

</destination>

Now, in flex mxml page, you can access the destination myfds-spring by doing something like this:

<mx:DataService id="ds" destination="myfds-spring" result="getData1(event)"/>

And call the methods in the Spring beans by using ds.getItem({myid:2})    

If you run myDataServiceSpring.mxml, you can get data from different method by click on different button.

Here is the simpleSpring.zip which incdules all the code.

Flex Campaign for Java Developers has launched on Monday, Feb. 13. This is good news for java developer who would like to make Flex app work with backend database.Christophe Coenraets  's 30 minute test drive  provides many examples about how to manipulate data with FDS. You can download the test drive server here.

Once you extracted fds-tomcat.zip , you can see flex samples that integrate with ActiveMQ , Spring 2 , Hibernate 3.2 , and HSQLDB 1.8 .  Sample 8 under testdrive folder demonstrated how to retrieve/create/update/delete data using FDS. The flex client code displays the collection managed objects retrieved from backend. However, users may have difficulty to get Single Managed Objects from flex app. It may not be clear how the identity is passed to the method. I was asked to create a sample to get Single Managed Objects from a specified remote destination. I am putting a simplified version of the example here to demonstrate how to do that.

1. Create java Assembler

1). Create your bean (MyBean.java)
First you create your bean with the data field you needed, and set/get method for each of them. 
2). Create MyService.java for your methods
For simplicity,  I have only defined two methods:
     getProducts()  -- retrieve all data, returns a list
     getProduct(int myid) --- retrieve data with myid as identity,  returns a single Object.
3). Create an Assembler (MyAssembler.java)
        public Collection fill(List fillArgs) {
                      MyService service = new MyService();
                      return service.getProducts();
        }
public Object getItem(Map identity) {
                      MyService service = new MyService();
                      MyBean mybean =  service.getProduct(((Integer) identity.get("myid")).intValue());
                      System.out.println("mybean.myid="+mybean.myid);
                      return mybean;
        }

As we can see, fill() method calls getProducts(), and getItem() calls getProduct() from MyService.
Note,  MyBean mybean =  service.getProduct(((Integer) identity.get("myid")).intValue());
Here myid is the identity field.  It must match the identity property in your destination configuration:
<identity property="myid"/>

2. Compile your java code.
As we mentioned before, MyAssembler extends AbstractAssembler which is defined in flex-messaging.jar. So when you compile the java code, you must include flex-messaging.jar in your classpath.  This jar is included in your fds flex app’s \WEB-INF\lib directory.  For example:
C:\flex\jrun4\servers\default\samples2\WEB-INF\classes>javac -classpath ./;C:\fds-tomcat\webapps\ROOT\WEB-INF\lib\flex-messaging.jar -Xlint myfds/*.java

3. Mapping client-side objects to Java objects
This is a very important step, but easy to forget. Here are some key points from doc:
1). To represent a server-side Java object in a client application, you use the [RemoteClass(alias=" ")] metadata tag to create an ActionScript object that maps directly to the Java object. You specify the fully qualified class name of the Java class as the value of alias. This is the same technique that you use to map to Java objects when using RemoteObject components.
2).You can use the [RemoteClass] metadata tag without an alias if you do not map to a Java object on the server, but you do send back your object type from the server. Your ActionScript object is serialized to a Map object when it is sent to the server, but the object returned from the server to the clients is your original ActionScript type.
3). To create a managed association between client-side and server-side objects, you also use the [Managed] metadata tag or explicitly implement the mx.data.IManaged interface. The [Managed] metadata tag ensures that the managed Contact object supports the proper change events to propagate changes between the client-based object and the server-based object.
See MyBeam.as for code details.

4. configure destination in data-management-config.xml
add the following into your data-management-config.xml, parallel to other destination definition.
<destination id="myfds">
        <adapter ref="java-dao" />
        <properties>
            <source>myfds.MyAssembler</source>
            <scope>application</scope>
            <metadata>
                <identity property="myid"/>
            </metadata>
            <network>
                <session-timeout>20</session-timeout>
                <paging enabled="false" pageSize="10" />
                <throttle-inbound policy="ERROR" max-frequency="500"/>
                <throttle-outbound policy="REPLACE" max-frequency="500"/>
            </network>
        </properties>
    </destination>
 
Note: source should point to the full qualified class name of your assembler.
         Identity should match the identity you are passing in Assembler:
         MyBean mybean =  service.getProduct(((Integer) identity.get("myid")).intValue());

5. create flex page to display the data (myDataSerivce.mxml)
1).  Retrieve data
        <mx:ArrayCollection id="mydata1"/>
        <mx:DataService id="ds1" destination="myfds" result="getData(event)"/>
        <mx:Button  id="bt1" label="Get data from fill method" click="ds1.fill(mydata1)"/> 
        <mx:Button  id="bt2" label="Get data from getItem method" click="ds1.getItem({myid:2})"/>
--- We first define a DataService ds1 which is mapped to destination named myfds. This should match <destination  id="myfds"> in data-management-config.xml.
---We call ds1.fill(mydata1) to populates an ArrayCollection mydata1, and use it as dataProvider of the datagrid.
    <mx:DataGrid dataProvider="{mydata1}"  width="300" height="100%" >
---We use ds1.getItem({myid:2}) to get single Object based on the dentity myid  we passed into getItem.
2). We use a result handler getData(event) to handle the data we retrieved from DataService. This will make sure that your event is trigged after the data has returned.   Now let’s look at resulte handler getData():
   private function getData(event:ResultEvent):void{
           if(myButton == "bt1"){
                       prodId.text = event.result[1].prodID;
                       firstName.text = event.result[1].firstName;
                       lastName.text = event.result[1].lastName;
             }else{
                        prodId.text = event.result.prodID;
                        firstName.text = event.result.firstName;
                        lastName.text = event.result.lastName;    
              }
   }
Because fill() method returns an ArrayCollection, getItem() returns a single object, so we have to treat it differently. To figure out which method is called by the user, we add EventListener to the button, and record the button id.
     private function init():void{
              bt1.addEventListener(MouseEvent.CLICK,clickHandler);
              bt2.addEventListener(MouseEvent.CLICK,clickHandler);
      }
      private function clickHandler(event:MouseEvent):void{
               myButton = event.currentTarget.id;
       }   
Now, when you click different button, different data will be displayed in "User Details" TitleWindow.

6. To test the sample:

1).  Unzip singleManagedObject.zip to your machine . Put myfds folder under your flex app’s WEB-INF/classes directory. Put myDataService.mxml and MyBean.as under you flex app’s root directory.
2). Double check the step 4 mentioned above. Restart your flex app server if needed.
3). Run myDataService.mxml, click on the two buttons and see different data displayed.


7. Troubleshooting

If there are no erros client side, but can't get data to retrun from the server side, check the following:

1). double check step 4 mentioned above, make sure your destinatio id, sourceand identity property are defined correctly. Also, make sure your database connection is valid and qurey statement are correctly retrieving data.

2). Trun on server side debug bysetting log level to debug in services-config.xml:

<target class="flex.messaging.log.ConsoleTarget" level="Debug">

Using FDS 2 with Tomcat

| 210 Comments

When using FDS 2 with Tomcat, there are extra files to install and configure. Please see flex install doc

1. About JOTM:
You must install JOTM from http://jotm.objectweb.org, and make sure you copy the JAR files from jotm-root/lib to tomcat-root/common/lib. The jar files are:

* jotm.jar
* jotm_jrmp_stubs.jar
* ow_carol.jar
* jta-spec1_0_1.jar
* jts1_0.jar
* objectweb-datasource.jar
* xapool.jar
* howl.jar
* commons-cli-1.0.jar
* connector-1_5.jar

To get JOTM configurate correctly with flex samples, see this link.
If you need to configure JDBC and transactions in Tomcat with JOTM, see this link.

2. About JMX
If you are using jdk 1.5. and up, then you don't need to do anything about this. You will only need to install JMX if you are using JDK 1.4.x.

How to access database from flex 2

| 139 Comments

We often hear people asking about how to config datasource in flex to connect to a database. It is a miss conception to think that you need to config a datasource in flex and can use that datasource to connect to a database. Then how does flex app access data from a database? Flex does not connect to DB directly, but thru Java or other means. The doc has all the details regarding this topic, and has a sample of using PHP. But it may not be clear for people who are not familiar with J2EE to connect using java. Here is the steps to create access to database using Java.

Basically, there are three steps you need to accomplish in order to communicating with database from flex.

1. Write java code to communicate to the database. We usually call this an Assembler. In here, you provide the information about what database and jdbc driver you are connecting to, and create a connection to it.

2. Then config a destination which point to the Assembler in data-management.xml. Any flex app uses this destination will use this Assembler, and connecting to the same database.

3. In your flex code, you reference the data service like this:
dsEmployee = new DataService("crm.company");
here crm.company is a destination defined in step 2.

Now, Let us look at the sample code included in the samples.war to see how it is done. Let us look at the crm sample in dataservice.

1. Open dataservice\crm\companyapp.mxml, In there you can see the following code:

dsCompany = new DataService("crm.company");
// if hibernate is used, change the destination of the data service
// dsCompany = new DataService("crm.company.hibernate");
dsCompany.addEventListener(ResultEvent.RESULT, companyResultHandler);
dsCompany.addEventListener(FaultEvent.FAULT, faultHandler);
dsCompany.addEventListener(DataConflictEvent.CONFLICT, conflictHandler);
dsCompany.autoCommit = false;

Here we are using a dataService named "crm.company" for our app.

2. Open WEF-INF\flex\data-management.xml, we can see crm.company is defined as:

<destination id="crm.company;">
<adapter ref="java-dao" />
<properties>
<source>samples.crm.CompanyAssembler</source>
<scope>application</scope>
....


This destination point to java class amples.crm.CompanyAssembler. This is our Assembler.

3. Let us see how the Assembler is constructed.
--- go to WEB-INF\src\samples\crm\CompanyAssembler.java, we can see :
CompanyDAO dao = new CompanyDAO(); //using CompanyDAO class
--- go to CompanyDAO.java, we can see
c = ConnectionHelper.getConnection(); //using ConnectionHelper class
--- go to ConnectionHelper.java, we can see the code to connect to database:

private ConnectionHelper()
{
try
{
Class.forName("org.hsqldb.jdbcDriver");
// Obtain a path to WEB-INF/classes/samples/crm
String str = URLDecoder.decode(getClass().getClassLoader().getResource("samples/crm").toString(),"UTF-8");
// Create HSQLDB JDBC URL pointing to WEB-INF/db/crm/crm (where the last crm is the datanase name)
url = "jdbc:hsqldb:" + str.substring(0, str.indexOf("classes/samples/crm")) + "db/crm/crm";
}
catch (Exception e)
{
e.printStackTrace();
}
}

This is the core of the Assembler. This is where you tell flex which database to connect.

The most important information you need to provide are the driver name and the URL. Each database has different driver name and URL, you have to make sure you are using the correct name and format. Here is a list of driver name and example of URL:


#MySql
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test

#Oracle
#driver=oracle.jdbc.OracleDriver
#url=jdbc:oracle:thin:@test:1521

#Sybase Enterprise
#driver=com.sybase.jdbc3.jdbc.SybDriver
#url=jdbc:sybase:Tds:localhost:2048/test

#Sybase Anywhere
#driver=com.sybase.jdbc3.jdbc.SybDriver
#url=jdbc:sybase:Tds:localhost:2638/test

#Informix
#driver=com.informix.jdbc.IfxDriver
#url=jdbc:informix-qli://localhost:50000/test:informixserver=testserver

#MS SQL
#driver=com.microsoft.jdbc.sqlserver.SQLServerDriver
#url please see http://msdn2.microsoft.com/en-us/library/ms378428.aspx