equinox-agentclass-hook/src/main/java/org/netbeans/html/equinox/agentclass/NbInstrumentation.java
author Jaroslav Tulach <jaroslav.tulach@netbeans.org>
Fri, 07 Feb 2014 07:44:34 +0100
changeset 551 7ca2253fa86d
parent 393 8b025bcde7bb
child 790 30f20d9c0986
permissions -rw-r--r--
Updating copyright headers to mention current year
     1 /**
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     5  *
     6  * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
     7  * Other names may be trademarks of their respective owners.
     8  *
     9  * The contents of this file are subject to the terms of either the GNU
    10  * General Public License Version 2 only ("GPL") or the Common
    11  * Development and Distribution License("CDDL") (collectively, the
    12  * "License"). You may not use this file except in compliance with the
    13  * License. You can obtain a copy of the License at
    14  * http://www.netbeans.org/cddl-gplv2.html
    15  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    16  * specific language governing permissions and limitations under the
    17  * License.  When distributing the software, include this License Header
    18  * Notice in each file and include the License file at
    19  * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    20  * particular file as subject to the "Classpath" exception as provided
    21  * by Oracle in the GPL Version 2 section of the License file that
    22  * accompanied this code. If applicable, add the following below the
    23  * License Header, with the fields enclosed by brackets [] replaced by
    24  * your own identifying information:
    25  * "Portions Copyrighted [year] [name of copyright owner]"
    26  *
    27  * Contributor(s):
    28  *
    29  * The Original Software is NetBeans. The Initial Developer of the Original
    30  * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    31  *
    32  * If you wish your version of this file to be governed by only the CDDL
    33  * or only the GPL Version 2, indicate your decision by adding
    34  * "[Contributor] elects to include this software in this distribution
    35  * under the [CDDL or GPL Version 2] license." If you do not indicate a
    36  * single choice of license, a recipient has the option to distribute
    37  * your version of this file under either the CDDL, the GPL Version 2 or
    38  * to extend the choice of license to its licensees as provided above.
    39  * However, if you add GPL Version 2 code and therefore, elected the GPL
    40  * Version 2 license, then the option applies only if the new code is
    41  * made subject to such option by the copyright holder.
    42  */
    43 package org.netbeans.html.equinox.agentclass;
    44 
    45 import java.lang.instrument.ClassDefinition;
    46 import java.lang.instrument.ClassFileTransformer;
    47 import java.lang.instrument.IllegalClassFormatException;
    48 import java.lang.instrument.Instrumentation;
    49 import java.lang.instrument.UnmodifiableClassException;
    50 import java.lang.reflect.InvocationTargetException;
    51 import java.lang.reflect.Method;
    52 import java.security.ProtectionDomain;
    53 import java.util.Collection;
    54 import java.util.HashSet;
    55 import java.util.List;
    56 import java.util.Set;
    57 import java.util.concurrent.CopyOnWriteArrayList;
    58 import java.util.jar.JarFile;
    59 import java.util.logging.Level;
    60 import java.util.logging.Logger;
    61 
    62 /**
    63  *
    64  * @author Jaroslav Tulach <jtulach@netbeans.org>
    65  */
    66 final class NbInstrumentation implements Instrumentation {
    67     private static final Logger LOG = Logger.getLogger(NbInstrumentation.class.getName());
    68     private static final Object LOCK = new Object();
    69     private static volatile Collection<NbInstrumentation> ACTIVE;
    70 
    71     private final List<ClassFileTransformer> transformers = new CopyOnWriteArrayList<ClassFileTransformer>();
    72     private static final ThreadLocal<Boolean> IN = new ThreadLocal<Boolean>();
    73     
    74     static NbInstrumentation registerAgent(ClassLoader l, String agentClassName) {
    75         try {
    76             return registerImpl(agentClassName, l);
    77         } catch (Throwable ex) {
    78             LOG.log(Level.WARNING, "Cannot register " + agentClassName, ex);
    79             return null;
    80         }
    81     }
    82     static void unregisterAgent(NbInstrumentation instr) {
    83         synchronized (LOCK) {
    84             if (ACTIVE != null) {
    85                 Collection<NbInstrumentation> clone = new HashSet<NbInstrumentation>();
    86                 clone.addAll(ACTIVE);
    87                 clone.remove(instr);
    88                 ACTIVE = clone;
    89             }
    90         }
    91     }
    92     private static NbInstrumentation registerImpl(String agentClassName, ClassLoader l) throws ClassNotFoundException, IllegalArgumentException, NoSuchMethodException, SecurityException, IllegalAccessException, InvocationTargetException {
    93         final NbInstrumentation inst = new NbInstrumentation();
    94         synchronized (LOCK) {
    95             if (ACTIVE == null) {
    96                 ACTIVE = new HashSet<NbInstrumentation>();
    97             } else {
    98                 Set<NbInstrumentation> s = new HashSet<NbInstrumentation>();
    99                 s.addAll(ACTIVE);
   100                 ACTIVE = s;
   101             }
   102             ACTIVE.add(inst);
   103         }
   104         Class<?> agentClass = Class.forName(agentClassName, true, l);
   105         try {
   106             Method m = agentClass.getMethod("agentmain", String.class, Instrumentation.class); // NOI18N
   107             m.invoke(null, "", inst);
   108         } catch (NoSuchMethodException ex) {
   109             Method m = agentClass.getMethod("agentmain", String.class); // NOI18N
   110             m.invoke(null, "");
   111         }
   112         return inst;
   113     }
   114     
   115     public static byte[] patchByteCode(ClassLoader l, String className, ProtectionDomain pd, byte[] arr) throws IllegalClassFormatException {
   116         if (ACTIVE == null) {
   117             return arr;
   118         }
   119         if (Boolean.TRUE.equals(IN.get())) {
   120             return arr;
   121         }
   122         try {
   123             IN.set(Boolean.TRUE);
   124             for (NbInstrumentation inst : ACTIVE) {
   125                 for (ClassFileTransformer t : inst.transformers) {
   126                     arr = t.transform(l, className, null, pd, arr);
   127                 }
   128             }
   129         } finally {
   130             IN.set(null);
   131         }
   132         return arr;
   133     }
   134     
   135     //
   136     // Instrumentation methods
   137     //
   138 
   139     @Override
   140     public void addTransformer(ClassFileTransformer transformer, boolean canRetransform) {
   141         transformers.add(transformer);
   142     }
   143 
   144     @Override
   145     public void addTransformer(ClassFileTransformer transformer) {
   146         transformers.add(transformer);
   147     }
   148 
   149     @Override
   150     public boolean removeTransformer(ClassFileTransformer transformer) {
   151         return transformers.remove(transformer);
   152     }
   153 
   154     @Override
   155     public boolean isRetransformClassesSupported() {
   156         return false;
   157     }
   158 
   159     @Override
   160     public void retransformClasses(Class<?>... classes) throws UnmodifiableClassException {
   161         throw new UnmodifiableClassException();
   162     }
   163 
   164     @Override
   165     public boolean isRedefineClassesSupported() {
   166         return false;
   167     }
   168 
   169     @Override
   170     public void redefineClasses(ClassDefinition... definitions) throws ClassNotFoundException, UnmodifiableClassException {
   171         throw new UnmodifiableClassException();
   172     }
   173 
   174     @Override
   175     public boolean isModifiableClass(Class<?> theClass) {
   176         return false;
   177     }
   178 
   179     @Override
   180     public Class[] getAllLoadedClasses() {
   181         return new Class[0];
   182     }
   183 
   184     @Override
   185     public Class[] getInitiatedClasses(ClassLoader loader) {
   186         return new Class[0];
   187     }
   188 
   189     @Override
   190     public long getObjectSize(Object objectToSize) {
   191         return 42;
   192     }
   193 
   194     @Override
   195     public void appendToBootstrapClassLoaderSearch(JarFile jarfile) {
   196     }
   197 
   198     @Override
   199     public void appendToSystemClassLoaderSearch(JarFile jarfile) {
   200         throw new UnsupportedOperationException();
   201     }
   202 
   203     @Override
   204     public boolean isNativeMethodPrefixSupported() {
   205         return false;
   206     }
   207 
   208     @Override
   209     public void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {
   210         throw new UnsupportedOperationException();
   211     }
   212     
   213 }