scripting: Move the script event request to its own class

It is possible to make event requests without having an analysis. So now
the trace module also provides a getEventIterator method for a trace,
the request has been moved to its own file, and has a #getEventIterator
method

Change-Id: I73a1d51aafdb87960e6b91877fb4102e41b6a6d2
Signed-off-by: Geneviève Bastien <gbastien+lttng@versatic.net>
Reviewed-on: https://git.eclipse.org/r/151118
Tested-by: CI Bot
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
diff --git a/analyses/org.eclipse.tracecompass.incubator.scripting.core.tests/src/org/eclipse/tracecompass/incubator/scripting/core/tests/trace/TraceModuleTest.java b/analyses/org.eclipse.tracecompass.incubator.scripting.core.tests/src/org/eclipse/tracecompass/incubator/scripting/core/tests/trace/TraceModuleTest.java
index 43e87b2..0d87d9c 100644
--- a/analyses/org.eclipse.tracecompass.incubator.scripting.core.tests/src/org/eclipse/tracecompass/incubator/scripting/core/tests/trace/TraceModuleTest.java
+++ b/analyses/org.eclipse.tracecompass.incubator.scripting.core.tests/src/org/eclipse/tracecompass/incubator/scripting/core/tests/trace/TraceModuleTest.java
@@ -16,6 +16,7 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.util.Iterator;
 
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
@@ -31,8 +32,10 @@
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.tracecompass.incubator.internal.scripting.core.trace.Messages;
 import org.eclipse.tracecompass.incubator.scripting.core.tests.ActivatorTest;
+import org.eclipse.tracecompass.incubator.scripting.core.tests.stubs.ScriptingTestUtils;
 import org.eclipse.tracecompass.incubator.scripting.core.trace.TraceScriptingModule;
 import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
 import org.eclipse.tracecompass.tmf.core.io.ResourceUtil;
 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
 import org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStub;
@@ -254,4 +257,31 @@
         }
         assertTrue(!fileExist);
     }
+
+    /**
+     * Test the event iterator
+     */
+    @Test
+    public void testEventIterator() {
+        TraceScriptingModule traceScriptingModule = new TraceScriptingModule();
+
+        ITmfTrace trace = ScriptingTestUtils.getTrace();
+        try {
+
+            Iterator<ITmfEvent> eventIterator = traceScriptingModule.getEventIterator(trace);
+            assertNotNull(eventIterator);
+
+            int count = 0;
+            while (eventIterator.hasNext()) {
+                eventIterator.next();
+                count++;
+            }
+            // Make sure it parsed the whole trace
+            assertEquals(36, count);
+
+        } finally {
+            trace.dispose();
+        }
+    }
+
 }
diff --git a/analyses/org.eclipse.tracecompass.incubator.scripting.core/src/org/eclipse/tracecompass/incubator/internal/scripting/core/trace/ScriptEventRequest.java b/analyses/org.eclipse.tracecompass.incubator.scripting.core/src/org/eclipse/tracecompass/incubator/internal/scripting/core/trace/ScriptEventRequest.java
new file mode 100644
index 0000000..aa7d421
--- /dev/null
+++ b/analyses/org.eclipse.tracecompass.incubator.scripting.core/src/org/eclipse/tracecompass/incubator/internal/scripting/core/trace/ScriptEventRequest.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2019 École Polytechnique de Montréal
+ *
+ * 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.incubator.internal.scripting.core.trace;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.collect.BufferedBlockingQueue;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.TmfEvent;
+import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
+import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+/**
+ * An event request for scripted analysis. This class has a {link
+ * #getEventIterator()} method which returns the iterator to go through the
+ * events. Callers need to explicitly send the request to a trace or experiment,
+ * using {@link ITmfTrace#sendRequest(ITmfEventRequest)}.
+ *
+ * @author Geneviève Bastien
+ */
+public class ScriptEventRequest extends TmfEventRequest {
+
+    private static final int DEFAULT_EVENTS_QUEUE_SIZE = 127;
+    private static final int DEFAULT_EVENTS_CHUNK_SIZE = 127;
+
+    /**
+     * Fake event indicating the build is over, and the provider should close
+     */
+    private static class EndEvent extends TmfEvent {
+        public EndEvent() {
+            super(null, ITmfContext.UNKNOWN_RANK, null, null, null);
+        }
+    }
+
+    private static final EndEvent END_EVENT = new EndEvent();
+
+    private final BufferedBlockingQueue<ITmfEvent> fEventsQueue;
+    private final EventIterator fEventIterator;
+
+    /**
+     * Constructor
+     */
+    public ScriptEventRequest() {
+        super(ITmfEvent.class, TmfTimeRange.ETERNITY, 0, ITmfEventRequest.ALL_DATA, ExecutionType.BACKGROUND, 100);
+        fEventsQueue = new BufferedBlockingQueue<>(DEFAULT_EVENTS_QUEUE_SIZE, DEFAULT_EVENTS_CHUNK_SIZE);
+        fEventIterator = new EventIterator(fEventsQueue);
+    }
+
+    @Override
+    public void handleData(@NonNull ITmfEvent event) {
+        super.handleData(event);
+        fEventsQueue.put(event);
+    }
+
+    @Override
+    public synchronized void done() {
+        super.done();
+        fEventsQueue.put(END_EVENT);
+        fEventsQueue.flushInputBuffer();
+    }
+
+    @Override
+    public synchronized void cancel() {
+        super.cancel();
+        fEventsQueue.put(END_EVENT);
+        fEventsQueue.flushInputBuffer();
+    }
+
+    /**
+     * Get the event iterator that will contain the events being read.
+     *
+     * @return The event iterator
+     */
+    public Iterator<ITmfEvent> getEventIterator() {
+        return fEventIterator;
+    }
+
+    private static class EventIterator implements Iterator<ITmfEvent> {
+
+        private final BufferedBlockingQueue<ITmfEvent> fEventsQueue;
+        private @Nullable ITmfEvent fNext;
+
+        public EventIterator(BufferedBlockingQueue<ITmfEvent> eventsQueue) {
+            fEventsQueue = eventsQueue;
+        }
+
+        @Override
+        public synchronized boolean hasNext() {
+            ITmfEvent next = fNext;
+            if (next == null) {
+                next = fEventsQueue.take();
+                fNext = next;
+            }
+            return next != END_EVENT;
+        }
+
+        @Override
+        public synchronized ITmfEvent next() {
+            if (hasNext()) {
+                ITmfEvent next = fNext;
+                fNext = null;
+                if (next != null) {
+                    return next;
+                }
+            }
+            throw new NoSuchElementException("No more elements in the queue"); //$NON-NLS-1$
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/analyses/org.eclipse.tracecompass.incubator.scripting.core/src/org/eclipse/tracecompass/incubator/scripting/core/analysis/ScriptedAnalysis.java b/analyses/org.eclipse.tracecompass.incubator.scripting.core/src/org/eclipse/tracecompass/incubator/scripting/core/analysis/ScriptedAnalysis.java
index 8460f24..1f1b07b 100644
--- a/analyses/org.eclipse.tracecompass.incubator.scripting.core/src/org/eclipse/tracecompass/incubator/scripting/core/analysis/ScriptedAnalysis.java
+++ b/analyses/org.eclipse.tracecompass.incubator.scripting.core/src/org/eclipse/tracecompass/incubator/scripting/core/analysis/ScriptedAnalysis.java
@@ -10,21 +10,14 @@
 package org.eclipse.tracecompass.incubator.scripting.core.analysis;
 
 import java.util.Iterator;
-import java.util.NoSuchElementException;
 
 import org.eclipse.ease.modules.ScriptParameter;
 import org.eclipse.ease.modules.WrapToScript;
-import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.tracecompass.common.core.collect.BufferedBlockingQueue;
 import org.eclipse.tracecompass.incubator.internal.scripting.core.analysis.TmfScriptAnalysis;
+import org.eclipse.tracecompass.incubator.internal.scripting.core.trace.ScriptEventRequest;
 import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
-import org.eclipse.tracecompass.tmf.core.event.TmfEvent;
-import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
-import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest;
-import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
-import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
 
@@ -37,20 +30,6 @@
  */
 public class ScriptedAnalysis {
 
-    private static final int DEFAULT_EVENTS_QUEUE_SIZE = 127;
-    private static final int DEFAULT_EVENTS_CHUNK_SIZE = 127;
-
-    /**
-     * Fake event indicating the build is over, and the provider should close
-     */
-    private static class EndEvent extends TmfEvent {
-        public EndEvent() {
-            super(null, ITmfContext.UNKNOWN_RANK, null, null, null);
-        }
-    }
-
-    private static final EndEvent END_EVENT = new EndEvent();
-
     private final ITmfTrace fTrace;
     private final String fName;
 
@@ -115,73 +94,9 @@
      */
     @WrapToScript
     public Iterator<ITmfEvent> getEventIterator() {
-        BufferedBlockingQueue<ITmfEvent> eventsQueue = new BufferedBlockingQueue<>(DEFAULT_EVENTS_QUEUE_SIZE, DEFAULT_EVENTS_CHUNK_SIZE);
-        fTrace.sendRequest(new ScriptEventRequest(eventsQueue));
-        return new EventIterator(eventsQueue);
-    }
-
-    private static class EventIterator implements Iterator<ITmfEvent> {
-
-        private final BufferedBlockingQueue<ITmfEvent> fEventsQueue;
-        private @Nullable ITmfEvent fNext;
-
-        public EventIterator(BufferedBlockingQueue<ITmfEvent> eventsQueue) {
-            fEventsQueue = eventsQueue;
-        }
-
-        @Override
-        public synchronized boolean hasNext() {
-            ITmfEvent next = fNext;
-            if (next == null) {
-                next = fEventsQueue.take();
-                fNext = next;
-            }
-            return next != END_EVENT;
-        }
-
-        @Override
-        public synchronized ITmfEvent next() {
-            if (hasNext()) {
-                ITmfEvent next = fNext;
-                fNext = null;
-                if (next != null) {
-                    return next;
-                }
-            }
-            throw new NoSuchElementException("No more elements in the queue"); //$NON-NLS-1$
-        }
-
-    }
-
-    private static class ScriptEventRequest extends TmfEventRequest {
-
-        private BufferedBlockingQueue<ITmfEvent> fEventsQueue;
-
-        public ScriptEventRequest(BufferedBlockingQueue<ITmfEvent> eventsQueue) {
-            super(ITmfEvent.class, TmfTimeRange.ETERNITY, 0, ITmfEventRequest.ALL_DATA, ExecutionType.BACKGROUND, 100);
-            fEventsQueue = eventsQueue;
-        }
-
-        @Override
-        public void handleData(@NonNull ITmfEvent event) {
-            super.handleData(event);
-            fEventsQueue.put(event);
-        }
-
-        @Override
-        public synchronized void done() {
-            super.done();
-            fEventsQueue.put(END_EVENT);
-            fEventsQueue.flushInputBuffer();
-        }
-
-        @Override
-        public synchronized void cancel() {
-            super.cancel();
-            fEventsQueue.put(END_EVENT);
-            fEventsQueue.flushInputBuffer();
-        }
-
+        ScriptEventRequest scriptEventRequest = new ScriptEventRequest();
+        fTrace.sendRequest(scriptEventRequest);
+        return scriptEventRequest.getEventIterator();
     }
 
     /**
diff --git a/analyses/org.eclipse.tracecompass.incubator.scripting.core/src/org/eclipse/tracecompass/incubator/scripting/core/trace/TraceScriptingModule.java b/analyses/org.eclipse.tracecompass.incubator.scripting.core/src/org/eclipse/tracecompass/incubator/scripting/core/trace/TraceScriptingModule.java
index 6903ded..b24b479 100644
--- a/analyses/org.eclipse.tracecompass.incubator.scripting.core/src/org/eclipse/tracecompass/incubator/scripting/core/trace/TraceScriptingModule.java
+++ b/analyses/org.eclipse.tracecompass.incubator.scripting.core/src/org/eclipse/tracecompass/incubator/scripting/core/trace/TraceScriptingModule.java
@@ -10,6 +10,7 @@
 package org.eclipse.tracecompass.incubator.scripting.core.trace;
 
 import java.io.FileNotFoundException;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 
@@ -22,6 +23,7 @@
 import org.eclipse.ease.modules.WrapToScript;
 import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.tracecompass.incubator.internal.scripting.core.trace.Messages;
+import org.eclipse.tracecompass.incubator.internal.scripting.core.trace.ScriptEventRequest;
 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
 import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
 import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceImportException;
@@ -139,4 +141,39 @@
     public @Nullable ITmfTrace getActiveTrace() {
         return TmfTraceManager.getInstance().getActiveTrace();
     }
+
+    /**
+     * Get an iterator to iterate chronologically through the events of the
+     * trace.
+     *
+     * Thus, to iterate through the events of a trace in a scripted analysis,
+     * one can just do the following snippet (javascript)
+     *
+     * <pre>
+     * var trace = getActiveTrace();
+     * var iter = getEventIterator(trace);
+     *
+     * var event = null;
+     * while (iter.hasNext()) {
+     *
+     *     event = iter.next();
+     *
+     *     // Do something with the event
+     * }
+     * </pre>
+     *
+     * @param trace
+     *            The trace for which to get the event iterator
+     *
+     * @return The event iterator, starting from the first event
+     */
+    @WrapToScript
+    public Iterator<ITmfEvent> getEventIterator(@Nullable ITmfTrace trace) {
+        if (trace == null) {
+            throw new NullPointerException("Trace should not be null"); //$NON-NLS-1$
+        }
+        ScriptEventRequest scriptEventRequest = new ScriptEventRequest();
+        trace.sendRequest(scriptEventRequest);
+        return scriptEventRequest.getEventIterator();
+    }
 }