Hibernate in a Layered Architecture

Version 2

    Hibernate in a Layered Architecture

    This page is used to centralize the issues developers have with a layered architecture and Hibernate as the persistence layer. Usually, you have some kind of service layer on top of the persistence layer. But presentation layers on top vary, with individual problems.

    We're talking about the completely decoupled client on this page, not about web-based presentation with Struts running in the same VM as the business facade. Imagine passing persistent objects out-of-process to a client (propably written with Swing and delivered with Webstart). What should be done when the objects come back from the client?

     

    The scope of this includes

    • how to declare the closure of data that can be retrieved by a client (business constraints)
    • how should a client specify what data he wants (graph plans, QBC, HQL)
    • how is data transfered (transport value objects) and how can we have navigation "accross" the cut, i.e., lazy loading of objects once you reach the edges of the loaded graph
    • sending data back from the client to the business layer (possibly bundled with some commands)

    If you need both client/server architecture and a clustered setup on the business/persistence side, go with known EJB patterns (data transfer objects/maps, coarse grained session facade, decouple presentation layer with command pattern). We want a good and clean solution for POJO based systems.

    See also Distributed Objects With Hibernate

    Some thoughts about Distributed Object Frameworks

    Forum Postings


    I've noticed recently that a couple of different threads in this forum have been talking about how to use Hibernate with a strongly structured layered architecture (*).

    A good example is this thread that discusses lazy loading in a layered architecture:

    http://sourceforge.net/forum/message.php?msg_id=2153943

    In one of the posts Todd Jonker wrote:

    "The only solution seems to be to force the higher logic and UI layers to tell the persistence layer exactly what subset of the available data is needed. (Which sounds like a a nightmare!)"

    And Gavin King responded with a post that basically said:

    "but what other possibility _is_ there?? the whole point behind a layered architecture is that you cant access the lowest layer (the db) from the much higher layers (the web tier). In practice, it isn't a nightmare at all."

    I'd like to start a thread discussing practical methods of dealing with this and other issue relating to use of Hibernate with layered architectures.

    Our project uses such an architecture and we have some ways of dealing with these problems, but I'd like to canvass other peoples methods of dealing with these kinds of issues when using Hibernate.

    Cheers,

    Shorn.

    (*) - This thread about Hibernate Vs EJB architecture has a good basic definition of the type of layered architecture I'm referring to:

    http://sourceforge.net/forum/message.php?msg_id=2153579


    Steve Ebersole partially defined his project architecture as:

    "service layer defined as stateless session beans; domain layer defined using Hibernate mappings; data-transfer-objects used to communicate between the service layer and clients." -- Steve Ebersole


    I found the following in the hibernate mailing list:

    http://article.gmane.org/gmane.comp.java.hibernate.devel/1433/

    It describes a solution, where the logic for a lazy loading from client to server is contained in a CGLIB-based interceptor that is added to the "hibernated" objects.


    Steve Ebersole

     

    Just to expand on the architecture I chose (and have briefly and disjunctly discussed on the forum). Let me first suggest a great book on this subject, written by Martin Fowler, entitled "Patterns of Enterprise Application Architecture". It is extremely insightful, helpful and well written.

    It seems that most of the discussion that I have seen on the forums regarding this topic relate to whether the objects mapped in Hibernate should be returned as-is to the clients, or whether some form of abstraction should be used to represent that data (whether XML, DTO, Commands, etc). To me, each approach has pros and cons. In my architecture, I chose the latter using DTOs as the communication medium with the presentation. In brief, my architecture is as follows:

    1. At the bottom tier is a very strong domain layer (mapped using Hibernate). By very strong, I mean that it bundles all the data elements mapped from Hibernate along with a lot of domain logic (see the section discussing business logic vs domain logic in the chapter on the "service layer" pattern in Fowler's book)...
    2. A set of DAOs with static methods for various methods of locating domain objects using HQL or session.load()
    3. A service layer, implemented as session beans for no other reason than for the transaction support as I have to coordinate transactions across JMS, LDAP as well as the DB. This could easily be non-ejb also, possibly using aspects to acheive transaction "cross-cuts".
    4. a set of "assemblers" (again, see Fowler) which are responsible for "molding" domain objects into DTOs and "swizzling" DTO data back into domain objects.
    5. a slew of DTOs which carry data to and from the clients of the service layer.

     

    To me, there are a couple of pros to this type of approach. Number one would have to be the fact that it completely decouples the client from anything that happens behind the service layer, and vice versa. Part of this is not having to worry about things like whether lazy relationships have been loaded when adding a new column to a search result table. Another advantage is that is gives your app a much more defined API feel. The methods exposed on the service layer are the functionality provided by the system to the outside world. And because a lot of the "nitty-gritty" code is hidden away in the DAOs and the assemblers, the service code is very clean. An example would be:

    public ContactDTO loadContact( Long contactId )
    throws my.PersistenceException
    {
        prepareCall();
        try
        {
            return ContactAssembler.buildDTO( ContactDAO.load( contactId ) );
        }
        catch( Exception e )
        {
            throw new my.PersistenceException( "Unable to load contact", e );
        }
        finally
        {
            endCall();
        }
    }
    

     

    The cons mainly deal with the fact that that's a lot of extra classes to code. At a minimum, in a small app, you can assume about a one-to-one correspondence between the domain objects in your app and their various DTO representations; this may be even bigger for larger apps. Why? Mainly it has to do with relationships and avoiding infinite loops. Consider a ContactDTO with a relationship to a CompanyDTO, which in turn has a collection relation to its employees which are ContactDTOs. This is normally handled by having different DTO representations of data with different "loading levels" (similiar to the Lightweight pattern discussed on the Hibernate patterns page). Thus, you now would have something like ContactDTO -> CompanyDTO -> ContactListDTO. And thats not even considering specialty DTOs like report DTOs, etc. Its hopefully pretty easy to see how this can become a lot of extra classes. Luckily, all these DTOs are pretty brainless to create as they are generally very simple Java Beans.