27 October 2008
Some working knowledge of Eclipse and the Adobe Flex Builder will be helpful to build the application. Some Java and Flex background will help as well, but even with no any Java or Flex background you can still build the application from the available source code.
Beginning
This article demonstrates how to create and run a simple Flex application that is connected to a relational database using the Hibernate implementation of the Java Persistence Architecture (JPA). It guides you through all steps required to create and run a sample application including setup of the required software.
The Hibernate website says this about Java Persistence with Hibernate:
The Java Persistence API is the standard object/relational mapping and persistence management interface of the Java EE 5.0 platform. As part of the EJB 3.0 specification effort, it is supported by all major vendors of the Java industry.
Hibernate implements the Java Persistence object/relational mapping and persistence management interfaces with the Hibernate Annotations and Hibernate EntityManager modules, on top of the mature and powerful Hibernate Core.
The Hibernate modules can be stacked and combined as desired. You can use the Hibernate Java Persistence provider in any environment, Java SE 5.0 or Java EE 5.0. The Hibernate Java Persistence provider is fully certified and passes the Sun TCK (Technology Compatibility Kit).
The sample application makes use of the following software and technology:
The application uses a Flex front end to perform the following tasks:
The application uses BlazeDS, a server-based Java remoting and Web messaging technology that enables developers to connect to back-end distributed data and push data in real-time to Adobe Flex and Adobe AIR applications. BlazeDS is an open source product. BlazeDS contains configurable channels that transport the data between the client and server. This article uses the Remote Procedure Call (RPC) Services (also called Flash Remoting) and Action Message Format (AMF).
AMF is a binary format for data serialization/deserialization and remote method invocation. It improves performance by dramatically compressing the size of data transferred and parsing binary data into objects in memory far more efficiently than parsing XML data.
This article is written for Java and Flex developers who want to learn more about integrating Flex with Java or vice versa. It follows a very practical approach and guides the reader through all steps needed to create a simple Web application; it includes all the code and configuration settings that are required to deploy and launch the application.
Flex developers will get a better understanding of the back end where the Java code communicates with the database, and Java developers will get a better understanding of the Flex coding in the front end.
Before building the application, install the software listed in the Requirements section.
First, download and install Eclipse, then install Adobe Flex Builder 3 as a plug-in into Eclipse. Because Flex Builder does not include the Java Development Tools, it is installed on Eclipse as a plug-in instead of the standalone version. For more information on installing Flex Builder 3, see Install Flex Builder Plug-in on Windows.
Extract the Tomcat Server file apache-tomcat-6.0.18.zip to the folder C:\ADC.
Create a C:\ADC\mysql folder.
Extract mysql-noinstall-5.0.51b-win32.zip and mysql-connector-java-5.1.6.zip in C:\ADC\mysql.
Also extract the four Hibernate ZIP files to the c:\ADC\hibernate directory as shown below in Figure 1.
Before you develop the application, you need to start MySQL and create a database. You can do this in Eclipse, but it is simple to do at the command prompt.
To start MySQL, open a command prompt window and go to the MySQL directory where you extracted the database files.
cd C:\ADC\mysql\mysql-5.0.67-win32\bin
Execute this command to start the database server:
mysqld --console
Later, if you need to shut down MySQL, execute this command:
mysqladmin -u root shutdown
To create the database, execute the following command at a command prompt while still in the C:\ADC\mysql\mysql-5.0.67-win32\bin directory:
mysqladmin -u root create consultant_db
The name of the newly created database is consultant_db. To verify the database has been successfully created, execute this command:
mysqlshow.exe -u root
After executing the command all databases are listed in the command prompt window. The database table will be generated by Hibernate from the Java bean when the application is run for the first time.
To set up your development environment, begin by starting Flex Builder 3. When the Workspace Launcher dialog box appears (see Figure 2), enter the directory to use for your workspace. For example:
C:\ADC\Workspace
If the Welcome page (see Figure 3) is open when Flex Builder starts, close it and go to the workbench.
As an optional step, you can update the Java Runtime Environment (JRE) to the most recent version. This is not a necessary step; Adobe Flex Builder ships with JRE 1.5.0_11, which will work just as well with the sample application. To do this in Flex Builder, follow these steps:
It helps to create the server runtime before you create the actual project so that you are prepared when the New Project wizard asks you to select a server. Choose Window > Preferences. Next, on the left hand side of the Preferences dialog box click Server then Runtime Environments. Click Add to add a new runtime (see Figure 8).
Expand Apache, select Apache Tomcat v6.0, and click Next (see Figure 9).
Click Browse, browse to the extracted Tomcat directory (in this case, c:\ADC\apache-tomcat-6.0.18), and then click Finish (see Figure 10).
Click OK to close the Preferences dialog box.
To create a new server, right-click in the Servers view of the Java EE perspective and select New > Server. In the New Server dialog box, select Apache Tomcat v6.0 Server and click Next (see Figure 11).
For now, do not add or remove any projects (see Figure 12). You will add the Web application to the Tomcat server later. Click Finish.
Now you are ready to start developing the actual application.
To create your project, switch to the Flex Development perspective and then choose File > New > Flex Project. In the New Flex Project wizard, type ADCDemo for the Project Name. Make sure that the application type is set to Web application, and select J2EE for the application server type. Because the application uses the remote object access service make sure LiveCycle Data Services is selected (this is necessary because you are using BlazeDS).
Finally, select Create combined Java/Flex project using WTP, so you have the Java and the Flex source in one single project (see Figure 13). Click Next.
On the next screen (see Figure 14) ensure the target runtime is set to Apache Tomcat v6.0. The Context root should already be set to ADCDemo. For the Flex War file, browse to the BlazeDS Web application archive (in this case C:\ADC\blazeds-bin-3.0.1.1755\blazeds.war).
On the next screen, verify the Main source folder, Main application file, and Output folder URL are as shown in Figure 15 and click Finish.
After Adobe Flex Builder generates the project, you can see the new project in the Flex Navigator view on the left hand side. The name of the project is ADCDemo and it contains the following folders:
Note: The project setup looks a little different in the Project Explorer view as shown in Figure 16.
The new project wizard has added the relevant BlazeDS JAR files to the project's WebContent\WEB-INF\lib folder as shown in Figure 17.
You will also need to copy a number of Java libraries (JAR files) to the lib folder of the project. These JAR files are required by the sample application to implement the following:
Copy the following JAR files to the target folder (C:\ADC\Workspace\ADCDemo\WebContent\WEB-INF\lib):
C:\ADC\hibernate\hibernate-validator-3.1.0.GA\hibernate-validator.jar
C:\ADC\hibernate\hibernate-entitymanager-3.4.0.GA\hibernate-entitymanager.jar
C:\ADC\hibernate\hibernate-entitymanager-3.4.0.GA\lib\ejb3-persistence.jar
C:\ADC\hibernate\hibernate-entitymanager-3.4.0.GA\lib\test\log4j.jar
C:\ADC\hibernate\hibernate-entitymanager-3.4.0.GA\lib\test\slf4j-log4j12.jar
C:\ADC\hibernate\hibernate-annotations-3.4.0.GA\hibernate-annotations.jar
C:\ADC\hibernate\hibernate-annotations-3.4.0.GA\lib\hibernate-commons-annotations.jar
C:\ADC\hibernate\hibernate-distribution-3.3.1.GA\hibernate3.jar
C:\ADC\hibernate\hibernate-distribution-3.3.1.GA\lib\required\antlr-2.7.6.jar
C:\ADC\hibernate\hibernate-distribution-3.3.1.GA\lib\required\commons-collections-3.1.jar
C:\ADC\hibernate\hibernate-distribution-3.3.1.GA\lib\required\dom4j-1.6.1.jar
C:\ADC\hibernate\hibernate-distribution-3.3.1.GA\lib\required\javassist-3.4.GA.jar
C:\ADC\hibernate\hibernate-distribution-3.3.1.GA\lib\required\jta-1.1.jar
C:\ADC\hibernate\hibernate-distribution-3.3.1.GA\lib\required\slf4j-api-1.4.2.jar
C:\ADC\mysql\mysql-connector-java-5.1.6\mysql-connector-java-5.1.6-bin.jar
After you have copied the files, you should have 27 JAR files in the target directory. When you refresh the project in Flex Builder, the lib folder in the Project Explorer view should show them all (see Figure 18).
Initially the server's context root is not set properly after the project has been created. To change this either open the properties of the Flex project ADCDemo, select Flex Server and change the context root to /ADCDemo or change the serverContextRoot property in the file .flexProperties. To do this open the file .flexProperties in Flex Builder (you can find it in the Flex Navigator view in the root folder of the ADCDemo project) and change the property serverContextRoot to the context root of the Web application ("/ADCDemo"). Replace
serverContextRoot="/WebContent"
with
serverContextRoot="/ADCDemo"
Save and close the file.
The sample application uses the Apache log4j logging utility to log database access. You need an XML configuration file in the Java Source folder named log4j.xml to configure log4j. In the Java source folder create a new file and name it log4j.xml and copy the following code into it.
The source code and the XML files are included in the available ZIP file and the file content can be reused by copy and paste its content or by simply copy the file to the correct location on the file system.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="false" xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{HH:mm:ss.SSS} %-5p %-40.70C{6} %x - %m%n" />
</layout>
</appender>
<appender name="ADC_DEMO" class="org.apache.log4j.RollingFileAppender">
<!-- Change the log path and file name here! -->
<param name="File" value="c:/ADC/logs/adc.log" />
<param name="Append" value="true" />
<param name="MaxFileSize" value="2MB" />
<param name="MaxBackupIndex" value="8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{HH:mm:ss.SSS} %-5p %-40.70C{6} %x - %m%n" /></layout>
</appender>
<appender name="LOG_APACHE" class="org.apache.log4j.RollingFileAppender">
<!-- Change the log path and file name here! -->
<param name="File" value="c:/ADC/logs/apache.log" />
<param name="Append" value="true" />
<param name="MaxFileSize" value="2MB" />
<param name="MaxBackupIndex" value="8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{HH:mm:ss.SSS} %-5p %-40.70C{6} %x - %m%n" />
</layout>
</appender>
<logger name="com.adobe" additivity="false">
<level value="DEBUG" />
<appender-ref ref="ADC_DEMO" />
<appender-ref ref="STDOUT" />
</logger>
<!-- Hibernate -->
<logger name="org.hibernate">
<level value="WARN" />
</logger>
<!-- Apache Commons -->
<logger name="org.apache.commons">
<level value="INFO" />
<appender-ref ref="LOG_APACHE" />
<appender-ref ref="STDOUT" />
</logger>
<!-- Apache Jasper -->
<logger name="org.apache.jasper">
<level value="INFO" />
<appender-ref ref="LOG_APACHE" />
<appender-ref ref="STDOUT" />
</logger>
<!-- Apache Catalina -->
<logger name="org.apache.catalina">
<level value="INFO" />
<appender-ref ref="LOG_APACHE" />
<appender-ref ref="STDOUT" />
</logger>
<!-- Apache Coyote -->
<logger name="org.apache.coyote">
<level value="INFO" />
<appender-ref ref="LOG_APACHE" />
<appender-ref ref="STDOUT" />
</logger>
<logger name="net">
<level value="WARN" />
<appender-ref ref="ADC_DEMO" />
<appender-ref ref="STDOUT" />
</logger>
<!--
DEFAULT: All log message are send to Appender ADC_DEMO and STDOUT.
Log Level Order: DEBUG, INFO, WARN, ERROR, FATAL
-->
<root>
<priority value="DEBUG" />
<appender-ref ref="STDOUT" />
<appender-ref ref="ADC_DEMO" />
</root>
</log4j:configuration>
Save and close the file. When you run the application log4j will create a new directory called logs in the directory c:\ADC and add two log files to it.
When using the JPA implementation of Hibernate you need to configure the entity beans. This is done with an XML configuration file called persistence.xml, which is a standard configuration file in JPA. It has to be included in the META-INF directory inside the classpath of the project or in a JAR file that contains the entity beans. The persistence.xml file must define a persistence-unit with a unique name in the current scoped classloader.
Create a new folder in the Java Source folder and name it META-INF. Create a new file in this folder, name it persistence.xml, and copy the following code into the file:
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="consultant_db">
<properties>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url" value="jdbc:mysql://localhost/consultant_db" />
<property name="hibernate.connection.username" value="root" />
<property name="hibernate.connection.password" value="" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
<property name="hibernate.connection.pool_size" value="6" />
<property name="hibernate.connection.autoReconnect" value="true" />
<property name="hibernate.generate_statistics" value="false" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.use_sql_comments" value="false" />
<property name="hibernate.hbm2ddl.auto" value="update" />
</properties>
</persistence-unit>
</persistence>
The persistence configuration must hold a persistence-unit node. In this case, the name is consultant_db. This name is used by the JPA EntityManager later to access the database described by the properties of the persistence-unit node.
Create a new Java package beneath the Java source folder and name it com.adobe.demo. In the newly created package create a new Java class and name it Consultant (see Figure 19). The Consultant class is the entity bean that defines the structure of an object Consultant. It also contains the annotations (a special form of syntactic metadata) that describe the database relation (here the table including its columns) and some SQL queries.
Copy the following code to the Java class Consultant (Consultant.java).
package com.adobe.demo;
import java.sql.Timestamp;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import org.hibernate.annotations.Index;
@Entity
@Table(name = "consultants")
@NamedQueries( {
@NamedQuery(name = "consultants.findAll", query = "from Consultant"),
@NamedQuery(name = "consultants.byId", query = "select c from Consultant c where c.consultantId= :consultantId") })
public class Consultant {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "consultantId", nullable = false)
private Long consultantId;
@Basic
@Index(name = "ldapName_idx_1")
@Column(name = "ldapName", nullable = true, unique = true)
private String ldapName;
@Basic
@Column(name = "firstName", nullable = true, unique = false)
private String firstName;
@Basic
@Column(name = "lastName", nullable = true, unique = false)
private String lastName;
@Basic
@Column(name = "title", nullable = true, unique = false)
private String title;
@Basic
@Column(name = "created", nullable = false, unique = false)
private Timestamp created;
public Consultant() {
super();
}
public Long getConsultantId() {
return consultantId;
}
public void setConsultantId(Long consultantId) {
this.consultantId = consultantId;
}
public String getLdapName() {
return ldapName;
}
public void setLdapName(String ldapName) {
this.ldapName = ldapName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Timestamp getCreated() {
return created;
}
public void setCreated(Timestamp created) {
this.created = created;
}
}
In the code above, the annotation @Table holds the name of the database table ("consultants") that will be created when the application runs the first time.
Next create the service class that contains the business methods of the demo application. Create a new class named ConsultantService in the package com.adobe.demo. This class contains those methods that are later consumed by the Flex application:
getConsultants: Retrieves all rows from the database table consultants.addUpdateConsultant: Adds or updates a consultant records into the database.deleteConsultant: Deletes a database record from the database.Copy the following code to the Java class ConsultantService (ConsultantService.java).
package com.adobe.demo;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;
import org.apache.log4j.Logger;
public class ConsultantService {
private static final String PERSISTENCE_UNIT = "consultant_db";
private static Logger logger = Logger.getLogger(ConsultantService.class);
public ConsultantService() {
super();
}
public List<Consultant> getConsultants() {
logger.debug("** getConsultants called...");
EntityManagerFactory entityManagerFactory = Persistence
.createEntityManagerFactory(PERSISTENCE_UNIT);
EntityManager em = entityManagerFactory.createEntityManager();
Query findAllQuery = em.createNamedQuery("consultants.findAll");
List<Consultant> consultants = findAllQuery.getResultList();
if (consultants != null)
logger.debug("** Found " + consultants.size() + "records:");
return consultants;
}
public void addUpdateConsultant(Consultant consultant) throws Exception {
logger.debug("** addUpdateConsultant called...");
EntityManagerFactory emf = Persistence
.createEntityManagerFactory(PERSISTENCE_UNIT);
EntityManager em = emf.createEntityManager();
// When passing Boolean and Number values from the Flash client to a
// Java object, Java interprets null values as the default values for
// primitive types; for example, 0 for double, float, long, int, short,
// byte.
if (consultant.getConsultantId() == null
|| consultant.getConsultantId() == 0) {
// New consultant is created
consultant.setConsultantId(null);
consultant.setCreated(new Timestamp(new Date().getTime()));
} else {
// Existing consultant is updated - do nothing.
}
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
em.merge(consultant);
tx.commit();
} catch (Exception e) {
logger.error("** Error: " + e.getMessage());
tx.rollback();
throw new Exception(e.getMessage());
} finally {
logger.info("** Closing Entity Manager.");
em.close();
}
}
public void deleteConsultant(Long consultantId) {
logger.debug("** deleteConsultant called...");
EntityManagerFactory emf = Persistence
.createEntityManagerFactory(PERSISTENCE_UNIT);
EntityManager em = emf.createEntityManager();
Query q = em.createNamedQuery("consultants.byId");
q.setParameter("consultantId", consultantId);
Consultant consultant = (Consultant) q.getSingleResult();
if (consultant != null) {
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
em.remove(consultant);
tx.commit();
} catch (Exception e) {
logger.error("** Error: " + e.getMessage());
tx.rollback();
} finally {
logger.info("** Closing Entity Manager.");
em.close();
}
}
}
}
On the sever side you need to extend a BlazeDS configuration file to enable the Java service to be accessed later from the Flex client. Open the remoting-config.xml file in the project folder WebContent/WEB-INF/flex and overwrite the content with the following:
<?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>
<!-- ADC Demo application -->
<destination id="consultantService">
<properties>
<source>com.adobe.demo.ConsultantService
</source>
</properties>
</destination>
</service>
This adds a new destination block that is identified by the id consultantService and that is linked to the Java service class ConsultantService.
A detailed explanation of the Flex view files is beyond the scope of this article. Adobe Flex Builder provides an integrated help system that explains all aspects of Adobe Flex 3.
To add the Flex code to the flex-src folder of the Flex project, switch to the Flex perspective and create a new hierarchical folder structure in the flex-src folder similar to the Java package as shown in Figure 20.
Copy the following code to the existing MXML file ADCDemo.mxml. This is the main application that loads the view ListConsultants that is created a few steps later.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:view="com.adobe.demo.view.*" backgroundColor="#FFFFFF">
<view:ListConsultants id="listConsultants" />
</mx:Application>
In the vo (value object) folder, create a new ActionScript class and name it Consultant.as. This class defines the client object that holds the consultant information. Please note that the class refers to the appropriate Java class Consultants. Copy the following content to the ActionScript class.
package com.adobe.demo.vo
{
[Bindable]
[RemoteClass(alias="com.adobe.demo.Consultant")]
public class Consultant
{
public function Consultant()
{
}
public var consultantId:Number;
public var ldapName:String;
public var firstName:String;
public var lastName:String;
public var title:String;
public var created:Date;
}
}
The next MXML file is more complex. In the view folder of the Flex source folder, create a file named ListConsultants.mxml and copy the following code into it.
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:view="com.adobe.demo.view.*"
width="100%" height="100%" title="Adobe Demo - Found {consultantRecords} consultants."
creationComplete="loadConsultants();">
<mx:RemoteObject id="loaderService" destination="consultantService"
result="handleLoadResult(event)" fault="handleFault(event)"
showBusyCursor="true" />
<mx:RemoteObject id="deleteService" destination="consultantService"
result="handleDeleteResult(event)" fault="handleFault(event)" showBusyCursor="true" />
<mx:Script>
<![CDATA[
import com.adobe.demo.vo.Consultant;
import mx.controls.Alert;
import mx.managers.PopUpManager;
import mx.containers.TitleWindow;
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
[Bindable]
private var message:String;
[Bindable]
private var consultants:ArrayCollection = new ArrayCollection();
[Bindable]
private var consultantRecords:int = 0;
public function loadConsultants():void {
loaderService.getConsultants();
}
private function deleteConsultant():void {
if(dataGrid.selectedItem != null) {
var selectedItem:Consultant = dataGrid.selectedItem as Consultant;
deleteService.deleteConsultant(selectedItem.consultantId);
}
}
private function createConsultant():void {
var titleWindow:ConsultantForm = ConsultantForm(PopUpManager.createPopUp(this, ConsultantForm, true));
titleWindow.setStyle("borderAlpha", 0.9);
titleWindow.formIsEmpty = true;
}
private function updateConsultant():void {
var titleWindow:ConsultantForm = ConsultantForm(PopUpManager.createPopUp(this, ConsultantForm, true));
titleWindow.setStyle("borderAlpha", 0.9);
titleWindow.consultant = dataGrid.selectedItem as Consultant;
titleWindow.formIsEmpty = false;
}
private function handleLoadResult(ev:ResultEvent):void {
consultants = ev.result as ArrayCollection;
consultantRecords = consultants.length;
}
private function handleDeleteResult(ev:ResultEvent):void {
Alert.show("The consultant has been deleted.",
"Information", Alert.OK, null, null, null, Alert.OK);
loadConsultants();
}
private function handleFault(ev:FaultEvent):void {
message = "Error: "
+ ev.fault.faultCode + " - "
+ ev.fault.faultDetail + " - "
+ ev.fault.faultString;
}
]]>
</mx:Script>
<mx:VBox width="100%" height="100%">
<mx:Label text="{message}" fontWeight="bold" includeInLayout="false" />
<mx:DataGrid id="dataGrid" width="100%" height="100%" dataProvider="{consultants}"
doubleClickEnabled="true" doubleClick="updateConsultant()" >
<mx:columns>
<mx:DataGridColumn dataField="consultantId" headerText="Consultant ID" width="100"/>
<mx:DataGridColumn dataField="ldapName" headerText="LDAP Name" />
<mx:DataGridColumn dataField="firstName" headerText="First Name" />
<mx:DataGridColumn dataField="lastName" headerText="Last Name" />
<mx:DataGridColumn dataField="title" headerText="Title" />
<mx:DataGridColumn dataField="created" headerText="Creation Date" />
</mx:columns>
</mx:DataGrid>
<mx:ControlBar horizontalAlign="center">
<mx:Button label="Create Consultant" click="createConsultant()" toolTip="Create a new consultant and store it in the database." />
<mx:Button label="Update Consultant" click="updateConsultant()" enabled="{dataGrid.selectedItem}" toolTip="Update an existing database consultant." />
<mx:Button label="Delete Consultant" click="deleteConsultant()" enabled="{dataGrid.selectedItem}" toolTip="Delete the consultant from the database." />
<mx:Button label="Reload Data" click="loadConsultants()" toolTip="Reload the consultant list from the database." />
</mx:ControlBar>
</mx:VBox>
</mx:Panel>
The mx:RemoteObject tags contain an id attribute and a destination attribute that is set to consultantService. This is the link to the service defined in remoting-config.xml, which in turn is linked to the appropriate Java service. This is basically the client-side configuration of the service. The Java service methods are called by referring to the id of the remote object followed by the method name of the Java service class. For example, here is the Java method getConsultants called using this command:
loaderService.getConsultants();
In the same view folder, create a file named ConsultantForm.mxml and copy the following code into it. This file represents the Flex view to create and update a consultant data record and it also contains actions to validate the data.
<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:vo="com.adobe.demo.vo.*"
width="100%" height="100%" defaultButton="{submitButton}"
showCloseButton="true" creationComplete="creationCompleteHandler();"
close="PopUpManager.removePopUp(this);"
title="Consultant Form" xmlns:text="flash.text.*">
<mx:RemoteObject id="saveService" destination="consultantService"
result="handleSaveResult(event)" fault="handleFault(event)"
showBusyCursor="true" />
<vo:Consultant id="consultant" ldapName="{ldapNameField.text}"
firstName="{firstNameField.text}"
lastName="{lastNameField.text}"
title="{titleField.text}" />
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
import mx.controls.Alert;
import mx.containers.Canvas;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
import mx.events.ValidationResultEvent;
import mx.validators.Validator;
[Bindable]
private var message:String;
[Bindable]
private var formIsValid:Boolean = false;
[Bindable]
public var formIsEmpty:Boolean;
// Holds a reference to the currently focussed control on the form.
private var focussedFormControl:DisplayObject;
private function handleSaveResult(ev:ResultEvent):void {
clearFormHandler();
validateForm(ev);
Alert.show("Consultant successfully created/updated.",
"Information", Alert.OK, null, null, null, Alert.OK);
// Reload the list.
parentApplication.listConsultants.loaderService.getConsultants();
PopUpManager.removePopUp(this);
}
private function handleFault(ev:FaultEvent):void {
message = "Error: " + ev.fault.faultCode + " \n "
+ "Detail: " + ev.fault.faultDetail + " \n "
+ "Message: " + ev.fault.faultString;
}
public function saveConsultant():void {
saveService.addUpdateConsultant(consultant);
}
private function creationCompleteHandler():void {
PopUpManager.centerPopUp(this);
resetFocus();
}
private function resetFocus():void {
focusManager.setFocus(ldapNameField);
}
// Validate the form
public function validateForm(event:Event):void {
focussedFormControl = event.target as DisplayObject;
formIsValid = true;
// Check if form is empty
formIsEmpty = (ldapNameField.text == "" && firstNameField.text == "" && firstNameField.text == "");
validate(ldapNameValidator);
validate(firstNameValidator);
validate(lastNameValidator);
}
private function validate(validator:Validator):Boolean {
// See also here for validating data:
// /devnet/flex/quickstart/validating_data/
var validatorSource:DisplayObject = validator.source as DisplayObject;
var suppressEvents:Boolean = (validatorSource != focussedFormControl);
var event:ValidationResultEvent = validator.validate(null, suppressEvents);
var currentControlIsValid:Boolean = (event.type ==
ValidationResultEvent.VALID);
formIsValid = formIsValid && currentControlIsValid;
return currentControlIsValid;
}
private function clearFormHandler():void {
// Clear all input fields.
ldapNameField.text = "";
firstNameField.text = "";
lastNameField.text = "";
message = "";
// Clear validation error messages.
ldapNameField.errorString = "";
firstNameField.errorString = "";
lastNameField.errorString = "";
formIsEmpty = true;
formIsValid = false;
resetFocus();
}
]]>
</mx:Script>
<mx:StringValidator id="ldapNameValidator" source="{ldapNameField}" property="text" minLength="2" required="true" />
<mx:StringValidator id="firstNameValidator" source="{firstNameField}" property="text" minLength="2" required="true" />
<mx:StringValidator id="lastNameValidator" source="{lastNameField}" property="text" minLength="2" required="true" />
<mx:Form>
<mx:FormItem label="LDAP Name" required="true">
<mx:TextInput id="ldapNameField" text="{consultant.ldapName}" change="validateForm(event);" />
</mx:FormItem>
<mx:FormItem label="First Name" required="true">
<mx:TextInput id="firstNameField" text="{consultant.firstName}" change="validateForm(event);" />
</mx:FormItem>
<mx:FormItem label="Last Name" required="true">
<mx:TextInput id="lastNameField" text="{consultant.lastName}" change="validateForm(event);" />
</mx:FormItem>
<mx:FormItem label="Title" required="false">
<mx:TextInput id="titleField" text="{consultant.title}" />
</mx:FormItem>
</mx:Form>
<mx:ControlBar horizontalAlign="center">
<mx:Button label="Save Consultant" id="submitButton" enabled="{formIsValid}" click="saveConsultant();" />
<mx:Button label="Clear form" enabled="{!formIsEmpty}" click="clearFormHandler();" />
<mx:Button label="Cancel" click="PopUpManager.removePopUp(this);"/>
</mx:ControlBar>
<mx:Spacer height="10" />
<mx:Text text="{message}" fontWeight="bold" width="300" />
</mx:TitleWindow>
Finally you are done setting up the infrastructure and creating the sample application. Now you can run the application on the Tomcat server and test it in a Web browser.
In the Java EE perspective of Eclipse right click on Tomcat v6.0 Server in the Server view and select Add and Remove Projects. In the Add and Remove Projects dialog box select the Web application ADCDemo from the list of available projects and click Add; then click Finish.
Click the Start the Server button in the Server view and verify the state of the server is "Started". Alternatively, consult the Console view of Eclipse, and look for a message that indicates the server is started, for example:
INFO: Server startup
in 5443 ms
Open a Web browser and enter the following URL to access the sample application:
http://localhost:8080/ADCDemo/ADCDemo.html
It takes a few seconds to generate the database table. Figure 22 shows the application running for the first time.
To create a new consultant record, click Create Consultant and enter the appropriate data. Click Save Consultant to close the window and refresh the data list. The newly created record is then displayed (see Figure 23). You can then add more data records, update existing data records (see Figure 24), and delete data records.
In this article you learned how to build and test a Flex application that connects to a relational database using the Hibernate implementation of the Java Persistence Architecture.
In Part 2 of the series, you'll extend the demo to use linked database relations.
To get a deeper understanding of the technologies used, explore some of the following references:
Flex User Forum |
More |
Flex Cookbook |
More |
| 02/09/2012 | Using Camera with a MediaContainer instead of VideoDisplay |
|---|---|
| 02/08/2012 | Digital Clock |
| 01/20/2012 | Skinnable Transform Tool |
| 12/12/2011 | Date calculations using 'out-of-the-box' functions |