Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/tracing/ProviderSkeleton.java
38829 views
/*1* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.tracing;2627import java.lang.reflect.InvocationHandler;28import java.lang.reflect.Method;29import java.lang.reflect.Proxy;30import java.lang.reflect.InvocationTargetException;31import java.lang.reflect.AnnotatedElement;32import java.lang.annotation.Annotation;33import java.util.HashMap;34import java.security.AccessController;35import java.security.PrivilegedAction;3637import com.sun.tracing.Provider;38import com.sun.tracing.Probe;39import com.sun.tracing.ProviderName;4041/**42* Provides a common code for implementation of {@code Provider} classes.43*44* Each tracing subsystem needs to provide three classes, a factory45* (derived from {@code ProviderFactory}, a provider (a subclass of46* {@code Provider}, and a probe type (subclass of {@code ProbeSkeleton}).47*48* The factory object takes a user-defined interface and provides an49* implementation of it whose method calls will trigger probes in the50* tracing framework.51*52* The framework's provider class, and its instances, are not seen by the53* user at all -- they usually sit in the background and receive and dispatch54* the calls to the user's provider interface. The {@code ProviderSkeleton}55* class provides almost all of the implementation needed by a framework56* provider. Framework providers must only provide a constructor and57* disposal method, and implement the {@code createProbe} method to create58* an appropriate {@code ProbeSkeleton} subclass.59*60* The framework's probe class provides the implementation of the two61* probe methods, {@code isEnabled()} and {@code uncheckedTrigger()}. Both are62* framework-dependent implementations.63*64* @since 1.765*/6667public abstract class ProviderSkeleton implements InvocationHandler, Provider {6869protected boolean active; // set to false after dispose() is called70protected Class<? extends Provider> providerType; // user's interface71protected HashMap<Method, ProbeSkeleton> probes; // methods to probes727374/**75* Creates a framework-specific probe subtype.76*77* This method is implemented by the framework's provider and returns78* framework-specific probes for a method.79*80* @param method A method in the user's interface81* @return a subclass of ProbeSkeleton for the particular framework.82*/83protected abstract ProbeSkeleton createProbe(Method method);8485/**86* Initializes the provider.87*88* @param type the user's interface89*/90protected ProviderSkeleton(Class<? extends Provider> type) {91this.active = false; // in case of some error during initialization92this.providerType = type;93this.probes = new HashMap<Method,ProbeSkeleton>();94}9596/**97* Post-constructor initialization routine.98*99* Subclass instances must be initialized before they can create probes.100* It is up to the factory implementations to call this after construction.101*/102public void init() {103Method[] methods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {104public Method[] run() {105return providerType.getDeclaredMethods();106}107});108109for (Method m : methods) {110if ( m.getReturnType() != Void.TYPE ) {111throw new IllegalArgumentException(112"Return value of method is not void");113} else {114probes.put(m, createProbe(m));115}116}117this.active = true;118}119120/**121* Magic routine which creates an implementation of the user's interface.122*123* This method creates the instance of the user's interface which is124* passed back to the user. Every call upon that interface will be125* redirected to the {@code invoke()} method of this class (until126* overridden by the VM).127*128* @return an implementation of the user's interface129*/130@SuppressWarnings("unchecked")131public <T extends Provider> T newProxyInstance() {132final InvocationHandler ih = this;133return AccessController.doPrivileged(new PrivilegedAction<T>() {134public T run() {135return (T)Proxy.newProxyInstance(providerType.getClassLoader(),136new Class<?>[] { providerType }, ih);137}});138}139140/**141* Triggers a framework probe when a user interface method is called.142*143* This method dispatches a user interface method call to the appropriate144* probe associated with this framework.145*146* If the invoked method is not a user-defined member of the interface,147* then it is a member of {@code Provider} or {@code Object} and we148* invoke the method directly.149*150* @param proxy the instance whose method was invoked151* @param method the method that was called152* @param args the arguments passed in the call.153* @return always null, if the method is a user-defined probe154*/155public Object invoke(Object proxy, Method method, Object[] args) {156Class declaringClass = method.getDeclaringClass();157// not a provider subtype's own method158if (declaringClass != providerType) {159try {160// delegate only to methods declared by161// com.sun.tracing.Provider or java.lang.Object162if (declaringClass == Provider.class ||163declaringClass == Object.class) {164return method.invoke(this, args);165} else {166// assert false : "this should never happen"167// reaching here would indicate a breach168// in security in the higher layers169throw new SecurityException();170}171} catch (IllegalAccessException e) {172assert false;173} catch (InvocationTargetException e) {174assert false;175}176} else {177triggerProbe(method, args);178}179return null;180}181182/**183* Direct accessor for {@code Probe} objects.184*185* @param m the method corresponding to a probe186* @return the method associated probe object, or null187*/188public Probe getProbe(Method m) {189return active ? probes.get(m) : null;190}191192/**193* Default provider disposal method.194*195* This is overridden in subclasses as needed.196*/197public void dispose() {198active = false;199probes.clear();200}201202/**203* Gets the user-specified provider name for the user's interface.204*205* If the user's interface has a {@ProviderName} annotation, that value206* is used. Otherwise we use the simple name of the user interface's class.207* @return the provider name208*/209protected String getProviderName() {210return getAnnotationString(211providerType, ProviderName.class, providerType.getSimpleName());212}213214/**215* Utility method for getting a string value from an annotation.216*217* Used for getting a string value from an annotation with a 'value' method.218*219* @param element the element that was annotated, either a class or method220* @param annotation the class of the annotation we're interested in221* @param defaultValue the value to return if the annotation doesn't222* exist, doesn't have a "value", or the value is empty.223*/224protected static String getAnnotationString(225AnnotatedElement element, Class<? extends Annotation> annotation,226String defaultValue) {227String ret = (String)getAnnotationValue(228element, annotation, "value", defaultValue);229return ret.isEmpty() ? defaultValue : ret;230}231232/**233* Utility method for calling an arbitrary method in an annotation.234*235* @param element the element that was annotated, either a class or method236* @param annotation the class of the annotation we're interested in237* @param methodName the name of the method in the annotation we wish238* to call.239* @param defaultValue the value to return if the annotation doesn't240* exist, or we couldn't invoke the method for some reason.241* @return the result of calling the annotation method, or the default.242*/243protected static Object getAnnotationValue(244AnnotatedElement element, Class<? extends Annotation> annotation,245String methodName, Object defaultValue) {246Object ret = defaultValue;247try {248Method m = annotation.getMethod(methodName);249Annotation a = element.getAnnotation(annotation);250ret = m.invoke(a);251} catch (NoSuchMethodException e) {252assert false;253} catch (IllegalAccessException e) {254assert false;255} catch (InvocationTargetException e) {256assert false;257} catch (NullPointerException e) {258assert false;259}260return ret;261}262263protected void triggerProbe(Method method, Object[] args) {264if (active) {265ProbeSkeleton p = probes.get(method);266if (p != null) {267// Skips argument check -- already done by javac268p.uncheckedTrigger(args);269}270}271}272}273274275