1 /*
   2  * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.tracing.dtrace;
  27 
  28 import java.lang.reflect.Method;
  29 import java.lang.reflect.Modifier;
  30 import java.lang.reflect.Constructor;
  31 import java.lang.reflect.InvocationHandler;
  32 import java.lang.reflect.InvocationTargetException;
  33 import java.lang.annotation.Annotation;
  34 
  35 import sun.tracing.ProviderSkeleton;
  36 import sun.tracing.ProbeSkeleton;
  37 import com.sun.tracing.Provider;
  38 import com.sun.tracing.ProbeName;
  39 import com.sun.tracing.dtrace.Attributes;
  40 import com.sun.tracing.dtrace.ModuleName;
  41 import com.sun.tracing.dtrace.FunctionName;
  42 import com.sun.tracing.dtrace.StabilityLevel;
  43 import com.sun.tracing.dtrace.DependencyClass;
  44 
  45 import sun.misc.ProxyGenerator;
  46 
  47 class DTraceProvider extends ProviderSkeleton {
  48 
  49     private Activation activation;
  50     private Object proxy;
  51 
  52     // For proxy generation
  53     private final static Class[] constructorParams = { InvocationHandler.class };
  54     private final String proxyClassNamePrefix = "$DTraceTracingProxy";
  55 
  56     static final String DEFAULT_MODULE = "java_tracing";
  57     static final String DEFAULT_FUNCTION = "unspecified";
  58 
  59     private static long nextUniqueNumber = 0;
  60     private static synchronized long getUniqueNumber() {
  61         return nextUniqueNumber++;
  62     }
  63 
  64     protected ProbeSkeleton createProbe(Method m) {
  65         return new DTraceProbe(proxy, m);
  66     }
  67 
  68     DTraceProvider(Class<? extends Provider> type) {
  69         super(type);
  70     }
  71 
  72     void setProxy(Object p) {
  73         proxy = p;
  74     }
  75 
  76     void setActivation(Activation a) {
  77         this.activation = a;
  78     }
  79 
  80     public void dispose() {
  81         if (activation != null) {
  82             activation.disposeProvider(this);
  83             activation = null;
  84         }
  85         super.dispose();
  86     }
  87 
  88     /**
  89      * Magic routine which creates an implementation of the user's interface.
  90      *
  91      * This method uses the ProxyGenerator directly to bypass the
  92      * java.lang.reflect.proxy cache so that we get a unique class each
  93      * time it's called and can't accidently reuse a $Proxy class.
  94      *
  95      * @return an implementation of the user's interface
  96      */
  97     @SuppressWarnings("unchecked")
  98     public <T extends Provider> T newProxyInstance() {
  99         /*
 100          * Choose a name for the proxy class to generate.
 101          */
 102         long num = getUniqueNumber();
 103 
 104         String proxyPkg = "";
 105         if (!Modifier.isPublic(providerType.getModifiers())) {
 106             String name = providerType.getName();
 107             int n = name.lastIndexOf('.');
 108             proxyPkg = ((n == -1) ? "" : name.substring(0, n + 1));
 109         }
 110 
 111         String proxyName = proxyPkg + proxyClassNamePrefix + num;
 112 
 113         /*
 114          * Generate the specified proxy class.
 115          */
 116         Class<?> proxyClass = null;
 117         byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
 118                 proxyName, new Class<?>[] { providerType });
 119         try {
 120             proxyClass = JVM.defineClass(
 121                 providerType.getClassLoader(), proxyName,
 122                 proxyClassFile, 0, proxyClassFile.length);
 123         } catch (ClassFormatError e) {
 124             /*
 125              * A ClassFormatError here means that (barring bugs in the
 126              * proxy class generation code) there was some other
 127              * invalid aspect of the arguments supplied to the proxy
 128              * class creation (such as virtual machine limitations
 129              * exceeded).
 130              */
 131             throw new IllegalArgumentException(e.toString());
 132         }
 133 
 134         /*
 135          * Invoke its constructor with the designated invocation handler.
 136          */
 137         try {
 138             Constructor cons = proxyClass.getConstructor(constructorParams);
 139             return (T)cons.newInstance(new Object[] { this });
 140         } catch (ReflectiveOperationException e) {
 141             throw new InternalError(e.toString(), e);
 142         }
 143     }
 144 
 145     // In the normal case, the proxy object's method implementations will call
 146     // this method (it usually calls the ProviderSkeleton's version).  That
 147     // method uses the passed 'method' object to lookup the associated
 148     // 'ProbeSkeleton' and calls uncheckedTrigger() on that probe to cause the
 149     // probe to fire.  DTrace probes are different in that the proxy class's
 150     // methods are immediately overridden with native code to fire the probe
 151     // directly.  So this method should never get invoked.  We also wire up the
 152     // DTraceProbe.uncheckedTrigger() method to call the proxy method instead
 153     // of doing the work itself.
 154     protected void triggerProbe(Method method, Object[] args) {
 155         assert false : "This method should have been overridden by the JVM";
 156     }
 157 
 158     public String getProviderName() {
 159         return super.getProviderName();
 160     }
 161 
 162     String getModuleName() {
 163         return getAnnotationString(
 164             providerType, ModuleName.class, DEFAULT_MODULE);
 165     }
 166 
 167     static String getProbeName(Method method) {
 168         return getAnnotationString(
 169             method, ProbeName.class, method.getName());
 170     }
 171 
 172     static String getFunctionName(Method method) {
 173         return getAnnotationString(
 174             method, FunctionName.class, DEFAULT_FUNCTION);
 175     }
 176 
 177     DTraceProbe[] getProbes() {
 178         return probes.values().toArray(new DTraceProbe[0]);
 179     }
 180 
 181     StabilityLevel getNameStabilityFor(Class<? extends Annotation> type) {
 182         Attributes attrs = (Attributes)getAnnotationValue(
 183             providerType, type, "value", null);
 184         if (attrs == null) {
 185             return StabilityLevel.PRIVATE;
 186         } else {
 187             return attrs.name();
 188         }
 189     }
 190 
 191     StabilityLevel getDataStabilityFor(Class<? extends Annotation> type) {
 192         Attributes attrs = (Attributes)getAnnotationValue(
 193             providerType, type, "value", null);
 194         if (attrs == null) {
 195             return StabilityLevel.PRIVATE;
 196         } else {
 197             return attrs.data();
 198         }
 199     }
 200 
 201     DependencyClass getDependencyClassFor(Class<? extends Annotation> type) {
 202         Attributes attrs = (Attributes)getAnnotationValue(
 203             providerType, type, "value", null);
 204         if (attrs == null) {
 205             return DependencyClass.UNKNOWN;
 206         } else {
 207             return attrs.dependency();
 208         }
 209     }
 210 }