| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package jdk.jfr.consumer;  | 
 | 
 | 
 | 
import java.io.IOException;  | 
 | 
import java.util.ArrayList;  | 
 | 
import java.util.List;  | 
 | 
import java.util.Objects;  | 
 | 
 | 
 | 
import jdk.jfr.EventType;  | 
 | 
import jdk.jfr.ValueDescriptor;  | 
 | 
import jdk.jfr.internal.MetadataDescriptor;  | 
 | 
import jdk.jfr.internal.PrivateAccess;  | 
 | 
import jdk.jfr.internal.Type;  | 
 | 
import jdk.jfr.internal.consumer.RecordingInput;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
final class ParserFactory { | 
 | 
    private final LongMap<Parser> parsers = new LongMap<>();  | 
 | 
    private final TimeConverter timeConverter;  | 
 | 
    private final LongMap<Type> types = new LongMap<>();  | 
 | 
    private final LongMap<ConstantMap> constantPools;  | 
 | 
 | 
 | 
    public ParserFactory(MetadataDescriptor metadata, TimeConverter timeConverter) throws IOException { | 
 | 
        this.constantPools = new LongMap<>();  | 
 | 
        this.timeConverter = timeConverter;  | 
 | 
        for (Type t : metadata.getTypes()) { | 
 | 
            types.put(t.getId(), t);  | 
 | 
        }  | 
 | 
        for (Type t : types) { | 
 | 
            if (!t.getFields().isEmpty()) {  | 
 | 
                CompositeParser cp = createCompositeParser(t);  | 
 | 
                if (t.isSimpleType()) {  | 
 | 
                   parsers.put(t.getId(), cp.parsers[0]);  | 
 | 
                }  | 
 | 
 | 
 | 
            }  | 
 | 
        }  | 
 | 
          | 
 | 
        for (EventType t : metadata.getEventTypes()) { | 
 | 
            parsers.put(t.getId(), createEventParser(t));  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public LongMap<Parser> getParsers() { | 
 | 
        return parsers;  | 
 | 
    }  | 
 | 
 | 
 | 
    public LongMap<ConstantMap> getConstantPools() { | 
 | 
        return constantPools;  | 
 | 
    }  | 
 | 
 | 
 | 
    public LongMap<Type> getTypeMap() { | 
 | 
        return types;  | 
 | 
    }  | 
 | 
 | 
 | 
    private EventParser createEventParser(EventType eventType) throws IOException { | 
 | 
        List<Parser> parsers = new ArrayList<Parser>();  | 
 | 
        for (ValueDescriptor f : eventType.getFields()) { | 
 | 
            parsers.add(createParser(f));  | 
 | 
        }  | 
 | 
        return new EventParser(timeConverter, eventType, parsers.toArray(new Parser[0]));  | 
 | 
    }  | 
 | 
 | 
 | 
    private Parser createParser(ValueDescriptor v) throws IOException { | 
 | 
        boolean constantPool = PrivateAccess.getInstance().isConstantPool(v);  | 
 | 
        if (v.isArray()) { | 
 | 
            Type valueType = PrivateAccess.getInstance().getType(v);  | 
 | 
            ValueDescriptor element = PrivateAccess.getInstance().newValueDescriptor(v.getName(), valueType, v.getAnnotationElements(), 0, constantPool, null);  | 
 | 
            return new ArrayParser(createParser(element));  | 
 | 
        }  | 
 | 
        long id = v.getTypeId();  | 
 | 
        Type type = types.get(id);  | 
 | 
        if (type == null) { | 
 | 
            throw new IOException("Type '" + v.getTypeName() + "' is not defined"); | 
 | 
        }  | 
 | 
        if (constantPool) { | 
 | 
            ConstantMap pool = constantPools.get(id);  | 
 | 
            if (pool == null) { | 
 | 
                pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());  | 
 | 
                constantPools.put(id, pool);  | 
 | 
            }  | 
 | 
            return new ConstantMapValueParser(pool);  | 
 | 
        }  | 
 | 
        Parser parser = parsers.get(id);  | 
 | 
        if (parser == null) { | 
 | 
            if (!v.getFields().isEmpty()) { | 
 | 
                return createCompositeParser(type);  | 
 | 
            } else { | 
 | 
                return registerParserType(type, createPrimitiveParser(type));  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return parser;  | 
 | 
    }  | 
 | 
 | 
 | 
    private Parser createPrimitiveParser(Type type) throws IOException { | 
 | 
        switch (type.getName()) { | 
 | 
        case "int":  | 
 | 
            return new IntegerParser();  | 
 | 
        case "long":  | 
 | 
            return new LongParser();  | 
 | 
        case "float":  | 
 | 
            return new FloatParser();  | 
 | 
        case "double":  | 
 | 
            return new DoubleParser();  | 
 | 
        case "char":  | 
 | 
            return new CharacterParser();  | 
 | 
        case "boolean":  | 
 | 
            return new BooleanParser();  | 
 | 
        case "short":  | 
 | 
            return new ShortParser();  | 
 | 
        case "byte":  | 
 | 
            return new ByteParser();  | 
 | 
        case "java.lang.String":  | 
 | 
            ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());  | 
 | 
            constantPools.put(type.getId(), pool);  | 
 | 
            return new StringParser(pool);  | 
 | 
        default:  | 
 | 
            throw new IOException("Unknown primitive type " + type.getName()); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private Parser registerParserType(Type t, Parser parser) { | 
 | 
        Parser p = parsers.get(t.getId());  | 
 | 
          | 
 | 
        if (p != null) { | 
 | 
            return p;  | 
 | 
        }  | 
 | 
        parsers.put(t.getId(), parser);  | 
 | 
        return parser;  | 
 | 
    }  | 
 | 
 | 
 | 
    private CompositeParser createCompositeParser(Type type) throws IOException { | 
 | 
        List<ValueDescriptor> vds = type.getFields();  | 
 | 
        Parser[] parsers = new Parser[vds.size()];  | 
 | 
        CompositeParser composite = new CompositeParser(parsers);  | 
 | 
          | 
 | 
        registerParserType(type, composite);  | 
 | 
 | 
 | 
        int index = 0;  | 
 | 
        for (ValueDescriptor vd : vds) { | 
 | 
            parsers[index++] = createParser(vd);  | 
 | 
        }  | 
 | 
        return composite;  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final class BooleanParser extends Parser { | 
 | 
        @Override  | 
 | 
        public Object parse(RecordingInput input) throws IOException { | 
 | 
            return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final class ByteParser extends Parser { | 
 | 
        @Override  | 
 | 
        public Object parse(RecordingInput input) throws IOException { | 
 | 
            return Byte.valueOf(input.readByte());  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final class LongParser extends Parser { | 
 | 
        @Override  | 
 | 
        public Object parse(RecordingInput input) throws IOException { | 
 | 
            return Long.valueOf(input.readLong());  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final class IntegerParser extends Parser { | 
 | 
        @Override  | 
 | 
        public Object parse(RecordingInput input) throws IOException { | 
 | 
            return Integer.valueOf(input.readInt());  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final class ShortParser extends Parser { | 
 | 
        @Override  | 
 | 
        public Object parse(RecordingInput input) throws IOException { | 
 | 
            return Short.valueOf(input.readShort());  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final class CharacterParser extends Parser { | 
 | 
        @Override  | 
 | 
        public Object parse(RecordingInput input) throws IOException { | 
 | 
            return Character.valueOf(input.readChar());  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final class FloatParser extends Parser { | 
 | 
        @Override  | 
 | 
        public Object parse(RecordingInput input) throws IOException { | 
 | 
            return Float.valueOf(input.readFloat());  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final class DoubleParser extends Parser { | 
 | 
        @Override  | 
 | 
        public Object parse(RecordingInput input) throws IOException { | 
 | 
            return Double.valueOf(input.readDouble());  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final class StringParser extends Parser { | 
 | 
        private final ConstantMap stringConstantMap;  | 
 | 
        private String last;  | 
 | 
 | 
 | 
        StringParser(ConstantMap stringConstantMap) { | 
 | 
            this.stringConstantMap = stringConstantMap;  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public Object parse(RecordingInput input) throws IOException { | 
 | 
            String s = parseEncodedString(input);  | 
 | 
            if (!Objects.equals(s, last)) { | 
 | 
                last = s;  | 
 | 
            }  | 
 | 
            return last;  | 
 | 
        }  | 
 | 
 | 
 | 
        private String parseEncodedString(RecordingInput input) throws IOException { | 
 | 
            byte encoding = input.readByte();  | 
 | 
            if (encoding == RecordingInput.STRING_ENCODING_CONSTANT_POOL) { | 
 | 
                long id = input.readLong();  | 
 | 
                return (String) stringConstantMap.get(id);  | 
 | 
            } else { | 
 | 
                return input.readEncodedString(encoding);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private final static class ArrayParser extends Parser { | 
 | 
        private final Parser elementParser;  | 
 | 
 | 
 | 
        public ArrayParser(Parser elementParser) { | 
 | 
            this.elementParser = elementParser;  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public Object parse(RecordingInput input) throws IOException { | 
 | 
            final int size = input.readInt();  | 
 | 
            final Object[] array = new Object[size];  | 
 | 
            for (int i = 0; i < size; i++) { | 
 | 
                array[i] = elementParser.parse(input);  | 
 | 
            }  | 
 | 
            return array;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private final static class CompositeParser extends Parser { | 
 | 
        private final Parser[] parsers;  | 
 | 
 | 
 | 
        public CompositeParser(Parser[] valueParsers) { | 
 | 
            this.parsers = valueParsers;  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public Object parse(RecordingInput input) throws IOException { | 
 | 
            final Object[] values = new Object[parsers.length];  | 
 | 
            for (int i = 0; i < values.length; i++) { | 
 | 
                values[i] = parsers[i].parse(input);  | 
 | 
            }  | 
 | 
            return values;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final class ConstantMapValueParser extends Parser { | 
 | 
        private final ConstantMap pool;  | 
 | 
 | 
 | 
        ConstantMapValueParser(ConstantMap pool) { | 
 | 
            this.pool = pool;  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public Object parse(RecordingInput input) throws IOException { | 
 | 
            return pool.get(input.readLong());  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |