/*******************************************************************************
* Copyright (c) 2010 Eric Bodden.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eric Bodden - initial API and implementation
* Andreas Sewe - coverage of array creation and reflective field accesses
******************************************************************************/
package de.bodden.tamiflex.playout;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.commons.Method;
import de.bodden.tamiflex.normalizer.NameExtractor;
import de.bodden.tamiflex.playout.transformation.AbstractTransformation;
public class ReflectionMonitor implements ClassFileTransformer {
private List<AbstractTransformation> transformations = new LinkedList<AbstractTransformation>();
public ReflectionMonitor(String instruments, boolean verbose) {
List<String> split = new ArrayList<String>(Arrays.asList(instruments.split("[ ]+")));
Collections.sort(split);
if(verbose) {
System.out.println("\nActive instruments:");
}
for (String className : split) {
className = className.trim();
if(className.isEmpty()) continue;
try {
@SuppressWarnings("unchecked")
Class<AbstractTransformation> c = (Class<AbstractTransformation>) Class.forName(className);
AbstractTransformation transform = c.newInstance();
transformations.add(transform);
if(verbose) {
System.out.print(className);
System.out.println(": ");
for(Method m: transform.getAffectedMethods()) {
System.out.print(" ");
System.out.print(transform.getAffectedClass().getName()+"."+m.getName()+m.getDescriptor()+"\n");
}
}
} catch (Exception e) {
throw new RuntimeException("There was an error instantiating the instrument "+className, e);
}
}
}
public List<Class<?>> getAffectedClasses() {
List<Class<?>> affectedClasses = new ArrayList<Class<?>>();
for (AbstractTransformation transformation : transformations)
affectedClasses.add(transformation.getAffectedClass());
return affectedClasses;
}
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if(className==null)
className = NameExtractor.extractName(classfileBuffer);
try {
final ClassReader creader = new ClassReader(classfileBuffer);
final ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor visitor = writer;
for (AbstractTransformation transformation : transformations)
visitor = transformation.getClassVisitor(className, visitor);
creader.accept(visitor, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
return writer.toByteArray();
} catch (IllegalStateException e) {
throw new IllegalClassFormatException("Error: " + e.getMessage() + " on class " + className);
} catch(RuntimeException e) {
e.printStackTrace();
throw e;
}
}
}