001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.harmony.instrument.internal;
019:
020: import java.lang.instrument.ClassDefinition;
021: import java.lang.instrument.ClassFileTransformer;
022: import java.lang.instrument.Instrumentation;
023: import java.lang.instrument.UnmodifiableClassException;
024: import java.lang.reflect.Method;
025: import java.security.ProtectionDomain;
026:
027: import org.apache.harmony.instrument.internal.nls.Messages;
028:
029: /**
030: * Default implementation of Instrumentation
031: */
032: public class InstrumentationImpl implements Instrumentation {
033: /*
034: * ----------------------------------------------------------------------------
035: * Consts
036: * ----------------------------------------------------------------------------
037: */
038:
039: private static final Class[] PREMAIN_SIGNATURE = new Class[] {
040: String.class, Instrumentation.class };
041:
042: /*
043: * ----------------------------------------------------------------------------
044: * Variables
045: * ----------------------------------------------------------------------------
046: */
047: private ClassFileTransformer[] transformers = new ClassFileTransformer[0];
048:
049: private boolean isRedefineClassesSupported;
050:
051: /*
052: * ----------------------------------------------------------------------------
053: * Constructor
054: * ----------------------------------------------------------------------------
055: */
056: /**
057: * Constructs a new instance.
058: *
059: * @param isRedefineClassesSupported
060: */
061: public InstrumentationImpl(boolean isRedefineClassesSupported) {
062: this .isRedefineClassesSupported = isRedefineClassesSupported;
063: }
064:
065: /*
066: * ----------------------------------------------------------------------------
067: * Methods implemented from Instrumentation
068: * ----------------------------------------------------------------------------
069: */
070: /*
071: * (non-Javadoc)
072: *
073: * @see java.lang.instrument.Instrumentation#addTransformer(java.lang.instrument.ClassFileTransformer)
074: */
075: public void addTransformer(ClassFileTransformer transformer) {
076: if (null == transformer) {
077: throw new NullPointerException();
078: }
079: int length = transformers.length;
080: ClassFileTransformer[] temp = new ClassFileTransformer[length + 1];
081: System.arraycopy(transformers, 0, temp, 0, length);
082: temp[length] = transformer;
083: transformers = temp;
084: }
085:
086: /*
087: * (non-Javadoc)
088: *
089: * @see java.lang.instrument.Instrumentation#redefineClasses(java.lang.instrument.ClassDefinition[])
090: */
091: public void redefineClasses(ClassDefinition[] definitions)
092: throws ClassNotFoundException, UnmodifiableClassException {
093: if (!isRedefineClassesSupported) {
094: throw new UnsupportedOperationException(Messages
095: .getString("instrument.3")); //$NON-NLS-1$
096: }
097: for (int i = 0; i < definitions.length; i++) {
098: if (null == definitions[i]) {
099: throw new NullPointerException();
100: }
101: }
102: redefineClasses_native(definitions);
103: }
104:
105: private native void redefineClasses_native(
106: ClassDefinition[] definitions);
107:
108: /*
109: * (non-Javadoc)
110: *
111: * @see java.lang.instrument.Instrumentation#removeTransformer(java.lang.instrument.ClassFileTransformer)
112: */
113: public boolean removeTransformer(ClassFileTransformer transformer) {
114: if (null == transformer) {
115: throw new NullPointerException();
116: }
117: int i = 0;
118: int length = transformers.length;
119: for (i = length - 1; i >= 0 && transformers[i] != transformer; i--)
120: ;
121: if (i == -1) {
122: return false;
123: }
124: ClassFileTransformer[] temp = new ClassFileTransformer[length - 1];
125: if (i > 0) {
126: System.arraycopy(transformers, 0, temp, 0, i);
127: }
128: if (i < length - 1) {
129: System.arraycopy(transformers, i + 1, temp, i, length - i
130: - 1);
131: }
132: transformers = temp;
133: return true;
134: }
135:
136: public void clear() {
137: transformers = new ClassFileTransformer[0];
138: }
139:
140: /*
141: * (non-Javadoc)
142: *
143: * @see java.lang.instrument.Instrumentation#getAllLoadedClasses()
144: */
145: public native Class[] getAllLoadedClasses();
146:
147: /*
148: * (non-Javadoc)
149: *
150: * @see java.lang.instrument.Instrumentation#getInitiatedClasses(java.lang.ClassLoader)
151: */
152: public native Class[] getInitiatedClasses(ClassLoader loader);
153:
154: /*
155: * (non-Javadoc)
156: *
157: * @see java.lang.instrument.Instrumentation#getObjectSize(java.lang.Object)
158: */
159: public long getObjectSize(Object objectToSize) {
160: if (null == objectToSize) {
161: throw new NullPointerException();
162: }
163: return getObjectSize_native(objectToSize);
164: }
165:
166: private native long getObjectSize_native(Object objectToSize);
167:
168: /*
169: * (non-Javadoc)
170: *
171: * @see java.lang.instrument.Instrumentation#isRedefineClassesSupported()
172: */
173: public boolean isRedefineClassesSupported() {
174: return isRedefineClassesSupported;
175: }
176:
177: /*
178: * ----------------------------------------------------------------------------
179: * Callback methods for native JVMTI agent
180: * ----------------------------------------------------------------------------
181: */
182: /*
183: * ClassFileLoadHook event handler method
184: */
185: private byte[] transform(ClassLoader loader, byte[] classNameBytes,
186: Class<?> classBeingRedefined,
187: ProtectionDomain protectionDomain, byte[] classfileBuffer) {
188: byte[] source = classfileBuffer;
189: byte[] result = null;
190: byte[] trans = null;
191: String className = new String(classNameBytes);
192: for (ClassFileTransformer t : transformers) {
193: try {
194: trans = t.transform(loader, className,
195: classBeingRedefined, protectionDomain, source);
196: if (null != trans && 0 != trans.length) {
197: result = trans;
198: source = trans;
199: }
200: } catch (Exception e) {
201: // nothing to do, just continue~
202: }
203: }
204: return result;
205: }
206:
207: /*
208: * callback method to execute javaagents' premain method
209: */
210: private void executePremain(byte[] className, byte[] options) {
211: try {
212: ClassLoader loader = ClassLoader.getSystemClassLoader();
213: Class c = loader.loadClass(new String(className));
214: Method method = c.getMethod("premain", PREMAIN_SIGNATURE); //$NON-NLS-1$
215: method.invoke(null,
216: new Object[] {
217: null == options ? null
218: : new String(options), this });
219: } catch (Exception e) {
220: e.printStackTrace();
221: System.err.println(Messages.getString("instrument.4")); //$NON-NLS-1$
222: System.exit(1);
223: }
224: }
225: }
|