001: /*
002: * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.instrument;
027:
028: import java.lang.instrument.Instrumentation;
029: import java.lang.instrument.ClassFileTransformer;
030: import java.security.ProtectionDomain;
031:
032: /*
033: * Copyright 2003 Wily Technology, Inc.
034: */
035:
036: /**
037: * Support class for the InstrumentationImpl. Manages the list of registered transformers.
038: * Keeps everything in the right order, deals with sync of the list,
039: * and actually does the calling of the transformers.
040: */
041: public class TransformerManager {
042: private class TransformerInfo {
043: final ClassFileTransformer mTransformer;
044: String mPrefix;
045:
046: TransformerInfo(ClassFileTransformer transformer) {
047: mTransformer = transformer;
048: mPrefix = null;
049: }
050:
051: ClassFileTransformer transformer() {
052: return mTransformer;
053: }
054:
055: String getPrefix() {
056: return mPrefix;
057: }
058:
059: void setPrefix(String prefix) {
060: mPrefix = prefix;
061: }
062: }
063:
064: /**
065: * a given instance of this list is treated as immutable to simplify sync;
066: * we pay copying overhead whenever the list is changed rather than every time
067: * the list is referenced.
068: * The array is kept in the order the transformers are added via addTransformer
069: * (first added is 0, last added is length-1)
070: * Use an array, not a List or other Collection. This keeps the set of classes
071: * used by this code to a minimum. We want as few dependencies as possible in this
072: * code, since it is used inside the class definition system. Any class referenced here
073: * cannot be transformed by Java code.
074: */
075: private TransformerInfo[] mTransformerList;
076:
077: /***
078: * Is this TransformerManager for transformers capable of retransformation?
079: */
080: private boolean mIsRetransformable;
081:
082: TransformerManager(boolean isRetransformable) {
083: mTransformerList = new TransformerInfo[0];
084: mIsRetransformable = isRetransformable;
085: }
086:
087: boolean isRetransformable() {
088: return mIsRetransformable;
089: }
090:
091: public synchronized void addTransformer(
092: ClassFileTransformer transformer) {
093: TransformerInfo[] oldList = mTransformerList;
094: TransformerInfo[] newList = new TransformerInfo[oldList.length + 1];
095: System.arraycopy(oldList, 0, newList, 0, oldList.length);
096: newList[oldList.length] = new TransformerInfo(transformer);
097: mTransformerList = newList;
098: }
099:
100: public synchronized boolean removeTransformer(
101: ClassFileTransformer transformer) {
102: boolean found = false;
103: TransformerInfo[] oldList = mTransformerList;
104: int oldLength = oldList.length;
105: int newLength = oldLength - 1;
106:
107: // look for it in the list, starting at the last added, and remember
108: // where it was if we found it
109: int matchingIndex = 0;
110: for (int x = oldLength - 1; x >= 0; x--) {
111: if (oldList[x].transformer() == transformer) {
112: found = true;
113: matchingIndex = x;
114: break;
115: }
116: }
117:
118: // make a copy of the array without the matching element
119: if (found) {
120: TransformerInfo[] newList = new TransformerInfo[newLength];
121:
122: // copy up to but not including the match
123: if (matchingIndex > 0) {
124: System.arraycopy(oldList, 0, newList, 0, matchingIndex);
125: }
126:
127: // if there is anything after the match, copy it as well
128: if (matchingIndex < (newLength)) {
129: System.arraycopy(oldList, matchingIndex + 1, newList,
130: matchingIndex, (newLength) - matchingIndex);
131: }
132: mTransformerList = newList;
133: }
134: return found;
135: }
136:
137: synchronized boolean includesTransformer(
138: ClassFileTransformer transformer) {
139: for (TransformerInfo info : mTransformerList) {
140: if (info.transformer() == transformer) {
141: return true;
142: }
143: }
144: return false;
145: }
146:
147: // This function doesn't actually snapshot anything, but should be
148: // used to set a local variable, which will snapshot the transformer
149: // list because of the copying semantics of mTransformerList (see
150: // the comment for mTransformerList).
151: private TransformerInfo[] getSnapshotTransformerList() {
152: return mTransformerList;
153: }
154:
155: public byte[] transform(ClassLoader loader, String classname,
156: Class classBeingRedefined,
157: ProtectionDomain protectionDomain, byte[] classfileBuffer) {
158: boolean someoneTouchedTheBytecode = false;
159:
160: TransformerInfo[] transformerList = getSnapshotTransformerList();
161:
162: byte[] bufferToUse = classfileBuffer;
163:
164: // order matters, gotta run 'em in the order they were added
165: for (int x = 0; x < transformerList.length; x++) {
166: TransformerInfo transformerInfo = transformerList[x];
167: ClassFileTransformer transformer = transformerInfo
168: .transformer();
169: byte[] transformedBytes = null;
170:
171: try {
172: transformedBytes = transformer.transform(loader,
173: classname, classBeingRedefined,
174: protectionDomain, bufferToUse);
175: } catch (Throwable t) {
176: // don't let any one transformer mess it up for the others.
177: // This is where we need to put some logging. What should go here? FIXME
178: }
179:
180: if (transformedBytes != null) {
181: someoneTouchedTheBytecode = true;
182: bufferToUse = transformedBytes;
183: }
184: }
185:
186: // if someone modified it, return the modified buffer.
187: // otherwise return null to mean "no transforms occurred"
188: byte[] result;
189: if (someoneTouchedTheBytecode) {
190: result = bufferToUse;
191: } else {
192: result = null;
193: }
194:
195: return result;
196: }
197:
198: int getTransformerCount() {
199: TransformerInfo[] transformerList = getSnapshotTransformerList();
200: return transformerList.length;
201: }
202:
203: boolean setNativeMethodPrefix(ClassFileTransformer transformer,
204: String prefix) {
205: TransformerInfo[] transformerList = getSnapshotTransformerList();
206:
207: for (int x = 0; x < transformerList.length; x++) {
208: TransformerInfo transformerInfo = transformerList[x];
209: ClassFileTransformer aTransformer = transformerInfo
210: .transformer();
211:
212: if (aTransformer == transformer) {
213: transformerInfo.setPrefix(prefix);
214: return true;
215: }
216: }
217: return false;
218: }
219:
220: String[] getNativeMethodPrefixes() {
221: TransformerInfo[] transformerList = getSnapshotTransformerList();
222: String[] prefixes = new String[transformerList.length];
223:
224: for (int x = 0; x < transformerList.length; x++) {
225: TransformerInfo transformerInfo = transformerList[x];
226: prefixes[x] = transformerInfo.getPrefix();
227: }
228: return prefixes;
229: }
230: }
|