org.apache.slide.common.AbstractXAServiceBase.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.slide.common.AbstractXAServiceBase.java

Source

/*
 * $Header: /var/chroot/cvs/cvs/factsheetDesigner/extern/jakarta-slide-server-src-2.1-iPlus Edit/src/share/org/apache/slide/common/AbstractXAServiceBase.java,v 1.2 2006-01-22 22:47:24 peter-cvs Exp $
 * $Revision: 1.2 $
 * $Date: 2006-01-22 22:47:24 $
 *
 * ====================================================================
 *
 * 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.Map;

import org.apache.commons.transaction.util.LoggerFacade;
import org.apache.slide.authenticate.CredentialsToken;
import org.apache.commons.transaction.util.xa.TransactionalResource;
import org.apache.slide.util.logger.Logger;
import org.apache.slide.util.logger.TxLogger;
import org.apache.slide.transaction.SlideXidWrapper;

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

import java.util.concurrent.ConcurrentHashMap;

/**
 * Slide Service abstract implementation.
 *
 * Changes: Removed the inheritance from AbstractXAResource and pasted the code in here so we could switch to
 * using a different implementation of XidWrapper.
 *
 * @version $Revision: 1.2 $
 */
public abstract class AbstractXAServiceBase /*extends AbstractXAResource*/ implements Service, XAResource, Status {

    // -------------------------------------------------------------- Constants

    protected String LOG_CHANNEL = this.getClass().getName();

    // ----------------------------------------------------- Instance Variables

    /**
     * Namespace.
     */
    protected Namespace namespace;

    // the scope of this store as specified in domain.xml
    protected Scope scope;

    protected LoggerFacade loggerFacade = null;

    // -------------------------------------------------------- Service Methods

    /**
     * Set the scope of the store as specified in domain.xml.
     */
    public void setScope(Scope scope) {
        this.scope = scope;
    }

    /**
     * Namespace setter.
     */
    public void setNamespace(Namespace namespace) {
        this.namespace = namespace;
    }

    /**
     * Logger accessor.
     */
    public Logger getLogger() {
        Logger logger = null;
        if (namespace != null) {
            logger = this.namespace.getLogger();
        }
        if (logger == null)
            logger = Domain.getLogger();
        return logger;
    }

    protected LoggerFacade getLoggerFacade() {
        if (loggerFacade == null) {
            loggerFacade = new TxLogger(getLogger(), LOG_CHANNEL);
        }
        return loggerFacade;
    }

    /**
     * Initializes the service with a set of parameters. Those could be :
     * <li>User name, login info
     * <li>Host name on which to connect
     * <li>Remote port
     * <li>JDBC driver whoich is to be used :-)
     * <li>Anything else ...
     *
     * @param parameters Hashtable containing the parameters' names
     * and associated values
     * @exception ServiceParameterErrorException Incorrect service parameter
     * @exception ServiceParameterMissingException Service parameter missing
     */
    public abstract void setParameters(Hashtable parameters)
            throws ServiceParameterErrorException, ServiceParameterMissingException;

    /**
     * Connects to the underlying data source (if any is needed).
     * Compatibility implementation for the previous store implementations
     *
     * @param crdtoken the slide token containing e.g. the credential
     * @exception ServiceConnectionFailedException Connection failed
     */
    public void connect(CredentialsToken crdtoken) throws ServiceConnectionFailedException {
        connect();
    }

    /**
     * Connects to the underlying data source (if any is needed).
     *
     * @exception ServiceConnectionFailedException Connection failed
     */
    public abstract void connect() throws ServiceConnectionFailedException;

    /**
     * Disconnects from the underlying data source.
     *
     * @exception ServiceDisconnectionFailedException Disconnection failed
     */
    public abstract void disconnect() throws ServiceDisconnectionFailedException;

    /**
     * Initializes service.
     *
     * @param token Namespace access token, needed if the service needs to
     * access objects or data within the namespace during its initialization
     * @exception ServiceInitializationFailedException May throw an exception
     * if the service has already been initialized before
     */
    public void initialize(NamespaceAccessToken token) throws ServiceInitializationFailedException {
    }

    /**
     * Deletes service underlying data source, if possible (and meaningful).
     *
     * @exception ServiceResetFailedException Reset failed
     */
    public abstract void reset() throws ServiceResetFailedException;

    /**
     * This function tells whether or not the service is connected.
     *
     * @return boolean true if we are connected
     * @exception ServiceAccessException Service access error
     */
    public abstract boolean isConnected() throws ServiceAccessException;

    /**
     * Connects to the service, if we were not previously connected.
     *
     * @param token the Credeantials token containing e.g. the credential
     * @return boolean true if we were not already connected
     * @exception ServiceAccessException Unspecified service access error
     * @exception ServiceConnectionFailedException Connection failed
     */
    public boolean connectIfNeeded(CredentialsToken token)
            throws ServiceConnectionFailedException, ServiceAccessException {
        boolean result = true;
        try {
            result = !isConnected();
        } catch (ServiceAccessException e) {
            // Ignore : Will try to reconnect
        }
        if (result) {
            connect(token);
        }
        return result;
    }

    /**
     * Connects to the service, if we were not previously connected.
     *
     * @return boolean true if we were not already connected
     * @exception ServiceAccessException Unspecified service access error
     * @exception ServiceConnectionFailedException Connection failed
     */
    public boolean connectIfNeeded() throws ServiceConnectionFailedException, ServiceAccessException {
        boolean result = true;
        try {
            result = !isConnected();
        } catch (ServiceAccessException e) {
            // Ignore : Will try to reconnect
        }
        if (result) {
            connect();
        }
        return result;
    }

    /**
     * Indicates whether or not the objects managed by this service should be
     * cached. Caching is enabled by default.
     *
     * @return boolean True if results should be cached
     */
    public boolean cacheResults() {
        return true;
    }

    // ----------------------------------------------------- XAResource Mathods

    // there might be at least one active transaction branch per thread
    private ThreadLocal activeTransactionBranch = new ThreadLocal();

    private Map suspendedContexts = new ConcurrentHashMap();
    private Map activeContexts = new ConcurrentHashMap();

    public abstract boolean isSameRM(XAResource xares) throws XAException;

    public abstract Xid[] recover(int flag) throws XAException;

    protected abstract boolean includeBranchInXid();

    public void forget(Xid xid) throws XAException {
        if (getLoggerFacade().isFineEnabled()) {
            getLoggerFacade().logFine("Forgetting transaction branch " + xid);
        }
        TransactionalResource ts = getTransactionalResource(xid);
        if (ts == null) {
            throw new XAException(XAException.XAER_NOTA);
        }
        setCurrentlyActiveTransactionalResource(null);
        removeActiveTransactionalResource(xid);
        removeSuspendedTransactionalResource(xid);
    }

    public void commit(Xid xid, boolean onePhase) throws XAException {
        TransactionalResource ts = getTransactionalResource(xid);
        if (ts == null) {
            throw new XAException(XAException.XAER_NOTA);
        }

        if (getLoggerFacade().isFineEnabled()) {
            getLoggerFacade().logFine("Committing transaction branch " + ts);
        }

        if (ts.getStatus() == STATUS_MARKED_ROLLBACK) {
            throw new XAException(XAException.XA_RBROLLBACK);
        }

        if (ts.getStatus() != STATUS_PREPARED) {
            if (onePhase) {
                ts.prepare();
            } else {
                throw new XAException(XAException.XAER_PROTO);
            }
        }
        ts.commit();
        setCurrentlyActiveTransactionalResource(null);
        removeActiveTransactionalResource(xid);
        removeSuspendedTransactionalResource(xid);
    }

    public void rollback(Xid xid) throws XAException {
        TransactionalResource ts = getTransactionalResource(xid);

        if (ts == null) {
            setCurrentlyActiveTransactionalResource(null);
            throw new XAException(XAException.XAER_NOTA);
        }

        if (getLoggerFacade().isFineEnabled()) {
            getLoggerFacade().logFine("Rolling back transaction branch " + ts);
        }
        try {
            ts.rollback();
        } finally {
            setCurrentlyActiveTransactionalResource(null);
            removeActiveTransactionalResource(xid);
            removeSuspendedTransactionalResource(xid);
        }
    }

    public int prepare(Xid xid) throws XAException {
        TransactionalResource ts = getTransactionalResource(xid);
        if (ts == null) {
            throw new XAException(XAException.XAER_NOTA);
        }

        if (getLoggerFacade().isFineEnabled()) {
            getLoggerFacade().logFine("Preparing transaction branch " + ts);
        }

        if (ts.getStatus() == STATUS_MARKED_ROLLBACK) {
            throw new XAException(XAException.XA_RBROLLBACK);
        }

        int result = ts.prepare();
        ts.setStatus(STATUS_PREPARED);
        return result;
    }

    public void end(Xid xid, int flags) throws XAException {
        TransactionalResource ts = getActiveTransactionalResource(xid);
        if (ts == null) {
            setCurrentlyActiveTransactionalResource(null);
            throw new XAException(XAException.XAER_NOTA);
        }
        if (getCurrentlyActiveTransactionalResource() == null) {
            throw new XAException(XAException.XAER_INVAL);
        }
        if (getLoggerFacade().isFineEnabled()) {
            getLoggerFacade().logFine(new StringBuffer(128).append("Thread ").append(Thread.currentThread())
                    .append(flags == TMSUSPEND ? " suspends" : flags == TMFAIL ? " fails" : " ends")
                    .append(" work on behalf of transaction branch ").append(ts).toString());
        }

        switch (flags) {
        case TMSUSPEND:
            ts.suspend();
            addSuspendedTransactionalResource(xid, ts);
            removeActiveTransactionalResource(xid);
            break;
        case TMFAIL:
            ts.setStatus(STATUS_MARKED_ROLLBACK);
            break;
        case TMSUCCESS:
            break;
        }
        setCurrentlyActiveTransactionalResource(null);
    }

    public void start(Xid xid, int flags) throws XAException {
        if (getCurrentlyActiveTransactionalResource() != null) {
            throw new XAException(XAException.XAER_INVAL);
        }
        if (getLoggerFacade().isFineEnabled()) {
            getLoggerFacade().logFine(new StringBuffer(128).append("Thread ").append(Thread.currentThread())
                    .append(flags == TMNOFLAGS ? " starts" : flags == TMJOIN ? " joins" : " resumes")
                    .append(" work on behalf of transaction branch ").append(xid).toString());
        }

        TransactionalResource ts;
        switch (flags) {
        // a new transaction
        case TMNOFLAGS:
        case TMJOIN:
        default:
            try {
                ts = createTransactionResource(xid);
                ts.begin();
            } catch (Exception e) {
                getLoggerFacade().logSevere("Could not create new transactional  resource", e);
                throw new XAException(e.getMessage());
            }
            break;
        case TMRESUME:
            ts = getSuspendedTransactionalResource(xid);
            if (ts == null) {
                throw new XAException(XAException.XAER_NOTA);
            }
            ts.resume();
            removeSuspendedTransactionalResource(xid);
            break;
        }
        setCurrentlyActiveTransactionalResource(ts);
        addAcitveTransactionalResource(xid, ts);
    }

    abstract protected TransactionalResource createTransactionResource(Xid xid) throws Exception;

    protected TransactionalResource getCurrentlyActiveTransactionalResource() {
        TransactionalResource context = (TransactionalResource) activeTransactionBranch.get();
        return context;
    }

    protected void setCurrentlyActiveTransactionalResource(TransactionalResource context) {
        activeTransactionBranch.set(context);
    }

    protected TransactionalResource getTransactionalResource(Xid xid) {
        TransactionalResource ts = getActiveTransactionalResource(xid);
        if (ts != null)
            return ts;
        else
            return getSuspendedTransactionalResource(xid);
    }

    protected TransactionalResource getActiveTransactionalResource(Xid xid) {
        Xid wxid = SlideXidWrapper.wrap(xid, includeBranchInXid());
        return (TransactionalResource) activeContexts.get(wxid);
    }

    protected TransactionalResource getSuspendedTransactionalResource(Xid xid) {
        Xid wxid = SlideXidWrapper.wrap(xid, includeBranchInXid());
        return (TransactionalResource) suspendedContexts.get(wxid);
    }

    protected void addAcitveTransactionalResource(Xid xid, TransactionalResource txContext) {
        Xid wxid = SlideXidWrapper.wrap(xid, includeBranchInXid());
        activeContexts.put(wxid, txContext);
    }

    protected void addSuspendedTransactionalResource(Xid xid, TransactionalResource txContext) {
        Xid wxid = SlideXidWrapper.wrap(xid, includeBranchInXid());
        suspendedContexts.put(wxid, txContext);
    }

    protected void removeActiveTransactionalResource(Xid xid) {
        Xid wxid = SlideXidWrapper.wrap(xid, includeBranchInXid());
        activeContexts.remove(wxid);
    }

    protected void removeSuspendedTransactionalResource(Xid xid) {
        Xid wxid = SlideXidWrapper.wrap(xid, includeBranchInXid());
        suspendedContexts.remove(wxid);
    }
}