Hi Alejandro!

Thanks for the patches :) I was just going to commit them. Unfortunately, the line breaks mess up the files. Could you please create a patch, at least for AbstractService? If your attachements do not get through to the mailing list, maybe it is a good idea to create a bugzilla issue and attach them there.

Oliver

Alejandro Gu�zar wrote:

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]




---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to