/*
 * $Header: /esup-portail/injac/applications/SlideServer/Packages/esup-serveur-WebDav-3/update/slide/add-ons/stores/uPortalStore/src/stores/org/apache/slide/common/AbstractSimpleService.java,v 1.1 2005/02/08 09:23:40 tbellemb Exp $
 * $Revision: 1.1 $
 * $Date: 2005/02/08 09:23:40 $
 *
 * ====================================================================
 *
 * 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.Vector;

import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import org.apache.slide.transaction.SlideTransactionManager;

/**
 * Slide Service simple implementation. Will allow only one simultaneous
 * transaction context.
 *
 * @deprecated do not use as it only allows for a single concurrent transaction context
 * @version $Revision: 1.1 $
 */
public abstract class AbstractSimpleService 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 Xid currentContext = null;
    
    
    /**
     * Status reagrding the current job.
     */
    protected int status = TX_IDLE;
    
    
    /**
     * Transaction timeout.
     */
    protected int transactionTimeout =
        SlideTransactionManager.DEFAULT_TRANSACTION_TIMEOUT;
    
    
    /**
     * Rollback only.
     */
    protected boolean rollbackOnly = false;
    
    
    // ----------------------------------------------------- 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 {
        
        if (currentContext == null)
            throw new XAException(XAException.XAER_NOTA);
	if (xid == null)
	    throw new XAException(XAException.XAER_INVAL);
        if (currentContext.getGlobalTransactionId()
            != xid.getGlobalTransactionId())
            throw new XAException(XAException.XAER_PROTO);
        
        if (!onePhase && status != TX_PREPARED)
            throw new XAException(XAException.XAER_PROTO);
        if (onePhase && (!((status == TX_IDLE) || (status == TX_SUSPENDED))))
            throw new XAException(XAException.XAER_PROTO);
        
        if (rollbackOnly) {
            rollback(xid);
            throw new XAException(XAException.XA_RBROLLBACK);
        }
        
        currentContext = null;
        status = TX_IDLE;
        rollbackOnly = false;
        
    }
    
    
    /**
     * 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 {
        
        if (currentContext == null)
            throw new XAException(XAException.XAER_NOTA);
	if (xid == null)
	    throw new XAException(XAException.XAER_INVAL);
        if (currentContext.getGlobalTransactionId()
            != xid.getGlobalTransactionId())
            throw new XAException(XAException.XAER_PROTO);
        
        if (flags == XAResource.TMSUSPEND)
            status = TX_SUSPENDED;
        
        if (flags == XAResource.TMFAIL)
            rollbackOnly = 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 {
        
        if (currentContext == null)
            throw new XAException(XAException.XAER_NOTA);
	if (xid == null)
	    throw new XAException(XAException.XAER_INVAL);
        if (currentContext.getGlobalTransactionId()
            != xid.getGlobalTransactionId())
            throw new XAException(XAException.XAER_PROTO);
        
        currentContext = null;
        status = TX_IDLE;
        rollbackOnly = false;
        
    }
    
    
    /**
     * 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 transactionTimeout;
        
    }
    
    
    /**
     * 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 {
        
        if (currentContext == null)
            throw new XAException(XAException.XAER_NOTA);
	if (xid == null)
	    throw new XAException(XAException.XAER_INVAL);
        if (currentContext.getGlobalTransactionId()
            != xid.getGlobalTransactionId())
            throw new XAException(XAException.XAER_PROTO);
        
        if (!((status == TX_IDLE) || (status == TX_SUSPENDED)))
            throw new XAException(XAException.XAER_PROTO);
        
        if (rollbackOnly) {
            // FIXME: Don't know if should be automatically rollbacked in that
            // case
            throw new XAException(XAException.XA_RBROLLBACK);
        }
        
        status = 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 {
        
        Vector list = new Vector();
        
        if ((status == 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 {
        
        if (currentContext == null)
            throw new XAException(XAException.XAER_NOTA);
	if (xid == null)
	    throw new XAException(XAException.XAER_INVAL);
        if (currentContext.getGlobalTransactionId()
            != xid.getGlobalTransactionId())
            throw new XAException(XAException.XAER_PROTO);
        
        status = TX_IDLE;
        currentContext = null;
        rollbackOnly = false;
        
    }
    
    
    /**
     * 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 {
        transactionTimeout = 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 {
        
	if (xid == null)
	    throw new XAException(XAException.XAER_INVAL);
        if ( (currentContext != null) &&
             (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;
            break;
        case XAResource.TMJOIN:
            if (currentContext == null)
                throw new XAException(XAException.XAER_NOTA);
            if (currentContext.getGlobalTransactionId()
                != xid.getGlobalTransactionId())
                throw new XAException(XAException.XAER_INVAL);
            break;
        case XAResource.TMRESUME:
            if (currentContext == null)
                throw new XAException(XAException.XAER_NOTA);
            if (status != TX_SUSPENDED)
                throw new XAException(XAException.XAER_INVAL);
            status = TX_IDLE;
            break;
        }
        
    }
    
    
}

