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.ClassAdapter;
007: import com.tc.asm.ClassVisitor;
008: import com.tc.asm.FieldVisitor;
009: import com.tc.asm.Label;
010: import com.tc.asm.MethodAdapter;
011: import com.tc.asm.MethodVisitor;
012: import com.tc.asm.Opcodes;
013:
014: import java.util.Collection;
015:
016: public class ChangePackageClassAdapter extends ClassAdapter implements
017: Opcodes {
018: private final static char DOT_DELIMITER = '.';
019: private final static char SLASH_DELIMITER = '/';
020:
021: private final String newName;
022: private final String targetName;
023: private final String newType;
024: private final String targetType;
025:
026: private final Collection innerClassNames;
027:
028: public static String replaceClassName(String name,
029: String targetPackage, String newPackage) {
030: name = name.replace(SLASH_DELIMITER, DOT_DELIMITER);
031: int index = name.indexOf(targetPackage);
032: if (index == -1) {
033: return name;
034: }
035: return newPackage + DOT_DELIMITER
036: + name.substring(targetPackage.length() + 1);
037: }
038:
039: /**
040: * @param targetClassName The class name at which package needs to be changed, e.g., HashMap.
041: * @param targetPackageName The package name at which package needs to be changed, e.g., com.tc.bootjar.java.util.
042: * @param newPackage The new package name, e.g., java.util.
043: * @param innerClassesHolder A collection which contains the inner class names of this class.
044: * It could be null if the inner class can be ignored.
045: */
046: public ChangePackageClassAdapter(ClassVisitor cv,
047: String targetClassName, String targetPackage,
048: String newPackage, Collection innerClassesHolder) {
049: super (cv);
050: this .targetName = targetPackage.replace(DOT_DELIMITER,
051: SLASH_DELIMITER)
052: + SLASH_DELIMITER + targetClassName;
053: this .newName = newPackage.replace(DOT_DELIMITER,
054: SLASH_DELIMITER)
055: + SLASH_DELIMITER + targetClassName;
056: this .targetType = "L" + targetName;
057: this .newType = "L" + newName;
058: this .innerClassNames = innerClassesHolder;
059: }
060:
061: public void visit(int version, int access, String name,
062: String signature, String super Name, String[] interfaces) {
063: name = replaceName(name);
064: super Name = replaceName(super Name);
065: super .visit(version, access, name, signature, super Name,
066: interfaces);
067: }
068:
069: public FieldVisitor visitField(int access, String name,
070: String desc, String signature, Object value) {
071: desc = replaceName(desc);
072: return super .visitField(access, name, desc, signature, value);
073: }
074:
075: public void visitInnerClass(String name, String outerName,
076: String innerName, int access) {
077: if (innerClassNames != null && !innerClassNames.contains(name)
078: && targetName.equals(outerName)) {
079: innerClassNames.add(name);
080: }
081:
082: name = replaceName(name);
083: outerName = replaceName(outerName);
084: super .visitInnerClass(name, outerName, innerName, access);
085: }
086:
087: public MethodVisitor visitMethod(int access, String name,
088: String desc, String signature, String[] exceptions) {
089: desc = replaceName(desc);
090: MethodVisitor mv = super .visitMethod(access, name, desc,
091: signature, exceptions);
092: return new ChangePackageMethodVisitor(mv);
093: }
094:
095: private String replaceName(String name) {
096: if (targetName.equals(name)) {
097: return newName;
098: }
099: int index = name.indexOf(targetName);
100: while (index != -1) {
101: name = name.substring(0, index) + newName
102: + name.substring(index + targetName.length());
103: index = name.indexOf(targetName);
104: }
105: return name;
106: }
107:
108: private String replaceDesc(String desc) {
109: if (targetType.equals(desc)) {
110: return newType;
111: }
112: int index = desc.indexOf(targetType);
113: while (index != -1) {
114: desc = desc.substring(0, index) + newType
115: + desc.substring(index + targetType.length());
116: index = desc.indexOf(targetType);
117: }
118: return desc;
119: }
120:
121: private class ChangePackageMethodVisitor extends MethodAdapter
122: implements Opcodes {
123: public ChangePackageMethodVisitor(MethodVisitor mv) {
124: super (mv);
125: }
126:
127: public void visitFieldInsn(int opcode, String owner,
128: String name, String desc) {
129: owner = replaceName(owner);
130: desc = replaceName(desc);
131: super .visitFieldInsn(opcode, owner, name, desc);
132: }
133:
134: public void visitMethodInsn(int opcode, String owner,
135: String name, String desc) {
136: owner = replaceName(owner);
137: desc = replaceDesc(desc);
138: super .visitMethodInsn(opcode, owner, name, desc);
139: }
140:
141: public void visitTypeInsn(int opcode, String desc) {
142: desc = replaceName(desc);
143: super .visitTypeInsn(opcode, desc);
144: }
145:
146: public void visitLocalVariable(String name, String desc,
147: String signature, Label start, Label end, int index) {
148: desc = replaceName(desc);
149: super.visitLocalVariable(name, desc, signature, start, end,
150: index);
151: }
152: }
153: }
|