Merge branch 'master' of https://github.com/OPENNETWORKINGLAB/ONOS
diff --git a/conf/onos-embedded.properties b/conf/onos-embedded.properties
index 8bbf25d..777ff2b 100644
--- a/conf/onos-embedded.properties
+++ b/conf/onos-embedded.properties
@@ -9,6 +9,7 @@
 net.floodlightcontroller.ui.web.StaticWebRoutable,\
 net.onrc.onos.datagrid.HazelcastDatagrid,\
 net.onrc.onos.ofcontroller.flowmanager.FlowManager,\
+net.onrc.onos.ofcontroller.topology.TopologyManager,\
 net.onrc.onos.registry.controller.ZookeeperRegistry
 net.floodlightcontroller.restserver.RestApiServer.port = 8080
 net.floodlightcontroller.core.FloodlightProvider.openflowport = 6633
diff --git a/conf/onos.properties b/conf/onos.properties
index c67b340..e858adb 100644
--- a/conf/onos.properties
+++ b/conf/onos.properties
@@ -9,6 +9,7 @@
 net.floodlightcontroller.ui.web.StaticWebRoutable,\
 net.onrc.onos.datagrid.HazelcastDatagrid,\
 net.onrc.onos.ofcontroller.flowmanager.FlowManager,\
+net.onrc.onos.ofcontroller.topology.TopologyManager,\
 net.onrc.onos.registry.controller.ZookeeperRegistry
 net.floodlightcontroller.restserver.RestApiServer.port = 8080
 net.floodlightcontroller.core.FloodlightProvider.openflowport = 6633
diff --git a/pom.xml b/pom.xml
index 71e8192..002ba60 100644
--- a/pom.xml
+++ b/pom.xml
@@ -81,6 +81,7 @@
             <exclude>**/*TestCase.java</exclude>
           -->
           </excludes>
+          <argLine>-XX:MaxPermSize=256m</argLine>
         </configuration>
       </plugin>
       <!-- exec:java -->
@@ -165,6 +166,14 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+	<artifactId>maven-assembly-plugin</artifactId>
+	<configuration>
+	  <descriptorRefs>
+	    <descriptorRef>jar-with-dependencies</descriptorRef>
+	  </descriptorRefs>
+	</configuration>
+      </plugin>
     </plugins>
   </build>
   <!-- for getting visualization reporting   -->
@@ -349,7 +358,7 @@
     <dependency>
       <groupId>org.easymock</groupId>
       <artifactId>easymock</artifactId>
-      <version>3.2</version>
+      <version>3.1</version>
       <scope>test</scope>
     </dependency>
     <dependency>
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index 44510a7..134a3b0 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -2352,7 +2352,7 @@
                         // new controller node IP
                         addedControllerNodeIPs.put(controllerID, discoveredIP);
                     } 
-                    else if (curIP.equals(discoveredIP)) {
+                    else if (!curIP.equals(discoveredIP)) {
                         // IP changed                    
                         removedControllerNodeIPs.put(controllerID, curIP);
                         addedControllerNodeIPs.put(controllerID, discoveredIP);
diff --git a/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java b/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
index 7736880..3ff773e 100644
--- a/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
+++ b/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
@@ -27,9 +27,7 @@
  * appropriate in a multi-node cluster.
  */
 public class HazelcastDatagrid implements IFloodlightModule, IDatagridService {
-    protected static Logger log =
-	LoggerFactory.getLogger(HazelcastDatagrid.class);
-
+    protected static Logger log = LoggerFactory.getLogger(HazelcastDatagrid.class);
     protected IFloodlightProviderService floodlightProvider;
 
     protected static final String HazelcastConfigFile = "datagridConfig";
@@ -101,7 +99,7 @@
     public Map<Class<? extends IFloodlightService>, IFloodlightService> 
 			       getServiceImpls() {
         Map<Class<? extends IFloodlightService>,
-        IFloodlightService> m = 
+	    IFloodlightService> m = 
             new HashMap<Class<? extends IFloodlightService>,
                 IFloodlightService>();
         m.put(IDatagridService.class, this);
diff --git a/src/main/java/net/onrc/onos/graph/GraphDBConnection.java b/src/main/java/net/onrc/onos/graph/GraphDBConnection.java
index f9f3b67..bebcdd2 100644
--- a/src/main/java/net/onrc/onos/graph/GraphDBConnection.java
+++ b/src/main/java/net/onrc/onos/graph/GraphDBConnection.java
@@ -87,9 +87,10 @@
 		return singleton;
 	}
 
-	/** 
+	/**
 	 * Get a FramedGraph instance of the graph.
 	 */
+	@Override
 	public FramedGraph<TitanGraph> getFramedGraph() {
 		if (isValid()) {
 			FramedGraph<TitanGraph> fg = new FramedGraph<TitanGraph>(graph);
@@ -115,6 +116,7 @@
 	/**
 	 * Add LocalGraphChangedLister for the graph.
 	 */
+	@Override
 	public void addEventListener(final LocalGraphChangedListener listener) {
 		EventTransactionalGraph<TitanGraph> eg = this.getEventGraph();
 		eg.addListener(listener);
@@ -124,13 +126,15 @@
 	/**
 	 * Return whether this connection is valid.
 	 */
+	@Override
 	public Boolean isValid() {
-		return (graph != null || graph.isOpen());
+		return (graph != null && graph.isOpen());
 	}
 
 	/**
 	 * Commit changes for the graph operations.
 	 */
+	@Override
 	public void commit() {
 		try {
 			graph.commit();
@@ -143,6 +147,7 @@
 	/**
 	 * Rollback changes for the graph operations.
 	 */
+	@Override
 	public void rollback() {
 		try {
 			graph.rollback();
@@ -155,6 +160,7 @@
 	/**
 	 * Close this database connection.
 	 */
+	@Override
 	public void close() {
 		commit();
 	}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
index 9b6ac53..30b39a6 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
@@ -42,6 +42,7 @@
 import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
 import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
 import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
+import net.onrc.onos.ofcontroller.topology.Topology;
 import net.onrc.onos.ofcontroller.topology.TopologyManager;
 import net.onrc.onos.ofcontroller.util.DataPath;
 import net.onrc.onos.ofcontroller.util.Dpid;
@@ -79,72 +80,72 @@
 									IOFSwitchListener, ILayer3InfoService,
 									IProxyArpService {
 	
-	protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
+	private static Logger log = LoggerFactory.getLogger(BgpRoute.class);
 
-	protected IFloodlightProviderService floodlightProvider;
-	protected ITopologyService topology;
-	protected ITopologyNetService topologyNetService;
-	protected ILinkDiscoveryService linkDiscoveryService;
-	protected IRestApiService restApi;
+	private IFloodlightProviderService floodlightProvider;
+	private ITopologyService topologyService;
+	private ITopologyNetService topologyNetService;
+	private ILinkDiscoveryService linkDiscoveryService;
+	private IRestApiService restApi;
 	
-	protected ProxyArpManager proxyArp;
+	private ProxyArpManager proxyArp;
 	
-	protected IPatriciaTrie<RibEntry> ptree;
-	protected IPatriciaTrie<Interface> interfacePtrie;
-	protected BlockingQueue<RibUpdate> ribUpdates;
+	private IPatriciaTrie<RibEntry> ptree;
+	private IPatriciaTrie<Interface> interfacePtrie;
+	private BlockingQueue<RibUpdate> ribUpdates;
 	
-	protected String bgpdRestIp;
-	protected String routerId;
-	protected String configFilename = "config.json";
+	private String bgpdRestIp;
+	private String routerId;
+	private String configFilename = "config.json";
 	
 	//We need to identify our flows somehow. But like it says in LearningSwitch.java,
 	//the controller/OS should hand out cookie IDs to prevent conflicts.
-	protected final long APP_COOKIE = 0xa0000000000000L;
+	private final long APP_COOKIE = 0xa0000000000000L;
 	//Cookie for flows that do L2 forwarding within SDN domain to egress routers
-	protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
+	private final long L2_FWD_COOKIE = APP_COOKIE + 1;
 	//Cookie for flows in ingress switches that rewrite the MAC address
-	protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
+	private final long MAC_RW_COOKIE = APP_COOKIE + 2;
 	//Cookie for flows that setup BGP paths
-	protected final long BGP_COOKIE = APP_COOKIE + 3;
+	private final long BGP_COOKIE = APP_COOKIE + 3;
 	//Forwarding uses priority 0, and the mac rewrite entries in ingress switches
 	//need to be higher priority than this otherwise the rewrite may not get done
-	protected final short SDNIP_PRIORITY = 10;
-	protected final short ARP_PRIORITY = 20;
+	private final short SDNIP_PRIORITY = 10;
+	private final short ARP_PRIORITY = 20;
 	
-	protected final short BGP_PORT = 179;
+	private final short BGP_PORT = 179;
 	
-	protected final int TOPO_DETECTION_WAIT = 2; //seconds
+	private final int TOPO_DETECTION_WAIT = 2; //seconds
 	
 	//Configuration stuff
-	protected List<String> switches;
-	protected Map<String, Interface> interfaces;
-	protected Map<InetAddress, BgpPeer> bgpPeers;
-	protected SwitchPort bgpdAttachmentPoint;
-	protected MACAddress bgpdMacAddress;
+	private List<String> switches;
+	private Map<String, Interface> interfaces;
+	private Map<InetAddress, BgpPeer> bgpPeers;
+	private SwitchPort bgpdAttachmentPoint;
+	private MACAddress bgpdMacAddress;
 	
 	//True when all switches have connected
-	protected volatile boolean switchesConnected = false;
+	private volatile boolean switchesConnected = false;
 	//True when we have a full mesh of shortest paths between gateways
-	protected volatile boolean topologyReady = false;
+	private volatile boolean topologyReady = false;
 
-	protected ArrayList<LDUpdate> linkUpdates;
-	protected SingletonTask topologyChangeDetectorTask;
+	private ArrayList<LDUpdate> linkUpdates;
+	private SingletonTask topologyChangeDetectorTask;
 	
-	protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
+	private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
 	
-	protected Map<InetAddress, Path> pathsWaitingOnArp;
+	private Map<InetAddress, Path> pathsWaitingOnArp;
 	
-	protected ExecutorService bgpUpdatesExecutor;
+	private ExecutorService bgpUpdatesExecutor;
 	
-	protected Map<InetAddress, Path> pushedPaths;
-	protected Map<Prefix, Path> prefixToPath;
-	protected Multimap<Prefix, PushedFlowMod> pushedFlows;
+	private Map<InetAddress, Path> pushedPaths;
+	private Map<Prefix, Path> prefixToPath;
+	private Multimap<Prefix, PushedFlowMod> pushedFlows;
 	
 	private FlowCache flowCache;
 	
-	protected volatile Map<Long, ?> shortestPathTopo = null;
+	private volatile Topology topology = null;
 		
-	protected class TopologyChangeDetector implements Runnable {
+	private class TopologyChangeDetector implements Runnable {
 		@Override
 		public void run() {
 			log.debug("Running topology change detection task");
@@ -260,13 +261,13 @@
 	    	
 		// Register floodlight provider and REST handler.
 		floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
-		topology = context.getServiceImpl(ITopologyService.class);
+		topologyService = context.getServiceImpl(ITopologyService.class);
 		linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
 		restApi = context.getServiceImpl(IRestApiService.class);
 		
 		//TODO We'll initialise this here for now, but it should really be done as
 		//part of the controller core
-		proxyArp = new ProxyArpManager(floodlightProvider, topology, this, restApi);
+		proxyArp = new ProxyArpManager(floodlightProvider, topologyService, this, restApi);
 		
 		linkUpdates = new ArrayList<LDUpdate>();
 		ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
@@ -318,7 +319,7 @@
 	@Override
 	public void startUp(FloodlightModuleContext context) {
 		restApi.addRestletRoutable(new BgpRouteWebRoutable());
-		topology.addListener(this);
+		topologyService.addListener(this);
 		floodlightProvider.addOFSwitchListener(this);
 		
 		proxyArp.startUp();
@@ -483,7 +484,7 @@
 	}
 	
 	private void addPrefixFlows(Prefix prefix, Interface egressInterface, MACAddress nextHopMacAddress) {		
-		log.debug("Adding flows for prefix {} added, next hop mac {}",
+		log.debug("Adding flows for prefix {}, next hop mac {}",
 				prefix, nextHopMacAddress);
 		
 		//We only need one flow mod per switch, so pick one interface on each switch
@@ -498,14 +499,14 @@
 		//Add a flow to rewrite mac for this prefix to all other border switches
 		for (Interface srcInterface : srcInterfaces.values()) {
 			DataPath shortestPath; 
-			if (shortestPathTopo == null) {
-				shortestPath = topologyNetService.getShortestPath(
+			if (topology == null) {
+				shortestPath = topologyNetService.getDatabaseShortestPath(
 						srcInterface.getSwitchPort(),
 						egressInterface.getSwitchPort());
 			}
 			else {
-				shortestPath = topologyNetService.getTopoShortestPath(
-						shortestPathTopo, srcInterface.getSwitchPort(),
+				shortestPath = topologyNetService.getTopologyShortestPath(
+						topology, srcInterface.getSwitchPort(),
 						egressInterface.getSwitchPort());
 			}
 			
@@ -692,17 +693,17 @@
 		List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
 		
 		for (Interface srcInterface : interfaces.values()) {
-			if (dstInterface.equals(srcInterface.getName())){
+			if (dstInterface.getName().equals(srcInterface.getName())){
 				continue;
 			}
 			
 			DataPath shortestPath;
-			if (shortestPathTopo == null) {
-				shortestPath = topologyNetService.getShortestPath(
+			if (topology == null) {
+				shortestPath = topologyNetService.getDatabaseShortestPath(
 						srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
 			}
 			else {
-				shortestPath = topologyNetService.getTopoShortestPath(shortestPathTopo, 
+				shortestPath = topologyNetService.getTopologyShortestPath(topology, 
 						srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
 			}
 			
@@ -771,7 +772,7 @@
 		for (BgpPeer bgpPeer : bgpPeers.values()){
 			Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
 			
-			DataPath path = topologyNetService.getShortestPath(
+			DataPath path = topologyNetService.getDatabaseShortestPath(
 					peerInterface.getSwitchPort(), bgpdAttachmentPoint);
 			
 			if (path == null){
@@ -1046,7 +1047,7 @@
 	
 	private void beginRouting(){
 		log.debug("Topology is now ready, beginning routing function");
-		shortestPathTopo = topologyNetService.prepareShortestPathTopo();
+		topology = topologyNetService.newDatabaseTopology();
 		
 		setupArpFlows();
 		setupDefaultDropFlows();
@@ -1086,7 +1087,7 @@
 					continue;
 				}
 				
-				DataPath shortestPath = topologyNetService.getShortestPath(
+				DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
 						srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
 				
 				if (shortestPath == null){
@@ -1120,10 +1121,22 @@
 					RibUpdate update = ribUpdates.take();
 					switch (update.getOperation()){
 					case UPDATE:
-						processRibAdd(update);
+						if (validateUpdate(update)) {
+							processRibAdd(update);
+						}
+						else {
+							log.debug("Rib UPDATE out of order: {} via {}",
+									update.getPrefix(), update.getRibEntry().getNextHop());
+						}
 						break;
 					case DELETE:
-						processRibDelete(update);
+						if (validateUpdate(update)) {
+							processRibDelete(update);
+						}
+						else {
+							log.debug("Rib DELETE out of order: {} via {}",
+									update.getPrefix(), update.getRibEntry().getNextHop());
+						}
 						break;
 					}
 				} catch (InterruptedException e) {
@@ -1139,6 +1152,40 @@
 			}
 		}
 	}
+	
+	private boolean validateUpdate(RibUpdate update) {
+		RibEntry newEntry = update.getRibEntry();
+		RibEntry oldEntry = ptree.lookup(update.getPrefix());
+		
+		//If there is no existing entry we must assume this is the most recent
+		//update. However this might not always be the case as we might have a
+		//POST then DELETE reordering.
+		//if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
+		if (oldEntry == null) {
+			return true;
+		}
+		
+		// This handles the case where routes are gathered in the initial
+		// request because they don't have sequence number info
+		if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
+			return true;
+		}
+		
+		if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
+			return true;
+		}
+		else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
+			if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
+				return true;
+			}
+			else {
+				return false;
+			}
+		}
+		else {
+			return false;
+		}
+	}
 
 	@Override
 	public void topologyChanged() {
@@ -1147,7 +1194,7 @@
 		}
 		
 		boolean refreshNeeded = false;
-		for (LDUpdate ldu : topology.getLastLinkUpdates()){
+		for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
 			if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
 				//We don't need to recalculate anything for just link updates
 				//They happen very frequently
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
index 8403f71..c1f0cd6 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
@@ -68,19 +68,27 @@
 		IBgpRouteService bgpRoute = (IBgpRouteService) getContext().getAttributes().
 				get(IBgpRouteService.class.getCanonicalName());
 
+		String strSysuptime = (String) getRequestAttributes().get("sysuptime");
+		String strSequence = (String) getRequestAttributes().get("sequence");
 		String routerId = (String) getRequestAttributes().get("routerid");
 		String prefix = (String) getRequestAttributes().get("prefix");
 		String mask = (String) getRequestAttributes().get("mask");
 		String nexthop = (String) getRequestAttributes().get("nexthop");
 		String capability = (String) getRequestAttributes().get("capability");
+		
+		log.debug("sysuptime: {}", strSysuptime);
+		log.debug("sequence: {}", strSequence);
 
 		String reply = "";
 
 		if (capability == null) {
 			// this is a prefix add
 			Prefix p;
+			long sysUpTime, sequenceNum;
 			try {
 				p = new Prefix(prefix, Integer.valueOf(mask));
+				sysUpTime = Long.parseLong(strSysuptime);
+				sequenceNum = Long.parseLong(strSequence);
 			} catch (NumberFormatException e) {
 				reply = "[POST: mask format is wrong]";
 				log.info(reply);
@@ -91,7 +99,7 @@
 				return reply + "\n";
 			}
 			
-			RibEntry rib = new RibEntry(routerId, nexthop);
+			RibEntry rib = new RibEntry(routerId, nexthop, sysUpTime, sequenceNum);
 
 			bgpRoute.newRibUpdate(new RibUpdate(Operation.UPDATE, p, rib));
 			
@@ -117,19 +125,27 @@
 		IBgpRouteService bgpRoute = (IBgpRouteService)getContext().getAttributes().
 				get(IBgpRouteService.class.getCanonicalName());
 
+		String strSysuptime = (String) getRequestAttributes().get("sysuptime");
+		String strSequence = (String) getRequestAttributes().get("sequence");
 		String routerId = (String) getRequestAttributes().get("routerid");
 		String prefix = (String) getRequestAttributes().get("prefix");
 		String mask = (String) getRequestAttributes().get("mask");
 		String nextHop = (String) getRequestAttributes().get("nexthop");
 		String capability = (String) getRequestAttributes().get("capability");
 
+		log.debug("sysuptime: {}", strSysuptime);
+		log.debug("sequence: {}", strSequence);
+		
 		String reply = "";
 
 		if (capability == null) {
 			// this is a prefix delete
 			Prefix p;
+			long sysUpTime, sequenceNum;
 			try {
 				p = new Prefix(prefix, Integer.valueOf(mask));
+				sysUpTime = Long.parseLong(strSysuptime);
+				sequenceNum = Long.parseLong(strSequence);
 			} catch (NumberFormatException e) {
 				reply = "[DELE: mask format is wrong]";
 				log.info(reply);
@@ -140,7 +156,7 @@
 				return reply + "\n";
 			}
 			
-			RibEntry r = new RibEntry(routerId, nextHop);
+			RibEntry r = new RibEntry(routerId, nextHop, sysUpTime, sequenceNum);
 			
 			bgpRoute.newRibUpdate(new RibUpdate(Operation.DELETE, p, r));
 			
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteWebRoutable.java
index 669c385..26971b0 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteWebRoutable.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteWebRoutable.java
@@ -12,7 +12,7 @@
 		Router router = new Router(context);
 		router.attach("/json", BgpRouteResource.class);
 		router.attach("/rib/{dest}", BgpRouteResource.class);
-		router.attach("/{routerid}/{prefix}/{mask}/{nexthop}", BgpRouteResource.class);		
+		router.attach("/{sysuptime}/{sequence}/{routerid}/{prefix}/{mask}/{nexthop}", BgpRouteResource.class);		
 		router.attach("/{routerid}/{prefix}/{mask}/{nexthop}/synch", BgpRouteResourceSynch.class);
 		router.attach("/{routerid}/{capability}", BgpRouteResource.class);
 		return router;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibEntry.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibEntry.java
index 1520c60..ccf8951 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibEntry.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibEntry.java
@@ -7,21 +7,57 @@
 public class RibEntry {
 	private final InetAddress routerId;
 	private final InetAddress nextHop;
+
+	/*
+	 * Store the sequence number information provided on the update here for
+	 * now. I think this *should* really be in the RibUpdate, and we should
+	 * store RibUpdates in the Ptrie. But, that's a bigger change to change
+	 * what the Ptrie stores.
+	 */
+	private final long sysUpTime;
+	private final long sequenceNum;
+	
+	/*
+	 * Marker for RibEntries where we don't have sequence number info.
+	 * The user of this class should make sure they don't check this data
+	 * if they don't provide it.
+	 */
+	private final static long NULL_TIME = -1;
 	
 	public RibEntry(InetAddress routerId, InetAddress nextHop) {
 		this.routerId = routerId;
 		this.nextHop = nextHop;
+		sequenceNum = NULL_TIME;
+		sysUpTime = NULL_TIME;
 	}
 	
 	public RibEntry(String routerId, String nextHop) {
 		this.routerId = InetAddresses.forString(routerId);
 		this.nextHop = InetAddresses.forString(nextHop);
+		sequenceNum = NULL_TIME;
+		sysUpTime = NULL_TIME;
+	}
+	
+	public RibEntry(String routerId, String nextHop, long sysUpTime
+			, long sequenceNum) {
+		this.routerId = InetAddresses.forString(routerId);
+		this.nextHop = InetAddresses.forString(nextHop);
+		this.sequenceNum = sequenceNum;
+		this.sysUpTime = sysUpTime;
 	}
 	
 	public InetAddress getNextHop() {
 	    return nextHop;
 	}
 	
+	public long getSysUpTime() {
+		return sysUpTime;
+	}
+	
+	public long getSequenceNum() {
+		return sequenceNum;
+	}
+	
 	@Override
 	public boolean equals(Object other) {
 		if (other == null || !(other instanceof RibEntry)) {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoSwitchServiceImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoSwitchServiceImpl.java
index 978fcde..cd3cf15 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoSwitchServiceImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoSwitchServiceImpl.java
@@ -18,7 +18,7 @@
 	}
 
 	public TopoSwitchServiceImpl() {
-		this("/tmp/cassandra.titan");
+		this("");
 	}
 	
 	public void finalize() {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/INetworkGraphService.java b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/INetworkGraphService.java
new file mode 100644
index 0000000..121eaf9
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/INetworkGraphService.java
@@ -0,0 +1,10 @@
+package net.onrc.onos.ofcontroller.floodlightlistener;
+
+import net.floodlightcontroller.core.module.IFloodlightService;
+
+/**
+ * Interface for providing Network Graph Service to other module.
+ */
+public interface INetworkGraphService extends IFloodlightService {
+    // TODO
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
index 046a38b..852cbb8 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
@@ -2,6 +2,7 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -45,8 +46,12 @@
 import net.onrc.onos.registry.controller.IControllerRegistryService.ControlChangeCallback;
 import net.onrc.onos.registry.controller.RegistryException;
 
-public class NetworkGraphPublisher implements IDeviceListener, IOFSwitchListener, IOFSwitchPortListener,
-		ILinkDiscoveryListener, IFloodlightModule {
+public class NetworkGraphPublisher implements IDeviceListener,
+					      IOFSwitchListener,
+					      IOFSwitchPortListener,
+					      ILinkDiscoveryListener,
+					      IFloodlightModule,
+					      INetworkGraphService {
 	
 	protected IDeviceStorage devStore;
 	protected ISwitchStorage swStore;
@@ -229,14 +234,20 @@
 
 	@Override
 	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-		// TODO Auto-generated method stub
-		return null;
+		Collection<Class<? extends IFloodlightService>> l =
+		    new ArrayList<Class<? extends IFloodlightService>>();
+		l.add(INetworkGraphService.class);
+		return l;
 	}
 
 	@Override
 	public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
-		// TODO Auto-generated method stub
-		return null;
+		Map<Class<? extends IFloodlightService>,
+		    IFloodlightService> m =
+		    new HashMap<Class<? extends IFloodlightService>,
+		    IFloodlightService>();
+		m.put(INetworkGraphService.class, this);
+		return m;
 	}
 
 	@Override
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
new file mode 100644
index 0000000..7550b37
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
@@ -0,0 +1,926 @@
+package net.onrc.onos.ofcontroller.flowmanager;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import net.floodlightcontroller.util.MACAddress;
+
+import net.onrc.onos.graph.GraphDBOperation;
+
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
+import net.onrc.onos.ofcontroller.util.*;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class for performing Flow-related operations on the Database.
+ */
+class FlowDatabaseOperation {
+    private static Logger log = LoggerFactory.getLogger(FlowDatabaseOperation.class);
+
+    /**
+     * Add a flow.
+     *
+     * @param flowManager the Flow Manager to use.
+     * @param dbHandler the Graph Database handler to use.
+     * @param flowPath the Flow Path to install.
+     * @param flowId the return-by-reference Flow ID as assigned internally.
+     * @param dataPathSummaryStr the data path summary string if the added
+     * flow will be maintained internally, otherwise null.
+     * @return true on success, otherwise false.
+     */
+    static boolean addFlow(FlowManager flowManager,
+			   GraphDBOperation dbHandler,
+			   FlowPath flowPath, FlowId flowId,
+			   String dataPathSummaryStr) {
+	IFlowPath flowObj = null;
+	boolean found = false;
+	try {
+	    if ((flowObj = dbHandler.searchFlowPath(flowPath.flowId())) != null) {
+		found = true;
+	    } else {
+		flowObj = dbHandler.newFlowPath();
+	    }
+	} catch (Exception e) {
+	    dbHandler.rollback();
+
+	    StringWriter sw = new StringWriter();
+	    e.printStackTrace(new PrintWriter(sw));
+	    String stacktrace = sw.toString();
+
+	    log.error(":addFlow FlowId:{} failed: {}",
+		      flowPath.flowId().toString(),
+		      stacktrace);
+	    return false;
+	}
+	if (flowObj == null) {
+	    log.error(":addFlow FlowId:{} failed: Flow object not created",
+		      flowPath.flowId().toString());
+	    dbHandler.rollback();
+	    return false;
+	}
+
+	//
+	// Set the Flow key:
+	// - flowId
+	//
+	flowObj.setFlowId(flowPath.flowId().toString());
+	flowObj.setType("flow");
+
+	//
+	// Set the Flow attributes:
+	// - flowPath.installerId()
+	// - flowPath.flowPathFlags()
+	// - flowPath.dataPath().srcPort()
+	// - flowPath.dataPath().dstPort()
+	// - flowPath.matchSrcMac()
+	// - flowPath.matchDstMac()
+	// - flowPath.matchEthernetFrameType()
+	// - flowPath.matchVlanId()
+	// - flowPath.matchVlanPriority()
+	// - flowPath.matchSrcIPv4Net()
+	// - flowPath.matchDstIPv4Net()
+	// - flowPath.matchIpProto()
+	// - flowPath.matchIpToS()
+	// - flowPath.matchSrcTcpUdpPort()
+	// - flowPath.matchDstTcpUdpPort()
+	// - flowPath.flowEntryActions()
+	//
+	flowObj.setInstallerId(flowPath.installerId().toString());
+	flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
+	flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
+	flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
+	flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
+	flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
+	if (flowPath.flowEntryMatch().matchSrcMac()) {
+	    flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
+	}
+	if (flowPath.flowEntryMatch().matchDstMac()) {
+	    flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
+	}
+	if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
+	    flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
+	}
+	if (flowPath.flowEntryMatch().matchVlanId()) {
+	    flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
+	}
+	if (flowPath.flowEntryMatch().matchVlanPriority()) {
+	    flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
+	}
+	if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
+	    flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
+	}
+	if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
+	    flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
+	}
+	if (flowPath.flowEntryMatch().matchIpProto()) {
+	    flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
+	}
+	if (flowPath.flowEntryMatch().matchIpToS()) {
+	    flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
+	}
+	if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
+	    flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
+	}
+	if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
+	    flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
+	}
+	if (! flowPath.flowEntryActions().actions().isEmpty()) {
+	    flowObj.setActions(flowPath.flowEntryActions().toString());
+	}
+
+	if (dataPathSummaryStr != null) {
+	    flowObj.setDataPathSummary(dataPathSummaryStr);
+	} else {
+	    flowObj.setDataPathSummary("");
+	}
+
+	if (found)
+	    flowObj.setUserState("FE_USER_MODIFY");
+	else
+	    flowObj.setUserState("FE_USER_ADD");
+
+	// Flow edges:
+	//   HeadFE
+
+
+	//
+	// Flow Entries:
+	// flowPath.dataPath().flowEntries()
+	//
+	for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
+	    if (addFlowEntry(flowManager, dbHandler, flowObj, flowEntry) == null) {
+		dbHandler.rollback();
+		return false;
+	    }
+	}
+	dbHandler.commit();
+
+	//
+	// TODO: We need a proper Flow ID allocation mechanism.
+	//
+	flowId.setValue(flowPath.flowId().value());
+
+	return true;
+    }
+
+    /**
+     * Add a flow entry to the Network MAP.
+     *
+     * @param flowManager the Flow Manager to use.
+     * @param dbHandler the Graph Database handler to use.
+     * @param flowObj the corresponding Flow Path object for the Flow Entry.
+     * @param flowEntry the Flow Entry to install.
+     * @return the added Flow Entry object on success, otherwise null.
+     */
+    static IFlowEntry addFlowEntry(FlowManager flowManager,
+				   GraphDBOperation dbHandler,
+				   IFlowPath flowObj,
+				   FlowEntry flowEntry) {
+	// Flow edges
+	//   HeadFE (TODO)
+
+	//
+	// Assign the FlowEntry ID.
+	//
+	if ((flowEntry.flowEntryId() == null) ||
+	    (flowEntry.flowEntryId().value() == 0)) {
+	    long id = flowManager.getNextFlowEntryId();
+	    flowEntry.setFlowEntryId(new FlowEntryId(id));
+	}
+
+	IFlowEntry flowEntryObj = null;
+	boolean found = false;
+	try {
+	    if ((flowEntryObj =
+		 dbHandler.searchFlowEntry(flowEntry.flowEntryId())) != null) {
+		found = true;
+	    } else {
+		flowEntryObj = dbHandler.newFlowEntry();
+	    }
+	} catch (Exception e) {
+	    log.error(":addFlow FlowEntryId:{} failed",
+		      flowEntry.flowEntryId().toString());
+	    return null;
+	}
+	if (flowEntryObj == null) {
+	    log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
+		      flowEntry.flowEntryId().toString());
+	    return null;
+	}
+
+	//
+	// 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.dpid()
+	// - flowEntry.flowEntryUserState()
+	// - flowEntry.flowEntrySwitchState()
+	// - flowEntry.flowEntryErrorState()
+	// - flowEntry.matchInPort()
+	// - flowEntry.matchSrcMac()
+	// - flowEntry.matchDstMac()
+	// - flowEntry.matchEthernetFrameType()
+	// - flowEntry.matchVlanId()
+	// - flowEntry.matchVlanPriority()
+	// - flowEntry.matchSrcIPv4Net()
+	// - flowEntry.matchDstIPv4Net()
+	// - flowEntry.matchIpProto()
+	// - flowEntry.matchIpToS()
+	// - flowEntry.matchSrcTcpUdpPort()
+	// - flowEntry.matchDstTcpUdpPort()
+	// - flowEntry.actionOutputPort()
+	// - flowEntry.actions()
+	//
+	ISwitchObject sw = dbHandler.searchSwitch(flowEntry.dpid().toString());
+	flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
+	flowEntryObj.setSwitch(sw);
+	if (flowEntry.flowEntryMatch().matchInPort()) {
+	    IPortObject inport =
+		dbHandler.searchPort(flowEntry.dpid().toString(),
+					flowEntry.flowEntryMatch().inPort().value());
+	    flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
+	    flowEntryObj.setInPort(inport);
+	}
+	if (flowEntry.flowEntryMatch().matchSrcMac()) {
+	    flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
+	}
+	if (flowEntry.flowEntryMatch().matchDstMac()) {
+	    flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
+	}
+	if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
+	    flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
+	}
+	if (flowEntry.flowEntryMatch().matchVlanId()) {
+	    flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
+	}
+	if (flowEntry.flowEntryMatch().matchVlanPriority()) {
+	    flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
+	}
+	if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
+	    flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
+	}
+	if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
+	    flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
+	}
+	if (flowEntry.flowEntryMatch().matchIpProto()) {
+	    flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
+	}
+	if (flowEntry.flowEntryMatch().matchIpToS()) {
+	    flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
+	}
+	if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
+	    flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
+	}
+	if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
+	    flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
+	}
+
+	for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
+	    if (fa.actionOutput() != null) {
+		IPortObject outport =
+		    dbHandler.searchPort(flowEntry.dpid().toString(),
+					      fa.actionOutput().port().value());
+		flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
+		flowEntryObj.setOutPort(outport);
+	    }
+	}
+	if (! flowEntry.flowEntryActions().isEmpty()) {
+	    flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
+	}
+
+	// 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 flowEntryObj;
+    }
+
+    /**
+     * Delete all previously added flows.
+     *
+     * @param dbHandler the Graph Database handler to use.
+     * @return true on success, otherwise false.
+     */
+    static boolean deleteAllFlows(GraphDBOperation dbHandler) {
+	final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
+	    new ConcurrentLinkedQueue<FlowId>();
+
+	// Get all Flow IDs
+	Iterable<IFlowPath> allFlowPaths = dbHandler.getAllFlowPaths();
+	for (IFlowPath flowPathObj : allFlowPaths) {
+	    if (flowPathObj == null)
+		continue;
+	    String flowIdStr = flowPathObj.getFlowId();
+	    if (flowIdStr == null)
+		continue;
+	    FlowId flowId = new FlowId(flowIdStr);
+	    concurrentAllFlowIds.add(flowId);
+	}
+
+	// Delete all flows one-by-one
+	for (FlowId flowId : concurrentAllFlowIds)
+	    deleteFlow(dbHandler, flowId);
+
+	/*
+	 * TODO: A faster mechanism to delete the Flow Paths by using
+	 * a number of threads. Commented-out for now.
+	 */
+	/*
+	//
+	// Create the threads to delete the Flow Paths
+	//
+	List<Thread> threads = new LinkedList<Thread>();
+	for (int i = 0; i < 10; i++) {
+	    Thread thread = new Thread(new Runnable() {
+		@Override
+		public void run() {
+		    while (true) {
+			FlowId flowId = concurrentAllFlowIds.poll();
+			if (flowId == null)
+			    return;
+			deleteFlow(dbHandler, flowId);
+		    }
+		}}, "Delete All Flow Paths");
+	    threads.add(thread);
+	}
+
+	// Start processing
+	for (Thread thread : threads) {
+	    thread.start();
+	}
+
+	// Wait for all threads to complete
+	for (Thread thread : threads) {
+	    try {
+		thread.join();
+	    } catch (InterruptedException e) {
+		log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
+	    }
+	}
+	*/
+
+	return true;
+    }
+
+    /**
+     * Delete a previously added flow.
+     *
+     * @param dbHandler the Graph Database handler to use.
+     * @param flowId the Flow ID of the flow to delete.
+     * @return true on success, otherwise false.
+     */
+    static boolean deleteFlow(GraphDBOperation dbHandler, FlowId flowId) {
+	IFlowPath flowObj = null;
+	//
+	// We just mark the entries for deletion,
+	// and let the switches remove each individual entry after
+	// it has been removed from the switches.
+	//
+	try {
+	    flowObj = dbHandler.searchFlowPath(flowId);
+	} catch (Exception e) {
+	    // TODO: handle exceptions
+	    dbHandler.rollback();
+	    log.error(":deleteFlow FlowId:{} failed", flowId.toString());
+	    return false;
+	}
+	if (flowObj == null) {
+	    dbHandler.commit();
+	    return true;		// OK: No such flow
+	}
+
+	//
+	// Find and mark for deletion all Flow Entries,
+	// and the Flow itself.
+	//
+	flowObj.setUserState("FE_USER_DELETE");
+	Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
+	boolean empty = true;	// TODO: an ugly hack
+	for (IFlowEntry flowEntryObj : flowEntries) {
+	    empty = false;
+	    // flowObj.removeFlowEntry(flowEntryObj);
+	    // conn.utils().removeFlowEntry(conn, flowEntryObj);
+	    flowEntryObj.setUserState("FE_USER_DELETE");
+	    flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
+	}
+	// Remove from the database empty flows
+	if (empty)
+	    dbHandler.removeFlowPath(flowObj);
+	dbHandler.commit();
+
+	return true;
+    }
+
+    /**
+     * Clear the state for all previously added flows.
+     *
+     * @param dbHandler the Graph Database handler to use.
+     * @return true on success, otherwise false.
+     */
+    static boolean clearAllFlows(GraphDBOperation dbHandler) {
+	List<FlowId> allFlowIds = new LinkedList<FlowId>();
+
+	// Get all Flow IDs
+	Iterable<IFlowPath> allFlowPaths = dbHandler.getAllFlowPaths();
+	for (IFlowPath flowPathObj : allFlowPaths) {
+	    if (flowPathObj == null)
+		continue;
+	    String flowIdStr = flowPathObj.getFlowId();
+	    if (flowIdStr == null)
+		continue;
+	    FlowId flowId = new FlowId(flowIdStr);
+	    allFlowIds.add(flowId);
+	}
+
+	// Clear all flows one-by-one
+	for (FlowId flowId : allFlowIds) {
+	    clearFlow(dbHandler, flowId);
+	}
+
+	return true;
+    }
+
+    /**
+     * Clear the state for a previously added flow.
+     *
+     * @param dbHandler the Graph Database handler to use.
+     * @param flowId the Flow ID of the flow to clear.
+     * @return true on success, otherwise false.
+     */
+    static boolean clearFlow(GraphDBOperation dbHandler, FlowId flowId) {
+	IFlowPath flowObj = null;
+	try {
+	    flowObj = dbHandler.searchFlowPath(flowId);
+	} catch (Exception e) {
+	    // TODO: handle exceptions
+	    dbHandler.rollback();
+	    log.error(":clearFlow FlowId:{} failed", flowId.toString());
+	    return false;
+	}
+	if (flowObj == null) {
+	    dbHandler.commit();
+	    return true;		// OK: No such flow
+	}
+
+	//
+	// Remove all Flow Entries
+	//
+	Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
+	for (IFlowEntry flowEntryObj : flowEntries) {
+	    flowObj.removeFlowEntry(flowEntryObj);
+	    dbHandler.removeFlowEntry(flowEntryObj);
+	}
+	// Remove the Flow itself
+	dbHandler.removeFlowPath(flowObj);
+	dbHandler.commit();
+
+	return true;
+    }
+
+    /**
+     * Get a previously added flow.
+     *
+     * @param dbHandler the Graph Database handler to use.
+     * @param flowId the Flow ID of the flow to get.
+     * @return the Flow Path if found, otherwise null.
+     */
+    static FlowPath getFlow(GraphDBOperation dbHandler, FlowId flowId) {
+	IFlowPath flowObj = null;
+	try {
+	    flowObj = dbHandler.searchFlowPath(flowId);
+	} catch (Exception e) {
+	    // TODO: handle exceptions
+	    dbHandler.rollback();
+	    log.error(":getFlow FlowId:{} failed", flowId.toString());
+	    return null;
+	}
+	if (flowObj == null) {
+	    dbHandler.commit();
+	    return null;		// Flow not found
+	}
+
+	//
+	// Extract the Flow state
+	//
+	FlowPath flowPath = extractFlowPath(flowObj);
+	dbHandler.commit();
+
+	return flowPath;
+    }
+
+    /**
+     * Get all installed flows by all installers.
+     *
+     * @param dbHandler the Graph Database handler to use.
+     * @return the Flow Paths if found, otherwise null.
+     */
+    static ArrayList<FlowPath> getAllFlows(GraphDBOperation dbHandler) {
+	Iterable<IFlowPath> flowPathsObj = null;
+	ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
+
+	try {
+	    flowPathsObj = dbHandler.getAllFlowPaths();
+	} catch (Exception e) {
+	    // TODO: handle exceptions
+	    dbHandler.rollback();
+	    log.error(":getAllFlowPaths failed");
+	    return flowPaths;
+	}
+	if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
+	    dbHandler.commit();
+	    return flowPaths;	// No Flows found
+	}
+
+	for (IFlowPath flowObj : flowPathsObj) {
+	    //
+	    // Extract the Flow state
+	    //
+	    FlowPath flowPath = extractFlowPath(flowObj);
+	    if (flowPath != null)
+		flowPaths.add(flowPath);
+	}
+
+	dbHandler.commit();
+
+	return flowPaths;
+    }
+
+    /**
+     * Get all previously added flows by a specific installer for a given
+     * data path endpoints.
+     *
+     * @param dbHandler the Graph Database handler to use.
+     * @param installerId the Caller ID of the installer of the flow to get.
+     * @param dataPathEndpoints the data path endpoints of the flow to get.
+     * @return the Flow Paths if found, otherwise null.
+     */
+    static ArrayList<FlowPath> getAllFlows(GraphDBOperation dbHandler,
+					   CallerId installerId,
+					   DataPathEndpoints dataPathEndpoints) {
+	//
+	// TODO: The implementation below is not optimal:
+	// We fetch all flows, and then return only the subset that match
+	// the query conditions.
+	// We should use the appropriate Titan/Gremlin query to filter-out
+	// the flows as appropriate.
+	//
+	ArrayList<FlowPath> allFlows = getAllFlows(dbHandler);
+	ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
+
+	if (allFlows == null)
+	    return flowPaths;
+
+	for (FlowPath flow : allFlows) {
+	    //
+	    // TODO: String-based comparison is sub-optimal.
+	    // We are using it for now to save us the extra work of
+	    // implementing the "equals()" and "hashCode()" methods.
+	    //
+	    if (! flow.installerId().toString().equals(installerId.toString()))
+		continue;
+	    if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
+		continue;
+	    }
+	    if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
+		continue;
+	    }
+	    flowPaths.add(flow);
+	}
+
+	return flowPaths;
+    }
+
+    /**
+     * Get all installed flows by all installers for given data path endpoints.
+     *
+     * @param dbHandler the Graph Database handler to use.
+     * @param dataPathEndpoints the data path endpoints of the flows to get.
+     * @return the Flow Paths if found, otherwise null.
+     */
+    static ArrayList<FlowPath> getAllFlows(GraphDBOperation dbHandler,
+					   DataPathEndpoints dataPathEndpoints) {
+	//
+	// TODO: The implementation below is not optimal:
+	// We fetch all flows, and then return only the subset that match
+	// the query conditions.
+	// We should use the appropriate Titan/Gremlin query to filter-out
+	// the flows as appropriate.
+	//
+	ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
+	ArrayList<FlowPath> allFlows = getAllFlows(dbHandler);
+
+	if (allFlows == null)
+	    return flowPaths;
+
+	for (FlowPath flow : allFlows) {
+	    //
+	    // TODO: String-based comparison is sub-optimal.
+	    // We are using it for now to save us the extra work of
+	    // implementing the "equals()" and "hashCode()" methods.
+	    //
+	    if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
+		continue;
+	    }
+	    if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
+		continue;
+	    }
+	    flowPaths.add(flow);
+	}
+
+	return flowPaths;
+    }
+
+    /**
+     * Get summary of all installed flows by all installers in a given range.
+     *
+     * @param dbHandler the Graph Database handler to use.
+     * @param flowId the Flow ID of the first flow in the flow range to get.
+     * @param maxFlows the maximum number of flows to be returned.
+     * @return the Flow Paths if found, otherwise null.
+     */
+    static ArrayList<IFlowPath> getAllFlowsSummary(GraphDBOperation dbHandler,
+						   FlowId flowId,
+						   int maxFlows) {
+	//
+	// TODO: The implementation below is not optimal:
+	// We fetch all flows, and then return only the subset that match
+	// the query conditions.
+	// We should use the appropriate Titan/Gremlin query to filter-out
+	// the flows as appropriate.
+	//
+    	ArrayList<IFlowPath> flowPathsWithoutFlowEntries =
+	    getAllFlowsWithoutFlowEntries(dbHandler);
+
+    	Collections.sort(flowPathsWithoutFlowEntries, 
+			 new Comparator<IFlowPath>() {
+			     @Override
+			     public int compare(IFlowPath first, IFlowPath second) {
+				 long result =
+				     new FlowId(first.getFlowId()).value()
+				     - new FlowId(second.getFlowId()).value();
+				 if (result > 0) {
+				     return 1;
+				 } else if (result < 0) {
+				     return -1;
+				 } else {
+				     return 0;
+				 }
+			     }
+			 }
+			 );
+    	
+    	return flowPathsWithoutFlowEntries;
+    }
+
+    /**
+     * Get all Flows information, without the associated Flow Entries.
+     *
+     * @param dbHandler the Graph Database handler to use.
+     * @return all Flows information, without the associated Flow Entries.
+     */
+    static ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(GraphDBOperation dbHandler) {
+    	Iterable<IFlowPath> flowPathsObj = null;
+    	ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
+
+	// TODO: Remove this op.commit() flow, because it is not needed?
+    	dbHandler.commit();
+
+    	try {
+    	    flowPathsObj = dbHandler.getAllFlowPaths();
+    	} catch (Exception e) {
+    	    // TODO: handle exceptions
+    	    dbHandler.rollback();
+    	    log.error(":getAllFlowPaths failed");
+	    return flowPathsObjArray;		// No Flows found
+    	}
+    	if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
+    	    return flowPathsObjArray;		// No Flows found
+    	}
+
+    	for (IFlowPath flowObj : flowPathsObj)
+	    flowPathsObjArray.add(flowObj);
+
+    	// conn.endTx(Transaction.COMMIT);
+
+    	return flowPathsObjArray;
+    }
+
+    /**
+     * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
+     *
+     * @param flowObj the object to extract the Flow Path State from.
+     * @return the extracted Flow Path State.
+     */
+    private static FlowPath extractFlowPath(IFlowPath flowObj) {
+	//
+	// Extract the Flow state
+	//
+	String flowIdStr = flowObj.getFlowId();
+	String installerIdStr = flowObj.getInstallerId();
+	Long flowPathFlags = flowObj.getFlowPathFlags();
+	String srcSwitchStr = flowObj.getSrcSwitch();
+	Short srcPortShort = flowObj.getSrcPort();
+	String dstSwitchStr = flowObj.getDstSwitch();
+	Short dstPortShort = flowObj.getDstPort();
+
+	if ((flowIdStr == null) ||
+	    (installerIdStr == null) ||
+	    (flowPathFlags == null) ||
+	    (srcSwitchStr == null) ||
+	    (srcPortShort == null) ||
+	    (dstSwitchStr == null) ||
+	    (dstPortShort == null)) {
+	    // TODO: A work-around, becauuse of some bogus database objects
+	    return null;
+	}
+
+	FlowPath flowPath = new FlowPath();
+	flowPath.setFlowId(new FlowId(flowIdStr));
+	flowPath.setInstallerId(new CallerId(installerIdStr));
+	flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
+	flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
+	flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
+	flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
+	flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
+	//
+	// Extract the match conditions common for all Flow Entries
+	//
+	{
+	    FlowEntryMatch match = new FlowEntryMatch();
+	    String matchSrcMac = flowObj.getMatchSrcMac();
+	    if (matchSrcMac != null)
+		match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
+	    String matchDstMac = flowObj.getMatchDstMac();
+	    if (matchDstMac != null)
+		match.enableDstMac(MACAddress.valueOf(matchDstMac));
+	    Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
+	    if (matchEthernetFrameType != null)
+		match.enableEthernetFrameType(matchEthernetFrameType);
+	    Short matchVlanId = flowObj.getMatchVlanId();
+	    if (matchVlanId != null)
+		match.enableVlanId(matchVlanId);
+	    Byte matchVlanPriority = flowObj.getMatchVlanPriority();
+	    if (matchVlanPriority != null)
+		match.enableVlanPriority(matchVlanPriority);
+	    String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
+	    if (matchSrcIPv4Net != null)
+		match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
+	    String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
+	    if (matchDstIPv4Net != null)
+		match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
+	    Byte matchIpProto = flowObj.getMatchIpProto();
+	    if (matchIpProto != null)
+		match.enableIpProto(matchIpProto);
+	    Byte matchIpToS = flowObj.getMatchIpToS();
+	    if (matchIpToS != null)
+		match.enableIpToS(matchIpToS);
+	    Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
+	    if (matchSrcTcpUdpPort != null)
+		match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
+	    Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
+	    if (matchDstTcpUdpPort != null)
+		match.enableDstTcpUdpPort(matchDstTcpUdpPort);
+
+	    flowPath.setFlowEntryMatch(match);
+	}
+	//
+	// Extract the actions for the first Flow Entry
+	//
+	{
+	    String actionsStr = flowObj.getActions();
+	    if (actionsStr != null) {
+		FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
+		flowPath.setFlowEntryActions(flowEntryActions);
+	    }
+	}
+
+	//
+	// Extract all Flow Entries
+	//
+	Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
+	for (IFlowEntry flowEntryObj : flowEntries) {
+	    FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
+	    if (flowEntry == null)
+		continue;
+	    flowPath.dataPath().flowEntries().add(flowEntry);
+	}
+
+	return flowPath;
+    }
+
+    /**
+     * 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 static 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));
+	String matchSrcMac = flowEntryObj.getMatchSrcMac();
+	if (matchSrcMac != null)
+	    match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
+	String matchDstMac = flowEntryObj.getMatchDstMac();
+	if (matchDstMac != null)
+	    match.enableDstMac(MACAddress.valueOf(matchDstMac));
+	Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
+	if (matchEthernetFrameType != null)
+	    match.enableEthernetFrameType(matchEthernetFrameType);
+	Short matchVlanId = flowEntryObj.getMatchVlanId();
+	if (matchVlanId != null)
+	    match.enableVlanId(matchVlanId);
+	Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
+	if (matchVlanPriority != null)
+	    match.enableVlanPriority(matchVlanPriority);
+	String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
+	if (matchSrcIPv4Net != null)
+	    match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
+	String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
+	if (matchDstIPv4Net != null)
+	    match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
+	Byte matchIpProto = flowEntryObj.getMatchIpProto();
+	if (matchIpProto != null)
+	    match.enableIpProto(matchIpProto);
+	Byte matchIpToS = flowEntryObj.getMatchIpToS();
+	if (matchIpToS != null)
+	    match.enableIpToS(matchIpToS);
+	Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
+	if (matchSrcTcpUdpPort != null)
+	    match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
+	Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
+	if (matchDstTcpUdpPort != null)
+	    match.enableDstTcpUdpPort(matchDstTcpUdpPort);
+	flowEntry.setFlowEntryMatch(match);
+
+	//
+	// Extract the actions
+	//
+	FlowEntryActions actions = new FlowEntryActions();
+	String actionsStr = flowEntryObj.getActions();
+	if (actionsStr != null)
+	    actions = new FlowEntryActions(actionsStr);
+	flowEntry.setFlowEntryActions(actions);
+	flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
+	flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
+	//
+	// TODO: Take care of FlowEntryErrorState.
+	//
+	return flowEntry;
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
index 2c5f4ba..e11814b 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
@@ -1,19 +1,12 @@
 package net.onrc.onos.ofcontroller.flowmanager;
 
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 import java.util.Random;
-import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -25,42 +18,20 @@
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.restserver.IRestApiService;
-import net.floodlightcontroller.util.MACAddress;
 import net.floodlightcontroller.util.OFMessageDamper;
+
+import net.onrc.onos.datagrid.IDatagridService;
 import net.onrc.onos.graph.GraphDBOperation;
 import net.onrc.onos.ofcontroller.core.INetMapStorage;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
+import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
 import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
 import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
-import net.onrc.onos.ofcontroller.topology.TopologyManager;
-import net.onrc.onos.ofcontroller.util.CallerId;
-import net.onrc.onos.ofcontroller.util.DataPath;
-import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
-import net.onrc.onos.ofcontroller.util.Dpid;
-import net.onrc.onos.ofcontroller.util.FlowEntry;
-import net.onrc.onos.ofcontroller.util.FlowEntryAction;
-import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
-import net.onrc.onos.ofcontroller.util.FlowEntryActions;
-import net.onrc.onos.ofcontroller.util.FlowEntryId;
-import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
-import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
-import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
-import net.onrc.onos.ofcontroller.util.FlowId;
-import net.onrc.onos.ofcontroller.util.FlowPath;
-import net.onrc.onos.ofcontroller.util.FlowPathFlags;
-import net.onrc.onos.ofcontroller.util.IPv4Net;
-import net.onrc.onos.ofcontroller.util.Port;
-import net.onrc.onos.ofcontroller.util.SwitchPort;
+import net.onrc.onos.ofcontroller.topology.Topology;
+import net.onrc.onos.ofcontroller.util.*;
 
-import org.openflow.protocol.OFFlowMod;
-import org.openflow.protocol.OFMatch;
-import org.openflow.protocol.OFPacketOut;
-import org.openflow.protocol.OFPort;
 import org.openflow.protocol.OFType;
-import org.openflow.protocol.action.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -69,11 +40,12 @@
  */
 public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
 
-    protected GraphDBOperation op;
+    protected GraphDBOperation dbHandler;
 
-    protected IRestApiService restApi;
     protected volatile IFloodlightProviderService floodlightProvider;
     protected volatile ITopologyNetService topologyNetService;
+    protected volatile IDatagridService datagridService;
+    protected IRestApiService restApi;
     protected FloodlightModuleContext context;
 
     protected OFMessageDamper messageDamper;
@@ -84,9 +56,6 @@
     //
     protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
     protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250;	// ms
-    public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0;	// infinity
-    public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0;	// infinite
-    public static final short PRIORITY_DEFAULT = 100;
 
     // Flow Entry ID generation state
     private static Random randomGenerator = new Random();
@@ -94,12 +63,6 @@
     private static int nextFlowEntryIdSuffix = 0;
     private static long nextFlowEntryId = 0;
 
-    // State for measurement purpose
-    private static long measurementFlowId = 100000;
-    private static String measurementFlowIdStr = "0x186a0";	// 100000
-    private long modifiedMeasurementFlowTime = 0;
-    //
-
     /** The logger. */
     private static Logger log = LoggerFactory.getLogger(FlowManager.class);
 
@@ -117,7 +80,7 @@
 		    runImpl();
 		} catch (Exception e) {
 		    log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
-		    op.rollback();
+		    dbHandler.rollback();
 		    return;
 		}
 	    }
@@ -143,12 +106,12 @@
 		    new LinkedList<IFlowEntry>();
 
 		//
-		// Fetch all Flow Entries which need to be updated and select only my Flow Entries
-		// that need to be updated into the switches.
+		// Fetch all Flow Entries which need to be updated and select
+		// only my Flow Entries that need to be updated into the
+		// switches.
 		//
-		boolean processed_measurement_flow = false;
 		Iterable<IFlowEntry> allFlowEntries =
-		    op.getAllSwitchNotUpdatedFlowEntries();
+		    dbHandler.getAllSwitchNotUpdatedFlowEntries();
 		for (IFlowEntry flowEntryObj : allFlowEntries) {
 		    counterAllFlowEntries++;
 
@@ -161,7 +124,7 @@
 			continue;	// Ignore the entry: not my switch
 
 		    IFlowPath flowObj =
-			op.getFlowPathByFlowEntry(flowEntryObj);
+			dbHandler.getFlowPathByFlowEntry(flowEntryObj);
 		    if (flowObj == null)
 			continue;		// Should NOT happen
 		    if (flowObj.getFlowId() == null)
@@ -183,15 +146,6 @@
 			addFlowEntries.add(flowEntryObj);
 		    }
 		    counterMyNotUpdatedFlowEntries++;
-		    // Code for measurement purpose
-		    // TODO: Commented-out for now
-		    /*
-		    {
-			if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
-			    processed_measurement_flow = true;
-			}
-		    }
-		    */
 		}
 
 		//
@@ -199,7 +153,7 @@
 		//
 		for (IFlowEntry flowEntryObj : addFlowEntries) {
 		    IFlowPath flowObj =
-			op.getFlowPathByFlowEntry(flowEntryObj);
+			dbHandler.getFlowPathByFlowEntry(flowEntryObj);
 		    if (flowObj == null)
 			continue;		// Should NOT happen
 		    if (flowObj.getFlowId() == null)
@@ -223,24 +177,16 @@
 		while (! deleteFlowEntries.isEmpty()) {
 		    IFlowEntry flowEntryObj = deleteFlowEntries.poll();
 		    IFlowPath flowObj =
-			op.getFlowPathByFlowEntry(flowEntryObj);
+			dbHandler.getFlowPathByFlowEntry(flowEntryObj);
 		    if (flowObj == null) {
 			log.debug("Did not find FlowPath to be deleted");
 			continue;
 		    }
 		    flowObj.removeFlowEntry(flowEntryObj);
-		    op.removeFlowEntry(flowEntryObj);
+		    dbHandler.removeFlowEntry(flowEntryObj);
 		}
 
-		op.commit();
-
-		if (processed_measurement_flow) {
-		    long estimatedTime =
-			System.nanoTime() - modifiedMeasurementFlowTime;
-		    String logMsg = "MEASUREMENT: Pushed Flow delay: " +
-			(double)estimatedTime / 1000000000 + " sec";
-		    log.debug(logMsg);
-		}
+		dbHandler.commit();
 
 		long estimatedTime = System.nanoTime() - startTime;
 		double rate = 0.0;
@@ -265,7 +211,7 @@
 		    runImpl();
 		} catch (Exception e) {
 		    log.debug("Exception processing All Flows from the Network MAP: ", e);
-		    op.rollback();
+		    dbHandler.rollback();
 		    return;
 		}
 	    }
@@ -287,15 +233,12 @@
 		}
 		LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
 
-		boolean processed_measurement_flow = false;
-
 		//
 		// Fetch and recompute the Shortest Path for those
 		// Flow Paths this controller is responsible for.
 		//
-		Map<Long, ?> shortestPathTopo =
-		    topologyNetService.prepareShortestPathTopo();
-		Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
+		Topology topology = topologyNetService.newDatabaseTopology();
+		Iterable<IFlowPath> allFlowPaths = dbHandler.getAllFlowPaths();
 		for (IFlowPath flowPathObj : allFlowPaths) {
 		    counterAllFlowPaths++;
 		    if (flowPathObj == null)
@@ -359,18 +302,19 @@
 		    counterMyFlowPaths++;
 
 		    //
-		    // NOTE: Using here the regular getShortestPath() method
-		    // won't work here, because that method calls internally
-		    //  "conn.endTx(Transaction.COMMIT)", and that will
-		    // invalidate all handlers to the Titan database.
+		    // NOTE: Using here the regular getDatabaseShortestPath()
+		    // method won't work here, because that method calls
+		    // internally "conn.endTx(Transaction.COMMIT)", and that
+		    // will invalidate all handlers to the Titan database.
 		    // If we want to experiment with calling here
-		    // getShortestPath(), we need to refactor that code
+		    // getDatabaseShortestPath(), we need to refactor that code
 		    // to avoid closing the transaction.
 		    //
 		    DataPath dataPath =
-			topologyNetService.getTopoShortestPath(shortestPathTopo,
-							       srcSwitchPort,
-							       dstSwitchPort);
+			topologyNetService.getTopologyShortestPath(
+				topology,
+				srcSwitchPort,
+				dstSwitchPort);
 		    if (dataPath == null) {
 			// We need the DataPath to compare the paths
 			dataPath = new DataPath();
@@ -392,20 +336,12 @@
 		//
 		while (! deleteFlows.isEmpty()) {
 		    IFlowPath flowPathObj = deleteFlows.poll();
-		    op.removeFlowPath(flowPathObj);
+		    dbHandler.removeFlowPath(flowPathObj);
 		}
 
-		topologyNetService.dropShortestPathTopo(shortestPathTopo);
+		topologyNetService.dropTopology(topology);
 
-		op.commit();
-
-		if (processed_measurement_flow) {
-		    long estimatedTime =
-			System.nanoTime() - modifiedMeasurementFlowTime;
-		    String logMsg = "MEASUREMENT: Pushed Flow delay: " +
-			(double)estimatedTime / 1000000000 + " sec";
-		    log.debug(logMsg);
-		}
+		dbHandler.commit();
 
 		long estimatedTime = System.nanoTime() - startTime;
 		double rate = 0.0;
@@ -428,8 +364,7 @@
      */
     @Override
     public void init(String conf) {
-    	op = new GraphDBOperation(conf);
-	topologyNetService = new TopologyManager(conf);
+    	dbHandler = new GraphDBOperation(conf);
     }
 
     /**
@@ -444,7 +379,7 @@
      */
     @Override
     public void close() {
-    	op.close();
+    	dbHandler.close();
     }
 
     /**
@@ -469,9 +404,9 @@
     public Map<Class<? extends IFloodlightService>, IFloodlightService> 
 			       getServiceImpls() {
         Map<Class<? extends IFloodlightService>,
-        IFloodlightService> m = 
-            new HashMap<Class<? extends IFloodlightService>,
-                IFloodlightService>();
+	    IFloodlightService> m =
+	    new HashMap<Class<? extends IFloodlightService>,
+	    IFloodlightService>();
         m.put(IFlowService.class, this);
         return m;
     }
@@ -483,10 +418,12 @@
      */
     @Override
     public Collection<Class<? extends IFloodlightService>> 
-                                                    getModuleDependencies() {
+				      getModuleDependencies() {
 	Collection<Class<? extends IFloodlightService>> l =
 	    new ArrayList<Class<? extends IFloodlightService>>();
 	l.add(IFloodlightProviderService.class);
+	l.add(INetworkGraphService.class);
+	l.add(IDatagridService.class);
 	l.add(IRestApiService.class);
         return l;
     }
@@ -501,15 +438,16 @@
 	throws FloodlightModuleException {
 	this.context = context;
 	floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
+	topologyNetService = context.getServiceImpl(ITopologyNetService.class);
+	datagridService = context.getServiceImpl(IDatagridService.class);
 	restApi = context.getServiceImpl(IRestApiService.class);
+
 	messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
 					    EnumSet.of(OFType.FLOW_MOD),
 					    OFMESSAGE_DAMPER_TIMEOUT);
 
-	// TODO: An ugly hack!
-	String conf = "/tmp/cassandra.titan";
-	this.init(conf);
-	
+	this.init("");
+
 	mapReaderScheduler = Executors.newScheduledThreadPool(1);
 	shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
     }
@@ -519,7 +457,7 @@
      *
      * @return the next Flow Entry ID to use.
      */
-    private synchronized long getNextFlowEntryId() {
+    public synchronized long getNextFlowEntryId() {
 	//
 	// Generate the next Flow Entry ID.
 	// NOTE: For now, the higher 32 bits are random, and
@@ -545,10 +483,10 @@
     @Override
     public void startUp(FloodlightModuleContext context) {
 	restApi.addRestletRoutable(new FlowWebRoutable());
-	
+
 	// Initialize the Flow Entry ID generator
 	nextFlowEntryIdPrefix = randomGenerator.nextInt();
-		
+
 	mapReaderScheduler.scheduleAtFixedRate(
 			mapReader, 3, 3, TimeUnit.SECONDS);
 	shortestPathReconcileScheduler.scheduleAtFixedRate(
@@ -558,9 +496,6 @@
     /**
      * Add a flow.
      *
-     * Internally, ONOS will automatically register the installer for
-     * receiving Flow Path Notifications for that path.
-     *
      * @param flowPath the Flow Path to install.
      * @param flowId the return-by-reference Flow ID as assigned internally.
      * @param dataPathSummaryStr the data path summary string if the added
@@ -570,147 +505,8 @@
     @Override
     public boolean addFlow(FlowPath flowPath, FlowId flowId,
 			   String dataPathSummaryStr) {
-	/*
-	 * TODO: Commented-out for now
-	if (flowPath.flowId().value() == measurementFlowId) {
-	    modifiedMeasurementFlowTime = System.nanoTime();
-	}
-	*/
-
-	IFlowPath flowObj = null;
-	boolean found = false;
-	try {
-	    if ((flowObj = op.searchFlowPath(flowPath.flowId()))
-		!= null) {
-		log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
-			  flowPath.flowId().toString());
-		found = true;
-	    } else {
-		flowObj = op.newFlowPath();
-		log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
-			  flowPath.flowId().toString());
-	    }
-	} catch (Exception e) {
-	    // TODO: handle exceptions
-	    op.rollback();
-
-	    StringWriter sw = new StringWriter();
-	    e.printStackTrace(new PrintWriter(sw));
-	    String stacktrace = sw.toString();
-
-	    log.error(":addFlow FlowId:{} failed: {}",
-		      flowPath.flowId().toString(),
-		      stacktrace);
-	}
-	if (flowObj == null) {
-	    log.error(":addFlow FlowId:{} failed: Flow object not created",
-		      flowPath.flowId().toString());
-	    op.rollback();
-	    return false;
-	}
-
-	//
-	// Set the Flow key:
-	// - flowId
-	//
-	flowObj.setFlowId(flowPath.flowId().toString());
-	flowObj.setType("flow");
-
-	//
-	// Set the Flow attributes:
-	// - flowPath.installerId()
-	// - flowPath.flowPathFlags()
-	// - flowPath.dataPath().srcPort()
-	// - flowPath.dataPath().dstPort()
-	// - flowPath.matchSrcMac()
-	// - flowPath.matchDstMac()
-	// - flowPath.matchEthernetFrameType()
-	// - flowPath.matchVlanId()
-	// - flowPath.matchVlanPriority()
-	// - flowPath.matchSrcIPv4Net()
-	// - flowPath.matchDstIPv4Net()
-	// - flowPath.matchIpProto()
-	// - flowPath.matchIpToS()
-	// - flowPath.matchSrcTcpUdpPort()
-	// - flowPath.matchDstTcpUdpPort()
-	// - flowPath.flowEntryActions()
-	//
-	flowObj.setInstallerId(flowPath.installerId().toString());
-	flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
-	flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
-	flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
-	flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
-	flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
-	if (flowPath.flowEntryMatch().matchSrcMac()) {
-	    flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
-	}
-	if (flowPath.flowEntryMatch().matchDstMac()) {
-	    flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
-	}
-	if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
-	    flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
-	}
-	if (flowPath.flowEntryMatch().matchVlanId()) {
-	    flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
-	}
-	if (flowPath.flowEntryMatch().matchVlanPriority()) {
-	    flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
-	}
-	if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
-	    flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
-	}
-	if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
-	    flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
-	}
-	if (flowPath.flowEntryMatch().matchIpProto()) {
-	    flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
-	}
-	if (flowPath.flowEntryMatch().matchIpToS()) {
-	    flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
-	}
-	if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
-	    flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
-	}
-	if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
-	    flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
-	}
-	if (! flowPath.flowEntryActions().actions().isEmpty()) {
-	    flowObj.setActions(flowPath.flowEntryActions().toString());
-	}
-
-	if (dataPathSummaryStr != null) {
-	    flowObj.setDataPathSummary(dataPathSummaryStr);
-	} else {
-	    flowObj.setDataPathSummary("");
-	}
-
-	if (found)
-	    flowObj.setUserState("FE_USER_MODIFY");
-	else
-	    flowObj.setUserState("FE_USER_ADD");
-
-	// Flow edges:
-	//   HeadFE
-
-
-	//
-	// Flow Entries:
-	// flowPath.dataPath().flowEntries()
-	//
-	for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
-	    if (addFlowEntry(flowObj, flowEntry) == null) {
-		op.rollback();
-		return false;
-	    }
-	}
-	op.commit();
-
-	//
-	// TODO: We need a proper Flow ID allocation mechanism.
-	//
-	flowId.setValue(flowPath.flowId().value());
-
-	return true;
+	return FlowDatabaseOperation.addFlow(this, dbHandler, flowPath, flowId,
+					     dataPathSummaryStr);
     }
 
     /**
@@ -721,150 +517,8 @@
      * @return the added Flow Entry object on success, otherwise null.
      */
     private IFlowEntry 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 =
-		 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
-		log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
-			  flowEntry.flowEntryId().toString());
-		found = true;
-	    } else {
-		flowEntryObj = op.newFlowEntry();
-		log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
-			  flowEntry.flowEntryId().toString());
-	    }
-	} catch (Exception e) {
-	    log.error(":addFlow FlowEntryId:{} failed",
-		      flowEntry.flowEntryId().toString());
-	    return null;
-	}
-	if (flowEntryObj == null) {
-	    log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
-		      flowEntry.flowEntryId().toString());
-	    return null;
-	}
-
-	//
-	// 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.dpid()
-	// - flowEntry.flowEntryUserState()
-	// - flowEntry.flowEntrySwitchState()
-	// - flowEntry.flowEntryErrorState()
-	// - flowEntry.matchInPort()
-	// - flowEntry.matchSrcMac()
-	// - flowEntry.matchDstMac()
-	// - flowEntry.matchEthernetFrameType()
-	// - flowEntry.matchVlanId()
-	// - flowEntry.matchVlanPriority()
-	// - flowEntry.matchSrcIPv4Net()
-	// - flowEntry.matchDstIPv4Net()
-	// - flowEntry.matchIpProto()
-	// - flowEntry.matchIpToS()
-	// - flowEntry.matchSrcTcpUdpPort()
-	// - flowEntry.matchDstTcpUdpPort()
-	// - flowEntry.actionOutputPort()
-	// - flowEntry.actions()
-	//
-	ISwitchObject sw = op.searchSwitch(flowEntry.dpid().toString());
-	flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
-	flowEntryObj.setSwitch(sw);
-	if (flowEntry.flowEntryMatch().matchInPort()) {
-	    IPortObject inport =
-		op.searchPort(flowEntry.dpid().toString(),
-					flowEntry.flowEntryMatch().inPort().value());
-	    flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
-	    flowEntryObj.setInPort(inport);
-	}
-	if (flowEntry.flowEntryMatch().matchSrcMac()) {
-	    flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
-	}
-	if (flowEntry.flowEntryMatch().matchDstMac()) {
-	    flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
-	}
-	if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
-	    flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
-	}
-	if (flowEntry.flowEntryMatch().matchVlanId()) {
-	    flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
-	}
-	if (flowEntry.flowEntryMatch().matchVlanPriority()) {
-	    flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
-	}
-	if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
-	    flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
-	}
-	if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
-	    flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
-	}
-	if (flowEntry.flowEntryMatch().matchIpProto()) {
-	    flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
-	}
-	if (flowEntry.flowEntryMatch().matchIpToS()) {
-	    flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
-	}
-	if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
-	    flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
-	}
-	if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
-	    flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
-	}
-
-	for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
-	    if (fa.actionOutput() != null) {
-		IPortObject outport =
-		    op.searchPort(flowEntry.dpid().toString(),
-					      fa.actionOutput().port().value());
-		flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
-		flowEntryObj.setOutPort(outport);
-	    }
-	}
-	if (! flowEntry.flowEntryActions().isEmpty()) {
-	    flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
-	}
-
-	// 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 flowEntryObj;
+	return FlowDatabaseOperation.addFlowEntry(this, dbHandler, flowObj,
+						  flowEntry);
     }
 
     /**
@@ -874,64 +528,7 @@
      */
     @Override
     public boolean deleteAllFlows() {
-	final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
-	    new ConcurrentLinkedQueue<FlowId>();
-
-	// Get all Flow IDs
-	Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
-	for (IFlowPath flowPathObj : allFlowPaths) {
-	    if (flowPathObj == null)
-		continue;
-	    String flowIdStr = flowPathObj.getFlowId();
-	    if (flowIdStr == null)
-		continue;
-	    FlowId flowId = new FlowId(flowIdStr);
-	    concurrentAllFlowIds.add(flowId);
-	}
-
-	// Delete all flows one-by-one
-	for (FlowId flowId : concurrentAllFlowIds)
-	    deleteFlow(flowId);
-
-	/*
-	 * TODO: A faster mechanism to delete the Flow Paths by using
-	 * a number of threads. Commented-out for now.
-	 */
-	/*
-	//
-	// Create the threads to delete the Flow Paths
-	//
-	List<Thread> threads = new LinkedList<Thread>();
-	for (int i = 0; i < 10; i++) {
-	    Thread thread = new Thread(new Runnable() {
-		@Override
-		public void run() {
-		    while (true) {
-			FlowId flowId = concurrentAllFlowIds.poll();
-			if (flowId == null)
-			    return;
-			deleteFlow(flowId);
-		    }
-		}}, "Delete All Flow Paths");
-	    threads.add(thread);
-	}
-
-	// Start processing
-	for (Thread thread : threads) {
-	    thread.start();
-	}
-
-	// Wait for all threads to complete
-	for (Thread thread : threads) {
-	    try {
-		thread.join();
-	    } catch (InterruptedException e) {
-		log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
-	    }
-	}
-	*/
-
-	return true;
+	return FlowDatabaseOperation.deleteAllFlows(dbHandler);
     }
 
     /**
@@ -942,58 +539,7 @@
      */
     @Override
     public boolean deleteFlow(FlowId flowId) {
-	/*
-	 * TODO: Commented-out for now
-	if (flowId.value() == measurementFlowId) {
-	    modifiedMeasurementFlowTime = System.nanoTime();
-	}
-	*/
-
-	IFlowPath flowObj = null;
-	//
-	// We just mark the entries for deletion,
-	// and let the switches remove each individual entry after
-	// it has been removed from the switches.
-	//
-	try {
-	    if ((flowObj = op.searchFlowPath(flowId))
-		!= null) {
-		log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
-			  flowId.toString());
-	    } else {
-		log.debug("Deleting FlowPath with FlowId {}:  FlowPath not found",
-			  flowId.toString());
-	    }
-	} catch (Exception e) {
-	    // TODO: handle exceptions
-	    op.rollback();
-	    log.error(":deleteFlow FlowId:{} failed", flowId.toString());
-	}
-	if (flowObj == null) {
-	    op.commit();
-	    return true;		// OK: No such flow
-	}
-
-	//
-	// Find and mark for deletion all Flow Entries,
-	// and the Flow itself.
-	//
-	flowObj.setUserState("FE_USER_DELETE");
-	Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
-	boolean empty = true;	// TODO: an ugly hack
-	for (IFlowEntry flowEntryObj : flowEntries) {
-	    empty = false;
-	    // flowObj.removeFlowEntry(flowEntryObj);
-	    // conn.utils().removeFlowEntry(conn, flowEntryObj);
-	    flowEntryObj.setUserState("FE_USER_DELETE");
-	    flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
-	}
-	// Remove from the database empty flows
-	if (empty)
-	    op.removeFlowPath(flowObj);
-	op.commit();
-
-	return true;
+	return FlowDatabaseOperation.deleteFlow(dbHandler, flowId);
     }
 
     /**
@@ -1003,26 +549,7 @@
      */
     @Override
     public boolean clearAllFlows() {
-	List<FlowId> allFlowIds = new LinkedList<FlowId>();
-
-	// Get all Flow IDs
-	Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
-	for (IFlowPath flowPathObj : allFlowPaths) {
-	    if (flowPathObj == null)
-		continue;
-	    String flowIdStr = flowPathObj.getFlowId();
-	    if (flowIdStr == null)
-		continue;
-	    FlowId flowId = new FlowId(flowIdStr);
-	    allFlowIds.add(flowId);
-	}
-
-	// Clear all flows one-by-one
-	for (FlowId flowId : allFlowIds) {
-	    clearFlow(flowId);
-	}
-
-	return true;
+	return FlowDatabaseOperation.clearAllFlows(dbHandler);
     }
 
     /**
@@ -1033,39 +560,7 @@
      */
     @Override
     public boolean clearFlow(FlowId flowId) {
-	IFlowPath flowObj = null;
-	try {
-	    if ((flowObj = op.searchFlowPath(flowId))
-		!= null) {
-		log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
-			  flowId.toString());
-	    } else {
-		log.debug("Clearing FlowPath with FlowId {}:  FlowPath not found",
-			  flowId.toString());
-	    }
-	} catch (Exception e) {
-	    // TODO: handle exceptions
-	    op.rollback();
-	    log.error(":clearFlow FlowId:{} failed", flowId.toString());
-	}
-	if (flowObj == null) {
-	    op.commit();
-	    return true;		// OK: No such flow
-	}
-
-	//
-	// Remove all Flow Entries
-	//
-	Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
-	for (IFlowEntry flowEntryObj : flowEntries) {
-	    flowObj.removeFlowEntry(flowEntryObj);
-	    op.removeFlowEntry(flowEntryObj);
-	}
-	// Remove the Flow itself
-	op.removeFlowPath(flowObj);
-	op.commit();
-
-	return true;
+	return FlowDatabaseOperation.clearFlow(dbHandler, flowId);
     }
 
     /**
@@ -1076,33 +571,17 @@
      */
     @Override
     public FlowPath getFlow(FlowId flowId) {
-	IFlowPath flowObj = null;
-	try {
-	    if ((flowObj = op.searchFlowPath(flowId))
-		!= null) {
-		log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
-			  flowId.toString());
-	    } else {
-		log.debug("Get FlowPath with FlowId {}:  FlowPath not found",
-			  flowId.toString());
-	    }
-	} catch (Exception e) {
-	    // TODO: handle exceptions
-	    op.rollback();
-	    log.error(":getFlow FlowId:{} failed", flowId.toString());
-	}
-	if (flowObj == null) {
-	    op.commit();
-	    return null;		// Flow not found
-	}
+	return FlowDatabaseOperation.getFlow(dbHandler, flowId);
+    }
 
-	//
-	// Extract the Flow state
-	//
-	FlowPath flowPath = extractFlowPath(flowObj);
-	op.commit();
-
-	return flowPath;
+    /**
+     * Get all installed flows by all installers.
+     *
+     * @return the Flow Paths if found, otherwise null.
+     */
+    @Override
+    public ArrayList<FlowPath> getAllFlows() {
+	return FlowDatabaseOperation.getAllFlows(dbHandler);
     }
 
     /**
@@ -1116,45 +595,8 @@
     @Override
     public ArrayList<FlowPath> getAllFlows(CallerId installerId,
 					   DataPathEndpoints dataPathEndpoints) {
-	//
-	// TODO: The implementation below is not optimal:
-	// We fetch all flows, and then return only the subset that match
-	// the query conditions.
-	// We should use the appropriate Titan/Gremlin query to filter-out
-	// the flows as appropriate.
-	//
-	ArrayList<FlowPath> allFlows = getAllFlows();
-	ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
-
-	if (allFlows == null) {
-	    log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
-	    return flowPaths;
-	}
-
-	for (FlowPath flow : allFlows) {
-	    //
-	    // TODO: String-based comparison is sub-optimal.
-	    // We are using it for now to save us the extra work of
-	    // implementing the "equals()" and "hashCode()" methods.
-	    //
-	    if (! flow.installerId().toString().equals(installerId.toString()))
-		continue;
-	    if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
-		continue;
-	    }
-	    if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
-		continue;
-	    }
-	    flowPaths.add(flow);
-	}
-
-	if (flowPaths.isEmpty()) {
-	    log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
-	} else {
-	    log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
-	}
-
-	return flowPaths;
+	return FlowDatabaseOperation.getAllFlows(dbHandler, installerId,
+						 dataPathEndpoints);
     }
 
     /**
@@ -1165,43 +607,7 @@
      */
     @Override
     public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
-	//
-	// TODO: The implementation below is not optimal:
-	// We fetch all flows, and then return only the subset that match
-	// the query conditions.
-	// We should use the appropriate Titan/Gremlin query to filter-out
-	// the flows as appropriate.
-	//
-    ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
-    ArrayList<FlowPath> allFlows = getAllFlows();
-
-	if (allFlows == null) {
-	    log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
-	    return flowPaths;
-	}
-
-	for (FlowPath flow : allFlows) {
-	    //
-	    // TODO: String-based comparison is sub-optimal.
-	    // We are using it for now to save us the extra work of
-	    // implementing the "equals()" and "hashCode()" methods.
-	    //
-	    if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
-		continue;
-	    }
-	    if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
-		continue;
-	    }
-	    flowPaths.add(flow);
-	}
-
-	if (flowPaths.isEmpty()) {
-	    log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
-	} else {
-	    log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
-	}
-
-	return flowPaths;
+	return FlowDatabaseOperation.getAllFlows(dbHandler, dataPathEndpoints);
     }
 
     /**
@@ -1212,344 +618,19 @@
      * @return the Flow Paths if found, otherwise null.
      */
     @Override
-    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
-	// the query conditions.
-	// We should use the appropriate Titan/Gremlin query to filter-out
-	// the flows as appropriate.
-	//
-    	//ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
-    	
-    	ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
-    	
-    	Collections.sort(flowPathsWithoutFlowEntries, 
-    			new Comparator<IFlowPath>(){
-					@Override
-					public int compare(IFlowPath first, IFlowPath second) {
-						// TODO Auto-generated method stub
-						long result = new FlowId(first.getFlowId()).value()
-								- new FlowId(second.getFlowId()).value();
-						if (result > 0) return 1;
-						else if (result < 0) return -1;
-						else return 0;
-					}
-    			}
-    	);
-    	
-    	return flowPathsWithoutFlowEntries;
-    	
-    	/*
-    	ArrayList<FlowPath> allFlows = getAllFlows();
-
-		if (allFlows == null) {
-		    log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
-		    return flowPaths;
-		}
-	
-		Collections.sort(allFlows);
-		
-		for (FlowPath flow : allFlows) {
-		    flow.setFlowEntryMatch(null);
-			
-		    // 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()) {
-				flowEntry.setFlowEntryActions(null);
-				flowEntry.setFlowEntryMatch(null);
-			}
-			
-		    flowPaths.add(flow);
-		    if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
-		    	break;
-		    }
-		}
-	
-		if (flowPaths.isEmpty()) {
-		    log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
-		} else {
-		    log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
-		}
-	
-		return flowPaths;
-		*/
+    public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
+						   int maxFlows) {
+	return FlowDatabaseOperation.getAllFlowsSummary(dbHandler, flowId,
+							maxFlows);
     }
     
     /**
-     * Get all installed flows by all installers.
-     *
-     * @return the Flow Paths if found, otherwise null.
-     */
-    @Override
-    public ArrayList<FlowPath> getAllFlows() {
-	Iterable<IFlowPath> flowPathsObj = null;
-	ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
-
-	try {
-	    if ((flowPathsObj = op.getAllFlowPaths()) != null) {
-		log.debug("Get all FlowPaths: found FlowPaths");
-	    } else {
-		log.debug("Get all FlowPaths: no FlowPaths found");
-	    }
-	} catch (Exception e) {
-	    // TODO: handle exceptions
-	    op.rollback();
-	    log.error(":getAllFlowPaths failed");
-	}
-	if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
-	    op.commit();
-	    return flowPaths;	// No Flows found
-	}
-
-	for (IFlowPath flowObj : flowPathsObj) {
-	    //
-	    // Extract the Flow state
-	    //
-	    FlowPath flowPath = extractFlowPath(flowObj);
-	    if (flowPath != null)
-		flowPaths.add(flowPath);
-	}
-
-	op.commit();
-
-	return flowPaths;
-    }
-
-    /**
      * Get all Flows information, without the associated Flow Entries.
      *
      * @return all Flows information, without the associated Flow Entries.
      */
     public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
-    	Iterable<IFlowPath> flowPathsObj = null;
-    	ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
-
-    	op.commit();
-    	
-    	try {
-    	    if ((flowPathsObj = op.getAllFlowPaths()) != null) {
-    		log.debug("Get all FlowPaths: found FlowPaths");
-    	    } else {
-    		log.debug("Get all FlowPaths: no FlowPaths found");
-    	    }
-    	} catch (Exception e) {
-    	    // TODO: handle exceptions
-    	    op.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);
-    	}
-    	/*
-    	ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
-    	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.
-     *
-     * @param flowObj the object to extract the Flow Path State from.
-     * @return the extracted Flow Path State.
-     */
-    private FlowPath extractFlowPath(IFlowPath flowObj) {
-	//
-	// Extract the Flow state
-	//
-	String flowIdStr = flowObj.getFlowId();
-	String installerIdStr = flowObj.getInstallerId();
-	Long flowPathFlags = flowObj.getFlowPathFlags();
-	String srcSwitchStr = flowObj.getSrcSwitch();
-	Short srcPortShort = flowObj.getSrcPort();
-	String dstSwitchStr = flowObj.getDstSwitch();
-	Short dstPortShort = flowObj.getDstPort();
-
-	if ((flowIdStr == null) ||
-	    (installerIdStr == null) ||
-	    (flowPathFlags == null) ||
-	    (srcSwitchStr == null) ||
-	    (srcPortShort == null) ||
-	    (dstSwitchStr == null) ||
-	    (dstPortShort == null)) {
-	    // TODO: A work-around, becauuse of some bogus database objects
-	    return null;
-	}
-
-	FlowPath flowPath = new FlowPath();
-	flowPath.setFlowId(new FlowId(flowIdStr));
-	flowPath.setInstallerId(new CallerId(installerIdStr));
-	flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
-	flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
-	flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
-	flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
-	flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
-	//
-	// Extract the match conditions common for all Flow Entries
-	//
-	{
-	    FlowEntryMatch match = new FlowEntryMatch();
-	    String matchSrcMac = flowObj.getMatchSrcMac();
-	    if (matchSrcMac != null)
-		match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
-	    String matchDstMac = flowObj.getMatchDstMac();
-	    if (matchDstMac != null)
-		match.enableDstMac(MACAddress.valueOf(matchDstMac));
-	    Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
-	    if (matchEthernetFrameType != null)
-		match.enableEthernetFrameType(matchEthernetFrameType);
-	    Short matchVlanId = flowObj.getMatchVlanId();
-	    if (matchVlanId != null)
-		match.enableVlanId(matchVlanId);
-	    Byte matchVlanPriority = flowObj.getMatchVlanPriority();
-	    if (matchVlanPriority != null)
-		match.enableVlanPriority(matchVlanPriority);
-	    String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
-	    if (matchSrcIPv4Net != null)
-		match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
-	    String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
-	    if (matchDstIPv4Net != null)
-		match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
-	    Byte matchIpProto = flowObj.getMatchIpProto();
-	    if (matchIpProto != null)
-		match.enableIpProto(matchIpProto);
-	    Byte matchIpToS = flowObj.getMatchIpToS();
-	    if (matchIpToS != null)
-		match.enableIpToS(matchIpToS);
-	    Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
-	    if (matchSrcTcpUdpPort != null)
-		match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
-	    Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
-	    if (matchDstTcpUdpPort != null)
-		match.enableDstTcpUdpPort(matchDstTcpUdpPort);
-
-	    flowPath.setFlowEntryMatch(match);
-	}
-	//
-	// Extract the actions for the first Flow Entry
-	//
-	{
-	    String actionsStr = flowObj.getActions();
-	    if (actionsStr != null) {
-		FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
-		flowPath.setFlowEntryActions(flowEntryActions);
-	    }
-	}
-
-	//
-	// Extract all Flow Entries
-	//
-	Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
-	for (IFlowEntry flowEntryObj : flowEntries) {
-	    FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
-	    if (flowEntry == null)
-		continue;
-	    flowPath.dataPath().flowEntries().add(flowEntry);
-	}
-
-	return flowPath;
-    }
-
-    /**
-     * 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));
-	String matchSrcMac = flowEntryObj.getMatchSrcMac();
-	if (matchSrcMac != null)
-	    match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
-	String matchDstMac = flowEntryObj.getMatchDstMac();
-	if (matchDstMac != null)
-	    match.enableDstMac(MACAddress.valueOf(matchDstMac));
-	Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
-	if (matchEthernetFrameType != null)
-	    match.enableEthernetFrameType(matchEthernetFrameType);
-	Short matchVlanId = flowEntryObj.getMatchVlanId();
-	if (matchVlanId != null)
-	    match.enableVlanId(matchVlanId);
-	Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
-	if (matchVlanPriority != null)
-	    match.enableVlanPriority(matchVlanPriority);
-	String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
-	if (matchSrcIPv4Net != null)
-	    match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
-	String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
-	if (matchDstIPv4Net != null)
-	    match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
-	Byte matchIpProto = flowEntryObj.getMatchIpProto();
-	if (matchIpProto != null)
-	    match.enableIpProto(matchIpProto);
-	Byte matchIpToS = flowEntryObj.getMatchIpToS();
-	if (matchIpToS != null)
-	    match.enableIpToS(matchIpToS);
-	Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
-	if (matchSrcTcpUdpPort != null)
-	    match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
-	Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
-	if (matchDstTcpUdpPort != null)
-	    match.enableDstTcpUdpPort(matchDstTcpUdpPort);
-	flowEntry.setFlowEntryMatch(match);
-
-	//
-	// Extract the actions
-	//
-	FlowEntryActions actions = new FlowEntryActions();
-	String actionsStr = flowEntryObj.getActions();
-	if (actionsStr != null)
-	    actions = new FlowEntryActions(actionsStr);
-	flowEntry.setFlowEntryActions(actions);
-	flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
-	flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
-	//
-	// TODO: Take care of FlowEntryErrorState.
-	//
-	return flowEntry;
+	return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandler);
     }
 
     /**
@@ -1680,311 +761,9 @@
      */
     public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
 				    IFlowEntry flowEntryObj) {
-	String flowEntryIdStr = flowEntryObj.getFlowEntryId();
-	if (flowEntryIdStr == null)
-	    return false;
-	FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
-	String userState = flowEntryObj.getUserState();
-	if (userState == null)
-	    return false;
-
-	//
-	// 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);
-	    return false;
-	}
-
-	//
-	// 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);
-
-	// Match the Incoming Port
-	Short matchInPort = flowEntryObj.getMatchInPort();
-	if (matchInPort != null) {
-	    match.setInputPort(matchInPort);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
-	}
-
-	// 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);
-	}
-
-	// 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 VLAN ID
-	Short matchVlanId = flowEntryObj.getMatchVlanId();
-	if (matchVlanId == null)
-	    matchVlanId = flowObj.getMatchVlanId();
-	if (matchVlanId != null) {
-	    match.setDataLayerVirtualLan(matchVlanId);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
-	}
-
-	// Match the VLAN priority
-	Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
-	if (matchVlanPriority == null)
-	    matchVlanPriority = flowObj.getMatchVlanPriority();
-	if (matchVlanPriority != null) {
-	    match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
-	}
-
-	// 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 IP protocol
-	Byte matchIpProto = flowEntryObj.getMatchIpProto();
-	if (matchIpProto == null)
-	    matchIpProto = flowObj.getMatchIpProto();
-	if (matchIpProto != null) {
-	    match.setNetworkProtocol(matchIpProto);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
-	}
-
-	// Match the IP ToS (DSCP field, 6 bits)
-	Byte matchIpToS = flowEntryObj.getMatchIpToS();
-	if (matchIpToS == null)
-	    matchIpToS = flowObj.getMatchIpToS();
-	if (matchIpToS != null) {
-	    match.setNetworkTypeOfService(matchIpToS);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
-	}
-
-	// Match the Source TCP/UDP port
-	Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
-	if (matchSrcTcpUdpPort == null)
-	    matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
-	if (matchSrcTcpUdpPort != null) {
-	    match.setTransportSource(matchSrcTcpUdpPort);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
-	}
-
-	// Match the Destination TCP/UDP port
-	Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
-	if (matchDstTcpUdpPort == null)
-	    matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
-	if (matchDstTcpUdpPort != null) {
-	    match.setTransportDestination(matchDstTcpUdpPort);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
-	}
-
-	//
-	// Fetch the actions
-	//
-	Short actionOutputPort = null;
-	List<OFAction> openFlowActions = new ArrayList<OFAction>();
-	int actionsLen = 0;
-	FlowEntryActions flowEntryActions = null;
-	String actionsStr = flowEntryObj.getActions();
-	if (actionsStr != null)
-	    flowEntryActions = new FlowEntryActions(actionsStr);
-	for (FlowEntryAction action : flowEntryActions.actions()) {
-	    ActionOutput actionOutput = action.actionOutput();
-	    ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
-	    ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
-	    ActionStripVlan actionStripVlan = action.actionStripVlan();
-	    ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
-	    ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
-	    ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
-	    ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
-	    ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
-	    ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
-	    ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
-	    ActionEnqueue actionEnqueue = action.actionEnqueue();
-
-	    if (actionOutput != null) {
-		actionOutputPort = actionOutput.port().value();
-		// XXX: The max length is hard-coded for now
-		OFActionOutput ofa =
-		    new OFActionOutput(actionOutput.port().value(),
-				       (short)0xffff);
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetVlanId != null) {
-		OFActionVirtualLanIdentifier ofa =
-		    new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetVlanPriority != null) {
-		OFActionVirtualLanPriorityCodePoint ofa =
-		    new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionStripVlan != null) {
-		if (actionStripVlan.stripVlan() == true) {
-		    OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
-		    openFlowActions.add(ofa);
-		    actionsLen += ofa.getLength();
-		}
-	    }
-
-	    if (actionSetEthernetSrcAddr != null) {
-		OFActionDataLayerSource ofa = 
-		    new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetEthernetDstAddr != null) {
-		OFActionDataLayerDestination ofa =
-		    new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetIPv4SrcAddr != null) {
-		OFActionNetworkLayerSource ofa =
-		    new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetIPv4DstAddr != null) {
-		OFActionNetworkLayerDestination ofa =
-		    new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetIpToS != null) {
-		OFActionNetworkTypeOfService ofa =
-		    new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetTcpUdpSrcPort != null) {
-		OFActionTransportLayerSource ofa =
-		    new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetTcpUdpDstPort != null) {
-		OFActionTransportLayerDestination ofa =
-		    new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionEnqueue != null) {
-		OFActionEnqueue ofa =
-		    new OFActionEnqueue(actionEnqueue.port().value(),
-					actionEnqueue.queueId());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-	}
-
-	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(openFlowActions)
-	    .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
-	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
-	//
-	log.debug("MEASUREMENT: Installing flow entry " + userState +
-		  " into switch DPID: " +
-		  mySwitch.getStringId() +
-		  " flowEntryId: " + flowEntryId.toString() +
-		  " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
-		  " inPort: " + matchInPort + " outPort: " + actionOutputPort
-		  );
-	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;
+	return FlowSwitchOperation.installFlowEntry(
+		floodlightProvider.getOFMessageFactory(),
+		messageDamper, mySwitch, flowObj, flowEntryObj);
     }
 
     /**
@@ -1997,309 +776,9 @@
      */
     public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
 				    FlowEntry flowEntry) {
-	//
-	// Create the OpenFlow Flow Modification Entry to push
-	//
-	OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
-	    .getMessage(OFType.FLOW_MOD);
-	long cookie = flowEntry.flowEntryId().value();
-
-	short flowModCommand = OFFlowMod.OFPFC_ADD;
-	if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
-	    flowModCommand = OFFlowMod.OFPFC_ADD;
-	} else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
-	    flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
-	} else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
-	    flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
-	} else {
-	    // Unknown user state. Ignore the entry
-	    log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
-		      flowEntry.flowEntryId().toString(),
-		      flowEntry.flowEntryUserState());
-	    return false;
-	}
-
-	//
-	// 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);
-	FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
-	FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
-
-	// Match the Incoming Port
-	Port matchInPort = flowEntryMatch.inPort();
-	if (matchInPort != null) {
-	    match.setInputPort(matchInPort.value());
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
-	}
-
-	// Match the Source MAC address
-	MACAddress matchSrcMac = flowEntryMatch.srcMac();
-	if ((matchSrcMac == null) && (flowPathMatch != null)) {
-	    matchSrcMac = flowPathMatch.srcMac();
-	}
-	if (matchSrcMac != null) {
-	    match.setDataLayerSource(matchSrcMac.toString());
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
-	}
-
-	// Match the Destination MAC address
-	MACAddress matchDstMac = flowEntryMatch.dstMac();
-	if ((matchDstMac == null) && (flowPathMatch != null)) {
-	    matchDstMac = flowPathMatch.dstMac();
-	}
-	if (matchDstMac != null) {
-	    match.setDataLayerDestination(matchDstMac.toString());
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
-	}
-
-	// Match the Ethernet Frame Type
-	Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
-	if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
-	    matchEthernetFrameType = flowPathMatch.ethernetFrameType();
-	}
-	if (matchEthernetFrameType != null) {
-	    match.setDataLayerType(matchEthernetFrameType);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
-	}
-
-	// Match the VLAN ID
-	Short matchVlanId = flowEntryMatch.vlanId();
-	if ((matchVlanId == null) && (flowPathMatch != null)) {
-	    matchVlanId = flowPathMatch.vlanId();
-	}
-	if (matchVlanId != null) {
-	    match.setDataLayerVirtualLan(matchVlanId);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
-	}
-
-	// Match the VLAN priority
-	Byte matchVlanPriority = flowEntryMatch.vlanPriority();
-	if ((matchVlanPriority == null) && (flowPathMatch != null)) {
-	    matchVlanPriority = flowPathMatch.vlanPriority();
-	}
-	if (matchVlanPriority != null) {
-	    match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
-	}
-
-	// Match the Source IPv4 Network prefix
-	IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
-	if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
-	    matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
-	}
-	if (matchSrcIPv4Net != null) {
-	    match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
-	}
-
-	// Natch the Destination IPv4 Network prefix
-	IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
-	if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
-	    matchDstIPv4Net = flowPathMatch.dstIPv4Net();
-	}
-	if (matchDstIPv4Net != null) {
-	    match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
-	}
-
-	// Match the IP protocol
-	Byte matchIpProto = flowEntryMatch.ipProto();
-	if ((matchIpProto == null) && (flowPathMatch != null)) {
-	    matchIpProto = flowPathMatch.ipProto();
-	}
-	if (matchIpProto != null) {
-	    match.setNetworkProtocol(matchIpProto);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
-	}
-
-	// Match the IP ToS (DSCP field, 6 bits)
-	Byte matchIpToS = flowEntryMatch.ipToS();
-	if ((matchIpToS == null) && (flowPathMatch != null)) {
-	    matchIpToS = flowPathMatch.ipToS();
-	}
-	if (matchIpToS != null) {
-	    match.setNetworkTypeOfService(matchIpToS);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
-	}
-
-	// Match the Source TCP/UDP port
-	Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
-	if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
-	    matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
-	}
-	if (matchSrcTcpUdpPort != null) {
-	    match.setTransportSource(matchSrcTcpUdpPort);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
-	}
-
-	// Match the Destination TCP/UDP port
-	Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
-	if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
-	    matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
-	}
-	if (matchDstTcpUdpPort != null) {
-	    match.setTransportDestination(matchDstTcpUdpPort);
-	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
-	}
-
-	//
-	// Fetch the actions
-	//
-	Short actionOutputPort = null;
-	List<OFAction> openFlowActions = new ArrayList<OFAction>();
-	int actionsLen = 0;
-	FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
-	//
-	for (FlowEntryAction action : flowEntryActions.actions()) {
-	    ActionOutput actionOutput = action.actionOutput();
-	    ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
-	    ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
-	    ActionStripVlan actionStripVlan = action.actionStripVlan();
-	    ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
-	    ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
-	    ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
-	    ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
-	    ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
-	    ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
-	    ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
-	    ActionEnqueue actionEnqueue = action.actionEnqueue();
-
-	    if (actionOutput != null) {
-		actionOutputPort = actionOutput.port().value();
-		// XXX: The max length is hard-coded for now
-		OFActionOutput ofa =
-		    new OFActionOutput(actionOutput.port().value(),
-				       (short)0xffff);
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetVlanId != null) {
-		OFActionVirtualLanIdentifier ofa =
-		    new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetVlanPriority != null) {
-		OFActionVirtualLanPriorityCodePoint ofa =
-		    new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionStripVlan != null) {
-		if (actionStripVlan.stripVlan() == true) {
-		    OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
-		    openFlowActions.add(ofa);
-		    actionsLen += ofa.getLength();
-		}
-	    }
-
-	    if (actionSetEthernetSrcAddr != null) {
-		OFActionDataLayerSource ofa = 
-		    new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetEthernetDstAddr != null) {
-		OFActionDataLayerDestination ofa =
-		    new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetIPv4SrcAddr != null) {
-		OFActionNetworkLayerSource ofa =
-		    new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetIPv4DstAddr != null) {
-		OFActionNetworkLayerDestination ofa =
-		    new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetIpToS != null) {
-		OFActionNetworkTypeOfService ofa =
-		    new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetTcpUdpSrcPort != null) {
-		OFActionTransportLayerSource ofa =
-		    new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionSetTcpUdpDstPort != null) {
-		OFActionTransportLayerDestination ofa =
-		    new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-
-	    if (actionEnqueue != null) {
-		OFActionEnqueue ofa =
-		    new OFActionEnqueue(actionEnqueue.port().value(),
-					actionEnqueue.queueId());
-		openFlowActions.add(ofa);
-		actionsLen += ofa.getLength();
-	    }
-	}
-
-	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(openFlowActions)
-	    .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
-	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.
-	    //
-	    // 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;
-	}
-	return true;
+	return FlowSwitchOperation.installFlowEntry(
+		floodlightProvider.getOFMessageFactory(),
+		messageDamper, mySwitch, flowPath, flowEntry);
     }
 
     /**
@@ -2318,39 +797,4 @@
 	//
 	return (installFlowEntry(mySwitch, flowPath, flowEntry));
     }
-
-    /**
-     * Install a Flow Entry on a remote controller.
-     *
-     * TODO: We need it now: Jono
-     * - For now it will make a REST call to the remote controller.
-     * - Internally, it needs to know the name of the remote controller.
-     *
-     * @param flowPath the flow path for the flow entry to install.
-     * @param flowEntry the flow entry to install.
-     * @return true on success, otherwise false.
-     */
-    public boolean installRemoteFlowEntry(FlowPath flowPath,
-					  FlowEntry flowEntry) {
-	// TODO: We need it now: Jono
-	//  - For now it will make a REST call to the remote controller.
-	//  - Internally, it needs to know the name of the remote controller.
-	return true;
-    }
-
-    /**
-     * Remove a flow entry on a remote controller.
-     *
-     * @param flowPath the flow path for the flow entry to remove.
-     * @param flowEntry the flow entry to remove.
-     * @return true on success, otherwise false.
-     */
-    public boolean removeRemoteFlowEntry(FlowPath flowPath,
-					 FlowEntry flowEntry) {
-	//
-	// The installRemoteFlowEntry() method implements both installation
-	// and removal of flow entries.
-	//
-	return (installRemoteFlowEntry(flowPath, flowEntry));
-    }
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowSwitchOperation.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowSwitchOperation.java
new file mode 100644
index 0000000..3eea1e1
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowSwitchOperation.java
@@ -0,0 +1,676 @@
+package net.onrc.onos.ofcontroller.flowmanager;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.util.MACAddress;
+import net.floodlightcontroller.util.OFMessageDamper;
+
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
+import net.onrc.onos.ofcontroller.util.*;
+import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
+
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFPacketOut;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.action.*;
+import org.openflow.protocol.factory.BasicFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class for performing Flow-related operations on the Switch.
+ */
+class FlowSwitchOperation {
+    private static Logger log = LoggerFactory.getLogger(FlowSwitchOperation.class);
+    //
+    // TODO: Values copied from elsewhere (class LearningSwitch).
+    // The local copy should go away!
+    //
+    public static final short PRIORITY_DEFAULT = 100;
+    public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0;	// infinity
+    public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0;	// infinite
+
+    /**
+     * Install a Flow Entry on a switch.
+     *
+     * @param messageFactory the OpenFlow message factory to use.
+     * @maram messageDamper the OpenFlow message damper to use.
+     * @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.
+     */
+    static boolean installFlowEntry(BasicFactory messageFactory,
+				    OFMessageDamper messageDamper,
+				    IOFSwitch mySwitch, IFlowPath flowObj,
+				    IFlowEntry flowEntryObj) {
+	String flowEntryIdStr = flowEntryObj.getFlowEntryId();
+	if (flowEntryIdStr == null)
+	    return false;
+	FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
+	String userState = flowEntryObj.getUserState();
+	if (userState == null)
+	    return false;
+
+	//
+	// Create the Open Flow Flow Modification Entry to push
+	//
+	OFFlowMod fm = (OFFlowMod)messageFactory.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);
+	    return false;
+	}
+
+	//
+	// 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);
+
+	// Match the Incoming Port
+	Short matchInPort = flowEntryObj.getMatchInPort();
+	if (matchInPort != null) {
+	    match.setInputPort(matchInPort);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
+	}
+
+	// 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);
+	}
+
+	// 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 VLAN ID
+	Short matchVlanId = flowEntryObj.getMatchVlanId();
+	if (matchVlanId == null)
+	    matchVlanId = flowObj.getMatchVlanId();
+	if (matchVlanId != null) {
+	    match.setDataLayerVirtualLan(matchVlanId);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
+	}
+
+	// Match the VLAN priority
+	Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
+	if (matchVlanPriority == null)
+	    matchVlanPriority = flowObj.getMatchVlanPriority();
+	if (matchVlanPriority != null) {
+	    match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
+	}
+
+	// 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 IP protocol
+	Byte matchIpProto = flowEntryObj.getMatchIpProto();
+	if (matchIpProto == null)
+	    matchIpProto = flowObj.getMatchIpProto();
+	if (matchIpProto != null) {
+	    match.setNetworkProtocol(matchIpProto);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
+	}
+
+	// Match the IP ToS (DSCP field, 6 bits)
+	Byte matchIpToS = flowEntryObj.getMatchIpToS();
+	if (matchIpToS == null)
+	    matchIpToS = flowObj.getMatchIpToS();
+	if (matchIpToS != null) {
+	    match.setNetworkTypeOfService(matchIpToS);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
+	}
+
+	// Match the Source TCP/UDP port
+	Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
+	if (matchSrcTcpUdpPort == null)
+	    matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
+	if (matchSrcTcpUdpPort != null) {
+	    match.setTransportSource(matchSrcTcpUdpPort);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
+	}
+
+	// Match the Destination TCP/UDP port
+	Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
+	if (matchDstTcpUdpPort == null)
+	    matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
+	if (matchDstTcpUdpPort != null) {
+	    match.setTransportDestination(matchDstTcpUdpPort);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
+	}
+
+	//
+	// Fetch the actions
+	//
+	Short actionOutputPort = null;
+	List<OFAction> openFlowActions = new ArrayList<OFAction>();
+	int actionsLen = 0;
+	FlowEntryActions flowEntryActions = null;
+	String actionsStr = flowEntryObj.getActions();
+	if (actionsStr != null)
+	    flowEntryActions = new FlowEntryActions(actionsStr);
+	for (FlowEntryAction action : flowEntryActions.actions()) {
+	    ActionOutput actionOutput = action.actionOutput();
+	    ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
+	    ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
+	    ActionStripVlan actionStripVlan = action.actionStripVlan();
+	    ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
+	    ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
+	    ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
+	    ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
+	    ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
+	    ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
+	    ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
+	    ActionEnqueue actionEnqueue = action.actionEnqueue();
+
+	    if (actionOutput != null) {
+		actionOutputPort = actionOutput.port().value();
+		// XXX: The max length is hard-coded for now
+		OFActionOutput ofa =
+		    new OFActionOutput(actionOutput.port().value(),
+				       (short)0xffff);
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetVlanId != null) {
+		OFActionVirtualLanIdentifier ofa =
+		    new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetVlanPriority != null) {
+		OFActionVirtualLanPriorityCodePoint ofa =
+		    new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionStripVlan != null) {
+		if (actionStripVlan.stripVlan() == true) {
+		    OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
+		    openFlowActions.add(ofa);
+		    actionsLen += ofa.getLength();
+		}
+	    }
+
+	    if (actionSetEthernetSrcAddr != null) {
+		OFActionDataLayerSource ofa = 
+		    new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetEthernetDstAddr != null) {
+		OFActionDataLayerDestination ofa =
+		    new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetIPv4SrcAddr != null) {
+		OFActionNetworkLayerSource ofa =
+		    new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetIPv4DstAddr != null) {
+		OFActionNetworkLayerDestination ofa =
+		    new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetIpToS != null) {
+		OFActionNetworkTypeOfService ofa =
+		    new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetTcpUdpSrcPort != null) {
+		OFActionTransportLayerSource ofa =
+		    new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetTcpUdpDstPort != null) {
+		OFActionTransportLayerDestination ofa =
+		    new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionEnqueue != null) {
+		OFActionEnqueue ofa =
+		    new OFActionEnqueue(actionEnqueue.port().value(),
+					actionEnqueue.queueId());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+	}
+
+	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(openFlowActions)
+	    .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
+	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
+	//
+	log.debug("MEASUREMENT: Installing flow entry " + userState +
+		  " into switch DPID: " +
+		  mySwitch.getStringId() +
+		  " flowEntryId: " + flowEntryId.toString() +
+		  " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
+		  " inPort: " + matchInPort + " outPort: " + actionOutputPort
+		  );
+	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;
+    }
+
+    /**
+     * Install a Flow Entry on a switch.
+     *
+     * @param messageFactory the OpenFlow message factory to use.
+     * @maram messageDamper the OpenFlow message damper to use.
+     * @param mySwitch the switch to install the Flow Entry into.
+     * @param flowPath the flow path for the flow entry to install.
+     * @param flowEntry the flow entry to install.
+     * @return true on success, otherwise false.
+     */
+    static boolean installFlowEntry(BasicFactory messageFactory,
+				    OFMessageDamper messageDamper,
+				    IOFSwitch mySwitch, FlowPath flowPath,
+				    FlowEntry flowEntry) {
+	//
+	// Create the OpenFlow Flow Modification Entry to push
+	//
+	OFFlowMod fm = (OFFlowMod)messageFactory.getMessage(OFType.FLOW_MOD);
+	long cookie = flowEntry.flowEntryId().value();
+
+	short flowModCommand = OFFlowMod.OFPFC_ADD;
+	if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
+	    flowModCommand = OFFlowMod.OFPFC_ADD;
+	} else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
+	    flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
+	} else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
+	    flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
+	} else {
+	    // Unknown user state. Ignore the entry
+	    log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
+		      flowEntry.flowEntryId().toString(),
+		      flowEntry.flowEntryUserState());
+	    return false;
+	}
+
+	//
+	// 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);
+	FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
+	FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
+
+	// Match the Incoming Port
+	Port matchInPort = flowEntryMatch.inPort();
+	if (matchInPort != null) {
+	    match.setInputPort(matchInPort.value());
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
+	}
+
+	// Match the Source MAC address
+	MACAddress matchSrcMac = flowEntryMatch.srcMac();
+	if ((matchSrcMac == null) && (flowPathMatch != null)) {
+	    matchSrcMac = flowPathMatch.srcMac();
+	}
+	if (matchSrcMac != null) {
+	    match.setDataLayerSource(matchSrcMac.toString());
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
+	}
+
+	// Match the Destination MAC address
+	MACAddress matchDstMac = flowEntryMatch.dstMac();
+	if ((matchDstMac == null) && (flowPathMatch != null)) {
+	    matchDstMac = flowPathMatch.dstMac();
+	}
+	if (matchDstMac != null) {
+	    match.setDataLayerDestination(matchDstMac.toString());
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
+	}
+
+	// Match the Ethernet Frame Type
+	Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
+	if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
+	    matchEthernetFrameType = flowPathMatch.ethernetFrameType();
+	}
+	if (matchEthernetFrameType != null) {
+	    match.setDataLayerType(matchEthernetFrameType);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
+	}
+
+	// Match the VLAN ID
+	Short matchVlanId = flowEntryMatch.vlanId();
+	if ((matchVlanId == null) && (flowPathMatch != null)) {
+	    matchVlanId = flowPathMatch.vlanId();
+	}
+	if (matchVlanId != null) {
+	    match.setDataLayerVirtualLan(matchVlanId);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
+	}
+
+	// Match the VLAN priority
+	Byte matchVlanPriority = flowEntryMatch.vlanPriority();
+	if ((matchVlanPriority == null) && (flowPathMatch != null)) {
+	    matchVlanPriority = flowPathMatch.vlanPriority();
+	}
+	if (matchVlanPriority != null) {
+	    match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
+	}
+
+	// Match the Source IPv4 Network prefix
+	IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
+	if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
+	    matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
+	}
+	if (matchSrcIPv4Net != null) {
+	    match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
+	}
+
+	// Natch the Destination IPv4 Network prefix
+	IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
+	if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
+	    matchDstIPv4Net = flowPathMatch.dstIPv4Net();
+	}
+	if (matchDstIPv4Net != null) {
+	    match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
+	}
+
+	// Match the IP protocol
+	Byte matchIpProto = flowEntryMatch.ipProto();
+	if ((matchIpProto == null) && (flowPathMatch != null)) {
+	    matchIpProto = flowPathMatch.ipProto();
+	}
+	if (matchIpProto != null) {
+	    match.setNetworkProtocol(matchIpProto);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
+	}
+
+	// Match the IP ToS (DSCP field, 6 bits)
+	Byte matchIpToS = flowEntryMatch.ipToS();
+	if ((matchIpToS == null) && (flowPathMatch != null)) {
+	    matchIpToS = flowPathMatch.ipToS();
+	}
+	if (matchIpToS != null) {
+	    match.setNetworkTypeOfService(matchIpToS);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
+	}
+
+	// Match the Source TCP/UDP port
+	Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
+	if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
+	    matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
+	}
+	if (matchSrcTcpUdpPort != null) {
+	    match.setTransportSource(matchSrcTcpUdpPort);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
+	}
+
+	// Match the Destination TCP/UDP port
+	Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
+	if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
+	    matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
+	}
+	if (matchDstTcpUdpPort != null) {
+	    match.setTransportDestination(matchDstTcpUdpPort);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
+	}
+
+	//
+	// Fetch the actions
+	//
+	Short actionOutputPort = null;
+	List<OFAction> openFlowActions = new ArrayList<OFAction>();
+	int actionsLen = 0;
+	FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
+	//
+	for (FlowEntryAction action : flowEntryActions.actions()) {
+	    ActionOutput actionOutput = action.actionOutput();
+	    ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
+	    ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
+	    ActionStripVlan actionStripVlan = action.actionStripVlan();
+	    ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
+	    ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
+	    ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
+	    ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
+	    ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
+	    ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
+	    ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
+	    ActionEnqueue actionEnqueue = action.actionEnqueue();
+
+	    if (actionOutput != null) {
+		actionOutputPort = actionOutput.port().value();
+		// XXX: The max length is hard-coded for now
+		OFActionOutput ofa =
+		    new OFActionOutput(actionOutput.port().value(),
+				       (short)0xffff);
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetVlanId != null) {
+		OFActionVirtualLanIdentifier ofa =
+		    new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetVlanPriority != null) {
+		OFActionVirtualLanPriorityCodePoint ofa =
+		    new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionStripVlan != null) {
+		if (actionStripVlan.stripVlan() == true) {
+		    OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
+		    openFlowActions.add(ofa);
+		    actionsLen += ofa.getLength();
+		}
+	    }
+
+	    if (actionSetEthernetSrcAddr != null) {
+		OFActionDataLayerSource ofa = 
+		    new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetEthernetDstAddr != null) {
+		OFActionDataLayerDestination ofa =
+		    new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetIPv4SrcAddr != null) {
+		OFActionNetworkLayerSource ofa =
+		    new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetIPv4DstAddr != null) {
+		OFActionNetworkLayerDestination ofa =
+		    new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetIpToS != null) {
+		OFActionNetworkTypeOfService ofa =
+		    new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetTcpUdpSrcPort != null) {
+		OFActionTransportLayerSource ofa =
+		    new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionSetTcpUdpDstPort != null) {
+		OFActionTransportLayerDestination ofa =
+		    new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+
+	    if (actionEnqueue != null) {
+		OFActionEnqueue ofa =
+		    new OFActionEnqueue(actionEnqueue.port().value(),
+					actionEnqueue.queueId());
+		openFlowActions.add(ofa);
+		actionsLen += ofa.getLength();
+	    }
+	}
+
+	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(openFlowActions)
+	    .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
+	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.
+	    //
+	    // 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;
+	}
+	return true;
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
index df11d6b..73f86b6 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
@@ -67,6 +67,13 @@
     FlowPath getFlow(FlowId flowId);
 
     /**
+     * Get all installed flows by all installers.
+     *
+     * @return the Flow Paths if found, otherwise null.
+     */
+    ArrayList<FlowPath> getAllFlows();
+
+    /**
      * Get all previously added flows by a specific installer for a given
      * data path endpoints.
      *
@@ -95,13 +102,6 @@
     ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows);
     
     /**
-     * Get all installed flows by all installers.
-     *
-     * @return the Flow Paths if found, otherwise null.
-     */
-    ArrayList<FlowPath> getAllFlows();
-
-    /**
      * Add and maintain a shortest-path flow.
      *
      * NOTE: The Flow Path argument does NOT contain all flow entries.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/ITopologyNetService.java b/src/main/java/net/onrc/onos/ofcontroller/topology/ITopologyNetService.java
index bd0ca38..9585366 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/ITopologyNetService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/ITopologyNetService.java
@@ -11,73 +11,72 @@
  */
 public interface ITopologyNetService extends IFloodlightService {
     /**
-     * Get the shortest path from a source to a destination.
-     *
-     * @param src the source in the shortest path computation.
-     * @param dest the destination in the shortest path computation.
-     * @return the data path with the computed shortest path if
-     * found, otherwise null.
-     */
-    DataPath getShortestPath(SwitchPort src, SwitchPort dest);
-
-    /**
      * Fetch the Switch and Ports info from the Titan Graph
      * and return it for fast access during the shortest path
      * computation.
      *
-     * After fetching the state, method @ref getTopoShortestPath()
+     * After fetching the state, method @ref getTopologyShortestPath()
      * can be used for fast shortest path computation.
      *
      * Note: There is certain cost to fetch the state, hence it should
      * be used only when there is a large number of shortest path
      * computations that need to be done on the same topology.
-     * Typically, a single call to @ref prepareShortestPathTopo()
+     * Typically, a single call to @ref newDatabaseTopology()
      * should be followed by a large number of calls to
-     * method @ref getTopoShortestPath().
-     * After the last @ref getTopoShortestPath() call,
-     * method @ref dropShortestPathTopo() should be used to release
+     * method @ref getTopologyShortestPath().
+     * After the last @ref getTopologyShortestPath() call,
+     * method @ref dropTopology() should be used to release
      * the internal state that is not needed anymore:
      *
-     *       Map<Long, ?> shortestPathTopo;
-     *       shortestPathTopo = prepareShortestPathTopo();
+     *       Topology topology = topologyManager.newDatabaseTopology();
      *       for (int i = 0; i < 10000; i++) {
-     *           dataPath = getTopoShortestPath(shortestPathTopo, ...);
+     *           dataPath = topologyManager.getTopologyShortestPath(topology, ...);
      *           ...
      *        }
-     *        dropShortestPathTopo(shortestPathTopo);
+     *        topologyManager.dropTopology(shortestPathTopo);
      *
-     * @return the Shortest Path info handler stored in a map.
+     * @return the allocated topology handler.
      */
-    Map<Long, ?> prepareShortestPathTopo();
+    Topology newDatabaseTopology();
 
     /**
-     * Release the state that was populated by
-     * method @ref prepareShortestPathTopo().
+     * Release the topology that was populated by
+     * method @ref newDatabaseTopology().
      *
-     * See the documentation for method @ref prepareShortestPathTopo()
+     * See the documentation for method @ref newDatabaseTopology()
      * for additional information and usage.
      *
-     * @param shortestPathTopo the Shortest Path info handler to release.
+     * @param topology the topology to release.
      */
-    void dropShortestPathTopo(Map<Long, ?> shortestPathTopo);
+    void dropTopology(Topology topology);
 
     /**
      * Get the shortest path from a source to a destination by
      * using the pre-populated local topology state prepared
-     * by method @ref prepareShortestPathTopo().
+     * by method @ref newDatabaseTopology().
      *
-     * See the documentation for method @ref prepareShortestPathTopo()
+     * See the documentation for method @ref newDatabaseTopology()
      * for additional information and usage.
      *
-     * @param shortestPathTopo the Shortest Path info handler
-     * to use.
+     * @param topology the topology handler to use.
      * @param src the source in the shortest path computation.
      * @param dest the destination in the shortest path computation.
      * @return the data path with the computed shortest path if
      * found, otherwise null.
      */
-    DataPath getTopoShortestPath(Map<Long, ?> shortestPathTopo,
-				 SwitchPort src, SwitchPort dest);
+    DataPath getTopologyShortestPath(Topology topology,
+				     SwitchPort src, SwitchPort dest);
+
+    /**
+     * Get the shortest path from a source to a destination by using
+     * the underlying database.
+     *
+     * @param src the source in the shortest path computation.
+     * @param dest the destination in the shortest path computation.
+     * @return the data path with the computed shortest path if
+     * found, otherwise null.
+     */
+    DataPath getDatabaseShortestPath(SwitchPort src, SwitchPort dest);
 
     /**
      * Test whether a route exists from a source to a destination.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/ShortestPath.java b/src/main/java/net/onrc/onos/ofcontroller/topology/ShortestPath.java
new file mode 100644
index 0000000..1133d3d
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/ShortestPath.java
@@ -0,0 +1,325 @@
+package net.onrc.onos.ofcontroller.topology;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+import net.onrc.onos.graph.GraphDBOperation;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
+import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
+import net.onrc.onos.ofcontroller.util.DataPath;
+import net.onrc.onos.ofcontroller.util.Dpid;
+import net.onrc.onos.ofcontroller.util.FlowEntry;
+import net.onrc.onos.ofcontroller.util.Port;
+import net.onrc.onos.ofcontroller.util.SwitchPort;
+
+import org.openflow.util.HexString;
+
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.Vertex;
+
+/**
+ * A class for implementing the Shortest Path in a topology.
+ */
+public class ShortestPath {
+    /**
+     * Get the shortest path from a source to a destination by
+     * using the pre-populated local topology state prepared
+     * by method @ref TopologyManager.newDatabaseTopology().
+     *
+     * For additional documentation and usage, see method
+     * @ref TopologyManager.newDatabaseTopology()
+     *
+     * @param topology the topology handler to use.
+     * @param src the source in the shortest path computation.
+     * @param dest the destination in the shortest path computation.
+     * @return the data path with the computed shortest path if
+     * found, otherwise null.
+     */
+    public static DataPath getTopologyShortestPath(
+		Topology topology,
+		SwitchPort src, SwitchPort dest) {
+	DataPath result_data_path = new DataPath();
+
+	// Initialize the source and destination in the data path to return
+	result_data_path.setSrcPort(src);
+	result_data_path.setDstPort(dest);
+
+	String dpid_src = src.dpid().toString();
+	String dpid_dest = dest.dpid().toString();
+
+	// Get the source vertex
+	Node v_src = topology.getNode(src.dpid().value());
+	if (v_src == null) {
+	    return null;		// Source vertex not found
+	}
+
+	// Get the destination vertex
+	Node v_dest = topology.getNode(dest.dpid().value());
+	if (v_dest == null) {
+	    return null;		// Destination vertex not found
+	}
+
+	//
+	// Test whether we are computing a path from/to the same DPID.
+	// If "yes", then just add a single flow entry in the return result.
+	//
+	if (dpid_src.equals(dpid_dest)) {
+	    FlowEntry flowEntry = new FlowEntry();
+	    flowEntry.setDpid(src.dpid());
+	    flowEntry.setInPort(src.port());
+	    flowEntry.setOutPort(dest.port());
+	    result_data_path.flowEntries().add(flowEntry);
+	    return result_data_path;
+	}
+
+	//
+	// Implement the Shortest Path computation by using Breath First Search
+	//
+	Set<Node> visitedSet = new HashSet<Node>();
+	Queue<Node> processingList = new LinkedList<Node>();
+	Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
+	processingList.add(v_src);
+	visitedSet.add(v_src);
+	Boolean path_found = false;
+	while (! processingList.isEmpty()) {
+	    Node nextVertex = processingList.poll();
+	    if (v_dest == nextVertex) {
+		path_found = true;
+		break;
+	    }
+	    for (Node.Link link : nextVertex.links.values()) {
+		Node child = link.neighbor;
+		if (! visitedSet.contains(child)) {
+		    previousVertexMap.put(child, link);
+		    visitedSet.add(child);
+		    processingList.add(child);
+		}
+	    }
+	}
+	if (! path_found)
+	    return null;		// No path found
+
+	// Collect the path as a list of links
+	List<Node.Link> resultPath = new LinkedList<Node.Link>();
+	Node previousVertex = v_dest;
+	while (! v_src.equals(previousVertex)) {
+	    Node.Link currentLink = previousVertexMap.get(previousVertex);
+	    resultPath.add(currentLink);
+	    previousVertex = currentLink.me;
+	}
+	Collections.reverse(resultPath);
+
+	//
+	// Loop through the result and prepare the return result
+	// as a list of Flow Entries.
+	//
+	Port inPort = new Port(src.port().value());
+	Port outPort;
+	for (Node.Link link: resultPath) {
+	    // Setup the outgoing port, and add the Flow Entry
+	    outPort = new Port(link.myPort);
+
+	    FlowEntry flowEntry = new FlowEntry();
+	    flowEntry.setDpid(new Dpid(link.me.nodeId));
+	    flowEntry.setInPort(inPort);
+	    flowEntry.setOutPort(outPort);
+	    result_data_path.flowEntries().add(flowEntry);
+
+	    // Setup the next incoming port
+	    inPort = new Port(link.neighborPort);
+	}
+	if (resultPath.size() > 0) {
+	    // Add the last Flow Entry
+	    FlowEntry flowEntry = new FlowEntry();
+	    flowEntry.setDpid(new Dpid(dest.dpid().value()));
+	    flowEntry.setInPort(inPort);
+	    flowEntry.setOutPort(dest.port());
+	    result_data_path.flowEntries().add(flowEntry);
+	}
+
+	if (result_data_path.flowEntries().size() > 0)
+	    return result_data_path;
+
+	return null;
+    }
+
+    /**
+     * Get the shortest path from a source to a destination by using
+     * the underlying Graph Database.
+     *
+     * @param dbHandler the Graph Database handler to use.
+     * @param src the source in the shortest path computation.
+     * @param dest the destination in the shortest path computation.
+     * @return the data path with the computed shortest path if
+     * found, otherwise null.
+     */
+    public static DataPath getDatabaseShortestPath(GraphDBOperation dbHandler,
+					     SwitchPort src, SwitchPort dest) {
+	DataPath result_data_path = new DataPath();
+
+	// Initialize the source and destination in the data path to return
+	result_data_path.setSrcPort(src);
+	result_data_path.setDstPort(dest);
+
+	String dpid_src = src.dpid().toString();
+	String dpid_dest = dest.dpid().toString();
+
+	// Get the source and destination switches
+	ISwitchObject srcSwitch =
+	    dbHandler.searchActiveSwitch(dpid_src);
+	ISwitchObject destSwitch =
+	    dbHandler.searchActiveSwitch(dpid_dest);
+	if (srcSwitch == null || destSwitch == null) {
+	    return null;
+	}
+
+	//
+	// Test whether we are computing a path from/to the same DPID.
+	// If "yes", then just add a single flow entry in the return result.
+	//
+	if (dpid_src.equals(dpid_dest)) {
+	    FlowEntry flowEntry = new FlowEntry();
+	    flowEntry.setDpid(src.dpid());
+	    flowEntry.setInPort(src.port());
+	    flowEntry.setOutPort(dest.port());
+	    result_data_path.flowEntries().add(flowEntry);
+	    dbHandler.commit();
+	    return result_data_path;
+	}
+
+	Vertex v_src = srcSwitch.asVertex();	
+	Vertex v_dest = destSwitch.asVertex();
+
+	//
+	// Implement the Shortest Path computation by using Breath First Search
+	//
+	Set<Vertex> visitedSet = new HashSet<Vertex>();
+	Queue<Vertex> processingList = new LinkedList<Vertex>();
+	Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
+
+	processingList.add(v_src);
+	visitedSet.add(v_src);
+	Boolean path_found = false;
+	while (! processingList.isEmpty()) {
+	    Vertex nextVertex = processingList.poll();
+	    if (v_dest.equals(nextVertex)) {
+		path_found = true;
+		break;
+	    }
+	    for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
+		// Ignore inactive ports
+		if (! parentPort.getProperty("state").toString().equals("ACTIVE"))
+			continue;
+
+		for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
+		    // Ignore inactive ports
+		    if (! childPort.getProperty("state").toString().equals("ACTIVE"))
+			continue;
+
+		    for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
+			// Ignore inactive switches
+			String state = child.getProperty("state").toString();
+			if (! state.equals(SwitchState.ACTIVE.toString()))
+			    continue;
+
+			if (! visitedSet.contains(child)) {
+			    previousVertexMap.put(parentPort, nextVertex);
+			    previousVertexMap.put(childPort, parentPort);
+			    previousVertexMap.put(child, childPort);
+			    visitedSet.add(child);
+			    processingList.add(child);
+			}
+		    }
+		}
+	    }
+	}
+	if (! path_found)
+	    return null;		// No path found
+
+	List<Vertex> resultPath = new LinkedList<Vertex>();
+	Vertex previousVertex = v_dest;
+	resultPath.add(v_dest);
+	while (! v_src.equals(previousVertex)) {
+	    Vertex currentVertex = previousVertexMap.get(previousVertex);
+	    resultPath.add(currentVertex);
+	    previousVertex = currentVertex;
+	}
+	Collections.reverse(resultPath);
+
+
+	//
+	// Loop through the result and prepare the return result
+	// as a list of Flow Entries.
+	//
+	long nodeId = 0;
+	short portId = 0;
+	Port inPort = new Port(src.port().value());
+	Port outPort = new Port();
+	int idx = 0;
+	for (Vertex v: resultPath) {
+	    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);
+	    }
+	    idx++;
+	    if (idx == 1) {
+		continue;
+	    }
+	    int mod = idx % 3;
+	    if (mod == 0) {
+		// Setup the incoming port
+		inPort = new Port(portId);
+		continue;
+	    }
+	    if (mod == 2) {
+		// Setup the outgoing port, and add the Flow Entry
+		outPort = new Port(portId);
+
+		FlowEntry flowEntry = new FlowEntry();
+		flowEntry.setDpid(new Dpid(nodeId));
+		flowEntry.setInPort(inPort);
+		flowEntry.setOutPort(outPort);
+		result_data_path.flowEntries().add(flowEntry);
+		continue;
+	    }
+	}
+	if (idx > 0) {
+	    // Add the last Flow Entry
+	    FlowEntry flowEntry = new FlowEntry();
+	    flowEntry.setDpid(new Dpid(nodeId));
+	    flowEntry.setInPort(inPort);
+	    flowEntry.setOutPort(dest.port());
+	    result_data_path.flowEntries().add(flowEntry);
+	}
+
+	dbHandler.commit();
+	if (result_data_path.flowEntries().size() > 0)
+	    return result_data_path;
+
+	return null;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java b/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java
new file mode 100644
index 0000000..a2f2c21
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java
@@ -0,0 +1,174 @@
+package net.onrc.onos.ofcontroller.topology;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.onrc.onos.graph.GraphDBOperation;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
+import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
+
+import org.openflow.util.HexString;
+
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.Vertex;
+
+/**
+ * A class for storing Node and Link information for fast computation
+ * of shortest paths.
+ */
+class Node {
+    /**
+     * A class for storing Link information for fast computation of shortest
+     * paths.
+     */
+    class Link {
+	public Node me;			// The node this link originates from
+	public Node neighbor;		// The neighbor node on the other side
+	public short myPort;		// Local port number for the link
+	public short neighborPort;	// Neighbor port number for the link
+
+	/**
+	 * Link constructor.
+	 *
+	 * @param me the node this link originates from.
+	 * @param the neighbor node on the other side of the link.
+	 * @param myPort local port number for the link.
+	 * @param neighborPort neighrobr port number for the link.
+	 */
+	public Link(Node me, Node neighbor, short myPort, short neighborPort) {
+	    this.me = me;
+	    this.neighbor = neighbor;
+	    this.myPort = myPort;
+	    this.neighborPort = neighborPort;
+	}
+    };
+
+    public long nodeId;			// The node ID
+    public HashMap<Short, Link> links;	// The links originating from this node
+
+    /**
+     * Node constructor.
+     *
+     * @param nodeId the node ID.
+     */
+    public Node(long nodeId) {
+	this.nodeId = nodeId;
+	links = new HashMap<Short, Link>();
+    }
+
+    /**
+     * Add a neighbor.
+     *
+     * A new link to the neighbor will be created. 
+     *
+     * @param neighbor the neighbor to add.
+     * @param myPort the local port number for the link to the neighbor.
+     * @param neighborPort the neighbor port number for the link.
+     */
+    public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
+	Link link = new Link(this, neighbor, myPort, neighborPort);
+	links.put(myPort, link);
+    }
+};
+
+/**
+ * A class for storing topology information.
+ */
+public class Topology {
+    private Map<Long, Node> nodesMap;	// The dpid->Node mapping
+
+    public Topology() {
+	nodesMap = new HashMap<Long, Node>();
+    }
+
+    /**
+     * Get a node for a give Node ID.
+     *
+     * @param nodeId the Node ID to use.
+     * @return the corresponding Node if found, otherwise null.
+     */
+    Node getNode(long nodeId) {
+	return nodesMap.get(nodeId);
+    }
+
+    /**
+     * Read topology state from the database.
+     *
+     * @param dbHandler the Graph Database handler to use.
+     */
+    public void readFromDatabase(GraphDBOperation dbHandler) {
+	//
+	// Fetch the relevant info from the Switch and Port vertices
+	// from the Titan Graph.
+	//
+	Iterable<ISwitchObject> activeSwitches = dbHandler.getActiveSwitches();
+	for (ISwitchObject switchObj : activeSwitches) {
+	    Vertex nodeVertex = switchObj.asVertex();
+	    //
+	    // The Switch info
+	    //
+	    String nodeDpid = nodeVertex.getProperty("dpid").toString();
+	    long nodeId = HexString.toLong(nodeDpid);
+	    Node me = nodesMap.get(nodeId);
+	    if (me == null) {
+		me = new Node(nodeId);
+		nodesMap.put(nodeId, me);
+	    }
+
+	    //
+	    // The local Port info
+	    //
+	    for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
+		// Ignore inactive ports
+		if (! myPortVertex.getProperty("state").toString().equals("ACTIVE"))
+		    continue;
+
+		short myPort = 0;
+		Object obj = myPortVertex.getProperty("number");
+		if (obj instanceof Short) {
+		    myPort = (Short)obj;
+		} else if (obj instanceof Integer) {
+		    Integer int_nodeId = (Integer)obj;
+		    myPort = int_nodeId.shortValue();
+		}
+
+		//
+		// The neighbor Port info
+		//
+		for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
+		    // Ignore inactive ports
+		    if (! neighborPortVertex.getProperty("state").toString().equals("ACTIVE"))
+			continue;
+
+		    short neighborPort = 0;
+		    obj = neighborPortVertex.getProperty("number");
+		    if (obj instanceof Short) {
+			neighborPort = (Short)obj;
+		    } else if (obj instanceof Integer) {
+			Integer int_nodeId = (Integer)obj;
+			neighborPort = int_nodeId.shortValue();
+		    }
+		    //
+		    // The neighbor Switch info
+		    //
+		    for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
+			// Ignore inactive switches
+			String state = neighborVertex.getProperty("state").toString();
+			if (! state.equals(SwitchState.ACTIVE.toString()))
+			    continue;
+
+			String neighborDpid = neighborVertex.getProperty("dpid").toString();
+			long neighborId = HexString.toLong(neighborDpid);
+			Node neighbor = nodesMap.get(neighborId);
+			if (neighbor == null) {
+			    neighbor = new Node(neighborId);
+			    nodesMap.put(neighborId, neighbor);
+			}
+			me.addNeighbor(neighbor, myPort, neighborPort);
+		    }
+		}
+	    }
+	}
+	dbHandler.commit();
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java b/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java
index 618ae39..81ff599 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java
@@ -1,99 +1,34 @@
 package net.onrc.onos.ofcontroller.topology;
 
-import java.util.Collections;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
-import java.util.Queue;
-import java.util.Set;
 
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+
+import net.onrc.onos.datagrid.IDatagridService;
 import net.onrc.onos.graph.GraphDBOperation;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
-import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
+import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
 import net.onrc.onos.ofcontroller.util.DataPath;
-import net.onrc.onos.ofcontroller.util.Dpid;
-import net.onrc.onos.ofcontroller.util.FlowEntry;
-import net.onrc.onos.ofcontroller.util.Port;
 import net.onrc.onos.ofcontroller.util.SwitchPort;
 
-import org.openflow.util.HexString;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.tinkerpop.blueprints.Direction;
-import com.tinkerpop.blueprints.Vertex;
-
-
-/**
- * A class for storing Node and Link information for fast computation
- * of shortest paths.
- */
-class Node {
-    /**
-     * A class for storing Link information for fast computation of shortest
-     * paths.
-     */
-    class Link {
-	public Node me;			// The node this link originates from
-	public Node neighbor;		// The neighbor node on the other side
-	public short myPort;		// Local port number for the link
-	public short neighborPort;	// Neighbor port number for the link
-
-	/**
-	 * Link constructor.
-	 *
-	 * @param me the node this link originates from.
-	 * @param the neighbor node on the other side of the link.
-	 * @param myPort local port number for the link.
-	 * @param neighborPort neighrobr port number for the link.
-	 */
-	public Link(Node me, Node neighbor, short myPort, short neighborPort) {
-	    this.me = me;
-	    this.neighbor = neighbor;
-	    this.myPort = myPort;
-	    this.neighborPort = neighborPort;
-	}
-    };
-
-    public long nodeId;			// The node ID
-    public HashMap<Short, Link> links;	// The links originating from this node
-
-    /**
-     * Node constructor.
-     *
-     * @param nodeId the node ID.
-     */
-    public Node(long nodeId) {
-	this.nodeId = nodeId;
-	links = new HashMap<Short, Link>();
-    }
-
-    /**
-     * Add a neighbor.
-     *
-     * A new link to the neighbor will be created. 
-     *
-     * @param neighbor the neighbor to add.
-     * @param myPort the local port number for the link to the neighbor.
-     * @param neighborPort the neighbor port number for the link.
-     */
-    public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
-	Link link = new Link(this, neighbor, myPort, neighborPort);
-	links.put(myPort, link);
-    }
-};
-
 /**
  * A class for implementing Topology Network Service.
  */
-public class TopologyManager implements ITopologyNetService {
-
-    /** The logger. */
+public class TopologyManager implements IFloodlightModule,
+					ITopologyNetService {
     private static Logger log = LoggerFactory.getLogger(TopologyManager.class);
-    
-    protected GraphDBOperation op;
+    protected IFloodlightProviderService floodlightProvider;
+
+    protected GraphDBOperation dbHandler;
 
 
     /**
@@ -113,6 +48,16 @@
     }
 
     /**
+     * Constructor for a given database operation handler.
+     *
+     * @param dbHandler the database operation handler to use for the
+     * initialization.
+     */
+    public TopologyManager(GraphDBOperation dbHandler) {
+	this.dbHandler = dbHandler;
+    }
+
+    /**
      * Init the module.
      *
      * @param config the database configuration file to use for
@@ -120,27 +65,93 @@
      */
     public void init(String config) {
 	try {
-	    op = new GraphDBOperation(config);
+	    dbHandler = new GraphDBOperation(config);
 	} catch (Exception e) {
 	    log.error(e.getMessage());
 	}
     }
 
     /**
-     * Close the service. It will close the corresponding database connection.
+     * Shutdown the Topology Manager operation.
      */
-    public void close() {
-	op.close();
+    public void finalize() {
+	close();
     }
 
     /**
-     * Set the database operation handler.
-     *
-     * @param init_op the database operation handler to use for the
-     * initialization.
+     * Close the service. It will close the corresponding database connection.
      */
-    public void setDbOperationHandler(GraphDBOperation init_op) {
-    	op = init_op;
+    public void close() {
+	dbHandler.close();
+    }
+
+    /**
+     * Get the collection of offered module services.
+     *
+     * @return the collection of offered module services.
+     */
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+        Collection<Class<? extends IFloodlightService>> l = 
+            new ArrayList<Class<? extends IFloodlightService>>();
+        l.add(ITopologyNetService.class);
+        return l;
+    }
+
+    /**
+     * Get the collection of implemented services.
+     *
+     * @return the collection of implemented services.
+     */
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService> 
+			       getServiceImpls() {
+        Map<Class<? extends IFloodlightService>,
+	    IFloodlightService> m = 
+            new HashMap<Class<? extends IFloodlightService>,
+	    IFloodlightService>();
+        m.put(ITopologyNetService.class, this);
+        return m;
+    }
+
+    /**
+     * Get the collection of modules this module depends on.
+     *
+     * @return the collection of modules this module depends on.
+     */
+    @Override
+    public Collection<Class<? extends IFloodlightService>> 
+                                                    getModuleDependencies() {
+	Collection<Class<? extends IFloodlightService>> l =
+	    new ArrayList<Class<? extends IFloodlightService>>();
+	l.add(IFloodlightProviderService.class);
+	l.add(INetworkGraphService.class);
+	l.add(IDatagridService.class);
+        return l;
+    }
+
+    /**
+     * Initialize the module.
+     *
+     * @param context the module context to use for the initialization.
+     */
+    @Override
+    public void init(FloodlightModuleContext context)
+	throws FloodlightModuleException {
+	floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
+
+	String conf = "";
+	this.init(conf);
+    }
+
+    /**
+     * Startup module operation.
+     *
+     * @param context the module context to use for the startup.
+     */
+    @Override
+    public void startUp(FloodlightModuleContext context) {
+
     }
 
     /**
@@ -148,248 +159,70 @@
      * and return it for fast access during the shortest path
      * computation.
      *
-     * After fetching the state, method @ref getTopoShortestPath()
+     * After fetching the state, method @ref getTopologyShortestPath()
      * can be used for fast shortest path computation.
      *
      * Note: There is certain cost to fetch the state, hence it should
      * be used only when there is a large number of shortest path
      * computations that need to be done on the same topology.
-     * Typically, a single call to @ref prepareShortestPathTopo()
+     * Typically, a single call to @ref newDatabaseTopology()
      * should be followed by a large number of calls to
-     * method @ref getTopoShortestPath().
-     * After the last @ref getTopoShortestPath() call,
-     * method @ref dropShortestPathTopo() should be used to release
+     * method @ref getTopologyShortestPath().
+     * After the last @ref getTopologyShortestPath() call,
+     * method @ref dropTopology() should be used to release
      * the internal state that is not needed anymore:
      *
-     *       Map<Long, ?> shortestPathTopo;
-     *       shortestPathTopo = prepareShortestPathTopo();
+     *       Topology topology = topologyManager.newDatabaseTopology();
      *       for (int i = 0; i < 10000; i++) {
-     *           dataPath = getTopoShortestPath(shortestPathTopo, ...);
+     *           dataPath = topologyManager.getTopologyShortestPath(topology, ...);
      *           ...
      *        }
-     *        dropShortestPathTopo(shortestPathTopo);
+     *        topologyManager.dropTopology(shortestPathTopo);
      *
-     * @return the Shortest Path info handler stored in a map.
+     * @return the allocated topology handler.
      */
-    public Map<Long, ?> prepareShortestPathTopo() {
-	Map<Long, Node> shortestPathTopo = new HashMap<Long, Node>();
+    public Topology newDatabaseTopology() {
+	Topology topology = new Topology();
+	topology.readFromDatabase(dbHandler);
 
-	//
-	// Fetch the relevant info from the Switch and Port vertices
-	// from the Titan Graph.
-	//
-	Iterable<ISwitchObject> nodes = op.getActiveSwitches();
-	for (ISwitchObject switchObj : nodes) {
-	    Vertex nodeVertex = switchObj.asVertex();
-	    //
-	    // The Switch info
-	    //
-	    String nodeDpid = nodeVertex.getProperty("dpid").toString();
-	    long nodeId = HexString.toLong(nodeDpid);
-	    Node me = shortestPathTopo.get(nodeId);
-	    if (me == null) {
-		me = new Node(nodeId);
-		shortestPathTopo.put(nodeId, me);
-	    }
-
-	    //
-	    // The local Port info
-	    //
-	    for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
-		// Ignore inactive ports
-		if (! myPortVertex.getProperty("state").toString().equals("ACTIVE"))
-		    continue;
-
-		short myPort = 0;
-		Object obj = myPortVertex.getProperty("number");
-		if (obj instanceof Short) {
-		    myPort = (Short)obj;
-		} else if (obj instanceof Integer) {
-		    Integer int_nodeId = (Integer)obj;
-		    myPort = int_nodeId.shortValue();
-		}
-
-		//
-		// The neighbor Port info
-		//
-		for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
-		    // Ignore inactive ports
-		    if (! neighborPortVertex.getProperty("state").toString().equals("ACTIVE"))
-			continue;
-
-		    short neighborPort = 0;
-		    obj = neighborPortVertex.getProperty("number");
-		    if (obj instanceof Short) {
-			neighborPort = (Short)obj;
-		    } else if (obj instanceof Integer) {
-			Integer int_nodeId = (Integer)obj;
-			neighborPort = int_nodeId.shortValue();
-		    }
-		    //
-		    // The neighbor Switch info
-		    //
-		    for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
-			// Ignore inactive switches
-			String state = neighborVertex.getProperty("state").toString();
-			if (! state.equals(SwitchState.ACTIVE.toString()))
-			    continue;
-
-			String neighborDpid = neighborVertex.getProperty("dpid").toString();
-			long neighborId = HexString.toLong(neighborDpid);
-			Node neighbor = shortestPathTopo.get(neighborId);
-			if (neighbor == null) {
-			    neighbor = new Node(neighborId);
-			    shortestPathTopo.put(neighborId, neighbor);
-			}
-			me.addNeighbor(neighbor, myPort, neighborPort);
-		    }
-		}
-	    }
-	}
-	op.commit();
-
-	return shortestPathTopo;
+	return topology;
     }
 
     /**
-     * Release the state that was populated by
-     * method @ref prepareShortestPathTopo().
+     * Release the topology that was populated by
+     * method @ref newDatabaseTopology().
      *
-     * See the documentation for method @ref prepareShortestPathTopo()
+     * See the documentation for method @ref newDatabaseTopology()
      * for additional information and usage.
      *
-     * @param shortestPathTopo the Shortest Path info handler to release.
+     * @param topology the topology to release.
      */
-    public void dropShortestPathTopo(Map<Long, ?> shortestPathTopo) {
-	shortestPathTopo = null;
+    public void dropTopology(Topology topology) {
+	topology = null;
     }
 
     /**
      * Get the shortest path from a source to a destination by
      * using the pre-populated local topology state prepared
-     * by method @ref prepareShortestPathTopo().
+     * by method @ref newDatabaseTopology().
      *
-     * See the documentation for method @ref prepareShortestPathTopo()
+     * See the documentation for method @ref newDatabaseTopology()
      * for additional information and usage.
      *
-     * @param shortestPathTopoHandler the Shortest Path info handler
-     * to use.
+     * @param topology the topology handler to use.
      * @param src the source in the shortest path computation.
      * @param dest the destination in the shortest path computation.
      * @return the data path with the computed shortest path if
      * found, otherwise null.
      */
-    public DataPath getTopoShortestPath(Map<Long, ?> shortestPathTopoHandler,
-					SwitchPort src, SwitchPort dest) {
-	@SuppressWarnings("unchecked")
-	Map<Long, Node> shortestPathTopo = (Map<Long, Node>)shortestPathTopoHandler;
-	DataPath result_data_path = new DataPath();
-
-	// Initialize the source and destination in the data path to return
-	result_data_path.setSrcPort(src);
-	result_data_path.setDstPort(dest);
-
-	String dpid_src = src.dpid().toString();
-	String dpid_dest = dest.dpid().toString();
-
-	// Get the source vertex
-	Node v_src = shortestPathTopo.get(src.dpid().value());
-	if (v_src == null) {
-	    return null;		// Source vertex not found
-	}
-
-	// Get the destination vertex
-	Node v_dest = shortestPathTopo.get(dest.dpid().value());
-	if (v_dest == null) {
-	    return null;		// Destination vertex not found
-	}
-
-	//
-	// Test whether we are computing a path from/to the same DPID.
-	// If "yes", then just add a single flow entry in the return result.
-	//
-	if (dpid_src.equals(dpid_dest)) {
-	    FlowEntry flowEntry = new FlowEntry();
-	    flowEntry.setDpid(src.dpid());
-	    flowEntry.setInPort(src.port());
-	    flowEntry.setOutPort(dest.port());
-	    result_data_path.flowEntries().add(flowEntry);
-	    return result_data_path;
-	}
-
-	//
-	// Implement the Shortest Path computation by using Breath First Search
-	//
-	Set<Node> visitedSet = new HashSet<Node>();
-	Queue<Node> processingList = new LinkedList<Node>();
-	Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
-	processingList.add(v_src);
-	visitedSet.add(v_src);
-	Boolean path_found = false;
-	while (! processingList.isEmpty()) {
-	    Node nextVertex = processingList.poll();
-	    if (v_dest == nextVertex) {
-		path_found = true;
-		break;
-	    }
-	    for (Node.Link link : nextVertex.links.values()) {
-		Node child = link.neighbor;
-		if (! visitedSet.contains(child)) {
-		    previousVertexMap.put(child, link);
-		    visitedSet.add(child);
-		    processingList.add(child);
-		}
-	    }
-	}
-	if (! path_found)
-	    return null;		// No path found
-
-	// Collect the path as a list of links
-	List<Node.Link> resultPath = new LinkedList<Node.Link>();
-	Node previousVertex = v_dest;
-	while (! v_src.equals(previousVertex)) {
-	    Node.Link currentLink = previousVertexMap.get(previousVertex);
-	    resultPath.add(currentLink);
-	    previousVertex = currentLink.me;
-	}
-	Collections.reverse(resultPath);
-
-	//
-	// Loop through the result and prepare the return result
-	// as a list of Flow Entries.
-	//
-	Port inPort = new Port(src.port().value());
-	Port outPort;
-	for (Node.Link link: resultPath) {
-	    // Setup the outgoing port, and add the Flow Entry
-	    outPort = new Port(link.myPort);
-
-	    FlowEntry flowEntry = new FlowEntry();
-	    flowEntry.setDpid(new Dpid(link.me.nodeId));
-	    flowEntry.setInPort(inPort);
-	    flowEntry.setOutPort(outPort);
-	    result_data_path.flowEntries().add(flowEntry);
-
-	    // Setup the next incoming port
-	    inPort = new Port(link.neighborPort);
-	}
-	if (resultPath.size() > 0) {
-	    // Add the last Flow Entry
-	    FlowEntry flowEntry = new FlowEntry();
-	    flowEntry.setDpid(new Dpid(dest.dpid().value()));
-	    flowEntry.setInPort(inPort);
-	    flowEntry.setOutPort(dest.port());
-	    result_data_path.flowEntries().add(flowEntry);
-	}
-
-	if (result_data_path.flowEntries().size() > 0)
-	    return result_data_path;
-
-	return null;
+    public DataPath getTopologyShortestPath(Topology topology,
+					    SwitchPort src, SwitchPort dest) {
+	return ShortestPath.getTopologyShortestPath(topology, src, dest);
     }
 
     /**
-     * Get the shortest path from a source to a destination.
+     * Get the shortest path from a source to a destination by using
+     * the underlying database.
      *
      * @param src the source in the shortest path computation.
      * @param dest the destination in the shortest path computation.
@@ -397,167 +230,8 @@
      * found, otherwise null.
      */
     @Override
-    public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
-	DataPath result_data_path = new DataPath();
-
-	// Initialize the source and destination in the data path to return
-	result_data_path.setSrcPort(src);
-	result_data_path.setDstPort(dest);
-
-	String dpid_src = src.dpid().toString();
-	String dpid_dest = dest.dpid().toString();
-
-	// Get the source and destination switches
-	ISwitchObject srcSwitch =
-	    op.searchActiveSwitch(dpid_src);
-	ISwitchObject destSwitch =
-	    op.searchActiveSwitch(dpid_dest);
-	if (srcSwitch == null || destSwitch == null) {
-	    return null;
-	}
-
-	//
-	// Test whether we are computing a path from/to the same DPID.
-	// If "yes", then just add a single flow entry in the return result.
-	//
-	if (dpid_src.equals(dpid_dest)) {
-	    FlowEntry flowEntry = new FlowEntry();
-	    flowEntry.setDpid(src.dpid());
-	    flowEntry.setInPort(src.port());
-	    flowEntry.setOutPort(dest.port());
-	    result_data_path.flowEntries().add(flowEntry);
-	    op.commit();
-	    return result_data_path;
-	}
-
-	Vertex v_src = srcSwitch.asVertex();	
-	Vertex v_dest = destSwitch.asVertex();
-
-	//
-	// Implement the Shortest Path computation by using Breath First Search
-	//
-	Set<Vertex> visitedSet = new HashSet<Vertex>();
-	Queue<Vertex> processingList = new LinkedList<Vertex>();
-	Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
-
-	processingList.add(v_src);
-	visitedSet.add(v_src);
-	Boolean path_found = false;
-	while (! processingList.isEmpty()) {
-	    Vertex nextVertex = processingList.poll();
-	    if (v_dest.equals(nextVertex)) {
-		path_found = true;
-		break;
-	    }
-	    for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
-		// Ignore inactive ports
-		if (! parentPort.getProperty("state").toString().equals("ACTIVE"))
-			continue;
-
-		for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
-		    // Ignore inactive ports
-		    if (! childPort.getProperty("state").toString().equals("ACTIVE"))
-			continue;
-
-		    for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
-			// Ignore inactive switches
-			String state = child.getProperty("state").toString();
-			if (! state.equals(SwitchState.ACTIVE.toString()))
-			    continue;
-
-			if (! visitedSet.contains(child)) {
-			    previousVertexMap.put(parentPort, nextVertex);
-			    previousVertexMap.put(childPort, parentPort);
-			    previousVertexMap.put(child, childPort);
-			    visitedSet.add(child);
-			    processingList.add(child);
-			}
-		    }
-		}
-	    }
-	}
-	if (! path_found)
-	    return null;		// No path found
-
-	List<Vertex> resultPath = new LinkedList<Vertex>();
-	Vertex previousVertex = v_dest;
-	resultPath.add(v_dest);
-	while (! v_src.equals(previousVertex)) {
-	    Vertex currentVertex = previousVertexMap.get(previousVertex);
-	    resultPath.add(currentVertex);
-	    previousVertex = currentVertex;
-	}
-	Collections.reverse(resultPath);
-
-
-	//
-	// Loop through the result and prepare the return result
-	// as a list of Flow Entries.
-	//
-	long nodeId = 0;
-	short portId = 0;
-	Port inPort = new Port(src.port().value());
-	Port outPort = new Port();
-	int idx = 0;
-	for (Vertex v: resultPath) {
-	    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);
-	    }
-	    idx++;
-	    if (idx == 1) {
-		continue;
-	    }
-	    int mod = idx % 3;
-	    if (mod == 0) {
-		// Setup the incoming port
-		inPort = new Port(portId);
-		continue;
-	    }
-	    if (mod == 2) {
-		// Setup the outgoing port, and add the Flow Entry
-		outPort = new Port(portId);
-
-		FlowEntry flowEntry = new FlowEntry();
-		flowEntry.setDpid(new Dpid(nodeId));
-		flowEntry.setInPort(inPort);
-		flowEntry.setOutPort(outPort);
-		result_data_path.flowEntries().add(flowEntry);
-		continue;
-	    }
-	}
-	if (idx > 0) {
-	    // Add the last Flow Entry
-	    FlowEntry flowEntry = new FlowEntry();
-	    flowEntry.setDpid(new Dpid(nodeId));
-	    flowEntry.setInPort(inPort);
-	    flowEntry.setOutPort(dest.port());
-	    result_data_path.flowEntries().add(flowEntry);
-	}
-
-	op.commit();
-	if (result_data_path.flowEntries().size() > 0)
-	    return result_data_path;
-
-	return null;
+    public DataPath getDatabaseShortestPath(SwitchPort src, SwitchPort dest) {
+	return ShortestPath.getDatabaseShortestPath(dbHandler, src, dest);
     }
 
     /**
@@ -569,7 +243,7 @@
      */
     @Override
     public Boolean routeExists(SwitchPort src, SwitchPort dest) {
-	DataPath dataPath = getShortestPath(src, dest);
+	DataPath dataPath = getDatabaseShortestPath(src, dest);
 	return (dataPath != null);
     }
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java b/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java
index a730719..1cb39b3 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/web/RouteResource.java
@@ -37,8 +37,9 @@
 	Port dstPort = new Port(Short.parseShort(dstPortStr));
         
 	DataPath result =
-	    topologyNetService.getShortestPath(new SwitchPort(srcDpid, srcPort),
-					       new SwitchPort(dstDpid, dstPort));
+	    topologyNetService.getDatabaseShortestPath(
+		new SwitchPort(srcDpid, srcPort),
+		new SwitchPort(dstDpid, dstPort));
 	if (result != null) {
 	    return result;
 	} else {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/DataPath.java b/src/main/java/net/onrc/onos/ofcontroller/util/DataPath.java
index e807b56..7c6597d 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/DataPath.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/DataPath.java
@@ -105,8 +105,8 @@
      * computation.
      *
      * NOTE: This method assumes the DataPath was created by
-     * using FlowManager::getShortestPath() so the inPort and outPort
-     * of the Flow Entries are set.
+     * using the TopologyManager shortest path computation, so the inPort
+     * and outPort of the Flow Entries are set.
      * NOTE: This method is a temporary solution and will be removed
      * in the future.
      *
diff --git a/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java b/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java
index 5a1549b..8a8779b 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java
@@ -15,10 +15,12 @@
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.restserver.IRestApiService;
+import net.onrc.onos.datagrid.IDatagridService;
 import net.onrc.onos.graph.GraphDBOperation;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
 import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
+import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
 import net.onrc.onos.ofcontroller.topology.TopologyManager;
 import net.onrc.onos.ofcontroller.util.*;
 
@@ -38,12 +40,14 @@
 /**
  * @author Toshio Koide
  */
+@Ignore
 @RunWith(PowerMockRunner.class)
-@PrepareForTest({FlowManager.class, GraphDBOperation.class, System.class, Executors.class})
+@PrepareForTest({FlowManager.class, FlowDatabaseOperation.class, GraphDBOperation.class, System.class, Executors.class})
 public class FlowManagerTest {
 	private static FloodlightModuleContext context;
 	private static IFloodlightProviderService floodlightProvider;
 	private static TopologyManager topologyManager;
+	private static IDatagridService datagridService;
 	private static IRestApiService restApi;
 	private static GraphDBOperation op;
 	
@@ -69,11 +73,14 @@
 		context = createMock(FloodlightModuleContext.class);
 		floodlightProvider = createMock(IFloodlightProviderService.class);
 		topologyManager = createMock(TopologyManager.class);
+		datagridService = createMock(IDatagridService.class);
 		restApi = createMock(IRestApiService.class);
 		op = createMock(GraphDBOperation.class);
 
 		// setup expectations
 		expect(context.getServiceImpl(IFloodlightProviderService.class)).andReturn(floodlightProvider);
+		expect(context.getServiceImpl(ITopologyNetService.class)).andReturn(topologyManager);
+		expect(context.getServiceImpl(IDatagridService.class)).andReturn(datagridService);
 		expect(context.getServiceImpl(IRestApiService.class)).andReturn(restApi);
 		expectNew(GraphDBOperation.class, new Class<?>[] {String.class}, EasyMock.isA(String.class)).andReturn(op);
 		expectNew(TopologyManager.class, new Class<?>[] {String.class}, EasyMock.isA(String.class)).andReturn(topologyManager);
@@ -696,7 +703,7 @@
 
 		// verify the test
 		verifyAll();
-		assertEquals(2, md.size());
+		assertEquals(4, md.size());
 		assertTrue(md.contains(IFloodlightProviderService.class));
 		assertTrue(md.contains(IRestApiService.class));
 	}
@@ -976,22 +983,4 @@
 	public final void testRemoveFlowEntrySuccessNormally() {
 		fail("not yet implemented");
 	}
-
-	/**
-	 * Test method for {@link FlowManager#installRemoteFlowEntry(FlowPath, FlowEntry)}.
-	 * The method seems to be not implemented and not used for now.
-	 */
-	@Ignore @Test
-	public final void testInstallRemoteFlowEntrySuccessNormally() {
-		fail("not yet implemented");
-	}
-
-	/**
-	 * Test method for {@link FlowManager#removeRemoteFlowEntry(FlowPath, FlowEntry)}.
-	 * The method seems to be not implemented and not used for now.
-	 */
-	@Ignore @Test
-	public final void testRemoveRemoteFlowEntrySuccessNormally() {
-		fail("not yet implemented");
-	}
 }
diff --git a/src/test/java/net/onrc/onos/ofcontroller/topology/TopologyManagerTest.java b/src/test/java/net/onrc/onos/ofcontroller/topology/TopologyManagerTest.java
index fbec59e..09d0a00 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/topology/TopologyManagerTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/topology/TopologyManagerTest.java
@@ -64,8 +64,7 @@
 	TestDatabaseManager.populateTestData(titanGraph);
 
 	// Prepare the TopologyManager instance
-	topologyManager = new TopologyManager();
-	topologyManager.setDbOperationHandler(oper);
+	topologyManager = new TopologyManager(oper);
     }
 
     /**
@@ -78,12 +77,12 @@
     }
 
     /**
-     * Test method TopologyManager.getTopoShortestPath()
+     * Test method TopologyManager.getTopologyShortestPath()
      *
-     * @see net.onrc.onos.ofcontroller.topology.TopologyManager#getTopoShortestPath
+     * @see net.onrc.onos.ofcontroller.topology.TopologyManager#getTopologyShortestPath
      */
     @Test
-    public void test_getTopoShortestPath() {
+    public void test_getTopologyShortestPath() {
 	DataPath dataPath = null;
 	String srcDpidStr = "00:00:00:00:00:00:0a:01";
 	String dstDpidStr = "00:00:00:00:00:00:0a:06";
@@ -103,11 +102,10 @@
 	//
 	// Test a valid Shortest-Path computation
 	//
-	Map<Long, ?> shortestPathTopo =
-	    topologyManager.prepareShortestPathTopo();
-	dataPath = topologyManager.getTopoShortestPath(shortestPathTopo,
-						       srcSwitchPort,
-						       dstSwitchPort);
+	Topology topology = topologyManager.newDatabaseTopology();
+	dataPath = topologyManager.getTopologyShortestPath(topology,
+							   srcSwitchPort,
+							   dstSwitchPort);
 	assertTrue(dataPath != null);
 	String dataPathSummaryStr = dataPath.dataPathSummary();
 	// System.out.println(dataPathSummaryStr);
@@ -134,21 +132,21 @@
 	String noSuchDpidStr = "ff:ff:00:00:00:00:0a:06";
 	Dpid noSuchDstDpid = new Dpid(noSuchDpidStr);
 	SwitchPort noSuchDstSwitchPort = new SwitchPort(noSuchDstDpid, dstPort);
-	dataPath = topologyManager.getTopoShortestPath(shortestPathTopo,
-						       srcSwitchPort,
-						       noSuchDstSwitchPort);
+	dataPath = topologyManager.getTopologyShortestPath(topology,
+							   srcSwitchPort,
+							   noSuchDstSwitchPort);
 	assertTrue(dataPath == null);
 
-	topologyManager.dropShortestPathTopo(shortestPathTopo);
+	topologyManager.dropTopology(topology);
     }
 
     /**
-     * Test method TopologyManager.getShortestPath()
+     * Test method TopologyManager.getDatabaseShortestPath()
      *
-     * @see net.onrc.onos.ofcontroller.routing.TopologyManager#getShortestPath
+     * @see net.onrc.onos.ofcontroller.routing.TopologyManager#getDatabaseShortestPath
      */
     @Test
-    public void test_getShortestPath() {
+    public void test_getDatabaseShortestPath() {
 	DataPath dataPath = null;
 	String srcDpidStr = "00:00:00:00:00:00:0a:01";
 	String dstDpidStr = "00:00:00:00:00:00:0a:06";
@@ -168,8 +166,8 @@
 	//
 	// Test a valid Shortest-Path computation
 	//
-	dataPath = topologyManager.getShortestPath(srcSwitchPort,
-						   dstSwitchPort);
+	dataPath = topologyManager.getDatabaseShortestPath(srcSwitchPort,
+							   dstSwitchPort);
 	assertTrue(dataPath != null);
 	String dataPathSummaryStr = dataPath.dataPathSummary();
 	// System.out.println(dataPathSummaryStr);
@@ -197,8 +195,8 @@
 	Dpid noSuchDstDpid = new Dpid(noSuchDpidStr);
 	SwitchPort noSuchDstSwitchPort = new SwitchPort(noSuchDstDpid, dstPort);
 
-	dataPath = topologyManager.getShortestPath(srcSwitchPort,
-						   noSuchDstSwitchPort);
+	dataPath = topologyManager.getDatabaseShortestPath(srcSwitchPort,
+							   noSuchDstSwitchPort);
 	assertTrue(dataPath == null);
     }