Package org.springmodules.transaction.jini

Source Code of org.springmodules.transaction.jini.JiniTransactionManager$JiniHolder

/**
* Created on Mar 12, 2006
*
* $Id$
* $Revision$
*/
package org.springmodules.transaction.jini;

import java.rmi.RemoteException;

import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;

import net.jini.core.lease.LeaseDeniedException;
import net.jini.core.transaction.CannotAbortException;
import net.jini.core.transaction.CannotCommitException;
import net.jini.core.transaction.Transaction;
import net.jini.core.transaction.TransactionFactory;
import net.jini.core.transaction.UnknownTransactionException;
import net.jini.core.transaction.server.NestableTransactionManager;
import net.jini.core.transaction.server.TransactionManager;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.InvalidIsolationLevelException;
import org.springframework.transaction.NestedTransactionNotSupportedException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.ResourceHolderSupport;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springmodules.jini.JiniUtils;

/**
* Jini PlatformTransactionManager . Requires a Jini TransactionManager service
* to perform to create the actual transactions using jini transactional context
* (transactionalContext property). For JavaSpaces for example, the context will
* be represented by the java space.
* Does <strong>not</strong> support nested transaction propagation yet.
*
* @author Costin Leau
*
*
* TODO: make it Serializable ? TODO: the default timeout (-1) is similar to
* Lease.ANY which might create a tx with infinite timeout which results in
* deadlock.
*
*/
public class JiniTransactionManager extends AbstractPlatformTransactionManager
    implements InitializingBean {

  // TransactionManager used for creating the actual transaction
  private transient TransactionManager transactionManager;

  // the jini participant - can be javaspace or any other service that wants
  // to take part in the transaction
  private Object transactionalContext;

  public JiniTransactionManager() {

  }

  public JiniTransactionManager(TransactionManager transactionManager,
      Object transactionalContext) {
    this.transactionManager = transactionManager;
    this.transactionalContext = transactionalContext;
    afterPropertiesSet();
  }

  /**
   * @see org.springmodules.beans.factory.InitializingBean#afterPropertiesSet()
   */
  public void afterPropertiesSet() {
    if (transactionManager == null)
      throw new IllegalArgumentException(
          "transactionManager property is required");
    if (transactionalContext == null)
      throw new IllegalArgumentException(
          "transactionalContext property is required");

    if (transactionManager instanceof NestableTransactionManager)
      setNestedTransactionAllowed(true);
  }

  /**
   * @see org.springmodules.transaction.support.AbstractPlatformTransactionManager#doGetTransaction()
   */
  protected Object doGetTransaction() throws TransactionException {

    JiniTransactionObject txObject = new JiniTransactionObject();
    // txObject.setNestedTransactionAllowed
    // txObject.setJiniHolder(transactionalContext);

    // set the jini holder is one is found
    if (TransactionSynchronizationManager.hasResource(transactionalContext)) {
      JiniHolder jiniHolder = (JiniHolder) TransactionSynchronizationManager
          .getResource(transactionalContext);
      if (logger.isDebugEnabled()) {
        logger.debug("Found thread-bound tx data [" + jiniHolder
            + "] for Jini resource " + transactionalContext);
      }
      txObject.setJiniHolder(jiniHolder, false);
    }

    return txObject;
  }

  protected RuntimeException convertJiniException(Exception e) {
    return JiniUtils.convertJiniException(e);
  }

  /**
   * @see org.springmodules.transaction.support.AbstractPlatformTransactionManager#doBegin(java.lang.Object,
   *      org.springmodules.transaction.TransactionDefinition)
   */
  protected void doBegin(Object transaction, TransactionDefinition definition)
      throws TransactionException {
    JiniTransactionObject txObject = (JiniTransactionObject) transaction;
    if (logger.isDebugEnabled())
      logger.debug("Beginning Jini transaction " + txObject.toString());
    try {
      doJiniBegin(txObject, definition);
    }
    catch (NotSupportedException ex) {
      // assume nested transaction not supported
      throw new NestedTransactionNotSupportedException(
          "Jini implementation does not support nested transactions",
          ex);
    }
    catch (UnsupportedOperationException ex) {
      // assume nested transaction not supported
      throw new NestedTransactionNotSupportedException(
          "Jini implementation does not support nested transactions",
          ex);
    }
    catch (SystemException ex) {
      throw new CannotCreateTransactionException("Jini failure on begin",
          ex);
    }
  }

  /**
   * Performs the transaction begin.
   *
   * @param txObject
   * @param definition
   * @throws NotSupportedException
   * @throws SystemException
   */
  protected void doJiniBegin(JiniTransactionObject txObject,
      TransactionDefinition definition) throws NotSupportedException,
      SystemException {

    // create the tx

    try {
      if (txObject.getJiniHolder() == null) {
        if (logger.isDebugEnabled())
          logger.debug("creating new jini tx for "
              + getTransactionalContext());
        Transaction.Created txCreated = TransactionFactory.create(
            transactionManager, definition.getTimeout());
        JiniHolder jiniHolder = new JiniHolder(txCreated);
        jiniHolder.setTimeoutInSeconds(definition.getTimeout());
        txObject.setJiniHolder(jiniHolder, true);
      }

      txObject.getJiniHolder().setSynchronizedWithTransaction(true);

      applyIsolationLevel(txObject, definition.getIsolationLevel());
      // check for timeout just in case
      // applyTimeout(txObject, definition.getTimeout());

      // Bind the session holder to the thread.
      if (txObject.isNewJiniHolder()) {
        TransactionSynchronizationManager.bindResource(
            getTransactionalContext(), txObject.getJiniHolder());
      }
    }
    catch (LeaseDeniedException e) {
      throw new CannotCreateTransactionException("lease denied", e);
    }
    catch (RemoteException e) {
      throw new CannotCreateTransactionException("remote exception", e);
    }

  }

  protected void applyIsolationLevel(JiniTransactionObject txObject,
      int isolationLevel) throws InvalidIsolationLevelException,
      SystemException {

    if (isolationLevel != TransactionDefinition.ISOLATION_DEFAULT) {
      throw new InvalidIsolationLevelException(
          "JiniTransactionManager does not support custom isolation levels");
    }
  }

  protected void applyTimeout(JiniTransactionObject txObject, int timeout)
      throws NotSupportedException {
    // TODO: maybe use a LeaseRenewalManager
    if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
      throw new NotSupportedException(
          "JiniTransactionManager does not support custom timeouts");
    }
  }

  /**
   * @see org.springmodules.transaction.support.AbstractPlatformTransactionManager#doCommit(org.springmodules.transaction.support.DefaultTransactionStatus)
   */
  protected void doCommit(DefaultTransactionStatus status)
      throws TransactionException {
    JiniTransactionObject txObject = (JiniTransactionObject) status
        .getTransaction();
    if (logger.isDebugEnabled())
      logger.debug("Committing Jini transaction " + txObject.toString());
    try {
      txObject.getTransaction().commit();
    }
    catch (UnknownTransactionException e) {
      throw convertJiniException(e);
    }
    catch (CannotCommitException e) {
      throw convertJiniException(e);
    }
    catch (RemoteException e) {
      throw convertJiniException(e);
    }
  }

  /**
   * @see org.springmodules.transaction.support.AbstractPlatformTransactionManager#isExistingTransaction(java.lang.Object)
   */
  protected boolean isExistingTransaction(Object transaction)
      throws TransactionException {
    JiniTransactionObject txObject = (JiniTransactionObject) transaction;
    return txObject.hasTransaction();
  }

  /**
   * @see org.springmodules.transaction.support.AbstractPlatformTransactionManager#doRollback(org.springmodules.transaction.support.DefaultTransactionStatus)
   */
  protected void doRollback(DefaultTransactionStatus status)
      throws TransactionException {
    JiniTransactionObject txObject = (JiniTransactionObject) status
        .getTransaction();
    if (logger.isDebugEnabled())
      logger.debug("Rolling back Jini transaction" + txObject.toString());
    try {
      txObject.getTransaction().abort();
    }
    catch (UnknownTransactionException e) {
      throw convertJiniException(e);
    }
    catch (CannotAbortException e) {
      throw convertJiniException(e);
    }
    catch (RemoteException e) {
      throw convertJiniException(e);
    }
  }

  protected void doCleanupAfterCompletion(Object transaction) {
    JiniTransactionObject txObject = (JiniTransactionObject) transaction;
    // Remove the session holder from the thread.
    if (txObject.isNewJiniHolder()) {
      if (logger.isDebugEnabled()) {
        logger.debug("Removing per-thread Jini transaction for "
            + getTransactionalContext());
      }
      TransactionSynchronizationManager
          .unbindResource(getTransactionalContext());
    }

    txObject.getJiniHolder().clear();
  }

  protected void doSetRollbackOnly(DefaultTransactionStatus status)
      throws TransactionException {
    JiniTransactionObject txObject = (JiniTransactionObject) status
        .getTransaction();
    if (status.isDebug()) {
      logger.debug("Setting Jini transaction on txContext ["
          + getTransactionalContext() + "] rollback-only");
    }
    txObject.setRollbackOnly();
  }

  /**
   * @see org.springmodules.transaction.support.AbstractPlatformTransactionManager#doResume(java.lang.Object,
   *      java.lang.Object)
   */
  protected void doResume(Object transaction, Object suspendedResources)
      throws TransactionException {
    JiniHolder jiniHolder = (JiniHolder) suspendedResources;
    TransactionSynchronizationManager.bindResource(
        getTransactionalContext(), jiniHolder);
  }

  /**
   * @see org.springmodules.transaction.support.AbstractPlatformTransactionManager#doSuspend(java.lang.Object)
   */
  protected Object doSuspend(Object transaction) throws TransactionException {
    JiniTransactionObject txObject = (JiniTransactionObject) transaction;
    txObject.setJiniHolder(null, false);
    JiniHolder jiniHolder = (JiniHolder) TransactionSynchronizationManager
        .unbindResource(getTransactionalContext());
    return jiniHolder;
  }

  /**
   * @return Returns the transactionManager.
   */
  public TransactionManager getTransactionManager() {
    return transactionManager;
  }

  /**
   * @param transactionManager
   *            The transactionManager to set.
   */
  public void setTransactionManager(TransactionManager transactionManager) {
    this.transactionManager = transactionManager;
  }

  /**
   * @see org.springmodules.transaction.support.AbstractPlatformTransactionManager#useSavepointForNestedTransaction()
   */
  protected boolean useSavepointForNestedTransaction() {
    return false;
  }

  /**
   * Jini Transaction object. Used as transaction object by
   * JiniTransactionManager.
   *
   * TODO: can SmartTransactionObject be implemented?
   */
  private static class JiniTransactionObject {

    private JiniHolder jiniHolder;

    private boolean newJiniHolder;

    public boolean hasTransaction() {
      return (jiniHolder != null && jiniHolder.hasTransaction());
    }

    public void setJiniHolder(JiniHolder jiniHolder,
        boolean newSessionHolder) {
      this.jiniHolder = jiniHolder;
      this.newJiniHolder = newSessionHolder;
    }

    public JiniHolder getJiniHolder() {
      return jiniHolder;
    }

    public boolean isNewJiniHolder() {
      return newJiniHolder;
    }

    public boolean isRollbackOnly() {
      return (jiniHolder != null && jiniHolder.isRollbackOnly());
    }

    public void setRollbackOnly() {
      if (jiniHolder != null)
        jiniHolder.setRollbackOnly();
    }

    public Transaction getTransaction() {
      if (hasTransaction())
        return jiniHolder.txCreated.transaction;
      return null;
    }

  }

  // is ResourceHolder really required
  public static class JiniHolder extends ResourceHolderSupport {
    private Transaction.Created txCreated;

    public JiniHolder(Transaction.Created txCreated) {
      this.txCreated = txCreated;
    }

    /**
     * @return Returns the txCreated.
     */
    public Transaction.Created getTxCreated() {
      return txCreated;
    }

    public boolean hasTransaction() {
      return (txCreated != null && txCreated.transaction != null);
    }

  }

  /**
   * @return Returns the transactionalContext.
   */
  public Object getTransactionalContext() {
    return transactionalContext;
  }

  /**
   * @param transactionalContext
   *            The transactionalContext to set.
   */
  public void setTransactionalContext(Object txResource) {
    this.transactionalContext = txResource;
  }

}
TOP

Related Classes of org.springmodules.transaction.jini.JiniTransactionManager$JiniHolder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.