transactioncontext.java

来自「jsr170接口的java实现。是个apache的开源项目。」· Java 代码 · 共 288 行

JAVA
288
字号
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements.  See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.jackrabbit.core;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.transaction.xa.XAException;import javax.transaction.Status;import java.util.HashMap;import java.util.Map;/** * Represents the transaction on behalf of the component that wants to * explictely demarcate transcation boundaries. After having been prepared, * starts a thread that rolls back the transaction if some time passes without * any further action. This will guarantee that global objects locked by one * of the resources' {@link InternalXAResource#prepare} method, are eventually * unlocked. */public class TransactionContext implements Runnable {    /**     * Logger instance.     */    private static final Logger log = LoggerFactory.getLogger(TransactionContext.class);    /**     * Transactional resources.     */    private final InternalXAResource[] resources;    /**     * Timeout, in seconds.     */    private final int timeout;    /**     * Transaction attributes.     */    private final Map attributes = new HashMap();    /**     * Status.     */    private int status;    /**     * Flag indicating whether the association is currently suspended.     */    private boolean suspended;    /**     * Create a new instance of this class.     * @param resources transactional resources     * @param timeout timeout, in seconds     */    public TransactionContext(InternalXAResource[] resources, int timeout) {        this.resources = resources;        this.timeout = timeout;    }    /**     * Set an attribute on this transaction. If the value specified is     * <code>null</code>, it is semantically equivalent to     * {@link #removeAttribute}.     *     * @param name  attribute name     * @param value attribute value     */    public void setAttribute(String name, Object value) {        if (value == null) {            removeAttribute(name);        }        attributes.put(name, value);    }    /**     * Return an attribute value on this transaction.     *     * @param name attribute name     * @return attribute value, <code>null</code> if no attribute with that     *         name exists     */    public Object getAttribute(String name) {        return attributes.get(name);    }    /**     * Remove an attribute on this transaction.     *     * @param name attribute name     */    public void removeAttribute(String name) {        attributes.remove(name);    }    /**     * Prepare the transaction identified by this context. Prepares changes on     * all resources. If some resource reports an error on prepare,     * automatically rollback changes on all other resources. Throw exception     * at the end if errors were found.     * @throws XAException if an error occurs     */    public synchronized void prepare() throws XAException {        status = Status.STATUS_PREPARING;        beforeOperation();        TransactionException txe = null;        for (int i = 0; i < resources.length; i++) {            try {                resources[i].prepare(this);            } catch (TransactionException e) {                txe = e;                break;            }        }        afterOperation();        status = Status.STATUS_PREPARED;        if (txe != null) {            // force immediate rollback on error.            try {                rollback();            } catch (XAException e) {                /* ignore */            }            XAException e = new XAException(XAException.XA_RBOTHER);            e.initCause(txe);            throw e;        }        // start rollback thread in case the commit is never issued        new Thread(this, "RollbackThread").start();    }    /**     * Commit the transaction identified by this context. Commits changes on     * all resources. If some resource reports an error on commit,     * automatically rollback changes on all other resources. Throw     * exception at the end if some commit failed.     * @throws XAException if an error occurs     */    public synchronized void commit() throws XAException {        if (status == Status.STATUS_ROLLEDBACK) {            throw new XAException(XAException.XA_RBTIMEOUT);        }        status = Status.STATUS_COMMITTING;        beforeOperation();        TransactionException txe = null;        for (int i = 0; i < resources.length; i++) {            InternalXAResource resource = resources[i];            if (txe != null) {                try {                    resource.rollback(this);                } catch (TransactionException e) {                    log.warn("Unable to rollback changes on " + resource, e);                }            } else {                try {                    resource.commit(this);                } catch (TransactionException e) {                    txe = e;                }            }        }        afterOperation();        status = Status.STATUS_COMMITTED;        if (txe != null) {            XAException e = new XAException(XAException.XA_RBOTHER);            e.initCause(txe);            throw e;        }    }    /**     * Rollback the transaction identified by this context. Rolls back changes     * on all resources. Throws exception at the end if errors were found.     * @throws XAException if an error occurs     */    public synchronized void rollback() throws XAException {        if (status == Status.STATUS_ROLLEDBACK) {            throw new XAException(XAException.XA_RBTIMEOUT);        }        status = Status.STATUS_ROLLING_BACK;        beforeOperation();        int errors = 0;        for (int i = 0; i < resources.length; i++) {            InternalXAResource resource = resources[i];            try {                resource.rollback(this);            } catch (TransactionException e) {                log.warn("Unable to rollback changes on " + resource, e);                errors++;            }        }        afterOperation();        status = Status.STATUS_ROLLEDBACK;        if (errors != 0) {            throw new XAException(XAException.XA_RBOTHER);        }    }    /**     * {@inheritDoc}     * <p/>     * Waits for the amount of time specified as transaction timeout. After     * this time has elapsed, rolls back the transaction if still prepared     * and marks the transaction rolled back.     */    public void run() {        try {            Thread.sleep(timeout * 1000);        } catch (InterruptedException e) {            /* ignore */        }        synchronized (this) {            if (status == Status.STATUS_PREPARED) {                try {                    rollback();                } catch (XAException e) {                    /* ignore */                }                log.warn("Transaction rolled back because timeout expired.");            }        }    }    /**     * Invoke all of the registered resources' {@link InternalXAResource#beforeOperation}     * methods.     */    private void beforeOperation() {        for (int i = 0; i < resources.length; i++) {            resources[i].beforeOperation(this);        }    }    /**     * Invoke all of the registered resources' {@link InternalXAResource#afterOperation}     * methods.     */    private void afterOperation() {        for (int i = 0; i < resources.length; i++) {            resources[i].afterOperation(this);        }    }    /**     * Return a flag indicating whether the association is suspended.     *     * @return <code>true</code> if the association is suspended;     *         <code>false</code> otherwise     */    public boolean isSuspended() {        return suspended;    }    /**     * Set a flag indicating whether the association is suspended.     *     * @param suspended flag whether that the association is suspended.     */    public void setSuspended(boolean suspended) {        this.suspended = suspended;    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?