package com.onpositive.instrumentation.processors;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.commons.GeneratorAdapter;
/**
*
* @author Pavel Petrochenko
*
*
*/
public class ClassProcessor {
ArrayList participants = new ArrayList();
public void addParticipant(ClassProcessingParticipant participant) {
participants.add(participant);
}
public void removeParticipant(ClassProcessingParticipant participant) {
participants.remove(participant);
}
public byte[] processClass(byte[] stream) throws IOException {
ClassReader reader = new ClassReader(stream);
ClassProcessingParticipant[] subjectOfInterest = isSubjectOfInterest(reader);
if (subjectOfInterest != null) {
return transform(reader, subjectOfInterest);
}
return null;
}
protected byte[] transform(final ClassReader reader,
final ClassProcessingParticipant[] subjectOfInterest) {
ClassWriter cv = new ClassWriter(ClassWriter.COMPUTE_FRAMES
| ClassWriter.COMPUTE_MAXS);
reader.accept(new ClassAdapter(cv) {
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces);
}
public FieldVisitor visitField(int access, String name,
String desc, String signature, Object value) {
for (int a = 0; a < subjectOfInterest.length; a++) {
ClassProcessingParticipant p = subjectOfInterest[a];
p.visitField(access,name,desc,signature,value);
}
return super.visitField(access, name, desc, signature, value);
}
public MethodVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
final ArrayList contributors = new ArrayList();
MethodVisitor visitMethod = super.visitMethod(access, name,
desc, signature, exceptions);
GeneratorAdapter ma = new GeneratorAdapter(visitMethod, access,
name, desc) {
public AnnotationVisitor visitAnnotation(String desc,
boolean visible) {
return super.visitAnnotation(desc, visible);
}
public AnnotationVisitor visitAnnotationDefault() {
return super.visitAnnotationDefault();
}
public void visitAttribute(Attribute attr) {
super.visitAttribute(attr);
}
public void visitCode() {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitCode();
}
super.visitCode();
}
public void visitEnd() {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitEnd();
}
super.visitEnd();
}
public void visitFieldInsn(int opcode, String owner,
String name, String desc) {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitFieldInsn(opcode, owner, name, desc);
}
super.visitFieldInsn(opcode, owner, name, desc);
}
public void visitInsn(int opcode) {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitInsn(opcode);
}
super.visitInsn(opcode);
}
public void visitIntInsn(int opcode, int operand) {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitIntInsn(opcode, operand);
}
super.visitIntInsn(opcode, operand);
}
public void visitJumpInsn(int opcode, Label label) {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitJumpInsn(opcode, label);
}
super.visitJumpInsn(opcode, label);
}
public void visitLabel(Label label) {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitLabel(label);
}
super.visitLabel(label);
}
public void visitLdcInsn(Object cst) {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitLdcInsn(cst);
}
super.visitLdcInsn(cst);
}
public void visitLookupSwitchInsn(Label dflt, int[] keys,
Label[] labels) {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitLookupSwitchInsn(dflt, keys, labels);
}
super.visitLookupSwitchInsn(dflt, keys, labels);
}
public void visitMethodInsn(int opcode, String owner,
String name, String desc) {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitMethodInsn(opcode, owner, name, desc);
}
super.visitMethodInsn(opcode, owner, name, desc);
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.afterVisitMethodInsn(opcode, owner, name, desc);
}
}
public void visitMultiANewArrayInsn(String desc, int dims) {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitMultiANewArrayInsn(desc, dims);
}
super.visitMultiANewArrayInsn(desc, dims);
}
public AnnotationVisitor visitParameterAnnotation(
int parameter, String desc, boolean visible) {
return super.visitParameterAnnotation(parameter, desc,
visible);
}
public void visitTableSwitchInsn(int min, int max,
Label dflt, Label[] labels) {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitTableSwitchInsn(min, max, dflt, labels);
}
super.visitTableSwitchInsn(min, max, dflt, labels);
}
public void visitTryCatchBlock(Label start, Label end,
Label handler, String type) {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitTryCatchBlock(start, end, handler, type);
}
super.visitTryCatchBlock(start, end, handler, type);
}
public void visitTypeInsn(int opcode, String type) {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitTypeInsn(opcode, type);
}
super.visitTypeInsn(opcode, type);
}
public void visitLineNumber(int line, Label start) {
int size = contributors.size();
for (int a = 0; a < size; a++) {
InstrumentationContributor c = (InstrumentationContributor) contributors
.get(a);
c.visitLineNumber(line, start);
}
super.visitLineNumber(line, start);
}
};
for (int a = 0; a < subjectOfInterest.length; a++) {
ClassProcessingParticipant p = subjectOfInterest[a];
InstrumentationContributor instrumentationContributor = p
.getInstrumentationContributor(access, name, desc,
signature, exceptions, ma);
if (instrumentationContributor != null) {
instrumentationContributor.visitMethod(reader, name, desc);
contributors.add(instrumentationContributor);
}
}
return ma;
}
}, ClassReader.EXPAND_FRAMES);
byte[] byteArray = cv.toByteArray();
return byteArray;
}
protected ClassProcessingParticipant[] isSubjectOfInterest(
ClassReader reader) {
int size = participants.size();
ArrayList result = null;
for (int a = 0; a < size; a++) {
ClassProcessingParticipant p = (ClassProcessingParticipant) participants
.get(a);
if (p.isInterestedIn(reader)) {
if (result == null) {
result = new ArrayList();
}
result.add(p);
}
}
return (ClassProcessingParticipant[]) (result == null ? null : result
.toArray(new ClassProcessingParticipant[result.size()]));
}
}