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.management.jfr;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Collections;
  30 import java.util.List;
  31 import java.util.StringJoiner;
  32 
  33 import javax.management.openmbean.CompositeData;
  34 
  35 import jdk.jfr.Category;
  36 import jdk.jfr.EventType;
  37 import jdk.jfr.SettingDescriptor;
  38 
  39 /**
  40  * Management representation of an {@code EventType}.
  41  *
  42  * @see EventType
  43  *
  44  * @since 8
  45  */
  46 public final class EventTypeInfo {
  47     private final List<SettingDescriptorInfo> settings;
  48     private final long id;
  49     private final String name;
  50     private final String description;
  51     private final String label;
  52     private final List<String> categoryNames;
  53 
  54     // package private
  55     EventTypeInfo(EventType eventType) {
  56         this.settings = creatingSettingDescriptorInfos(eventType);
  57         this.id = eventType.getId();
  58         this.name = eventType.getName();
  59         this.label = eventType.getLabel();
  60         this.description = eventType.getDescription();
  61         this.categoryNames = eventType.getCategoryNames();
  62     }
  63 
  64     private EventTypeInfo(CompositeData cd) {
  65         this.settings = createSettings(cd.get("settings"));
  66         this.id = (long) cd.get("id");
  67         this.name = (String) cd.get("name");
  68         this.label = (String) cd.get("label");
  69         this.description = (String) cd.get("description");
  70         this.categoryNames = createCategoryNames((Object[]) cd.get("category"));
  71     }
  72 
  73     private static List<String> createCategoryNames(Object[] array) {
  74         List<String> list = new ArrayList<>(array.length);
  75         for (int i = 0; i < array.length; i++) {
  76             list.add((String) array[i]);
  77         }
  78         return Collections.unmodifiableList(list);
  79     }
  80 
  81     private static List<SettingDescriptorInfo> creatingSettingDescriptorInfos(EventType eventType) {
  82         List<SettingDescriptor> settings = eventType.getSettingDescriptors();
  83         List<SettingDescriptorInfo> settingDescriptorInfos = new ArrayList<>(settings.size());
  84         for (SettingDescriptor s : settings) {
  85             settingDescriptorInfos.add(new SettingDescriptorInfo(s));
  86         }
  87         return Collections.unmodifiableList(settingDescriptorInfos);
  88     }
  89 
  90     private static List<SettingDescriptorInfo> createSettings(Object settings) {
  91         if (settings != null && settings.getClass().isArray()) {
  92             Object[] settingsArray = (Object[]) settings;
  93             List<SettingDescriptorInfo> list = new ArrayList<>(settingsArray.length);
  94             for (Object cd : settingsArray) {
  95                 if (cd instanceof CompositeData) {
  96                     list.add(SettingDescriptorInfo.from((CompositeData) cd));
  97                 }
  98             }
  99             return Collections.unmodifiableList(list);
 100         }
 101         return Collections.emptyList();
 102     }
 103 
 104     /**
 105      * Returns the label, a human-readable name, associated with the event type
 106      * for this {@code EventTypeInfo} (for example, {@code "Garbage Collection"}).
 107      *
 108      * @return the label, or {@code null} if a label is not set
 109      *
 110      * @see EventType#getLabel()
 111      */
 112     public String getLabel() {
 113         return label;
 114     }
 115 
 116     /**
 117      *
 118      * Returns the list of human-readable names that makes up the category for this
 119      * {@code EventTypeInfo} (for example, {@code "Java Virtual Machine"} or {@code "Garbage Collector"}).
 120      *
 121      * @return an immutable list of category names, or a list with the name
 122      *         {@code "Uncategorized"} if no category has been set
 123      *
 124      * @see EventType#getCategoryNames()
 125      * @see Category
 126      */
 127     public List<String> getCategoryNames() {
 128         return categoryNames;
 129     }
 130 
 131     /**
 132      * Returns the unique ID for the event type associated with this
 133      * {@code EventTypeInfo}, not guaranteed to be the same for different Java
 134      * Virtual Machines (JVMs) instances.
 135      *
 136      * @return the ID
 137      *
 138      * @see EventType#getId()
 139      */
 140     public long getId() {
 141         return id;
 142     }
 143 
 144     /**
 145      * Returns the name for the event type associated with this
 146      * {@code EventTypeInfo} (for example, {@code "jdk.GarbageCollection"}).
 147      *
 148      * @return the name, not {@code null}
 149      *
 150      * @see EventType#getName()
 151      */
 152     public String getName() {
 153         return name;
 154     }
 155 
 156     /**
 157      * Returns a short sentence or two describing the event type associated with
 158      * this {@code EventTypeInfo}, for example
 159      * {@code "Garbage collection performed by the JVM""}.
 160      *
 161      * @return the description, or {@code null} if no description exists
 162      *
 163      * @see EventType#getDescription()
 164      */
 165     public String getDescription() {
 166         return description;
 167     }
 168 
 169     /**
 170      * Returns settings for the event type associated with this
 171      * {@code EventTypeInfo}.
 172      *
 173      * @return the settings, not {@code null}
 174      *
 175      * @see EventType#getSettingDescriptors()
 176      */
 177     public List<SettingDescriptorInfo> getSettingDescriptors() {
 178         return settings;
 179     }
 180 
 181     /**
 182      * Returns a description of this {@code EventTypeInfo}.
 183      *
 184      * @return description, not {@code null}
 185      */
 186     @Override
 187     public String toString() {
 188         Stringifier s = new Stringifier();
 189         s.add("id", id);
 190         s.add("name", name);
 191         s.add("label", label);
 192         s.add("description", description);
 193         StringJoiner sj = new StringJoiner(", ", "{", "}");
 194         for (String categoryName : categoryNames) {
 195             sj.add(categoryName);
 196         }
 197         s.add("category", sj.toString());
 198         return s.toString();
 199     }
 200 
 201     /**
 202      * Returns an {@code EventType} represented by the specified
 203      * {@code CompositeData}
 204      * <p>
 205      * The supplied {@code CompositeData} must have the following item names and
 206      * item types to be valid. <blockquote>
 207      * <table class="striped">
 208      * <caption>The name and type the specified CompositeData must contain</caption>
 209      * <thead>
 210      * <tr>
 211      * <th scope="col" style="text-align:left">Name</th>
 212      * <th scope="col" style="text-align:left">Type</th>
 213      * </tr>
 214      * </thead>
 215      * <tbody>
 216      * <tr>
 217      * <th scope="row">id</th>
 218      * <td>{@code Long}</td>
 219      * </tr>
 220      * <tr>
 221      * <th scope="row">name</th>
 222      * <td>{@code String}</td>
 223      * </tr>
 224      * <tr>
 225      * <th scope="row">label</th>
 226      * <td>{@code String}</td>
 227      * </tr>
 228      * <tr>
 229      * <th scope="row">description</th>
 230      * <td>{@code String}</td>
 231      * </tr>
 232      * <tr>
 233      * <th scope="row">category</th>
 234      * <td><code>ArrayType(1, SimpleType.STRING)</code></td>
 235      * </tr>
 236      * <tr>
 237      * <th scope="row">settings</th>
 238      * <td>{@code javax.management.openmbean.CompositeData[]} whose element type
 239      * is the mapped type for {@link SettingDescriptorInfo} as specified in the
 240      * {@link SettingDescriptorInfo#from} method.</td>
 241      *
 242      * </tr>
 243      * </tbody>
 244      * </table>
 245      * </blockquote>
 246      *
 247      * @param cd {@code CompositeData} representing the {@code EventTypeInfo} to
 248      *        return
 249      *
 250      * @throws IllegalArgumentException if {@code cd} does not represent a valid
 251      *         {@code EventTypeInfo}
 252      *
 253      * @return an {@code EventTypeInfo}, or {@code null} if {@code cd} is
 254      *         {@code null}
 255      */
 256     public static EventTypeInfo from(CompositeData cd) {
 257         if (cd == null) {
 258             return null;
 259         }
 260         return new EventTypeInfo(cd);
 261     }
 262 }