Added ability for commands to post properties to be used as params of other commands.

Starting to add monitor GUI.

Change-Id: I9fcf1568d0de27dfd1c19e875f8646fd731a1dfa
diff --git a/utils/stc/src/main/java/org/onlab/stc/Monitor.java b/utils/stc/src/main/java/org/onlab/stc/Monitor.java
new file mode 100644
index 0000000..4e6f63f
--- /dev/null
+++ b/utils/stc/src/main/java/org/onlab/stc/Monitor.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onlab.stc;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Maps;
+import org.onlab.stc.MonitorLayout.Box;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Map;
+
+import static org.onlab.stc.Coordinator.Status.IN_PROGRESS;
+
+/**
+ * Scenario test monitor.
+ */
+public class Monitor implements StepProcessListener {
+
+    private final ObjectMapper mapper = new ObjectMapper();
+
+    private final Coordinator coordinator;
+    private final Compiler compiler;
+    private final MonitorLayout layout;
+
+    private MonitorDelegate delegate;
+
+    private Map<Step, Box> boxes = Maps.newHashMap();
+
+    /**
+     * Creates a new shared process flow monitor.
+     *
+     * @param coordinator process flow coordinator
+     * @param compiler    scenario compiler
+     */
+    Monitor(Coordinator coordinator, Compiler compiler) {
+        this.coordinator = coordinator;
+        this.compiler = compiler;
+        this.layout = new MonitorLayout(compiler);
+        coordinator.addListener(this);
+    }
+
+    /**
+     * Sets the process monitor delegate.
+     *
+     * @param delegate process monitor delegate
+     */
+    void setDelegate(MonitorDelegate delegate) {
+        this.delegate = delegate;
+    }
+
+    /**
+     * Notifies the process monitor delegate with the specified event.
+     *
+     * @param event JSON event data
+     */
+    public void notify(ObjectNode event) {
+        if (delegate != null) {
+            delegate.notify(event);
+        }
+    }
+
+    /**
+     * Returns the scenario process flow as JSON data.
+     *
+     * @return scenario process flow data
+     */
+    ObjectNode scenarioData() {
+        ObjectNode root = mapper.createObjectNode();
+        ArrayNode steps = mapper.createArrayNode();
+        ArrayNode requirements = mapper.createArrayNode();
+
+        ProcessFlow pf = compiler.processFlow();
+        pf.getVertexes().forEach(step -> add(step, steps));
+        pf.getEdges().forEach(requirement -> add(requirement, requirements));
+
+        root.set("steps", steps);
+        root.set("requirements", requirements);
+
+        try (FileWriter fw = new FileWriter("/tmp/data.json");
+             PrintWriter pw = new PrintWriter(fw)) {
+            pw.println(root.toString());
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return root;
+    }
+
+
+    private void add(Step step, ArrayNode steps) {
+        Box box = layout.get(step);
+        ObjectNode sn = mapper.createObjectNode()
+                .put("name", step.name())
+                .put("isGroup", step instanceof Group)
+                .put("status", status(coordinator.getStatus(step)))
+                .put("tier", box.tier())
+                .put("depth", box.depth());
+        if (step.group() != null) {
+            sn.put("group", step.group().name());
+        }
+        steps.add(sn);
+    }
+
+    private String status(Coordinator.Status status) {
+        return status.toString().toLowerCase();
+    }
+
+    private void add(Dependency requirement, ArrayNode requirements) {
+        ObjectNode rn = mapper.createObjectNode();
+        rn.put("src", requirement.src().name())
+                .put("dst", requirement.dst().name())
+                .put("isSoft", requirement.isSoft());
+        requirements.add(rn);
+    }
+
+    @Override
+    public void onStart(Step step, String command) {
+        notify(event(step, status(IN_PROGRESS)));
+    }
+
+    @Override
+    public void onCompletion(Step step, Coordinator.Status status) {
+        notify(event(step, status(status)));
+    }
+
+    @Override
+    public void onOutput(Step step, String line) {
+
+    }
+
+    private ObjectNode event(Step step, String status) {
+        ObjectNode event = mapper.createObjectNode()
+                .put("name", step.name())
+                .put("status", status);
+        return event;
+    }
+
+}