Package org.objectweb.speedo.workingset.lib

Source Code of org.objectweb.speedo.workingset.lib.AbstractTransaction

/**
* Copyright (C) 2001-2005 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
package org.objectweb.speedo.workingset.lib;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.control.LifeCycleController;
import org.objectweb.jorm.api.PMapper;
import org.objectweb.medor.eval.prefetch.api.PrefetchCache;
import org.objectweb.perseus.persistence.api.ConnectionHolder;
import org.objectweb.perseus.persistence.api.PersistenceException;
import org.objectweb.perseus.persistence.api.State;
import org.objectweb.perseus.persistence.api.TransactionalPersistenceManager;
import org.objectweb.perseus.persistence.api.TransactionalWorkingSet;
import org.objectweb.perseus.persistence.api.VirtualState;
import org.objectweb.perseus.persistence.api.WorkingSet;
import org.objectweb.perseus.persistence.api.WorkingSetLifeCycle;
import org.objectweb.perseus.persistence.lib.BasicWorkingSet;
import org.objectweb.speedo.api.ExceptionHelper;
import org.objectweb.speedo.api.SpeedoProperties;
import org.objectweb.speedo.api.SpeedoRuntimeException;
import org.objectweb.speedo.api.TransactionListener;
import org.objectweb.speedo.mim.api.StateItf;
import org.objectweb.speedo.pm.api.POManagerItf;
import org.objectweb.speedo.workingset.api.TransactionItf;
import org.objectweb.util.monolog.api.BasicLevel;

import java.util.ArrayList;
import java.util.Iterator;

import javax.transaction.Status;
import javax.transaction.Synchronization;


/**
*
*
* @author S.Chassande-Barrioz
*/
public abstract class AbstractTransaction
    extends BasicWorkingSet
    implements TransactionItf, LifeCycleController {

    public final static String PO_MANAGER_BINDING = "po-manager";
    public final static String MAPPER_BINDING = "mapper";
    public final static String TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING
            = "transactional-persistence-manager";
    public final static String COMPONENT_BINDING = "component";

    public static TransactionListener txListener = null;

  /**
   * is the mapper permitting to reach the prefetch cache and to invalidate
   * prefetched buffer at working set closing time.
   */
  protected PMapper mapper = null;

  /**
   * Is used to delegates working set/transaction demercation
   */
  protected TransactionalPersistenceManager tpm = null;

  protected boolean nontransactionalRead;
  protected boolean nontransactionalWrite;

  /**
   * Indicates if the transaction is optimistic.
   */
  protected boolean optimistic;

  /**
   * The JDO user synchronization registered (can be null if none has been
   * registered).
   */
  protected Synchronization synchronization = null;

  /**
   * indicates if the transaction is managed by a J2EE environnement.
   */
  protected boolean managedEnv = false;
 
  /**
   * Indicates if the jdo transaction must be rolledback.
   */
  protected boolean rollbackOnly = false;

  /**
   * the reference to this component in Speedo
   */
  protected TransactionItf thisT;

    /**
     * Is the linked po manager.
     */
    protected POManagerItf pm = null;

  /**
   *
   */
  public AbstractTransaction() {
    super();
  }

    /**
     * Attaches an entry to the transaction.
     * Plus version update.
     * @param state the state which must be attached to the transaction
     * @param mode the action that stared the binding: either read or write intention
     */
    public State bind(State state, Object oid, byte mode) {
        State old = super.bind(state, oid, mode);
        if(! (state instanceof VirtualState)){
            if (mode == BasicWorkingSet.WRITE_INTENTION) {
                StateItf sa = (StateItf) state;
                sa.speedoChangeVersion();
            }
        }
        return old;
    }

    /**
     * Invalidates the prefetch buffer associated to this working set.
     *
     * @throws PersistenceException
     */
    public void beforeWSPrepare() throws PersistenceException {
        logger.log(BasicLevel.DEBUG, "Starting beforeWSPrepare");
        Iterator it = oid2state.values().iterator();
        ArrayList exceptions = null;
        while(it.hasNext()) {
            org.objectweb.perseus.persistence.api.State state = (org.objectweb.perseus.persistence.api.State) it.next();
            if (state == VirtualState.instance) {
                continue;
            }
            try {
                ((StateItf) state).prepareWrite();
            } catch (Exception e) {
                if (exceptions == null) {
                    exceptions = new ArrayList();
                }
                exceptions.add(e);
                int level = e instanceof RuntimeException ? BasicLevel.DEBUG : BasicLevel.ERROR ;
                if (logger.isLoggable(level)) {
                    logger.log(level,
                        "Error on StateItf preparation for flushing: "
                        + "\n\tstate.ce.identifier=" + state.getCacheEntry().getCeIdentifier()
                        + "\n\tstate=" + state
                        + "\n\texception: ", e);
                }
            }
        }
        // close the prefetch buffers associated to the context
        PrefetchCache pc = mapper.getPrefetchCache();
        if (pc != null) {
            pc.invalidatePrefetchBuffer(thisT);
        }
        logger.log(BasicLevel.DEBUG, "Ending beforeWSPrepare");
        if (exceptions != null) {
            throw new PersistenceException(new SpeedoRuntimeException(
                    "Impossible to prepare instances before flushing",
                    (Exception[]) exceptions.toArray(
                            new Exception[exceptions.size()])));
        }
    }

    /**
     * Signal to the persistent instances reached in the working set that the
     * current working set is closed. Some actions on persistent instances at
     * this time can be done, such as reference unswizlling
     */
    public void onWSEnd() {
        logger.log(BasicLevel.DEBUG, "Starting onWSEnd");
        ArrayList exceptions = null;
        if (!oid2state.isEmpty()) {
            Iterator it = oid2state.values().iterator();
            while(it.hasNext()) {
                org.objectweb.perseus.persistence.api.State state = (org.objectweb.perseus.persistence.api.State) it.next();
                if (state == VirtualState.instance) {
                    continue;
                }
                try {
                    ((StateItf) state).workingSetClosed();
                } catch (Exception e) {
                    if (exceptions == null) {
                        exceptions = new ArrayList();
                    }
                    exceptions.add(e);
                    if (!(e instanceof RuntimeException)) {
                        logger.log(BasicLevel.ERROR,
                            "Error on workingSetClosed for the StateItf: "
                            + "\n\tstate.ce.identifier=" + state.getCacheEntry().getCeIdentifier()
                            + "\n\tstate=" + state
                            + "\n\texception: ", e);
                    }
                }
            }
        }
        if (txListener != null) {
            txListener.transactionPreValidate(this, oid2state.size());
        }
        logger.log(BasicLevel.DEBUG, "Ending onWSEnd");
        if (exceptions != null) {
            throw new SpeedoRuntimeException(
                    "Error when signal the close of working set on states:",
                    (Exception[]) exceptions.toArray(new Exception[exceptions.size()]));
        }
    }

    // IMPLEMENTATION OF THE LifeCycleController INTERFACE //
    //-----------------------------------------------------//

    public String getFcState() {
        return null;
    }

    public void startFc() {
        managedEnv = pm.getPOManagerFactory().getProperties()
            .getProperty(SpeedoProperties.MANAGED, "")
            .equals("true");
    }

    public void stopFc() {
    }

    // IMPLEMENTATION OF THE UserBindingController INTERFACE //
    //-------------------------------------------------------//

    public String[] listFc() {
        String[] names = super.listFc();
        String[] itfs = new String[names.length + 3];
        itfs[0] = PO_MANAGER_BINDING;
        itfs[1] = TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING;
        itfs[2] = MAPPER_BINDING;
        System.arraycopy(names, 0, itfs, 3, names.length);
        return itfs;
    }

    public Object lookupFc(String c) {
        if (PO_MANAGER_BINDING.equals(c))
            return pm;
        else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(c))
            return tpm;
        else if (MAPPER_BINDING.equals(c))
            return mapper;
        else
            return super.lookupFc(c);
    }

    public void bindFc(String c, Object s) {
        if (PO_MANAGER_BINDING.equals(c))
            pm = (POManagerItf) s;
        else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(c))
            tpm = (TransactionalPersistenceManager) s;
        else if (MAPPER_BINDING.equals(c))
            mapper = (PMapper) s;
        else if (COMPONENT_BINDING.equals(c)) {
            try {
                thisT = (TransactionItf) ((Component) s).getFcInterface("transaction");
            } catch (Exception e) {
                throw new SpeedoRuntimeException(
                        "Impossible to get self transaction",
                        ExceptionHelper.getNested(e));
            }
        } else
            super.bindFc(c, s);
    }

    public void unbindFc(String c) {
        if (PO_MANAGER_BINDING.equals(c))
            pm = null;
        else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(c))
            tpm = null;
        else if (MAPPER_BINDING.equals(c))
            mapper = null;
        else
            super.unbindFc(c);
    }

    public void setStatus(byte status) throws PersistenceException {
        try {
            switch(status) {
            case TransactionalWorkingSet.CTX_PREPARED:
                beforeWSPrepare();
                break;
            case TransactionalWorkingSet.CTX_COMMITTED:
            case TransactionalWorkingSet.CTX_ABORTED:
                onWSEnd();
                break;
            case TransactionalWorkingSet.CTX_CLOSED:
                if (oid2state.isEmpty()) {
                    // close the prefetch buffers associated to the context
                    PrefetchCache pc = mapper.getPrefetchCache();
                    if (pc != null) {
                        pc.invalidatePrefetchBuffer(thisT);
                    }
                }
                onWSEnd();
                break;
            }
        } finally {
            super.setStatus(status);
        }
    }

    public boolean isActive() {
        switch(status){
        case TransactionalWorkingSet.CTX_ACTIVE_TRANSACTIONAL:
        case TransactionalWorkingSet.CTX_PREPARED:
        case TransactionalWorkingSet.CTX_PREPARED_OK:
        case TransactionalWorkingSet.CTX_PREPARED_FAIL:
            return true;
        case TransactionalWorkingSet.CTX_ACTIVE:
        case TransactionalWorkingSet.CTX_COMMITTED:
        case TransactionalWorkingSet.CTX_ABORTED:
        case TransactionalWorkingSet.CTX_CLOSED:
        default:
            return false;
        }
    }

  /**
   * @see org.objectweb.speedo.workingset.api.TransactionItf#begin()
   */
  public void begin() {
        logger.log(BasicLevel.INFO, "Begin the transaction");
        rollbackOnly = false; //initialize the flag
        try {
            tpm.begin(thisT);
        } catch (PersistenceException e) {
            Exception ie = ExceptionHelper.getNested(e);
            logger.log(BasicLevel.ERROR,
                    "Error during the begin of the transaction:", ie);
            throw new SpeedoRuntimeException("", ie);
        }
        if (txListener != null) {
            txListener.transactionBegun(this);
        }
  }

  /**
   * @see org.objectweb.speedo.workingset.api.TransactionItf#commit()
   */
  public void commit() {
        int size = oid2state.size();
        logger.log(BasicLevel.INFO, "Commit the transaction, working set size: " + size);
        if (synchronization != null) {
            synchronization.beforeCompletion();
        }
        //register working set size for statistics
        boolean validated = rollbackOnly;
        try {
            if (rollbackOnly) {
                tpm.rollback(thisT);
            } else {
                tpm.commit(thisT);
                validated = true;
            }
        } catch (PersistenceException e) {
            Exception ie = ExceptionHelper.getNested(e);
            if (ie instanceof RuntimeException) {
                throw (RuntimeException) ie;
            } else {
                ie = new SpeedoRuntimeException(
                    "JDOTransactionItf rolledback due to an exception at commit time: ", ie);
                logger.log(BasicLevel.INFO, ie.getMessage(), ie);
                throw (SpeedoRuntimeException) ie;
            }
        } finally {
            if (synchronization != null)
                synchronization.afterCompletion((validated
                        ? Status.STATUS_COMMITTED : Status.STATUS_ROLLEDBACK));
            if (txListener != null) {
                if (validated) {
                    txListener.transactionCommitted(this, size);
                } else {
                    txListener.transactionAborted(this, size);
                }
            }
        }
  }

  /**
   * @see org.objectweb.speedo.workingset.api.TransactionItf#rollback()
   */
  public void rollback() {
        logger.log(BasicLevel.INFO, "Roll back a transaction: ");
        int size = oid2state.size();
        try {
            tpm.rollback(thisT);
        } catch (PersistenceException e) {
            Exception ie = ExceptionHelper.getNested(e);
            logger.log(BasicLevel.ERROR,
                    "Error during the rollback of the transaction:", ie);
            throw new SpeedoRuntimeException("", ie);
        } finally {
            if (txListener != null) {
                txListener.transactionAborted(this, size);
            }
            if (synchronization != null) {
                synchronization.afterCompletion(Status.STATUS_ROLLEDBACK);
            }
        }
  }

    /**
     * It activates the working set. This is used to delimit the begining of
     * the working set.
     */
    public void activate() throws PersistenceException {
        tpm.createWS(thisT);
        try {
            status = WorkingSetLifeCycle.getNextStatus(
                    status, WorkingSetLifeCycle.ACTIVE_ACTION);
        } catch (PersistenceException e) {
            logger.log(BasicLevel.WARN, "Bad initial state of the working set:", e);
            status = WorkingSet.CTX_ACTIVE;
        }
    }

    public boolean isManagedEnv() {
        return managedEnv;
    }

  public void setConnectionHolder(ConnectionHolder ch) {
    connectionHolder = ch;
    connectionHolder.bindWorkingSet(thisT);
  }

    public boolean getRollbackOnly() {
        return rollbackOnly;
    }

    public void setRollbackOnly() {
        rollbackOnly = true;
    }  
    public POManagerItf getPOManager() {
        return pm;
    }
}
TOP

Related Classes of org.objectweb.speedo.workingset.lib.AbstractTransaction

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.