Package ch.ethz.prose

Source Code of ch.ethz.prose.LocalAspectManager$TransactionGroup

//
//  This file is part of the prose package.
//
//  The contents of this file are subject to the Mozilla Public License
//  Version 1.1 (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.mozilla.org/MPL/
//
//  Software distributed under the License is distributed on an "AS IS" basis,
//  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
//  for the specific language governing rights and limitations under the
//  License.
//
//  The Original Code is prose.
//
//  The Initial Developer of the Original Code is Andrei Popovici. Portions
//  created by Andrei Popovici are Copyright (C) 2002 Andrei Popovici.
//  All Rights Reserved.
//
//  Contributor(s):
//  $Id: LocalAspectManager.java,v 1.4 2008/11/18 11:44:47 anicoara Exp $
//  =====================================================================
//

package ch.ethz.prose;

// used packages
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.HashMap;

import ch.ethz.jvmai.JVMAspectInterface;
import ch.ethz.prose.crosscut.Crosscut;
import ch.ethz.prose.crosscut.CrosscutRequest;
import ch.ethz.prose.crosscut.CrosscutGroup;
import ch.ethz.prose.engine.ClassLoadListener;
import ch.ethz.prose.engine.JoinPointManager;
import ch.ethz.prose.engine.JoinPointRequest;
import ch.ethz.inf.util.Logger;

/**
* Class LocalAspectManager extends AspectManager and implements a local
* extension manager. Upon creation, a <code>LocalAspectManager</code> registers
* itself as a listener of class load events into the current JoinPointManager.
*
* @version  $Revision: 1.4 $
* @author  Andrei Popovici
*/
public class LocalAspectManager implements AspectManager, ClassLoadListener {

  static int ABORT = 0x1;
  static int COMMIT = 0x2;

  private HashMap txMap = new HashMap();
  private Set theExtensions;
  private boolean isConnectedToVM;
  private boolean isStarted;
  protected JoinPointManager jpm;


  /**
   * Create a new <code>LocalAspectManager</code>
   * with no aspects inserted and create a <code>JoinPointManager</code>.
   * register this extension manager as a class load listener
   * of the current JoinPointManager.
   */
  protected LocalAspectManager(boolean isConnected, JVMAspectInterface ai) {
    isConnectedToVM = isConnected;
    isStarted       = false;
    theExtensions = Collections.synchronizedSet(new HashSet());
    createJoinPointManager(isConnectedToVM, ai);
    jpm.registerListener(this);
  }


  /**
   * This Method is going to be overwritten from a subclass of <code>LocalAspectManager</code>
   * that wants to register its own <code>JoinPointManager</code>.
   */
  protected void createJoinPointManager(boolean isConnected, JVMAspectInterface ai) {
    jpm = new JoinPointManager(isConnected, ai,  true);
  }

  /**
   * This method has to be called before an <code>AspectManager</code> is used.
   */
  public synchronized void startup() {
    isStarted = true;
    // do nothing
  }

  /**
   * This method has to be called before an <code>AspectManager</code> is destroyed.
   */
  public synchronized void teardown() {
    if (!isStarted)
      return;

    withdrawAll();
    if (jpm != null) {
      jpm.disconnectFromJVMAI();
      jpm = null;
    }
    isStarted=false;
  }


  { Class c=Throwable.class;}
  /** This method is called every time a new class has been successfully
   * loaded and prepared into the system. It implements the functionality
   * needed to update the extensions currently inserted into this extension
   * to the current state of the system. For example, if a new class is loaded
   * that contains join-points cross-cut by an existing crosscut E.C, the
   * crosscut in question will be added as a listener of the JoinPointManager.
   */
  public void classLoaded(Class newClass) {
    // FIXME: exception classes are loaded when an exception is
    // thrown. It is better not to stop the throwing of an exception
    // with cross-cutting activity. Unfortunatelly, the test 'isAssignableFrom'
    // was false for both exception and non-exeception classes. This
    // seemed to be the only way around. Unclean, error prone. FIX!!
    if (newClass.getName().endsWith("Exception"))
      return;

    synchronized(theExtensions) {
      Iterator i = theExtensions.iterator();
      while (i.hasNext()) {
        Aspect crtExtension = (Aspect)i.next();
        registerCrosscuts(crtExtension,newClass);
      }
    }
  }


  static class TransactionGroup {
    CrosscutGroup insertGroup;
    CrosscutGroup withdrawGroup;
    List          toBeInserted;
    List          toBeWithdrawn;

    TransactionGroup() {
      insertGroup = new CrosscutGroup();
      insertGroup.setExecuteAdvice(false);
      withdrawGroup = new CrosscutGroup();
      withdrawGroup.setExecuteAdvice(true);
      toBeInserted = new Vector();
      toBeWithdrawn = new Vector();
    }
  };

  private TransactionGroup getTransactionGroup(Object transactionId) {
    TransactionGroup crtGroup = (TransactionGroup)txMap.get(transactionId);
    if (crtGroup == null) {
      crtGroup = new TransactionGroup();
      txMap.put(transactionId,crtGroup);
    }

    return crtGroup;
  }

  private void prepareInsertExtension(Aspect ext, Object transactionId) {
    // get the transaction group
    TransactionGroup crtGroup = getTransactionGroup(transactionId);

    //add ext to the list which should be inserted
    crtGroup.toBeInserted.add(ext);

    // associate all ext crosscuts to this group
    Iterator i = ext.getCrosscuts().iterator();
    while (i.hasNext()) {
      Crosscut crtCrosscut = (Crosscut)i.next();
      crtCrosscut.associateToGroup(crtGroup.insertGroup);
    }
  }

  private void prepareWithdrawExtension(Aspect ext, Object transactionId) {
    // get the transaction group
    TransactionGroup crtGroup = getTransactionGroup(transactionId);

    //add ext to the list which should be withdrawn
    crtGroup.toBeWithdrawn.add(ext);

    // associate all crosscuts to this group
    Iterator i = ext.getCrosscuts().iterator();
    while (i.hasNext())
    {
      Crosscut crtCrosscut = (Crosscut)i.next();
      crtCrosscut.associateToGroup(crtGroup.withdrawGroup);
    }
  }


  private void finishTransaction(Object transactionId, int commitOrAbort) {
    // do withdraw (toBeInserted)
    TransactionGroup crtGroup = getTransactionGroup(transactionId);
    List           extensionsToWithdraw = null;

    if (commitOrAbort == COMMIT) {
      crtGroup.insertGroup.setExecuteAdvice(true);
      crtGroup.withdrawGroup.setExecuteAdvice(false);
      extensionsToWithdraw = crtGroup.toBeWithdrawn;
    }
    if (commitOrAbort == ABORT) {
      extensionsToWithdraw  = crtGroup.toBeInserted;
    }

    Iterator i  = extensionsToWithdraw.iterator();
    while (i.hasNext())
      doWithdrawExtension((Aspect)(i.next()));

    txMap.remove(transactionId);
  }


  public void insert(Aspect x,Object txId) {
    if (txId == null)
      throw new IllegalArgumentException("txId must be non-null");
    prepareInsertExtension(x,txId);
    doInsertExtension(x);
  }

  public void withdraw(Aspect x, Object txId) {
    if (txId == null || x == null)
      throw new IllegalArgumentException("txId must be non-null");
    prepareWithdrawExtension(x,txId);
  }


  public void insert(Aspect x) {
    Object txId = new Object();
    if (txId == null || x == null)
      throw new IllegalArgumentException("txId and x must be non-null");

    try {
      insert(x,txId);
      finishTransaction(txId,COMMIT);
    }
    catch (RuntimeException e) {
      finishTransaction(txId,ABORT);
      throw e;
    }

  }

  public void withdraw(Aspect x) {
    Object txId = new Object();
    if (txId == null || x == null)
      throw new IllegalArgumentException("txId must be non-null");

    try {
      withdraw(x,txId);
      finishTransaction(txId,COMMIT);
    }
    catch (RuntimeException e) {
      finishTransaction(txId,ABORT);
      throw e;
    }
  }

  public void commit(Object txId) {
    finishTransaction(txId,COMMIT);
  }

  public void abort(Object txId) {
    finishTransaction(txId,ABORT);
  }

  /**
   * Insert the extension <code>ext</code> into the extension
   * manager. This involves registering the <code>ext</code>'s
   * crosscut into the current <code>JoinPointManager</code>.
   */
  public synchronized void doInsertExtension(Aspect ext) throws AspectManagerException {

    // supress notification
    jpm.suspendListenerNotification(Thread.currentThread());

    Logger.message("LocalAspectManager(" + isConnectedToVM + ").insertExtension: attempting insert, extension=" + ext);
    try {
      ext.insertionAction(true);
    }
    catch (AspectInsertionException extDoesntLikeThisVM) {
      Logger.warning("LocalExtgensionManager(" + isConnectedToVM +
          ").insertExtnesion:failed 'insertAction'",extDoesntLikeThisVM);
      throw new AspectManagerException("Aspect ext does not wish to be inserted(" +
          extDoesntLikeThisVM.toString()+")");
    }

    // has extension already been inserted?
    if (theExtensions.contains(ext)) {
      Logger.message("LocalAspectManager(" + isConnectedToVM +
          ").insertExtension: failed, ext. already existent, extension=" + ext);
      throw new AspectManagerException("Aspect already available");
    }

    // insert into the JPM all crosscut requests generated by the extension's crosscuts.
    // insert Crosscuts
    registerCrosscuts(ext,null);

    // bookkeeping the inserted extensions
    theExtensions.add(ext);

    // tell the extension we are finished
    try {
      ext.insertionAction(false);
    }
    catch (Exception e) {
      Logger.warning("LocalAspectManager(" + isConnectedToVM
          + ").insertExtension: insertAction failed, extension = " + ext);
    }

    // re-enable notification
    jpm.resumeListenerNotification(Thread.currentThread());
    Logger.message("LocalAspectManager(" + isConnectedToVM + ").insertExtension: done");
  }


  private void registerCrosscuts(Aspect ext, Class cls) {
    //System.out.println("LocalAspectManager - Aspect = " + ext.toString());
    //System.out.println("LocalAspectManager - Class = " + cls);
    Iterator i = ext.getCrosscuts().iterator();
    while (i.hasNext()) {

      Crosscut crtCrosscut = (Crosscut)i.next();
      //System.out.println("LocalAspectManager - crtCrosscut = " + crtCrosscut.toString());

      if (  (crtCrosscut instanceof Insertable) && cls == null)
        ((Insertable)crtCrosscut).insertionAction(true);

      CrosscutRequest crtRequest = null;
      if (cls == null)
        // This method is used by first use of this crosscut
        crtRequest =  crtCrosscut.createRequest();
      else
        // This method is used upon loading of new classes in the VM
        crtRequest = crtCrosscut.createRequest(cls);

      Iterator j = crtRequest.iterator();
      while (j.hasNext()) {
        //System.out.println("LocalAspectManager - crtCrosscut.iterator = " + crtRequest.toString());
        JoinPointRequest crtJPR = (JoinPointRequest)(j.next());
        jpm.registerListener(crtCrosscut,crtJPR);
      }

      if ( (crtCrosscut instanceof Insertable) && cls == null)
        ((Insertable)crtCrosscut).insertionAction(false);
    }
  }

  /**
   * Unregister the crosscuts belonging to <code>ext</code>
   * from the corresponding <code>JoinPointManager</code>
   */
  public synchronized void doWithdrawExtension(Aspect ext) {
    Logger.message("LocalAspectManager(" + isConnectedToVM + ").withdrawExtension: withdrawing " + ext);
    jpm.suspendListenerNotification(Thread.currentThread());

    try {
      ext.withdrawalAction(true);
    }
    catch (Exception e) {
      Logger.warning("Aspect does not wish withdrawal",e);
    }

    Iterator i = ext.getCrosscuts().iterator();
    while (i.hasNext()) {
      Crosscut crtCrosscut = (Crosscut)i.next();
      jpm.unregisterListener(crtCrosscut);
    }
    theExtensions.remove(ext);

    try {
      ext.withdrawalAction(false);
    }
    catch (Exception e) {
      Logger.message("extension  " + ext + " does not wish withdrawal (end)");
    }

    jpm.resumeListenerNotification(Thread.currentThread());
  }

  /**
   * Return the list of extensions currently
   * inserted into the system.
   */
  public List getAllAspects() {
    return new Vector(theExtensions);
  }


  /**
   * Return the <code>JoinPointManager</code> of this extension manager.
   */
  public JoinPointManager getJoinPointManager() {
    return jpm;
  }


  /**
   * Return the boolean status that indicates if this extension manager is connected to the
   * VM through its joinpoint manager or if it is the test manager and has no connection to the VM.
   */
  public boolean isConnectedToVM() {
    return isConnectedToVM;
  }


  private void withdrawAll() {
    if (jpm == null)
      return;

    jpm.suspendListenerNotification(Thread.currentThread());

    if (getAllAspects() == null)
      return;

    Iterator i = new HashSet(getAllAspects()).iterator();
    while (i.hasNext()) {
      Aspect e = (Aspect)i.next();
      withdraw(e);
    }

    jpm.resumeListenerNotification(Thread.currentThread());
  }

  /**
   * Remove all inserted extensions from this extension manager, disconnect the joinpoint manager
   * from the JVMAI System and deconstruct it.
   */
  protected void finalize() {

    //withdrawAll();
    if (jpm != null) {
      jpm.disconnectFromJVMAI();
      jpm = null;
    }
  }

}
TOP

Related Classes of ch.ethz.prose.LocalAspectManager$TransactionGroup

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.