2016/05/28 - Apache Tuscany has been retired.

For more information, please explore the Attic.

 
 Apache Tuscany > Home > Menus > Subproject Menus > DAS Java Subproject Menu > Design Discussions > Transaction Intents and Transaction Manager support User List | Dev List | Issue Tracker  

As this topic involves a lot of discussion thought the better place will be wiki.

I was just thinking randomly to see how to integrate the work in JIRA-1816 with the work
in JIRA-1700(implementation.das support for tx inents/policies). Below are some suggestions I could gather,
but need lot of feedback and ideas.

TransactionManager support in SCA (JIRA-1816)

---------------------------------------------------------------------------------------------------------------------------------
TransactionInfo - can have 2 subclasses - GlobalTransactionInfo (XADataSource...), LocalTransactionInfo (Connection...)
we can rename TransactionInfo to TransactionContext if it suits.

TransactionManager - also can have 2 similar flavours - LocalTransactionManager (what is there in the transaction.zip today)
and GlobalTransactionManager. GlobalTransactionManager can support say a class level annotation - @TransactionManagerFactory(Geronimo)
to have a way to inject an externally available TransactionManager like Geronimo, JOTM etc.
---------------------------------------------------------------------------------------------------------------------------------

Tx Policy Support in implementation.das (JIRA-1700)

----------------------------------------------------------------------------------------------------------------------------------------------
I went through the Tx Policy Draft and trying to understand it in detail. Below trying to give examples of different scenarions
for implementation.das and attempting to analyze just some part from that. Getting lost in different places . Need all possible comments.
I am just gathering all points below, with some discussions can prepare a design doc if that helps.

(RM=Resource Manager) (xads = XADataSource) (xares=XAResource)(conn=connection)(2PC - 2 Phase Commit)
----------------------------------------------------------------------------------------------------------------------------------------------
Note:
a> It is possible that the caller (say junit test case) passes XADataSource(which has Connection and XAResource) OR same can be obtained from
within SCA runtime.
b> At das.implementation level intents can be - managedTransaction.global, managedTransaction.local, noManagedTransaction, (still not clear why to support unqualified managedTransaction)
c> At present, implementation.das does not support oneWayInvocation - so need not consider transactedOneWay and immediateOneWay - is this right assumption?
d> At service level intents can be - propagatesTransaction, suspendsTransaction
----------------------------------------------------------------------------------------------------------------------------------------------
Scenarios:-

CASE1) 1 component - 1 impl - 1 connection info - multiple services - multiple operations/service

so at the time of createInvoker() for a service, the SCArutime can know both the intents (impl and interaction) and decide how to act on it.
i.e. during DASImplementationProvider.createInvoker().

1 impl == 1 RM (multiple Connections/XAConnections).
so multiple services in the same .composite will use the same RM

In DASImplementationProvider(component, impl) we have DASImplementationProvider.createInvoker(service, operation)
One DASImplementationProvider has 1 DataAccessEngineManager. Bue each createInvoker() has a new DASInvoker() with new das
and new DataAccessEngine. So each new invoker() will have a diff das instance.

example

scaDomain = SCADomain.newInstance("company.composite");
dasCompanyService = scaDomain.getService(CompanyService.class, "CompanyComponent/CompanyServiceComponent");

dasCustomerService = scaDomain.getService(CustomerService.class, "CompanyComponent/CustomerServiceComponent");

dasCompanyService.updateCompanies();//RM0 - das0
dasCustomerService.updateCustomers();//RM0 - das1
----------------------------------------------------------------------------------------------------------------------------------------------
CASE2) also there can be - multiple RMs (multiple XAConnections for Tx support for atomic tx, if atomic is not needed can use java.sql.Connections)

scaDomain1 = SCADomain.newInstance("company.composite");
dasCompanyService = scaDomain.getService(CompanyService.class, "CompanyComponent/CompanyServiceComponent");

scaDomain2 = SCADomain.newInstance("customer.composite");
dasCustomerService = scaDomain.getService(CustomerService.class, "CustomerComponent/CustomerServiceComponent");

dasCompanyService.updateCompanies(); //RM1 - das1
dasCustomerService.updateCustomers(); //RM2 - das2
----------------------------------------------------------------------------------------------------------------------------------------------
CASE3) case when at least one das (say das1) instance has a config with managedtx=true (i.e. das manages tx)
In this case the configs and intents of all other das instances are immeterial, because to support managedtx=true (for das1), all others will need
to follow the same mode.
----------------------------------------------------------------------------------------------------------------------------------------------
CASE4) case when non-DBMS RMs are involved

scaDomain1 = SCADomain.newInstance("company.composite");
dasCompanyService = scaDomain.getService(CompanyService.class, "CompanyComponent/CompanyServiceComponent");

scaDomain2 = SCADomain.newInstance("jmscustomer.composite");
jmsCustomerService = scaDomain.getService(jmsCustomerService.class, "jmsCustomerComponent/jmsCustomerServiceComponent");

dasCompanyService.updateCompanies(); //RM1 DBMS
jmsCustomerService.updateCustomers(); //RM2 JMS
--------------------------------------------------------------------------------------------------------------------------------------------------
The Table2 from Tx Policy Draft needs to be considered.

As the knowledge about das.implemnetation intent is at the construction of DASImplementationProvider(), but the knowledge of service level intent
is at DASImplementationProvider.createInvoke() level, createInvoker() is the place which can take decision about tx control.

The ConnectionInfo - finally present inside das (may it be from config.xml or .composite) should be in accordance with what is expected in the
effective intents.

DataAccessImplementationProvider.createInvoker() when calls getDAS() should pass as IN params the effective intents.

When caller wants to pass xads (in case of global tx)/connection (in case of local tx), it needs a way to inject it (i.e. inject tx context) in
the service. Some possible ways -
**All DAS based services - can say mandatorily have a method setTransactionContext(Object ctx) (ctx can be Connection/XADS based on local
or global). This should be invoked by the caller before calling any business method for the service.
**Another way, from JIRA-1816 work - say the caller does
GlobalTransactionContext.setContext(XADS) OR LocalTransactionContext.setContext(Connection).
with this the thread context will have info to be used inside SCA component/services.
DataAccessImplementationProvider will do getContext() and if it is available (i.e. caller did setContext), will pass it to the getDAS(),
so das instance will get Connection during construction.

---------------------------------------------------------------------------------------------------------------------------------------------------
I] propagatesTransaction + managedTransaction.global

MEANING: caller will ideally start tx and pass the tx context to sca runtime. the tx is distributed xa tx.

FLOW:
i) during DataAccessImplementationProvider.createInvoker()

Unknown macro: {das=getDAS()}
, inents will be passed in as well as necessary info from
txn context will be passed in by DataAccessImplementationProvider.
ii) das will get constructed with passing "new" connection to FACTORY.createDAS(). Also set managedtx=false to enalble non-das tx management.

the caller will be responsible to handle the txn (i.e. managed shared global txn pattern)

example

XADS= GlobalTransactionManager.getXADataSource(pass in properties);
GlobalTransactionContext.setContext(XADS tied to XID); //due to threadlocal, this context is referenceable by DataAccessImplementationProvider now.
GlobalTransactionManager.begin(GlobalTransactionContext.getContext());

scaDomain = SCADomain.newInstance("company.composite");
dasCompanyService = scaDomain.getService(CompanyService.class, "CompanyComponent/CompanyServiceComponent");//needs XADS1 tied with same XID

dasCustomerService = scaDomain.getService(CustomerService.class, "CompanyComponent/CustomerServiceComponent");//needs XADS2 tied with same XID

dasCompanyService.updateCompanies();//RM0 - das0
dasCustomerService.updateCustomers();//RM0 - das1

GlobalTransactionManager.commit(context);//see that XID has 2 XADS tied to it and does necessaty actions for 2PC
--------------------------------------------------------------------------------------------------------------------------------------------------
Now for the case that, the caller is not having a ongoing tx and so does not inject tx context in sca runtime.

When DASImplementationProvider detects there is no tx context set , inside createInvoker(), it can first instantiate das without a connection
(some changes needed in tuscany-das-rdb for this), and then use das.getConfig() to get necessary config props and construct a tx context
to be used by the current DASInvoker. Say we create a new DASTransactionCoordinator() for this work.

DASTransactionCoordinator {

GlobalTransactionContext setTxContext(dasConfig)

Unknown macro: { XADS= GlobalTransactionManager.getXADataSource(pass in properties); GlobalTransactionContext.setContext(XADS); //due to threadlocal, this context is referenceable by DataAccessImplementationProvider now. GlobalTransactionManager.begin(GlobalTransactionContext.getContext());//starts tx, this tx will be shared by all invokers. }

//multiple XADS will need to be tied to single xid to make them part of 1 xa tx.
//more methods here for getContext, enqueXAResourceInXID, dqueue XAResource from XID, XID based 2PhaseCommit...
}

and will also pass "new" conection from the tx context to each new das instance.

Also DASImplementationProvider() in this case will need to terminate tx. This can be done in stop() of DASImplementationProvider();
start() can not be used to start a tx as at that time, there is no existing tx context.

Questions:
Now are my confusions. In DASImplementationProvider.stop() what is the way to know whether to commit/rollback? i.e. how stop() method will know about the invoke() having exceptions? Or otherwise each DASinvoker will need access to xid which is shared by all XAResources in the global tx
and the DASInvoker is supposed to call DASTransactionCoordinator.rollback() for case of exception?

Also, this whole story relates to only one RuntimeComponent (i.e. multiple services and multiple operations in each services but all in same
component. Thus the tx can be encompassed by DASImplementationProvider.) What to do for the case when the global tx needs to span multiple
components?
------------------------------------------------------------------------------------------------------------------------------------------------
II] suspendsTransaction + managedTransaction.global
Here even if caller has a tx, it will be ignored and DASImplementationProvider+DASTransactionCoordinator will create a new Tx context and
will manage tx. Same questions as I]
-------------------------------------------------------------------------------------------------------------------------------------------------
III] suspendsTransaction + managedTransaction.local

DASImplementationProvider() will pass DASConfig.connectionInfo() to LocalTransactionManager.getDataSource() and setContext() to get
java.sql.Connection (can be DriverManager or DataSource - in case of DataSource, the external env. is responsible for the JNDI initialization.)
(As local tx, no question of XADS). Same question - how to communicate exception occuring in DASInvoker.invoke() to stop()?
to decide whether to commit/rollback? Also as these are mere Connections and not XID/XADS etc. is it better for the DASInvoker() to control
the commit/rollback of tx? i.e. each DASInvoker() thread will be a Local Tx.
--------------------------------------------------------------------------------------------------------------------------------------------------
IV] suspendsTransaction + noManagedTransaction
this is equivalent to a das config with managedtx=true.

Now say in case, there are das1 and das2 involved from 2 different .composites in a caller's business method
and das1 has IV] / managedtx=true and das2 has I], how will we be able to dectate that , because das1 is das managed tx, das2 should behave in
same way?
-------------------------------------------------------------------------------------------------------------------------------------------------
Also, need to specify behavior for cases when only impl intent is present or only interaction intent is present.

CASE2) and CASE4) in case of I] need the caller to manage tx. If this is not happening, how implementation.das will be able to manage tx
(if there are multiple components involved)

website stats