1 /*
   2  * Copyright (c) 2016, 2019, 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.Collections;
  30 import java.util.List;
  31 import java.util.Objects;
  32 
  33 import jdk.jfr.internal.AnnotationConstruct;
  34 import jdk.jfr.internal.Type;
  35 
  36 /**
  37  * Describes an event setting.
  38  *
  39  * @since 9
  40  */
  41 public final class SettingDescriptor {
  42 
  43     private final AnnotationConstruct annotationConstruct;
  44     private final Type type;
  45     private final String name;
  46     private final String defaultValue;
  47 
  48     // package private, invoked by jdk.internal.
  49     SettingDescriptor(Type type, String name, String defaultValue, List<AnnotationElement> annotations) {
  50         Objects.requireNonNull(annotations);
  51         this.name = Objects.requireNonNull(name, "Name of value descriptor can't be null");
  52         this.type = Objects.requireNonNull(type);
  53         this.annotationConstruct = new AnnotationConstruct(annotations);
  54         this.defaultValue = Objects.requireNonNull(defaultValue);
  55     }
  56 
  57     // package private
  58     void setAnnotations(List<AnnotationElement> as) {
  59         annotationConstruct.setAnnotationElements(as);
  60     }
  61 
  62     /**
  63      * Returns the name of the setting (for example, {@code "threshold"}).
  64      *
  65      * @return the name, not {@code null}
  66      */
  67     public String getName() {
  68         return name;
  69     }
  70 
  71     /**
  72      * Returns a human-readable name that describes the setting (for example,
  73      * {@code "Threshold"}).
  74      * <p>
  75      * If the setting lacks a label, the label for the type that is associated with this
  76      * setting is returned, or {@code null} if not available.
  77      *
  78      * @return a human-readable name, or {@code null} if not available
  79      */
  80     public String getLabel() {
  81         String label = annotationConstruct.getLabel();
  82         if (label == null) {
  83             label = type.getLabel();
  84         }
  85         return label;
  86     }
  87 
  88     /**
  89      * Returns a sentence that describes the setting (for example
  90      * {@code "Record event with duration
  91      * above or equal to threshold"}).
  92      * <p>
  93      * If the setting lacks a description, the description for the type that is
  94      * associated with this setting is returned, or {@code null} if not available.
  95      *
  96      * @return the description, or {@code null} if not available
  97      */
  98     public String getDescription() {
  99         String description = annotationConstruct.getDescription();
 100         if (description == null) {
 101             description = type.getDescription();
 102         }
 103         return description;
 104     }
 105 
 106     /**
 107      * Returns a textual identifier that specifies how a value that is represented by
 108      * this {@link SettingDescriptor} object is interpreted or formatted.
 109      * <p>
 110      * For example, if the setting descriptor represents a percentage, then
 111      * {@code "jdk.jfr.Percentage"} hints to a client that a value of "0.5"
 112      * is formatted as "50%".
 113      * <p>
 114      * The JDK provides the following predefined content types:
 115      * <ul>
 116      * <li>jdk.jfr.Percentage</li>
 117      * <li>jdk.jfr.Timespan</li>
 118      * <li>jdk.jfr.Timestamp</li>
 119      * <li>jdk.jfr.Frequency</li>
 120      * <li>jdk.jfr.Flag</li>
 121      * <li>jdk.jfr.MemoryAddress</li>
 122      * <li>jdk.jfr.DataAmount</li>
 123      * <li>jdk.jfr.NetworkAddress</li>
 124      * </ul>
 125      * <p>
 126      * User-defined content types can be created by using {@link ContentType}.
 127      * <p>
 128      * If the setting lacks a content type, the content type for the type
 129      * that is associated with this setting is returned, or {@code null} if not
 130      * available.
 131      *
 132      * @return the content type, or {@code null} if not available
 133      *
 134      * @see ContentType
 135      */
 136     public String getContentType() {
 137         for (AnnotationElement anno : getAnnotationElements()) {
 138             for (AnnotationElement meta : anno.getAnnotationElements()) {
 139                 if (meta.getTypeName().equals(ContentType.class.getName())) {
 140                     return anno.getTypeName();
 141                 }
 142             }
 143         }
 144         for (AnnotationElement anno : type.getAnnotationElements()) {
 145             for (AnnotationElement meta : anno.getAnnotationElements()) {
 146                 if (meta.getTypeName().equals(ContentType.class.getName())) {
 147                     return anno.getTypeName();
 148                 }
 149             }
 150         }
 151         return null;
 152     }
 153 
 154     /**
 155      * Returns the fully qualified class name of the type that is associated with this
 156      * setting descriptor.
 157      *
 158      * @return the type name, not {@code null}
 159      *
 160      * @see SettingDescriptor#getTypeId()
 161      */
 162     public String getTypeName() {
 163         return type.getName();
 164     }
 165 
 166     /**
 167      * Returns a unique identifier for the type in the Java Virtual Machine (JVM).
 168      *
 169      * The ID might not be the same between JVM instances.
 170      *
 171      * @return the type ID, not negative
 172      */
 173     public long getTypeId() {
 174         return type.getId();
 175     }
 176 
 177     /**
 178      * Returns the first annotation for the specified type if an annotation
 179      * element with the same name is available, {@code null} otherwise.
 180      *
 181      * @param <A> the type of the annotation to query for and return if available
 182      * @param annotationType the Class object that corresponds to the annotation
 183      *        type, not {@code null}
 184      * @return this element's annotation for the specified annotation type if
 185      *         available, {@code null} otherwise
 186      */
 187     public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
 188         Objects.requireNonNull(annotationType);
 189         return annotationConstruct.getAnnotation(annotationType);
 190     }
 191 
 192     /**
 193      * Returns an immutable list of annotation elements for this value
 194      * descriptor.
 195      *
 196      * @return a list of annotations, not {@code null}
 197      */
 198     public List<AnnotationElement> getAnnotationElements() {
 199         return Collections.unmodifiableList(annotationConstruct.getUnmodifiableAnnotationElements());
 200     }
 201 
 202     /**
 203      * Returns the default value for this setting descriptor.
 204      *
 205      * @return the default value, not {@code null}
 206      */
 207     public String getDefaultValue() {
 208         return defaultValue;
 209     }
 210 
 211     // package private
 212     Type getType() {
 213         return type;
 214     }
 215 }