//
// 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 Developers of the Original Code are Andrei Popovici and
// Angela Nicoara. Portions created by Andrei Popovici and Angela Nicoara
// are Copyright (C) 2002 Andrei Popovici and Angela Nicoara.
// All Rights Reserved.
//
// Contributor(s):
// $Id: RemoteAspectManagerImpl.java,v 1.4 2008/11/18 11:43:39 anicoara Exp $
// =====================================================================
//
package ch.ethz.prose.tools;
import java.io.InputStream;
import java.rmi.RemoteException;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import ch.ethz.prose.Aspect;
import ch.ethz.prose.DefaultAspect;
import ch.ethz.prose.AspectManager;
import ch.ethz.prose.ProseSystem;
import ch.ethz.inf.util.Logger;
import ch.ethz.jvmai.JVMAspectInterface;
import ch.ethz.jvmai.SunBCELRepositoryInterface;
import ch.ethz.prose.crosscut.MethodRedefineCut;
import ch.ethz.prose.query.QueryManager;
import ch.ethz.prose.query.AspectSurrogate;
import ch.ethz.prose.crosscut.Crosscut;
/** Class <code>RemoteAspectManagerImpl</code> a simple implementation for the
* <code>RemoteAspectManager</code> prose instance.
*
* <code>RemoteAspectManagerImpl</code> DOES NOT export the created objects;
* @version $Revision: 1.4 $
* @author Andrei Popovici
* @author Angela Nicoara
*/
public class RemoteAspectManagerImpl implements RemoteAspectManager {
private SunBCELRepositoryInterface ai; // only used for the remote insertion (event notification JVMDI + JVMTI)
private boolean isReal;
private boolean isRemote;
private AspectManager extMgr;
private QueryManager qMgr;
public RemoteAspectManagerImpl(boolean real) throws RemoteException {
isReal = real;
}
public void init() throws RemoteException {
if (extMgr==null) {
if (isReal)
extMgr = ProseSystem.getAspectManager();
else
extMgr = ProseSystem.getTestAspectManager();
qMgr = new QueryManager(extMgr);
if( extMgr.getJoinPointManager().getAspectInterface() instanceof SunBCELRepositoryInterface) { // gerry
ai = (SunBCELRepositoryInterface) extMgr.getJoinPointManager().getAspectInterface();
}
}
}
/**
* Insert an extension into the underlying <code>ProseSystem</code>.
*/
public void insert(Aspect ext) throws RemoteException {
init();
insert(ext,null);
}
public void withdraw(AspectSurrogate ext) throws RemoteException,ClassNotFoundException {
init();
withdraw(ext,null);
}
public void insert(Aspect ext, Object txId) throws RemoteException {
try {
init();
// Workaround for MethodRedefineCuts and crosscutting aspects.
// The BCEL based implementation needs access to the aspects class file(s)
// to redefine the advice methods bodies.
if( ai != null ) {
// transfer ext and member classes to
// AspectInterfaces BCEL repository
putFullAspectIntoBCELRepository(ext);
}
if (txId == null)
extMgr.insert(ext);
else
extMgr.insert(ext,txId);
}
catch (Throwable t) {
// t.printStackTrace();
throw new RemoteException(t.toString());
}
}
/**
* Makes the declared fields of a class available to PROSE BCEL repository.
*
* @param cls The class
*/
private void putFieldsIntoBCELRepository(Class cls) {
//System.err.println("RemoteAspectManagerImpl - putFieldsIntoBCELRepository => CLASS = " + cls.getName());
// get all fields that it declares
Field[] declaredFields = cls.getDeclaredFields();
for(int i = 0; i < declaredFields.length; i++) {
//System.err.println("RemoteAspectManagerImpl - putFieldsIntoBCELRepository + FIELDS.type = " + declaredFields[i].getType());
// Don't send classes primitive types
if(!declaredFields[i].getType().isPrimitive())
putClassFileIntoBCELRepository(declaredFields[i].getType());
}
}
/**
* Makes the methods parameters of a class available
* to PROSE BCEL repository.
*
* @param cls The class
*/
private void putMethodParametersIntoBCELRepository(Class cls) {
//System.err.println("RemoteAspectManagerImpl - putMethodParametersIntoBCELRepository => CLASS = " + cls.getName());
Method[] methods = cls.getDeclaredMethods();
for(int i=0; i<methods.length; i++) {
//System.err.println("RemoteAspectManagerImpl - putMethodParametersIntoBCELRepository => METHODS = " + methods[i]);
Class[] param = methods[i].getParameterTypes();
for(int j=0; j < param.length; j++) {
putClassFileIntoBCELRepository(param[j]);
//System.err.println("RemoteAspectManagerImpl - putMethodParametersIntoBCELRepository => PARAM types: " + param[j].getName());
//System.err.println("RemoteAspectManagerImpl - putMethodParametersIntoBCELRepository => PARAM length: " + param.length);
}
// Put also the return type into the repository
putClassFileIntoBCELRepository(methods[i].getReturnType());
}
}
/**
* Makes the crosscuts of an aspect available to the
* PROSE BCEL repository.
*
* @param ext The aspect
*/
private void putCrosscutsIntoBCELRepository(Aspect ext) {
//System.err.println("RemoteAspectManagerImpl - putCrosscutsIntoBCELRepository => CLASS = " + ext.toString());
try{
Method m = null;
Class cls = ext.getClass();
if (DefaultAspect.class.isAssignableFrom(cls)) {
do {
cls = cls.getSuperclass();
} while( ! DefaultAspect.class.equals(cls));
}
//System.err.println("RemoteAspectManagerImpl - putCrosscutsIntoBCELRepository => CROSSCUT = " + cls.getName());
m = cls.getDeclaredMethod("crosscuts",new Class[]{});
m.setAccessible(true);
Crosscut[] cc = (Crosscut[]) m.invoke(ext, new Object[]{});
//System.err.println("RemoteAspectManagerImpl - putCrosscutsIntoBCELRepository => Number of CROSSCUTS => " + cc.length);
for (int i=0; i < cc.length; i++){
//System.err.println("RemoteAspectManagerImpl - putCrosscutsIntoBCELRepository - CROSSCUT = " + cc[i].toString());
Class ccls = cc[i].getClass();
putFieldsIntoBCELRepository(ccls);
putMethodParametersIntoBCELRepository(ccls);
putClassFileIntoBCELRepository(ccls);
}
} catch(Exception e) { System.err.println("RemoteAspectManagerImpl - putCrosscutIntoBCELRepository: " + e); }
}
/**
* Makes an aspect available to PROSEs BCEL repository.
* <P>
* The aspect, all classes of its fields and all member/inner
* classes will be added to the repository.
* <P>
* This fetches the aspects, its fields and inner classes,
* the public inner classes and fields of its super classes and its
* anonymous inner classes.
*
* @param ext the aspect
*/
private void putFullAspectIntoBCELRepository(Aspect ext) {
// 1. get all crosscuts and put them into the BCEL repository
putCrosscutsIntoBCELRepository(ext);
Class clazz = ext.getClass();
do {
// 2. put the class into the repository
putClassFileIntoBCELRepository(clazz);
// 3. put the types of the methods parameters into the repository
putMethodParametersIntoBCELRepository(clazz);
// 4. put its fields into the repository
putFieldsIntoBCELRepository(clazz);
// 5. put its declared inner classes into the repository
Class[] declaredClasses = clazz.getDeclaredClasses();
for(int i = 0; i < declaredClasses.length; i++) {
Class innerClass = declaredClasses[i];
putClassFileIntoBCELRepository(innerClass);
putFieldsIntoBCELRepository(innerClass);
putMethodParametersIntoBCELRepository(innerClass);
}
// 6. put its anonymous inner classes into the repository
String extName = clazz.getName();
int j = 1;
InputStream classFile;
// Anonymous inner classes are numbered beginning from 1.
// Following approach reconstructs the filenames and tries to get
// the according files. If no file is found, all anonymous inner classes are
// already processed.
while(null != (classFile = ext.getClass().getResourceAsStream( extName.replace('.','/') + "$" + j + ".class"))) {
String clsName = extName + "$" + j;
//System.err.println(">> RemoteAspectManagerImpl - putFullAspectIntoBCELRepository => anonymous CLASS = " + clsName);
//System.err.println(">> RemoteAspectManagerImpl - putFullAspectIntoBCELRepository => class = " + classFile.getClass().getName());
ai.addBCELClassDefiniton(classFile, clsName);
j++;
}
// 7. do the same thing for its super class (until the class 'Aspect' is reached)
// looking for 'DefaultAspect' might be more efficient. But this is
// safe, in case an aspect class was directly derived from 'Aspect'.
clazz = clazz.getSuperclass();
} while(!clazz.equals(Aspect.class));
}
/**
* Makes a class file available to PROSEs BCEL repository.
* <P>
* (for this method, the client must be connected to a PROSE VM
* that uses a HotSwap based execution monitor)
*
* @param cls the class that will be transfered
*/
private void putClassFileIntoBCELRepository(Class cls) {
//System.err.println("RemoteAspectManagerImpl - putClassFileIntoBCELRepository => CLASS = " + cls.getName());
//System.err.println("RemoteAspectManagerImpl - putClassFileIntoBCELRepository => class name: " + cls.getName() + " converted to " + cls.getName().replace('.','/') + ".class");
//InputStream classFile = cls.getResourceAsStream( cls.getName().replace('.','/') + ".class"); //BEFORE - BUGFIX - aspects package
InputStream classFile = null; //PLUS - BUGFIX - aspects package
if (null != cls.getClassLoader()) //PLUS - BUGFIX - aspects package
classFile = cls.getClassLoader().getResourceAsStream( cls.getName().replace('.','/') + ".class"); //PLUS - BUGFIX - aspects package
else //PLUS - BUGFIX - aspects package
classFile = cls.getResourceAsStream( cls.getName().replace('.','/') + ".class"); //PLUS - BUGFIX - aspects package
if( null != classFile && null != ai) {
((SunBCELRepositoryInterface) ai).addBCELClassDefiniton( classFile, cls.getName());
Logger.message("transfered class file " + cls.getName() );
}
else {
Logger.warning("RemoteAspectManager.putClassFileInBCELRepository failed for " + cls + " (AspectInterface: " + ai + ")");
}
}
public void withdraw(AspectSurrogate ext,Object txId) throws RemoteException,ClassNotFoundException {
init();
Aspect asp = qMgr.reconstructAspect(ext);
List x = new Vector((extMgr.getAllAspects()));
int extIndx = x.indexOf(asp);
if (extIndx >= 0) {
if (txId == null) {
extMgr.withdraw((Aspect)(x.get(extIndx)));
}
else
extMgr.withdraw((Aspect)(x.get(extIndx)),txId);
}
else {
Logger.message("extension " + ext + " not known");
throw new RuntimeException( "extension " + ext + " not known");
}
}
public void commit(Object txId) throws RemoteException {
init();
extMgr.commit(txId);
}
public void abort(Object txId) throws RemoteException {
init();
extMgr.abort(txId);
}
/**
* Return a list of the current inserted extensions.
*/
public List allAspects() throws RemoteException {
init();
return qMgr.queryAllAspects();
}
public List allJoinpoints() throws RemoteException {
init();
return qMgr.queryAllJoinpoints();
}
/**
* Return a List of Tupel objects (without duplicates) that represents the result of querying the system
* with a list of Aspects.
*/
public List queryAspects(List aspectList, int selectFields, int groupBy) throws RemoteException {
init();
return qMgr.queryAspects(aspectList,selectFields,groupBy);
}
/**
* Return a List of Tupel objects (without duplicates) that represents the result of querying the system
* with a list of Crosscuts.
*/
public List queryCrosscuts(List crosscutList, int selectFields, int groupBy) throws RemoteException {
init();
return qMgr.queryCrosscuts(crosscutList,selectFields,groupBy);
}
/**
* Return a List of Tupel objects (without duplicates) that represents the result of querying the system
* with a list of JoinPointRequests.
*/
public List queryJoinpoints(List joinpointList, int selectFields, int groupBy) throws RemoteException {
init();
return qMgr.queryJoinpoints(joinpointList,selectFields,groupBy);
}
}