001 package org.shiftone.jrat.inject.bytecode.asm;
002
003
004 import org.objectweb.asm.*;
005 import org.objectweb.asm.commons.GeneratorAdapter;
006 import org.objectweb.asm.commons.Method;
007 import org.shiftone.jrat.core.JRatException;
008 import org.shiftone.jrat.inject.bytecode.InjectorStrategy;
009 import org.shiftone.jrat.inject.bytecode.Modifier;
010 import org.shiftone.jrat.util.VersionUtil;
011 import org.shiftone.jrat.util.log.Logger;
012
013 import java.util.Date;
014
015
016 public class InjectClassVisitor extends ClassAdapter implements Constants, Opcodes {
017
018 private static final Logger LOG = Logger.getLogger(InjectClassVisitor.class);
019 private int handlerCount;
020 private Type classType;
021 private GeneratorAdapter initializer;
022
023 public InjectClassVisitor(ClassVisitor visitor) {
024 super(visitor);
025 }
026
027
028 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
029
030 handlerCount = 0;
031 classType = Type.getType("L" + name.replace('.', '/') + ";");
032
033 super.visit(version, access, name, signature, superName, interfaces);
034
035 initializer = addInitializer();
036 }
037
038
039 private GeneratorAdapter addInitializer() {
040
041 int access = Modifier.PRIVATE_STATIC;
042 String descriptor = "()V";
043 MethodVisitor initMethodVisitor = super.visitMethod(access, initializeName, descriptor, null, null);
044 GeneratorAdapter initializer = new GeneratorAdapter(initMethodVisitor, access, initializeName,
045 descriptor);
046
047 initMethodVisitor.visitCode();
048
049 return initializer;
050 }
051
052
053 public void visitEnd() {
054
055 initializer.returnValue();
056 initializer.endMethod();
057 addCommentField();
058 super.visitEnd();
059 }
060
061
062 private void addCommentField() {
063
064 FieldVisitor commentField = super.visitField(Modifier.PRIVATE_STATIC_FINAL,
065 InjectorStrategy.COMMENT_FIELD_NAME, "Ljava/lang/String;", null,
066 "Class enhanced on " + new Date() + " w/ version JRat v"
067 + VersionUtil.getBuiltOn() + " built on " + VersionUtil.getBuiltOn());
068
069 commentField.visitEnd();
070 }
071
072
073 public FieldVisitor visitField(final int access, final String name, final String desc, final String signature,
074 final Object value) {
075
076 if (name.equals(InjectorStrategy.COMMENT_FIELD_NAME)) {
077 throw new JRatException("this class was previously injected by JRat");
078 }
079
080 return super.visitField(access, name, desc, signature, value);
081 }
082
083
084 private void addMethodHandlerField(String fieldName, String methodName, String descriptor) {
085
086 FieldVisitor handler = super.visitField(Modifier.PRIVATE_STATIC_FINAL, fieldName,
087 MethodHandler.TYPE.getDescriptor(), null, null);
088
089 handler.visitEnd();
090 initializer.push(classType.getClassName());
091 initializer.push(methodName);
092 initializer.push(descriptor);
093 initializer.invokeStatic(HandlerFactory.TYPE, HandlerFactory.getMethodHandler);
094 initializer.putStatic(classType, fieldName, MethodHandler.TYPE);
095 }
096
097
098 public void pushThis(GeneratorAdapter adapter, boolean isStatic) {
099
100 if (isStatic) {
101 adapter.push("test");
102 } else {
103 adapter.loadThis();
104 }
105 }
106
107
108 public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
109 String[] exceptions) {
110
111 if (name.equals("<clinit>") || name.equals("<init>") || Modifier.isAbstract(access)
112 || Modifier.isNative(access)) {
113
114 // LOG.debug("skipping " + name);
115 return super.visitMethod(access, name, descriptor, signature, exceptions);
116 }
117
118 int index = (handlerCount++);
119 String handlerFieldName = InjectorStrategy.HANDLER_PREFIX + index;
120 String targetMethodName = name + InjectorStrategy.METHOD_POSTFIX;
121
122 addMethodHandlerField(handlerFieldName, name, descriptor);
123
124 // -- [ Proxy Method ] --
125 {
126 Method method = new Method(name, descriptor);
127 MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
128 ProxyMethodVisitor visitor = new ProxyMethodVisitor(access, method, mv, classType, targetMethodName,
129 handlerFieldName);
130
131 visitor.visitCode();
132 visitor.visitEnd();
133 }
134
135 // -- [ Target Method ] --
136 return super.visitMethod(Modifier.makePrivate(access), targetMethodName, descriptor, signature, exceptions);
137 }
138 }