1 /*
2  * Copyright (c) 2016, 2018, 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 jdk.jfr;
27 
28 import java.lang.annotation.Annotation;
29 import java.util.Arrays;
30 import java.util.Collections;
31 import java.util.LinkedHashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Objects;
35 
36 import jdk.jfr.internal.JVMSupport;
37 import jdk.jfr.internal.MetadataRepository;
38 import jdk.jfr.internal.PlatformEventType;
39 import jdk.jfr.internal.Type;
40 import jdk.jfr.internal.Utils;
41 
42 /**
43  * Describes an event, its fields, settings and annotations.
44  *
45  * @since 9
46  */
47 public final class EventType {
48     private final PlatformEventType platformEventType;
49     private final List<String> UNCATEGORIZED = Collections.singletonList("Uncategorized");
50     private Map<String, ValueDescriptor> cache; // create lazy to avoid memory overhead
51     // helper constructor
EventType(PlatformEventType platformEventType)52     EventType(PlatformEventType platformEventType) {
53         this.platformEventType = platformEventType;
54     }
55 
56     /**
57      * Returns an immutable list of descriptors that describe the event fields of
58      * this event type.
59      *
60      * @return the list of field descriptors, not {@code null}
61      */
getFields()62     public List<ValueDescriptor> getFields() {
63         return platformEventType.getFields();
64     }
65 
66     /**
67      * Returns the field with the specified name, or {@code null} if it doesn't
68      * exist.
69      *
70      * @return a value descriptor that describes the field, or <code>null</code> if
71      *         the field with the specified name doesn't exist
72      *
73      * @return a value descriptor, or <code>null</code> if it doesn't exist
74      */
getField(String name)75     public ValueDescriptor getField(String name) {
76         Objects.requireNonNull(name);
77         if (cache == null) {
78             List<ValueDescriptor> fields = getFields();
79             Map<String, ValueDescriptor> newCache = new LinkedHashMap<String, ValueDescriptor>(fields.size());
80             for (ValueDescriptor v :fields) {
81                 newCache.put(v.getName(), v);
82             }
83             cache = newCache;
84         }
85         return cache.get(name);
86     }
87 
88     /**
89      * Returns an identifier for the event (for example,
90      * {@code "jdk.CPULoad"}).
91      * <p>
92      * The identifier is the fully qualified name of the event class, if not set using
93      * the {@link Name} annotation.
94      *
95      * @return the name, not {@code null}
96      *
97      * @see Name
98      */
getName()99     public String getName() {
100         return platformEventType.getName();
101     }
102 
103     /**
104      * Returns a human-readable name (for example, {@code "CPU Load"}).
105      * <p>
106      * The label of an event class can be set with {@link Label}.
107      *
108      * @return the label, or {@code null} if a label is not set
109      *
110      * @see Label
111      */
getLabel()112     public String getLabel() {
113         return platformEventType.getLabel();
114     }
115 
116     /**
117      * Returns a unique ID for this event type in the Java Virtual Machine (JVM).
118      *
119      * @return the ID that is used in the JVM
120      */
getId()121     public long getId() {
122         return platformEventType.getId();
123     }
124 
125     /**
126      * Returns an immutable list of annotation elements for this event type.
127      *
128      * @return an immutable list of annotations or an empty list if no
129      *         annotations exists, not {@code null}
130      */
getAnnotationElements()131     public List<AnnotationElement> getAnnotationElements() {
132         return platformEventType.getAnnotationElements();
133     }
134 
135     /**
136      * Returns {@code true} if the event is enabled and at least one recording is
137      * running, {@code false} otherwise.
138      * <p>
139      * By default, the event is enabled. The event can be enabled or disabled by
140      * setting the enabled setting to {@code true} or {@code false}, programmatically or by using a
141      * configuration file. The event can also be disabled by annotating event with
142      * the {@code @Enabled(false)} annotation.
143      *
144      * @return true if event is enabled, false otherwise
145      *
146      * @see Enabled
147      * @see Recording#enable(Class)
148      */
isEnabled()149     public boolean isEnabled() {
150         return platformEventType.isEnabled();
151     }
152 
153     /**
154      * Returns a short sentence that describes the event class.
155      * <p>
156      * The description of an event class can be set with {@link Description}.
157      *
158      * @return the description, or {@code null} if no description exists
159      *
160      * @see Description
161      */
getDescription()162     public String getDescription() {
163         return platformEventType.getDescription();
164     }
165 
166     /**
167      * Returns the first annotation for the specified type if an annotation
168      * element with the same name is directly present, otherwise {@code null}.
169      *
170      * @param <A> the type of the annotation to query for and return if present
171      * @param annotationClass the {@code Class} object that corresponds to the
172      *        annotation type, not {@code null}
173      * @return this element's annotation for the specified annotation type if
174      *         directly present, else {@code null}
175      */
getAnnotation(Class<A> annotationClass)176     public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
177         Objects.requireNonNull(annotationClass);
178         return platformEventType.getAnnotation(annotationClass);
179     }
180 
181     /**
182      * Returns the event type for an event class, or {@code null} if it doesn't
183      * exist.
184      *
185      * @param eventClass the event class, not {@code null}
186      * @return the event class, or null if class doesn't exist
187      *
188      * @throws IllegalArgumentException if {@code eventClass} is an abstract class
189      *
190      * @throws IllegalStateException if the class is annotated with
191      *         {@code Registered(false)}, but not manually registered
192      */
getEventType(Class<? extends Event> eventClass)193     public static EventType getEventType(Class<? extends Event> eventClass) {
194         Objects.requireNonNull(eventClass);
195         Utils.ensureValidEventSubclass(eventClass);
196         JVMSupport.ensureWithInternalError();
197         return MetadataRepository.getInstance().getEventType(eventClass);
198     }
199 
200     /**
201      * Returns an immutable list of the setting descriptors that describe the available
202      * event settings for this event type.
203      *
204      * @return the list of setting descriptors for this event type, not
205      *         {@code null}
206      */
getSettingDescriptors()207     public List<SettingDescriptor> getSettingDescriptors() {
208         return Collections.unmodifiableList(platformEventType.getSettings());
209     }
210 
211     /**
212      * Returns the list of human-readable names that makes up the categories for
213      * this event type (for example, {@code "Java Application"}, {@code "Statistics"}).
214      *
215      * @return an immutable list of category names, or a list with the name
216      *         {@code "Uncategorized"} if no category is set
217      *
218      * @see Category
219      */
getCategoryNames()220     public List<String> getCategoryNames() {
221         Category c = platformEventType.getAnnotation(Category.class);
222         if (c == null) {
223             return UNCATEGORIZED;
224         }
225         return Collections.unmodifiableList(Arrays.asList(c.value()));
226     }
227 
228     // package private
getType()229     Type getType() {
230         return platformEventType;
231     }
232 
233     // package private
getPlatformEventType()234     PlatformEventType getPlatformEventType() {
235         return platformEventType;
236     }
237 }
238