src/jdk.jfr/share/classes/jdk/jfr/consumer/ParserFactory.java
changeset 58863 c16ac7a2eba4
parent 58861 2c3cc4b01880
child 58864 fba8635290df
equal deleted inserted replaced
58861:2c3cc4b01880 58863:c16ac7a2eba4
     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.consumer;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.util.ArrayList;
       
    30 import java.util.List;
       
    31 import java.util.Objects;
       
    32 
       
    33 import jdk.jfr.EventType;
       
    34 import jdk.jfr.ValueDescriptor;
       
    35 import jdk.jfr.internal.MetadataDescriptor;
       
    36 import jdk.jfr.internal.PrivateAccess;
       
    37 import jdk.jfr.internal.Type;
       
    38 import jdk.jfr.internal.consumer.RecordingInput;
       
    39 
       
    40 /**
       
    41  * Class that create parsers suitable for reading events and constant pools
       
    42  */
       
    43 final class ParserFactory {
       
    44     private final LongMap<Parser> parsers = new LongMap<>();
       
    45     private final TimeConverter timeConverter;
       
    46     private final LongMap<Type> types = new LongMap<>();
       
    47     private final LongMap<ConstantMap> constantPools;
       
    48 
       
    49     public ParserFactory(MetadataDescriptor metadata, TimeConverter timeConverter) throws IOException {
       
    50         this.constantPools = new LongMap<>();
       
    51         this.timeConverter = timeConverter;
       
    52         for (Type t : metadata.getTypes()) {
       
    53             types.put(t.getId(), t);
       
    54         }
       
    55         for (Type t : types) {
       
    56             if (!t.getFields().isEmpty()) { // Avoid primitives
       
    57                 CompositeParser cp = createCompositeParser(t);
       
    58                 if (t.isSimpleType()) { // Reduce to nested parser
       
    59                    parsers.put(t.getId(), cp.parsers[0]);
       
    60                 }
       
    61 
       
    62             }
       
    63         }
       
    64         // Override event types with event parsers
       
    65         for (EventType t : metadata.getEventTypes()) {
       
    66             parsers.put(t.getId(), createEventParser(t));
       
    67         }
       
    68     }
       
    69 
       
    70     public LongMap<Parser> getParsers() {
       
    71         return parsers;
       
    72     }
       
    73 
       
    74     public LongMap<ConstantMap> getConstantPools() {
       
    75         return constantPools;
       
    76     }
       
    77 
       
    78     public LongMap<Type> getTypeMap() {
       
    79         return types;
       
    80     }
       
    81 
       
    82     private EventParser createEventParser(EventType eventType) throws IOException {
       
    83         List<Parser> parsers = new ArrayList<Parser>();
       
    84         for (ValueDescriptor f : eventType.getFields()) {
       
    85             parsers.add(createParser(f));
       
    86         }
       
    87         return new EventParser(timeConverter, eventType, parsers.toArray(new Parser[0]));
       
    88     }
       
    89 
       
    90     private Parser createParser(ValueDescriptor v) throws IOException {
       
    91         boolean constantPool = PrivateAccess.getInstance().isConstantPool(v);
       
    92         if (v.isArray()) {
       
    93             Type valueType = PrivateAccess.getInstance().getType(v);
       
    94             ValueDescriptor element = PrivateAccess.getInstance().newValueDescriptor(v.getName(), valueType, v.getAnnotationElements(), 0, constantPool, null);
       
    95             return new ArrayParser(createParser(element));
       
    96         }
       
    97         long id = v.getTypeId();
       
    98         Type type = types.get(id);
       
    99         if (type == null) {
       
   100             throw new IOException("Type '" + v.getTypeName() + "' is not defined");
       
   101         }
       
   102         if (constantPool) {
       
   103             ConstantMap pool = constantPools.get(id);
       
   104             if (pool == null) {
       
   105                 pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
       
   106                 constantPools.put(id, pool);
       
   107             }
       
   108             return new ConstantMapValueParser(pool);
       
   109         }
       
   110         Parser parser = parsers.get(id);
       
   111         if (parser == null) {
       
   112             if (!v.getFields().isEmpty()) {
       
   113                 return createCompositeParser(type);
       
   114             } else {
       
   115                 return registerParserType(type, createPrimitiveParser(type));
       
   116             }
       
   117         }
       
   118         return parser;
       
   119     }
       
   120 
       
   121     private Parser createPrimitiveParser(Type type) throws IOException {
       
   122         switch (type.getName()) {
       
   123         case "int":
       
   124             return new IntegerParser();
       
   125         case "long":
       
   126             return new LongParser();
       
   127         case "float":
       
   128             return new FloatParser();
       
   129         case "double":
       
   130             return new DoubleParser();
       
   131         case "char":
       
   132             return new CharacterParser();
       
   133         case "boolean":
       
   134             return new BooleanParser();
       
   135         case "short":
       
   136             return new ShortParser();
       
   137         case "byte":
       
   138             return new ByteParser();
       
   139         case "java.lang.String":
       
   140             ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
       
   141             constantPools.put(type.getId(), pool);
       
   142             return new StringParser(pool);
       
   143         default:
       
   144             throw new IOException("Unknown primitive type " + type.getName());
       
   145         }
       
   146     }
       
   147 
       
   148     private Parser registerParserType(Type t, Parser parser) {
       
   149         Parser p = parsers.get(t.getId());
       
   150         // check if parser exists (known type)
       
   151         if (p != null) {
       
   152             return p;
       
   153         }
       
   154         parsers.put(t.getId(), parser);
       
   155         return parser;
       
   156     }
       
   157 
       
   158     private CompositeParser createCompositeParser(Type type) throws IOException {
       
   159         List<ValueDescriptor> vds = type.getFields();
       
   160         Parser[] parsers = new Parser[vds.size()];
       
   161         CompositeParser composite = new CompositeParser(parsers);
       
   162         // need to pre-register so recursive types can be handled
       
   163         registerParserType(type, composite);
       
   164 
       
   165         int index = 0;
       
   166         for (ValueDescriptor vd : vds) {
       
   167             parsers[index++] = createParser(vd);
       
   168         }
       
   169         return composite;
       
   170     }
       
   171 
       
   172     private static final class BooleanParser extends Parser {
       
   173         @Override
       
   174         public Object parse(RecordingInput input) throws IOException {
       
   175             return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE;
       
   176         }
       
   177     }
       
   178 
       
   179     private static final class ByteParser extends Parser {
       
   180         @Override
       
   181         public Object parse(RecordingInput input) throws IOException {
       
   182             return Byte.valueOf(input.readByte());
       
   183         }
       
   184     }
       
   185 
       
   186     private static final class LongParser extends Parser {
       
   187         @Override
       
   188         public Object parse(RecordingInput input) throws IOException {
       
   189             return Long.valueOf(input.readLong());
       
   190         }
       
   191     }
       
   192 
       
   193     private static final class IntegerParser extends Parser {
       
   194         @Override
       
   195         public Object parse(RecordingInput input) throws IOException {
       
   196             return Integer.valueOf(input.readInt());
       
   197         }
       
   198     }
       
   199 
       
   200     private static final class ShortParser extends Parser {
       
   201         @Override
       
   202         public Object parse(RecordingInput input) throws IOException {
       
   203             return Short.valueOf(input.readShort());
       
   204         }
       
   205     }
       
   206 
       
   207     private static final class CharacterParser extends Parser {
       
   208         @Override
       
   209         public Object parse(RecordingInput input) throws IOException {
       
   210             return Character.valueOf(input.readChar());
       
   211         }
       
   212     }
       
   213 
       
   214     private static final class FloatParser extends Parser {
       
   215         @Override
       
   216         public Object parse(RecordingInput input) throws IOException {
       
   217             return Float.valueOf(input.readFloat());
       
   218         }
       
   219     }
       
   220 
       
   221     private static final class DoubleParser extends Parser {
       
   222         @Override
       
   223         public Object parse(RecordingInput input) throws IOException {
       
   224             return Double.valueOf(input.readDouble());
       
   225         }
       
   226     }
       
   227 
       
   228     private static final class StringParser extends Parser {
       
   229         private final ConstantMap stringConstantMap;
       
   230         private String last;
       
   231 
       
   232         StringParser(ConstantMap stringConstantMap) {
       
   233             this.stringConstantMap = stringConstantMap;
       
   234         }
       
   235 
       
   236         @Override
       
   237         public Object parse(RecordingInput input) throws IOException {
       
   238             String s = parseEncodedString(input);
       
   239             if (!Objects.equals(s, last)) {
       
   240                 last = s;
       
   241             }
       
   242             return last;
       
   243         }
       
   244 
       
   245         private String parseEncodedString(RecordingInput input) throws IOException {
       
   246             byte encoding = input.readByte();
       
   247             if (encoding == RecordingInput.STRING_ENCODING_CONSTANT_POOL) {
       
   248                 long id = input.readLong();
       
   249                 return (String) stringConstantMap.get(id);
       
   250             } else {
       
   251                 return input.readEncodedString(encoding);
       
   252             }
       
   253         }
       
   254     }
       
   255 
       
   256     private final static class ArrayParser extends Parser {
       
   257         private final Parser elementParser;
       
   258 
       
   259         public ArrayParser(Parser elementParser) {
       
   260             this.elementParser = elementParser;
       
   261         }
       
   262 
       
   263         @Override
       
   264         public Object parse(RecordingInput input) throws IOException {
       
   265             final int size = input.readInt();
       
   266             final Object[] array = new Object[size];
       
   267             for (int i = 0; i < size; i++) {
       
   268                 array[i] = elementParser.parse(input);
       
   269             }
       
   270             return array;
       
   271         }
       
   272     }
       
   273 
       
   274     private final static class CompositeParser extends Parser {
       
   275         private final Parser[] parsers;
       
   276 
       
   277         public CompositeParser(Parser[] valueParsers) {
       
   278             this.parsers = valueParsers;
       
   279         }
       
   280 
       
   281         @Override
       
   282         public Object parse(RecordingInput input) throws IOException {
       
   283             final Object[] values = new Object[parsers.length];
       
   284             for (int i = 0; i < values.length; i++) {
       
   285                 values[i] = parsers[i].parse(input);
       
   286             }
       
   287             return values;
       
   288         }
       
   289     }
       
   290 
       
   291     private static final class ConstantMapValueParser extends Parser {
       
   292         private final ConstantMap pool;
       
   293 
       
   294         ConstantMapValueParser(ConstantMap pool) {
       
   295             this.pool = pool;
       
   296         }
       
   297 
       
   298         @Override
       
   299         public Object parse(RecordingInput input) throws IOException {
       
   300             return pool.get(input.readLong());
       
   301         }
       
   302     }
       
   303 }