Merge pull request #331 from pgreyson/master

Minor improvements
diff --git a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
index 587b3c2..19addad 100644
--- a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
@@ -1,7 +1,10 @@
 package net.floodlightcontroller.core;
 
+import net.floodlightcontroller.flowcache.web.DatapathSummarySerializer;
+
 import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
 
 import com.tinkerpop.blueprints.Direction;
 import com.tinkerpop.frames.Adjacency;
@@ -155,48 +158,57 @@
 	}
 
 public interface IFlowPath extends IBaseObject {
+		@JsonProperty("flowId")
 		@Property("flow_id")
 		public String getFlowId();
 
 		@Property("flow_id")
 		public void setFlowId(String flowId);
 
+		@JsonProperty("installerId")
 		@Property("installer_id")
 		public String getInstallerId();
 
 		@Property("installer_id")
 		public void setInstallerId(String installerId);
 
+		@JsonProperty("srcDpid")
 		@Property("src_switch")
 		public String getSrcSwitch();
 
 		@Property("src_switch")
 		public void setSrcSwitch(String srcSwitch);
 
+		@JsonProperty("srcPort")
 		@Property("src_port")
 		public Short getSrcPort();
 
 		@Property("src_port")
 		public void setSrcPort(Short srcPort);
 
+		@JsonProperty("dstDpid")
 		@Property("dst_switch")
 		public String getDstSwitch();
 
 		@Property("dst_switch")
 		public void setDstSwitch(String dstSwitch);
 
+		@JsonProperty("dstPort")
 		@Property("dst_port")
 		public Short getDstPort();
 
 		@Property("dst_port")
 		public void setDstPort(Short dstPort);
 
+		@JsonProperty("dataPath")
+		@JsonSerialize(using=DatapathSummarySerializer.class)
 		@Property("data_path_summary")
 		public String getDataPathSummary();
 
 		@Property("data_path_summary")
 		public void setDataPathSummary(String dataPathSummary);
 
+		@JsonIgnore
 		@Adjacency(label="flow", direction=Direction.IN)
 		public Iterable<IFlowEntry> getFlowEntries();
 
@@ -206,30 +218,35 @@
 		@Adjacency(label="flow", direction=Direction.IN)
 		public void removeFlowEntry(final IFlowEntry flowEntry);
 
+		@JsonIgnore
 		@Property("matchEthernetFrameType")
 		public Short getMatchEthernetFrameType();
 
 		@Property("matchEthernetFrameType")
 		public void setMatchEthernetFrameType(Short matchEthernetFrameType);
 
+		@JsonIgnore
 		@Property("matchSrcMac")
 		public String getMatchSrcMac();
 
 		@Property("matchSrcMac")
 		public void setMatchSrcMac(String matchSrcMac);
 
+		@JsonIgnore
 		@Property("matchDstMac")
 		public String getMatchDstMac();
 
 		@Property("matchDstMac")
 		public void setMatchDstMac(String matchDstMac);
 
+		@JsonIgnore
 		@Property("matchSrcIPv4Net")
 		public String getMatchSrcIPv4Net();
 
 		@Property("matchSrcIPv4Net")
 		public void setMatchSrcIPv4Net(String matchSrcIPv4Net);
 
+		@JsonIgnore
 		@Property("matchDstIPv4Net")
 		public String getMatchDstIPv4Net();
 
@@ -239,6 +256,10 @@
 		@JsonIgnore
 		@GremlinGroovy("_().in('flow').out('switch')")
 		public Iterable<IDeviceObject> getSwitches();
+		
+		@JsonIgnore
+		@Property("state")
+		public String getState();
 	}
 
 public interface IFlowEntry extends IBaseObject {
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index f9177f2..2b9bf68 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -3,7 +3,6 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -12,12 +11,9 @@
 import java.util.Map;
 import java.util.Random;
 import java.util.TreeMap;
-import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
@@ -32,13 +28,12 @@
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
-import net.floodlightcontroller.flowcache.IFlowService;
 import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.util.CallerId;
 import net.floodlightcontroller.util.DataPath;
-import net.floodlightcontroller.util.Dpid;
 import net.floodlightcontroller.util.DataPathEndpoints;
+import net.floodlightcontroller.util.Dpid;
 import net.floodlightcontroller.util.FlowEntry;
 import net.floodlightcontroller.util.FlowEntryAction;
 import net.floodlightcontroller.util.FlowEntryId;
@@ -52,7 +47,6 @@
 import net.floodlightcontroller.util.OFMessageDamper;
 import net.floodlightcontroller.util.Port;
 import net.floodlightcontroller.util.SwitchPort;
-import net.onrc.onos.flow.IFlowManager;
 import net.onrc.onos.util.GraphDBConnection;
 import net.onrc.onos.util.GraphDBConnection.Transaction;
 
@@ -63,11 +57,10 @@
 import org.openflow.protocol.OFType;
 import org.openflow.protocol.action.OFAction;
 import org.openflow.protocol.action.OFActionOutput;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class FlowManager implements IFloodlightModule, IFlowService, IFlowManager, INetMapStorage {
+public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
 
     public GraphDBConnection conn;
 
@@ -102,167 +95,9 @@
     private static Logger log = LoggerFactory.getLogger(FlowManager.class);
 
     // The periodic task(s)
-    private final ScheduledExecutorService measureShortestPathScheduler =
-	Executors.newScheduledThreadPool(1);
-    private final ScheduledExecutorService measureMapReaderScheduler =
-	Executors.newScheduledThreadPool(1);
     private final ScheduledExecutorService mapReaderScheduler =
 	Executors.newScheduledThreadPool(1);
 
-    private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
-    private ThreadPoolExecutor shortestPathExecutor =
-	new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
-
-    class ShortestPathTask implements Runnable {
-	private int hint;
-	private ITopoRouteService topoRouteService;
-	private ArrayList<DataPath> dpList;
-
-	public ShortestPathTask(int hint,
-				ITopoRouteService topoRouteService,
-				ArrayList<DataPath> dpList) {
-	    this.hint = hint;
-	    this.topoRouteService = topoRouteService;
-	    this.dpList = dpList;
-	}
-
-	@Override
-	public void run() {
-	    /*
-	    String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
-	    log.debug(logMsg);
-	    long startTime = System.nanoTime();
-	    */
-	    for (DataPath dp : this.dpList) {
-		topoRouteService.getTopoShortestPath(dp.srcPort(), dp.dstPort());
-	    }
-	    /*
-	    long estimatedTime = System.nanoTime() - startTime;
-	    double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
-	    logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
-	    log.debug(logMsg);
-	    */
-	}
-    }
-
-    final Runnable measureShortestPath = new Runnable() {
-	    public void run() {
-		log.debug("Recomputing Shortest Paths from the Network Map Flows...");
-		if (floodlightProvider == null) {
-		    log.debug("FloodlightProvider service not found!");
-		    return;
-		}
-
-		if (topoRouteService == null) {
-		    log.debug("Topology Route Service not found");
-		    return;
-		}
-
-		int leftoverQueueSize = shortestPathExecutor.getQueue().size();
-		if (leftoverQueueSize > 0) {
-		    String logMsg = "MEASUREMENT: Leftover Shortest Path Queue Size: " + leftoverQueueSize;
-		    log.debug(logMsg);
-		    return;
-		}
-		log.debug("MEASUREMENT: Beginning Shortest Path Computation");
-
-		//
-		// Recompute the Shortest Paths for all Flows
-		//
-		int counter = 0;
-		int hint = 0;
-		ArrayList<DataPath> dpList = new ArrayList<DataPath>();
-		long startTime = System.nanoTime();
-
-		topoRouteService.prepareShortestPathTopo();
-
-		Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
-		for (IFlowPath flowPathObj : allFlowPaths) {
-		    FlowId flowId = new FlowId(flowPathObj.getFlowId());
-
-		    // log.debug("Found Path {}", flowId.toString());
-		    Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
-		    Port srcPort = new Port(flowPathObj.getSrcPort());
-		    Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
-		    Port dstPort = new Port(flowPathObj.getDstPort());
-		    SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
-		    SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
-
-		    /*
-		    DataPath dp = new DataPath();
-		    dp.setSrcPort(srcSwitchPort);
-		    dp.setDstPort(dstSwitchPort);
-		    dpList.add(dp);
-		    if ((dpList.size() % 10) == 0) {
-			shortestPathExecutor.execute(
-				new ShortestPathTask(hint, topoRouteService,
-						     dpList));
-			dpList = new ArrayList<DataPath>();
-			hint++;
-		    }
-		    */
-
-		    DataPath dataPath =
-			topoRouteService.getTopoShortestPath(srcSwitchPort,
-							     dstSwitchPort);
-		    counter++;
-		}
-		if (dpList.size() > 0) {
-		    shortestPathExecutor.execute(
-			new ShortestPathTask(hint, topoRouteService,
-					     dpList));
-		}
-
-		/*
-		// Wait for all tasks to finish
-		try {
-		    while (shortestPathExecutor.getQueue().size() > 0) {
-			Thread.sleep(100);
-		    }
-		} catch (InterruptedException ex) {
-		    log.debug("MEASUREMENT: Shortest Path Computation interrupted");
-		}
-		*/
-
-		conn.endTx(Transaction.COMMIT);
-		topoRouteService.dropShortestPathTopo();
-
-		long estimatedTime = System.nanoTime() - startTime;
-		double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
-		String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
-		log.debug(logMsg);
-	    }
-	};
-
-    final Runnable measureMapReader = new Runnable() {
-	    public void run() {
-		if (floodlightProvider == null) {
-		    log.debug("FloodlightProvider service not found!");
-		    return;
-		}
-
-		//
-		// Fetch all Flow Entries
-		//
-		int counter = 0;
-		long startTime = System.nanoTime();
-		Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
-		for (IFlowEntry flowEntryObj : allFlowEntries) {
-		    counter++;
-		    FlowEntryId flowEntryId =
-			new FlowEntryId(flowEntryObj.getFlowEntryId());
-		    String userState = flowEntryObj.getUserState();
-		    String switchState = flowEntryObj.getSwitchState();
-		}
-		conn.endTx(Transaction.COMMIT);
-
-		long estimatedTime = System.nanoTime() - startTime;
-		double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
-		String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
-		log.debug(logMsg);
-	    }
-	};
-
     final Runnable mapReader = new Runnable() {
 	    public void run() {
 		long startTime = System.nanoTime();
@@ -305,14 +140,6 @@
 		    FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
 		    Dpid dpid = new Dpid(dpidStr);
 
-		    /*
-		    log.debug("Found Flow Entry Id = {} {}",
-			      flowEntryId.toString(),
-			      "DPID = " + dpid.toString() +
-			      " User State: " + userState +
-			      " Switch State: " + switchState);
-		    */
-
 		    if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
 			continue;	// Ignore the entry: nothing to do
 
@@ -321,10 +148,17 @@
 			continue;	// Ignore the entry: not my switch
 
 		    myFlowEntries.put(flowEntryId.value(), flowEntryObj);
+		    if (userState.equals("FE_USER_DELETE")) {
+			// An entry that needs to be deleted.
+			deleteFlowEntries.add(flowEntryObj);
+		    }
 		}
 
+		log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
+			  myFlowEntries.size());
+
 		//
-		// Process my Flow Entries
+		// Process my Flow Entries in the Flow Entry ID order
 		//
 		boolean processed_measurement_flow = false;
 		for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
@@ -337,156 +171,28 @@
 			continue;		// Should NOT happen
 
 		    // Code for measurement purpose
+		    // TODO: Commented-out for now
+		    /*
 		    {
 			if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
 			    processed_measurement_flow = true;
 			}
 		    }
+		    */
 
-		    //
-		    // TODO: Eliminate the re-fetching of flowEntryId,
-		    // userState, switchState, and dpid from the flowEntryObj.
-		    //
-		    FlowEntryId flowEntryId =
-			new FlowEntryId(flowEntryObj.getFlowEntryId());
 		    Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
-		    String userState = flowEntryObj.getUserState();
-		    String switchState = flowEntryObj.getSwitchState();
 		    IOFSwitch mySwitch = mySwitches.get(dpid.value());
 		    if (mySwitch == null)
 			continue;		// Shouldn't happen
-
-		    //
-		    // Create the Open Flow Flow Modification Entry to push
-		    //
-		    OFFlowMod fm =
-			(OFFlowMod) floodlightProvider.getOFMessageFactory()
-			.getMessage(OFType.FLOW_MOD);
-		    long cookie = flowEntryId.value();
-
-		    short flowModCommand = OFFlowMod.OFPFC_ADD;
-		    if (userState.equals("FE_USER_ADD")) {
-			flowModCommand = OFFlowMod.OFPFC_ADD;
-		    } else if (userState.equals("FE_USER_MODIFY")) {
-			flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
-		    } else if (userState.equals("FE_USER_DELETE")) {
-			flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
-		    } else {
-			// Unknown user state. Ignore the entry
-			log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
-				  flowEntryId.toString(), userState);
-			continue;
-		    }
-
-		    //
-		    // Fetch the match conditions.
-		    //
-		    // NOTE: The Flow matching conditions common for all
-		    // Flow Entries are used ONLY if a Flow Entry does NOT
-		    // have the corresponding matching condition set.
-		    //
-		    OFMatch match = new OFMatch();
-		    match.setWildcards(OFMatch.OFPFW_ALL);
-		    //
-		    Short matchInPort = flowEntryObj.getMatchInPort();
-		    if (matchInPort != null) {
-			match.setInputPort(matchInPort);
-			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
-		    }
-		    //
-		    Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
-		    if (matchEthernetFrameType == null)
-			matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
-		    if (matchEthernetFrameType != null) {
-			match.setDataLayerType(matchEthernetFrameType);
-			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
-		    }
-		    //
-		    String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
-		    if (matchSrcIPv4Net == null)
-			matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
-		    if (matchSrcIPv4Net != null) {
-			match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
-		    }
-		    //
-		    String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
-		    if (matchDstIPv4Net == null)
-			matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
-		    if (matchDstIPv4Net != null) {
-			match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
-		    }
-		    //
-		    String matchSrcMac = flowEntryObj.getMatchSrcMac();
-		    if (matchSrcMac == null)
-			matchSrcMac = flowObj.getMatchSrcMac();
-		    if (matchSrcMac != null) {
-			match.setDataLayerSource(matchSrcMac);
-			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
-		    }
-		    //
-		    String matchDstMac = flowEntryObj.getMatchDstMac();
-		    if (matchDstMac == null)
-			matchDstMac = flowObj.getMatchDstMac();
-		    if (matchDstMac != null) {
-			match.setDataLayerDestination(matchDstMac);
-			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
-		    }
-
-		    //
-		    // Fetch the actions
-		    //
-		    List<OFAction> actions = new ArrayList<OFAction>();
-		    Short actionOutputPort = flowEntryObj.getActionOutput();
-		    if (actionOutputPort != null) {
-			OFActionOutput action = new OFActionOutput();
-			// XXX: The max length is hard-coded for now
-			action.setMaxLength((short)0xffff);
-			action.setPort(actionOutputPort);
-			actions.add(action);
-		    }
-
-		    fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
-			.setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
-			.setPriority(PRIORITY_DEFAULT)
-			.setBufferId(OFPacketOut.BUFFER_ID_NONE)
-			.setCookie(cookie)
-			.setCommand(flowModCommand)
-			.setMatch(match)
-			.setActions(actions)
-			.setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
-		    fm.setOutPort(OFPort.OFPP_NONE.getValue());
-		    if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
-			(flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
-			if (actionOutputPort != null)
-			    fm.setOutPort(actionOutputPort);
-		    }
-
-		    //
-		    // TODO: Set the following flag
-		    // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
-		    // See method ForwardingBase::pushRoute()
-		    //
-		    try {
-			messageDamper.write(mySwitch, fm, null);
-			mySwitch.flush();
-			//
-			// TODO: We should use the OpenFlow Barrier mechanism
-			// to check for errors, and update the SwitchState
-			// for a flow entry after the Barrier message is
-			// is received.
-			//
-			flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
-			if (userState.equals("FE_USER_DELETE")) {
-			    // An entry that needs to be deleted.
-			    deleteFlowEntries.add(flowEntryObj);
-			}
-		    } catch (IOException e) {
-			log.error("Failure writing flow mod from network map", e);
-		    }
+		    installFlowEntry(mySwitch, flowObj, flowEntryObj);
 		}
 
+		log.debug("MEASUREMENT: Found {} Flow Entries to delete",
+			  deleteFlowEntries.size());
+
 		//
-		// Delete all entries marked for deletion
+		// Delete all entries marked for deletion from the
+		// Network MAP.
 		//
 		// TODO: We should use the OpenFlow Barrier mechanism
 		// to check for errors, and delete the Flow Entries after the
@@ -502,19 +208,6 @@
 		    }
 		    flowObj.removeFlowEntry(flowEntryObj);
 		    conn.utils().removeFlowEntry(conn, flowEntryObj);
-
-		    // Test whether the last flow entry
-		    Iterable<IFlowEntry> tmpflowEntries =
-			flowObj.getFlowEntries();
-		    boolean found = false;
-		    for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
-			found = true;
-			break;
-		    }
-		    if (! found) {
-			// Remove the Flow Path as well
-			conn.utils().removeFlowPath(conn, flowObj);
-		    }
 		}
 
 
@@ -522,11 +215,6 @@
 		// Fetch and recompute the Shortest Path for those
 		// Flow Paths this controller is responsible for.
 		//
-
-		/*
-		 * TODO: For now, the computation of the reconciliation is
-		 * commented-out.
-		 */
 		topoRouteService.prepareShortestPathTopo();
 		Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
 		HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
@@ -604,6 +292,8 @@
 			      flowId.toString());
 		    flowObjSet.add(flowPathObj);
 		}
+		log.debug("MEASUREMENT: Found {} Flows to reconcile",
+			  flowObjSet.size());
 		reconcileFlows(flowObjSet);
 		topoRouteService.dropShortestPathTopo();
 
@@ -611,29 +301,28 @@
 		conn.endTx(Transaction.COMMIT);
 
 		if (processed_measurement_flow) {
-		    long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
+		    long estimatedTime =
+			System.nanoTime() - modifiedMeasurementFlowTime;
 		    String logMsg = "MEASUREMENT: Pushed Flow delay: " +
 			(double)estimatedTime / 1000000000 + " sec";
 		    log.debug(logMsg);
 		}
 
 		long estimatedTime = System.nanoTime() - startTime;
-		double rate = (estimatedTime > 0)? ((double)counterAllFlowPaths * 1000000000) / estimatedTime: 0.0;
-		String logMsg = "MEASUREMENT: Processed AllFlowEntries: " + counterAllFlowEntries + " MyNotUpdatedFlowEntries: " + counterMyNotUpdatedFlowEntries + " AllFlowPaths: " + counterAllFlowPaths + " MyFlowPaths: " + counterMyFlowPaths + " in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " paths/s";
+		double rate = 0.0;
+		if (estimatedTime > 0)
+		    rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
+		String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
+		    counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
+		    counterMyNotUpdatedFlowEntries + " AllFlowPaths: " +
+		    counterAllFlowPaths + " MyFlowPaths: " +
+		    counterMyFlowPaths + " in " +
+		    (double)estimatedTime / 1000000000 + " sec: " +
+		    rate + " paths/s";
 		log.debug(logMsg);
 	    }
 	};
 
-    /*
-    final ScheduledFuture<?> measureShortestPathHandle =
-	measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
-    */
-
-    /*
-    final ScheduledFuture<?> measureMapReaderHandle =
-	measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
-    */
-
     final ScheduledFuture<?> mapReaderHandle =
 	mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
 
@@ -737,19 +426,12 @@
     @Override
     public boolean addFlow(FlowPath flowPath, FlowId flowId,
 			   String dataPathSummaryStr) {
+	/*
+	 * TODO: Commented-out for now
 	if (flowPath.flowId().value() == measurementFlowId) {
 	    modifiedMeasurementFlowTime = System.nanoTime();
 	}
-
-	//
-	// Assign the FlowEntry IDs
-	// Right now every new flow entry gets a new flow entry ID
-	// TODO: This needs to be redesigned!
-	//
-	for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
-	    long id = getNextFlowEntryId();
-	    flowEntry.setFlowEntryId(new FlowEntryId(id));
-	}
+	*/
 
 	IFlowPath flowObj = null;
 	try {
@@ -829,112 +511,10 @@
 	// flowPath.dataPath().flowEntries()
 	//
 	for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
-	    IFlowEntry flowEntryObj = null;
-	    boolean found = false;
-	    try {
-		if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
-		    log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
-			      flowEntry.flowEntryId().toString());
-		    found = true;
-		} else {
-		    flowEntryObj = conn.utils().newFlowEntry(conn);
-		    log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
-			      flowEntry.flowEntryId().toString());
-		}
-	    } catch (Exception e) {
-		// TODO: handle exceptions
-		conn.endTx(Transaction.ROLLBACK);
-		log.error(":addFlow FlowEntryId:{} failed",
-			  flowEntry.flowEntryId().toString());
-	    }
-	    if (flowEntryObj == null) {
-		log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
-		      flowEntry.flowEntryId().toString());
+	    if (addFlowEntry(flowObj, flowEntry) != true) {
 		conn.endTx(Transaction.ROLLBACK);
 		return false;
 	    }
-
-	    //
-	    // Set the Flow Entry key:
-	    // - flowEntry.flowEntryId()
-	    //
-	    flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
-	    flowEntryObj.setType("flow_entry");
-
-	    // 
-	    // Set the Flow Entry Edges and attributes:
-	    // - Switch edge
-	    // - InPort edge
-	    // - OutPort edge
-	    //
-	    // - flowEntry.flowEntryMatch()
-	    // - flowEntry.flowEntryActions()
-	    // - flowEntry.dpid()
-	    // - flowEntry.flowEntryUserState()
-	    // - flowEntry.flowEntrySwitchState()
-	    // - flowEntry.flowEntryErrorState()
-	    // - flowEntry.matchInPort()
-	    // - flowEntry.matchEthernetFrameType()
-	    // - flowEntry.matchSrcIPv4Net()
-	    // - flowEntry.matchDstIPv4Net()
-	    // - flowEntry.matchSrcMac()
-	    // - flowEntry.matchDstMac()
-	    // - flowEntry.actionOutput()
-	    //
-	    ISwitchObject sw =
-		conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
-	    flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
-	    flowEntryObj.setSwitch(sw);
-	    if (flowEntry.flowEntryMatch().matchInPort()) {
-	    	IPortObject inport =
-		    conn.utils().searchPort(conn, flowEntry.dpid().toString(),
-					    flowEntry.flowEntryMatch().inPort().value());
-	    	flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
-	    	flowEntryObj.setInPort(inport);
-	    }
-	    if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
-	    	flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
-	    }
-	    if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
-	    	flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
-	    }
-	    if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
-	    	flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
-	    }
-	    if (flowEntry.flowEntryMatch().matchSrcMac()) {
-	    	flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
-	    }
-	    if (flowEntry.flowEntryMatch().matchDstMac()) {
-	    	flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
-	    }
-
-	    for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
-	    	if (fa.actionOutput() != null) {
-		    IPortObject outport =
-			conn.utils().searchPort(conn,
-						flowEntry.dpid().toString(),
-						fa.actionOutput().port().value());
-		    flowEntryObj.setActionOutput(fa.actionOutput().port().value());
-		    flowEntryObj.setOutPort(outport);
-	    	}
-	    }
-	    // TODO: Hacks with hard-coded state names!
-	    if (found)
-		flowEntryObj.setUserState("FE_USER_MODIFY");
-	    else
-		flowEntryObj.setUserState("FE_USER_ADD");
-	    flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
-	    //
-	    // TODO: Take care of the FlowEntryErrorState.
-	    //
-
-	    // Flow Entries edges:
-	    //   Flow
-	    //   NextFE (TODO)
-	    if (! found) {
-		flowObj.addFlowEntry(flowEntryObj);
-		flowEntryObj.setFlow(flowObj);
-	    }
 	}
 	conn.endTx(Transaction.COMMIT);
 
@@ -947,6 +527,135 @@
     }
 
     /**
+     * Add a flow entry to the Network MAP.
+     *
+     * @param flowObj the corresponding Flow Path object for the Flow Entry.
+     * @param flowEntry the Flow Entry to install.
+     * @return true on success, otherwise false.
+     */
+    private boolean addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
+	// Flow edges
+	//   HeadFE (TODO)
+
+	//
+	// Assign the FlowEntry ID.
+	//
+	if ((flowEntry.flowEntryId() == null) ||
+	    (flowEntry.flowEntryId().value() == 0)) {
+	    long id = getNextFlowEntryId();
+	    flowEntry.setFlowEntryId(new FlowEntryId(id));
+	}
+
+	IFlowEntry flowEntryObj = null;
+	boolean found = false;
+	try {
+	    if ((flowEntryObj =
+		 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
+		log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
+			  flowEntry.flowEntryId().toString());
+		found = true;
+	    } else {
+		flowEntryObj = conn.utils().newFlowEntry(conn);
+		log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
+			  flowEntry.flowEntryId().toString());
+	    }
+	} catch (Exception e) {
+	    log.error(":addFlow FlowEntryId:{} failed",
+		      flowEntry.flowEntryId().toString());
+	    return false;
+	}
+	if (flowEntryObj == null) {
+	    log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
+		      flowEntry.flowEntryId().toString());
+	    return false;
+	}
+
+	//
+	// Set the Flow Entry key:
+	// - flowEntry.flowEntryId()
+	//
+	flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
+	flowEntryObj.setType("flow_entry");
+
+	// 
+	// Set the Flow Entry Edges and attributes:
+	// - Switch edge
+	// - InPort edge
+	// - OutPort edge
+	//
+	// - flowEntry.flowEntryMatch()
+	// - flowEntry.flowEntryActions()
+	// - flowEntry.dpid()
+	// - flowEntry.flowEntryUserState()
+	// - flowEntry.flowEntrySwitchState()
+	// - flowEntry.flowEntryErrorState()
+	// - flowEntry.matchInPort()
+	// - flowEntry.matchEthernetFrameType()
+	// - flowEntry.matchSrcIPv4Net()
+	// - flowEntry.matchDstIPv4Net()
+	// - flowEntry.matchSrcMac()
+	// - flowEntry.matchDstMac()
+	// - flowEntry.actionOutput()
+	//
+	ISwitchObject sw =
+	    conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
+	flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
+	flowEntryObj.setSwitch(sw);
+	if (flowEntry.flowEntryMatch().matchInPort()) {
+	    IPortObject inport =
+		conn.utils().searchPort(conn, flowEntry.dpid().toString(),
+					flowEntry.flowEntryMatch().inPort().value());
+	    flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
+	    flowEntryObj.setInPort(inport);
+	}
+	if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
+	    flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
+	}
+	if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
+	    flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
+	}
+	if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
+	    flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
+	}
+	if (flowEntry.flowEntryMatch().matchSrcMac()) {
+	    flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
+	}
+	if (flowEntry.flowEntryMatch().matchDstMac()) {
+	    flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
+	}
+
+	for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
+	    if (fa.actionOutput() != null) {
+		IPortObject outport =
+		    conn.utils().searchPort(conn,
+					    flowEntry.dpid().toString(),
+					    fa.actionOutput().port().value());
+		flowEntryObj.setActionOutput(fa.actionOutput().port().value());
+		flowEntryObj.setOutPort(outport);
+	    }
+	}
+	// TODO: Hacks with hard-coded state names!
+	if (found)
+	    flowEntryObj.setUserState("FE_USER_MODIFY");
+	else
+	    flowEntryObj.setUserState("FE_USER_ADD");
+	flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
+	//
+	// TODO: Take care of the FlowEntryErrorState.
+	//
+
+	// Flow Entries edges:
+	//   Flow
+	//   NextFE (TODO)
+	if (! found) {
+	    flowObj.addFlowEntry(flowEntryObj);
+	    flowEntryObj.setFlow(flowObj);
+	}
+
+	return true;
+    }
+
+    /**
      * Delete a previously added flow.
      *
      * @param flowId the Flow ID of the flow to delete.
@@ -954,9 +663,12 @@
      */
     @Override
     public boolean deleteFlow(FlowId flowId) {
+	/*
+	 * TODO: Commented-out for now
 	if (flowId.value() == measurementFlowId) {
 	    modifiedMeasurementFlowTime = System.nanoTime();
 	}
+	*/
 
 	IFlowPath flowObj = null;
 	//
@@ -1190,7 +902,10 @@
      * @return the Flow Paths if found, otherwise null.
      */
     @Override
-    public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
+    public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
+    	
+    	
+    	
 		//
 		// TODO: The implementation below is not optimal:
 		// We fetch all flows, and then return only the subset that match
@@ -1198,10 +913,15 @@
 		// We should use the appropriate Titan/Gremlin query to filter-out
 		// the flows as appropriate.
 		//
-    	ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
+    	//ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
     	
+    	ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
+    	
+    	return flowPathsWithoutFlowEntries;
+    	
+    	/*
     	ArrayList<FlowPath> allFlows = getAllFlows();
-	
+
 		if (allFlows == null) {
 		    log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
 		    return flowPaths;
@@ -1212,10 +932,10 @@
 		for (FlowPath flow : allFlows) {
 		    flow.setFlowEntryMatch(null);
 			
-			// start from desired flowId
-			//if (flow.flowId().value() < flowId.value()) {
-			//	continue;
-			//}
+		    // start from desired flowId
+		    if (flow.flowId().value() < flowId.value()) {
+			continue;
+		    }
 			
 			// Summarize by making null flow entry fields that are not relevant to report
 			for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
@@ -1236,6 +956,7 @@
 		}
 	
 		return flowPaths;
+		*/
     }
     
     /**
@@ -1277,6 +998,45 @@
 
 	return flowPaths;
     }
+    
+    public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
+    	Iterable<IFlowPath> flowPathsObj = null;
+    	ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
+    	ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
+
+    	try {
+    	    if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
+    		log.debug("Get all FlowPaths: found FlowPaths");
+    	    } else {
+    		log.debug("Get all FlowPaths: no FlowPaths found");
+    	    }
+    	} catch (Exception e) {
+    	    // TODO: handle exceptions
+    	    conn.endTx(Transaction.ROLLBACK);
+    	    log.error(":getAllFlowPaths failed");
+    	}
+    	if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
+    	    return new ArrayList<IFlowPath>();	// No Flows found
+    	}
+    	
+    	for (IFlowPath flowObj : flowPathsObj){
+    		flowPathsObjArray.add(flowObj);
+    	}
+    	/*
+    	for (IFlowPath flowObj : flowPathsObj) {
+    	    //
+    	    // Extract the Flow state
+    	    //
+    	    FlowPath flowPath = extractFlowPath(flowObj);
+    	    if (flowPath != null)
+    		flowPaths.add(flowPath);
+    	}
+    	*/
+
+    	//conn.endTx(Transaction.COMMIT);
+
+    	return flowPathsObjArray;
+    }
 
     /**
      * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
@@ -1285,8 +1045,6 @@
      * @return the extracted Flow Path State.
      */
     private FlowPath extractFlowPath(IFlowPath flowObj) {
-	FlowPath flowPath = new FlowPath();
-
 	//
 	// Extract the Flow state
 	//
@@ -1307,6 +1065,7 @@
 	    return null;
 	}
 
+	FlowPath flowPath = new FlowPath();
 	flowPath.setFlowId(new FlowId(flowIdStr));
 	flowPath.setInstallerId(new CallerId(installerIdStr));
 	flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
@@ -1341,63 +1100,9 @@
 	//
 	Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
 	for (IFlowEntry flowEntryObj : flowEntries) {
-	    FlowEntry flowEntry = new FlowEntry();
-	    String flowEntryIdStr = flowEntryObj.getFlowEntryId();
-	    String switchDpidStr = flowEntryObj.getSwitchDpid();
-	    String userState = flowEntryObj.getUserState();
-	    String switchState = flowEntryObj.getSwitchState();
-
-	    if ((flowEntryIdStr == null) ||
-		(switchDpidStr == null) ||
-		(userState == null) ||
-		(switchState == null)) {
-		// TODO: A work-around, becauuse of some bogus database objects
+	    FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
+	    if (flowEntry == null)
 		continue;
-	    }
-	    flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
-	    flowEntry.setDpid(new Dpid(switchDpidStr));
-
-	    //
-	    // Extract the match conditions
-	    //
-	    FlowEntryMatch match = new FlowEntryMatch();
-	    Short matchInPort = flowEntryObj.getMatchInPort();
-	    if (matchInPort != null)
-		match.enableInPort(new Port(matchInPort));
-	    Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
-	    if (matchEthernetFrameType != null)
-		match.enableEthernetFrameType(matchEthernetFrameType);
-	    String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
-	    if (matchSrcIPv4Net != null)
-		match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
-	    String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
-	    if (matchDstIPv4Net != null)
-		match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
-	    String matchSrcMac = flowEntryObj.getMatchSrcMac();
-	    if (matchSrcMac != null)
-		match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
-	    String matchDstMac = flowEntryObj.getMatchDstMac();
-	    if (matchDstMac != null)
-		match.enableDstMac(MACAddress.valueOf(matchDstMac));
-	    flowEntry.setFlowEntryMatch(match);
-
-	    //
-	    // Extract the actions
-	    //
-	    ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
-	    Short actionOutputPort = flowEntryObj.getActionOutput();
-	    if (actionOutputPort != null) {
-		FlowEntryAction action = new FlowEntryAction();
-		action.setActionOutput(new Port(actionOutputPort));
-		actions.add(action);
-	    }
-	    flowEntry.setFlowEntryActions(actions);
-	    flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
-	    flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
-	    //
-	    // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
-	    // and FlowEntryErrorState.
-	    //
 	    flowPath.dataPath().flowEntries().add(flowEntry);
 	}
 
@@ -1405,6 +1110,74 @@
     }
 
     /**
+     * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
+     *
+     * @param flowEntryObj the object to extract the Flow Entry State from.
+     * @return the extracted Flow Entry State.
+     */
+    private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
+	String flowEntryIdStr = flowEntryObj.getFlowEntryId();
+	String switchDpidStr = flowEntryObj.getSwitchDpid();
+	String userState = flowEntryObj.getUserState();
+	String switchState = flowEntryObj.getSwitchState();
+
+	if ((flowEntryIdStr == null) ||
+	    (switchDpidStr == null) ||
+	    (userState == null) ||
+	    (switchState == null)) {
+	    // TODO: A work-around, becauuse of some bogus database objects
+	    return null;
+	}
+
+	FlowEntry flowEntry = new FlowEntry();
+	flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
+	flowEntry.setDpid(new Dpid(switchDpidStr));
+
+	//
+	// Extract the match conditions
+	//
+	FlowEntryMatch match = new FlowEntryMatch();
+	Short matchInPort = flowEntryObj.getMatchInPort();
+	if (matchInPort != null)
+	    match.enableInPort(new Port(matchInPort));
+	Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
+	if (matchEthernetFrameType != null)
+	    match.enableEthernetFrameType(matchEthernetFrameType);
+	String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
+	if (matchSrcIPv4Net != null)
+	    match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
+	String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
+	if (matchDstIPv4Net != null)
+	    match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
+	String matchSrcMac = flowEntryObj.getMatchSrcMac();
+	if (matchSrcMac != null)
+	    match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
+	String matchDstMac = flowEntryObj.getMatchDstMac();
+	if (matchDstMac != null)
+	    match.enableDstMac(MACAddress.valueOf(matchDstMac));
+	flowEntry.setFlowEntryMatch(match);
+
+	//
+	// Extract the actions
+	//
+	ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
+	Short actionOutputPort = flowEntryObj.getActionOutput();
+	if (actionOutputPort != null) {
+	    FlowEntryAction action = new FlowEntryAction();
+	    action.setActionOutput(new Port(actionOutputPort));
+	    actions.add(action);
+	}
+	flowEntry.setFlowEntryActions(actions);
+	flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
+	flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
+	//
+	// TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
+	// and FlowEntryErrorState.
+	//
+	return flowEntry;
+    }
+
+    /**
      * Add and maintain a shortest-path flow.
      *
      * NOTE: The Flow Path argument does NOT contain flow entries.
@@ -1473,78 +1246,6 @@
     }
 
     /**
-     * Create a Flow from port to port.
-     *
-     * TODO: We don't need it for now.
-     *
-     * @param src_port the source port.
-     * @param dest_port the destination port.
-     */
-    @Override
-    public void createFlow(IPortObject src_port, IPortObject dest_port) {
-	// TODO: We don't need it for now.
-    }
-
-    /**
-     * Get all Flows matching a source and a destination port.
-     *
-     * TODO: Pankaj might be implementing it later.
-     *
-     * @param src_port the source port to match.
-     * @param dest_port the destination port to match.
-     * @return all flows matching the source and the destination port.
-     */
-    @Override
-    public Iterable<FlowPath> getFlows(IPortObject src_port,
-				       IPortObject dest_port) {
-	// TODO: Pankaj might be implementing it later.
-	return null;
-    }
-
-    /**
-     * Get all Flows going out from a port.
-     *
-     * TODO: We need it now: Pankaj
-     *
-     * @param port the port to match.
-     * @return the list of flows that are going out from the port.
-     */
-    @Override
-    public Iterable<FlowPath> getOutFlows(IPortObject port) {
-	// TODO: We need it now: Pankaj
-	return null;
-    }
-
-    /**
-     * Reconcile all flows on inactive switch port.
-     *
-     * @param portObject the port that has become inactive.
-     */
-    @Override
-    public void reconcileFlows(IPortObject portObject) {
-	Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
-	Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
-
-	//
-	// Collect all affected Flow IDs from the affected flow entries
-	//
-	HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
-	for (IFlowEntry flowEntryObj: inFlowEntries) {
-	    IFlowPath flowObj = flowEntryObj.getFlow();
-	    if (flowObj != null)
-		flowObjSet.add(flowObj);
-	}
-	for (IFlowEntry flowEntryObj: outFlowEntries) {
-	    IFlowPath flowObj = flowEntryObj.getFlow();
-	    if (flowObj != null)
-		flowObjSet.add(flowObj);
-	}
-
-	// Reconcile the affected flows
-	reconcileFlows(flowObjSet);
-    }
-
-    /**
      * Reconcile all flows in a set.
      *
      * @param flowObjSet the set of flows that need to be reconciliated.
@@ -1652,96 +1353,156 @@
     }
 
     /**
-     * Reconcile all flows between a source and a destination port.
+     * Install a Flow Entry on a switch.
      *
-     * TODO: We don't need it for now.
-     *
-     * @param src_port the source port.
-     * @param dest_port the destination port.
+     * @param mySwitch the switch to install the Flow Entry into.
+     * @param flowObj the flow path object for the flow entry to install.
+     * @param flowEntryObj the flow entry object to install.
+     * @return true on success, otherwise false.
      */
-    @Override
-    public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
-	// TODO: We don't need it for now.
-    }
-
-    /**
-     * Compute the shortest path between a source and a destination ports.
-     *
-     * @param src_port the source port.
-     * @param dest_port the destination port.
-     * @return the computed shortest path between the source and the
-     * destination ports. The flow entries in the path itself would
-     * contain the incoming port matching and the outgoing port output
-     * actions set. However, the path itself will NOT have the Flow ID,
-     * Installer ID, and any additional matching conditions for the
-     * flow entries (e.g., source or destination MAC address, etc).
-     */
-    @Override
-    public FlowPath computeFlowPath(IPortObject src_port,
-				    IPortObject dest_port) {
-	//
-	// Prepare the arguments
-	//
-	String dpidStr = src_port.getSwitch().getDPID();
-	Dpid srcDpid = new Dpid(dpidStr);
-	Port srcPort = new Port(src_port.getNumber());
-
-	dpidStr = dest_port.getSwitch().getDPID();
-	Dpid dstDpid = new Dpid(dpidStr);
-	Port dstPort = new Port(dest_port.getNumber());
-
-	SwitchPort src = new SwitchPort(srcDpid, srcPort);
-	SwitchPort dst = new SwitchPort(dstDpid, dstPort);
+    public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
+				    IFlowEntry flowEntryObj) {
+	FlowEntryId flowEntryId =
+	    new FlowEntryId(flowEntryObj.getFlowEntryId());
+	String userState = flowEntryObj.getUserState();
 
 	//
-	// Do the shortest path computation
+	// Create the Open Flow Flow Modification Entry to push
 	//
-	DataPath dataPath = topoRouteService.getShortestPath(src, dst);
-	if (dataPath == null)
-	    return null;
+	OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
+	    .getMessage(OFType.FLOW_MOD);
+	long cookie = flowEntryId.value();
 
-	//
-	// Set the incoming port matching and the outgoing port output
-	// actions for each flow entry.
-	//
-	for (FlowEntry flowEntry : dataPath.flowEntries()) {
-	    // Set the incoming port matching
-	    FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
-	    if (flowEntryMatch == null) {
-		flowEntryMatch = new FlowEntryMatch();
-		flowEntry.setFlowEntryMatch(flowEntryMatch);
-	    }
-	    flowEntryMatch.enableInPort(flowEntry.inPort());
-
-	    // Set the outgoing port output action
-	    ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
-	    if (flowEntryActions == null) {
-		flowEntryActions = new ArrayList<FlowEntryAction>();
-		flowEntry.setFlowEntryActions(flowEntryActions);
-	    }
-	    FlowEntryAction flowEntryAction = new FlowEntryAction();
-	    flowEntryAction.setActionOutput(flowEntry.outPort());
-	    flowEntryActions.add(flowEntryAction);
+	short flowModCommand = OFFlowMod.OFPFC_ADD;
+	if (userState.equals("FE_USER_ADD")) {
+	    flowModCommand = OFFlowMod.OFPFC_ADD;
+	} else if (userState.equals("FE_USER_MODIFY")) {
+	    flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
+	} else if (userState.equals("FE_USER_DELETE")) {
+	    flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
+	} else {
+	    // Unknown user state. Ignore the entry
+	    log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
+		      flowEntryId.toString(), userState);
+	    return false;
 	}
 
 	//
-	// Prepare the return result
+	// Fetch the match conditions.
 	//
-	FlowPath flowPath = new FlowPath();
-	flowPath.setDataPath(dataPath);
+	// NOTE: The Flow matching conditions common for all Flow Entries are
+	// used ONLY if a Flow Entry does NOT have the corresponding matching
+	// condition set.
+	//
+	OFMatch match = new OFMatch();
+	match.setWildcards(OFMatch.OFPFW_ALL);
 
-	return flowPath;
-    }
+	// Match the Incoming Port
+	Short matchInPort = flowEntryObj.getMatchInPort();
+	if (matchInPort != null) {
+	    match.setInputPort(matchInPort);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
+	}
 
-    /**
-     * Get all Flow Entries of a Flow.
-     *
-     * @param flow the flow whose flow entries should be returned.
-     * @return the flow entries of the flow.
-     */
-    @Override
-    public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
-	return flow.dataPath().flowEntries();
+	// Match the Ethernet Frame Type
+	Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
+	if (matchEthernetFrameType == null)
+	    matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
+	if (matchEthernetFrameType != null) {
+	    match.setDataLayerType(matchEthernetFrameType);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
+	}
+
+	// Match the Source IPv4 Network prefix
+	String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
+	if (matchSrcIPv4Net == null)
+	    matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
+	if (matchSrcIPv4Net != null) {
+	    match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
+	}
+
+	// Natch the Destination IPv4 Network prefix
+	String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
+	if (matchDstIPv4Net == null)
+	    matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
+	if (matchDstIPv4Net != null) {
+	    match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
+	}
+
+	// Match the Source MAC address
+	String matchSrcMac = flowEntryObj.getMatchSrcMac();
+	if (matchSrcMac == null)
+	    matchSrcMac = flowObj.getMatchSrcMac();
+	if (matchSrcMac != null) {
+	    match.setDataLayerSource(matchSrcMac);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
+	}
+
+	// Match the Destination MAC address
+	String matchDstMac = flowEntryObj.getMatchDstMac();
+	if (matchDstMac == null)
+	    matchDstMac = flowObj.getMatchDstMac();
+	if (matchDstMac != null) {
+	    match.setDataLayerDestination(matchDstMac);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
+	}
+
+	//
+	// Fetch the actions
+	//
+	// TODO: For now we support only the "OUTPUT" actions.
+	//
+	List<OFAction> actions = new ArrayList<OFAction>();
+	Short actionOutputPort = flowEntryObj.getActionOutput();
+	if (actionOutputPort != null) {
+	    OFActionOutput action = new OFActionOutput();
+	    // XXX: The max length is hard-coded for now
+	    action.setMaxLength((short)0xffff);
+	    action.setPort(actionOutputPort);
+	    actions.add(action);
+	}
+
+	fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
+	    .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
+	    .setPriority(PRIORITY_DEFAULT)
+	    .setBufferId(OFPacketOut.BUFFER_ID_NONE)
+	    .setCookie(cookie)
+	    .setCommand(flowModCommand)
+	    .setMatch(match)
+	    .setActions(actions)
+	    .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
+	fm.setOutPort(OFPort.OFPP_NONE.getValue());
+	if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
+	    (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
+	    if (actionOutputPort != null)
+		fm.setOutPort(actionOutputPort);
+	}
+
+	//
+	// TODO: Set the following flag
+	// fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
+	// See method ForwardingBase::pushRoute()
+	//
+
+	//
+	// Write the message to the switch
+	//
+	try {
+	    messageDamper.write(mySwitch, fm, null);
+	    mySwitch.flush();
+	    //
+	    // TODO: We should use the OpenFlow Barrier mechanism
+	    // to check for errors, and update the SwitchState
+	    // for a flow entry after the Barrier message is
+	    // is received.
+	    //
+	    flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
+	} catch (IOException e) {
+	    log.error("Failure writing flow mod from network map", e);
+	    return false;
+	}
+
+	return true;
     }
 
     /**
@@ -1752,7 +1513,6 @@
      * @param flowEntry the flow entry to install.
      * @return true on success, otherwise false.
      */
-    @Override
     public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
 				    FlowEntry flowEntry) {
 	//
@@ -1892,6 +1652,15 @@
 	try {
 	    messageDamper.write(mySwitch, fm, null);
 	    mySwitch.flush();
+	    //
+	    // TODO: We should use the OpenFlow Barrier mechanism
+	    // to check for errors, and update the SwitchState
+	    // for a flow entry after the Barrier message is
+	    // is received.
+	    //
+	    // TODO: The FlowEntry Object in Titan should be set
+	    // to FE_SWITCH_UPDATED.
+	    //
 	} catch (IOException e) {
 	    log.error("Failure writing flow mod from network map", e);
 	    return false;
@@ -1907,7 +1676,6 @@
      * @param flowEntry the flow entry to remove.
      * @return true on success, otherwise false.
      */
-    @Override
     public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
 				   FlowEntry flowEntry) {
 	//
@@ -1928,7 +1696,6 @@
      * @param flowEntry the flow entry to install.
      * @return true on success, otherwise false.
      */
-    @Override
     public boolean installRemoteFlowEntry(FlowPath flowPath,
 					  FlowEntry flowEntry) {
 	// TODO: We need it now: Jono
@@ -1944,7 +1711,6 @@
      * @param flowEntry the flow entry to remove.
      * @return true on success, otherwise false.
      */
-    @Override
     public boolean removeRemoteFlowEntry(FlowPath flowPath,
 					 FlowEntry flowEntry) {
 	//
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
index 619d36b..855f064 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
@@ -2,6 +2,7 @@
 
 import java.util.ArrayList;
 
+import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.util.CallerId;
 import net.floodlightcontroller.util.DataPathEndpoints;
@@ -77,7 +78,7 @@
      * @param maxFlows: number of flows to return
      * @return the Flow Paths if found, otherwise null.
      */
-    ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows);
+    ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows);
     
     /**
      * Get all installed flows by all installers.
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/DatapathSummarySerializer.java b/src/main/java/net/floodlightcontroller/flowcache/web/DatapathSummarySerializer.java
new file mode 100644
index 0000000..b780e5c
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/DatapathSummarySerializer.java
@@ -0,0 +1,82 @@
+package net.floodlightcontroller.flowcache.web;
+
+import java.io.IOException;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.JsonSerializer;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DatapathSummarySerializer extends JsonSerializer<String>{
+	static Logger log = LoggerFactory.getLogger(DatapathSummarySerializer.class);
+	
+	@Override
+	public void serialize(String datapathSummary, JsonGenerator jGen,
+			SerializerProvider serializer) throws IOException,
+			JsonProcessingException {
+		
+		String[] flowEntries = datapathSummary.split(";");
+		if (flowEntries.length < 2){
+			log.debug("datapathSummary string to short to parse: {}", 
+					datapathSummary);
+			jGen.writeStartObject();
+			jGen.writeEndObject();
+			return;
+		}
+		
+		String[] srcFlowEntry = flowEntries[0].split("/");
+		String[] dstFlowEntry = flowEntries[flowEntries.length - 1].split("/");
+		if (srcFlowEntry.length != 3 || dstFlowEntry.length != 3){
+			log.debug("Malformed datapathSummary string: {}", datapathSummary);
+			jGen.writeStartObject();
+			jGen.writeEndObject();
+			return;
+		}
+		
+		jGen.writeStartObject();
+		
+		/*
+		jGen.writeObjectFieldStart("srcPort");
+		jGen.writeObjectFieldStart("dpid");
+		jGen.writeStringField("value", srcFlowEntry[1]);
+		jGen.writeEndObject();
+		jGen.writeObjectFieldStart("port");
+		jGen.writeStringField("value", srcFlowEntry[0]);
+		jGen.writeEndObject();
+		jGen.writeEndObject();
+		
+		jGen.writeObjectFieldStart("dstPort");
+		jGen.writeObjectFieldStart("dpid");
+		jGen.writeStringField("value", srcFlowEntry[1]);
+		jGen.writeEndObject();
+		jGen.writeObjectFieldStart("port");
+		jGen.writeStringField("value", srcFlowEntry[2]);
+		jGen.writeEndObject();
+		jGen.writeEndObject();
+		*/
+		jGen.writeArrayFieldStart("flowEntries");
+		
+		for (String flowEntryString : flowEntries){
+			String[] flowEntry = flowEntryString.split("/");
+			if (flowEntry.length != 3){
+				log.debug("Malformed datapathSummary string: {}", datapathSummary);
+				jGen.writeStartObject();
+				jGen.writeEndObject();
+				continue;
+			}
+			
+			jGen.writeStartObject();
+			jGen.writeObjectFieldStart("dpid");
+			jGen.writeStringField("value", flowEntry[1]);
+			jGen.writeEndObject();
+			jGen.writeEndObject();
+		}
+		
+		jGen.writeEndArray();
+		
+		jGen.writeEndObject();
+	}
+
+}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/GetSummaryFlowsResource.java b/src/main/java/net/floodlightcontroller/flowcache/web/GetSummaryFlowsResource.java
index 7a928c9..5f63222 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/web/GetSummaryFlowsResource.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/GetSummaryFlowsResource.java
@@ -2,9 +2,10 @@
 
 import java.util.ArrayList;
 
+import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
 import net.floodlightcontroller.flowcache.IFlowService;
-import net.floodlightcontroller.util.FlowPath;
 import net.floodlightcontroller.util.FlowId;
+import net.floodlightcontroller.util.FlowPath;
 
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
@@ -15,8 +16,8 @@
     protected static Logger log = LoggerFactory.getLogger(GetSummaryFlowsResource.class);
 
     @Get("json")
-    public ArrayList<FlowPath> retrieve() {
-    	ArrayList<FlowPath> result = null;
+    public ArrayList<IFlowPath> retrieve() {
+    	ArrayList<IFlowPath> result = null;
     	
     	FlowId flowId;
     	int maxFlows = 0;
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index ec8051f..634f7eb 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -82,10 +82,7 @@
 import net.floodlightcontroller.topology.NodePortTuple;
 import net.floodlightcontroller.util.EventHistory;
 import net.floodlightcontroller.util.EventHistory.EvAction;
-
 import net.onrc.onos.registry.controller.IControllerRegistryService;
-import net.onrc.onos.registry.controller.IControllerRegistryService.ControlChangeCallback;
-import net.onrc.onos.registry.controller.RegistryException;
 
 import org.openflow.protocol.OFMessage;
 import org.openflow.protocol.OFPacketIn;
@@ -130,6 +127,12 @@
 IStorageSourceListener, ILinkDiscoveryService,
 IFloodlightModule, IInfoProvider, IHAListener {
     protected static Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class);
+    
+    protected enum NetworkMapOperation {
+    	NONE,
+    	INSERT,
+    	UPDATE
+    }
 
     // Names of table/fields for links in the storage API
     private static final String LINK_TABLE_NAME = "controller_link";
@@ -1025,6 +1028,7 @@
 
         NodePortTuple srcNpt, dstNpt;
         boolean linkChanged = false;
+        NetworkMapOperation operation = NetworkMapOperation.NONE;
 
         lock.writeLock().lock();
         try {
@@ -1073,7 +1077,8 @@
                 writeLinkToStorage(lt, newInfo);
                 
                 // Write link to network map
-                linkStore.update(lt, newInfo, DM_OPERATION.INSERT);
+                operation = NetworkMapOperation.INSERT;
+                //linkStore.update(lt, newInfo, DM_OPERATION.INSERT);
                 
                 updateOperation = UpdateOperation.LINK_UPDATED;
                 linkChanged = true;
@@ -1132,7 +1137,8 @@
                 writeLinkToStorage(lt, newInfo);
 
                 // Write link to network map
-                linkStore.update(lt, newInfo, DM_OPERATION.UPDATE);
+                operation = NetworkMapOperation.UPDATE;
+                //linkStore.update(lt, newInfo, DM_OPERATION.UPDATE);
                 
                 if (linkChanged) {
                     updateOperation = getUpdateOperation(newInfo.getSrcPortState(),
@@ -1162,6 +1168,18 @@
         } finally {
             lock.writeLock().unlock();
         }
+        
+        switch (operation){
+        case INSERT:
+        	linkStore.update(lt, newInfo, DM_OPERATION.INSERT);
+        	break;
+        case UPDATE:
+        	linkStore.update(lt, newInfo, DM_OPERATION.UPDATE);
+        	break;
+        case NONE:
+        default:
+        	break;
+        }
 
         return linkChanged;
     }
diff --git a/start-rest.sh b/start-rest.sh
index 564eccf..01e7638 100755
--- a/start-rest.sh
+++ b/start-rest.sh
@@ -11,6 +11,16 @@
 REST_LOG="${LOGDIR}/rest.`hostname`.log"
 #######################
 
+dokill() {
+    for cpid in $(ps -o pid= --ppid $1)
+    do 
+        dokill $cpid
+    done
+    echo "killing: $(ps -p $1 -o cmd=)"
+    kill -9 $1 > /dev/null 2>&1
+}
+
+
 function lotate {
     logfile=$1
     nr_max=${2:-10}
@@ -28,15 +38,16 @@
     pids=`ps -edalf |grep ${script_name} | grep python | grep -v grep | awk '{print $4}'`
     for p in ${pids}; do
 	if [ x$p != "x" ]; then
-	    sudo kill -KILL $p
-	    echo "Killed existing prosess (pid: $p)"
+            dokill $p
+#	    sudo kill -KILL $p
+#	    echo "Killed existing prosess (pid: $p)"
 	fi
     done
 }
 
 function status {
     nr_process=`ps -edalf |grep ${script_name} | grep python | grep -v grep | wc -l` 
-    if [ x${nr_process} != "x" ] ; then
+    if [ ${nr_process} != 0 ] ; then
       echo "rest server is running"
     else
       echo "rest server is not running"
diff --git a/web/ons-demo/js/app.js b/web/ons-demo/js/app.js
index 6176c3a..bc3cc6d 100644
--- a/web/ons-demo/js/app.js
+++ b/web/ons-demo/js/app.js
@@ -98,8 +98,8 @@
 			var pts = [];
 			if (!d.dataPath.flowEntries) {
 				// create a temporary vector to indicate the pending flow
-				var s1 = d3.select(document.getElementById(d.dataPath.srcPort.dpid.value));
-				var s2 = d3.select(document.getElementById(d.dataPath.dstPort.dpid.value));
+				var s1 = d3.select(document.getElementById(d.srcDpid));
+				var s2 = d3.select(document.getElementById(d.dstDpid));
 
 				var pt1 = document.querySelector('svg').createSVGPoint();
 				pt1.x = s1.attr('x');
@@ -199,7 +199,7 @@
 		});
 		row.on('dblclick', function () {
 			if (d) {
-				var prompt = 'Delete flow ' + d.flowId.value + '?';
+				var prompt = 'Delete flow ' + d.flowId + '?';
 				if (confirm(prompt)) {
 					deleteFlow(d);
 					d.deletePending = true;
@@ -217,7 +217,7 @@
 			.text(function (d) {
 				if (d) {
 					if (d.flowId) {
-						return d.flowId.value;
+						return d.flowId;
 					} else {
 						return '0x--';
 					}
@@ -230,14 +230,14 @@
 		row.select('.srcDPID')
 			.text(function (d) {
 				if (d) {
-					return d.dataPath.srcPort.dpid.value;
+					return d.srcDpid;
 				}
 			});
 
 		row.select('.dstDPID')
 			.text(function (d) {
 				if (d) {
-					return d.dataPath.dstPort.dpid.value;
+					return d.dstDpid;
 				}
 			});
 	}
@@ -280,7 +280,7 @@
 	}
 
 	if (flow.flowId) {
-		console.log('starting iperf for: ' + flow.flowId.value);
+		console.log('starting iperf for: ' + flow.flowId);
 		startIPerf(flow, duration, updateRate/interval);
 		flow.iperfDisplayInterval = setInterval(function () {
 			if (flow.iperfData) {
@@ -386,7 +386,7 @@
 }
 
 function clearIPerf(flow) {
-	console.log('clearing iperf interval for: ' + flow.flowId.value);
+	console.log('clearing iperf interval for: ' + flow.flowId);
 	clearInterval(flow.iperfFetchInterval);
 	delete flow.iperfFetchInterval;
 	clearInterval(flow.iperfDisplayInterval);
@@ -433,20 +433,20 @@
 		row.append('div')
 			.classed('flowId', true)
 			.text(function (d) {
-				return d.flowId.value;
+				return d.flowId;
 			});
 
 		row.append('div')
 			.classed('srcDPID', true)
 			.text(function (d) {
-				return d.dataPath.srcPort.dpid.value;
+				return d.srcDpid;
 			});
 
 
 		row.append('div')
 			.classed('dstDPID', true)
 			.text(function (d) {
-				return d.dataPath.dstPort.dpid.value;
+				return d.dstDpid;
 			});
 
 	}
@@ -589,7 +589,7 @@
 }
 
 function makeFlowKey(flow) {
-	return flow.dataPath.srcPort.dpid.value + '=>' + flow.dataPath.dstPort.dpid.value;
+	return flow.srcDpid + '=>' + flow.dstDpid;
 }
 
 function makeSelectedFlowKey(flow) {
@@ -935,6 +935,8 @@
 								}
 							}
 						},
+					        srcDpid: srcData.dpid,
+					        dstDpid: dstData.dpid,
 						createPending: true
 					};
 
diff --git a/web/ons-demo/js/controller.js b/web/ons-demo/js/controller.js
index a6c7843..fbc381e 100644
--- a/web/ons-demo/js/controller.js
+++ b/web/ons-demo/js/controller.js
@@ -38,16 +38,16 @@
 		callURL(url);
 	},
 	delFlowCmd: function (flow) {
-		var url = '/proxy/gui/delflow/' + flow.flowId.value;
+		var url = '/proxy/gui/delflow/' + flow.flowId;
 		callURL(url);
 	},
 	startIPerfCmd: function (flow, duration, numSamples) {
-		var flowId = parseInt(flow.flowId.value, 16);
+		var flowId = parseInt(flow.flowId, 16);
 		var url = '/proxy/gui/iperf/start/' + [flowId, duration, numSamples].join('/');
 		callURL(url)
 	},
 	getIPerfDataCmd: function (flow, cb) {
-		var flowId = parseInt(flow.flowId.value, 16);
+		var flowId = parseInt(flow.flowId, 16);
 		var url = '/proxy/gui/iperf/rate/' + flowId;
 		callURL(url, cb);
 	}
@@ -91,4 +91,4 @@
 
 function getIPerfData(flow, cb) {
 	controllerFunctions.getIPerfDataCmd(flow, cb);
-}
\ No newline at end of file
+}
diff --git a/web/topology_rest.py b/web/topology_rest.py
index 4ed3ae5..d55bf7f 100755
--- a/web/topology_rest.py
+++ b/web/topology_rest.py
@@ -7,18 +7,17 @@
 import argparse
 import io
 import time
+import random
 
 import re
 
 from flask import Flask, json, Response, render_template, make_response, request
 
-## Global Var ##
+## Global Var for ON.Lab local REST ##
 RestIP="localhost"
 RestPort=8080
-#DBName="onos-network-map"
 
 ## Uncomment the desired block based on your testbed environment
-
 # Settings for running on production
 controllers=["onosgui1", "onosgui2", "onosgui3", "onosgui4", "onosgui5", "onosgui6", "onosgui7", "onosgui8"]
 core_switches=["00:00:00:00:ba:5e:ba:11", "00:00:00:00:00:00:ba:12", "00:00:20:4e:7f:51:8a:35", "00:00:00:00:ba:5e:ba:13", "00:00:00:08:a2:08:f9:01", "00:00:00:16:97:08:9a:46"]
@@ -27,17 +26,18 @@
 
 # Settings for running on dev testbed. Replace dev
 #controllers=["onosdevb1", "onosdevb2", "onosdevb3", "onosdevb4"]
+#controllers=["onosdevt1", "onosdevt2", "onosdevt3", "onosdevt4", "onosdevt5", "onosdevt6", "onosdevt7", "onosdevt8"]
 #core_switches=["00:00:00:00:00:00:01:01", "00:00:00:00:00:00:01:02", "00:00:00:00:00:00:01:03", "00:00:00:00:00:00:01:04", "00:00:00:00:00:00:01:05", "00:00:00:00:00:00:01:06"]
-#ONOS_GUI3_HOST="http://devb-gui.onlab.us:8080"
-#ONOS_GUI3_CONTROL_HOST="http://devb-gui.onlab.us:8080"
 
-ONOS_LOCAL_HOST="http://localhost:8080" ;# for Amazon EC2
+#ONOS_GUI3_HOST="http://devt-gui.onlab.us:8080"
+#ONOS_GUI3_CONTROL_HOST="http://devt-gui.onlab.us:8080"
 
-nr_flow=0
+LB=True #; True or False
+ONOS_DEFAULT_HOST="localhost" ;# Has to set if LB=False
 
 DEBUG=1
-pp = pprint.PrettyPrinter(indent=4)
 
+pp = pprint.PrettyPrinter(indent=4)
 app = Flask(__name__)
 
 ## Worker Functions ##
@@ -48,7 +48,6 @@
   if DEBUG:
     print '%s' % (txt)
 
-## Rest APIs ##
 ### File Fetch ###
 @app.route('/ui/img/<filename>', methods=['GET'])
 @app.route('/img/<filename>', methods=['GET'])
@@ -88,7 +87,7 @@
 
   return response
 
-
+## Proxy ##
 @app.route("/proxy/gui/link/<cmd>/<src_dpid>/<src_port>/<dst_dpid>/<dst_port>")
 def proxy_link_change(cmd, src_dpid, src_port, dst_dpid, dst_port):
   try:
@@ -181,98 +180,103 @@
   return resp
 
 
+###### ONOS RESET API ##############################
+## Worker Func ###
+def get_json(url):
+  code = 200
+  try:
+    command = "curl -s %s" % (url)
+    result = os.popen(command).read()
+    parsedResult = json.loads(result)    
+    if type(parsedResult) == 'dict' and parsedResult.has_key('code'):
+      print "REST %s returned code %s" % (command, parsedResult['code'])
+      code=500
+  except:
+    print "REST IF %s has issue" % command
+    result = ""
+    code = 500
+
+  return (code, result)
+
+def pick_host():
+  if LB == True:
+    nr_host=len(controllers)
+    r=random.randint(0, nr_host - 1)
+    host=controllers[r]
+  else:
+    host=ONOS_DEFAULT_HOST
+    
+  return "http://" + host + ":8080"
+
+## Switch ##
 @app.route("/wm/core/topology/switches/all/json")
 def switches():
   if request.args.get('proxy') == None:
-    host = ONOS_LOCAL_HOST
+    host = pick_host()
   else:
     host = ONOS_GUI3_HOST
 
-  try:
-    command = "curl -s %s/wm/core/topology/switches/all/json" % (host)
-#    print command
-    result = os.popen(command).read()
-  except:
-    print "REST IF has issue"
-    exit
+  url ="%s/wm/core/topology/switches/all/json" % (host)
+  (code, result) = get_json(url)
 
-  resp = Response(result, status=200, mimetype='application/json')
+  resp = Response(result, status=code, mimetype='application/json')
   return resp
 
+## Link ##
 @app.route("/wm/core/topology/links/json")
 def links():
   if request.args.get('proxy') == None:
-    host = ONOS_LOCAL_HOST
+    host = pick_host()
   else:
     host = ONOS_GUI3_HOST
 
-  try:
-    command = "curl -s %s/wm/core/topology/links/json" % (host)
-    print command
-    result = os.popen(command).read()
-  except:
-    print "REST IF has issue"
-    exit
+  url ="%s/wm/core/topology/links/json" % (host)
+  (code, result) = get_json(url)
 
-  resp = Response(result, status=200, mimetype='application/json')
+  resp = Response(result, status=code, mimetype='application/json')
   return resp
 
-@app.route("/wm/flow/getsummary/0/0/json")
-def flows():
+## FlowSummary ##
+@app.route("/wm/flow/getsummary/<start>/<range>/json")
+def flows(start, range):
   if request.args.get('proxy') == None:
-    host = ONOS_LOCAL_HOST
+    host = pick_host()
   else:
     host = ONOS_GUI3_HOST
 
-  try:
-    command = "curl -s %s/wm/flow/getsummary/0/0/json" % (host)
-#    print command
-    result = os.popen(command).read()
-  except:
-    print "REST IF has issue"
-    exit
+  url ="%s/wm/flow/getsummary/%s/%s/json" % (host, start, range)
+  (code, result) = get_json(url)
 
-
-  resp = Response(result, status=200, mimetype='application/json')
+  resp = Response(result, status=code, mimetype='application/json')
   return resp
 
 @app.route("/wm/registry/controllers/json")
 def registry_controllers():
   if request.args.get('proxy') == None:
-    host = ONOS_LOCAL_HOST
+    host = pick_host()
   else:
     host = ONOS_GUI3_HOST
 
-  try:
-    command = "curl -s %s/wm/registry/controllers/json" % (host)
-#    print command
-    result = os.popen(command).read()
-  except:
-    print "REST IF has issue"
-    exit
+  url= "%s/wm/registry/controllers/json" % (host)
+  (code, result) = get_json(url)
 
-  resp = Response(result, status=200, mimetype='application/json')
+  resp = Response(result, status=code, mimetype='application/json')
   return resp
 
+
 @app.route("/wm/registry/switches/json")
 def registry_switches():
   if request.args.get('proxy') == None:
-    host = ONOS_LOCAL_HOST
+    host = pick_host()
   else:
     host = ONOS_GUI3_HOST
 
-  try:
-    command = "curl -s %s/wm/registry/switches/json" % (host)
-#    print command
-    result = os.popen(command).read()
-  except:
-    print "REST IF has issue"
-    exit
+  url="%s/wm/registry/switches/json" % (host)
+  (code, result) = get_json(url)
 
-  resp = Response(result, status=200, mimetype='application/json')
+  resp = Response(result, status=code, mimetype='application/json')
   return resp
 
-
 def node_id(switch_array, dpid):
   id = -1
   for i, val in enumerate(switch_array):
@@ -312,39 +316,6 @@
         sw['group']=0
       switches.append(sw)
 
-## Comment in if we need devies
-#      sw_index = len(switches) - 1
-#      for p in v['ports']:
-#        for d in p['devices']:
-#          device = {}
-#          device['attached_switch']=dpid
-#          device['name']=d['mac']
-#          if d['state'] == "ACTIVE":
-#            device['group']=1000
-#          else:
-#            device['group']=1001
-#
-#          switches.append(device)
-#          device_index = len (switches) -1
-#          link = {}
-#          link['source'] = device_index
-#          link['target'] = sw_index
-#          link['type'] = -1
-#          links.append(link)
-#          link = {}
-#          link['source'] = sw_index
-#          link['target'] = device_index
-#          link['type'] = -1
-#          links.append(link)
-
-#  try:
-#    command = "curl -s \'http://%s:%s/wm/registry/controllers/json\'" % (RestIP, RestPort)
-#    result = os.popen(command).read()
-#    controllers = json.loads(result)
-#  except:
-#    log_error("xx REST IF has issue: %s" % command)
-#    log_error("%s" % result)
-
   try:
     command = "curl -s \'http://%s:%s/wm/registry/switches/json\'" % (RestIP, RestPort)
     result = os.popen(command).read()
@@ -416,7 +387,6 @@
   topo['nodes'] = switches
   topo['links'] = links
 
-  pp.pprint(topo)
   js = json.dumps(topo)
   resp = Response(js, status=200, mimetype='application/json')
   return resp
@@ -503,7 +473,6 @@
   topo['nodes'] = switches
   topo['links'] = links
 
-#  pp.pprint(topo)
   js = json.dumps(topo)
   resp = Response(js, status=200, mimetype='application/json')
   return resp
@@ -575,7 +544,6 @@
     device['attachmentPoint']=attachpoints
     devices.append(device)
 
-  print devices
   js = json.dumps(devices)
   resp = Response(js, status=200, mimetype='application/json')
   return resp
@@ -649,82 +617,6 @@
   resp = Response(js, status=200, mimetype='application/json')
   return resp
 
-topo_less = {
-  "nodes" : [
-    {"name" : "00:a0", "group" : 1},
-    {"name" : "00:a1", "group" : 1},
-    {"name" : "00:a2", "group" : 1},
-    ],
-  "links" : [
-    {"source" :0, "target": 1},
-    {"source" :1, "target": 0},
-    {"source" :0, "target": 2},
-    {"source" :2, "target": 0},
-    {"source" :1, "target": 2},
-    {"source" :2, "target": 1},
-    ]
-}
-
-topo_more = {
-  "nodes" : [
-    {"name" : "00:a3", "group" : 2},
-    {"name" : "00:a0", "group" : 1},
-    {"name" : "00:a1", "group" : 1},
-    {"name" : "00:a2", "group" : 1},
-    ],
-  "links" : [
-    {"source" :1, "target": 2},
-    {"source" :2, "target": 1},
-    {"source" :1, "target": 3},
-    {"source" :3, "target": 1},
-    {"source" :2, "target": 3},
-    {"source" :3, "target": 2},
-    {"source" :0, "target": 2},
-    ]
-}
-
-@app.route("/topology_more")
-def topology_more():
-  topo = topo_more
-  js = json.dumps(topo)
-  resp = Response(js, status=200, mimetype='application/json')
-  return resp
-
-@app.route("/topology_less")
-def topology_less():
-  topo = topo_less
-  js = json.dumps(topo)
-  resp = Response(js, status=200, mimetype='application/json')
-  return resp
-
-cont_status1 = [
-           {"name":"onos9vpc",  "onos": 1, "cassandra": 1},
-            {"name":"onos10vpc",  "onos": 0, "cassandra": 1},
-            {"name":"onos11vpc",  "onos": 1, "cassandra": 0},
-            {"name":"onos12vpc",  "onos": 1, "cassandra": 0}]
-
-cont_status2 = [
-            {"name":"onos9vpc",  "onos": 0, "cassandra": 1},
-            {"name":"onos10vpc",  "onos": 0, "cassandra": 1},
-            {"name":"onos11vpc",  "onos": 0, "cassandra": 1},
-            {"name":"onos12vpc",  "onos": 0, "cassandra": 1}]
-
-@app.route("/controller_status1")
-def controller_status1():
-  status = cont_status1
-  js = json.dumps(status)
-  resp = Response(js, status=200, mimetype='application/json')
-  pp.pprint(resp)
-  return resp
-
-@app.route("/controller_status2")
-def controller_status2():
-  status = cont_status2
-  js = json.dumps(status)
-  resp = Response(js, status=200, mimetype='application/json')
-  pp.pprint(resp)
-  return resp
-
 @app.route("/controller_status")
 def controller_status():
   onos_check="ssh -i ~/.ssh/onlabkey.pem %s ONOS/start-onos.sh status | awk '{print $1}'"
@@ -741,20 +633,18 @@
 
   js = json.dumps(cont_status)
   resp = Response(js, status=200, mimetype='application/json')
-  pp.pprint(js)
   return resp
 
+### Command ###
 @app.route("/gui/controller/<cmd>/<controller_name>")
 def controller_status_change(cmd, controller_name):
   start_onos="ssh -i ~/.ssh/onlabkey.pem %s ONOS/start-onos.sh start" % (controller_name)
   stop_onos="ssh -i ~/.ssh/onlabkey.pem %s ONOS/start-onos.sh stop" % (controller_name)
 
   if cmd == "up":
-    print start_onos
     result=os.popen(start_onos).read()
     ret = "controller %s is up" % (controller_name)
   elif cmd == "down":
-    print stop_onos
     result=os.popen(stop_onos).read()
     ret = "controller %s is down" % (controller_name)
 
@@ -838,9 +728,11 @@
 
   flow_nr += 1
   command = "/home/ubuntu/ONOS/web/add_flow.py -m onos %d %s %s %s %s %s matchSrcMac %s matchDstMac %s" % (flow_nr, "dummy", src_dpid, src_port, dst_dpid, dst_port, srcMAC, dstMAC)
+  command1 = "/home/ubuntu/ONOS/web/add_flow.py -m onos %d %s %s %s %s %s matchSrcMac %s matchDstMac %s" % (flow_nr, "dummy", dst_dpid, dst_port, src_dpid, src_port, dstMAC, srcMAC)
   print command
   errcode = os.popen(command).read()
-  return errcode
+  errcode1 = os.popen(command1).read()
+  return errcode+" "+errcode1
 
 #* Delete Flow
 #http://localhost:9000/gui/delflow/<flow_id>
@@ -886,7 +778,7 @@
   print cmd_string
   os.popen(cmd_string)
 
-  return
+  return cmd_string
 
 #* Get Iperf Throughput
 #http://localhost:9000/gui/iperf/rate/<flow_id>
@@ -897,8 +789,8 @@
     print command
     result = os.popen(command).read()
     if len(result) == 0:
-      print "No Flow found"
-      return;
+      resp = Response(result, status=400, mimetype='text/html')
+      return "no such iperf flow (flowid %s)" % flow_id;
   except:
     print "REST IF has issue"
     exit
@@ -922,14 +814,18 @@
     print command
     result = os.popen(command).read()
   except:
-    print "REST IF has issue"
     exit
 
-  resp = Response(result, status=200, mimetype='application/json')
-  return resp
+  if len(result) == 0:
+    resp = Response(result, status=400, mimetype='text/html')
+    return "no iperf file found (flowid %s)" % flow_id;
+  else:
+    resp = Response(result, status=200, mimetype='application/json')
+    return resp
 
 
 if __name__ == "__main__":
+  random.seed()
   if len(sys.argv) > 1 and sys.argv[1] == "-d":
 #      add_flow("00:00:00:00:00:00:02:02", 1, "00:00:00:00:00:00:03:02", 1, "00:00:00:00:02:02", "00:00:00:00:03:0c")
 #     link_change("up", "00:00:00:00:ba:5e:ba:11", 1, "00:00:00:00:00:00:00:00", 1)
@@ -945,8 +841,9 @@
 #    query_links()
 #    print "-- query all devices --"
 #    devices()
-    iperf_start(1,10,15)
-    iperf_rate(1)
+#    iperf_start(1,10,15)
+#    iperf_rate(1)
+    switches()
   else:
     app.debug = True
     app.run(threaded=True, host="0.0.0.0", port=9000)