You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-dev@db.apache.org by Guido Anzuoni <ga...@gmail.com> on 2007/09/28 17:16:24 UTC

Access via Proxy: an alternative raw proposal

I have followed to a some extent the discussion about the proxy.
I am not totally convinced that the whole feature cannot be implemented
on top of existing JDO implementations.
More, I see a certain weakness in the proposed approach.
In fact, an application will normally use the proxy but the PM obtained
by issuing a JDOHelper.getPersistenceManager(o) is the real one !!

The purpose is to have a mean to get the PM "current" for the calling
context and the PM should live as long as the context to which is bound.
Something like:
// get it once at application startup
JDOCurrent curr = JDOCurrent.getCurrent(pmf);

// get the current valid pm
PersistenceManager pm = curr.get();

Let's deal with JTA case.
In the JTA case the pm should live for the extent of a single transaction.
The problem here is that JDOCurrent doesn't know when the
all the processing related to the transaction is completed.
A non-solution is to register a Synchronization with the JTA
transaction and close the pm in afterCompletion(). In fact,
it is possible that the JDO implementation might need to register
itself as a Synchronization and it could happen of being called
by the TransactionManager **after** the pm itself has been closed.
A fragile solution is to register a Synchronization with the pm using
pm.currentTransaction().setSynchronization().
In fact, the application might need to set its own Synchronization
object, overwriting the JDOCurrent one.
The enhancement of PersistenceManager to allow
multiple Synchronization will not work in thread-local case (see after).
A solution could be the introduction of an event listener at
PersistenceManager level.
public interface PersistenceManagerListener {
  public void newTransactionBegin(PersistenceManager pm);
  public void transactionCompleted(PersistenceManager pm, int status);
  public void persistenceManagerClosed(PersistenceManager pm);
}

with PersistenceManager interface augmented with

public void addPersistenceManagerListener(PersistenceManagerListener l)
public void removePersistenceManagerListener(PersistenceManagerListener l)

The method transactionCompleted() will be invoked by the
JDO implementation after any internal operation related to transaction
finalization has been performed (i.e., after invoking its
Synchronization object afterCompletion()).
It must be safe for a listener to close the pm in transactionCompleted().

Summarizing the operation
PersistenceManager pm = curr.get();
should do (brand-new txn):
1. get the current transaction from TM
2. get a PersistenceManager from pmf
3. update the map<Transaction, PersistenceManager> bound to the
   pmf the current works for
4. register a Synchronization with the current transaction
   to cleanup the map
5. add a PersistenceManagerListener to close the pm after complete
   finalization of the transaction

In this way, the application always uses the real PersistenceManager
which persistent objects are bound to.

The thread-local case is slightly different.
Here the same "current" pm can be used for multiple transaction.
Its association with the current thread should be removed when the
thread dies (!) or when it is explicitly closed.
Summarizing the operation:
PersistenceManager pm = curr.get();
should do (brand-new thread):
1. get a PersistenceManager from pmf
2. update the map<Thread, PersistenceManager> bound to the
   pmf the current works for
3. add a PersistenceManagerListener remove the binding above
   when persistenceManagerClosed() is invoked.

There is just an open point and it is related to the way the JDOCurrent
could know which is the TransactionManager instance a certain
PersistenceManagerFactory is referring to, but a simple method would
do the job.

Guido