You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by Jason Mihalick <ja...@jCraftsmen.com> on 2004/08/19 04:53:28 UTC
A managed version of SequenceManagerHighLowImpl
Armin,
While we are chatting, I have another patch, but I need some advice on
how to finish it off...
I recently finished our upgrade to OJB 1.0. Our producton deployment
environment is Websphere 5.0 on OS/390 and our dev environment is Tomcat
5. One of the things that prompted our upgrade was that we recently
discovered a horrible bug has been in place in our production deployment
since January. The problem was that we were using the
ConnectionFactoryManagedImpl, but we were not using JTA! Not until I
turned on OJB debugging did I realize that the PersistenceBroker calls
to beginTransaction and rollback were having NO EFFECT! After I had a
small heart-attack ;-), I started working on refactoring our code to use
JTA. While working on that refactor, I found this (at
http://db.apache.org/ojb/docu/guides/sequencemanager.html#High%2FLow+sequence+manager):
High/Low sequence manager
...
Limitations:
- do not use in managed environments when connections were
enlisted in running transactions, e.g. when using DataSources of
an application server
Well, unfortunately, we really depend on this sequence manager for one
of our tables so that we can guarantee that a primary key value is NEVER
reused. So, I started looking at what it would take to make this
SequenceManagerHighLowImp JTA friendly and I came up with the attached
subclass. The problem is, however, the attached class has dependencies
from our project's class structure. In particular, I currently depend
on our own JtaTransactionImpl class for fetching the UserTransaction
JNDI name, which varies from AppServer to AppServer. What are your
thoughts about this? Do you have any ideas where in OJB we can store
the JNDI name for the UserTransaction class? I have some other ideas
for this too. If we had a place to keep the JNDI name, then I can also
see a PersistenceBroker Implementation that could use JTA instead of the
PersistenceBroker transaction managment -- OR -- a new API in OJB that
will abstract the transaction manager so that you can easily configure
it to use the PersistenceBroker implementation or the JTA
implementation. This is what I have done in our application ... I have
both a PersistenceBrokerTransactionImpl and JtaTransactionImpl along
with a TransactionFactory to create the proper type of transactions
based on whether we are deployed to Tomcat vs. WebSphere.
What are your thoughts?
Thanks,
Jason
Re: A managed version of SequenceManagerHighLowImpl
Posted by Armin Waibel <ar...@apache.org>.
Hi Jason,
Jason Mihalick wrote:
> Armin,
>
> While we are chatting, I have another patch, but I need some advice on
> how to finish it off...
>
> I recently finished our upgrade to OJB 1.0. Our producton deployment
> environment is Websphere 5.0 on OS/390 and our dev environment is Tomcat
> 5. One of the things that prompted our upgrade was that we recently
> discovered a horrible bug has been in place in our production deployment
> since January. The problem was that we were using the
> ConnectionFactoryManagedImpl, but we were not using JTA! Not until I
> turned on OJB debugging did I realize that the PersistenceBroker calls
> to beginTransaction and rollback were having NO EFFECT! After I had a
> small heart-attack ;-), I started working on refactoring our code to use
> JTA.
yep, when using JTA tx it is not allowed to commit/rollback the
connection, therefore in ConnectionFactoryManagedImpl these methods are
no-op. To use the PB-api in a "normal" consistent way in managed
environments internal calls to PB.beginTransaction/commitTransaction...
are needed (cache handling, resource cleanup, ...), but these methods
also commit/rollback the connection, so we introduce
ConnectionFactoryManagedImpl which use a wrapper class for the
connections with no-op methods.
> While working on that refactor, I found this (at
> http://db.apache.org/ojb/docu/guides/sequencemanager.html#High%2FLow+sequence+manager):
>
> High/Low sequence manager
>
> ...
> Limitations:
> - do not use in managed environments when connections were
> enlisted in running transactions, e.g. when using DataSources of
> an application server
>
> Well, unfortunately, we really depend on this sequence manager for one
> of our tables so that we can guarantee that a primary key value is NEVER
> reused. So, I started looking at what it would take to make this
> SequenceManagerHighLowImp JTA friendly and I came up with the attached
> subclass.
Looks fine! Hope I understand the idea: When this sequence manager SM
was called within a running tx, e.g. an ArticleManagerBean with cm-tx
and we store new Article objects, the SM lookup a UserTransaction, the
SM begin the "new" UserTransaction, so the container should suspend the
running (container managed) tx. SM obtain a new key sequence and commit
the UserTransaction, then the container should resume the suspended tx.
Is this right?
> The problem is, however, the attached class has dependencies
> from our project's class structure. In particular, I currently depend
> on our own JtaTransactionImpl class for fetching the UserTransaction
> JNDI name, which varies from AppServer to AppServer. What are your
> thoughts about this? Do you have any ideas where in OJB we can store
> the JNDI name for the UserTransaction class?
No problem, we can store this information in the
org.apache.ojb.broker.transaction.tm.TransactionManagerFactory
implementation classes (adding new method "UserTransaction
getUserTransaction()" or something similar). Should be easy to
implement, all we need are the JNDI lookup names of the UserTransaction
for all supported appServer/JTA implementations.
> I have some other ideas
> for this too. If we had a place to keep the JNDI name, then I can also
> see a PersistenceBroker Implementation that could use JTA instead of the
> PersistenceBroker transaction managment -- OR -- a new API in OJB that
> will abstract the transaction manager so that you can easily configure
> it to use the PersistenceBroker implementation or the JTA
> implementation.
Think the last suggestion will be great! Separation of the transaction
demarcation methods from the PB interface. Should the new tx handling be
extendable by the top-level api (odmg, jdo)? Or a better approach could
be making listener available to allow top-level api to participate in
tx. I'm not sure how to handle this stuff.
regards,
Armin
> This is what I have done in our application ... I have
> both a PersistenceBrokerTransactionImpl and JtaTransactionImpl along
> with a TransactionFactory to create the proper type of transactions
> based on whether we are deployed to Tomcat vs. WebSphere.
>
> What are your thoughts?
>
> Thanks,
> Jason
>
>
> ------------------------------------------------------------------------
>
> /*
> * Created on Aug 16, 2004
> *
> */
> package org.apache.ojb.broker.util.sequence;
>
> import javax.naming.Context;
> import javax.naming.InitialContext;
> import javax.transaction.Status;
> import javax.transaction.Transaction;
> import javax.transaction.TransactionManager;
> import javax.transaction.UserTransaction;
>
> import org.apache.commons.lang.exception.NestableRuntimeException;
> import org.apache.ojb.broker.PBFactoryException;
> import org.apache.ojb.broker.PersistenceBroker;
> import org.apache.ojb.broker.PersistenceBrokerFactory;
> import org.apache.ojb.broker.metadata.FieldDescriptor;
> import org.apache.ojb.broker.transaction.tm.TransactionManagerFactoryException;
> import org.apache.ojb.broker.transaction.tm.TransactionManagerFactoryFactory;
> import org.apache.ojb.broker.util.logging.Logger;
> import org.apache.ojb.broker.util.logging.LoggerFactory;
>
> import com.aep.appsvcs.util.persist.JtaTransactionImpl;
>
> /**
> * @author s011974
> *
> */
> public class SequenceManagerManagedHighLowImpl extends
> SequenceManagerHighLowImpl {
>
> private static Logger log = LoggerFactory.getLogger(SequenceManagerManagedHighLowImpl.class);
> // private TransactionManager txMan = null;
>
> public SequenceManagerManagedHighLowImpl(PersistenceBroker broker) {
>
> super(broker);
> /*
> try
> {
> txMan = TransactionManagerFactoryFactory.instance().getTransactionManager();
> }
> catch (TransactionManagerFactoryException e)
> {
> throw new PBFactoryException("Can't instantiate TransactionManager of managed environment", e);
> }
> */
> }
>
> // NEW METHOD -- JRM
> protected UserTransaction newTransaction() {
>
> String jndiName = System.getProperty( JtaTransactionImpl.JNDI_USERTRANSACTION_PROPERTY );
> if ( null == jndiName ) {
> throw new NestableRuntimeException( "The property " + JtaTransactionImpl.JNDI_USERTRANSACTION_PROPERTY +
> " has not been set. SequenceManagerManagedHighLowImpl transaction handling will fail. " );
> }
>
> // Now do the lookup to resolve a UserTransaction object
> UserTransaction tran = null;
> try {
> Context ctx = new InitialContext();
> tran = (UserTransaction) ctx.lookup( jndiName );
> } catch ( Exception ex ) {
> throw new NestableRuntimeException( "Failure to acquire UserTransaction " +
> "from JNDI lookup of " + jndiName );
> }
>
> return tran;
> }
>
> protected HighLowSequence getSequence(PersistenceBroker brokerForSequence,
> FieldDescriptor field,
> String sequenceName) throws SequenceManagerException
> {
> HighLowSequence newSequence = null;
> PersistenceBroker internBroker = null;
> UserTransaction tran = null;
>
> try
> {
> internBroker = PersistenceBrokerFactory.createPersistenceBroker(brokerForSequence.getPBKey());
>
> // NEW CODE, USE JTA -- JRM
> tran = newTransaction();
> if ( tran == null ) {
> throw new SequenceManagerException( "Failed to invoke new UserTransaction." );
> }
>
> tran.begin();
> // END NEW CODE
>
>
> newSequence = lookupStoreSequence(internBroker, field, sequenceName);
>
> // NEW CODE, USE JTA -- JRM
> tran.commit();
> // END NEW CODE
>
> if (log.isDebugEnabled()) log.debug("new sequence was " + newSequence);
> }
> catch(Exception e)
> {
> log.error("Can't lookup new HighLowSequence for field "
> + (field != null ? field.getAttributeName() : null)
> + " using sequence name " + sequenceName, e);
> // NEW CODE, USE JTA -- JRM
> if ( tran != null )
> {
> try {
>
> int status = tran.getStatus();
> if ( status == Status.STATUS_ACTIVE )
> {
> tran.rollback();
> }
> } catch ( Exception ex ) {
> log.error( "Error while rolling back HighLowSequence for field "
> + (field != null ? field.getAttributeName() : null)
> + " using sequence name " + sequenceName, ex);
> }
> }
> // END NEW CODE
> throw new SequenceManagerException("Can't build new sequence", e);
> }
> finally
> {
> attempts = 0;
> if (internBroker != null) internBroker.close();
> }
> return newSequence;
> }
>
> }
>
>
>
>
> ------------------------------------------------------------------------
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
> For additional commands, e-mail: ojb-dev-help@db.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org