db-ojb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Charles Anthony <charles.anth...@hpdsoftware.com>
Subject OJB Proxies
Date Thu, 16 Sep 2004 08:09:33 GMT
Hi All,

I have an "itch" I think I need to scratch, and I'd like some pointers. 

Our domain objects (AKA persisent objects) are plain-old-java-objects, and
they do *not* have interfaces defining their operations. This means that we
cannot implement dynamic (or virtual) proxies in OJB for single
relationships (we can and do for collections). There are over 1000
persistent classes (and rising, slowly) and it is not practical to
retrospectivel introduce them.

Instead, we "simulate" proxies by doing lazy-loading in the getter methods.
For instance : 

class Agreement {
   AgreementType agreementType;
   BigInteger agreementTypeId;

  public AgreementType getAgreementType(){
     RelationshipHelper.lazyLoad(this, "agreementType");
     return agreementType;
  }
}

RelationshipHelper.lazyLoad simply checks to see if the named attribute is
null, and if so, invokes pb.refreshRelationship(...). (All
reference-descriptors have auto-load=false)

Kludgy ? Yes. Does it work ? Yes. Just about.

However (and you knew one was coming, didn't you), when we lock an object to
an ODMG transaction, it is necc. to force all the single relationships to be
loaded, in order that the PB layer can propogate the correct foreign keys.
In our light-ish layer above OJB, we do this :
...
public static void lockObject(Object o, int lockType, long timeout) {
    if (isBegun()) {

      boolean lockAcquired = false;
      if (lockType == WRITE) {
        loadSingleRelationships(o);
      }
...

This works. The downside is that we are doing loads of unecessary queries
which obv. has a negative impact on performance .


So...


I had a brainwave - could I use CGLIB to dynamic generate proxies for our
classes ? (I believe Hibernate does this). The simple answer is "Yes" -
although in practice it isn't simple. Firth thing yesterday morning, I
downloaded CGLIB for the first time, and by lunchtime I had created an
OJBProxyGenerator (which created a class subclassing the specified domain
class, and that routed all method calls to an OJB IndirectionHandler.
Coooool (well, I thought so. We need to intercept field access too, but it
seems that CGLIB can do that as well - even if it is a bit trickier - so I
skipped it). It fried my brain, and is a big mess, but I thought I'd done
the hard bit.

I then spent the afternoon trying to plug the OJBProxyGenerator stuff into
OJB itself. This is were I got very  confused. In the end, I managed to have
some kind of integration - basic steps were these :

1. Introduced a simple interface OJBProxy (pretty much mirroring the methods
on VirtualProxy)

public interface OJBProxy {

  public void setIndirectionHandler(IndirectionHandler handler);
  public IndirectionHandler getIndirectionHandler();
  /**
   * Determines whether this proxy already has been materialized.
   *
   * @return <code>true</code> if the real subject already been loaded
   */
  public boolean alreadyMaterialized();

  /**
   * Returns the proxies real subject. The subject will be materialized if
necessary.
   *
   * @return The subject
   */
  public Object getRealSubject() throws PersistenceBrokerException;

  Identity getIdentity();
}

2. Modified VirtualProxy.createProxy to use my OJBProxyGenerator if the
proxyClass on the class-descriptor was the OJBProxy class :

public static Object createProxy(PBKey key, Class proxyClass, Identity
realSubjectsIdentity) {
    try {
      if (proxyClass.equals(OJBProxy.class)) {
        return OJBProxyHelper.createProxy(key, realSubjectsIdentity);
      } else {
        // the invocation handler manages all delegation stuff
        Indire
...

3. Modify ProxyHelper.getRealObject, ProxyHelper.getRealClass etc to
recognise and use the new proxy.

4. Modified all reference-descriptors to be auto-load=true, proxy=true

Good News : all single relationships were CGLIB Proxies. Woo Hoo !

Bad news : All OJB Queries appeared to return proxies. 

For example, if I did a QueryByCriteria for all Agreements (as above) the
materialized objects were proxies. This is bad for two reasons :
a) If I did a query returning 5 objects, and iterated the collection, this
would results in 6 queries (one for each proxy). Bad.
b) More importantly, for me,  this caused ClassCast exceptions in some part
of our application (too long-and-complex to explain right now)

So, in essence, how can I ensure that proxies are generated for the
references, and not for direct queries ? Or, turn it around, how and where
should I integrate this new proxying code ?

As ever, if this would be useful to anyone else and if I get anywhere with
this - and it's entirely possible I won't - I am very willing to contribute
the code back to OJB.

Thanks for reading to the end. This message will self destruct in 10
seconds. As will my brain.

Cheers,

Charles.


___________________________________________________________
HPD Software Ltd. - Helping Business Finance Business
Email terms and conditions: www.hpdsoftware.com/disclaimer 



---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org


Mime
View raw message