Border
Author: Bruce Grant, Jr. (BX)
Published: February 13, 2010
Adopting JPA, JSF and JBoss Richfaces
Giving bxgrant.com a face lift - JPA Migration
It's time to move bxgrant.com forward in time with JPA, JSF and JBoss Rich Faces. This article explains how I've begun the effort by migrating to JPA from iBatis and highlites the benefit of clean, simple, enterprise architectures which make doing this piece-meal update possible. Look for future articles on JSF and Richfaces
Of course, no sooner than I finish documenting how my website works, it's time to change it. I've done some big applications using JPA, JSF and Richfaces and every time I switch back to change bxgrant.com I feel a bit of dread at dealing with these older approaches. So, it's time to give it an update.

I have some friends who wonder why I pay so much attention to the architectural and design patterns I use. They feel like it's overkill in today's world. They remark how productive they can be with PHP or Python. I get it. I've spent some time now with Python and I definitely see its benefits and I will still say that there's no substitute for future-proofing the applications you create. You can adopt a scripting language and also have the discipline to maintain a clean separation between the logical tiers of functionality in your application. If you will adopt sound abstractions that physically separate the tiers of your application then you can successfully replace any single piece of your architecture without affecting the other tiers of your application.

In a previous blog entry I documented the architecture of this web site. Perhaps the single most important design decision I made was to separate the functionality into logical groupings and ensure that each tier remained physically distinct from the others. I used the Spring Inversion of Control container to enforce this by only allowing interfaces with no dependencies on any other libraries to be injected into the various tiers that needed access to the functionality from another tier.

It's time to get down to the details of the migration.

Lets start with an architectural diagram of the state of the website before I began changing it.

Application Workflow

  1. Moving to JPA
    First of all, I don't want to migrate the entire site whole-sale. I want to migrate as little as possible, see that it works, deploy it into production and then continue migrating the rest over time. In fact, in this article we're just migrating to JPA. This is possible because of the clean separation of tiers of functionality I spoke about above. If you look at the diagram above, the only code I have to change is in the iBatis ORM layer of the Model/Persistence Tier of logic. The DAO layer doesn't have to change above it and the database I'm using, H2, doesn't have to change below it. Lets explode the Model/Persistence Tier into more detail with a class diagram (I'm leaving out some relationships to keep the diagram clean).
    1. Migration Approach

      Persistence Tier Class Diagram

      Web API Layer
      The web API layer includes an interface which is exposed to the rest of the world. The implementation uses the Facade design pattern to include APIs from various services. The services themselves are injected by Spring. Note that the WebApi concrete implementation doesn't reference a service's implementation class but only its interface class.

      Service Class Layer
      The service layer includes an interface which is used to hide the service implementation. Spring injects the IMainDao data access object class interface into the service implementation class. The service class performs the logic associated with a particular service and its corresponding DAO provides access to the objects that need to be persisted to/from the database. Note again that the actual DAO implementation class remains completely hidden from the service implementation class. How these objects are created and persisted to/from the database remains a detail the service implementation class doesn't need to know about.

      DAO Class Layer
      You'll notice the IMainDao interface is implemented both by the MainDaoIbatisImpl and the MainDaoJpaImpl classes. The MainDaoIbatisImpl class is the old way I was doing object relational mapping. I was using iBatis. Spring injected the SqlMapClientTemplate object into implementation class so it could persist to/from the H2 database.

      Now, I've just begun migrating the first service which is backed by the IMainDao to use Open JPA. For JPA to work, Spring injects the persistence context as the EntityManager member either by direct setter injection or by using an annotation that achieves the same thing. That's it. All I have to do is to tell Spring to inject the MainDaoJpaImpl class into the appropriate Service Class and implement the methods using Open JPA instead of iBatis and it's a done deal!

      You might be wondering about transaction management. Well, it's taken care of thanks to Spring. I've layered transaction management as a higher level construct at the service class layer using Spring. So, when an exception happens in an API that has some iBatis-backed calls and some OpenJPA-backed calls, Spring will rollback across the DAO's backed by the two different ORM technologies. A friend of mine once told me that a sign of a good architecture is that you find that you get features/functionality you didn't expect to get initially for free. This is a very powerful feature to essentially get for "free."
    2. JPA Implementation
      Persistence frameworks share some pretty basic constructs in common so moving from iBatis to Open JPA or Hibernate's JPA isn't very tough. Here are the basics persistence ORM frameworks features:
      1. Map SQL to objects
        The most fundamental feature of ORM frameworks is that they provide some way to map the rows returned from a SQL query into a set of objects. Similarly, they provide a way to perform an insert statement to persist a new object you've created. And lastly, you guessed it, a way to update and delete an object resulting in a SQL update or delete of the corresponding row.

        With JPA, you map a class to a table and the private fields of the class to columns in a database table. You achieve this mapping either with annotations or declaratively with XML. I started migrating the PhotoService so lets take a glance at the Photo domain object that I'll want to persist to/from the database.
        Photo Domain Object
        This annotation specifies that the Photo class is an entity in a database. Some hate all these annotation sprinkled through their domain objects. Remember, all of these annotations could be in a separate XML document if you wanted.
        This annotation specifies that the field below is part of the primary key (or at least uniquely identifies it). You can have multiple fields as part of the key or you could specify a class whose fields are the primary key.
        When the column name in the database doesn't exactly match the field name in your class, you need to provide the mapping yourself.
        JPA provides some pretty sophisticated support for automatically generating an integer value to stick into a key field to act as the ID of that row. By default, JPA will create a database table and to get the next value to use for your table. H2 supports the concept of an "identity" natively so this annotation tells JPA to let the database itself do it.
        The field that will hold the value to put into the column in the database and the field to hold the photo_id column value taken from a row of the table.
        Another field/column mapping.
        This annotation tells JPA to ignore the field beneath it and not attempt to map the field to a column in the database. _numComments is a value I compute at execution time and don't persist for performance reasons.
      2. The DAO Implementation
        Here is the IPhotoDao interface. Of course, I've simplified it to make the example cleaner. The important thing to note is that this interface has absolutely NO dependencies on anything in the persistence tier - not Spring, not JPA and not the database.


        Now, lets get into the JPA implementation of this interface.
        This annotation is similar to declaring to spring that this is a DAO that needs managing. How the repository concept differs from a dao pattern is beyond the scope of this article but google it and you'll find plenty of help. At its most fundamental, this annotation tells Spring to manage the exceptions coming from the class and that it's going to act as a DAO.
        This annotation causes the correct persistence context implementation to be injected into the EntityManager interface. You will use the Entitymanager to interact with the persistence tier to persist, remove and find rows in the database.
        Shows you how to find an object in the database.
        Shows you how to update an object to the database.
        Shows you how to delete objects from the database.
      3. Wiring it all Together
        Now, lets wire it all together with Spring. Here's a stripped down Spring configuration file.
        Sample Spring File
         1<?xml version="1.0" encoding="UTF-8"?>  2<beans xmlns="http://www.springframework.org/schema/beans"  3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  4 xmlns:p="http://www.springframework.org/schema/p"  5 xmlns:context="http://www.springframework.org/schema/context"  6 xmlns:tx="http://www.springframework.org/schema/tx">  7  8 <context:property-placeholder location="classpath:/jdbc.properties" />  9 10 <!-- bean post-processor for JPA annotations --> 11 <context:annotation-config /> 12 13 <!-- Spring will perform dependency injection based on annotations --> 14 <tx:annotation-driven /> 15 16 <!-- Tells Spring to manage exceptions across the persistence layer. --> 17 <bean 18 class="PersistenceExceptionTranslationPostProcessor" /> 19 20 <!-- Registering the DAO implementation bean. --> 21 <bean id="photoDao" class="com.bxgrant.web.dao.PhotoDaoJpaImpl" /> 22 23 <!-- Creating a datasource for hitting the database. --> 24 <bean id="dataSource" 25 class="org.springframework.jdbc.datasource.DriverManagerDataSource" 26 p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" 27 p:username="${jdbc.username}" p:password="${jdbc.password}" /> 28 29 <!-- Creates an entity manager backed by the datasource and OpenJPA. --> 30 <bean id="entityManagerFactory" 31 class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" 32 p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter"> 33 </bean> 34 35 <!-- The transaction manager to use. --> 36 <bean id="transactionManager" 37 class="org.springframework.orm.jpa.JpaTransactionManager" 38 p:entityManagerFactory-ref="entityManagerFactory" /> 39 40 <!-- Creates an OpenJPA instance which we use above. --> 41 <bean id="jpaAdapter" 42 class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter" 43 p:database="${jpa.database}" p:showSql="${jpa.showSql}" /> 44 45</beans>
Tags
       
Comments
Be the first to add a comment.
Add a Comment
User:
Anonymous (Login or Create Account or Help)
Border