7.4. A Rudimentary Approach to Integration with JPA and Hibernate

Let me start with an effortless but a limited way to integrate Flex and JPA/Hibernate. This time, the sample application that maintains a list of open source software products and its contributors will have a Flex interface.

7.4.1. Setting Up

To create this project, I leverage the facility to create a joint Flex and Java WTP project in Eclipse. Here are the steps that you need to follow:

  • Using the Flash Builder plug-in for Eclipse-with WTP, first create a new Flex Project. You will be prompted with a screen as in Figure 7-10.

Give your project a name. I call it FlexOSSCatalog. Choose a J2EE server type and opt to create a joint Java/Flex project using WTP. Also select a LifeCycle Data Services (LCDS) remote object service type. Although it reads LCDS, the settings work just fine for BlazeDS as well.

  • On clicking Next, a new screen is presented to you. This new screen allows inputs for J2EE settings, compilation options, and the output directory. Figure 7-11 shows the details. I selected JBoss AS 4.2 as the deployment environment and point to blazeds.war version 3.2.0.3978 archive file as the Flex WAR file.

    Figure 7.10. Figure 7-10

    Figure 7.11. Figure 7-11
  • Finally edit and confirm the source folder name, main application filename, and output folder URL, and click the Finish button to create the project. Figure 7-12 depicts what this last Project Creation Wizard screen looks like.

Figure 7.12. Figure 7-12

On creation, your project structure should have the following files and folders at its root:

  • .settings—Eclipse project-specific configuration.

  • bin-debug—Compiled Flex application resides here.

  • flex_libs—Folder for referenced .swc files.

  • flex_src—Flex source folder.

  • html-template—Folder that contains wrappers for the Flex application.

  • src—Java source folder.

  • WebContent—Folder that contains the content that finally gets packaged as a WAR file and gets deployed in an application server or a Servlet container.

  • .actionScriptProperties—ActionScript 3 (AS3) properties for the Flex SWF and SWC compilers, namely mxmlc and compc.

  • .classpath—The classpath that specifies the Eclipse modules on the Java classpath.

  • .flexProperties—Flex project–specific properties. Open this file and change the serverContextRoot="/WebContent" to serverContextRoot="/<Your project name>", which in our case becomes serverContextRoot="/FlexOSSCatalog".

  • .project—Eclipse project properties file.

A MySQL instance and a database called oss_catalog_db were created earlier in the section titled "Introducing JPA." You can reuse the same database. Remember to start the instance before you start interacting with it.

In addition, it's assumed here that:

  • The required JPA and Hibernate JAR files are downloaded and available.

  • A JBoss AS 4.2 server environment is preconfigured in Eclipse.

All of these were discussed in the section titled "Introducing JPA." You may want to look back at that section if you are unsure about the steps involved.

At this stage, add a few additional JAR files to your project classpath. This can be done by adding them to the WebContent/WEB-INF/lib folder. These JAR files must include the following:

  • Hibernate JPA implementation

  • A log4j-based logging facility

  • The MySQL JDBC driver

The list of additional JAR files, beyond the ones added by BlazeDS, is:

  • hibernate-entitymanager.jar (part of Hibernate-EntityManager GA 3.4.0.GA, abbreviated as HEM 3.4.0.GA for the rest of this list. It can be downloaded from www.hibernate.org/6.html).

  • dom4j.jar (lib folder of HEM 3.4.0.GA).

  • ejb3-persistence.jar (lib folder of HEM 3.4.0.GA).

  • hibernate-annotations.jar (lib folder of HEM 3.4.0.GA).

  • hibernate-commons-annotations.jar (lib folder of HEM 3.4.0.GA).

  • hibernate-core.jar (lib folder of HEM 3.4.0.GA).

  • javassist.jar (lib folder of HEM 3.4.0.GA).

  • jta.jar (lib folder of HEM 3.4.0.GA).

  • slf4j-api.jar (lib folder of HEM 3.4.0.GA).

  • hibernate-validator.jar (part of Hibernate-Validator 3.1.0.GA. It can be downloaded from www.hibernate.org/6.html).

  • log4j.jar (The latest version of Apache log4j is 1.2.15. Can be downloaded from http://logging.apache.org/log4j/1.2/download.html).

  • slf4j-log4j12.jar (a simple logging facade for Java; more details are available at www.slf4j.org).

  • antlr-2.7.6.jar (ANTLR parser generator. More details at www.antlr.org).

  • mysql-connector-java-5.1.17-bin.jar (download it from www.mysql.com/products/connector).

At this stage most of the initial setup is complete. Let's start programming the Flex and JPA/Hibernate application.

7.4.2. Programming the Flex and JPA/Hibernate Application

As a first step, create the persistence.xml file and copy it over to a folder called META-INF within the Java src folder. For the first time, you will need to create the META-INF folder. The contents of persistence.xml can be the same as shown earlier in Listing 7-2.

In the Java source folder, create the entities: OSSProduct and Contributor. The classes can be the same as defined in the section titled "Introducing JPA." The OSSProduct class is also illustrated in Listing 7-1.

At this stage, your project should look like the screenshot shown in Figure 7-13.

Figure 7.13. Figure 7-13

Next, create a service class that helps connect Flex to the persistence layer. Listing 7-5 includes the contents of this service class. Then configure the service class as a remote object destination. Configuring the service class as a remote destination is straightforward. Hopefully, it is something that you are familiar with by now. Just add the following lines to flex/remoting-config.xml:

<destination id="oSSProductService">
    <properties>
        <source>problazeds.ch07.OSSProductService</source>
    </properties>
</destination>

The remoting-config.xml, which is part of services-config.xml, has an AMF-based channel and a Java adapter defined by default. The configured oSSProductService destination uses the default AMF channel and the Java adapter.

Example 7.5. OSSProductService.java
package problazeds.ch07;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class OSSProductService
{

    public OSSProductService() {

    }

    public List<OSSProduct> getOSSProducts() {

        EntityManagerFactory entityManagerFactory =
            Persistence.createEntityManagerFactory(FlexOSSCatalogConstants.
               PERSISTENCE_UNIT);

        EntityManager em = entityManagerFactory.createEntityManager();

        Query findAllQuery = em.createNamedQuery("ossproducts.findAll");
        List<OSSProduct> ossproducts = findAllQuery.getResultList();

        return ossproducts;

    }

    public void createOrUpdateOSSProduct(OSSProduct oSSProduct) {

        EntityManagerFactory emf =
            Persistence.createEntityManagerFactory(FlexOSSCatalogConstants.
               PERSISTENCE_UNIT);

        EntityManager em = emf.createEntityManager();

        if (oSSProduct.getOSSProductId() == 0) {
            oSSProduct.setOSSProductId(0);
        }

        EntityTransaction etx = em.getTransaction();
        etx.begin();
        try {
            em.merge(oSSProduct);
            etx.commit();
        } catch (Exception e) {
            etx.rollback();
        } finally {
            em.close();
        }
    }

    public void deleteOSSProduct(int oSSProductId){

EntityManagerFactory emf =
                Persistence.createEntityManagerFactory(FlexOSSCatalogConstants.
                   PERSISTENCE_UNIT);

        EntityManager em = emf.createEntityManager();

        Query findByIdQuery = em.createNamedQuery("ossproducts.findById");
        findByIdQuery.setParameter("oSSProductId", oSSProductId);
        OSSProduct oSSProduct = (OSSProduct)findByIdQuery.getSingleResult();

        if (oSSProduct != null) {
            EntityTransaction etx = em.getTransaction();
            etx.begin();
            try {
                em.remove(oSSProduct);
                etx.commit();
            } catch (Exception e) {
                etx.rollback();
            } finally {
                em.close();
            }
        }
    }


}

The JPA/Hibernate code is ready and is wired up for consumption by a Flex client. Last of all, let's create a simple Flex client to interact with it.

In this Flex client, the main view contains a pair of data grids. The main or parent data grid contains the collection of OSS products. An associated child data grid contains the collection of contributors, each time making visible only those that are related to the selected OSS product in the parent data grid.

In addition to the two data grids, there is a view that brings up a form to enter details of an OSS product. This provides a way to edit OSS products and add them to the data store.

The sources for the two main data grids are:

<mx:DataGrid id="parentDataGrid"
            dataProvider="{oSSProducts}"
            rowCount="8"
            editable="true"
            resizableColumns="true"
            itemClick="itemClickEventHandler(event);">
    <mx:columns>
        <mx:DataGridColumn headerText="Name" dataField="name" />
        <mx:DataGridColumn headerText="License Type" dataField="licenseType" />
    </mx:columns>
</mx:DataGrid>

<mx:DataGrid id="childDataGrid"
            dataProvider="{}"
            rowCount="8"

editable="true"
            resizableColumns="true">
    <mx:columns>
        <mx:DataGridColumn headerText="Name" dataField="name" />
        <mx:DataGridColumn headerText="Role" dataField="role" />
    </mx:columns>
</mx:DataGrid>

The source for the form is:

<mx:Form width="100%" height="80%" id="ossProductsForm">
    <mx:FormItem label="Name:" id="name_form">
        <mx:TextInput id="name_TextInput" text=""/>
    </mx:FormItem>
    <mx:FormItem label="License Type:" id="license_type_form">
        <mx:TextInput id="licenseType_TextInput" text=""/>
    </mx:FormItem>
</mx:Form>

All of the four CRUD operations (create, read, update, and delete) can be accomplished with the help of functions that invoke the corresponding server-side service methods via a remote object handle. The AS3 functions in scripts/flexOSSCatalogScript.as are as follows:

private function loadAllOSSProducts():void {
        remoteOSSPService.getOSSProducts();
    }

    private function deleteOSSProduct():void {
        if(parentDataGrid.selectedItem != null) {
            var selectedItem:OSSProduct = parentDataGrid.selectedItem as OSSProduct;
            remoteOSSPService.deleteOSSProduct(selectedItem.oSSProductId);
        }
    }

    private function addOSSProduct():void {
        applicationScreens.selectedChild = update;
    }
    private function updateOSSProduct():void {
        applicationScreens.selectedChild = update;
        if(parentDataGrid.selectedItem != null) {
            var selectedItem:OSSProduct = parentDataGrid.selectedItem as OSSProduct;
            name_TextInput.text = selectedItem.name;
            licenseType_TextInput.text = selectedItem.licenseType;
        }
    }

The main view with the two data grids and the second view with a form are put together in a ViewStack. Navigation is accomplished between the two views as a result of appropriate button clicks, whose click handlers select the appropriate ViewStack child component.

All the communication between the Flex client and the persistence layer is accomplished through the remoting service. The remote object that acts as the proxy for the service on the client side defines result handlers for each of the service methods to handle the results appropriately. The source is:

<mx:RemoteObject
        id="remoteOSSPService"
        destination="oSSProductService">

        <mx:method name="getOSSProducts" result="loadAllResultHandler(event)"
            fault="mx.controls.Alert.show(event.fault.faultString)"/>
        <mx:method name="createOrUpdateOSSProduct"
            result="createOrUpdateResultHandler(event)"
            fault="mx.controls.Alert.show(event.fault.faultString)"/>
        <mx:method name="deleteOSSProduct" result="deleteResultHandler(event)"
            fault="mx.controls.Alert.show(event.fault.faultString)"/>
    </mx:RemoteObject>

When the results come back from the server-side service, the output is cast into appropriate strongly typed objects, which are counterparts of the server-side Java POJOs. This simple application has two such objects: OSSProduct and Contributor.

Build and deploy the application and you are up and ready with a Flex and JPA/Hibernate-based CRUD application. This was simple, and even if it involved a few steps, it didn't seem extremely complex. Why then is the much talked about lack of off-the-shelf support for JPA and Hibernate with BlazeDS such a problem? This solution did not involve any special adapters or such!

The answer to this question is not a tricky puzzle. However, instead of stating it right up front, let me ask you a question: if you were to load a large number of related entities and hardly navigate through the entire interconnected network, which is probably often the case, would you still want to load everything eagerly? Probably not; after all, you desire good performance and resource optimization.

With this naïve approach, you do not leverage the lazy loading and effective relationship management features of JPA and Hibernate. Also, you set yourself up for possible exceptions, which are thrown when there are attempts to access referenced objects that are still not initialized. In the next section, I enlist some of these and put together an expected set of features for Flex and JPA or Hibernate integration.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.250.203