Java tutorial
/* * $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); } }