Member Menu
 
 Monthly JBoss newsletter:
 
Java Persistence with Hibernate
CaveatEmptor

Distributed Objects With Hibernate

Problem:

You are building a three tier distributed system and you are passing persistent objects between tiers. When you send the objects back to the server, you want to save the only the changes.

Solutions:

1)Hibernate added the select-before-update option in 2.1. Setting this option on your class will cause Hibernate to load the data from the database and compare that to the data in your object to determine what has changed. It makes use of a version or timestamp field to enforce optimistic concurrency. This works well but introduces additional database access that could effect performance.

2)Save the original data for each persistent object and implement a custom EntityPersister to return the original state to Hibernate instead of accessing the state in the database.

Implementing Solution 2:

Step 1: Save the original state for each persistent object

The easiest way to implement this is to have each persistent object remember the original values of any properties that changed. If you make all your persistent objects proper JavaBeans, you can capture this in the base class when the object fires a propertyChanged event:

public abstract class AbstractDomainObject implements Serializable {

  private PropertyChangeSupport support = new PropertyChangeSupport(this);

  private Map originalValues = new HashMap();

  public AbstractDomainObject() {
    super();
  }

  public Map getOriginalState() {
    return originalValues;
  }

  public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener) {
    support.addPropertyChangeListener(propertyChangeListener);
  }

  protected void firePropertyChange(String property, Object oldValue, Object newValue) {
    if (!originalValues.containsKey(property)) {
      originalValues.put(property, oldValue);
    }
    support.firePropertyChange(property, oldValue, newValue);
  }

}

Step 2: Create your domain objects

A domain object might look like follows. Because it fires propertyChange events, the base class will remember original values of properties that changed. Note that you will want to map the properties as access=field since the setter fires a propertyChange event when called.

public class Customer extends AbstractDomainObject {

  private String name;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    String oldValue = this.name;
    this.name = name;
    firePropertyChange("name", oldValue, name);
  }

}

Step 3: Create a custome entity persister

Create a custom entity persister and override getCurrentPersistentState. Set the persister for each class to this custom persister.

public Object[] getCurrentPersistentState(Serializable id, Object version, SessionImplementor session) throws HibernateException {
  AbstractDomainObject entity = (AbstractDomainObject) session.getEntity(new Key(id, this));
  Map originalValues = entity.getOriginalState();
  Type[] types = getPropertyTypes();
  String[] propertyNames = getPropertyNames();
  Object[] values = new Object[propertyNames.length];
  boolean[] includeProperty = getPropertyUpdateability();
  for (int i = 0; i < propertyNames.length; i++) {
    if (includeProperty[i]) {
      if (originalValues.containsKey(propertyNames[i])) {
        values[i] = types[i].disassemble(originalValues.get(propertyNames[i]), session);
      } else {
        values[i] = types[i].disassemble(getPropertyValue(entity, propertyNames[i]), session);
      }
    }
  }
  return values;
}

What about collections you ask? Well, Hibernate keeps track of changes to collections in the collection class wrappers for you.

Please note this solution has worked great in my example programs, but I have not yet implemented it in a production program.


  NEW COMMENT

How to know then that entity has become stale? 12 Dec 2003, 20:34 vijpan
In case of optimistic concurrency if you dont access the database how 
can you be sure that you are not trying to update the stale data?
 
Re: How to know then that entity has become stale? 13 Dec 2003, 03:18 gavin
On 12 Dec 2003 20:34, vijpan wrote:

>In case of optimistic concurrency if you dont access the database how
>can you be sure that you are not trying to update the stale data?

Hibernate does a version number or timestamp check in the SQL UPDATE.
This is standard Hibernate functionality.
 
Re: How to know then that entity has become stale? 15 Dec 2003, 17:56 vijpan
On 13 Dec 2003 03:18, gavin wrote:

>On 12 Dec 2003 20:34, vijpan wrote:

>>In case of optimistic concurrency if you dont access the database
how 
>>can you be sure that you are not trying to update the stale data?

>Hibernate does a version number or timestamp check in the SQL UPDATE.
>This is standard Hibernate functionality.

Dear Gavin
My comment on optimistic concurrency was referring to the solution# 1 
provided in this article.I knew about this Hibernate functionality of 
version number or timestamp check.
The author of the article  stated the fact as below.

1)Hibernate added the select-before-update option in 2.1. Setting 
this option on your class will cause Hibernate to load the data from 
the database and compare that to the data in your object to determine 
what has changed. It makes use of a version or timestamp field to 
enforce optimistic concurrency. This works well but introduces 
additional database access that could effect performance.

So with the hibernate facility there will be 2 calls for an update if 
we have (verion number or timestamp) set.Or the hibernate does that 
within 1 call i.e. if ther version number or timestamp doesnt match 
with the record in the database it gives back the error or else 
updates it.

Whether Hibernate does it in 1 call or 2 calls we have to make sure 
that we are not writing over the stale data and for that there will be 
a call(1 or 2) to DB to check that.
 
well ther is a little bug here 27 Jul 2004, 20:47 tetrione
if user changes original value and then changes it back to the 
original value within the same transaction, the originalValue map has 
to be updated accordingly.

Otherwise it is pretty cool; it will help a lot with graph merges when 
I finally get a chance to implement it :-)

Thanks,
Alex
 
original forum thread is here 05 Oct 2004, 23:51 gschrader
http://forum.hibernate.org/viewtopic.php?t=926083
 
for Hibernate 3 29 Oct 2004, 00:26 gschrader
getCurrentPersistentState was renamed to getDatabaseSnapshot
 
Remote lazy loading 03 Nov 2005, 17:07 mmcgovern
I'd like to add value.

Yes every month someone does suggest that Hibernate should be able to 
do remote lazy loading. And the arguments against are valid.

However I think that we need to look at this as a challenge. Look how 
far we have come in the last 10 years with Java and ORM.


If I have a tiered platform with the client co-located with the 
server, things work nicely. But what if I need to move the client tier 
into a DMZ. I'd like to NOT have to make drastic changes to my 
application.

There must be solutions to this because people are hand coding such 
things. What about an extension framework that supports a number of 
the most common, manually coded solutions. Optimistic locking is an 
example of a solution to a problem where you have made some tradeoffs. 
I'm sure there are a few solutions to this problem, with trade offs 
that many people would be willing to make - to get the benefits that 
come with it.
 
Re: Remote lazy loading 05 Nov 2005, 06:34 mmcgovern
POST QUESTIONS ON THE FORUM! COMMENTS HERE SHOULD ADD VALUE TO THE 
PAGE!On 03 Nov 2005 17:07, mmcgovern wrote:

>I'd like to add value.

>Yes every month someone does suggest that Hibernate should be able to
>do remote lazy loading. And the arguments against are valid.

>However I think that we need to look at this as a challenge. Look how
>far we have come in the last 10 years with Java and ORM.


>If I have a tiered platform with the client co-located with the
>server, things work nicely. But what if I need to move the client
tier 
>into a DMZ. I'd like to NOT have to make drastic changes to my
>application.

>There must be solutions to this because people are hand coding such
>things. What about an extension framework that supports a number of
>the most common, manually coded solutions. Optimistic locking is an
>example of a solution to a problem where you have made some
tradeoffs. 
>I'm sure there are a few solutions to this problem, with trade offs
>that many people would be willing to make - to get the benefits that
>come with it.

So I've got a client tier in the DMZ, therefore the although I'll need 
long-running session in the server tier it still corresponds to a UI 
event. All I need is for some AOP/CGLIB smarts in the client to talk 
to a SFSB to start/end my transaction and for all other session bean 
calls from my client to let the server-side CMT know about this 
special SFSB. In a read-only environment this would work - and even if 
I change things the magic AOP/CGLIB can let the SFSB know and it can 
handle things.

This can work - at least for this special case - but its a start. Can 
anyone make this happen?
 
Extra benefits for rich-client apps 29 Mar 2007, 16:23 pcentgraf
Implementing "beans with history" as this page suggests will have extra
benefits for rich-client applications.  If a bean can compute its own
dirty state, the UI in the client can use this to enable/disable
features like the "save" command and can prompt to save before closing a
window containing dirty state.  A client app can also provide feedback
when a user has performed "undo" enough to reset the window to its
original state or manually resets the original values.
 
© Copyright 2006, Red Hat Middleware, LLC. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc. [Privacy Policy]