| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package jdk.jfr.internal;  | 
 | 
 | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_CONSTANT_POOL;  | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_DEFAULT_VALUE;  | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_DIMENSION;  | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_GMT_OFFSET;  | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_ID;  | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_LOCALE;  | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_NAME;  | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_SIMPLE_TYPE;  | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_SUPER_TYPE;  | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_TYPE_ID;  | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_ANNOTATION;  | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_FIELD;  | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_SETTING;  | 
 | 
import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_TYPE;  | 
 | 
 | 
 | 
import java.io.DataOutput;  | 
 | 
import java.io.IOException;  | 
 | 
import java.util.HashMap;  | 
 | 
import java.util.HashSet;  | 
 | 
import java.util.LinkedHashMap;  | 
 | 
import java.util.List;  | 
 | 
import java.util.Set;  | 
 | 
 | 
 | 
import jdk.jfr.AnnotationElement;  | 
 | 
import jdk.jfr.SettingDescriptor;  | 
 | 
import jdk.jfr.ValueDescriptor;  | 
 | 
import jdk.jfr.internal.MetadataDescriptor.Attribute;  | 
 | 
import jdk.jfr.internal.MetadataDescriptor.Element;  | 
 | 
import jdk.jfr.internal.consumer.RecordingInput;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
final class MetadataWriter { | 
 | 
 | 
 | 
    private final Element metadata = new Element("metadata"); | 
 | 
    private final Element root = new Element("root"); | 
 | 
 | 
 | 
    public MetadataWriter(MetadataDescriptor descriptor) { | 
 | 
        descriptor.getTypes().forEach(type -> makeTypeElement(metadata, type));  | 
 | 
 | 
 | 
        root.add(metadata);  | 
 | 
        Element region = new Element("region"); | 
 | 
        region.addAttribute(ATTRIBUTE_LOCALE, descriptor.locale);  | 
 | 
        region.addAttribute(ATTRIBUTE_GMT_OFFSET, descriptor.gmtOffset);  | 
 | 
        root.add(region);  | 
 | 
    }  | 
 | 
 | 
 | 
    public void writeBinary(DataOutput output) throws IOException { | 
 | 
        Set<String> stringPool = new HashSet<>(1000);  | 
 | 
        // Possible improvement, sort string by how often they occur.  | 
 | 
          | 
 | 
        buildStringPool(root, stringPool);  | 
 | 
        HashMap<String, Integer> lookup = new LinkedHashMap<>(stringPool.size());  | 
 | 
        int index = 0;  | 
 | 
        int poolSize = stringPool.size();  | 
 | 
        writeInt(output, poolSize);  | 
 | 
        for (String s : stringPool) { | 
 | 
            lookup.put(s, index);  | 
 | 
            writeString(output, s);  | 
 | 
            index++;  | 
 | 
        }  | 
 | 
        write(output, root, lookup);  | 
 | 
    }  | 
 | 
 | 
 | 
    private void writeString(DataOutput out, String s) throws IOException { | 
 | 
        if (s == null ) { | 
 | 
            out.writeByte(RecordingInput.STRING_ENCODING_NULL);  | 
 | 
            return;  | 
 | 
        }  | 
 | 
        out.writeByte(RecordingInput.STRING_ENCODING_CHAR_ARRAY);   | 
 | 
        int length = s.length();  | 
 | 
        writeInt(out, length);  | 
 | 
            for (int i = 0; i < length; i++) { | 
 | 
                writeInt(out, s.charAt(i));  | 
 | 
            }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void writeInt(DataOutput out, int v) throws IOException { | 
 | 
 | 
 | 
        long s = v & 0xffffffffL;  | 
 | 
        if (s < 1 << 7) { | 
 | 
            out.write((byte) (s));  | 
 | 
            return;  | 
 | 
        }  | 
 | 
        out.write((byte) (s | 0x80));   | 
 | 
        s >>= 7;  | 
 | 
        if (s < 1 << 7) { | 
 | 
            out.write((byte) (s));  | 
 | 
            return;  | 
 | 
        }  | 
 | 
        out.write((byte) (s | 0x80));   | 
 | 
        s >>= 7;  | 
 | 
        if (s < 1 << 7) { | 
 | 
            out.write((byte) (s));  | 
 | 
            return;  | 
 | 
        }  | 
 | 
        out.write((byte) (s | 0x80));   | 
 | 
        s >>= 7;  | 
 | 
        if (s < 1 << 7) { | 
 | 
            out.write((byte) (s));  | 
 | 
            return;  | 
 | 
        }  | 
 | 
        s >>= 7;  | 
 | 
        out.write((byte) (s));  | 
 | 
    }  | 
 | 
 | 
 | 
    private void buildStringPool(Element element, Set<String> pool) { | 
 | 
        pool.add(element.name);  | 
 | 
        for (Attribute a : element.attributes) { | 
 | 
            pool.add(a.name);  | 
 | 
            pool.add(a.value);  | 
 | 
        }  | 
 | 
        for (Element child : element.elements) { | 
 | 
            buildStringPool(child, pool);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void write(DataOutput output,Element element, HashMap<String, Integer> lookup) throws IOException { | 
 | 
        writeInt(output, lookup.get(element.name));  | 
 | 
        writeInt(output, element.attributes.size());  | 
 | 
        for (Attribute a : element.attributes) { | 
 | 
            writeInt(output, lookup.get(a.name));  | 
 | 
            writeInt(output, lookup.get(a.value));  | 
 | 
        }  | 
 | 
        writeInt(output, element.elements.size());  | 
 | 
        for (Element child : element.elements) { | 
 | 
            write(output, child, lookup);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void makeTypeElement(Element root, Type type) { | 
 | 
        Element element = root.newChild(ELEMENT_TYPE);  | 
 | 
        element.addAttribute(ATTRIBUTE_NAME, type.getName());  | 
 | 
        String superType = type.getSuperType();  | 
 | 
        if (superType != null) { | 
 | 
            element.addAttribute(ATTRIBUTE_SUPER_TYPE, superType);  | 
 | 
        }  | 
 | 
        if (type.isSimpleType()) { | 
 | 
            element.addAttribute(ATTRIBUTE_SIMPLE_TYPE, true);  | 
 | 
        }  | 
 | 
        element.addAttribute(ATTRIBUTE_ID, type.getId());  | 
 | 
        if (type instanceof PlatformEventType) { | 
 | 
            for (SettingDescriptor v : ((PlatformEventType)type).getSettings()) { | 
 | 
                makeSettingElement(element, v);  | 
 | 
            }  | 
 | 
        }  | 
 | 
        for (ValueDescriptor v : type.getFields()) { | 
 | 
            makeFieldElement(element, v);  | 
 | 
        }  | 
 | 
        for (AnnotationElement a : type.getAnnotationElements()) { | 
 | 
            makeAnnotation(element, a);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void makeSettingElement(Element typeElement, SettingDescriptor s) { | 
 | 
        Element element = typeElement.newChild(ELEMENT_SETTING);  | 
 | 
        element.addAttribute(ATTRIBUTE_NAME, s.getName());  | 
 | 
        element.addAttribute(ATTRIBUTE_TYPE_ID, s.getTypeId());  | 
 | 
        element.addAttribute(ATTRIBUTE_DEFAULT_VALUE, s.getDefaultValue());  | 
 | 
        for (AnnotationElement a : s.getAnnotationElements()) { | 
 | 
            makeAnnotation(element, a);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void makeFieldElement(Element typeElement, ValueDescriptor v) { | 
 | 
        Element element = typeElement.newChild(ELEMENT_FIELD);  | 
 | 
        element.addAttribute(ATTRIBUTE_NAME, v.getName());  | 
 | 
        element.addAttribute(ATTRIBUTE_TYPE_ID, v.getTypeId());  | 
 | 
        if (v.isArray()) { | 
 | 
            element.addAttribute(ATTRIBUTE_DIMENSION, 1);  | 
 | 
        }  | 
 | 
        if (PrivateAccess.getInstance().isConstantPool(v)) { | 
 | 
            element.addAttribute(ATTRIBUTE_CONSTANT_POOL, true);  | 
 | 
        }  | 
 | 
        for (AnnotationElement a : v.getAnnotationElements()) { | 
 | 
            makeAnnotation(element, a);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void makeAnnotation(Element entity, AnnotationElement annotation) { | 
 | 
        Element element = entity.newChild(ELEMENT_ANNOTATION);  | 
 | 
        element.addAttribute(ATTRIBUTE_TYPE_ID, annotation.getTypeId());  | 
 | 
        List<Object> values = annotation.getValues();  | 
 | 
        int index = 0;  | 
 | 
        for (ValueDescriptor v : annotation.getValueDescriptors()) { | 
 | 
            Object value = values.get(index++);  | 
 | 
            if (v.isArray()) { | 
 | 
                element.addArrayAttribute(element, v.getName(), value);  | 
 | 
            } else { | 
 | 
                element.addAttribute(v.getName(), value);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
}  |