jdk/src/jdk.runtime/share/classes/sun/tracing/ProviderSkeleton.java
changeset 29262 1698800c8606
parent 29261 ea6e20f98dfa
parent 29099 766801b4d95d
child 29263 66e30e926405
child 29505 682be03b8f41
equal deleted inserted replaced
29261:ea6e20f98dfa 29262:1698800c8606
     1 /*
       
     2  * Copyright (c) 2008, 2014, 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;
       
    27 
       
    28 import java.lang.reflect.InvocationHandler;
       
    29 import java.lang.reflect.Method;
       
    30 import java.lang.reflect.Proxy;
       
    31 import java.lang.reflect.InvocationTargetException;
       
    32 import java.lang.reflect.AnnotatedElement;
       
    33 import java.lang.annotation.Annotation;
       
    34 import java.util.HashMap;
       
    35 import java.security.AccessController;
       
    36 import java.security.PrivilegedAction;
       
    37 
       
    38 import com.sun.tracing.Provider;
       
    39 import com.sun.tracing.Probe;
       
    40 import com.sun.tracing.ProviderName;
       
    41 
       
    42 /**
       
    43  * Provides a common code for implementation of {@code Provider} classes.
       
    44  *
       
    45  * Each tracing subsystem needs to provide three classes, a factory
       
    46  * (derived from {@code ProviderFactory}, a provider (a subclass of
       
    47  * {@code Provider}, and a probe type (subclass of {@code ProbeSkeleton}).
       
    48  *
       
    49  * The factory object takes a user-defined interface and provides an
       
    50  * implementation of it whose method calls will trigger probes in the
       
    51  * tracing framework.
       
    52  *
       
    53  * The framework's provider class, and its instances, are not seen by the
       
    54  * user at all -- they usually sit in the background and receive and dispatch
       
    55  * the calls to the user's provider interface.  The {@code ProviderSkeleton}
       
    56  * class provides almost all of the implementation needed by a framework
       
    57  * provider.  Framework providers must only provide a constructor and
       
    58  * disposal method, and implement the {@code createProbe} method to create
       
    59  * an appropriate {@code ProbeSkeleton} subclass.
       
    60  *
       
    61  * The framework's probe class provides the implementation of the two
       
    62  * probe methods, {@code isEnabled()} and {@code uncheckedTrigger()}.  Both are
       
    63  * framework-dependent implementations.
       
    64  *
       
    65  * @since 1.7
       
    66  */
       
    67 
       
    68 public abstract class ProviderSkeleton implements InvocationHandler, Provider {
       
    69 
       
    70     protected boolean active; // set to false after dispose() is called
       
    71     protected Class<? extends Provider> providerType; // user's interface
       
    72     protected HashMap<Method, ProbeSkeleton> probes; // methods to probes
       
    73 
       
    74 
       
    75     /**
       
    76      * Creates a framework-specific probe subtype.
       
    77      *
       
    78      * This method is implemented by the framework's provider and returns
       
    79      * framework-specific probes for a method.
       
    80      *
       
    81      * @param method A method in the user's interface
       
    82      * @return a subclass of ProbeSkeleton for the particular framework.
       
    83      */
       
    84     protected abstract ProbeSkeleton createProbe(Method method);
       
    85 
       
    86     /**
       
    87      * Initializes the provider.
       
    88      *
       
    89      * @param type the user's interface
       
    90      */
       
    91     protected ProviderSkeleton(Class<? extends Provider> type) {
       
    92         this.active = false; // in case of some error during initialization
       
    93         this.providerType = type;
       
    94         this.probes = new HashMap<Method,ProbeSkeleton>();
       
    95     }
       
    96 
       
    97     /**
       
    98      * Post-constructor initialization routine.
       
    99      *
       
   100      * Subclass instances must be initialized before they can create probes.
       
   101      * It is up to the factory implementations to call this after construction.
       
   102      */
       
   103     public void init() {
       
   104         Method[] methods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
       
   105             public Method[] run() {
       
   106                 return providerType.getDeclaredMethods();
       
   107             }
       
   108         });
       
   109 
       
   110         for (Method m : methods) {
       
   111             if ( m.getReturnType() != Void.TYPE ) {
       
   112                 throw new IllegalArgumentException(
       
   113                    "Return value of method is not void");
       
   114             } else {
       
   115                 probes.put(m, createProbe(m));
       
   116             }
       
   117         }
       
   118         this.active = true;
       
   119     }
       
   120 
       
   121     /**
       
   122      * Magic routine which creates an implementation of the user's interface.
       
   123      *
       
   124      * This method creates the instance of the user's interface which is
       
   125      * passed back to the user.  Every call upon that interface will be
       
   126      * redirected to the {@code invoke()} method of this class (until
       
   127      * overridden by the VM).
       
   128      *
       
   129      * @return an implementation of the user's interface
       
   130      */
       
   131     @SuppressWarnings("unchecked")
       
   132     public <T extends Provider> T newProxyInstance() {
       
   133         final InvocationHandler ih = this;
       
   134         return AccessController.doPrivileged(new PrivilegedAction<T>() {
       
   135             public T run() {
       
   136                return (T)Proxy.newProxyInstance(providerType.getClassLoader(),
       
   137                    new Class<?>[] { providerType }, ih);
       
   138             }});
       
   139     }
       
   140 
       
   141     /**
       
   142      * Triggers a framework probe when a user interface method is called.
       
   143      *
       
   144      * This method dispatches a user interface method call to the appropriate
       
   145      * probe associated with this framework.
       
   146      *
       
   147      * If the invoked method is not a user-defined member of the interface,
       
   148      * then it is a member of {@code Provider} or {@code Object} and we
       
   149      * invoke the method directly.
       
   150      *
       
   151      * @param proxy the instance whose method was invoked
       
   152      * @param method the method that was called
       
   153      * @param args the arguments passed in the call.
       
   154      * @return always null, if the method is a user-defined probe
       
   155      */
       
   156     public Object invoke(Object proxy, Method method, Object[] args) {
       
   157         Class<?> declaringClass = method.getDeclaringClass();
       
   158         // not a provider subtype's own method
       
   159         if (declaringClass != providerType) {
       
   160             try {
       
   161                 // delegate only to methods declared by
       
   162                 // com.sun.tracing.Provider or java.lang.Object
       
   163                 if (declaringClass == Provider.class ||
       
   164                     declaringClass == Object.class) {
       
   165                     return method.invoke(this, args);
       
   166                 } else {
       
   167                     // assert false : "this should never happen"
       
   168                     //    reaching here would indicate a breach
       
   169                     //    in security in the higher layers
       
   170                     throw new SecurityException();
       
   171                 }
       
   172             } catch (IllegalAccessException e) {
       
   173                 assert false;
       
   174             } catch (InvocationTargetException e) {
       
   175                 assert false;
       
   176             }
       
   177         } else {
       
   178             triggerProbe(method, args);
       
   179         }
       
   180         return null;
       
   181     }
       
   182 
       
   183     /**
       
   184      * Direct accessor for {@code Probe} objects.
       
   185      *
       
   186      * @param m the method corresponding to a probe
       
   187      * @return the method associated probe object, or null
       
   188      */
       
   189     public Probe getProbe(Method m) {
       
   190         return active ? probes.get(m) : null;
       
   191     }
       
   192 
       
   193     /**
       
   194      * Default provider disposal method.
       
   195      *
       
   196      * This is overridden in subclasses as needed.
       
   197      */
       
   198     public void dispose() {
       
   199         active = false;
       
   200         probes.clear();
       
   201     }
       
   202 
       
   203     /**
       
   204      * Gets the user-specified provider name for the user's interface.
       
   205      *
       
   206      * If the user's interface has a {@ProviderName} annotation, that value
       
   207      * is used.  Otherwise we use the simple name of the user interface's class.
       
   208      * @return the provider name
       
   209      */
       
   210     protected String getProviderName() {
       
   211         return getAnnotationString(
       
   212                 providerType, ProviderName.class, providerType.getSimpleName());
       
   213     }
       
   214 
       
   215     /**
       
   216      * Utility method for getting a string value from an annotation.
       
   217      *
       
   218      * Used for getting a string value from an annotation with a 'value' method.
       
   219      *
       
   220      * @param element the element that was annotated, either a class or method
       
   221      * @param annotation the class of the annotation we're interested in
       
   222      * @param defaultValue the value to return if the annotation doesn't
       
   223      * exist, doesn't have a "value", or the value is empty.
       
   224      */
       
   225     protected static String getAnnotationString(
       
   226             AnnotatedElement element, Class<? extends Annotation> annotation,
       
   227             String defaultValue) {
       
   228         String ret = (String)getAnnotationValue(
       
   229                 element, annotation, "value", defaultValue);
       
   230         return ret.isEmpty() ? defaultValue : ret;
       
   231     }
       
   232 
       
   233     /**
       
   234      * Utility method for calling an arbitrary method in an annotation.
       
   235      *
       
   236      * @param element the element that was annotated, either a class or method
       
   237      * @param annotation the class of the annotation we're interested in
       
   238      * @param methodName the name of the method in the annotation we wish
       
   239      * to call.
       
   240      * @param defaultValue the value to return if the annotation doesn't
       
   241      * exist, or we couldn't invoke the method for some reason.
       
   242      * @return the result of calling the annotation method, or the default.
       
   243      */
       
   244     protected static Object getAnnotationValue(
       
   245             AnnotatedElement element, Class<? extends Annotation> annotation,
       
   246             String methodName, Object defaultValue) {
       
   247         Object ret = defaultValue;
       
   248         try {
       
   249             Method m = annotation.getMethod(methodName);
       
   250             Annotation a = element.getAnnotation(annotation);
       
   251             ret = m.invoke(a);
       
   252         } catch (NoSuchMethodException e) {
       
   253             assert false;
       
   254         } catch (IllegalAccessException e) {
       
   255             assert false;
       
   256         } catch (InvocationTargetException e) {
       
   257             assert false;
       
   258         } catch (NullPointerException e) {
       
   259             assert false;
       
   260         }
       
   261         return ret;
       
   262     }
       
   263 
       
   264     protected void triggerProbe(Method method, Object[] args) {
       
   265         if (active) {
       
   266             ProbeSkeleton p = probes.get(method);
       
   267             if (p != null) {
       
   268                 // Skips argument check -- already done by javac
       
   269                 p.uncheckedTrigger(args);
       
   270             }
       
   271         }
       
   272     }
       
   273 }