Merge branch 'master' of https://github.com/OPENNETWORKINGLAB/ONOS
diff --git a/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java b/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java
new file mode 100644
index 0000000..9d921f5
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java
@@ -0,0 +1,150 @@
+package net.floodlightcontroller.routing;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import net.floodlightcontroller.core.internal.SwitchStorageImpl;
+import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
+import net.floodlightcontroller.topology.NodePortTuple;
+
+import org.openflow.util.HexString;
+
+import com.thinkaurelius.titan.core.TitanFactory;
+import com.thinkaurelius.titan.core.TitanGraph;
+// import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.Vertex;
+// import com.tinkerpop.gremlin.groovy.Gremlin;
+// import com.tinkerpop.gremlin.java.GremlinPipeline;
+// import com.tinkerpop.pipes.Pipe;
+// import com.tinkerpop.pipes.PipeFunction;
+// import com.tinkerpop.pipes.branch.LoopPipe;
+// import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
+// import com.tinkerpop.pipes.filter.FilterPipe.Filter;
+// import com.tinkerpop.pipes.util.PipesFluentPipeline;
+
+import com.tinkerpop.blueprints.Element;
+
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+import com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
+
+public class TopoRouteService implements ITopoRouteService {
+
+	ThreadLocal<SwitchStorageImpl> store = new ThreadLocal<SwitchStorageImpl>() {
+	    @Override
+	    protected SwitchStorageImpl initialValue() {
+		SwitchStorageImpl swStore = new SwitchStorageImpl();
+		// NOTE: This is the file path from global properties
+		swStore.init("/tmp/cassandra.titan");
+		return swStore;
+	    }
+	};
+
+	SwitchStorageImpl swStore = store.get();
+
+	@Override
+	public List<NodePortTuple> GetShortestPath(NodePortTuple src,
+			NodePortTuple dest) {
+	    List<NodePortTuple> result_list = new ArrayList<NodePortTuple>();
+
+	    TitanGraph titanGraph = swStore.graph;
+
+	    String dpid_src = HexString.toHexString(src.getNodeId());
+	    String dpid_dest = HexString.toHexString(dest.getNodeId());
+
+	    //
+	    // Implement the Shortest Path between two vertices by using
+	    // the following Gremlin code:
+	    //   results = []; v_src.as('x').out.out.in.has("type", "switch").dedup().loop('x'){it.object.dpid != v_dest.dpid & it.loops < 10}.path().fill(results)
+	    //
+
+	    String gremlin = "v_src.as(\"x\").out.out.in.has(\"type\", \"switch\").dedup().loop(\"x\"){it.object.dpid != v_dest.dpid & it.loops < 10}.path().fill(results)";
+
+	    // Get the source vertex
+	    Iterator<Vertex> iter = titanGraph.getVertices("dpid", dpid_src).iterator();
+	    if (! iter.hasNext())
+		return null;		// Source vertex not found
+	    Vertex v_src = iter.next();
+
+	    // Get the destination vertex
+	    iter = titanGraph.getVertices("dpid", dpid_dest).iterator();
+	    if (! iter.hasNext())
+		return null;		// Destination vertex not found
+	    Vertex v_dest = iter.next();
+	
+	    //
+	    // Implement the Gremlin script and run it
+	    //
+	    ScriptEngine engine = new GremlinGroovyScriptEngine();
+
+	    ArrayList<ArrayList<Vertex>> results = new ArrayList<ArrayList<Vertex>>();
+	    engine.getBindings(ScriptContext.ENGINE_SCOPE).put("g", titanGraph);
+	    engine.getBindings(ScriptContext.ENGINE_SCOPE).put("v_src", v_src);
+	    engine.getBindings(ScriptContext.ENGINE_SCOPE).put("v_dest", v_dest);
+	    engine.getBindings(ScriptContext.ENGINE_SCOPE).put("results", results);
+
+	    try {
+		engine.eval(gremlin);
+	    } catch (ScriptException e) {
+		System.err.println("Caught ScriptException running Gremlin script: " + e.getMessage());
+		return null;
+	    }
+
+	    //
+	    // Loop through the result and return the list
+	    // of <dpid, port> tuples.
+	    //
+	    long nodeId = 0;
+	    short portId = 0;
+	    for (ArrayList<Vertex> lv : results) {
+		int idx = 0;
+		for (Vertex v: lv) {
+		    String type = v.getProperty("type").toString();
+		    System.out.println("type: " + type);
+		    if (type.equals("port")) {
+                        String number = v.getProperty("number").toString();
+                        System.out.println("number: " + number);
+
+			Object obj = v.getProperty("number");
+			// String class_str = obj.getClass().toString();
+			if (obj instanceof Short) {
+			    portId = (Short)obj;
+			} else if (obj instanceof Integer) {
+			    Integer int_nodeId = (Integer)obj;
+			    portId = int_nodeId.shortValue();
+			    // int int_nodeId = (Integer)obj;
+			    // portId = (short)int_nodeId.;
+			}
+		    } else if (type.equals("switch")) {
+			String dpid = v.getProperty("dpid").toString();
+			nodeId = HexString.toLong(dpid);
+
+                        System.out.println("dpid: " + dpid);
+		    }
+		    if (idx == 0) {
+			idx++;
+			continue;
+		    }
+		    int mod = (idx - 1) % 3;
+		    if ((mod == 0) || (mod == 2))  {
+			result_list.add(new NodePortTuple(nodeId, portId));
+		    }
+		    idx++;
+		}
+	    }
+	    if (result_list.size() > 0)
+		return result_list;
+
+	    return null;
+	}
+
+	@Override
+	public Boolean RouteExists(NodePortTuple src, NodePortTuple dest) {
+		List<NodePortTuple> route = GetShortestPath(src, dest);
+		if (route != null)
+		    return true;
+		return false;
+	}
+}
diff --git a/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java b/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java
index 70e406f..fe33f47 100644
--- a/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java
+++ b/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java
@@ -4,7 +4,9 @@
 
 import net.floodlightcontroller.routing.IRoutingService;
 import net.floodlightcontroller.routing.Route;
+import net.floodlightcontroller.routing.TopoRouteService;
 import net.floodlightcontroller.topology.NodePortTuple;
+import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
 
 import org.openflow.util.HexString;
 import org.restlet.resource.Get;
@@ -18,9 +20,16 @@
 
     @Get("json")
     public List<NodePortTuple> retrieve() {
+	/*
         IRoutingService routing = 
                 (IRoutingService)getContext().getAttributes().
                     get(IRoutingService.class.getCanonicalName());
+	*/
+	ITopoRouteService onos_routing = new TopoRouteService();
+	if (onos_routing == null) {
+	    log.debug("ONOS Route Service not found");
+	    return null;
+	}
         
         String srcDpid = (String) getRequestAttributes().get("src-dpid");
         String srcPort = (String) getRequestAttributes().get("src-port");
@@ -34,12 +43,19 @@
         long longDstDpid = HexString.toLong(dstDpid);
         short shortDstPort = Short.parseShort(dstPort);
         
+	/*
         Route result = routing.getRoute(longSrcDpid, shortSrcPort, longDstDpid, shortDstPort);
         
         if (result!=null) {
             return routing.getRoute(longSrcDpid, shortSrcPort, longDstDpid, shortDstPort).getPath();
         }
-        else {
+	*/
+	List<NodePortTuple> result =
+	    onos_routing.GetShortestPath(new NodePortTuple(longSrcDpid, shortSrcPort),
+					 new NodePortTuple(longDstDpid, shortDstPort));
+	if ((result != null) && (result.size() > 0)) {
+	    return result;
+	} else {
             log.debug("ERROR! no route found");
             return null;
         }
diff --git a/src/test/java/net/floodlightcontroller/core/internal/SwitchStorageImplTest.java b/src/test/java/net/floodlightcontroller/core/internal/SwitchStorageImplTest.java
index 8f272c5..177769b 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/SwitchStorageImplTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/SwitchStorageImplTest.java
@@ -5,7 +5,9 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 
 import net.floodlightcontroller.core.ISwitchStorage;
 import net.floodlightcontroller.core.ISwitchStorage.SwitchState;
@@ -17,8 +19,22 @@
 import org.openflow.protocol.OFPhysicalPort;
 
 import com.thinkaurelius.titan.core.TitanGraph;
+import com.tinkerpop.blueprints.Direction;
 import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.gremlin.groovy.Gremlin;
 import com.tinkerpop.gremlin.java.GremlinPipeline;
+import com.tinkerpop.pipes.Pipe;
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.branch.LoopPipe;
+import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
+import com.tinkerpop.pipes.filter.FilterPipe.Filter;
+import com.tinkerpop.pipes.util.PipesFluentPipeline;
+
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+import com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
+
 
 public class SwitchStorageImplTest {
 
@@ -143,4 +159,107 @@
 	public void testGetActiveSwitches() {
 		fail("Not yet implemented");
 	}
+
+	static class MyLoopFunction implements PipeFunction<LoopBundle<Vertex>, Boolean> {
+	    String dpid;
+	    public MyLoopFunction(String dpid) {
+		super();
+		this.dpid = dpid;
+	    }
+	    public Boolean compute(LoopBundle<Vertex> bundle) {
+		Boolean output = false;
+		if ((bundle.getObject().getProperty("dpid") != dpid) && 
+		    (bundle.getLoops() < 10)) {
+		    output = true;
+		}
+		return output;
+	    }
+	}
+
+	@Test
+	public void testShortestPath() {
+	    String dpid_src = "00:00:00:00:00:00:0a:01";
+	    String dpid_dest = "00:00:00:00:00:00:0a:06";
+
+	    //
+	    // Implement the Shortest Path between two vertices by using
+	    // the following Gremlin code:
+	    //   results = []; v_src.as('x').out.out.in.has("type", "switch").dedup().loop('x'){it.object.dpid != v_dest.dpid & it.loops < 10}.path().fill(results)
+	    //
+
+	    String gremlin = "v_src.as(\"x\").out.out.in.has(\"type\", \"switch\").dedup().loop(\"x\"){it.object.dpid != v_dest.dpid & it.loops < 10}.path().fill(results)";
+
+	    // Get the source vertex
+	    Iterator<Vertex> iter = titanGraph.getVertices("dpid", dpid_src).iterator();
+	    if (! iter.hasNext())
+		return;			// Source vertex not found
+	    Vertex v_src = iter.next();
+
+	    // Get the destination vertex
+	    iter = titanGraph.getVertices("dpid", dpid_dest).iterator();
+	    if (! iter.hasNext())
+		return;			// Destination vertex not found
+	    Vertex v_dest = iter.next();
+	
+	    //
+	    // Implement the Gremlin script and run it
+	    //
+	    ScriptEngine engine = new GremlinGroovyScriptEngine();
+
+	    ArrayList<ArrayList<Vertex>> results = new ArrayList<ArrayList<Vertex>>();
+	    engine.getBindings(ScriptContext.ENGINE_SCOPE).put("g", titanGraph);
+	    engine.getBindings(ScriptContext.ENGINE_SCOPE).put("v_src", v_src);
+	    engine.getBindings(ScriptContext.ENGINE_SCOPE).put("v_dest", v_dest);
+	    engine.getBindings(ScriptContext.ENGINE_SCOPE).put("results", results);
+
+	    try {
+		engine.eval(gremlin);
+	    } catch (ScriptException e) {
+		System.err.println("Caught ScriptException running Gremlin script: " + e.getMessage());
+		return;
+	    }
+
+	    //
+	    // Extract the result and compose it into a string
+	    //
+	    String results_str = "";
+	    // System.out.println("BEGIN " + results.size());
+	    for (ArrayList<Vertex> lv : results) {
+		// System.out.println(lv);
+		for (Vertex v: lv) {
+		    // System.out.println(v);
+		    String type = v.getProperty("type").toString();
+		    results_str += "[type: " + type;
+		    // System.out.println("type: " + type);
+		    if (type.equals("port")) {
+			String number = v.getProperty("number").toString();
+			// System.out.println("number: " + number);
+			results_str += " number: " + number + "]";
+		    }
+		    if (type.equals("switch")) {
+			String dpid = v.getProperty("dpid").toString();
+			// System.out.println("dpid: " + dpid);
+			results_str += " dpid: " + dpid + "]";
+		    }
+		}
+	    }
+	    // System.out.println("END\n");
+	    System.out.println(results_str);
+	    
+	    String expected_result = "[type: switch dpid: 00:00:00:00:00:00:0a:01][type: port number: 2][type: port number: 1][type: switch dpid: 00:00:00:00:00:00:0a:03][type: port number: 2][type: port number: 2][type: switch dpid: 00:00:00:00:00:00:0a:04][type: port number: 3][type: port number: 1][type: switch dpid: 00:00:00:00:00:00:0a:06]";
+
+
+	    // Pipe<Vertex, Vertex> pipe = Gremlin.compile(gremlin);
+	    // pipe.setStarts(new SingleIterator<Vertex>(v1));
+
+	    //
+	    // XXX: An alternative (faster?) solution that fails to compile
+	    //
+	    MyLoopFunction whileFunction = new MyLoopFunction(dpid_dest);
+	    GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
+	    // pipe.start(v_src).as("x").out().out().in().has("type", "switch").dedup().loop("x", whileFunction);
+
+	    // Check the result
+	    assertEquals(results_str, expected_result);
+	}
 }
diff --git a/web/shortest_path.py b/web/shortest_path.py
new file mode 100755
index 0000000..5bea182
--- /dev/null
+++ b/web/shortest_path.py
@@ -0,0 +1,71 @@
+#! /usr/bin/env python
+# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
+
+import pprint
+import os
+import sys
+import subprocess
+import json
+import argparse
+import io
+import time
+
+from flask import Flask, json, Response, render_template, make_response, request
+
+#
+# curl http://127.0.0.1:8080/wm/topology/route/00:00:00:00:00:00:0a:01/1/00:00:00:00:00:00:0a:04/1/json
+#
+
+## Global Var ##
+ControllerIP="127.0.0.1"
+ControllerPort=8080
+
+DEBUG=0
+pp = pprint.PrettyPrinter(indent=4)
+
+app = Flask(__name__)
+
+## Worker Functions ##
+def log_error(txt):
+  print '%s' % (txt)
+
+def debug(txt):
+  if DEBUG:
+    print '%s' % (txt)
+
+# @app.route("/wm/topology/route/<srcdpid>/<srcport>/<destdpid>/<destport>/json")
+def shortest_path(v1, p1, v2, p2):
+  try:
+    command = "curl -s http://%s:%s/wm/topology/route/%s/%s/%s/%s/json" % (ControllerIP, ControllerPort, v1, p1, v2, p2)
+    result = os.popen(command).read()
+    parsedResult = json.loads(result)
+  except:
+    log_error("Controller IF has issue")
+    exit(1)
+
+  debug("shortest_path %s" % command)
+  debug("parsed %s" % parsedResult)
+
+  for v in parsedResult:
+    dpid = v['switch'];
+    port = v['port'];
+    print "PathEntry: (%s, %s)" % (dpid, port)
+
+
+if __name__ == "__main__":
+  usage_msg = "Usage: %s <src-dpid> <src-port> <dest-dpid> <dest-port>" % (sys.argv[0])
+
+  # app.debug = False;
+
+  # Usage info
+  if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
+    print(usage_msg)
+    exit(0)
+
+  # Check arguments
+  if len(sys.argv) < 5:
+    log_error(usage_msg)
+    exit(1)
+
+  # Do the work
+  shortest_path(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]);