de.bodden.tamiflex.playout.ReflectionMonitor.java Source code

Java tutorial

Introduction

Here is the source code for de.bodden.tamiflex.playout.ReflectionMonitor.java

Source

/* *****************************************************************************
 * 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 de.bodden.tamiflex.normalizer.NameExtractor;
import de.bodden.tamiflex.playout.transformation.AbstractTransformation;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.*;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.commons.Method;

public class ReflectionMonitor implements ClassFileTransformer {

    private List<AbstractTransformation> transformations = new LinkedList<>();

    public ReflectionMonitor(String instruments, boolean verbose) {
        List<String> split = new ArrayList<>(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<>();

        for (AbstractTransformation transformation : transformations) {
            affectedClasses.add(transformation.getAffectedClass());
        }

        return affectedClasses;
    }

    @Override
    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(Agent.err());
            throw e;
        }
    }
}