1 /***
2 *
3 */
4 package org.vafer.dependency.resources.buildtime;
5
6 import java.util.Iterator;
7 import java.util.Set;
8
9 import org.objectweb.asm.ClassVisitor;
10 import org.objectweb.asm.MethodVisitor;
11 import org.objectweb.asm.Opcodes;
12 import org.objectweb.asm.commons.RemappingClassAdapter;
13 import org.objectweb.asm.tree.AbstractInsnNode;
14 import org.objectweb.asm.tree.LdcInsnNode;
15 import org.objectweb.asm.tree.MethodInsnNode;
16 import org.objectweb.asm.tree.MethodNode;
17 import org.objectweb.asm.tree.analysis.Analyzer;
18 import org.objectweb.asm.tree.analysis.AnalyzerException;
19 import org.objectweb.asm.tree.analysis.Frame;
20 import org.objectweb.asm.tree.analysis.SourceInterpreter;
21 import org.objectweb.asm.tree.analysis.SourceValue;
22 import org.vafer.dependency.asm.Remapper;
23 import org.vafer.dependency.resources.ResolverUtils;
24
25 final class BuildtimeResourceResolvingClassAdapter extends RemappingClassAdapter implements Opcodes {
26
27 private final Remapper mapper;
28
29 public BuildtimeResourceResolvingClassAdapter(ClassVisitor cv, Remapper pMapper) {
30 super(cv, pMapper);
31 mapper = pMapper;
32 }
33
34 protected MethodVisitor createRemappingMethodAdapter( int access, String newDesc, MethodVisitor mv ) {
35 final MethodVisitor rmv = super.createRemappingMethodAdapter( access, newDesc, mv );
36
37
38 return new MethodNode(access, null, newDesc, null, null) {
39 public void visitEnd() {
40 final Analyzer an = new Analyzer(new SourceInterpreter());
41 try {
42 final Frame[] frames = an.analyze(className, this);
43
44
45
46 for (int i = 0; i < frames.length; i++) {
47 final Frame frame = frames[i];
48
49 final AbstractInsnNode insn = instructions.get(i);
50
51 if (insn.getOpcode() == Opcodes.INVOKEVIRTUAL) {
52 final MethodInsnNode minsn = (MethodInsnNode) insn;
53
54 final String owner = minsn.owner;
55 final String name = minsn.name;
56
57 if (ResolverUtils.needsResourceResolving(owner, name)) {
58
59 changeResource(frame, owner, name);
60
61 } else if (ResolverUtils.needsClassResolving(owner, name)) {
62
63 changeResource(frame, owner, name);
64 }
65 }
66 }
67
68 accept(rmv);
69 } catch (AnalyzerException ex) {
70 ex.printStackTrace();
71 }
72 }
73 };
74 }
75
76 private void changeResource( Frame frame, String owner, String name ) {
77
78 final SourceValue value = (SourceValue) frame.getStack(1);
79 final Set sources = value.insns;
80 for ( Iterator it = sources.iterator(); it.hasNext(); ) {
81 final AbstractInsnNode source = (AbstractInsnNode) it.next();
82 if (source.getOpcode() == Opcodes.LDC) {
83 final LdcInsnNode constant = (LdcInsnNode) source;
84
85
86 final String oldValue = (String) constant.cst;
87 final String newValue = mapper.map(oldValue);
88 constant.cst = newValue;
89
90 System.out.println("Changing " + owner + "." + name + " " + oldValue + "->" + newValue);
91
92 } else {
93
94 System.out.println("ERROR: resource source:" + source);
95 }
96 }
97
98 }
99
100 }