org.apache.slide.store.mem.AbstractTransientStore.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.slide.store.mem.AbstractTransientStore.java

Source

/*
 * $Header: /var/chroot/cvs/cvs/factsheetDesigner/extern/jakarta-slide-server-src-2.1-iPlus Edit/src/stores/org/apache/slide/store/mem/AbstractTransientStore.java,v 1.2 2006-01-22 22:49:06 peter-cvs Exp $
 * $Revision: 1.2 $
 * $Date: 2006-01-22 22:49:06 $
 *
 * ====================================================================
 *
 * 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.store.mem;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;

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

import org.apache.commons.transaction.memory.ConflictException;
import org.apache.commons.transaction.memory.TransactionalMapWrapper;
import org.apache.commons.transaction.memory.jca.MapXAResource;
import org.apache.commons.transaction.util.LoggerFacade;

import org.apache.slide.common.AbstractServiceBase;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.ServiceConnectionFailedException;
import org.apache.slide.common.ServiceDisconnectionFailedException;
import org.apache.slide.common.ServiceInitializationFailedException;
import org.apache.slide.common.ServiceParameterErrorException;
import org.apache.slide.common.ServiceParameterMissingException;
import org.apache.slide.common.ServiceResetFailedException;
import org.apache.slide.util.logger.Logger;
import org.apache.slide.util.logger.TxLogger;

/**
 * Base class for the stores that what to store its data transient in a
 * map.
 * 
 * <p>Implementations access the backing map only via {@link #put(Object, Object)},
 * {@link #get(Object)} and {@link #remove(Object)}.
 * 
 * <p>The backed map can be any class that is derived from 
 * {@link org.apache.commons.transaction.memory.TransactionalMapWrapper}.
 * 
 * <p>The class may be configured in the <code>domain.xml</code> using the
 * parameter <code>map-classname</code>. 
 * Default is {@link org.apache.commons.transaction.memory.OptimisticMapWrapper}.
 * 
 * 
 */
public abstract class AbstractTransientStore extends AbstractServiceBase {

    static final String MAP_IMPL_PARAMETER = "map-classname";
    static final String MAP_IMPL_PARAMETER_DEFAULT = "org.apache.commons.transaction.memory.OptimisticMapWrapper";

    private Map parameters = null;
    private boolean isConnected = false;

    /**
     * The map containing the stored content.
     */
    private TransactionalMapWrapper store = null;

    /**
     * The XAResource to delegate all XA requests.
     */
    private MapXAResource xaResource = null;

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

    public void start(Xid xid, int flags) throws XAException {
        debug("start {0} {1}", xid, Integer.toString(flags));
        this.xaResource.start(xid, flags);
    }

    public void commit(Xid xid, boolean onePhase) throws XAException {
        debug("commit {0} {1}", xid, onePhase ? "true" : "false");
        try {
            this.xaResource.commit(xid, onePhase);
        } catch (ConflictException e) {
            this.xaResource.rollback(xid);
            // TODO it would be great if we could throw something
            // that would (on the webdav layer) leads to a 409 Conflict
            // instead of 500 Internal Server Error
            throw new XAException(XAException.XA_RBOTHER); // ??
        }
    }

    public int prepare(Xid xid) throws XAException {
        debug("prepare {0}", xid);
        return this.xaResource.prepare(xid);
    }

    public void end(Xid xid, int flags) throws XAException {
        debug("end {0} {1}", xid, Integer.toString(flags));
        this.xaResource.end(xid, flags);
    }

    public void rollback(Xid xid) throws XAException {
        debug("rollback {0}", xid);
        this.xaResource.rollback(xid);
    }

    public Xid[] recover(int flag) throws XAException {
        debug("recover {0}", Integer.toString(flag));
        return this.xaResource.recover(flag);
    }

    public void forget(Xid xid) throws XAException {
        debug("forget {0}", xid);
        this.xaResource.forget(xid);
    }

    public int getTransactionTimeout() throws XAException {
        return this.xaResource.getTransactionTimeout();
    }

    public boolean setTransactionTimeout(int seconds) throws XAException {
        return this.xaResource.setTransactionTimeout(seconds);
    }

    public boolean isSameRM(XAResource xares) throws XAException {
        return this == xares;
    }

    // ------------------------------------- Store accessors for implementations

    protected void put(Object key, Object value) {
        this.store.put(key, value);
    }

    protected Object get(Object key) {
        return this.store.get(key);
    }

    protected Object remove(Object key) {
        return this.store.remove(key);
    }

    // ------------------------------------------------ ContextTuple InnerClass

    public void setParameters(Hashtable parameters)
            throws ServiceParameterErrorException, ServiceParameterMissingException {
        this.parameters = new HashMap(parameters);
    }

    protected String getParameter(String name) {
        if (this.parameters != null) {
            return (String) this.parameters.get(name);
        } else {
            throw new IllegalStateException("Parameter not yet set!");
        }
    }

    public void initialize(NamespaceAccessToken token) throws ServiceInitializationFailedException {
        super.initialize(token);

        TxLogger txLogger = new TxLogger(getLogger(), LogChannel());

        String param = (String) this.parameters.get(MAP_IMPL_PARAMETER);
        if (param == null) {
            param = MAP_IMPL_PARAMETER_DEFAULT;
        }
        try {
            info("Initializing {0} using {1}.", getClass().getName(), param);
            Map toBeWrapped = new HashMap();
            Class mapClass = Class.forName(param);

            try {
                Class[] ctorFormalArgs = { Map.class, LoggerFacade.class };
                Constructor ctor = mapClass.getConstructor(ctorFormalArgs);
                Object[] ctorArgs = { toBeWrapped, txLogger };
                this.store = (TransactionalMapWrapper) ctor.newInstance(ctorArgs);
            } catch (NoSuchMethodException e) {
                // try next
                try {
                    Class[] ctorFormalArgs = { Map.class };
                    Constructor ctor = mapClass.getConstructor(ctorFormalArgs);
                    Object[] ctorArgs = { toBeWrapped };
                    this.store = (TransactionalMapWrapper) ctor.newInstance(ctorArgs);
                } catch (NoSuchMethodException ee) {
                    error("Initialization error: ", ee);
                    throw new ServiceInitializationFailedException(this, ee);
                }
            }
        } catch (ClassNotFoundException e) {
            error("Initialization error: ", e);
            throw new ServiceInitializationFailedException(this, e);
        } catch (InstantiationException e) {
            error("Initialization error: ", e);
            throw new ServiceInitializationFailedException(this, e);
        } catch (IllegalAccessException e) {
            error("Initialization error: ", e);
            throw new ServiceInitializationFailedException(this, e);
        } catch (InvocationTargetException e) {
            error("Initialization error: ", e);
            throw new ServiceInitializationFailedException(this, e);
        } catch (ClassCastException e) {
            error("Initialization error: ", e);
            throw new ServiceInitializationFailedException(this, "class in parameter '" + MAP_IMPL_PARAMETER
                    + "' must " + "be derived from TransactionalMapWrapper");
        }

        this.xaResource = new MapXAResource(this.store);
        // FIXME can't set logging because methods are not public, and
        // ctor doesn't take a loggerFacade
    }

    public void connect() throws ServiceConnectionFailedException {
        this.isConnected = true;
    }

    public void disconnect() throws ServiceDisconnectionFailedException {
        this.isConnected = false;
    }

    public void reset() throws ServiceResetFailedException {
    }

    public boolean isConnected() throws ServiceAccessException {
        return this.isConnected;
    }

    // -------------------------------------------------------------------

    protected String LogChannel() {
        return LOG_CHANNEL;
    }

    protected void debug(String msg, Object o) {
        if (this.getLogger().isEnabled(Logger.DEBUG)) {
            Object[] args = { o };
            this.getLogger().log(MessageFormat.format(msg, args), LogChannel(), Logger.DEBUG);
        }
    }

    protected void debug(String msg, Object o1, Object o2) {
        if (this.getLogger().isEnabled(Logger.DEBUG)) {
            Object[] args = { o1, o2 };
            this.getLogger().log(MessageFormat.format(msg, args), LogChannel(), Logger.DEBUG);
        }
    }

    private void info(String msg, Object o1, Object o2) {
        if (this.getLogger().isEnabled(Logger.INFO)) {
            Object[] args = { o1, o2 };
            this.getLogger().log(MessageFormat.format(msg, args), LogChannel(), Logger.INFO);
        }
    }

    private void error(String msg, Throwable t) {
        if (this.getLogger().isEnabled(Logger.INFO)) {
            this.getLogger().log(msg, t, LogChannel(), Logger.INFO);
        }
    }

    /**
     * Empty enumeration.
     */
    protected static Enumeration EMPTY_ENUM = new Enumeration() {
        public boolean hasMoreElements() {
            return false;
        }

        public Object nextElement() {
            throw new NoSuchElementException();
        }
    };

    /**
     * Enumeration wrapper for an Iterator. 
     */
    protected static class IteratorEnum implements Enumeration {
        private Iterator iterator;

        public IteratorEnum(Iterator iterator) {
            this.iterator = iterator;
        }

        public boolean hasMoreElements() {
            return this.iterator.hasNext();
        }

        public Object nextElement() {
            return this.iterator.next();
        }
    }
}