Weird, the copy I sent to myself did contain the files. I'm inlining them in the mail body.
-Alejandro --- AbstractService.java --- /* * $Header$ * $Revision$ * $Date$ * * ==================================================================== * * Copyright 1999-2002 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.slide.common; import java.util.Hashtable; import java.util.Vector; import java.util.Arrays; import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; import org.apache.slide.transaction.SlideTransactionManager; /** * Slide Service abstract implementation with support for multiple * simultaneous transaction context. * * @version $Revision$ */ public abstract class AbstractService extends AbstractServiceBase implements Service { // -------------------------------------------------------------- Constants public static final int TX_IDLE = 0; public static final int TX_PREPARED = 1; public static final int TX_SUSPENDED = 2; // ----------------------------------------------------- Instance Variables /** * Current transaction context. */ protected Hashtable currentContexts = new Hashtable(); // ----------------------------------------------------- XAResource Mathods /** * Commit the global transaction specified by xid. * * @param xid A global transaction identifier * @param onePhase If true, the resource manager should use a one-phase * commit protocol to commit the work done on behalf of xid. * @exception XAException An error has occurred. Possible XAExceptions * are XA_HEURHAZ, XA_HEURCOM, XA_HEURRB, XA_HEURMIX, XAER_RMERR, * XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO. If the resource * manager did not commit the transaction and the paramether onePhase is * set to true, the resource manager may throw one of the XA_RB* * exceptions. Upon return, the resource manager has rolled back the * branch's work and has released all held resources. */ public void commit(Xid xid, boolean onePhase) throws XAException { ContextTuple currentContextTuple = (ContextTuple) currentContexts.get(Thread.currentThread()); Xid currentContext = currentContextTuple!=null?currentContextTuple.getXid():null; if (currentContext == null) throw new XAException(XAException.XAER_NOTA); if (xid == null) throw new XAException(XAException.XAER_INVAL); if (!Arrays.equals(currentContext.getGlobalTransactionId(), xid.getGlobalTransactionId())) throw new XAException(XAException.XAER_PROTO); if (!onePhase && currentContextTuple.getStatus() != TX_PREPARED) throw new XAException(XAException.XAER_PROTO); if (onePhase && (!((currentContextTuple.getStatus() == TX_IDLE) || (currentContextTuple.getStatus() == TX_SUSPENDED)))) throw new XAException(XAException.XAER_PROTO); if (((ContextTuple) currentContexts.get(Thread.currentThread())) .getRollbackOnly()) { rollback(xid); throw new XAException(XAException.XA_RBROLLBACK); } currentContexts.remove(Thread.currentThread()); } /** * Ends the work performed on behalf of a transaction branch. The * resource manager disassociates the XA resource from the transaction * branch specified and let the transaction be completed. * If TMSUSPEND is specified in flags, the transaction branch is * temporarily suspended in incomplete state. The transaction context is * in suspened state and must be resumed via start with TMRESUME specified. * If TMFAIL is specified, the portion of work has failed. The resource * manager may mark the transaction as rollback-only. * If TMSUCCESS is specified, the portion of work has completed * successfully. * * @param xid A global transaction identifier that is the same as what * was used previously in the start method. * @param flags One of TMSUCCESS, TMFAIL, or TMSUSPEND * @exception XAException An error has occurred. Possible XAException * values are XAER_RMERR, XAER_RMFAILED, XAER_NOTA, XAER_INVAL, * XAER_PROTO, or XA_RB*. */ public void end(Xid xid, int flags) throws XAException { ContextTuple currentContextTuple = (ContextTuple) currentContexts.get(Thread.currentThread()); Xid currentContext = currentContextTuple!=null?currentContextTuple.getXid():null; if (currentContext == null) throw new XAException(XAException.XAER_NOTA); if (xid == null) throw new XAException(XAException.XAER_INVAL); if (!Arrays.equals(currentContext.getGlobalTransactionId(), xid.getGlobalTransactionId())) throw new XAException(XAException.XAER_PROTO); if (flags == XAResource.TMSUSPEND) currentContextTuple.setStatus(TX_SUSPENDED); if (flags == XAResource.TMFAIL) ((ContextTuple) currentContexts.get(Thread.currentThread())) .setRollbackOnly(true); } /** * Tell the resource manager to forget about a heuristically completed * transaction branch. * * @param xid A global transaction identifier * @exception XAException An error has occurred. Possible exception values * are XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO. */ public void forget(Xid xid) throws XAException { ContextTuple currentContextTuple = (ContextTuple) currentContexts.get(Thread.currentThread()); Xid currentContext = currentContextTuple!=null?currentContextTuple.getXid():null; if (currentContext == null) throw new XAException(XAException.XAER_NOTA); if (xid == null) throw new XAException(XAException.XAER_INVAL); if (!Arrays.equals(currentContext.getGlobalTransactionId(), xid.getGlobalTransactionId())) throw new XAException(XAException.XAER_PROTO); currentContexts.remove(Thread.currentThread()); } /** * Obtain the current transaction timeout value set for this XAResource * instance. If XAResource.setTransactionTimeout was not use prior to * invoking this method, the return value is the default timeout set for * the resource manager; otherwise, the value used in the previous * setTransactionTimeout call is returned. * * @return the transaction timeout value in seconds. * @exception XAException An error has occurred. Possible exception * values are XAER_RMERR, XAER_RMFAIL. */ public int getTransactionTimeout() throws XAException { return ((ContextTuple) currentContexts.get(Thread.currentThread())) .getTransactionTimeout(); } /** * This method is called to determine if the resource manager instance * represented by the target object is the same as the resouce manager * instance represented by the parameter xares. * * @param xares An XAResource object whose resource manager instance is * to be compared with the resource manager instance of the target object. * @return true if it's the same RM instance; otherwise false. * @exception XAException An error has occurred. Possible exception values * are XAER_RMERR, XAER_RMFAIL. */ public boolean isSameRM(XAResource xares) throws XAException { if (xares == null) return false; return (this == xares); } /** * Ask the resource manager to prepare for a transaction commit of the * transaction specified in xid. * * @param xid A global transaction identifier * @return A value indicating the resource manager's vote on the outcome * of the transaction. The possible values are: XA_RDONLY or XA_OK. If * the resource manager wants to roll back the transaction, it should do * so by raising an appropriate XAException in the prepare method. * @exception XAException An error has occurred. Possible exception * values are: XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, * or XAER_PROTO. */ public int prepare(Xid xid) throws XAException { ContextTuple currentContextTuple = (ContextTuple) currentContexts.get(Thread.currentThread()); Xid currentContext = currentContextTuple!=null?currentContextTuple.getXid():null; if (currentContext == null) throw new XAException(XAException.XAER_NOTA); if (xid == null) throw new XAException(XAException.XAER_INVAL); if (!Arrays.equals(currentContext.getGlobalTransactionId(), xid.getGlobalTransactionId())) throw new XAException(XAException.XAER_PROTO); if (!((currentContextTuple.getStatus() == TX_IDLE) || (currentContextTuple.getStatus() == TX_SUSPENDED))) throw new XAException(XAException.XAER_PROTO); if (((ContextTuple) currentContexts.get(Thread.currentThread())) .getRollbackOnly()) { // FIXME: Don't know if should be automatically rollbacked in that // case throw new XAException(XAException.XA_RBROLLBACK); } currentContextTuple.setStatus(TX_PREPARED); return XAResource.XA_OK; } /** * Obtain a list of prepared transaction branches from a resource manager. * The transaction manager calls this method during recovery to obtain the * list of transaction branches that are currently in prepared or * heuristically completed states. * * @param flag One of TMSTARTRSCAN, TMENDRSCAN, TMNOFLAGS. TMNOFLAGS must * be used when no other flags are set in flags. * @return The resource manager returns zero or more XIDs for the * transaction branches that are currently in a prepared or heuristically * completed state. If an error occurs during the operation, the resource * manager should throw the appropriate XAException. * @exception XAException An error has occurred. Possible values are * XAER_RMERR, XAER_RMFAIL, XAER_INVAL, and XAER_PROTO. */ public Xid[] recover(int flag) throws XAException { ContextTuple currentContextTuple = (ContextTuple) currentContexts.get(Thread.currentThread()); Xid currentContext = currentContextTuple!=null?currentContextTuple.getXid():null; Vector list = new Vector(); if ((currentContextTuple.getStatus() == TX_PREPARED) && (currentContext != null)) list.addElement(currentContext); return (Xid[]) list.toArray(new Xid[list.size()]); } /** * Inform the resource manager to roll back work done on behalf of a * transaction branch. * * @param xid A global transaction identifier * @exception XAException An error has occurred */ public void rollback(Xid xid) throws XAException { ContextTuple currentContextTuple = (ContextTuple) currentContexts.get(Thread.currentThread()); Xid currentContext = currentContextTuple!=null?currentContextTuple.getXid():null; if (currentContext == null) throw new XAException(XAException.XAER_NOTA); if (xid == null) throw new XAException(XAException.XAER_INVAL); if (!Arrays.equals(currentContext.getGlobalTransactionId(), xid.getGlobalTransactionId())) throw new XAException(XAException.XAER_PROTO); currentContexts.remove(Thread.currentThread()); } /** * Set the current transaction timeout value for this XAResource instance. * * @param seconds the transaction timeout value in seconds. * @return true if transaction timeout value is set successfully; * otherwise false. * @exception XAException An error has occurred. Possible exception * values are XAER_RMERR, XAER_RMFAIL, or XAER_INVAL. */ public boolean setTransactionTimeout(int seconds) throws XAException { ((ContextTuple) currentContexts.get(Thread.currentThread())) .setTransactionTimeout(seconds); return true; } /** * Start work on behalf of a transaction branch specified in xid If * TMJOIN is specified, the start is for joining a transaction previously * seen by the resource manager. If TMRESUME is specified, the start is * to resume a suspended transaction specified in the parameter xid. If * neither TMJOIN nor TMRESUME is specified and the transaction specified * by xid has previously been seen by the resource manager, the resource * manager throws the XAException exception with XAER_DUPID error code. * * @param xid A global transaction identifier to be associated with the * resource * @param flags One of TMNOFLAGS, TMJOIN, or TMRESUME * @exception XAException An error has occurred. Possible exceptions are * XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_DUPID, XAER_OUTSIDE, XAER_NOTA, * XAER_INVAL, or XAER_PROTO. */ public void start(Xid xid, int flags) throws XAException { ContextTuple currentContextTuple = (ContextTuple) currentContexts.get(Thread.currentThread()); Xid currentContext = currentContextTuple!=null?currentContextTuple.getXid():null; if (xid == null) throw new XAException(XAException.XAER_INVAL); if ( (currentContext != null) && (!Arrays.equals(currentContext.getGlobalTransactionId(), xid.getGlobalTransactionId())) ) throw new XAException(XAException.XAER_OUTSIDE); switch (flags) { case XAResource.TMNOFLAGS: if (currentContext != null) throw new XAException(XAException.XAER_INVAL); currentContext = xid; // is the idle status really ok ??? currentContexts.put (Thread.currentThread(),new ContextTuple (xid, TX_IDLE, SlideTransactionManager.DEFAULT_TRANSACTION_TIMEOUT, false)); break; case XAResource.TMJOIN: if (currentContext == null) throw new XAException(XAException.XAER_NOTA); if (!Arrays.equals(currentContext.getGlobalTransactionId(), xid.getGlobalTransactionId())) throw new XAException(XAException.XAER_INVAL); break; case XAResource.TMRESUME: if (currentContext == null) throw new XAException(XAException.XAER_NOTA); if (currentContextTuple.getStatus() != TX_SUSPENDED) throw new XAException(XAException.XAER_INVAL); currentContextTuple.setStatus(TX_IDLE); break; } } // ------------------------------------------------ ContextTuple InnerClass /** * inner class to pack both the xid and the status **/ private class ContextTuple { private Xid xid; private int status; private int transactionTimeout; private boolean rollbackOnly; public ContextTuple(Xid xid, int status, int transactionTimeout, boolean rollbackOnly) { this.xid = xid; setStatus(status); setTransactionTimeout(transactionTimeout); setRollbackOnly(rollbackOnly); } public Xid getXid() { return xid; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public int getTransactionTimeout() { return transactionTimeout; } public void setTransactionTimeout(int transactionTimeout) { this.transactionTimeout = transactionTimeout; } public boolean getRollbackOnly() { return rollbackOnly; } public void setRollbackOnly(boolean rollbackOnly) { this.rollbackOnly = rollbackOnly; } } } --- ExternalTransactionStore.java --- /* * $Header$ * $Revision$ * $Date$ * * ==================================================================== * * Copyright 1999-2003 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.slide.store; import java.util.Hashtable; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.transaction.TransactionManager; import org.apache.slide.common.Namespace; import org.apache.slide.common.ServiceParameterErrorException; import org.apache.slide.common.ServiceParameterMissingException; import org.apache.slide.util.logger.Logger; /** * Store that allows for transactional caching of data over JTA transactions * provided by an external transaction manager. * * @version $Revision$ */ public class ExternalTransactionStore extends ExtendedStore { private TransactionManager txManager; /** * Parameter to specify the JNDI name of the transaction manager. */ public static final String TX_MANAGER_NAME_PARAMETER = "tx-manager-name"; /** * Default value for the transaction manager name parameter. */ public static final String DEFAULT_TX_MANAGER_NAME = "java:/TransactionManager"; private static final String LOG_CHANNEL = AppServerStore.class.getName(); /** * Default constructor. */ public ExternalTransactionStore() { } /* (non-Javadoc) * @see org.apache.slide.common.Service#setParameters(java.util.Hashtable) */ public void setParameters(Hashtable parameters) throws ServiceParameterErrorException, ServiceParameterMissingException { super.setParameters(parameters); String txManagerName = (String) parameters.get(TX_MANAGER_NAME_PARAMETER); if (txManagerName == null) { txManagerName = DEFAULT_TX_MANAGER_NAME; } Logger logger = getLogger(); logger.log("Setting transaction manager name for store " + getName() + " to " + txManagerName, LOG_CHANNEL, Logger.INFO); try { txManager = (TransactionManager) new InitialContext().lookup(txManagerName); } catch (NamingException e) { logger.log("Could not retrieve transaction manager named: " + txManagerName + "from JNDI context! Using default value", e, LOG_CHANNEL, Logger.WARNING); } } /* (non-Javadoc) * @see org.apache.slide.common.Service#setNamespace( * org.apache.slide.common.Namespace) */ public void setNamespace(Namespace namespace) { super.setNamespace(namespace); namespace.initTransactionManager(txManager); } } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
