tmf: Enforce non-null state sytem backends
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / TransientState.java
index 26f163cc901d3e6966f47fccc144c54612dd76a0..c86b90641a68fd0f29162c1fd51f2f2436fb541f 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012 Ericsson
+ * Copyright (c) 2012, 2013 Ericsson
  * Copyright (c) 2010, 2011 École Polytechnique de Montréal
  * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
  *
@@ -16,108 +16,156 @@ import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.IStateHistoryBackend;
 import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
 import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
 import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
 import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
 import org.eclipse.linuxtools.tmf.core.interval.TmfStateInterval;
 import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
+import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue.Type;
 import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
 
 /**
- * The Transient State is used to build intervals from punctual state changes. It
- * contains a "state info" vector similar to the "current state", except here we
- * also record the start time of every state stored in it.
+ * The Transient State is used to build intervals from punctual state changes.
+ * It contains a "state info" vector similar to the "current state", except here
+ * we also record the start time of every state stored in it.
  *
- * We can then build StateInterval's, to be inserted in the State History when
- * we detect state changes : the "start time" of the interval will be the
- * recorded time we have here, and the "end time" will be the timestamp of the
- * new state-changing event we just read.
- *
- * @author alexmont
+ * We can then build {@link ITmfStateInterval}'s, to be inserted in a
+ * {@link IStateHistoryBackend} when we detect state changes : the "start time"
+ * of the interval will be the recorded time we have here, and the "end time"
+ * will be the timestamp of the new state-changing event we just read.
  *
+ * @author Alexandre Montplaisir
  */
-class TransientState {
+public class TransientState {
 
     /* Indicates where to insert state changes that we generate */
-    private final IStateHistoryBackend backend;
+    @NonNull private final IStateHistoryBackend backend;
 
     private boolean isActive;
     private long latestTime;
 
-    private ArrayList<ITmfStateValue> ongoingStateInfo;
-    private final ArrayList<Long> ongoingStateStartTimes;
-    private final ArrayList<Byte> stateValueTypes;
+    private List<ITmfStateValue> ongoingStateInfo;
+    private List<Long> ongoingStateStartTimes;
+    private List<Type> stateValueTypes;
 
-    TransientState(IStateHistoryBackend backend) {
+    /**
+     * Constructor
+     *
+     * @param backend
+     *            The back-end in which to insert the generated state intervals
+     */
+    public TransientState(@NonNull IStateHistoryBackend backend) {
         this.backend = backend;
         isActive = true;
-        ongoingStateInfo = new ArrayList<ITmfStateValue>();
-        ongoingStateStartTimes = new ArrayList<Long>();
-        stateValueTypes = new ArrayList<Byte>();
-
-        if (backend != null) {
-            latestTime = backend.getStartTime();
-        } else {
-            latestTime = 0;
-        }
+        ongoingStateInfo = new ArrayList<>();
+        ongoingStateStartTimes = new ArrayList<>();
+        stateValueTypes = new ArrayList<>();
+
+        latestTime = backend.getStartTime();
     }
 
-    long getLatestTime() {
+    /**
+     * Get the latest time we have seen so far.
+     *
+     * @return The latest time seen in the transient state
+     */
+    public long getLatestTime() {
         return latestTime;
     }
 
-    ITmfStateValue getOngoingStateValue(int index)
-            throws AttributeNotFoundException {
-
-        checkValidAttribute(index);
-        return ongoingStateInfo.get(index);
+    /**
+     * Retrieve the ongoing state value for a given index (attribute quark).
+     *
+     * @param quark
+     *            The quark of the attribute to look for
+     * @return The corresponding state value
+     * @throws AttributeNotFoundException
+     *             If the quark is invalid
+     */
+    public ITmfStateValue getOngoingStateValue(int quark) throws AttributeNotFoundException {
+        checkValidAttribute(quark);
+        return ongoingStateInfo.get(quark);
     }
 
-    void changeOngoingStateValue(int index, ITmfStateValue newValue)
-            throws AttributeNotFoundException {
-
-        checkValidAttribute(index);
-        ongoingStateInfo.set(index, newValue);
+    /**
+     * Retrieve the start time of the state in which the given attribute is in.
+     *
+     * @param quark
+     *            The quark of the attribute to look for
+     * @return The start time of the current state for this attribute
+     * @throws AttributeNotFoundException
+     *             If the quark is invalid
+     */
+    public long getOngoingStartTime(int quark) throws AttributeNotFoundException {
+        checkValidAttribute(quark);
+        return ongoingStateStartTimes.get(quark);
     }
 
     /**
-     * Return the "ongoing" value for a given attribute as a dummy interval
-     * whose end time = -1 (since we don't know its real end time yet).
+     * Modify the current state for a given attribute. This will not update the
+     * "ongoing state start time" in any way, so be careful when using this.
      *
      * @param quark
+     *            The quark of the attribute to modify
+     * @param newValue
+     *            The state value the attribute should have
      * @throws AttributeNotFoundException
+     *             If the quark is invalid
      */
-    ITmfStateInterval getOngoingInterval(int quark)
+    public void changeOngoingStateValue(int quark, ITmfStateValue newValue)
             throws AttributeNotFoundException {
-
         checkValidAttribute(quark);
-        return new TmfStateInterval(ongoingStateStartTimes.get(quark), -1, quark,
-                ongoingStateInfo.get(quark));
+        ongoingStateInfo.set(quark, newValue);
     }
 
-    private void checkValidAttribute(int quark)
-            throws AttributeNotFoundException {
+    /**
+     * Convenience method to return the "ongoing" value for a given attribute as
+     * a dummy interval whose end time = the current latest time.
+     *
+     * @param quark
+     *            The quark of the attribute
+     * @return An interval representing the current state (but whose end time is
+     *         the current one, and probably not the "final" one)
+     * @throws AttributeNotFoundException
+     *             If the quark is invalid
+     */
+    public ITmfStateInterval getOngoingInterval(int quark) throws AttributeNotFoundException {
+        checkValidAttribute(quark);
+        return new TmfStateInterval(ongoingStateStartTimes.get(quark), latestTime,
+                quark, ongoingStateInfo.get(quark));
+    }
 
+    private void checkValidAttribute(int quark) throws AttributeNotFoundException {
         if (quark > ongoingStateInfo.size() - 1 || quark < 0) {
             throw new AttributeNotFoundException();
         }
     }
 
     /**
-     * Batch method of changeOngoingStateValue(), updates the complete
-     * ongoingStateInfo in one go. BE VERY CAREFUL WITH THIS! Especially with
-     * the sizes of both arrays.
+     * More advanced version of {@link #changeOngoingStateValue}. Replaces the
+     * complete ongoingStateInfo in one go, and updates the
+     * ongoingStateStartTimes and #stateValuesTypes accordingly. BE VERY CAREFUL
+     * WITH THIS!
      *
-     * Note that the new ongoingStateInfo will be a shallow copy of
-     * newStateInfo, so that last one must be already instantiated and all.
-     *
-     * @param newStateInfo
-     *            The List of StateValues to replace the old ongoingStateInfo
-     *            one.
+     * @param newStateIntervals
+     *            The List of intervals that will represent the new
+     *            "ongoing state". Their end times don't matter, we will only
+     *            check their value and start times.
      */
-    void changeOngoingStateInfo(ArrayList<ITmfStateValue> newStateInfo) {
-        this.ongoingStateInfo = newStateInfo;
+    public synchronized void replaceOngoingState(List<ITmfStateInterval> newStateIntervals) {
+        int size = newStateIntervals.size();
+        ongoingStateInfo = new ArrayList<>(size);
+        ongoingStateStartTimes = new ArrayList<>(size);
+        stateValueTypes = new ArrayList<>(size);
+
+        for (ITmfStateInterval interval : newStateIntervals) {
+            ongoingStateInfo.add(interval.getStateValue());
+            ongoingStateStartTimes.add(interval.getStartTime());
+            stateValueTypes.add(interval.getStateValue().getType());
+        }
     }
 
     /**
@@ -125,7 +173,7 @@ class TransientState {
      * Ongoing... tables can stay in sync with the number of attributes in the
      * attribute tree, namely when we add sub-path attributes.
      */
-    synchronized void addEmptyEntry() {
+    public synchronized void addEmptyEntry() {
         /*
          * Since this is a new attribute, we suppose it was in the "null state"
          * since the beginning (so we can have intervals covering for all
@@ -133,13 +181,9 @@ class TransientState {
          * change.
          */
         ongoingStateInfo.add(TmfStateValue.nullValue());
-        stateValueTypes.add((byte) -1);
+        stateValueTypes.add(Type.NULL);
 
-        if (backend == null) {
-            ongoingStateStartTimes.add(0L);
-        } else {
-            ongoingStateStartTimes.add(backend.getStartTime());
-        }
+        ongoingStateStartTimes.add(backend.getStartTime());
     }
 
     /**
@@ -157,43 +201,46 @@ class TransientState {
      * @return True if the value is present in the Transient State at this
      *         moment in time, false if it's not
      */
-    boolean hasInfoAboutStateOf(long time, int quark) {
+    public boolean hasInfoAboutStateOf(long time, int quark) {
         return (this.isActive() && time >= ongoingStateStartTimes.get(quark));
     }
 
     /**
-     * This is the lower-level method that will be called by the
-     * StateHistorySystem (with already-built StateValues and timestamps)
+     * Process a state change to be inserted in the history.
      *
-     * @param index
-     *            The index in the vectors (== the quark of the attribute)
-     * @param value
-     *            The new StateValue associated to this attribute
      * @param eventTime
      *            The timestamp associated with this state change
+     * @param value
+     *            The new StateValue associated to this attribute
+     * @param quark
+     *            The quark of the attribute that is being modified
      * @throws TimeRangeException
+     *             If 'eventTime' is invalid
      * @throws AttributeNotFoundException
+     *             IF 'quark' does not represent an existing attribute
      * @throws StateValueTypeException
+     *             If the state value to be inserted is of a different type of
+     *             what was inserted so far for this attribute.
      */
-    synchronized void processStateChange(long eventTime,
-            ITmfStateValue value, int index) throws TimeRangeException,
+    public synchronized void processStateChange(long eventTime,
+            ITmfStateValue value, int quark) throws TimeRangeException,
             AttributeNotFoundException, StateValueTypeException {
         assert (this.isActive);
 
-        byte expectedSvType = stateValueTypes.get(index);
-        checkValidAttribute(index);
+        Type expectedSvType = stateValueTypes.get(quark);
+        checkValidAttribute(quark);
 
         /*
          * Make sure the state value type we're inserting is the same as the
          * one registered for this attribute.
          */
-        if (expectedSvType == -1) {
+        if (expectedSvType == Type.NULL) {
             /*
              * The value hasn't been used yet, set it to the value
              * we're currently inserting (which might be null/-1 again).
              */
-            stateValueTypes.set(index, value.getType());
-        } else if ((value.getType() != -1) && (value.getType() != expectedSvType)) {
+            stateValueTypes.set(quark, value.getType());
+        } else if ((value.getType() != Type.NULL) && (value.getType() != expectedSvType)) {
             /*
              * We authorize inserting null values in any type of attribute,
              * but for every other types, it needs to match our expectations!
@@ -206,7 +253,7 @@ class TransientState {
             latestTime = eventTime;
         }
 
-        if (ongoingStateInfo.get(index).equals(value)) {
+        if (ongoingStateInfo.get(quark).equals(value)) {
             /*
              * This is the case where the new value and the one already present
              * in the Builder are the same. We do not need to create an
@@ -215,19 +262,19 @@ class TransientState {
             return;
         }
 
-        if (backend != null && ongoingStateStartTimes.get(index) < eventTime) {
+        if (ongoingStateStartTimes.get(quark) < eventTime) {
             /*
              * These two conditions are necessary to create an interval and
              * update ongoingStateInfo.
              */
-            backend.insertPastState(ongoingStateStartTimes.get(index),
+            backend.insertPastState(ongoingStateStartTimes.get(quark),
                     eventTime - 1, /* End Time */
-                    index, /* attribute quark */
-                    ongoingStateInfo.get(index)); /* StateValue */
+                    quark, /* attribute quark */
+                    ongoingStateInfo.get(quark)); /* StateValue */
 
-            ongoingStateStartTimes.set(index, eventTime);
+            ongoingStateStartTimes.set(quark, eventTime);
         }
-        ongoingStateInfo.set(index, value);
+        ongoingStateInfo.set(quark, value);
         return;
     }
 
@@ -240,7 +287,7 @@ class TransientState {
      * @param t
      *            The requested timestamp
      */
-    void doQuery(List<ITmfStateInterval> stateInfo, long t) {
+    public void doQuery(List<ITmfStateInterval> stateInfo, long t) {
         ITmfStateInterval interval;
 
         if (!this.isActive) {
@@ -262,11 +309,16 @@ class TransientState {
     }
 
     /**
-     * Close off the Transient State, used for example when we are done reading a
-     * static trace file. All the information currently contained in it will be
-     * converted to intervals and "flushed" to the State History.
+     * Close off the Transient State, used for example when we are done reading
+     * a static trace file. All the information currently contained in it will
+     * be converted to intervals and "flushed" to the state history.
+     *
+     * @param endTime
+     *            The timestamp to use as end time for the state history (since
+     *            it may be different than the timestamp of the last state
+     *            change)
      */
-    void closeTransientState(long endTime) {
+    public void closeTransientState(long endTime) {
         assert (this.isActive);
 
         for (int i = 0; i < ongoingStateInfo.size(); i++) {
@@ -288,7 +340,7 @@ class TransientState {
                  * This shouldn't happen, since we control where the interval's
                  * start time comes from
                  */
-                e.printStackTrace();
+                throw new IllegalStateException(e);
             }
         }
 
@@ -301,22 +353,26 @@ class TransientState {
     /**
      * Simply returns if this Transient State is currently being used or not
      *
-     * @return
+     * @return True if this transient state is active
      */
-    boolean isActive() {
+    public boolean isActive() {
         return this.isActive;
     }
 
-    void setInactive() {
+    /**
+     * Mark this transient state as inactive
+     */
+    public void setInactive() {
         isActive = false;
     }
 
     /**
-     * Debugging method that prints the contents of both 'ongoing...' vectors
+     * Debugging method that prints the contents of the transient state
      *
      * @param writer
+     *            The writer to which the output should be written
      */
-    void debugPrint(PrintWriter writer) {
+    public void debugPrint(PrintWriter writer) {
         /* Only used for debugging, shouldn't be externalized */
         writer.println("------------------------------"); //$NON-NLS-1$
         writer.println("Info stored in the Builder:"); //$NON-NLS-1$
This page took 0.032245 seconds and 5 git commands to generate.