001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.object.bytecode;
005:
006: import com.tc.asm.ClassVisitor;
007: import com.tc.asm.FieldVisitor;
008: import com.tc.asm.Label;
009: import com.tc.asm.MethodAdapter;
010: import com.tc.asm.MethodVisitor;
011: import com.tc.asm.Opcodes;
012:
013: import java.util.Collection;
014: import java.util.Collections;
015: import java.util.Map;
016:
017: public class ChangeClassNameRootAdapter extends
018: ChangeClassNameHierarchyAdapter implements Opcodes {
019: private final Collection innerClassesNames;
020:
021: private final String srcClassNameSlashes;
022: private final String targetClassNameSlashes;
023: private final String fullClassNameSlashes;
024: private final String srcInnerClassName;
025: private final String targetInnerClassName;
026: private final Map instrumentedContext;
027: private final ChangeContext changeContext;
028: private final Collection methodsToBeRemoved;
029:
030: public static String replaceClassName(String className,
031: String srcClassName, String targetClassName,
032: String srcInnerClassName, String targetInnerClassName) {
033: if (className == null || className.length() == 0) {
034: return className;
035: }
036:
037: String returnStr = replaceInnerClassName(replaceClassNameInner(
038: className, srcClassName, targetClassName),
039: srcInnerClassName, targetInnerClassName);
040: return returnStr.replace(SLASH_DELIMITER, DOT_DELIMITER);
041: }
042:
043: private static String replaceClassNameInner(String classNameDots,
044: String srcClassNameDots, String targetClassNameDots) {
045: if (classNameDots == null || classNameDots.length() == 0) {
046: return classNameDots;
047: }
048:
049: classNameDots = classNameDots.replace(DOT_DELIMITER,
050: SLASH_DELIMITER);
051: srcClassNameDots = srcClassNameDots.replace(DOT_DELIMITER,
052: SLASH_DELIMITER);
053: targetClassNameDots = targetClassNameDots.replace(
054: DOT_DELIMITER, SLASH_DELIMITER);
055:
056: int index = classNameDots.indexOf(srcClassNameDots);
057: if (index == -1) {
058: return classNameDots;
059: }
060:
061: StringBuffer newClassName = new StringBuffer();
062: while (index != -1) {
063: if (index > 0) {
064: newClassName.append(classNameDots.substring(0, index));
065: }
066: newClassName.append(targetClassNameDots);
067: classNameDots = classNameDots.substring(index
068: + srcClassNameDots.length());
069: index = classNameDots.indexOf(srcClassNameDots);
070: }
071: newClassName.append(classNameDots);
072: return newClassName.toString();
073: }
074:
075: private static String replaceInnerClassName(String classNameDots,
076: String srcInnerClassName, String targetInnerClassName) {
077: if (classNameDots == null || srcInnerClassName == null
078: || targetInnerClassName == null) {
079: return classNameDots;
080: }
081:
082: int index = classNameDots.indexOf(INNER_CLASS_DELIMITER);
083: if (index == -1) {
084: return classNameDots;
085: }
086:
087: StringBuffer newClassName = new StringBuffer();
088: newClassName.append(classNameDots.substring(0, index + 1));
089: String innerClassName = classNameDots.substring(index + 1);
090: innerClassName = replaceClassNameInner(innerClassName,
091: srcInnerClassName, targetInnerClassName);
092: newClassName.append(innerClassName);
093: return newClassName.toString();
094: }
095:
096: public ChangeClassNameRootAdapter(ClassVisitor cv,
097: String fullClassNameDots, String srcClassNameDots,
098: String targetClassNameDots, String srcInnerClassName,
099: String targetInnerClassName, Map instrumentedContext,
100: Collection innerClassesHolder) {
101: this (cv, fullClassNameDots, srcClassNameDots,
102: targetClassNameDots, srcInnerClassName,
103: targetInnerClassName, instrumentedContext,
104: innerClassesHolder, Collections.EMPTY_SET);
105: }
106:
107: /**
108: * @param fullClassNameDots The fully qualified class name that this class adapter is working on, e.g.,
109: * java.util.LinkedHashMap.
110: * @param srcClassNameSlashes The fully qualified class name that needs to be changed, e.g., java.util.HashMap$Entry.
111: * @param targetClassNameSlashes The fully qualified new class name, e.g., java.util.HashMap_J$Entry.
112: */
113: public ChangeClassNameRootAdapter(ClassVisitor cv,
114: String fullClassNameDots, String srcClassNameDots,
115: String targetClassNameDots, String srcInnerClassName,
116: String targetInnerClassName, Map instrumentedContext,
117: Collection innerClassesHolder, Collection methodsToBeRemoved) {
118: super (cv);
119: this .srcClassNameSlashes = srcClassNameDots.replace(
120: DOT_DELIMITER, SLASH_DELIMITER);
121: this .targetClassNameSlashes = targetClassNameDots.replace(
122: DOT_DELIMITER, SLASH_DELIMITER);
123: this .srcInnerClassName = srcInnerClassName;
124: this .targetInnerClassName = targetInnerClassName;
125: this .fullClassNameSlashes = fullClassNameDots.replace(
126: DOT_DELIMITER, SLASH_DELIMITER);
127: this .innerClassesNames = innerClassesHolder;
128: this .methodsToBeRemoved = methodsToBeRemoved;
129: this .instrumentedContext = instrumentedContext;
130: this .changeContext = addNewContextIfNotExist(
131: fullClassNameSlashes, replaceInnerClassName(
132: replaceClassNameInner(fullClassNameSlashes,
133: srcClassNameSlashes,
134: targetClassNameSlashes),
135: srcInnerClassName, targetInnerClassName),
136: instrumentedContext);
137: }
138:
139: public void visit(int version, int access, String name,
140: String signature, String super Name, String[] interfaces) {
141: this .changeContext.setOriginalSuperClass(super Name);
142: name = replaceInnerClassName(replaceClassNameInner(name,
143: srcClassNameSlashes, targetClassNameSlashes),
144: srcInnerClassName, targetInnerClassName);
145: super Name = replaceClassNameInner(super Name,
146: srcClassNameSlashes, targetClassNameSlashes);
147: super .visit(version, access & ~ACC_ABSTRACT, name, signature,
148: super Name, interfaces);
149: }
150:
151: public void visitSource(String source, String debug) {
152: int lastIndex = srcClassNameSlashes
153: .lastIndexOf(SLASH_DELIMITER);
154: String srcName = srcClassNameSlashes.substring(lastIndex + 1);
155: lastIndex = targetClassNameSlashes.lastIndexOf(SLASH_DELIMITER);
156: String targetName = targetClassNameSlashes
157: .substring(lastIndex + 1);
158:
159: source = replaceClassNameInner(source, srcName, targetName);
160: super .visitSource(source, debug);
161: }
162:
163: public void visitInnerClass(String name, String outerName,
164: String innerName, int access) {
165: if (innerClassesNames != null
166: && !innerClassesNames.contains(name)
167: && fullClassNameSlashes.equals(outerName)) {
168: innerClassesNames.add(name);
169: }
170: name = replaceInnerClassName(replaceClassNameInner(name,
171: srcClassNameSlashes, targetClassNameSlashes),
172: srcInnerClassName, targetInnerClassName);
173: outerName = replaceInnerClassName(
174: replaceClassNameInner(outerName, srcClassNameSlashes,
175: targetClassNameSlashes), srcInnerClassName,
176: targetInnerClassName);
177: super .visitInnerClass(name, outerName, innerName, access);
178: }
179:
180: public FieldVisitor visitField(int access, String name,
181: String desc, String signature, Object value) {
182: String convertedDesc = replaceInnerClassName(
183: replaceClassNameInner(desc, srcClassNameSlashes,
184: targetClassNameSlashes), srcInnerClassName,
185: targetInnerClassName);
186: String convertedSign = replaceClassName(signature,
187: srcClassNameSlashes, targetClassNameSlashes,
188: srcInnerClassName, targetInnerClassName);
189: if (!convertedDesc.equals(desc)
190: || (convertedSign != null && !convertedSign
191: .equals(signature))) {
192: changeContext.addModifiedFieldInfo(name, desc,
193: convertedDesc, signature, convertedSign);
194: }
195: return super .visitField(access, name, convertedDesc,
196: convertedSign, value);
197: }
198:
199: public MethodVisitor visitMethod(int access, String name,
200: String desc, String signature, String[] exceptions) {
201: // if (methodsToBeRemoved.contains(name+desc)) { return invokeSuperVisitMethod(access, name, desc, signature,
202: // exceptions, instrumentedContext, fullClassNameSlashes); }
203:
204: String convertedDesc = replaceInnerClassName(
205: replaceClassNameInner(desc, srcClassNameSlashes,
206: targetClassNameSlashes), srcInnerClassName,
207: targetInnerClassName);
208: String convertedSign = replaceInnerClassName(
209: replaceClassNameInner(signature, srcClassNameSlashes,
210: targetClassNameSlashes), srcInnerClassName,
211: targetInnerClassName);
212:
213: if (!convertedDesc.equals(desc)
214: || (convertedSign != null && !convertedSign
215: .equals(signature))) {
216: changeContext.addModifiedMethodInfo(name, desc,
217: convertedDesc, signature, convertedSign);
218: }
219: return new ChangeClassNameMethodAdapter(super .visitMethod(
220: access, name, convertedDesc, convertedSign, exceptions));
221: }
222:
223: private class ChangeClassNameMethodAdapter extends MethodAdapter
224: implements Opcodes {
225: public ChangeClassNameMethodAdapter(MethodVisitor mv) {
226: super (mv);
227: }
228:
229: public void visitFieldInsn(int opcode, String owner,
230: String name, String desc) {
231: owner = replaceInnerClassName(replaceClassNameInner(owner,
232: srcClassNameSlashes, targetClassNameSlashes),
233: srcInnerClassName, targetInnerClassName);
234: desc = replaceInnerClassName(replaceClassNameInner(desc,
235: srcClassNameSlashes, targetClassNameSlashes),
236: srcInnerClassName, targetInnerClassName);
237: super .visitFieldInsn(opcode, owner, name, desc);
238: }
239:
240: public void visitTypeInsn(int opcode, String desc) {
241: ChangeContext context = (ChangeContext) instrumentedContext
242: .get(desc);
243: if (context != null) {
244: desc = context.convertedClassNameSlashes;
245: } else {
246: desc = replaceInnerClassName(replaceClassNameInner(
247: desc, srcClassNameSlashes,
248: targetClassNameSlashes), srcInnerClassName,
249: targetInnerClassName);
250: }
251: super .visitTypeInsn(opcode, desc);
252: }
253:
254: public void visitMethodInsn(int opcode, String owner,
255: String name, String desc) {
256: ChangeContext context = (ChangeContext) instrumentedContext
257: .get(owner);
258: if (context != null) {
259: owner = context.convertedClassNameSlashes;
260: } else {
261: owner = replaceInnerClassName(replaceClassNameInner(
262: owner, srcClassNameSlashes,
263: targetClassNameSlashes), srcInnerClassName,
264: targetInnerClassName);
265: }
266:
267: desc = replaceInnerClassName(replaceClassNameInner(desc,
268: srcClassNameSlashes, targetClassNameSlashes),
269: srcInnerClassName, targetInnerClassName);
270:
271: super .visitMethodInsn(opcode, owner, name, desc);
272: }
273:
274: public void visitLocalVariable(String name, String desc,
275: String signature, Label start, Label end, int index) {
276: desc = replaceClassNameInner(desc, srcClassNameSlashes,
277: targetClassNameSlashes);
278: super.visitLocalVariable(name, desc, signature, start, end,
279: index);
280: }
281: }
282: }
|