Nov 23, 2009

Spring Flex Integration using SBI

Flex and Spring Integration Architecture

Many applications are implemented with a three-tier architecture wherein data is stored in the database. The web server runs Java services that access the database and retrieve the information. The Java classes are responsible for the business logic that receives a call from the client tier, assembles the information from the database, and returns the result.

The client tier utilizes browser technology that runs a Flash application to provide an interface to the user and calls the Java services for required information. The client workstations call the Tomcat server, which calls the database to gather data and executes the Spring services that contain the application’s business logic.

In this architecture, the compiled Flex and Spring code resides on the Tomcat server. The client workstations download the Flex SWF and associated files, which contain the hooks into the Spring services.

Sample Application

To demonstrate the Spring and Flex integration, I am presenting a sample application which is a web based application with the following architecture.

image

Spring

Spring addresses Java/Java EE development by organizing your middle-tier objects and takes care of the plumbing that is usually left up for you to create. Spring can also work in any architecture layer while running in any runtime environment.

Spring Bean Wiring

The IoC container, also called the core container, wires Spring beans together. It is also responsible

for the configuration and creation of objects in Spring.

In most cases, when an object needs references to data, it does a lookup or retrieval from an external data repository. IoC allows the component to not require information regarding the location of the data source, thus cleaning up the process of data retrieval through inverting the direction of the retrieval.

IoC helps to create layers of abstraction through your Spring applications. Spring’s core container provides a central location for accessing objects, called the application context. The application context can be configured as Java 5 annotations or as an XML file that contains the signatures of each bean that is created in a Spring application.

Building Spring Service

To demonstrate I will present a simple spring service that gets a list of objects from the database using Hibernate as the ORM technology.

Building a Simple Bean

The first item of interest is to build a bean for our service. This bean is part of the IoC container.

Beans defined in the IoC container are nothing more than a pool of components you have access to by referencing the service with which they are associated.

The MyService is a simple POJO with a method to print the project list. This bean does not have a constructor, as no arguments need to be passed to the bean at instantiation.

Bean Interface (MyService.java)

package com.sampleapp.services;

import java.util.List;
import com.sampleapp.domain.MyDomainObject;

public interface MyService {

List<MyDomainObject> getProjects();

}


Bean Implementation (MyServiceImpl.java)



package com.sampleapp.services;

import java.util.List;
import java.util.Map;
import com.sampleapp.domain.MyDomainObject;
import com.sampleapp.dao.MyDao;
import org.springframework.beans.factory.annotation.Autowired;

public class MyServiceImpl implements MyService {

MyDao myDao;

@Autowired(required = true)
public void setConsDbDao(MyDao myDao) {
this.myDao = myDao;
}

public List<MyDomainObject> getProjects() {
// TODO Auto-generated method stub
return myDao.getProjects();
}
}


Building Data Persistence





The Spring Framework provides a layer of abstraction for transaction management to allow you to consistently program across different transaction APIs, such as JDBC, Hibernate, JPA, and Java Data Objects (JDO). Spring provides support for both programmatic and declarative transaction management.



Spring Transaction Managers



Spring provides transaction managers that delegate work to platform-specific transaction implementations through either JTA or the transaction manager’s framework; Spring does not manage transactions directly. Spring provides transaction managers for J2EE Connector Architecture (JCA), JDBC, JMS, Hibernate, JDO, JPA, TopLink, and others.



Since here I am going to use Hibernate as ORM solution, so you will use the HibernateTransactionManager.



To demonstrate how to persist data with Spring, we need a database, so lets create a database table DOMAINOBJECT.



clip_image002



Once that is complete, you can go ahead and create a class to support the table.



Domain Object (MyDomainObject.java)



package com.sampleapp.domain;

import java.io.Serializable;
import java.sql.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

@Entity
@Table(name="DOMAINOBJECT")
public class MyDomainObject implements Serializable {

static final long serialVersionUID = 1L;

private int id;
private String project;
private String ownerName;
private Date lastUpdated;

public MyDomainObject() {}

@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="gen_id")
@SequenceGenerator(name="gen_id", sequenceName = "DOMAINOBJ_SEQ")
@Column(name="ID")
public int getId() {
return this.id;
}

public void setId(int id) {
this.id = id;
}

@Column(name = "PROJECT", nullable = false, length = 255)
public String getProject() {
return project;
}

public void setProject(String project) {
this.project = project;
}

@Column(name = "OWNERNAME", length = 255)
public String getOwnerName() {
return ownerName;
}

public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}

@Column(name = "LASTUPDATED")
public Date getLastUpdated() {
return lastUpdated;
}

public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
}
}


We will need to create a DAO to support database operations, each of which is carried out by a DAO method. Since we have only one operation here so will have one method defined in the interface.



These methods should be defined in the DAO interface to allow for different implementation technologies such as Hibernate and iBATIS.



Dao Interface (MyDao.java)



package com.sampleapp.dao;

import java.util.List;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Propagation;
import com.sampleapp.domain.MyDomainObject;

public interface MyDao {

@Transactional(readOnly=true, propagation=Propagation.SUPPORTS)
List<MyDomainObject> getProjects();

}


Since I am using Hibernate as the implementation technology so let’s create the Hibernate implementation of the above defined DAO interface.



Dao Implementation (MyDaoImpl.java)



package com.sampleapp.dao;

import java.util.List;
import com.sampleapp.domain.MyDomainObject;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Transactional(propagation=Propagation.SUPPORTS, readOnly=true)
public class MyDaoImpl extends HibernateDaoSupport implements MyDao {

@SuppressWarnings({"unchecked"})
@Transactional(propagation=Propagation.SUPPORTS, readOnly=true)
public List<MyDomainObject> getProjects() {
// TODO Auto-generated method stub
List<MyDomainObject> projects = getHibernateTemplate().find("from MyDomainObject");
return projects;
}
}


Once done we can now start registering the beans in the Spring ICO container called applicationContext.xml.



For simplicity, I am going to keep the database/hibernate related properties in a separate file called hibernate.properties. This has advantage that in future if the database needs to change I can change the settings in a file without touching rest of the application.



Hibernate SessionFactory Configuration (hibernate.properties)



# Hibernate 3 configuration
hibernate.connection.driver_class=oracle.jdbc.driver.OracleDriver
hibernate.connection.url=jdbc:oracle:thin:@servername:port:DB
hibernate.connection.username=username
hibernate.connection.password=password
hibernate.show_sql=true
hibernate.format_sql=false
hibernate.transaction.factory_class=org.hibernate.transaction.JDBCTransactionFactory
hibernate.dialect=org.hibernate.dialect.Oracle9Dialect
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=5
hibernate.c3p0.max_statements=50
hibernate.c3p0.timeout=1800


Now lets start registering the various components in Spring IOC container.



1. Configure Hibernate Session Factory



<bean id="sessionFactory" 
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="annotatedClasses">
<list>
<!-- Add annotated domain objects here-->
<value>com.sampleapp.domain.MyDomainObj</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">${hibernate.show_sql}
</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}
</prop>
<prop key="hibernate.transaction.factory_class">${hibernate.transaction.factory_class}
</prop>
<prop
key="hibernate.dialect">${hibernate.dialect}
</prop>
<prop key="hibernate.c3p0.min_size">${hibernate.c3p0.min_size}
</prop>
<prop key="hibernate.c3p0.max_size">${hibernate.c3p0.max_size}</prop>
<prop key="hibernate.c3p0.timeout">${hibernate.c3p0.timeout}</prop>
<prop key="hibernate.c3p0.max_statements">${hibernate.c3p0.max_statements}</prop>
<prop key="hibernate.connection.driver_class">${hibernate.connection.driver_class}</prop>
<prop key="hibernate.connection.url">${hibernate.connection.url}</prop>
<prop key="hibernate.connection.username">${hibernate.connection.username}</prop>
<prop key="hibernate.connection.password">${hibernate.connection.password}</prop>
</props>
</property>
</bean>


2. Autowiring and Annotation Support



<!-- enable the configuration of transactional behavior based on annotations -->

<tx:annotation-driven transaction-manager="txManager"/>

<!-- enable autowiring -->
<context:annotation-config />

<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>


3. Transaction Manager Registration



<bean id="txManager"  class="org.springframework.orm.hibernate3.HibernateTransactionManager">    
<property name="sessionFactory"><ref local="sessionFactory" />
</property>
</bean>


4. Dao Registration



<bean id="myDao" 
class="com.sampleapp.dao.MyDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>


5. Registration of Services



<bean id="myService" 
class="com.sampleapp.services.MyServiceImpl"/>


That completes our Server side development of our sample application.



To expose the Spring services to the Flex, we need to have the BlazeDS integration done.



For this download the BlazeDS jars and Spring SBI jars and put it in your application classpath.



The SBI suite is designed as a best practice solution for integrating Flex and Spring. Its main goal is to simplify communication between Flex and Spring by providing Remoting and messaging capabilities in combination with BlazeDS.



Setting Up the BlazeDS MessageBroker



The MessageBroker is a the SBI component responsible for handling HTTP messages from the



Flex client. The MessageBroker is managed by Spring instead of BlazeDS. Messages are routed



to the Spring-managed MessageBroker via the Spring DispatcherServlet.



Lets modify the web.xml with the configuration required to handle the requests from Flex.



Web.xml



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>

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

<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-config/applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/spring/*</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
</welcome-file-list>

</web-app>


Since we are using the MessageBroker which is managed by Spring so we have to register it in the Spring IOC container applicationContext.xml



<bean 
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/*=springManagedMessageBroker
</value>
</property>
</bean>

<!-- Dispatches requests mapped to a MessageBroker -->
<bean
class="org.springframework.flex.servlet.MessageBrokerHandlerAdapter"/>

<!-- Bootstraps and exposes the BlazeDS MessageBroker -->
<bean id="springManagedMessageBroker"
class="org.springframework.flex.core.MessageBrokerFactoryBean" />


Also we need to expose our service beans to flex remoting



<bean id="myServiceRO" class="org.springframework.flex.remoting.RemotingDestinationExporter">
<property name="messageBroker"
ref="springManagedMessageBroker"/>
<property name="service" ref="consDbService"/>
<property name="destinationId" value="myService" />
<property name="channels" value="my-amf, my-secure-amf"/>
</bean>


Now lets register the channels my-amf in the BlazeDS configuration files (remoting-config.xml and services-config.xml)



remoting-config.xml



<?xml version="1.0" encoding="UTF-8"?>
<service id="remoting-service"
class="flex.messaging.services.RemotingService">
<adapters>
<adapter-definition id="java-object" class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true"/>
</adapters>
<default-channels>
<channel ref="my-amf"/>
</default-channels>
</service>
services-config.xml
<channels>

<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/spring/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>false</polling-enabled>
</properties>
</channel-definition>
</channels>

image

Deploy the application on your favourite web server.



I am using Tomcat



Flex



In this application, Flex makes an RPC call to the BlazeDS server to consume the getProjects we created in Spring.



So lets create the flex application which will make RPC calls to the spring services we defined.



SampleApp.mxml



<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
pageTitle="Projects List"
layout="absolute"
width="100%"
height="100%"
initialize="initializeHandler()" borderColor="#009DFF"
creationComplete="initializeHandler()">

<mx:RemoteObject
id="ro"
destination="myService"
endpoint="http://localhost:8080/SampleApp/spring/messagebroker/amf"
result="resultHandler(event)"
fault="faultHandler(event)"
showBusyCursor="true"
/>

<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
import mx.utils.ObjectUtil;
import mx.controls.Alert;
import mx.utils.StringUtil;


[Bindable]
private var systemsData:ArrayCollection = new ArrayCollection();

private var selectedItem:Object;

private function initializeHandler():void
{
ro.getProjects();
}

private function resultHandler(event:ResultEvent):void
{
systemsData = ArrayCollection(event.result);
}

private function faultHandler(event:FaultEvent):void
{
Alert.show(ObjectUtil.toString(event.fault) );
}

]]>
</mx:Script>


<mx:VBox width="100%" height="100%" y="10" x="10">
<mx:ApplicationControlBar width="100%" height="81" borderColor="#F7FAFC" fillColors="[#009DFF, #009DFF]" fillAlphas="[0.53, 0.53]" autoLayout="true" themeColor="#F6F8F9">
<mx:Text text="Project List" fontSize="26" fontWeight="bold" fontStyle="italic" themeColor="#9E5814" alpha="0.52" color="#F4FAFB" width="310"/>
</mx:ApplicationControlBar>
<mx:HBox x="10" y="10" width="100%" height="100%" id="hbox1">

<mx:Panel id="systemStatus" width="100%" height="100%" layout="absolute" cornerRadius="0" borderColor="#009DFF" fontSize="13" backgroundAlpha="0.5" backgroundColor="#009DFF">
<mx:VBox label = 'Report' borderColor="#009DFF" borderStyle="solid" borderThickness="6" backgroundColor="#009DFF" x="33" y="9">
<mx:DataGrid
id="dgrid"
updateComplete=""
dataProvider="{systemsData}"
width="622" height="362"
bottom="0" right="0" alternatingItemColors="[#F7F7F7, #BDE7E8]" themeColor="#32C582" borderThickness="5" borderStyle="solid" borderColor="#009DFF">
<mx:columns>
<mx:DataGridColumn fontSize="9" headerText="Project Name" dataField="project" />
<mx:DataGridColumn fontSize="9" headerText="Last Updated" dataField="lastUpdated">
<mx:itemRenderer>
<mx:Component>
<mx:VBox>
<mx:DateFormatter id="formatDateTime" formatString="MM/DD/YY" />
<mx:Label text="{formatDateTime.format(data.lastUpdated)}"/>
</mx:VBox>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
<mx:DataGridColumn fontSize="9" headerText="Owner Name" dataField="ownerName" />
</mx:columns>
</mx:DataGrid>
</mx:VBox>
</mx:Panel>
</mx:HBox>
</mx:VBox>
</mx:Application>


Once done copy the sampleApp.html, sampleApp.swf, AC_OETags.js and playerProductInstall.swf in your web application and you should be able to view the application deployed on tomcat as below:



clip_image002[5]



References



0 comments:

Text Widget

Copyright © Vinay's Blog | Powered by Blogger

Design by | Blogger Theme by