tmf : Introduce pattern segment and pattern segment builder
authorJean-Christian Kouame <jean-christian.kouame@ericsson.com>
Wed, 16 Dec 2015 16:29:10 +0000 (11:29 -0500)
committerMatthew Khouzam <matthew.khouzam@ericsson.com>
Wed, 17 Feb 2016 15:38:01 +0000 (10:38 -0500)
The pattern segments are generated using an XML description. They will
be generated by the XML pattern matching analysis and could be used to
feed views such as the timing analysis views.

Change-Id: I366cf8fa4344c05e0067a61dd1e0f720b18d51a3
Signed-off-by: Jean-Christian Kouame <jean-christian.kouame@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/62873
Reviewed-by: Hudson CI
Reviewed-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Tested-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/META-INF/MANIFEST.MF
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlPatternSegmentBuilder.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/segment/TmfXmlPatternSegment.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/stateprovider/TmfXmlStrings.java

index f9b084ed08d754135b5bfb70570ab9b6535fae1a..2111229a28778005f3172d0446fff0dfbd9a8006 100644 (file)
@@ -10,10 +10,13 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-ActivationPolicy: lazy
 Require-Bundle: org.eclipse.core.runtime,
  org.eclipse.tracecompass.common.core,
- org.eclipse.tracecompass.tmf.core
+ org.eclipse.tracecompass.tmf.core,
+ org.eclipse.tracecompass.segmentstore.core
 Export-Package: org.eclipse.tracecompass.internal.tmf.analysis.xml.core;x-friends:="org.eclipse.tracecompass.tmf.analysis.xml.core.tests",
  org.eclipse.tracecompass.tmf.analysis.xml.core.model,
  org.eclipse.tracecompass.tmf.analysis.xml.core.model.readonly,
  org.eclipse.tracecompass.tmf.analysis.xml.core.model.readwrite,
  org.eclipse.tracecompass.tmf.analysis.xml.core.module,
+ org.eclipse.tracecompass.tmf.analysis.xml.core.segment,
  org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider
+Import-Package: com.google.common.collect
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlPatternSegmentBuilder.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/model/TmfXmlPatternSegmentBuilder.java
new file mode 100644 (file)
index 0000000..7817979
--- /dev/null
@@ -0,0 +1,298 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.model;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator;
+import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
+import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.segment.TmfXmlPatternSegment;
+import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * This class defines a pattern segment builder. It will use the XML description
+ * of the pattern segment to generate it at runtime.
+ *
+ * @author Jean-Christian Kouame
+ * @since 2.0
+ *
+ */
+public class TmfXmlPatternSegmentBuilder {
+
+    /**
+     * The string unknown
+     */
+    public static final String UNKNOWN_STRING = "unknown"; //$NON-NLS-1$
+    /**
+     * Prefix for the pattern segment name
+     */
+    public static final String PATTERN_SEGMENT_NAME_PREFIX = "seg_"; //$NON-NLS-1$
+    private final ITmfXmlModelFactory fModelFactory;
+    private final IXmlStateSystemContainer fContainer;
+    private final List<TmfXmlPatternSegmentField> fFields = new ArrayList<>();
+    private final TmfXmlPatternSegmentType fSegmentType;
+
+    /**
+     * @param modelFactory
+     *            The factory used to create XML model elements
+     * @param node
+     *            XML element of the pattern segment builder
+     * @param parent
+     *            The state system container this pattern segment builder
+     *            belongs to
+     */
+    public TmfXmlPatternSegmentBuilder(ITmfXmlModelFactory modelFactory, Element node, IXmlStateSystemContainer parent) {
+        fModelFactory = modelFactory;
+        fContainer = parent;
+
+        //Set the XML type of the segment
+        NodeList nodesSegmentType = node.getElementsByTagName(TmfXmlStrings.SEGMENT_TYPE);
+        Element element = (Element) nodesSegmentType.item(0);
+        if (element == null) {
+            throw new IllegalArgumentException();
+        }
+        fSegmentType = new TmfXmlPatternSegmentType(element);
+
+        //Set the XML content of the segment
+        NodeList nodesSegmentContent = node.getElementsByTagName(TmfXmlStrings.SEGMENT_CONTENT);
+        Element fContentElement = (Element) nodesSegmentContent.item(0);
+        if (fContentElement != null) {
+            NodeList nodesSegmentField = fContentElement.getElementsByTagName(TmfXmlStrings.SEGMENT_FIELD);
+            for (int i = 0; i < nodesSegmentField.getLength(); i++) {
+                fFields.add(new TmfXmlPatternSegmentField(checkNotNull((Element) nodesSegmentField.item(i))));
+            }
+        }
+    }
+
+    /**
+     * Generate a pattern segment
+     *
+     * @param event
+     *            The active event
+     * @param start
+     *            Start time of the pattern segment to generate
+     * @param end
+     *            End time of the pattern segment to generate
+     * @return The pattern segment generated
+     */
+    public TmfXmlPatternSegment generatePatternSegment(ITmfEvent event, ITmfTimestamp start, ITmfTimestamp end) {
+        int scale = event.getTimestamp().getScale();
+        long startValue = start.normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+        long endValue = end.normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+        String segmentName = getPatternSegmentName(event);
+        Map<String, ITmfStateValue> fields = new HashMap<>();
+        setPatternSegmentContent(event, start, end, fields);
+        return new TmfXmlPatternSegment(startValue, endValue, scale, segmentName, fields);
+    }
+
+    /**
+     * Get the pattern segment name
+     *
+     * @param event
+     *            The active event
+     * @return The name of the segment
+     */
+    private String getPatternSegmentName(ITmfEvent event) {
+        return fSegmentType.getName(event);
+    }
+
+    /**
+     * Compute all the fields and their values for this pattern segment. The
+     * fields could be constant values or values queried from the state system.
+     *
+     * @param event
+     *            The current event
+     * @param start
+     *            The start timestamp of this segment
+     * @param end
+     *            The end timestamp of this segment
+     * @param fields
+     *            The map that will contained all the fields
+     */
+    private void setPatternSegmentContent(ITmfEvent event, ITmfTimestamp start, ITmfTimestamp end, Map<String, ITmfStateValue> fields) {
+        for (TmfXmlPatternSegmentField field : fFields) {
+            fields.put(field.getName(), field.getValue(event));
+        }
+    }
+
+    private static ITmfStateValue getStateValueFromConstant(String constantValue, String type) {
+        switch (type) {
+        case TmfXmlStrings.TYPE_INT:
+            return TmfStateValue.newValueInt(Integer.parseInt(constantValue));
+        case TmfXmlStrings.TYPE_LONG:
+            return TmfStateValue.newValueLong(Long.parseLong(constantValue));
+        case TmfXmlStrings.TYPE_STRING:
+            return TmfStateValue.newValueString(constantValue);
+        case TmfXmlStrings.TYPE_NULL:
+            return TmfStateValue.nullValue();
+        default:
+            throw new IllegalArgumentException("Invalid type of field : " + type); //$NON-NLS-1$
+        }
+    }
+
+    private static void getNameFromXmlStateValue(ITmfEvent event, StringBuilder builder, ITmfXmlStateValue xmlStateValue) {
+        try {
+            ITmfStateValue value = xmlStateValue.getValue(event);
+            switch (value.getType()) {
+            case DOUBLE:
+                builder.append(value.unboxDouble());
+                break;
+            case INTEGER:
+                builder.append(value.unboxInt());
+                break;
+            case LONG:
+                builder.append(value.unboxLong());
+                break;
+            case NULL:
+                builder.append(UNKNOWN_STRING);
+                break;
+            case STRING:
+                builder.append(value.unboxStr());
+                break;
+            default:
+                throw new StateValueTypeException("Invalid type of state value"); //$NON-NLS-1$
+            }
+        } catch (AttributeNotFoundException e) {
+            Activator.logInfo("Impossible to get the state value", e); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * This class represents the segment fields described in the XML. The real
+     * value of the field will be set at runtime using the active event.
+     *
+     * @author Jean-Christian Kouame
+     *
+     */
+    private class TmfXmlPatternSegmentField {
+        private final String fName;
+        private final String fType;
+        private final @Nullable ITmfStateValue fStateValue;
+        private final @Nullable ITmfXmlStateValue fXmlStateValue;
+
+        /**
+         * Constructor
+         *
+         * @param element
+         *            The pattern segment field node
+         */
+        public TmfXmlPatternSegmentField(Element element) {
+            // The name, the type and the value of each field could respectively
+            // be found from the attributes name, type and value. If the value
+            // attribute is not available, try to find it from the child state
+            // value.
+            fName = element.getAttribute(TmfXmlStrings.NAME);
+            fType = element.getAttribute(TmfXmlStrings.TYPE);
+            String constantValue = element.getAttribute(TmfXmlStrings.VALUE);
+            if (constantValue.isEmpty() && !fType.equals(TmfXmlStrings.TYPE_NULL)) {
+                fStateValue = null;
+                Element elementFieldStateValue = (Element) element.getElementsByTagName(TmfXmlStrings.STATE_VALUE).item(0);
+                if (elementFieldStateValue == null) {
+                    throw new IllegalArgumentException("The value of the field " + fName + " is missing"); //$NON-NLS-1$ //$NON-NLS-2$
+                }
+                fXmlStateValue = fModelFactory.createStateValue(elementFieldStateValue, fContainer, new ArrayList<>());
+            } else {
+                fStateValue = getStateValueFromConstant(constantValue, fType);
+                fXmlStateValue = null;
+            }
+        }
+
+        /**
+         * Get the real value of the XML pattern segment field
+         *
+         * @param event
+         *            The active event
+         * @return The state value representing the value of the XML pattern
+         *         segment field
+         */
+        public ITmfStateValue getValue(ITmfEvent event) {
+            if (fStateValue != null) {
+                return fStateValue;
+            }
+            try {
+                return checkNotNull(fXmlStateValue).getValue(event);
+            } catch (AttributeNotFoundException e) {
+                Activator.logError("Failed to get the state value", e); //$NON-NLS-1$
+            }
+            throw new IllegalStateException("Failed to get the value for the segment field " + fName); //$NON-NLS-1$
+        }
+
+        /**
+         * Get the name of the XML pattern segment field
+         *
+         * @return The name
+         */
+        public String getName() {
+            return fName;
+        }
+    }
+
+    /**
+     * This class represents the segment type described in XML.
+     *
+     * @author Jean-Christian Kouame
+     *
+     */
+    private class TmfXmlPatternSegmentType {
+        private final String fSegmentNameAttribute;
+        private final @Nullable ITmfXmlStateValue fNameStateValue;
+
+        /**
+         * Constructor
+         *
+         * @param element
+         *            The pattern segment type node
+         */
+        public TmfXmlPatternSegmentType(Element element) {
+            // Try to find the segment name from the name attribute. If
+            // attribute not available, try to find it from the child state value
+            fSegmentNameAttribute = element.getAttribute(TmfXmlStrings.SEGMENT_NAME);
+            if (!fSegmentNameAttribute.isEmpty()) {
+                fNameStateValue = null;
+            } else {
+                Element elementSegmentNameStateValue = (Element) element.getElementsByTagName(TmfXmlStrings.STATE_VALUE).item(0);
+                if (elementSegmentNameStateValue == null) {
+                    throw new IllegalArgumentException("Failed to get the segment name. A state value is needed."); //$NON-NLS-1$
+                }
+                fNameStateValue = fModelFactory.createStateValue(elementSegmentNameStateValue, fContainer, new ArrayList<>());
+            }
+        }
+
+        /**
+         * Get the name of the segment
+         *
+         * @param event
+         *            The active event
+         * @return The segment name
+         */
+        public String getName(ITmfEvent event) {
+            StringBuilder name = new StringBuilder(PATTERN_SEGMENT_NAME_PREFIX);
+            if (fNameStateValue != null) {
+                getNameFromXmlStateValue(event, name, fNameStateValue);
+            } else {
+                name.append(fSegmentNameAttribute);
+            }
+            return name.toString();
+        }
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/segment/TmfXmlPatternSegment.java b/tmf/org.eclipse.tracecompass.tmf.analysis.xml.core/src/org/eclipse/tracecompass/tmf/analysis/xml/core/segment/TmfXmlPatternSegment.java
new file mode 100644 (file)
index 0000000..300e730
--- /dev/null
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package org.eclipse.tracecompass.tmf.analysis.xml.core.segment;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.segmentstore.core.ISegment;
+import org.eclipse.tracecompass.segmentstore.core.SegmentComparators;
+import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+
+import com.google.common.collect.Ordering;
+
+/**
+ * This class implements an XML Pattern Segment. This type of segment has
+ * content and a default timestamp, which is the start time of the segment.
+ *
+ * @author Jean-Christian Kouame
+ * @since 2.0
+ *
+ */
+public class TmfXmlPatternSegment implements ISegment {
+
+    /**
+     * The serial version UID
+     */
+    private static final long serialVersionUID = 3556323761465412078L;
+
+    /* 'Byte' equivalent for state values types */
+    private static final byte TYPE_NULL = -1;
+    private static final byte TYPE_INTEGER = 0;
+    private static final byte TYPE_STRING = 1;
+    private static final byte TYPE_LONG = 2;
+
+    private static final @NonNull Comparator<ISegment> COMPARATOR = Ordering
+            .from(SegmentComparators.INTERVAL_START_COMPARATOR)
+            .compound(SegmentComparators.INTERVAL_END_COMPARATOR)
+             /* Kind of lazy, but should work! */
+            .compound(Ordering.usingToString());
+
+    private final int fScale;
+    private final long fStart;
+    private final long fEnd;
+    private final String fSegmentName;
+    private transient Map<@NonNull String, @NonNull ITmfStateValue> fContent;
+
+    /**
+     * Constructs an XML pattern segment
+     *
+     * @param start
+     *            Start time of the pattern segment
+     * @param end
+     *            End time of the pattern segment
+     * @param scale
+     *            Scale of the pattern segment
+     * @param segmentName
+     *            Name of the pattern segment
+     * @param fields
+     *            Fields of the pattern segment
+     */
+    public TmfXmlPatternSegment(long start, long end, int scale, String segmentName, @NonNull Map<@NonNull String, @NonNull ITmfStateValue> fields) {
+        fStart = start;
+        fEnd = end;
+        fScale = scale;
+        fSegmentName = segmentName;
+        fContent = Collections.unmodifiableMap(fields);
+    }
+
+    /**
+     * Get the start timestamp of the segment
+     *
+     * @return The start timestamp
+     */
+    public @NonNull ITmfTimestamp getTimestampStart() {
+        return new TmfTimestamp(fStart, fScale);
+    }
+
+    /**
+     * Get the end timestamp of this segment
+     *
+     * @return The end timestamp
+     */
+    public @NonNull ITmfTimestamp getTimestampEnd() {
+        return new TmfTimestamp(fEnd, fScale);
+    }
+
+    /**
+     * Get the content of the pattern segment
+     * @return The content
+     */
+    public Map<@NonNull String, @NonNull ITmfStateValue> getContent() {
+        return fContent;
+    }
+
+    /**
+     * Get the name of pattern segment
+     * @return The name
+     */
+    public String getName() {
+        return fSegmentName;
+    }
+
+    /**
+     * Get the timestamp scale of the pattern segment
+     * @return The timestamp scale
+     */
+    public int getScale() {
+        return fScale;
+    }
+
+    @Override
+    public int compareTo(@Nullable ISegment o) {
+        if (o == null) {
+            throw new IllegalArgumentException("Cannot compare to null"); //$NON-NLS-1$
+        }
+        return COMPARATOR.compare(this, o);
+    }
+
+    @Override
+    public long getStart() {
+        return fStart;
+    }
+
+    @Override
+    public long getEnd() {
+        return fEnd;
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder(getClass().getSimpleName())
+                .append(", [fTimestampStart=").append(getTimestampStart()) //$NON-NLS-1$
+                .append(", fTimestampEnd=").append(getTimestampEnd()) //$NON-NLS-1$
+                .append(", duration= ").append(getLength()) //$NON-NLS-1$
+                .append(", fName=").append(getName()) //$NON-NLS-1$
+                .append(", fContent=").append(getContent()) //$NON-NLS-1$
+                .append("]").toString(); //$NON-NLS-1$
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        out.defaultWriteObject();
+
+        // Write the number of fields
+        out.writeInt(fContent.size());
+
+        // Write the fields
+        for (Map.Entry<String, ITmfStateValue> entry : fContent.entrySet()) {
+            out.writeInt(entry.getKey().length());
+            out.writeBytes(entry.getKey());
+            final ITmfStateValue value = entry.getValue();
+            final byte type = getByteFromType(value.getType());
+            out.writeByte(type);
+            switch (type) {
+            case TYPE_NULL:
+                break;
+            case TYPE_INTEGER:
+                out.writeInt(value.unboxInt());
+                break;
+            case TYPE_LONG:
+                out.writeLong(value.unboxLong());
+                break;
+            case TYPE_STRING:
+                final @NonNull String string = value.unboxStr();
+                out.writeInt(string.length());
+                out.writeBytes(string);
+                break;
+            default:
+                throw new IOException("Write object failed : Invalid data"); //$NON-NLS-1$
+            }
+        }
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        int contentSize = in.readInt();
+
+        final Map<@NonNull String, @NonNull ITmfStateValue> content = new HashMap<>();
+        for (int i = 0; i < contentSize; i++) {
+            int length = in.readInt();
+            byte[] bytes = new byte[length];
+            in.read(bytes, 0, length);
+            String name = new String(bytes);
+
+            Byte type = in.readByte();
+            ITmfStateValue value;
+            switch (type) {
+            case TYPE_NULL:
+                value = TmfStateValue.nullValue();
+                break;
+            case TYPE_INTEGER:
+                value = TmfStateValue.newValueInt(in.readInt());
+                break;
+            case TYPE_LONG:
+                value = TmfStateValue.newValueLong(in.readLong());
+                break;
+            case TYPE_STRING:
+                length = in.readInt();
+                bytes = new byte[length];
+                in.read(bytes, 0, length);
+                value = TmfStateValue.newValueString(new String(bytes));
+                break;
+            default:
+                throw new IOException("Read object failed : Invalid data"); //$NON-NLS-1$
+            }
+            content.put(name, value);
+        }
+        fContent = content;
+    }
+
+    /**
+     * Here we determine how state values "types" are written in the 8-bit field
+     * that indicates the value type in the file.
+     */
+    private static byte getByteFromType(ITmfStateValue.Type type) {
+        switch (type) {
+        case NULL:
+            return TYPE_NULL;
+        case INTEGER:
+            return TYPE_INTEGER;
+        case STRING:
+            return TYPE_STRING;
+        case LONG:
+            return TYPE_LONG;
+        case DOUBLE:
+        default:
+            /* Should not happen if the switch is fully covered */
+            throw new IllegalStateException("Data type " + type + " not supported"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+    }
+}
index e6e4111d39244a6cf93a15613ec4b9f84f32fbe3..47f4c1b5238129e044d9aafd23c6fa4a1f15276a 100644 (file)
@@ -100,4 +100,32 @@ public interface TmfXmlStrings {
     String LE = "le";
     String LT = "lt";
 
+    /* XML pattern elements */
+    /**
+     * @since 2.0
+     */
+    String PATTERN = "pattern";
+
+    /* XML synthetic event elements */
+    /**
+     * @since 2.0
+     */
+    String SEGMENT_NAME = "segName";
+    /**
+     * @since 2.0
+     */
+    String SEGMENT = "segment";
+    /**
+     * @since 2.0
+     */
+    String SEGMENT_TYPE = "segType";
+    /**
+     * @since 2.0
+     */
+    String SEGMENT_CONTENT = "segContent";
+    /**
+     * @since 2.0
+     */
+    String SEGMENT_FIELD = "segField";
+
 }
\ No newline at end of file
This page took 0.032133 seconds and 5 git commands to generate.