Hi,
To prepare JBoss to become independent of the
JTA implementation used, I have made some
changes to the current TM and a few other
classes.
Some of these changes were discussed on this
list last year.
The main change is that RemoteMethodInvocation
(RMI) no longer uses a serialized Transaction
instance for passing the transaction context
on remote invocations. Now the transaction
propagation context (TPC) as used in the RMI is
an instance of Object, as this is the most
narrow class that can hold any form of TCP we
may want to use. A nice sideeffect of this is
that we only have one Transaction instance in
the native JBoss TM per transaction.
Two new interfaces are added for import of
TPCs and creating TPCs:
Instances of classes implementing interface
org.jboss.tm.TransactionPropagationContextFactory
knows how to create a TPC from the transaction
currently associated with the calling thread or
a Transaction given as an argument.
Instances of classes implementing interface
org.jboss.tm.TransactionPropagationContextImporter
knows how to create a Transaction from a TPC,
possibly importing the TPC into the TM.
Instances implementing these two interfaces are
added to the java: JNDI namespace.
For the current JBoss TM, these two interfaces
are implemented by our singleton instance of
org.jboss.tm.TxManager. This means that we have
three different JNDI names for the same instance,
implementing different interfaces. The TPC
Factory and Importer interfaces have to be seperate,
as only the factory is available to clients. This
may be handy, as the jboss-client can be thinner
by sending a TPC belonging to some other TM familiy
(ie. OTS), and delegate the job of converting to
the JBoss server (if/when the JBoss server TM knows
how to translate and import that).
Also, the TPC Factory interface can be used for
implementing a UserTransaction that can be used
in stand-alone clients, and that may even work
with the current VM-local TM if the client only
accesses a single JBoss server and the client
does no transactional work in its local VM other
than calling beans in the JBoss server.
Class GenericProxy is changed to have a class
variable referencing an instance of the TPC
Factory. This defaults to null, meaning that no
transaction is propagated. The JRMP container
invoker is changed so that is sets this field
in GenericProxy to an instance found in JNDI,
same as currently done with the TM field.
Class org.jboss.ejb.MethodInvocation is also
changed. A class variable referring to an
instance of the TPC Importer is added. This
will be filled in by an instance the first
time needed. An extra constructor that takes
a TPC is added, and used when the MI is created
from a RMI. Internally in MI, the TX and TPC
are seperate private variables. The method
getTransaction() is changed so that if the TX
is null and the TPC is not null, the TPC Importer
is called to create a TX. This TX is set in the
MI and returned to the caller.
This way, changes are transparent to the container
and its interceptors. Only the container invoker
has to use the new extra constructor when creating
a MI from a RMI.
And this also means that a transaction will *not*
be imported unless it needs to (MI.getTransaction()
called). When we get distributed transactions, the
import can be expensive. Currently, the TX
interceptors call MI.getTransaction() every time,
but changing them to do it only when needed should
be easy.
Another thing that binds JBoss to the current
native TM is the use of the non-JTA methods
associateThread() and disassociateThread. As a
proparation for avoiding these calls, I've
implemented the JTA methods suspend() and
resume(). When JBoss has been changed to use
JTA calls only to the TM, class
org.jboss.tm.TxManager can become package-
private.
When these things are in place, all it takes to
add support for any other TM is:
1) Write a TPC Factory. This should create a
transaction propagation context suitable for
propagating transaction for the TM. For
example, a JTS-based TM would need a TPC of
class org.omg.CosTransaction.PropagationContext.
If transaction propagation is not needed, a
TPC Factory returning null will do.
2) Write a TPC Importer. This should import the
TPC into the local TM (if needed), and return an
instance implementing javax.transaction.Transaction
that represents the transaction in the local VM.
If transaction propagation is not needed, a
TPC Importer returning null will do, but it should
at least warn if given a non-null TPC.
3) Create a MBean for the service. This should
initialize and add the TM, TPC Factory and TPC
Importer into the VM-local JNDI space.
I am currently testing these changes, and unless
anybody have objections or questions, I'll commit
this in a few days.
Best Regards,
Ole Husgaard.