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 9
  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 {@link EventTypeInfo}, for example {@code "Garbage Collection"}.
 107      *
 108      * @return the label
 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
 119      * this event type, for instance "Java Virtual Machine",
 120      * "Garbage Collector".
 121      *
 122      * @return an immutable list of category names, or a list with the name
 123      *         "Uncategorized" if no category has been set
 124      *
 125      * @see EventType#getCategoryNames()
 126      * @see Category
 127      */
 128     public List<String> getCategoryNames() {
 129         return categoryNames;
 130     }
 131 
 132     /**
 133      * Returns the unique numeric id for the event type associated with this
 134      * {@link EventTypeInfo}, not guaranteed to be the same for different JVM
 135      * instances.
 136      *
 137      * @return the id
 138      *
 139      * @see EventType#getId()
 140      */
 141     public long getId() {
 142         return id;
 143     }
 144 
 145     /**
 146      * Returns the name for the event type associated with this
 147      * {@link EventTypeInfo}, for example
 148      * {@code "com.oracle.jdk.GarbageCollection"}.
 149      *
 150      * @return the name
 151      *
 152      * @see EventType#getName()
 153      */
 154     public String getName() {
 155         return name;
 156     }
 157 
 158     /**
 159      * Returns a short sentence or two describing the event type associated with
 160      * this {@code EventTypeInfo}, for example
 161      * {@code ""Garbage collection performed by the JVM""}.
 162      *
 163      * @return the description, or {@code null} if no description exists
 164      *
 165      * @see EventType#getDescription()
 166      */
 167     public String getDescription() {
 168         return description;
 169     }
 170 
 171     /**
 172      * Returns settings for the event type associated with this
 173      * {@code EventTypeInfo}.
 174      *
 175      * @return the settings, not {@code null}
 176      *
 177      * @see EventType#getSettingDescriptors()
 178      */
 179     public List<SettingDescriptorInfo> getSettingDescriptors() {
 180         return settings;
 181     }
 182 
 183     /**
 184      * Returns a string description of this {@link EventTypeInfo}.
 185      *
 186      * @return description, not {@code null}
 187      */
 188     @Override
 189     public String toString() {
 190         Stringifier s = new Stringifier();
 191         s.add("id", id);
 192         s.add("name", name);
 193         s.add("label", label);
 194         s.add("description", description);
 195         StringJoiner sj = new StringJoiner(", ", "{", "}");
 196         for (String categoryName : categoryNames) {
 197             sj.add(categoryName);
 198         }
 199         s.add("category", sj.toString());
 200         return s.toString();
 201     }
 202 
 203     /**
 204      * Returns an {@code EventType} represented by the specified
 205      * {@code CompositeData}
 206      * <p>
 207      * The supplied {@code CompositeData} must have the following item names and
 208      * item types to be valid. <blockquote>
 209      * <table class="striped">
 210      * <caption>The name and type the specified CompositeData must contain</caption>
 211      * <thead>
 212      * <tr>
 213      * <th scope="col" style="text-align:left">Name</th>
 214      * <th scope="col" style="text-align:left">Type</th>
 215      * </tr>
 216      * </thead>
 217      * <tbody>
 218      * <tr>
 219      * <th scope="row">id</th>
 220      * <td>{@code Long}</td>
 221      * </tr>
 222      * <tr>
 223      * <th scope="row">name</th>
 224      * <td>{@code String}</td>
 225      * </tr>
 226      * <tr>
 227      * <th scope="row">label</th>
 228      * <td>{@code String}</td>
 229      * </tr>
 230      * <tr>
 231      * <th scope="row">description</th>
 232      * <td>{@code String}</td>
 233      * </tr>
 234      * <tr>
 235      * <th scope="row">category</th>
 236      * <td><code>ArrayType(1, SimpleType.STRING)</code></td>
 237      * </tr>
 238      * <tr>
 239      * <th scope="row">settings</th>
 240      * <td>{@code javax.management.openmbean.CompositeData[]} whose element type
 241      * is the mapped type for {@link SettingDescriptorInfo} as specified in the
 242      * {@link SettingDescriptorInfo#from} method.</td>
 243      *
 244      * </tr>
 245      * </tbody>
 246      * </table>
 247      * </blockquote>
 248      *
 249      * @param cd {@code CompositeData} representing the {@code EventTypeInfo} to
 250      *        return
 251      *
 252      * @throws IllegalArgumentException if {@code cd} does not represent a valid
 253      *         {@code EventTypeInfo}
 254      *
 255      * @return an {@code EventTypeInfo}, or {@code null} if {@code cd} is
 256      *         {@code null}
 257      */
 258     public static EventTypeInfo from(CompositeData cd) {
 259         if (cd == null) {
 260             return null;
 261         }
 262         return new EventTypeInfo(cd);
 263     }
 264 }