src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java
changeset 50113 caf115bb98ad
child 52413 6372f5af9612
equal deleted inserted replaced
50112:7a2a740815b7 50113:caf115bb98ad
       
     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.internal;
       
    27 
       
    28 import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_CONSTANT_POOL;
       
    29 import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_DIMENSION;
       
    30 import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_ID;
       
    31 import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_NAME;
       
    32 import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_SIMPLE_TYPE;
       
    33 import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_SUPER_TYPE;
       
    34 import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_TYPE_ID;
       
    35 import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_ANNOTATION;
       
    36 import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_FIELD;
       
    37 import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_SETTING;
       
    38 import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_TYPE;
       
    39 
       
    40 import java.io.DataInput;
       
    41 import java.io.IOException;
       
    42 import java.util.ArrayList;
       
    43 import java.util.Collections;
       
    44 import java.util.HashMap;
       
    45 import java.util.List;
       
    46 import java.util.Map;
       
    47 
       
    48 import jdk.jfr.AnnotationElement;
       
    49 import jdk.jfr.SettingDescriptor;
       
    50 import jdk.jfr.ValueDescriptor;
       
    51 import jdk.jfr.internal.MetadataDescriptor.Element;
       
    52 
       
    53 /**
       
    54  * Parses metadata.
       
    55  *
       
    56  */
       
    57 final class MetadataReader {
       
    58 
       
    59     private final DataInput input;
       
    60     private final List<String> pool;
       
    61     private final MetadataDescriptor descriptor;
       
    62     private final Map<Long, Type> types = new HashMap<>();
       
    63 
       
    64     public MetadataReader(DataInput input) throws IOException {
       
    65         this.input = input;
       
    66         int size = input.readInt();
       
    67         this.pool = new ArrayList<>(size);
       
    68         for (int i = 0; i < size; i++) {
       
    69             this.pool.add(input.readUTF());
       
    70         }
       
    71         descriptor = new MetadataDescriptor();
       
    72         Element root = createElement();
       
    73         Element metadata = root.elements("metadata").get(0);
       
    74         declareTypes(metadata);
       
    75         defineTypes(metadata);
       
    76         annotateTypes(metadata);
       
    77         buildEvenTypes();
       
    78         Element time = root.elements("region").get(0);
       
    79         descriptor.gmtOffset = time.attribute(MetadataDescriptor.ATTRIBUTE_GMT_OFFSET, 1);
       
    80         descriptor.locale = time.attribute(MetadataDescriptor.ATTRIBUTE_LOCALE, "");
       
    81         descriptor.root = root;
       
    82         if (LogTag.JFR_SYSTEM_PARSER.shouldLog(LogLevel.TRACE.level)) {
       
    83              List<Type> ts = new ArrayList<>(types.values());
       
    84              Collections.sort(ts, (x,y) -> x.getName().compareTo(y.getName()));
       
    85              for (Type t : ts) {
       
    86                  t.log("Found", LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE);
       
    87              }
       
    88         }
       
    89     }
       
    90 
       
    91     private String readString() throws IOException {
       
    92         return pool.get(readInt());
       
    93     }
       
    94 
       
    95     private int readInt() throws IOException {
       
    96         return input.readInt();
       
    97     }
       
    98 
       
    99     private Element createElement() throws IOException {
       
   100         String name = readString();
       
   101         Element e = new Element(name);
       
   102         int attributeCount = readInt();
       
   103         for (int i = 0; i < attributeCount; i++) {
       
   104             e.addAttribute(readString(), readString());
       
   105         }
       
   106         int childrenCount = readInt();
       
   107         for (int i = 0; i < childrenCount; i++) {
       
   108             e.add(createElement());
       
   109         }
       
   110         return e;
       
   111     }
       
   112 
       
   113     private void annotateTypes(Element metadata) throws IOException {
       
   114         for (Element typeElement : metadata.elements(ELEMENT_TYPE)) {
       
   115             Type type = getType(ATTRIBUTE_ID, typeElement);
       
   116             ArrayList<AnnotationElement> aes = new ArrayList<>();
       
   117             for (Element annotationElement : typeElement.elements(ELEMENT_ANNOTATION)) {
       
   118                 aes.add(makeAnnotation(annotationElement));
       
   119             }
       
   120             aes.trimToSize();
       
   121             type.setAnnotations(aes);
       
   122 
       
   123             int index = 0;
       
   124             if (type instanceof PlatformEventType) {
       
   125                 List<SettingDescriptor> settings = ((PlatformEventType) type).getAllSettings();
       
   126                 for (Element settingElement : typeElement.elements(ELEMENT_SETTING)) {
       
   127                     ArrayList<AnnotationElement> annotations = new ArrayList<>();
       
   128                     for (Element annotationElement : settingElement.elements(ELEMENT_ANNOTATION)) {
       
   129                         annotations.add(makeAnnotation(annotationElement));
       
   130                     }
       
   131                     annotations.trimToSize();
       
   132                     PrivateAccess.getInstance().setAnnotations(settings.get(index), annotations);
       
   133                     index++;
       
   134                 }
       
   135             }
       
   136             index = 0;
       
   137             List<ValueDescriptor> fields = type.getFields();
       
   138             for (Element fieldElement : typeElement.elements(ELEMENT_FIELD)) {
       
   139                 ArrayList<AnnotationElement> annotations = new ArrayList<>();
       
   140                 for (Element annotationElement : fieldElement.elements(ELEMENT_ANNOTATION)) {
       
   141                     annotations.add(makeAnnotation(annotationElement));
       
   142                 }
       
   143                 annotations.trimToSize();
       
   144                 PrivateAccess.getInstance().setAnnotations(fields.get(index), annotations);
       
   145                 index++;
       
   146             }
       
   147         }
       
   148     }
       
   149 
       
   150     private AnnotationElement makeAnnotation(Element annotationElement) throws IOException {
       
   151         Type annotationType = getType(ATTRIBUTE_TYPE_ID, annotationElement);
       
   152         List<Object> values = new ArrayList<>();
       
   153         for (ValueDescriptor v : annotationType.getFields()) {
       
   154             if (v.isArray()) {
       
   155                 List<Object> list = new ArrayList<>();
       
   156                 int index = 0;
       
   157                 while (true) {
       
   158                     String text = annotationElement.attribute(v.getName() + "-" + index);
       
   159                     if (text == null) {
       
   160                         break;
       
   161                     }
       
   162                     list.add(objectify(v.getTypeName(), text));
       
   163                     index++;
       
   164                 }
       
   165                 Object object = Utils.makePrimitiveArray(v.getTypeName(), list);
       
   166                 if (object == null) {
       
   167                     throw new IOException("Unsupported type " + list + " in array");
       
   168                 }
       
   169                 values.add(object);
       
   170             } else {
       
   171                 String text = annotationElement.attribute(v.getName());
       
   172                 values.add(objectify(v.getTypeName(), text));
       
   173             }
       
   174         }
       
   175         return PrivateAccess.getInstance().newAnnotation(annotationType, values, false);
       
   176     }
       
   177 
       
   178     private Object objectify(String typeName, String text) throws IOException {
       
   179         try {
       
   180             switch (typeName) {
       
   181             case "int":
       
   182                 return Integer.valueOf(text);
       
   183             case "long":
       
   184                 return Long.valueOf(text);
       
   185             case "double":
       
   186                 return Double.valueOf(text);
       
   187             case "float":
       
   188                 return Float.valueOf(text);
       
   189             case "short":
       
   190                 return Short.valueOf(text);
       
   191             case "char":
       
   192                 if (text.length() != 1) {
       
   193                     throw new IOException("Unexpected size of char");
       
   194                 }
       
   195                 return text.charAt(0);
       
   196             case "byte":
       
   197                 return Byte.valueOf(text);
       
   198             case "boolean":
       
   199                 return Boolean.valueOf(text);
       
   200             case "java.lang.String":
       
   201                 return text;
       
   202             }
       
   203         } catch (IllegalArgumentException iae) {
       
   204             throw new IOException("Could not parse text representation of " + typeName);
       
   205         }
       
   206         throw new IOException("Unsupported type for annotation " + typeName);
       
   207     }
       
   208 
       
   209     private Type getType(String attribute, Element element) {
       
   210         long id = element.longValue(attribute);
       
   211         Type type = types.get(id);
       
   212         if (type == null) {
       
   213             String name = element.attribute("type");
       
   214             throw new IllegalStateException("Type '" + id + "' is not defined for " + name);
       
   215         }
       
   216         return type;
       
   217     }
       
   218 
       
   219     private void buildEvenTypes() {
       
   220         for (Type type : descriptor.types) {
       
   221             if (type instanceof PlatformEventType) {
       
   222                 descriptor.eventTypes.add(PrivateAccess.getInstance().newEventType((PlatformEventType) type));
       
   223             }
       
   224         }
       
   225     }
       
   226 
       
   227     private void defineTypes(Element metadata) {
       
   228         for (Element typeElement : metadata.elements(ELEMENT_TYPE)) {
       
   229             long id = typeElement.attribute(ATTRIBUTE_ID, -1);
       
   230             Type t = types.get(id);
       
   231             for (Element fieldElement : typeElement.elements(ELEMENT_SETTING)) {
       
   232                 String name = fieldElement.attribute(ATTRIBUTE_NAME);
       
   233                 String defaultValue = fieldElement.attribute(ATTRIBUTE_NAME);
       
   234                 Type settingType = getType(ATTRIBUTE_TYPE_ID, fieldElement);
       
   235                 PlatformEventType eventType = (PlatformEventType) t;
       
   236                 eventType.add(PrivateAccess.getInstance().newSettingDescriptor(settingType, name, defaultValue, new ArrayList<>(2)));
       
   237             }
       
   238             for (Element fieldElement : typeElement.elements(ELEMENT_FIELD)) {
       
   239                 String name = fieldElement.attribute(ATTRIBUTE_NAME);
       
   240                 Type fieldType = getType(ATTRIBUTE_TYPE_ID, fieldElement);
       
   241                 long dimension = fieldElement.attribute(ATTRIBUTE_DIMENSION, 0);
       
   242                 boolean constantPool = fieldElement.attribute(ATTRIBUTE_CONSTANT_POOL) != null;
       
   243                 // Add annotation later, because they may refer to undefined
       
   244                 // types at this stage
       
   245                 t.add(PrivateAccess.getInstance().newValueDescriptor(name, fieldType, new ArrayList<>(), (int) dimension, constantPool, null));
       
   246             }
       
   247             t.trimFields();
       
   248         }
       
   249     }
       
   250 
       
   251     private void declareTypes(Element metadata) {
       
   252         for (Element typeElement : metadata.elements(ELEMENT_TYPE)) {
       
   253             String typeName = typeElement.attribute(ATTRIBUTE_NAME);
       
   254             String superType = typeElement.attribute(ATTRIBUTE_SUPER_TYPE);
       
   255             boolean simpleType = typeElement.attribute(ATTRIBUTE_SIMPLE_TYPE) != null;
       
   256             long id = typeElement.attribute(ATTRIBUTE_ID, -1);
       
   257             Type t;
       
   258             if (Type.SUPER_TYPE_EVENT.equals(superType)) {
       
   259                 t = new PlatformEventType(typeName, id, false, false);
       
   260             } else {
       
   261                 t = new Type(typeName, superType, id, false, simpleType);
       
   262             }
       
   263             types.put(id, t);
       
   264             descriptor.types.add(t);
       
   265         }
       
   266     }
       
   267 
       
   268     public MetadataDescriptor getDescriptor() {
       
   269         return descriptor;
       
   270     }
       
   271 }