1 /*
   2  * Copyright (c) 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.internal.tool;
  27 
  28 import java.io.IOException;
  29 import java.io.PrintWriter;
  30 import java.nio.file.Path;
  31 import java.util.Collections;
  32 import java.util.Comparator;
  33 import java.util.Deque;
  34 import java.util.List;
  35 
  36 import jdk.jfr.consumer.RecordingFile;
  37 import jdk.jfr.internal.Type;
  38 import jdk.jfr.internal.consumer.RecordingInternals;
  39 
  40 final class Metadata extends Command {
  41 
  42     private static class TypeComparator implements Comparator<Type> {
  43 
  44         @Override
  45         public int compare(Type t1, Type t2) {
  46             int g1 = groupValue(t1);
  47             int g2 = groupValue(t2);
  48             if (g1 == g2) {
  49                 String n1 = t1.getName();
  50                 String n2 = t2.getName();
  51                 String package1 = n1.substring(0, n1.lastIndexOf('.') + 1);
  52                 String package2 = n2.substring(0, n2.lastIndexOf('.') + 1);
  53 
  54                 if (package1.equals(package2)) {
  55                     return n1.compareTo(n2);
  56                 } else {
  57                     // Ensure that jdk.* are printed first
  58                     // This makes it easier to find user defined events at the end.
  59                     if (Type.SUPER_TYPE_EVENT.equals(t1.getSuperType()) && !package1.equals(package2)) {
  60                         if (package1.equals("jdk.jfr")) {
  61                             return -1;
  62                         }
  63                         if (package2.equals("jdk.jfr")) {
  64                             return 1;
  65                         }
  66                     }
  67                     return package1.compareTo(package2);
  68                 }
  69             } else {
  70                 return Integer.compare(groupValue(t1), groupValue(t2));
  71             }
  72         }
  73 
  74         int groupValue(Type t) {
  75             String superType = t.getSuperType();
  76             if (superType == null) {
  77                 return 1;
  78             }
  79             if (Type.SUPER_TYPE_ANNOTATION.equals(superType)) {
  80                 return 3;
  81             }
  82             if (Type.SUPER_TYPE_SETTING.equals(superType)) {
  83                 return 4;
  84             }
  85             if (Type.SUPER_TYPE_EVENT.equals(superType)) {
  86                 return 5;
  87             }
  88             return 2; // reserved for enums in the future
  89         }
  90     }
  91 
  92     @Override
  93     public String getName() {
  94         return "metadata";
  95     }
  96 
  97     @Override
  98     public List<String> getOptionSyntax() {
  99         return Collections.singletonList("<file>");
 100     }
 101 
 102     @Override
 103     public String getDescription() {
 104         return "Display event metadata, such as labels, descriptions and field layout";
 105     }
 106 
 107     @Override
 108     public void execute(Deque<String> options) throws UserSyntaxException, UserDataException {
 109         Path file = getJFRInputFile(options);
 110 
 111         boolean showIds = false;
 112         int optionCount = options.size();
 113         while (optionCount > 0) {
 114             if (acceptOption(options, "--ids")) {
 115                 showIds = true;
 116             }
 117             if (optionCount == options.size()) {
 118                 // No progress made
 119                 throw new UserSyntaxException("unknown option " + options.peek());
 120             }
 121             optionCount = options.size();
 122         }
 123 
 124         try (PrintWriter pw = new PrintWriter(System.out)) {
 125             PrettyWriter prettyWriter = new PrettyWriter(pw);
 126             prettyWriter.setShowIds(showIds);
 127             try (RecordingFile rf = new RecordingFile(file)) {
 128                 List<Type> types = RecordingInternals.INSTANCE.readTypes(rf);
 129                 Collections.sort(types, new TypeComparator());
 130                 for (Type type : types) {
 131                     prettyWriter.printType(type);
 132                 }
 133                 prettyWriter.flush(true);
 134             } catch (IOException ioe) {
 135                 couldNotReadError(file, ioe);
 136             }
 137         }
 138     }
 139 }