Merge in changes from master
diff --git a/README.md b/README.md
index b71b9aa..9f2c040 100644
--- a/README.md
+++ b/README.md
@@ -15,12 +15,12 @@
 
 0. Install custom jars and dependencies (needs to be run only once)
 
-    $ ./setup-local-maven.sh
+        $ ./setup-local-maven.sh
 
 1. Cleanly build ONOS
 
-    $ mvn clean
-    $ mvn compile
+        $ mvn clean
+        $ mvn compile
 
     NOTE: installing maven for the first time may switch java version
     from 1.7 to 1.6. This might prevent Cassandra to run.
@@ -28,17 +28,19 @@
 Dependencies
 ------------
 1. Zookeeper
+
     Download and install apache-zookeeper-3.4.5:
     http://zookeeper.apache.org/releases.html
 
-    Edit file (ONOS-INSTALL-DIR)/start-zk.sh and set variable "ZK_DIR"
+    Edit file `(ONOS-INSTALL-DIR)/start-zk.sh` and set variable "ZK_DIR"
     to point to the Zookeeper directory.
 
 2. Cassandra
+
     Download and install apache-cassandra-1.2.4:
     http://cassandra.apache.org/download/
 
-    Edit file (ONOS-INSTALL-DIR)/start-cassandra.sh and set variable
+    Edit file `(ONOS-INSTALL-DIR)/start-cassandra.sh` and set variable
     "CASSANDRA_DIR" to point to the Cassandra directory.
 
 Running ONOS with Cassandra as a separate process
@@ -47,62 +49,62 @@
 
 1. Start Zookeeper
 
-    $ cd (ONOS-INSTALL-DIR)/
-    $ ./start-zk.sh start
+        $ cd (ONOS-INSTALL-DIR)/
+        $ ./start-zk.sh start
 
-    ## Confirm Zookeeper is running:
-    $ ./start.zk.sh status
+        ## Confirm Zookeeper is running:
+        $ ./start.zk.sh status
 
 2. Start Cassandra
 
-    $ cd (ONOS-INSTALL-DIR)/
-    $ ./start-cassandra.sh start
+        $ cd (ONOS-INSTALL-DIR)/
+        $ ./start-cassandra.sh start
 
-    ## Confirm Cassandra is running:
-    $ ./start-cassandra.sh status
+        ## Confirm Cassandra is running:
+        $ ./start-cassandra.sh status
 
 3. Start ONOS
 
-    $ cd (ONOS-INSTALL-DIR)/
-    $ ./start-onos.sh start
+        $ cd (ONOS-INSTALL-DIR)/
+        $ ./start-onos.sh start
 
-    ## Confirm ONOS is running:
-    $ ./start-onos.sh status
-    
+        ## Confirm ONOS is running:
+        $ ./start-onos.sh status
+
 4. Start ONOS REST API server
 
-    $ cd (ONOS-INSTALL-DIR)/
-    $ ./start-rest.sh start
+        $ cd (ONOS-INSTALL-DIR)/
+        $ ./start-rest.sh start
 
-    ## Confirm the REST API server is running:
-    $ ./start-rest.sh status
+        ## Confirm the REST API server is running:
+        $ ./start-rest.sh status
 
 Running ONOS with Cassandra embedded (Optional)
 -----------------------------------------------
 
 1. Start Zookeeper
 
-    $ cd (ONOS-INSTALL-DIR)/
-    $ ./start-zk.sh start
+        $ cd (ONOS-INSTALL-DIR)/
+        $ ./start-zk.sh start
 
-    ## Confirm Zookeeper is running:
-    $ ./start.zk.sh status
-    
+        ## Confirm Zookeeper is running:
+        $ ./start.zk.sh status
+
 2. Start ONOS and Cassandra embedded
 
-    $ cd (ONOS-INSTALL_DIR)/
-    $ ./start-onos-embedded.sh start
+        $ cd (ONOS-INSTALL_DIR)/
+        $ ./start-onos-embedded.sh start
 
-    ## Confirm ONOS is running:
-    $ ./start-onos-embedded.sh status
-    
+        ## Confirm ONOS is running:
+        $ ./start-onos-embedded.sh status
+
 3. Start ONOS REST API server
 
-    $ cd (ONOS-INSTALL-DIR)/
-    $ ./start-rest.sh start
+        $ cd (ONOS-INSTALL-DIR)/
+        $ ./start-rest.sh start
 
-    ## Confirm the REST API server is running:
-    $ ./start-rest.sh status
+        ## Confirm the REST API server is running:
+        $ ./start-rest.sh status
 
 
 Running in offline mode (Optional)
@@ -110,9 +112,9 @@
 
 Maven is used to build and run ONOS. By default, maven tries to reach
 the repositories. The '-o' option can be given to the 'mvn' command to
-suppress this behavior. The MVN environmental variable can be used to
+suppress this behavior. The `MVN` environmental variable can be used to
 set additional options to the 'mvn' command used in ONOS.
 
 * Example: Running in offline mode
 
-    $ env MVN="mvn -o" ./start-onos.sh start
+        $ env MVN="mvn -o" ./start-onos.sh start
diff --git a/cluster-mgmt/bin/cho-link-failure.sh b/cluster-mgmt/bin/cho-link-failure.sh
index 6c5f128..4db887a 100755
--- a/cluster-mgmt/bin/cho-link-failure.sh
+++ b/cluster-mgmt/bin/cho-link-failure.sh
@@ -16,7 +16,6 @@
 dsh -w ${basename}1 "cd ONOS/scripts; ./all-linkup.sh"
 echo "clean up flow"
 dsh -w ${basename}1 "cd ONOS/web; ./delete_flow.py 1 100"
-dsh -w ${basename}1 "cd ONOS/web; ./clear_flow.py 1 100"
 sleep 1
 dsh -w ${basename}1 "cd ONOS/web; ./get_flow.py all"
 dsh "cd ONOS/scripts; ./delflow.sh"
diff --git a/cluster-mgmt/bin/demo-reset-hw.sh b/cluster-mgmt/bin/demo-reset-hw.sh
index 8c586f5..15f97e1 100755
--- a/cluster-mgmt/bin/demo-reset-hw.sh
+++ b/cluster-mgmt/bin/demo-reset-hw.sh
@@ -9,7 +9,6 @@
 
 echo "cleanup excess flows"
 $DIR/web/delete_flow.py 201 300
-$DIR/web/clear_flow.py 201 300
 echo "cleanup excess flows done"
 echo "Adding 200 flows"
 $DIR/web/add_flow.py -m onos -f $DIR/web/flowdef_demo_start.txt
diff --git a/cluster-mgmt/bin/test-link-failure.sh b/cluster-mgmt/bin/test-link-failure.sh
index 6c5f128..4db887a 100755
--- a/cluster-mgmt/bin/test-link-failure.sh
+++ b/cluster-mgmt/bin/test-link-failure.sh
@@ -16,7 +16,6 @@
 dsh -w ${basename}1 "cd ONOS/scripts; ./all-linkup.sh"
 echo "clean up flow"
 dsh -w ${basename}1 "cd ONOS/web; ./delete_flow.py 1 100"
-dsh -w ${basename}1 "cd ONOS/web; ./clear_flow.py 1 100"
 sleep 1
 dsh -w ${basename}1 "cd ONOS/web; ./get_flow.py all"
 dsh "cd ONOS/scripts; ./delflow.sh"
diff --git a/cluster-mgmt/template/onsdemo_edge_template.py b/cluster-mgmt/template/onsdemo_edge_template.py
index e340f38..c3d0287 100755
--- a/cluster-mgmt/template/onsdemo_edge_template.py
+++ b/cluster-mgmt/template/onsdemo_edge_template.py
@@ -65,7 +65,7 @@
             switch.append(sw)
 
         for i in range (NR_NODES):
-            host.append(self.addHost( 'host%d' % (int(i)+1) ))
+            host.append(self.addHost( 'host%d.%d' % (NWID, int(i)+1) ))
 
         for i in range (NR_NODES):
             self.addLink(host[i], switch[i])
@@ -117,7 +117,7 @@
 
     host = []
     for i in range (NR_NODES):
-      host.append(net.get( 'host%d' % (int(i)+1) ))
+      host.append(net.get( 'host%d.%d' % (NWID, (int(i)+1)) ))
 
     net.start()
 
diff --git a/conf/cassandra.titan b/conf/cassandra.titan
index c36ecc0..9a9b00f 100644
--- a/conf/cassandra.titan
+++ b/conf/cassandra.titan
@@ -2,6 +2,6 @@
 storage.hostname=localhost
 storage.keyspace=onos
 storage.connection-pool-size=4096
-storage.replication-factor=3
+storage.replication-factor=1
 storage.write-consistency-level=ALL
 storage.read-consistency-level=ONE
diff --git a/conf/hazelcast.titan b/conf/hazelcast.titan
new file mode 100644
index 0000000..d4719fa
--- /dev/null
+++ b/conf/hazelcast.titan
@@ -0,0 +1,2 @@
+storage.backend=hazelcastcache
+storage.directory=/tmp/cache
diff --git a/conf/hazelcast.xml b/conf/hazelcast.xml
index 11bef59..84c7354 100644
--- a/conf/hazelcast.xml
+++ b/conf/hazelcast.xml
@@ -101,5 +101,6 @@
 
   <properties>
     <property name="hazelcast.logging.type">slf4j</property>
+    <property name="hazelcast.version.check.enabled">false</property>
   </properties>
 </hazelcast>
diff --git a/conf/onos-embedded.properties b/conf/onos-embedded.properties
index 44af87f..ea70eac 100644
--- a/conf/onos-embedded.properties
+++ b/conf/onos-embedded.properties
@@ -2,9 +2,7 @@
 net.floodlightcontroller.threadpool.ThreadPool,\
 net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher, \
 net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\
-net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\
 net.floodlightcontroller.counter.CounterStore,\
-net.floodlightcontroller.perfmon.PktInProcessingTime,\
 net.floodlightcontroller.ui.web.StaticWebRoutable,\
 net.onrc.onos.datagrid.HazelcastDatagrid,\
 net.onrc.onos.ofcontroller.flowmanager.FlowManager,\
diff --git a/conf/onos.properties b/conf/onos.properties
index 00e6279..f1beb0f 100644
--- a/conf/onos.properties
+++ b/conf/onos.properties
@@ -2,9 +2,7 @@
 net.floodlightcontroller.threadpool.ThreadPool,\
 net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher, \
 net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\
-net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\
 net.floodlightcontroller.counter.CounterStore,\
-net.floodlightcontroller.perfmon.PktInProcessingTime,\
 net.floodlightcontroller.ui.web.StaticWebRoutable,\
 net.onrc.onos.datagrid.HazelcastDatagrid,\
 net.onrc.onos.ofcontroller.flowmanager.FlowManager,\
diff --git a/curator/curator-client-1.3.5-SNAPSHOT.jar b/curator/curator-client-1.3.5-SNAPSHOT.jar
new file mode 100644
index 0000000..c22d602
--- /dev/null
+++ b/curator/curator-client-1.3.5-SNAPSHOT.jar
Binary files differ
diff --git a/curator/curator-framework-1.3.5-SNAPSHOT.jar b/curator/curator-framework-1.3.5-SNAPSHOT.jar
new file mode 100644
index 0000000..1b89270
--- /dev/null
+++ b/curator/curator-framework-1.3.5-SNAPSHOT.jar
Binary files differ
diff --git a/curator/curator-recipes-1.3.5-SNAPSHOT.jar b/curator/curator-recipes-1.3.5-SNAPSHOT.jar
new file mode 100644
index 0000000..30efe51
--- /dev/null
+++ b/curator/curator-recipes-1.3.5-SNAPSHOT.jar
Binary files differ
diff --git a/curator/curator-x-discovery-1.3.5-SNAPSHOT.jar b/curator/curator-x-discovery-1.3.5-SNAPSHOT.jar
new file mode 100644
index 0000000..147417e
--- /dev/null
+++ b/curator/curator-x-discovery-1.3.5-SNAPSHOT.jar
Binary files differ
diff --git a/kryo2/pom.xml b/kryo2/pom.xml
index 1beb87d..788f952 100644
--- a/kryo2/pom.xml
+++ b/kryo2/pom.xml
@@ -7,7 +7,7 @@
   <version>2.22</version>
   <packaging>jar</packaging>
 
-  <name>kyro2</name>
+  <name>kryo2</name>
   <url>http://maven.apache.org</url>
 
   <properties>
diff --git a/lib/jamm-0.2.5.jar b/lib/jamm-0.2.5.jar
index e9baf75..ef8750d 100644
--- a/lib/jamm-0.2.5.jar
+++ b/lib/jamm-0.2.5.jar
Binary files differ
diff --git a/perf-scripts/flow-sync-perf.py b/perf-scripts/flow-sync-perf.py
new file mode 100755
index 0000000..f0af050
--- /dev/null
+++ b/perf-scripts/flow-sync-perf.py
@@ -0,0 +1,210 @@
+#!/usr/bin/python
+'''
+ Script that tests Flow Synchronizer performance
+ Author: Brian O'Connor <bocon@onlab.us>
+
+ Usage: 
+   1. Ensure that ONOS is running
+   2. sudo ./flow-sync-perf.sh <list of tests>
+      e.g. sudo ./flow-sync-perf.sh 1 10 100 1000 
+      or to run the default tests:
+      sudo ./flow-sync-perf.sh
+   3. Results are CSV files in a date stamped directory
+'''
+
+import csv
+import os
+import sys
+from time import sleep, strftime
+from subprocess import Popen, call, check_output, PIPE
+from mininet.net import Mininet
+from mininet.topo import SingleSwitchTopo
+from mininet.node import RemoteController
+from mininet.cli import CLI
+from mininet.log import setLogLevel
+try:
+  import pexpect
+except:
+  # install pexpect if it cannot be found and re-import
+  print '* Installing Pexpect'
+  call( 'apt-get install -y python-pexpect', stdout=PIPE, shell=True )
+  import pexpect
+
+ONOS_HOME = '..'
+ONOS_LOG = '%s/onos-logs/onos.%s.log' % ( ONOS_HOME, check_output( 'hostname').strip() )
+print "ONOS Log File:", ONOS_LOG
+
+# Verify that tcpkill is installed
+if not Popen( 'which tcpkill', stdout=PIPE, shell=True).communicate():
+  print '* Installing tcpkill'
+  call( 'apt-get install -y dsniff', stdout=PIPE, shell=True )
+
+# ----------------- Tests scenarios -------------------------
+def doNothing(n):
+  print "Doing nothing with %d flows..." % n
+
+def addFakeFlows(n):
+  print "Adding %d random flows to switch..." % n
+  for i in range( 1, (n+1) ):
+    a = i / (256*256) % 256
+    b = i / 256 % 256
+    c = i % 256
+    ip = '10.%d.%d.%d' % (a,b,c)
+    call( 'ovs-ofctl add-flow s1 "ip, nw_src=%s/32, idle_timeout=0, hard_timeout=0, cookie=%d, actions=output:2"' % ( ip, i ), shell=True )
+
+def delFlowsFromSwitch(n):
+  print "Removing all %d flows from switch..." % n
+  call( 'ovs-ofctl del-flows s1', shell=True )
+
+
+# ----------------- Utility Functions -------------------------
+def wait(time, msg=None):
+  if msg:
+    print msg,
+  for i in range(time):
+    sys.stdout.write('.')
+    sys.stdout.flush()
+    sleep(1)
+  print ". done"
+
+def startNet(net):
+  tail = pexpect.spawn( 'tail -0f %s' % ONOS_LOG )
+  sleep(1) 
+  net.start()
+  print "Waiting for ONOS to detech the switch..."
+  index = tail.expect(['Sync time \(ms\)', pexpect.EOF, pexpect.TIMEOUT])
+  if index >= 1:
+    print '* ONOS not started'
+    net.stop()
+    exit(1)
+  tail.terminate()
+
+def dumpFlows():
+  return check_output( 'ovs-ofctl dump-flows s1', shell=True )
+
+def addFlowsToONOS(n):
+  print "Adding %d flows to ONOS" % n,
+  call( './generate_flows.py 1 %d > /tmp/flows.txt' % n, shell=True )
+  #call( '%s/web/add_flow.py -m onos -f /tmp/flows.txt' % ONOS_HOME, shell=True )
+  p = Popen( '%s/web/add_flow.py -m onos -f /tmp/flows.txt' % ONOS_HOME, shell=True )
+  while p.poll() is None:
+    sys.stdout.write('.')
+    sys.stdout.flush()
+    sleep(1)
+  print ". done\nWaiting for flow entries to be added to switch",
+  while True:
+    output = check_output( 'ovs-ofctl dump-flows s1', shell=True )
+    lines = len(output.split('\n'))
+    if lines >= (n+2):
+      break
+    sys.stdout.write('.')
+    sys.stdout.flush()
+    sleep(1)
+  print ". done\nWaiting for flow entries to be visible in network graph",
+  while True:
+    output = pexpect.spawn( '%s/web/get_flow.py all' % ONOS_HOME )
+    count = 0
+    while count < n:
+      if output.expect(['FlowEntry', pexpect.EOF], timeout=2000) == 1:
+        break
+      count += 1 
+      print '. done'
+      return
+    sys.stdout.write('.')
+    sys.stdout.flush()
+    sleep(5)
+
+def removeFlowsFromONOS(checkSwitch=True):
+  print "Removing all flows from ONOS",
+  #call( '%s/web/delete_flow.py all' % ONOS_HOME, shell=True )
+  p = Popen( '%s/web/delete_flow.py all' % ONOS_HOME, shell=True )
+  while p.poll() is None:
+    sys.stdout.write('.')
+    sys.stdout.flush()
+    sleep(1)
+  print ". done"
+  if checkSwitch:
+    print "Waiting for flow entries to be removed from switch",
+    while True:
+      output = check_output( 'ovs-ofctl dump-flows s1', shell=True )
+      lines = len(output.split('\n'))
+      if lines == 2:
+        break
+      sys.stdout.write('.')
+      sys.stdout.flush()
+      sleep(1)
+    print ". done"
+  print "Waiting for flow entries to be removed from network graph",
+  while True:
+    output = pexpect.spawn( '%s/web/get_flow.py all' % ONOS_HOME )
+    if output.expect(['FlowEntry', pexpect.EOF], timeout=2000) == 1:
+      break
+    sys.stdout.write('.')
+    sys.stdout.flush()
+    sleep(5)
+  print '. done'
+
+# ----------------- Running the test and output  -------------------------
+def test(i, fn):
+  # Start tailing the onos log
+  tail = pexpect.spawn( "tail -0f %s" % ONOS_LOG )
+  # disconnect the switch from the controller using tcpkill
+  tcp  = Popen( 'exec tcpkill -i lo -9 port 6633 > /dev/null 2>&1', shell=True )
+  # wait until the switch has been disconnected
+  tail.expect( 'Switch removed' )
+  # call the test function
+  fn(i) 
+  # dump to flows to ensure they have all made it to ovs
+  dumpFlows() 
+  # end tcpkill process to reconnect the switch to the controller
+  tcp.terminate()
+  tail.expect('Sync time \(ms\):', timeout=6000)
+  tail.expect('([\d.]+,?)+\s')
+  print "* Results:", tail.match.group(0)
+  tail.terminate()
+  wait(3, "Waiting for 3 seconds between tests")
+  return tail.match.group(0).strip().split(',')
+
+def initResults(files):
+  headers = ['# of FEs', 'Flow IDs from Graph', 'FEs from Switch', 'Compare', 
+             'Read FE from graph', 'Extract FE', 'Push', 'Total' ]
+  for filename in files.values():
+    with open(filename, 'w') as csvfile:
+      writer = csv.writer(csvfile)
+      writer.writerow(headers)
+
+def outputResults(filename, n, results):
+  results.insert(0, n)
+  with open(filename, 'a') as csvfile:
+    writer = csv.writer(csvfile)
+    writer.writerow(results)
+
+def runPerf( resultDir, tests):
+  fileMap = { 'add':    os.path.join(resultDir, 'add.csv'),
+              'delete': os.path.join(resultDir, 'delete.csv'),
+              'sync':   os.path.join(resultDir, 'sync.csv') }
+  initResults(fileMap)
+  removeFlowsFromONOS(checkSwitch=False) # clear ONOS before starting
+  # start Mininet
+  topo = SingleSwitchTopo()
+  net = Mininet(topo=topo, controller=RemoteController)
+  print "Starting Mininet"
+  startNet(net)
+  wait(30, "Give ONOS 30 seconds to warm up") # let ONOS "warm-up"
+  for i in tests:
+    addFlowsToONOS(i)
+    outputResults(fileMap['sync'],   i, test(i, doNothing))
+    outputResults(fileMap['delete'], i, test(i, delFlowsFromSwitch))
+    removeFlowsFromONOS()
+    outputResults(fileMap['add'],    i, test(i, addFakeFlows)) # test needs empty DB
+  net.stop()
+
+if __name__ == '__main__':
+  setLogLevel( 'output' )
+  resultDir = strftime( '%Y%m%d-%H%M%S' )
+  os.mkdir( resultDir )
+  tests = sys.argv[1:]
+  if not tests:
+    tests = [1, 10, 100, 1000, 10000]
+  runPerf( resultDir, tests )
+
diff --git a/perf-scripts/generate_flows.py b/perf-scripts/generate_flows.py
new file mode 100755
index 0000000..11d9c19
--- /dev/null
+++ b/perf-scripts/generate_flows.py
@@ -0,0 +1,90 @@
+#! /usr/bin/env python
+# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
+
+#
+# A script for generating a number of flows.
+#
+# The output of the script should be saved to a file, and the flows from
+# that file should be added by the following command:
+#
+#   web/add_flow.py -f filename
+# 
+# NOTE: Currently, some of the parameters fo the flows are hard-coded,
+# and all flows are between same source and destination DPID and ports
+# (differentiated by different matchSrcMac and matchDstMac).
+#
+
+import copy
+import pprint
+import os
+import sys
+import subprocess
+import json
+import argparse
+import io
+import time
+
+## Global Var ##
+
+DEBUG=0
+pp = pprint.PrettyPrinter(indent=4)
+
+## Worker Functions ##
+def log_error(txt):
+  print '%s' % (txt)
+
+def debug(txt):
+  if DEBUG:
+    print '%s' % (txt)
+
+
+if __name__ == "__main__":
+  usage_msg = "Generate a number of flows by using a pre-defined template.\n"
+  usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "NOTE: This script is work-in-progress. Currently all flows are within same\n"
+  usage_msg = usage_msg + "pair of switch ports and contain auto-generated MAC-based matching conditions.\n"
+  usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "Usage: %s <begin-flow-id> <end-flow-id>\n" % (sys.argv[0])
+  usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "    The output should be saved to a file, and the flows should be installed\n"
+  usage_msg = usage_msg + "    by using the command './add_flow.py -f filename'\n"
+
+
+  # app.debug = False;
+
+  # Usage info
+  if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
+    print(usage_msg)
+    exit(0)
+
+  # Check arguments
+  if len(sys.argv) < 3:
+    log_error(usage_msg)
+    exit(1)
+
+  # Extract the arguments
+  begin_flow_id = int(sys.argv[1], 0)
+  end_flow_id = int(sys.argv[2], 0)
+  if begin_flow_id > end_flow_id:
+    log_error(usage_msg)
+    exit(1)
+
+  #
+  # Do the work
+  #
+  # NOTE: Currently, up to 65536 flows are supported.
+  # More flows can be supported by iterating by, say, iterating over some of
+  # the other bytes of the autogenereated source/destination MAC addresses.
+  #
+  flow_id = begin_flow_id
+  idx = 0
+  while flow_id <= end_flow_id:
+    mac3 = idx / 255
+    mac4 = idx % 255
+    str_mac3 = "%0.2x" % mac3
+    str_mac4 = "%0.2x" % mac4
+    src_mac = "00:00:" + str_mac3 + ":" + str_mac4 + ":00:00";
+    dst_mac = "00:01:" + str_mac3 + ":" + str_mac4 + ":00:00";
+    print "%s FOOBAR 00:00:00:00:00:00:00:01 1 00:00:00:00:00:00:00:01 2 matchSrcMac %s matchDstMac %s" % (flow_id, src_mac, dst_mac)
+    flow_id = flow_id + 1
+    idx = idx + 1
diff --git a/pom.xml b/pom.xml
index a8730a5..ebed868 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,7 +31,7 @@
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <powermock.version>1.5.1</powermock.version>
-    <restlet.version>2.1-RC1</restlet.version>
+    <restlet.version>2.1.4</restlet.version>
     <github.global.server>github</github.global.server>
   </properties>
   <build>
@@ -251,13 +251,11 @@
       <artifactId>frames</artifactId>
       <version>2.3.1</version>
     </dependency>
-    <!--
     <dependency>
       <groupId>com.tinkerpop.blueprints</groupId>
       <artifactId>blueprints-core</artifactId>
       <version>2.3.0</version>
     </dependency>
-    -->
     <dependency>
       <groupId>com.hazelcast</groupId>
       <artifactId>hazelcast</artifactId>
@@ -292,7 +290,7 @@
     <dependency>
       <groupId>ch.qos.logback</groupId>
       <artifactId>logback-classic</artifactId>
-      <version>1.0.0</version>
+      <version>1.0.13</version>
       <scope>runtime</scope>
     </dependency>
     <!-- Floodlight's dependencies -->
@@ -305,13 +303,13 @@
     <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
-      <version>13.0.1</version>
+      <version>14.0.1</version>
     </dependency>
     -->
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
-      <version>1.6.4</version>
+      <version>1.7.5</version>
     </dependency>
     <dependency>
       <groupId>org.restlet.jse</groupId>
@@ -336,12 +334,12 @@
     <dependency>
       <groupId>args4j</groupId>
       <artifactId>args4j</artifactId>
-      <version>2.0.16</version>
+      <version>2.0.25</version>
     </dependency>
     <dependency>
       <groupId>com.googlecode.concurrentlinkedhashmap</groupId>
       <artifactId>concurrentlinkedhashmap-lru</artifactId>
-      <version>1.3</version>
+      <version>1.4</version>
     </dependency>
     <!--<dependency>
       <groupId>org.python</groupId>
diff --git a/scripts/demo-reset-sw.sh b/scripts/demo-reset-sw.sh
index 65a2ff1..e6cabae 100755
--- a/scripts/demo-reset-sw.sh
+++ b/scripts/demo-reset-sw.sh
@@ -6,7 +6,6 @@
 $DIR/scripts/all-linkup.sh
 echo "Delete Flows"
 $DIR/web/delete_flow.py 201 300
-$DIR/web/clear_flow.py 201 300
 echo "Adding Flows"
 $DIR/web/add_flow.py -m onos -f $DIR/web/flowdef_demo_start.txt
 ssh -i ~/.ssh/onlabkey.pem  ${basename}5 'ONOS/start-onos.sh stop'
diff --git a/setup-local-maven.sh b/setup-local-maven.sh
index 371d50f..f8e00f8 100755
--- a/setup-local-maven.sh
+++ b/setup-local-maven.sh
@@ -7,10 +7,10 @@
 # Kryo2 workaround
 ${MVN} -f kryo2/pom.xml package exec:exec
 
-${MVN} install:install-file -Dfile=./lib/curator-framework-1.3.5-SNAPSHOT.jar -DgroupId=com.netflix.curator -DartifactId=curator-framework -Dversion=1.3.5-SNAPSHOT -Dpackaging=jar -DgeneratePom=true
-${MVN} install:install-file -Dfile=./lib/curator-client-1.3.5-SNAPSHOT.jar -DgroupId=com.netflix.curator -DartifactId=curator-client -Dversion=1.3.5-SNAPSHOT -Dpackaging=jar -DgeneratePom=true
-${MVN} install:install-file -Dfile=./lib/curator-recipes-1.3.5-SNAPSHOT.jar -DgroupId=com.netflix.curator -DartifactId=curator-recipes -Dversion=1.3.5-SNAPSHOT -Dpackaging=jar -DgeneratePom=true
-${MVN} install:install-file -Dfile=./lib/curator-x-discovery-1.3.5-SNAPSHOT.jar -DgroupId=com.netflix.curator -DartifactId=curator-x-discovery -Dversion=1.3.5-SNAPSHOT -Dpackaging=jar -DgeneratePom=true
+${MVN} install:install-file -Dfile=./curator/curator-framework-1.3.5-SNAPSHOT.jar -DgroupId=com.netflix.curator -DartifactId=curator-framework -Dversion=1.3.5-SNAPSHOT -Dpackaging=jar -DgeneratePom=true
+${MVN} install:install-file -Dfile=./curator/curator-client-1.3.5-SNAPSHOT.jar -DgroupId=com.netflix.curator -DartifactId=curator-client -Dversion=1.3.5-SNAPSHOT -Dpackaging=jar -DgeneratePom=true
+${MVN} install:install-file -Dfile=./curator/curator-recipes-1.3.5-SNAPSHOT.jar -DgroupId=com.netflix.curator -DartifactId=curator-recipes -Dversion=1.3.5-SNAPSHOT -Dpackaging=jar -DgeneratePom=true
+${MVN} install:install-file -Dfile=./curator/curator-x-discovery-1.3.5-SNAPSHOT.jar -DgroupId=com.netflix.curator -DartifactId=curator-x-discovery -Dversion=1.3.5-SNAPSHOT -Dpackaging=jar -DgeneratePom=true
 
 # download package dependencies
 ${MVN} dependency:go-offline
diff --git a/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java b/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java
index 3541fc9..cbc8c7c 100644
--- a/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java
+++ b/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java
@@ -11,9 +11,9 @@
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.counter.ICounterStoreService;
-import net.floodlightcontroller.perfmon.IPktInProcessingTimeService;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
 import net.onrc.onos.registry.controller.IControllerRegistryService;
 
 public class FloodlightProvider implements IFloodlightModule {
@@ -44,20 +44,18 @@
     public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
         Collection<Class<? extends IFloodlightService>> dependencies =
             new ArrayList<Class<? extends IFloodlightService>>(5);
-        dependencies.add(IPktInProcessingTimeService.class);
         dependencies.add(IRestApiService.class);
         dependencies.add(ICounterStoreService.class);
         dependencies.add(IThreadPoolService.class);
         // Following added by ONOS
         dependencies.add(IControllerRegistryService.class);
+        dependencies.add(ILinkDiscoveryService.class);
 
         return dependencies;
     }
 
     @Override
     public void init(FloodlightModuleContext context) throws FloodlightModuleException {
-       controller.setPktInProcessingService(
-           context.getServiceImpl(IPktInProcessingTimeService.class));
        controller.setCounterStore(
            context.getServiceImpl(ICounterStoreService.class));
        controller.setRestApiService(
@@ -67,6 +65,8 @@
        // Following added by ONOS
        controller.setMastershipService(
     		   context.getServiceImpl(IControllerRegistryService.class));
+       controller.setLinkDiscoveryService(
+    		   context.getServiceImpl(ILinkDiscoveryService.class));
 
        controller.init(context.getConfigParams(this));
     }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index 084d6c4..70a53f5 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -62,10 +62,10 @@
 import net.floodlightcontroller.core.web.CoreWebRoutable;
 import net.floodlightcontroller.counter.ICounterStoreService;
 import net.floodlightcontroller.packet.Ethernet;
-import net.floodlightcontroller.perfmon.IPktInProcessingTimeService;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.onrc.onos.ofcontroller.core.IOFSwitchPortListener;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
 import net.onrc.onos.registry.controller.IControllerRegistryService;
 import net.onrc.onos.registry.controller.IControllerRegistryService.ControlChangeCallback;
 import net.onrc.onos.registry.controller.RegistryException;
@@ -171,10 +171,11 @@
     // Module dependencies
     protected IRestApiService restApi;
     protected ICounterStoreService counterStore = null;
-    protected IPktInProcessingTimeService pktinProcTime;
     protected IThreadPoolService threadPool;
     protected IControllerRegistryService registryService;
     
+    protected ILinkDiscoveryService linkDiscovery;
+    
     // Configuration options
     protected int openFlowPort = 6633;
     protected int workerThreads = 0;
@@ -332,9 +333,7 @@
         this.counterStore = counterStore;
     }
     
-    public void setPktInProcessingService(IPktInProcessingTimeService pits) {
-        this.pktinProcTime = pits;
-    }
+ 
     
     public void setRestApiService(IRestApiService restApi) {
         this.restApi = restApi;
@@ -348,6 +347,10 @@
 		this.registryService = serviceImpl;		
 	}
 	
+	public void setLinkDiscoveryService(ILinkDiscoveryService linkDiscovery) {
+		this.linkDiscovery = linkDiscovery;
+	}
+	
     @Override
     public Role getRole() {
         synchronized(roleChanger) {
@@ -1199,6 +1202,12 @@
                 //updatePortInfo(sw, port);
             log.debug("Port #{} modified for {}", portNumber, sw);
         } else if (m.getReason() == (byte)OFPortReason.OFPPR_ADD.ordinal()) {
+        	// XXX Workaround to prevent race condition where a link is detected
+        	// and attempted to be written to the database before the port is in
+        	// the database. We now suppress link discovery on ports until we're
+        	// sure they're in the database.
+        	linkDiscovery.AddToSuppressLLDPs(sw.getId(), port.getPortNumber());
+        	
             sw.setPort(port);
             SwitchUpdate update = new SwitchUpdate(sw, port, SwitchUpdateType.PORTADDED);
             try {
@@ -1337,8 +1346,7 @@
                     // Get the starting time (overall and per-component) of 
                     // the processing chain for this packet if performance
                     // monitoring is turned on
-                    pktinProcTime.bootstrap(listeners);
-                    pktinProcTime.recordStartTimePktIn();                     
+                    
                     Command cmd;
                     for (IOFMessageListener listener : listeners) {
                         if (listener instanceof IOFSwitchFilter) {
@@ -1347,15 +1355,15 @@
                             }
                         }
 
-                        pktinProcTime.recordStartTimeComp(listener);
+
                         cmd = listener.receive(sw, m, bc);
-                        pktinProcTime.recordEndTimeComp(listener);
+
                         
                         if (Command.STOP.equals(cmd)) {
                             break;
                         }
                     }
-                    pktinProcTime.recordEndTimePktIn(sw, m, bc);
+
                 } else {
                     log.warn("Unhandled OF Message: {} from {}", m, sw);
                 }
@@ -1442,6 +1450,14 @@
                     "network problem that can be ignored."
             )
     protected void addSwitch(IOFSwitch sw) {
+    	// XXX Workaround to prevent race condition where a link is detected
+    	// and attempted to be written to the database before the port is in
+    	// the database. We now suppress link discovery on ports until we're
+    	// sure they're in the database.
+    	for (OFPhysicalPort port : sw.getPorts()) {
+    		linkDiscovery.AddToSuppressLLDPs(sw.getId(), port.getPortNumber());
+    	}
+    	
         // TODO: is it safe to modify the HashMap without holding 
         // the old switch's lock?
         OFSwitchImpl oldSw = (OFSwitchImpl) this.activeSwitches.put(sw.getId(), sw);
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
index 5810967..1a52418 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
@@ -49,7 +49,7 @@
 import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
-import org.codehaus.jackson.map.ser.std.ToStringSerializer;
+import org.codehaus.jackson.map.ser.ToStringSerializer;
 import org.jboss.netty.channel.Channel;
 import org.openflow.protocol.OFFeaturesReply;
 import org.openflow.protocol.OFFeaturesRequest;
@@ -73,6 +73,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
 /**
  * This is the internal representation of an openflow switch.
  */
diff --git a/src/main/java/net/floodlightcontroller/core/types/MacVlanPair.java b/src/main/java/net/floodlightcontroller/core/types/MacVlanPair.java
deleted file mode 100644
index 7a44f1d..0000000
--- a/src/main/java/net/floodlightcontroller/core/types/MacVlanPair.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
-*    Copyright 2011, Big Switch Networks, Inc. 
-*    Originally created by David Erickson, Stanford University
-* 
-*    Licensed under the Apache License, Version 2.0 (the "License"); you may
-*    not use this file except in compliance with the License. You may obtain
-*    a copy of the License at
-*
-*         http://www.apache.org/licenses/LICENSE-2.0
-*
-*    Unless required by applicable law or agreed to in writing, software
-*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-*    License for the specific language governing permissions and limitations
-*    under the License.
-**/
-
-package net.floodlightcontroller.core.types;
-
-public class MacVlanPair {
-    public Long mac;
-    public Short vlan;
-    public MacVlanPair(Long mac, Short vlan) {
-        this.mac = mac;
-        this.vlan = vlan;
-    }
-    
-    public long getMac() {
-        return mac.longValue();
-    }
-    
-    public short getVlan() {
-        return vlan.shortValue();
-    }
-    
-    public boolean equals(Object o) {
-        return (o instanceof MacVlanPair) && (mac.equals(((MacVlanPair) o).mac))
-            && (vlan.equals(((MacVlanPair) o).vlan));
-    }
-    
-    public int hashCode() {
-        return mac.hashCode() ^ vlan.hashCode();
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/types/SwitchMessagePair.java b/src/main/java/net/floodlightcontroller/core/types/SwitchMessagePair.java
deleted file mode 100644
index 0e91bc9..0000000
--- a/src/main/java/net/floodlightcontroller/core/types/SwitchMessagePair.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
-*    Copyright 2011, Big Switch Networks, Inc. 
-*    Originally created by David Erickson, Stanford University
-* 
-*    Licensed under the Apache License, Version 2.0 (the "License"); you may
-*    not use this file except in compliance with the License. You may obtain
-*    a copy of the License at
-*
-*         http://www.apache.org/licenses/LICENSE-2.0
-*
-*    Unless required by applicable law or agreed to in writing, software
-*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-*    License for the specific language governing permissions and limitations
-*    under the License.
-**/
-
-package net.floodlightcontroller.core.types;
-
-import org.openflow.protocol.OFMessage;
-
-import net.floodlightcontroller.core.IOFSwitch;
-
-public class SwitchMessagePair {
-    private final IOFSwitch sw;
-    private final OFMessage msg;
-    
-    public SwitchMessagePair(IOFSwitch sw, OFMessage msg) {
-        this.sw = sw;
-        this.msg = msg;
-    }
-    
-    public IOFSwitch getSwitch() {
-        return this.sw;
-    }
-    
-    public OFMessage getMessage() {
-        return this.msg;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java b/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
index a014795..2eeec70 100644
--- a/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
@@ -24,8 +24,6 @@
 import java.util.Map;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
-import net.floodlightcontroller.core.types.MacVlanPair;
-
 import org.openflow.protocol.OFFeaturesReply;
 import org.openflow.protocol.statistics.OFStatistics;
 import org.openflow.protocol.statistics.OFStatisticsType;
@@ -136,7 +134,6 @@
         private OFStatisticsType statType;
         private REQUESTTYPE requestType;
         private OFFeaturesReply featuresReply;
-        private Map<MacVlanPair, Short> switchTable;
         
         public GetConcurrentStatsThread(long switchId, REQUESTTYPE requestType, OFStatisticsType statType) {
             this.switchId = switchId;
@@ -144,7 +141,6 @@
             this.statType = statType;
             this.switchReply = null;
             this.featuresReply = null;
-            this.switchTable = null;
         }
         
         public List<OFStatistics> getStatisticsReply() {
@@ -155,10 +151,6 @@
             return featuresReply;
         }
         
-        public Map<MacVlanPair, Short> getSwitchTable() {
-            return switchTable;
-        }
-        
         public long getSwitchId() {
             return switchId;
         }
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java b/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java
index 725d699..7426163 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java
@@ -20,7 +20,7 @@
 import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
 
 import org.codehaus.jackson.map.annotate.JsonSerialize;
-import org.codehaus.jackson.map.ser.std.ToStringSerializer;
+import org.codehaus.jackson.map.ser.ToStringSerializer;
 
 /**
  * A simple switch DPID/port pair
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
index 3fd109c..92e78b6 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
@@ -57,9 +57,6 @@
 import net.floodlightcontroller.devicemanager.IEntityClassifierService;
 import net.floodlightcontroller.devicemanager.SwitchPort;
 import net.floodlightcontroller.devicemanager.web.DeviceRoutable;
-import net.floodlightcontroller.flowcache.IFlowReconcileListener;
-import net.floodlightcontroller.flowcache.IFlowReconcileService;
-import net.floodlightcontroller.flowcache.OFMatchReconcile;
 import net.floodlightcontroller.packet.ARP;
 import net.floodlightcontroller.packet.DHCP;
 import net.floodlightcontroller.packet.Ethernet;
@@ -88,7 +85,7 @@
 public class DeviceManagerImpl implements
 IDeviceService, IOFMessageListener, ITopologyListener,
 IFloodlightModule, IEntityClassListener,
-IFlowReconcileListener, IInfoProvider, IHAListener {
+IInfoProvider, IHAListener {
     protected final static Logger logger =
             LoggerFactory.getLogger(DeviceManagerImpl.class);
 
@@ -96,7 +93,7 @@
     protected ITopologyService topology;
     protected IRestApiService restApi;
     protected IThreadPoolService threadPool;
-    protected IFlowReconcileService flowReconcileMgr;
+
 
     /**
      * Time in milliseconds before entities will expire
@@ -599,62 +596,7 @@
         return Command.CONTINUE;
     }
 
-    // ***************
-    // IFlowReconcileListener
-    // ***************
-    @Override
-    public Command reconcileFlows(ArrayList<OFMatchReconcile> ofmRcList) {
-        ListIterator<OFMatchReconcile> iter = ofmRcList.listIterator();
-        while (iter.hasNext()) {
-            OFMatchReconcile ofm = iter.next();
-            
-            // Remove the STOPPed flow.
-            if (Command.STOP == reconcileFlow(ofm)) {
-                iter.remove();
-            }
-        }
-        
-        if (ofmRcList.size() > 0) {
-            return Command.CONTINUE;
-        } else {
-            return Command.STOP;
-        }
-    }
-
-    protected Command reconcileFlow(OFMatchReconcile ofm) {
-        // Extract source entity information
-        Entity srcEntity =
-                getEntityFromFlowMod(ofm.ofmWithSwDpid, true);
-        if (srcEntity == null)
-            return Command.STOP;
-
-        // Find the device by source entity
-        Device srcDevice = findDeviceByEntity(srcEntity);
-        if (srcDevice == null)
-            return Command.STOP;
-
-        // Store the source device in the context
-        fcStore.put(ofm.cntx, CONTEXT_SRC_DEVICE, srcDevice);
-
-        // Find the device matching the destination from the entity
-        // classes of the source.
-        Entity dstEntity = getEntityFromFlowMod(ofm.ofmWithSwDpid, false);
-        Device dstDevice = null;
-        if (dstEntity != null) {
-            dstDevice = findDestByEntity(srcDevice, dstEntity);
-            if (dstDevice != null)
-                fcStore.put(ofm.cntx, CONTEXT_DST_DEVICE, dstDevice);
-        }
-        if (logger.isTraceEnabled()) {
-            logger.trace("Reconciling flow: match={}, srcEntity={}, srcDev={}, " 
-                         + "dstEntity={}, dstDev={}",
-                         new Object[] {ofm.ofmWithSwDpid.getOfMatch(),
-                                       srcEntity, srcDevice, 
-                                       dstEntity, dstDevice } );
-        }
-        return Command.CONTINUE;
-    }
-
+ 
     // *****************
     // IFloodlightModule
     // *****************
@@ -687,7 +629,6 @@
         l.add(ITopologyService.class);
         l.add(IRestApiService.class);
         l.add(IThreadPoolService.class);
-        l.add(IFlowReconcileService.class);
         l.add(IEntityClassifierService.class);
         return l;
     }
@@ -708,7 +649,6 @@
                 fmc.getServiceImpl(ITopologyService.class);
         this.restApi = fmc.getServiceImpl(IRestApiService.class);
         this.threadPool = fmc.getServiceImpl(IThreadPoolService.class);
-        this.flowReconcileMgr = fmc.getServiceImpl(IFlowReconcileService.class);
         this.entityClassifier = fmc.getServiceImpl(IEntityClassifierService.class);
     }
 
@@ -726,7 +666,6 @@
         floodlightProvider.addHAListener(this);
         if (topology != null)
             topology.addListener(this);
-        flowReconcileMgr.addFlowReconcileListener(this);
         entityClassifier.addListener(this);
 
         Runnable ecr = new Runnable() {
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FCQueryObj.java b/src/main/java/net/floodlightcontroller/flowcache/FCQueryObj.java
deleted file mode 100644
index cce3401..0000000
--- a/src/main/java/net/floodlightcontroller/flowcache/FCQueryObj.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package net.floodlightcontroller.flowcache;
-
-import java.util.Arrays;
-
-import net.floodlightcontroller.devicemanager.IDevice;
-import net.floodlightcontroller.flowcache.IFlowCacheService.FCQueryEvType;
-
-
-/**
- * The Class FCQueryObj.
- */
-public class FCQueryObj {
-
-    /** The caller of the flow cache query. */
-    public IFlowQueryHandler fcQueryHandler;
-    /** The application instance name. */
-    public String applInstName;
-    /** The vlan Id. */
-    public Short[] vlans;
-    /** The destination device. */
-    public IDevice dstDevice;
-    /** The source device. */
-    public IDevice srcDevice;
-    /** The caller name */
-    public String callerName;
-    /** Event type that triggered this flow query submission */
-    public FCQueryEvType evType;
-    /** The caller opaque data. Returned unchanged in the query response
-     * via the callback. The type of this object could be different for
-     * different callers */
-    public Object callerOpaqueObj;
-
-    /**
-     * Instantiates a new flow cache query object
-     */
-    public FCQueryObj(IFlowQueryHandler fcQueryHandler,
-            String        applInstName,
-            Short         vlan,
-            IDevice       srcDevice,
-            IDevice       dstDevice,
-            String        callerName,
-            FCQueryEvType evType,
-            Object        callerOpaqueObj) {
-        this.fcQueryHandler    = fcQueryHandler;
-        this.applInstName     = applInstName;
-        this.srcDevice        = srcDevice;
-        this.dstDevice        = dstDevice;
-        this.callerName       = callerName;
-        this.evType           = evType;
-        this.callerOpaqueObj  = callerOpaqueObj;
-        
-        if (vlan != null) {
-        	this.vlans = new Short[] { vlan };
-        } else {
-	        if (srcDevice != null) {
-	        	this.vlans = srcDevice.getVlanId();
-	        } else if (dstDevice != null) {
-	            this.vlans = dstDevice.getVlanId();
-	        }
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "FCQueryObj [fcQueryCaller=" + fcQueryHandler
-                + ", applInstName="
-                + applInstName + ", vlans=" + Arrays.toString(vlans)
-                + ", dstDevice=" + dstDevice + ", srcDevice="
-                + srcDevice + ", callerName=" + callerName + ", evType="
-                + evType + ", callerOpaqueObj=" + callerOpaqueObj + "]";
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        FCQueryObj other = (FCQueryObj) obj;
-        if (applInstName == null) {
-            if (other.applInstName != null)
-                return false;
-        } else if (!applInstName.equals(other.applInstName))
-            return false;
-        if (callerName == null) {
-            if (other.callerName != null)
-                return false;
-        } else if (!callerName.equals(other.callerName))
-            return false;
-        if (callerOpaqueObj == null) {
-            if (other.callerOpaqueObj != null)
-                return false;
-        } else if (!callerOpaqueObj.equals(other.callerOpaqueObj))
-            return false;
-        if (dstDevice == null) {
-            if (other.dstDevice != null)
-                return false;
-        } else if (!dstDevice.equals(other.dstDevice))
-            return false;
-        if (evType != other.evType)
-            return false;
-        if (fcQueryHandler != other.fcQueryHandler)
-            return false;
-        if (srcDevice == null) {
-            if (other.srcDevice != null)
-                return false;
-        } else if (!srcDevice.equals(other.srcDevice))
-            return false;
-        if (!Arrays.equals(vlans, other.vlans))
-            return false;
-        return true;
-    }
-    
-    
-}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowCacheQueryResp.java b/src/main/java/net/floodlightcontroller/flowcache/FlowCacheQueryResp.java
deleted file mode 100644
index b01aedf..0000000
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowCacheQueryResp.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package net.floodlightcontroller.flowcache;
-
-import java.util.ArrayList;
-
-/**
- * Object to return flows in response to a query message to BigFlowCache.
- * This object is passed in the flowQueryRespHandler() callback.
- */
-public class FlowCacheQueryResp {
-
-    /** query object provided by the caller, returned unchanged. */
-    public FCQueryObj  queryObj;
-    /** 
-     * Set to true if more flows could be returned for this query in
-     * additional callbacks. Set of false in the last callback for the
-     * query. 
-     */
-    public boolean     moreFlag;
-    
-    /**
-     * Set to true if the response has been sent to handler
-     */
-    public boolean     hasSent;
-    
-    /** 
-     * The flow list. If there are large number of flows to be returned
-     * then they may be returned in multiple callbacks.
-     */
-    public ArrayList<QRFlowCacheObj> qrFlowCacheObjList;
-
-    /**
-     * Instantiates a new big flow cache query response.
-     *
-     * @param query the flow cache query object as given by the caller of
-     * flow cache submit query API.
-     */
-    public FlowCacheQueryResp(FCQueryObj query) {
-        qrFlowCacheObjList = new ArrayList<QRFlowCacheObj>();
-        queryObj    = query;
-        moreFlag    = false;
-        hasSent     = false;
-    }
-
-    /* (non-Javadoc)
-     * @see java.lang.Object#toString()
-     */
-    @Override
-    public String toString() {
-        String s = queryObj.toString() + "; moreFlasg=" + moreFlag +
-                   "; hasSent=" + hasSent;
-        s += "; FlowCount=" + Integer.toString(qrFlowCacheObjList.size());
-        return s;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
deleted file mode 100644
index b221b84..0000000
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
+++ /dev/null
@@ -1,440 +0,0 @@
-package net.floodlightcontroller.flowcache;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-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.floodlightcontroller.core.util.ListenerDispatcher;
-import net.floodlightcontroller.core.util.SingletonTask;
-import net.floodlightcontroller.counter.CounterStore;
-import net.floodlightcontroller.counter.ICounter;
-import net.floodlightcontroller.counter.ICounterStoreService;
-import net.floodlightcontroller.counter.SimpleCounter;
-import net.floodlightcontroller.devicemanager.IDevice;
-import net.floodlightcontroller.flowcache.IFlowCacheService.FCQueryEvType;
-import net.floodlightcontroller.flowcache.IFlowReconcileListener;
-import net.floodlightcontroller.flowcache.OFMatchReconcile;
-import net.floodlightcontroller.threadpool.IThreadPoolService;
-
-import org.openflow.protocol.OFType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class FlowReconcileManager 
-        implements IFloodlightModule, IFlowReconcileService {
-
-    /** The logger. */
-    private final static Logger logger =
-                        LoggerFactory.getLogger(FlowReconcileManager.class);
-    
-    /** Reference to dependent modules */
-    protected IThreadPoolService threadPool;
-    protected ICounterStoreService counterStore;
-
-    /**
-     * The list of flow reconcile listeners that have registered to get
-     * flow reconcile callbacks. Such callbacks are invoked, for example, when
-     * a switch with existing flow-mods joins this controller and those flows
-     * need to be reconciled with the current configuration of the controller.
-     */
-    protected ListenerDispatcher<OFType, IFlowReconcileListener>
-                                               flowReconcileListeners;
-
-    /** A FIFO queue to keep all outstanding flows for reconciliation */
-    Queue<OFMatchReconcile> flowQueue;
-    
-    /** Asynchronous task to feed the flowReconcile pipeline */
-    protected SingletonTask flowReconcileTask;
-    
-    String controllerPktInCounterName;
-    protected SimpleCounter lastPacketInCounter;
-    
-    protected static int MAX_SYSTEM_LOAD_PER_SECOND = 50000;
-    /** a minimum flow reconcile rate so that it won't stave */
-    protected static int MIN_FLOW_RECONCILE_PER_SECOND = 1000;
-    
-    /** once per second */
-    protected static int FLOW_RECONCILE_DELAY_MILLISEC = 10;
-    protected Date lastReconcileTime;
-    
-    /** Config to enable or disable flowReconcile */
-    protected static final String EnableConfigKey = "enable";
-    protected boolean flowReconcileEnabled;
-    
-    public int flowReconcileThreadRunCount;
-    
-    @Override
-    public synchronized void addFlowReconcileListener(
-                IFlowReconcileListener listener) {
-        flowReconcileListeners.addListener(OFType.FLOW_MOD, listener);
-
-        if (logger.isTraceEnabled()) {
-            StringBuffer sb = new StringBuffer();
-            sb.append("FlowMod listeners: ");
-            for (IFlowReconcileListener l :
-                flowReconcileListeners.getOrderedListeners()) {
-                sb.append(l.getName());
-                sb.append(",");
-            }
-            logger.trace(sb.toString());
-        }
-    }
-
-    @Override
-    public synchronized void removeFlowReconcileListener(
-                IFlowReconcileListener listener) {
-        flowReconcileListeners.removeListener(listener);
-    }
-    
-    @Override
-    public synchronized void clearFlowReconcileListeners() {
-        flowReconcileListeners.clearListeners();
-    }
-    
-    /**
-     * Add to-be-reconciled flow to the queue.
-     *
-     * @param ofmRcIn the ofm rc in
-     */
-    public void reconcileFlow(OFMatchReconcile ofmRcIn) {
-        if (ofmRcIn == null) return;
-        
-        // Make a copy before putting on the queue.
-        OFMatchReconcile myOfmRc = new OFMatchReconcile(ofmRcIn);
-    
-        flowQueue.add(myOfmRc);
-    
-        Date currTime = new Date();
-        long delay = 0;
-
-        /** schedule reconcile task immidiately if it has been more than 1 sec
-         *  since the last run. Otherwise, schedule the reconcile task in
-         *  DELAY_MILLISEC.
-         */
-        if (currTime.after(new Date(lastReconcileTime.getTime() + 1000))) {
-            delay = 0;
-        } else {
-            delay = FLOW_RECONCILE_DELAY_MILLISEC;
-        }
-        flowReconcileTask.reschedule(delay, TimeUnit.MILLISECONDS);
-    
-        if (logger.isTraceEnabled()) {
-            logger.trace("Reconciling flow: {}, total: {}",
-                myOfmRc.toString(), flowQueue.size());
-        }
-    }
-    
-    @Override
-    public void updateFlowForDestinationDevice(IDevice device,
-                                            IFlowQueryHandler handler,
-                                            FCQueryEvType fcEvType) {
-        // NO-OP
-    }
-
-    @Override
-    public void updateFlowForSourceDevice(IDevice device,
-                                          IFlowQueryHandler handler,
-                                          FCQueryEvType fcEvType) {
-        // NO-OP
-    }
-    
-    @Override
-    public void flowQueryGenericHandler(FlowCacheQueryResp flowResp) {
-        if (flowResp.queryObj.evType != FCQueryEvType.GET) {
-            OFMatchReconcile ofmRc = new OFMatchReconcile();;
-            /* Re-provision these flows */
-            for (QRFlowCacheObj entry : flowResp.qrFlowCacheObjList) {
-                /* reconcile the flows in entry */
-                entry.toOFMatchReconcile(ofmRc,
-                        flowResp.queryObj.applInstName,
-                        OFMatchReconcile.ReconcileAction.UPDATE_PATH);
-                reconcileFlow(ofmRc);
-            }
-        }
-        return;
-    }
-    
-    // IFloodlightModule
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> l = 
-            new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(IFlowReconcileService.class);
-        return l;
-    }
-
-    @Override
-    public Map<Class<? extends IFloodlightService>, IFloodlightService> 
-                                                            getServiceImpls() {
-        Map<Class<? extends IFloodlightService>,
-        IFloodlightService> m = 
-            new HashMap<Class<? extends IFloodlightService>,
-                IFloodlightService>();
-        m.put(IFlowReconcileService.class, this);
-        return m;
-    }
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>> 
-                                                    getModuleDependencies() {
-        Collection<Class<? extends IFloodlightService>> l = 
-                new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(IThreadPoolService.class);
-        l.add(ICounterStoreService.class);
-        return null;
-    }
-
-    @Override
-    public void init(FloodlightModuleContext context)
-            throws FloodlightModuleException {
-        threadPool = context.getServiceImpl(IThreadPoolService.class);
-        counterStore = context.getServiceImpl(ICounterStoreService.class);
-    
-        flowQueue = new ConcurrentLinkedQueue<OFMatchReconcile>();
-        flowReconcileListeners = 
-                new ListenerDispatcher<OFType, IFlowReconcileListener>();
-        
-        Map<String, String> configParam = context.getConfigParams(this);
-        String enableValue = configParam.get(EnableConfigKey);
-        // Set flowReconcile default to true
-        flowReconcileEnabled = true;
-        if (enableValue != null &&
-            enableValue.equalsIgnoreCase("false")) {
-            flowReconcileEnabled = false;
-        }
-        
-        flowReconcileThreadRunCount = 0;
-        lastReconcileTime = new Date(0);
-        logger.debug("FlowReconcile is {}", flowReconcileEnabled);
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext context) {
-        // thread to do flow reconcile
-        ScheduledExecutorService ses = threadPool.getScheduledExecutor();
-        flowReconcileTask = new SingletonTask(ses, new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    if (doReconcile()) {
-                        flowReconcileTask.reschedule(
-                            FLOW_RECONCILE_DELAY_MILLISEC,
-                            TimeUnit.MILLISECONDS);
-                    }
-                } catch (Exception e) {
-                    logger.warn("Exception in doReconcile(): {}",
-                                e.getMessage());
-                    e.printStackTrace();
-                }
-            }
-        });
-        
-        String packetInName = OFType.PACKET_IN.toClass().getName();
-        packetInName = packetInName.substring(packetInName.lastIndexOf('.')+1); 
-        
-        // Construct controller counter for the packet_in
-        controllerPktInCounterName =
-            CounterStore.createCounterName(ICounterStoreService.CONTROLLER_NAME, 
-                                           -1,
-                                           packetInName);
-    }
-    
-    /**
-     * Feed the flows into the flow reconciliation pipeline.
-     * @return true if more flows to be reconciled
-     *         false if no more flows to be reconciled.
-     */
-    protected boolean doReconcile() {
-        if (!flowReconcileEnabled) {
-            return false;
-        }
-    
-        // Record the execution time.
-        lastReconcileTime = new Date();
-    
-        ArrayList<OFMatchReconcile> ofmRcList =
-                        new ArrayList<OFMatchReconcile>();
-        
-        // Get the maximum number of flows that can be reconciled.
-        int reconcileCapacity = getCurrentCapacity();
-        if (logger.isTraceEnabled()) {
-            logger.trace("Reconcile capacity {} flows", reconcileCapacity);
-        }
-        while (!flowQueue.isEmpty() && reconcileCapacity > 0) {
-            OFMatchReconcile ofmRc = flowQueue.poll();
-            reconcileCapacity--;
-            if (ofmRc != null) {
-                ofmRcList.add(ofmRc);
-                if (logger.isTraceEnabled()) {
-                    logger.trace("Add flow {} to be the reconcileList", ofmRc.cookie);
-                }
-            } else {
-                break;
-            }
-        }
-        
-        // Run the flow through all the flow reconcile listeners
-        IFlowReconcileListener.Command retCmd;
-        if (ofmRcList.size() > 0) {
-            List<IFlowReconcileListener> listeners =
-                flowReconcileListeners.getOrderedListeners();
-            if (listeners == null) {
-                if (logger.isTraceEnabled()) {
-                    logger.trace("No flowReconcile listener");
-                }
-                return false;
-            }
-        
-            for (IFlowReconcileListener flowReconciler :
-                flowReconcileListeners.getOrderedListeners()) {
-                if (logger.isTraceEnabled()) {
-                    logger.trace("Reconciling flow: call listener {}",
-                            flowReconciler.getName());
-                }
-                retCmd = flowReconciler.reconcileFlows(ofmRcList);
-                if (retCmd == IFlowReconcileListener.Command.STOP) {
-                    break;
-                }
-            }
-            flowReconcileThreadRunCount++;
-        } else {
-            if (logger.isTraceEnabled()) {
-                logger.trace("No flow to be reconciled.");
-            }
-        }
-        
-        // Return true if there are more flows to be reconciled
-        if (flowQueue.isEmpty()) {
-            return false;
-        } else {
-            if (logger.isTraceEnabled()) {
-                logger.trace("{} more flows to be reconciled.",
-                            flowQueue.size());
-            }
-            return true;
-        }
-    }
-    
-    /**
-     * Compute the maximum number of flows to be reconciled.
-     * 
-     * It computes the packetIn increment from the counter values in
-     * the counter store;
-     * Then computes the rate based on the elapsed time
-     * from the last query;
-     * Then compute the max flow reconcile rate by subtracting the packetIn
-     * rate from the hard-coded max system rate.
-     * If the system rate is reached or less than MIN_FLOW_RECONCILE_PER_SECOND,
-     * set the maximum flow reconcile rate to the MIN_FLOW_RECONCILE_PER_SECOND
-     * to prevent starvation.
-     * Then convert the rate to an absolute number for the
-     * FLOW_RECONCILE_PERIOD.
-     * @return
-     */
-    protected int getCurrentCapacity() {
-        ICounter pktInCounter =
-            counterStore.getCounter(controllerPktInCounterName);
-        int minFlows = MIN_FLOW_RECONCILE_PER_SECOND *
-                        FLOW_RECONCILE_DELAY_MILLISEC / 1000;
-        
-        // If no packetInCounter, then there shouldn't be any flow.
-        if (pktInCounter == null ||
-            pktInCounter.getCounterDate() == null ||
-            pktInCounter.getCounterValue() == null) {
-            logger.debug("counter {} doesn't exist",
-                        controllerPktInCounterName);
-            return minFlows;
-        }
-        
-        // Haven't get any counter yet.
-        if (lastPacketInCounter == null) {
-            logger.debug("First time get the count for {}",
-                        controllerPktInCounterName);
-            lastPacketInCounter = (SimpleCounter)
-            SimpleCounter.createCounter(pktInCounter);
-            return minFlows;
-        }
-        
-        int pktInRate = getPktInRate(pktInCounter, new Date());
-        
-        // Update the last packetInCounter
-        lastPacketInCounter = (SimpleCounter)
-        SimpleCounter.createCounter(pktInCounter);
-        int capacity = minFlows;
-        if ((pktInRate + MIN_FLOW_RECONCILE_PER_SECOND) <=
-                               MAX_SYSTEM_LOAD_PER_SECOND) {
-            capacity = (MAX_SYSTEM_LOAD_PER_SECOND - pktInRate)
-                    * FLOW_RECONCILE_DELAY_MILLISEC / 1000;
-        }
-        
-        if (logger.isTraceEnabled()) {
-            logger.trace("Capacity is {}", capacity);
-        }
-        return capacity;
-    }
-    
-    protected int getPktInRate(ICounter newCnt, Date currentTime) {
-        if (newCnt == null ||
-            newCnt.getCounterDate() == null ||
-            newCnt.getCounterValue() == null) {
-            return 0;
-        }
-    
-        // Somehow the system time is messed up. return max packetIn rate
-        // to reduce the system load.
-        if (newCnt.getCounterDate().before(
-                lastPacketInCounter.getCounterDate())) {
-            logger.debug("Time is going backward. new {}, old {}",
-                    newCnt.getCounterDate(),
-                    lastPacketInCounter.getCounterDate());
-            return MAX_SYSTEM_LOAD_PER_SECOND;
-        }
-    
-        long elapsedTimeInSecond = (currentTime.getTime() -
-                    lastPacketInCounter.getCounterDate().getTime()) / 1000;
-        if (elapsedTimeInSecond == 0) {
-            // This should never happen. Check to avoid division by zero.
-            return 0;
-        }
-    
-        long diff = 0;
-        switch (newCnt.getCounterValue().getType()) {
-            case LONG:
-                long newLong = newCnt.getCounterValue().getLong();
-                long oldLong = lastPacketInCounter.getCounterValue().getLong();
-                if (newLong < oldLong) {
-                    // Roll over event
-                    diff = Long.MAX_VALUE - oldLong + newLong;
-                } else {
-                    diff = newLong - oldLong;
-                }
-                break;
-    
-            case DOUBLE:
-                double newDouble = newCnt.getCounterValue().getDouble();
-                double oldDouble = lastPacketInCounter.getCounterValue().getDouble();
-                if (newDouble < oldDouble) {
-                    // Roll over event
-                    diff = (long)(Double.MAX_VALUE - oldDouble + newDouble);
-                } else {
-                    diff = (long)(newDouble - oldDouble);
-                }
-                break;
-        }
-    
-        return (int)(diff/elapsedTimeInSecond);
-    }
-}
-
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowCacheService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowCacheService.java
deleted file mode 100644
index 8e44ed3..0000000
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowCacheService.java
+++ /dev/null
@@ -1,185 +0,0 @@
-package net.floodlightcontroller.flowcache;
-
-import org.openflow.protocol.OFMatchWithSwDpid;
-
-import net.floodlightcontroller.core.FloodlightContext;
-import net.floodlightcontroller.core.FloodlightContextStore;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.devicemanager.SwitchPort;
-import net.floodlightcontroller.core.module.IFloodlightService;
-
-/**
- * The Interface IFlowCache.
- * <p>
- * public interface APIs to Big Switch Flow-Cache Service. Flow-Cache maintains
- * the network-level flows that are currently deployed in the underlying 
- * network. The flow cache can be queried using various filters by using the
- * corresponding APIs.
- * 
- * @author subrata
- *
- */
-public interface IFlowCacheService extends IFloodlightService {
-
-    public static final String FLOWCACHE_APP_NAME = 
-        "net.floodlightcontroller.flowcache.appName";
-    public static final String FLOWCACHE_APP_INSTANCE_NAME = 
-        "net.floodlightcontroller.flowcache.appInstanceName";
-
-    /**
-     * The flow cache query event type indicating the event that triggered the
-     * query. The callerOpaqueObj can be keyed based on this event type
-     */
-    public static enum FCQueryEvType {
-        /** The GET query. Flows need not be reconciled for this query type */
-        GET,
-        /** A new App was added. */
-        APP_ADDED,
-        /** An App was deleted. */
-        APP_DELETED,
-        /** Interface rule of an app was modified */
-        APP_INTERFACE_RULE_CHANGED,
-        /** Some App configuration was changed */
-        APP_CONFIG_CHANGED,
-        /** An ACL was added */
-        ACL_ADDED,
-        /** An ACL was deleted */
-        ACL_DELETED,
-        /** An ACL rule was added */
-        ACL_RULE_ADDED,
-        /** An ACL rule was deleted */
-        ACL_RULE_DELETED,
-        /** ACL configuration was changed */
-        ACL_CONFIG_CHANGED,
-        /** device had moved to a different port in the network */
-        DEVICE_MOVED,
-        /** device's property had changed, such as tag assignment */
-        DEVICE_PROPERTY_CHANGED,
-        /** Link down */
-        LINK_DOWN,
-        /** Periodic scan of switch flow table */
-        PERIODIC_SCAN,
-    }
-    
-    /**
-     * A FloodlightContextStore object that can be used to interact with the 
-     * FloodlightContext information about flowCache.
-     */
-    public static final FloodlightContextStore<String> fcStore = 
-        new FloodlightContextStore<String>();
-    
-    /**
-     * Submit a flow cache query with query parameters specified in FCQueryObj
-     * object. The query object can be created using one of the newFCQueryObj 
-     * helper functions in IFlowCache interface. 
-     * <p>
-     * The queried flows are returned via the flowQueryRespHandler() callback 
-     * that the caller must implement. The caller can match the query with
-     * the response using unique callerOpaqueData which remains unchanged
-     * in the request and response callback.
-     *
-     * @see  com.bigswitch.floodlight.flowcache#flowQueryRespHandler
-     * @param query the flow cache query object as input
-     * 
-     */
-    public void submitFlowCacheQuery(FCQueryObj query);
-
-    /**
-     * Deactivates all flows in the flow cache for which the source switch
-     * matches the given switchDpid. Note that the flows are NOT deleted
-     * from the cache.
-     *
-     * @param switchDpid Data-path identifier of the source switch
-     */
-    public void deactivateFlowCacheBySwitch(long switchDpid);
-
-    /**
-     * Deletes all flows in the flow cache for which the source switch
-     * matches the given switchDpid. 
-     * 
-     * @param switchDpid Data-path identifier of the source switch
-     */
-    public void deleteFlowCacheBySwitch(long switchDpid);
-
-    /**
-     * Add a flow to the flow-cache - called when a flow-mod is about to be
-     * written to a set of switches. If it returns false then it should not
-     * be written to the switches. If it returns true then the cookie returned
-     * should be used for the flow mod sent to the switches.
-     *
-     * @param appInstName Application instance name
-     * @param ofm openflow match object
-     * @param cookie openflow-mod cookie
-     * @param swPort SwitchPort object
-     * @param priority openflow match priority
-     * @param action action taken on the matched packets (PERMIT or DENY)
-     * @return true:  flow should be written to the switch(es)
-     *         false: flow should not be written to the switch(es). false is
-     *                returned, for example, when the flow was recently
-     *                written to the flow-cache and hence it is dampened to
-     *                avoid frequent writes of the same flow to the switches
-     *                This case can typically arise for the flows written at the
-     *                internal ports as they are heavily wild-carded.
-     */
-    public boolean addFlow(String appInstName, OFMatchWithSwDpid ofm, 
-                           Long cookie, long srcSwDpid, 
-                           short inPort, short priority, byte action);
-
-    /**
-     * Add a flow to the flow-cache - called when a flow-mod is about to be
-     * written to a set of switches. If it returns false then it should not
-     * be written to the switches. If it returns true then the cookie returned
-     * should be used for the flow mod sent to the switches.
-     *
-     * @param cntx the cntx
-     * @param ofm the ofm
-     * @param cookie the cookie
-     * @param swPort the sw port
-     * @param priority the priority
-     * @param action the action
-     * @return true:  flow should be written to the switch(es)
-     * false: flow should not be written to the switch(es). false is
-     * returned, for example, when the flow was recently
-     * written to the flow-cache and hence it is dampened to
-     * avoid frequent writes of the same flow to the switches
-     * This case can typically arise for the flows written at the
-     * internal ports as they are heavily wild-carded.
-     */
-    public boolean addFlow(FloodlightContext cntx, OFMatchWithSwDpid ofm, 
-                           Long cookie, SwitchPort swPort, 
-                           short priority, byte action);
-
-    /**
-     * Move the specified flow from its current application instance to a 
-     * different application instance. This API can be used when a flow moves
-     * to a different application instance when the application instance
-     * configuration changes or when a device moves to a different part in
-     * the network that belongs to a different application instance.
-     * <p>
-     * Note that, if the flow was not found in the current application 
-     * instance then the flow is not moved to the new application instance.
-     * 
-     * @param ofMRc the object containing the flow match and new application
-     * instance name.
-     * @return true is the flow was found in the flow cache in the current 
-     * application instance; false if the flow was not found in the flow-cache
-     * in the current application instance.
-     */
-    public boolean moveFlowToDifferentApplInstName(OFMatchReconcile ofMRc);
-
-    /**
-     * Delete all flow from the specified switch
-     * @param sw
-     */
-    public void deleteAllFlowsAtASourceSwitch(IOFSwitch sw);
-    
-    /**
-     * Post a request to update flowcache from a switch.
-     * This is an asynchronous operation.
-     * It queries the switch for stats and updates the flowcache asynchronously
-     * with the response.
-     * @param swDpid
-     * @param delay_ms
-     */
-    public void querySwitchFlowTable(long swDpid);
-}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowQueryHandler.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowQueryHandler.java
deleted file mode 100644
index 5d1b1a9..0000000
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowQueryHandler.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package net.floodlightcontroller.flowcache;
-
-public interface IFlowQueryHandler {
-    /**
-     * This callback function is called in response to a flow query request
-     * submitted to the flow cache service. The module handling this callback
-     * can be different from the one that submitted the query. In the flow
-     * query object used for submitting the flow query, the identity of the
-     * callback handler is passed. When flow cache service has all or some
-     * of the flows that needs to be returned then this callback is called
-     * for the appropriate module. The respone contains a boolean more flag 
-     * that indicates if there are additional flows that may be returned
-     * via additional callback calls.
-     *
-     * @param resp the response object containing the original flow query 
-     * object, partial or complete list of flows that we queried and some 
-     * metadata such as the more flag described aboce.
-     *
-     */
-    public void flowQueryRespHandler(FlowCacheQueryResp resp);
-}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileListener.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileListener.java
deleted file mode 100644
index f1100ed..0000000
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileListener.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package net.floodlightcontroller.flowcache;
-
-import java.util.ArrayList;
-
-import net.floodlightcontroller.core.IListener;
-import org.openflow.protocol.OFType;
-
-/**
- * The Interface IFlowReconciler.
- *
- * @author subrata
- */
-public interface IFlowReconcileListener extends IListener<OFType> {
-    /**
-     * Given an input OFMatch, this method applies the policy of the reconciler
-     * and returns a the same input OFMatch structure modified. Additional
-     * OFMatches, if needed, are returned in OFMatch-list. All the OFMatches
-     * are assumed to have "PERMIT" action.
-     *
-     * @param ofmRcList  input flow matches, to be updated to be consistent with
-     *                   the policies of this reconciler 
-     *                   Additional OFMatch-es can be added to the "list" as
-     *                   needed. 
-     *                   For example after a new ACL application, one flow-match
-     *                   may result in multiple flow-matches
-     *                   The method must also update the ReconcileAction
-     *                   member in ofmRcList entries to indicate if the
-     *                   flow needs to be modified, deleted or left unchanged
-     *                   OR of a new entry is to be added after flow 
-     *                   reconciliation
-     *
-     *
-     * @return   Command.CONTINUE if the OFMatch should be sent to the
-     *           next flow reconciler. 
-     *           Command.STOP if the OFMatch shouldn't be processed
-     *           further. In this case the no reconciled flow-mods would 
-     *           be programmed
-     */
-    public Command reconcileFlows(ArrayList<OFMatchReconcile> ofmRcList);
-}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileService.java
deleted file mode 100644
index f48c4e0..0000000
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileService.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * Provides Flow Reconcile service to other modules that need to reconcile
- * flows.
- */
-package net.floodlightcontroller.flowcache;
-
-import net.floodlightcontroller.core.module.IFloodlightService;
-import net.floodlightcontroller.devicemanager.IDevice;
-import net.floodlightcontroller.flowcache.IFlowCacheService.FCQueryEvType;
-
-public interface IFlowReconcileService extends IFloodlightService {
-    /**
-     * Add a flow reconcile listener
-     * @param listener The module that can reconcile flows
-     */
-    public void addFlowReconcileListener(IFlowReconcileListener listener);
-
-    /**
-     * Remove a flow reconcile listener
-     * @param listener The module that no longer reconcile flows
-     */
-    public void removeFlowReconcileListener(IFlowReconcileListener listener);
-    
-    /**
-     * Remove all flow reconcile listeners
-     */
-    public void clearFlowReconcileListeners();
-    
-    /**
-     * Reconcile flow. Returns false if no modified flow-mod need to be 
-     * programmed if cluster ID is providced then pnly flows in the given 
-     * cluster are reprogrammed
-     *
-     * @param ofmRcIn the ofm rc in
-     */
-    public void reconcileFlow(OFMatchReconcile ofmRcIn);
-    
-    /**
-     * Updates the flows to a device after the device moved to a new location
-     * <p>
-     * Queries the flow-cache to get all the flows destined to the given device.
-     * Reconciles each of these flows by potentially reprogramming them to its
-     * new attachment point
-     *
-     * @param device      device that has moved
-     * @param handler	  handler to process the flows
-     * @param fcEvType    Event type that triggered the update
-     *
-     */
-    public void updateFlowForDestinationDevice(IDevice device,
-            IFlowQueryHandler handler,
-    		FCQueryEvType fcEvType);
-    
-    /**
-     * Updates the flows from a device
-     * <p>
-     * Queries the flow-cache to get all the flows source from the given device.
-     * Reconciles each of these flows by potentially reprogramming them to its
-     * new attachment point
-     *
-     * @param device      device where the flow originates
-     * @param handler	  handler to process the flows
-     * @param fcEvType    Event type that triggered the update
-     *
-     */
-    public void updateFlowForSourceDevice(IDevice device,
-            IFlowQueryHandler handler,
-    		FCQueryEvType fcEvType);
-
-    /**
-     * Generic flow query handler to insert FlowMods into the reconcile pipeline.
-     * @param flowResp
-     */
-    public void flowQueryGenericHandler(FlowCacheQueryResp flowResp);
-}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java b/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java
deleted file mode 100644
index 68831f4..0000000
--- a/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package net.floodlightcontroller.flowcache;
-
-import net.floodlightcontroller.core.FloodlightContext;
-import org.openflow.protocol.OFMatchWithSwDpid;
-
-/**
- * OFMatchReconcile class to indicate result of a flow-reconciliation.
- */
-public class OFMatchReconcile  {
- 
-    /**
-     * The enum ReconcileAction. Specifies the result of reconciliation of a 
-     * flow.
-     */
-    public enum ReconcileAction {
-
-        /** Delete the flow-mod from the switch */
-        DROP,
-        /** Leave the flow-mod as-is. */
-        NO_CHANGE,
-        /** Program this new flow mod. */
-        NEW_ENTRY,
-        /** 
-         * Reprogram the flow mod as the path of the flow might have changed,
-         * for example when a host is moved or when a link goes down. */
-        UPDATE_PATH,
-        /* Flow is now in a different BVS */
-        APP_INSTANCE_CHANGED,
-        /* Delete the flow-mod - used to delete, for example, drop flow-mods
-         * when the source and destination are in the same BVS after a 
-         * configuration change */
-        DELETE
-    }
-
-    /** The open flow match after reconciliation. */
-    public OFMatchWithSwDpid ofmWithSwDpid;
-    /** flow mod. priority */
-    public short priority;
-    /** Action of this flow-mod PERMIT or DENY */
-    public byte action;
-    /** flow mod. cookie */
-    public long cookie;
-    /** The application instance name. */
-    public String appInstName;
-    /**
-     * The new application instance name. This is null unless the flow
-     * has moved to a different BVS due to BVS config change or device
-     * move to a different switch port etc.*/
-    public String newAppInstName;
-    /** The reconcile action. */
-    public ReconcileAction rcAction;
-
-    // The context for the reconcile action
-    public FloodlightContext cntx;
-    
-    /**
-     * Instantiates a new oF match reconcile object.
-     */
-    public OFMatchReconcile() {
-        ofmWithSwDpid      = new OFMatchWithSwDpid();
-        rcAction = ReconcileAction.NO_CHANGE;
-        cntx = new FloodlightContext();
-    }
-    
-    public OFMatchReconcile(OFMatchReconcile copy) {
-        ofmWithSwDpid =
-            new OFMatchWithSwDpid(copy.ofmWithSwDpid.getOfMatch(),
-                    copy.ofmWithSwDpid.getSwitchDataPathId());
-        priority = copy.priority;
-        action = copy.action;
-        cookie = copy.cookie;
-        appInstName = copy.appInstName;
-        newAppInstName = copy.newAppInstName;
-        rcAction = copy.rcAction;
-        cntx = new FloodlightContext();
-    }
-    
-    @Override
-    public String toString() {
-        return "OFMatchReconcile [" + ofmWithSwDpid + " priority=" + priority + " action=" + action + 
-                " cookie=" + cookie + " appInstName=" + appInstName + " newAppInstName=" + newAppInstName + 
-                " ReconcileAction=" + rcAction + "]";
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/PendingSwRespKey.java b/src/main/java/net/floodlightcontroller/flowcache/PendingSwRespKey.java
deleted file mode 100644
index 767ce94..0000000
--- a/src/main/java/net/floodlightcontroller/flowcache/PendingSwRespKey.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package net.floodlightcontroller.flowcache;
-
-public class PendingSwRespKey {
-    long swDpid;
-    int  transId;
-
-    public PendingSwRespKey(long swDpid, int transId) {
-        this.swDpid  = swDpid;
-        this.transId = transId;
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 97;
-        Long dpid   = swDpid;
-        Integer tid = transId;
-        return (tid.hashCode()*prime + dpid.hashCode());
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (!(obj instanceof PendingSwRespKey)) {
-            return false;
-        }
-        PendingSwRespKey other = (PendingSwRespKey) obj;
-        if ((swDpid != other.swDpid) || (transId != other.transId)) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return Long.toHexString(swDpid)+","+Integer.toString(transId);
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/PendingSwitchResp.java b/src/main/java/net/floodlightcontroller/flowcache/PendingSwitchResp.java
deleted file mode 100644
index d6f264f..0000000
--- a/src/main/java/net/floodlightcontroller/flowcache/PendingSwitchResp.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package net.floodlightcontroller.flowcache;
-
-import net.floodlightcontroller.flowcache.IFlowCacheService.FCQueryEvType;
-
-/**
- * The Class PendingSwitchResp. This object is used to track the pending
- * responses to switch flow table queries.
- */
-public class PendingSwitchResp {
-    protected FCQueryEvType evType;
-
-    public PendingSwitchResp(
-            FCQueryEvType evType) {
-        this.evType      = evType;
-    }
-    
-    public FCQueryEvType getEvType() {
-        return evType;
-    }
-
-    public void setEvType(FCQueryEvType evType) {
-        this.evType = evType;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/QRFlowCacheObj.java b/src/main/java/net/floodlightcontroller/flowcache/QRFlowCacheObj.java
deleted file mode 100644
index 5121f8b..0000000
--- a/src/main/java/net/floodlightcontroller/flowcache/QRFlowCacheObj.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package net.floodlightcontroller.flowcache;
-
-
-import org.openflow.protocol.OFMatchWithSwDpid;
-
-/**
- * Used in BigFlowCacheQueryResp as query result.
- * Used to return one flow when queried by one of the big flow cache APIs.
- * One of these QRFlowCacheObj is returned for each combination of
- * priority and action.
- *
- * @author subrata
- */
-public class QRFlowCacheObj {
-
-    /** The open flow match object. */
-    public OFMatchWithSwDpid ofmWithSwDpid;
-    /** The flow-mod priority. */
-    public short   priority;
-    /** flow-mod cookie */
-    public long    cookie;
-    /** The action - PERMIT or DENY. */
-    public byte    action;
-    /** The reserved byte to align with 8 bytes. */
-    public byte    reserved;
-
-    /**
-     * Instantiates a new flow cache query object.
-     *
-     * @param priority the priority
-     * @param action the action
-     */
-    public QRFlowCacheObj(short priority, byte action, long cookie) {
-        ofmWithSwDpid = new OFMatchWithSwDpid();
-        this.action   = action;
-        this.priority = priority;
-        this.cookie   = cookie;
-    }
-
-    /**
-     * Populate a given OFMatchReconcile object from the values of this
-     * class.
-     *
-     * @param ofmRc the given OFMatchReconcile object
-     * @param appInstName the application instance name
-     * @param rcAction the reconcile action
-     */
-    public   void toOFMatchReconcile(OFMatchReconcile ofmRc,
-                            String appInstName, OFMatchReconcile.ReconcileAction rcAction) {
-        ofmRc.ofmWithSwDpid   = ofmWithSwDpid; // not copying
-        ofmRc.appInstName     = appInstName;
-        ofmRc.rcAction        = rcAction;
-        ofmRc.priority        = priority;
-        ofmRc.cookie          = cookie;
-        ofmRc.action          = action;
-    }
-    
-    @Override
-    public String toString() {
-        String str = "ofmWithSwDpid: " + this.ofmWithSwDpid.toString() + " ";
-        str += "priority: " + this.priority + " ";
-        str += "cookie: " + this.cookie + " ";
-        str += "action: " + this.action + " ";
-        str += "reserved: " + this.reserved + " ";
-        return str;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/perfmon/CumulativeTimeBucket.java b/src/main/java/net/floodlightcontroller/perfmon/CumulativeTimeBucket.java
deleted file mode 100644
index e76253d..0000000
--- a/src/main/java/net/floodlightcontroller/perfmon/CumulativeTimeBucket.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package net.floodlightcontroller.perfmon;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.codehaus.jackson.map.annotate.JsonSerialize;
-
-import net.floodlightcontroller.core.IOFMessageListener;
-
-@JsonSerialize(using=CumulativeTimeBucketJSONSerializer.class)
-public class CumulativeTimeBucket {
-    private long startTime_ns; // First pkt time-stamp in this bucket
-    private Map<Integer, OneComponentTime> compStats;
-    private long totalPktCnt;
-    private long totalProcTimeNs; // total processing time for one pkt in
-    private long sumSquaredProcTimeNs2;
-    private long maxTotalProcTimeNs;
-    private long minTotalProcTimeNs;
-    private long avgTotalProcTimeNs;
-    private long sigmaTotalProcTimeNs; // std. deviation
-
-    public long getStartTimeNs() {
-        return startTime_ns;
-    }
-
-    public long getTotalPktCnt() {
-        return totalPktCnt;
-    }
-    
-    public long getAverageProcTimeNs() {
-        return avgTotalProcTimeNs;
-    }
-
-    public long getMinTotalProcTimeNs() {
-        return minTotalProcTimeNs;
-    }
-    
-    public long getMaxTotalProcTimeNs() {
-        return maxTotalProcTimeNs;
-    }
-    
-    public long getTotalSigmaProcTimeNs() {
-        return sigmaTotalProcTimeNs;
-    }
-    
-    public int getNumComps() {
-        return compStats.values().size();
-    }
-    
-    public Collection<OneComponentTime> getModules() {
-        return compStats.values();
-    }
-
-    public CumulativeTimeBucket(List<IOFMessageListener> listeners) {
-        compStats = new ConcurrentHashMap<Integer, OneComponentTime>(listeners.size());
-        for (IOFMessageListener l : listeners) {
-            OneComponentTime oct = new OneComponentTime(l);
-            compStats.put(oct.hashCode(), oct);
-        }
-        startTime_ns = System.nanoTime();
-    }
-
-    private void updateSquaredProcessingTime(long curTimeNs) {
-        sumSquaredProcTimeNs2 += (Math.pow(curTimeNs, 2));
-    }
-    
-    /**
-     * Resets all counters and counters for each component time
-     */
-    public void reset() {
-        startTime_ns = System.nanoTime();
-        totalPktCnt = 0;
-        totalProcTimeNs = 0;
-        avgTotalProcTimeNs = 0;
-        sumSquaredProcTimeNs2 = 0;
-        maxTotalProcTimeNs = Long.MIN_VALUE;
-        minTotalProcTimeNs = Long.MAX_VALUE;
-        sigmaTotalProcTimeNs = 0;
-        for (OneComponentTime oct : compStats.values()) {
-            oct.resetAllCounters();
-        }
-    }
-    
-    private void computeSigma() {
-        // Computes std. deviation from the sum of count numbers and from
-        // the sum of the squares of count numbers
-        double temp = totalProcTimeNs;
-        temp = Math.pow(temp, 2) / totalPktCnt;
-        temp = (sumSquaredProcTimeNs2 - temp) / totalPktCnt;
-        sigmaTotalProcTimeNs = (long) Math.sqrt(temp);
-    }
-    
-    public void computeAverages() {
-        // Must be called last to, needs latest info
-        computeSigma();
-        
-        for (OneComponentTime oct : compStats.values()) {
-            oct.computeSigma();
-        }
-    }
-    
-    public void updatePerPacketCounters(long procTimeNs) {
-        totalPktCnt++;
-        totalProcTimeNs += procTimeNs;
-        avgTotalProcTimeNs = totalProcTimeNs / totalPktCnt;
-        updateSquaredProcessingTime(procTimeNs);
-        
-        if (procTimeNs > maxTotalProcTimeNs) {
-            maxTotalProcTimeNs = procTimeNs;
-        }
-        
-        if (procTimeNs < minTotalProcTimeNs) {
-            minTotalProcTimeNs = procTimeNs;
-        }
-    }
-    
-    public void updateOneComponent(IOFMessageListener l, long procTimeNs) {
-        compStats.get(l.hashCode()).updatePerPacketCounters(procTimeNs);
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/perfmon/CumulativeTimeBucketJSONSerializer.java b/src/main/java/net/floodlightcontroller/perfmon/CumulativeTimeBucketJSONSerializer.java
deleted file mode 100644
index e492777..0000000
--- a/src/main/java/net/floodlightcontroller/perfmon/CumulativeTimeBucketJSONSerializer.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package net.floodlightcontroller.perfmon;
-
-import java.io.IOException;
-import java.sql.Timestamp;
-
-
-import org.codehaus.jackson.JsonGenerator;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.map.JsonSerializer;
-import org.codehaus.jackson.map.SerializerProvider;
-
-public class CumulativeTimeBucketJSONSerializer
-                                extends JsonSerializer<CumulativeTimeBucket> {
-    /**
-     * Performs the serialization of a OneComponentTime object
-     */
-   @Override
-   public void serialize(CumulativeTimeBucket ctb,
-                   JsonGenerator jGen,
-                   SerializerProvider serializer) 
-                   throws IOException, JsonProcessingException {
-       jGen.writeStartObject();
-       Timestamp ts = new Timestamp(ctb.getStartTimeNs()/1000000);
-       jGen.writeStringField("start-time", ts.toString());
-       jGen.writeStringField("current-time", 
-         new Timestamp(System.currentTimeMillis()).toString());
-       jGen.writeNumberField("total-packets", ctb.getTotalPktCnt());
-       jGen.writeNumberField("average", ctb.getAverageProcTimeNs());
-       jGen.writeNumberField("min", ctb.getMinTotalProcTimeNs());
-       jGen.writeNumberField("max", ctb.getMaxTotalProcTimeNs());
-       jGen.writeNumberField("std-dev", ctb.getTotalSigmaProcTimeNs());
-       jGen.writeArrayFieldStart("modules");
-       for (OneComponentTime oct : ctb.getModules()) {
-           serializer.defaultSerializeValue(oct, jGen);
-       }
-       jGen.writeEndArray();
-       jGen.writeEndObject();
-   }
-
-   /**
-    * Tells SimpleModule that we are the serializer for OFMatch
-    */
-   @Override
-   public Class<CumulativeTimeBucket> handledType() {
-       return CumulativeTimeBucket.class;
-   }
-}
diff --git a/src/main/java/net/floodlightcontroller/perfmon/IPktInProcessingTimeService.java b/src/main/java/net/floodlightcontroller/perfmon/IPktInProcessingTimeService.java
deleted file mode 100644
index 80dfda0..0000000
--- a/src/main/java/net/floodlightcontroller/perfmon/IPktInProcessingTimeService.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package net.floodlightcontroller.perfmon;
-
-import java.util.List;
-
-import org.openflow.protocol.OFMessage;
-
-import net.floodlightcontroller.core.FloodlightContext;
-import net.floodlightcontroller.core.IOFMessageListener;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.module.IFloodlightService;
-
-public interface IPktInProcessingTimeService extends IFloodlightService {
-
-    /**
-     * Creates time buckets for a set of modules to measure their performance
-     * @param listeners The message listeners to create time buckets for
-     */
-    public void bootstrap(List<IOFMessageListener> listeners);
-    
-    /**
-     * Stores a timestamp in ns. Used right before a service handles an
-     * OF message. Only stores if the service is enabled.
-     */
-    public void recordStartTimeComp(IOFMessageListener listener);
-    
-    public void recordEndTimeComp(IOFMessageListener listener);
-    
-    public void recordStartTimePktIn();
-    
-    public void recordEndTimePktIn(IOFSwitch sw, OFMessage m, FloodlightContext cntx);
-    
-    public boolean isEnabled();
-    
-    public void setEnabled(boolean enabled);
-    
-    public CumulativeTimeBucket getCtb();
-}
diff --git a/src/main/java/net/floodlightcontroller/perfmon/NullPktInProcessingTime.java b/src/main/java/net/floodlightcontroller/perfmon/NullPktInProcessingTime.java
deleted file mode 100644
index 3d9504b..0000000
--- a/src/main/java/net/floodlightcontroller/perfmon/NullPktInProcessingTime.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package net.floodlightcontroller.perfmon;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.openflow.protocol.OFMessage;
-
-import net.floodlightcontroller.core.FloodlightContext;
-import net.floodlightcontroller.core.IOFMessageListener;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.module.FloodlightModuleContext;
-import net.floodlightcontroller.core.module.FloodlightModuleException;
-import net.floodlightcontroller.core.module.IFloodlightModule;
-import net.floodlightcontroller.core.module.IFloodlightService;
-
-/**
- * An IPktInProcessingTimeService implementation that does nothing.
- * This is used mainly for performance testing or if you don't
- * want to use the IPktInProcessingTimeService features.
- * @author alexreimers
- *
- */
-public class NullPktInProcessingTime 
-    implements IFloodlightModule, IPktInProcessingTimeService {
-    
-    private CumulativeTimeBucket ctb;
-    private boolean inited = false;
-    
-    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> l = 
-                new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(IPktInProcessingTimeService.class);
-        return l;
-    }
-    
-    @Override
-    public Map<Class<? extends IFloodlightService>, IFloodlightService>
-            getServiceImpls() {
-        Map<Class<? extends IFloodlightService>,
-        IFloodlightService> m = 
-            new HashMap<Class<? extends IFloodlightService>,
-                        IFloodlightService>();
-        // We are the class that implements the service
-        m.put(IPktInProcessingTimeService.class, this);
-        return m;
-    }
-    
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
-        // We don't have any dependencies
-        return null;
-    }
-    
-    @Override
-    public void init(FloodlightModuleContext context)
-                             throws FloodlightModuleException {
-
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext context) {
-        // no-op
-    }
-
-    @Override
-    public boolean isEnabled() {
-        return false;
-    }
-
-    @Override
-    public void bootstrap(List<IOFMessageListener> listeners) {
-        if (!inited)
-            ctb = new CumulativeTimeBucket(listeners);
-    }
-
-    @Override
-    public void recordStartTimeComp(IOFMessageListener listener) {
-
-    }
-
-    @Override
-    public void recordEndTimeComp(IOFMessageListener listener) {
-
-    }
-
-    @Override
-    public void recordStartTimePktIn() {
-
-    }
-
-    @Override
-    public void recordEndTimePktIn(IOFSwitch sw, OFMessage m,
-                                   FloodlightContext cntx) {
-        
-    }
-
-    @Override
-    public void setEnabled(boolean enabled) {
-    
-    }
-
-    @Override
-    public CumulativeTimeBucket getCtb() {
-        return ctb;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/perfmon/OneComponentTime.java b/src/main/java/net/floodlightcontroller/perfmon/OneComponentTime.java
deleted file mode 100644
index 3e9734b..0000000
--- a/src/main/java/net/floodlightcontroller/perfmon/OneComponentTime.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package net.floodlightcontroller.perfmon;
-
-import org.codehaus.jackson.annotate.JsonProperty;
-
-import net.floodlightcontroller.core.IOFMessageListener;
-
-/**
- * Holds OF message processing time information for one IFloodlightModule.
- * @author Subrata
- */
-public class OneComponentTime {
-    private int compId; // hascode of IOFMessageListener
-    private String compName;
-    private int pktCnt;
-    // all times in nanoseconds
-    private long totalProcTimeNs;
-    private long sumSquaredProcTimeNs2; // squared
-    private long maxProcTimeNs;
-    private long minProcTimeNs;
-    private long avgProcTimeNs;
-    private long sigmaProcTimeNs;  // std. deviation
-
-    public OneComponentTime(IOFMessageListener module) {
-        compId = module.hashCode();
-        compName = module.getClass().getCanonicalName();
-        resetAllCounters();
-    }
-    
-    public void resetAllCounters() {
-        maxProcTimeNs = Long.MIN_VALUE;
-        minProcTimeNs = Long.MAX_VALUE;
-        pktCnt = 0;
-        totalProcTimeNs = 0;
-        sumSquaredProcTimeNs2 = 0;
-        avgProcTimeNs = 0;
-        sigmaProcTimeNs = 0;
-    }
-    
-    @JsonProperty("module-name")
-    public String getCompName() {
-        return compName;
-    }
-
-    @JsonProperty("num-packets")
-    public int getPktCnt() {
-        return pktCnt;
-    }
-
-    @JsonProperty("total")
-    public long getSumProcTimeNs() {
-        return totalProcTimeNs;
-    }
-
-    @JsonProperty("max")
-    public long getMaxProcTimeNs() {
-        return maxProcTimeNs;
-    }
-
-    @JsonProperty("min")
-    public long getMinProcTimeNs() {
-        return minProcTimeNs;
-    }
-
-    @JsonProperty("average")
-    public long getAvgProcTimeNs() {
-        return avgProcTimeNs;
-    }
-
-    @JsonProperty("std-dev")
-    public long getSigmaProcTimeNs() {
-        return sigmaProcTimeNs;
-    }
-    
-    @JsonProperty("average-squared")
-    public long getSumSquaredProcTimeNs() {
-        return sumSquaredProcTimeNs2;
-    }
-
-    // Methods used to update the counters
-    
-    private void increasePktCount() {
-        pktCnt++;
-    }
-    
-    private void updateTotalProcessingTime(long procTimeNs) {
-        totalProcTimeNs += procTimeNs;
-    }
-    
-    private void updateAvgProcessTime() {
-        avgProcTimeNs = totalProcTimeNs / pktCnt;
-    }
-    
-    private void updateSquaredProcessingTime(long procTimeNs) {
-        sumSquaredProcTimeNs2 += (Math.pow(procTimeNs, 2));
-    }
-    
-    private void calculateMinProcTime(long curTimeNs) {
-        if (curTimeNs < minProcTimeNs)
-            minProcTimeNs = curTimeNs;
-    }
-    
-    private void calculateMaxProcTime(long curTimeNs) {
-        if (curTimeNs > maxProcTimeNs)
-            maxProcTimeNs = curTimeNs;
-    }
-    
-    public void computeSigma() {
-        // Computes std. deviation from the sum of count numbers and from
-        // the sum of the squares of count numbers
-        double temp = totalProcTimeNs;
-        temp = Math.pow(temp, 2) / pktCnt;
-        temp = (sumSquaredProcTimeNs2 - temp) / pktCnt;
-        sigmaProcTimeNs = (long) Math.sqrt(temp);
-    }
-    
-    public void updatePerPacketCounters(long procTimeNs) {
-        increasePktCount();
-        updateTotalProcessingTime(procTimeNs);
-        calculateMinProcTime(procTimeNs);
-        calculateMaxProcTime(procTimeNs);
-        updateAvgProcessTime();
-        updateSquaredProcessingTime(procTimeNs);
-    }
-    
-    @Override
-    public int hashCode() {
-        return compId;
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/perfmon/PerfMonDataResource.java b/src/main/java/net/floodlightcontroller/perfmon/PerfMonDataResource.java
deleted file mode 100644
index 297c44e..0000000
--- a/src/main/java/net/floodlightcontroller/perfmon/PerfMonDataResource.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package net.floodlightcontroller.perfmon;
-
-import org.restlet.data.Status;
-import org.restlet.resource.Get;
-import org.restlet.resource.ServerResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-/**
- * Return the performance monitoring data for the get rest api call
- * @author subrata
- */
-public class PerfMonDataResource extends ServerResource {
-    protected final static Logger logger = LoggerFactory.getLogger(PerfMonDataResource.class);  
-    
-    @Get("json")
-    public CumulativeTimeBucket handleApiQuery() {        
-        IPktInProcessingTimeService pktinProcTime = 
-            (IPktInProcessingTimeService)getContext().getAttributes().
-                get(IPktInProcessingTimeService.class.getCanonicalName());
-        
-        setStatus(Status.SUCCESS_OK, "OK");
-        // Allocate output object
-        if (pktinProcTime.isEnabled()) {
-            CumulativeTimeBucket ctb = pktinProcTime.getCtb();
-            ctb.computeAverages();
-            return ctb;
-        }
-        
-        return null;
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/perfmon/PerfMonToggleResource.java b/src/main/java/net/floodlightcontroller/perfmon/PerfMonToggleResource.java
deleted file mode 100644
index 9ea1876..0000000
--- a/src/main/java/net/floodlightcontroller/perfmon/PerfMonToggleResource.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package net.floodlightcontroller.perfmon;
-
-import org.restlet.data.Status;
-import org.restlet.resource.Get;
-import org.restlet.resource.ServerResource;
-
-public class PerfMonToggleResource extends ServerResource {
-    
-    @Get("json")
-    public String retrieve() {
-        IPktInProcessingTimeService pktinProcTime = 
-                (IPktInProcessingTimeService)getContext().getAttributes().
-                    get(IPktInProcessingTimeService.class.getCanonicalName());
-        
-        String param = ((String)getRequestAttributes().get("perfmonstate")).toLowerCase();
-        if (param.equals("reset")) {
-            pktinProcTime.getCtb().reset();
-        } else {
-            if (param.equals("enable") || param.equals("true")) {
-                pktinProcTime.setEnabled(true);
-            } else if (param.equals("disable") || param.equals("false")) {
-                pktinProcTime.setEnabled(false);
-            }
-        }
-        setStatus(Status.SUCCESS_OK, "OK");
-        return "{ \"enabled\" : " + pktinProcTime.isEnabled() + " }";
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/perfmon/PerfWebRoutable.java b/src/main/java/net/floodlightcontroller/perfmon/PerfWebRoutable.java
deleted file mode 100644
index ace0bc8..0000000
--- a/src/main/java/net/floodlightcontroller/perfmon/PerfWebRoutable.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package net.floodlightcontroller.perfmon;
-
-import org.restlet.Context;
-import org.restlet.Restlet;
-import org.restlet.routing.Router;
-
-import net.floodlightcontroller.restserver.RestletRoutable;
-
-public class PerfWebRoutable implements RestletRoutable {
-
-    @Override
-    public Restlet getRestlet(Context context) {
-        Router router = new Router(context);
-        router.attach("/data/json", PerfMonDataResource.class);
-        router.attach("/{perfmonstate}/json", PerfMonToggleResource.class); // enable, disable, or reset
-        return router;
-    }
-
-    @Override
-    public String basePath() {
-        return "/wm/performance";
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/perfmon/PktInProcessingTime.java b/src/main/java/net/floodlightcontroller/perfmon/PktInProcessingTime.java
deleted file mode 100644
index 639623b..0000000
--- a/src/main/java/net/floodlightcontroller/perfmon/PktInProcessingTime.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/**
- * Performance monitoring package
- */
-package net.floodlightcontroller.perfmon;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import net.floodlightcontroller.core.FloodlightContext;
-import net.floodlightcontroller.core.IOFMessageListener;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.annotations.LogMessageCategory;
-import net.floodlightcontroller.core.annotations.LogMessageDoc;
-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.floodlightcontroller.restserver.IRestApiService;
-
-import org.openflow.protocol.OFMessage;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * This class contains a set of buckets (called time buckets as the
- * primarily contain 'times' that are used in a circular way to 
- * store information on packet in processing time.
- * Each bucket is meant to store the various processing time 
- * related data for a fixed duration.
- * Buckets are reused to reduce garbage generation! Once the
- * last bucket is used up the LRU bucket is reused.
- * 
- * Naming convention for variable or constants
- * variable_s : value in seconds
- * variable_ms: value in milliseconds
- * variable_us: value in microseconds
- * variable_ns: value in nanoseconds
- * 
- * Key Constants:
- * ONE_BUCKET_DURATION_SECONDS_INT:  time duration of each bucket
- * BUCKET_SET_SIZE: Number of buckets
- * TOT_PROC_TIME_WARN_THRESHOLD_US: if processing time for a packet
- *    exceeds this threshold then a warning LOG message is generated
- * TOT_PROC_TIME_ALERT_THRESHOLD_US: same as above but an alert level
- *    syslog is generated instead
- * 
- */
-@LogMessageCategory("Performance Monitoring")
-public class PktInProcessingTime
-    implements IFloodlightModule, IPktInProcessingTimeService {
-
-    
-    // Our dependencies
-    private IRestApiService restApi;
-    
-    protected long ptWarningThresholdInNano;
-
-    // DB storage tables
-    protected static final String ControllerTableName = "controller_controller";
-    public static final String COLUMN_ID = "id";
-    public static final String COLUMN_PERF_MON = "performance_monitor_feature";
-    
-    protected static  Logger  logger = 
-        LoggerFactory.getLogger(PktInProcessingTime.class);
-    
-    protected boolean isEnabled = false;
-    protected boolean isInited = false;
-    // Maintains the time when the last packet was processed
-    protected long lastPktTime_ns;
-    private CumulativeTimeBucket ctb = null;
-
-    
-    /***
-     * BUCKET_SET_SIZE buckets each holding 10s of processing time data, a total
-     * of 30*10s = 5mins of processing time data is maintained
-     */
-    protected static final int ONE_BUCKET_DURATION_SECONDS = 10;// seconds
-    protected static final long ONE_BUCKET_DURATION_NANOSECONDS  =
-                                ONE_BUCKET_DURATION_SECONDS * 1000000000;
-    
-    @Override
-    public void bootstrap(List<IOFMessageListener> listeners) {
-        if (!isInited) {
-            ctb = new CumulativeTimeBucket(listeners);
-            isInited = true;
-        }
-    }
-    
-    @Override
-    public boolean isEnabled() {
-        return isEnabled && isInited;
-    }
-    
-    @Override
-    public void setEnabled(boolean enabled) {
-        this.isEnabled = enabled;
-        logger.debug("Setting module to " + isEnabled);
-    }
-    
-    @Override
-    public CumulativeTimeBucket getCtb() {
-        return ctb;
-    }
-    
-    private long startTimePktNs;
-    private long startTimeCompNs;
-    @Override
-    public void recordStartTimeComp(IOFMessageListener listener) {
-        if (isEnabled()) {
-            startTimeCompNs = System.nanoTime();
-        }
-    }
-    
-    @Override
-    public void recordEndTimeComp(IOFMessageListener listener) {
-        if (isEnabled()) {
-            long procTime = System.nanoTime() - startTimeCompNs;
-            ctb.updateOneComponent(listener, procTime);
-        }
-    }
-    
-    @Override
-    public void recordStartTimePktIn() {
-        if (isEnabled()) {
-            startTimePktNs = System.nanoTime();
-        }
-    }
-    
-    @Override
-    @LogMessageDoc(level="WARN",
-            message="Time to process packet-in exceeded threshold: {}",
-            explanation="Time to process packet-in exceeded the configured " +
-            		"performance threshold",
-            recommendation=LogMessageDoc.CHECK_CONTROLLER)
-    public void recordEndTimePktIn(IOFSwitch sw, OFMessage m, FloodlightContext cntx) {
-        if (isEnabled()) {
-            long procTimeNs = System.nanoTime() - startTimePktNs;
-            ctb.updatePerPacketCounters(procTimeNs);
-            
-            if (ptWarningThresholdInNano > 0 && 
-                    procTimeNs > ptWarningThresholdInNano) {
-                logger.warn("Time to process packet-in exceeded threshold: {}", 
-                            procTimeNs/1000);
-            }
-        }
-    }
-    
-    // IFloodlightModule methods
-    
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> l = 
-                new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(IPktInProcessingTimeService.class);
-        return l;
-    }
-    
-    @Override
-    public Map<Class<? extends IFloodlightService>, IFloodlightService>
-            getServiceImpls() {
-        Map<Class<? extends IFloodlightService>,
-        IFloodlightService> m = 
-            new HashMap<Class<? extends IFloodlightService>,
-                        IFloodlightService>();
-        // We are the class that implements the service
-        m.put(IPktInProcessingTimeService.class, this);
-        return m;
-    }
-    
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
-        Collection<Class<? extends IFloodlightService>> l = 
-                new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(IRestApiService.class);
-        return l;
-    }
-    
-    @Override
-    public void init(FloodlightModuleContext context)
-                                             throws FloodlightModuleException {
-        restApi = context.getServiceImpl(IRestApiService.class);
-    }
-    
-    @Override
-    @LogMessageDoc(level="INFO",
-        message="Packet processing time threshold for warning" +
-            " set to {time} ms.",
-        explanation="Performance monitoring will log a warning if " +
-    		"packet processing time exceeds the configured threshold")
-    public void startUp(FloodlightModuleContext context) {
-        // Add our REST API
-        restApi.addRestletRoutable(new PerfWebRoutable());
-        
-        // TODO - Alex - change this to a config option
-        ptWarningThresholdInNano = Long.parseLong(System.getProperty(
-             "net.floodlightcontroller.core.PTWarningThresholdInMilli", "0")) * 1000000;
-        if (ptWarningThresholdInNano > 0) {
-            logger.info("Packet processing time threshold for warning" +
-            		" set to {} ms.", ptWarningThresholdInNano/1000000);
-        }
-    }
-}
diff --git a/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java b/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
index 180cbe9..6483121 100644
--- a/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
+++ b/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
@@ -27,7 +27,6 @@
 import net.onrc.onos.ofcontroller.util.FlowPath;
 import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
 
-import org.openflow.util.HexString;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -99,8 +98,7 @@
 	 *
 	 * @param event the notification event for the entry.
 	 */
-	public void entryAdded(EntryEvent event) {
-	    Long keyLong = (Long)event.getKey();
+	public void entryAdded(EntryEvent<Long, byte[]> event) {
 	    byte[] valueBytes = (byte[])event.getValue();
 
 	    //
@@ -118,8 +116,7 @@
 	 *
 	 * @param event the notification event for the entry.
 	 */
-	public void entryRemoved(EntryEvent event) {
-	    Long keyLong = (Long)event.getKey();
+	public void entryRemoved(EntryEvent<Long, byte[]> event) {
 	    byte[] valueBytes = (byte[])event.getValue();
 
 	    //
@@ -137,8 +134,7 @@
 	 *
 	 * @param event the notification event for the entry.
 	 */
-	public void entryUpdated(EntryEvent event) {
-	    Long keyLong = (Long)event.getKey();
+	public void entryUpdated(EntryEvent<Long, byte[]> event) {
 	    byte[] valueBytes = (byte[])event.getValue();
 
 	    //
@@ -156,7 +152,7 @@
 	 *
 	 * @param event the notification event for the entry.
 	 */
-	public void entryEvicted(EntryEvent event) {
+	public void entryEvicted(EntryEvent<Long, byte[]> event) {
 	    // NOTE: We don't use eviction for this map
 	}
     }
@@ -174,14 +170,7 @@
 	 *
 	 * @param event the notification event for the entry.
 	 */
-	public void entryAdded(EntryEvent event) {
-	    //
-	    // NOTE: Ignore Flow Entries Events originated by this instance
-	    //
-	    if (event.getMember().localMember())
-		return;
-
-	    Long keyLong = (Long)event.getKey();
+	public void entryAdded(EntryEvent<Long, byte[]> event) {
 	    byte[] valueBytes = (byte[])event.getValue();
 
 	    //
@@ -199,14 +188,7 @@
 	 *
 	 * @param event the notification event for the entry.
 	 */
-	public void entryRemoved(EntryEvent event) {
-	    //
-	    // NOTE: Ignore Flow Entries Events originated by this instance
-	    //
-	    if (event.getMember().localMember())
-		return;
-
-	    Long keyLong = (Long)event.getKey();
+	public void entryRemoved(EntryEvent<Long, byte[]> event) {
 	    byte[] valueBytes = (byte[])event.getValue();
 
 	    //
@@ -224,14 +206,7 @@
 	 *
 	 * @param event the notification event for the entry.
 	 */
-	public void entryUpdated(EntryEvent event) {
-	    //
-	    // NOTE: Ignore Flow Entries Events originated by this instance
-	    //
-	    if (event.getMember().localMember())
-		return;
-
-	    Long keyLong = (Long)event.getKey();
+	public void entryUpdated(EntryEvent<Long, byte[]> event) {
 	    byte[] valueBytes = (byte[])event.getValue();
 
 	    //
@@ -249,7 +224,7 @@
 	 *
 	 * @param event the notification event for the entry.
 	 */
-	public void entryEvicted(EntryEvent event) {
+	public void entryEvicted(EntryEvent<Long, byte[]> event) {
 	    // NOTE: We don't use eviction for this map
 	}
     }
@@ -267,8 +242,7 @@
 	 *
 	 * @param event the notification event for the entry.
 	 */
-	public void entryAdded(EntryEvent event) {
-	    String keyString = (String)event.getKey();
+	public void entryAdded(EntryEvent<String, byte[]> event) {
 	    byte[] valueBytes = (byte[])event.getValue();
 
 	    //
@@ -287,8 +261,7 @@
 	 *
 	 * @param event the notification event for the entry.
 	 */
-	public void entryRemoved(EntryEvent event) {
-	    String keyString = (String)event.getKey();
+	public void entryRemoved(EntryEvent<String, byte[]> event) {
 	    byte[] valueBytes = (byte[])event.getValue();
 
 	    //
@@ -307,8 +280,7 @@
 	 *
 	 * @param event the notification event for the entry.
 	 */
-	public void entryUpdated(EntryEvent event) {
-	    String keyString = (String)event.getKey();
+	public void entryUpdated(EntryEvent<String, byte[]> event) {
 	    byte[] valueBytes = (byte[])event.getValue();
 
 	    //
@@ -327,7 +299,7 @@
 	 *
 	 * @param event the notification event for the entry.
 	 */
-	public void entryEvicted(EntryEvent event) {
+	public void entryEvicted(EntryEvent<String, byte[]> event) {
 	    // NOTE: We don't use eviction for this map
 	}
     }
@@ -607,6 +579,29 @@
     }
 
     /**
+     * Get a Flow for a given Flow ID.
+     *
+     * @param flowId the Flow ID of the Flow to get.
+     * @return the Flow if found, otherwise null.
+     */
+    @Override
+    public FlowPath getFlow(FlowId flowId) {
+	byte[] valueBytes = mapFlow.get(flowId.value());
+	if (valueBytes == null)
+	    return null;
+
+	Kryo kryo = kryoFactory.newKryo();
+	//
+	// Decode the value
+	//
+	Input input = new Input(valueBytes);
+	FlowPath flowPath = kryo.readObject(input, FlowPath.class);
+	kryoFactory.deleteKryo(kryo);
+
+	return flowPath;
+    }
+
+    /**
      * Send a notification that a Flow is added.
      *
      * @param flowPath the Flow that is added.
@@ -702,6 +697,29 @@
     }
 
     /**
+     * Get a Flow Entry for a given Flow Entry ID.
+     *
+     * @param flowEntryId the Flow Entry ID of the Flow Entry to get.
+     * @return the Flow Entry if found, otherwise null.
+     */
+    @Override
+    public FlowEntry getFlowEntry(FlowEntryId flowEntryId) {
+	byte[] valueBytes = mapFlowEntry.get(flowEntryId.value());
+	if (valueBytes == null)
+	    return null;
+
+	Kryo kryo = kryoFactory.newKryo();
+	//
+	// Decode the value
+	//
+	Input input = new Input(valueBytes);
+	FlowEntry flowEntry = kryo.readObject(input, FlowEntry.class);
+	kryoFactory.deleteKryo(kryo);
+
+	return flowEntry;
+    }
+
+    /**
      * Send a notification that a FlowEntry is added.
      *
      * @param flowEntry the FlowEntry that is added.
diff --git a/src/main/java/net/onrc/onos/datagrid/IDatagridService.java b/src/main/java/net/onrc/onos/datagrid/IDatagridService.java
index 9361341..034fe25 100644
--- a/src/main/java/net/onrc/onos/datagrid/IDatagridService.java
+++ b/src/main/java/net/onrc/onos/datagrid/IDatagridService.java
@@ -50,7 +50,7 @@
      * @param arpEventHandler The ARP event handler to de-register.
      */
     public void deregisterArpEventHandler(IArpEventHandler arpEventHandler);
-    
+
     /**
      * Get all Flows that are currently in the datagrid.
      *
@@ -59,6 +59,14 @@
     Collection<FlowPath> getAllFlows();
 
     /**
+     * Get a Flow for a given Flow ID.
+     *
+     * @param flowId the Flow ID of the Flow to get.
+     * @return the Flow if found, otherwise null.
+     */
+    FlowPath getFlow(FlowId flowId);
+
+    /**
      * Send a notification that a Flow is added.
      *
      * @param flowPath the Flow that is added.
@@ -92,6 +100,14 @@
     Collection<FlowEntry> getAllFlowEntries();
 
     /**
+     * Get a Flow Entry for a given Flow Entry ID.
+     *
+     * @param flowEntryId the Flow Entry ID of the Flow Entry to get.
+     * @return the Flow Entry if found, otherwise null.
+     */
+    FlowEntry getFlowEntry(FlowEntryId flowEntryId);
+
+    /**
      * Send a notification that a FlowEntry is added.
      *
      * @param flowEntry the FlowEntry that is added.
diff --git a/src/main/java/net/onrc/onos/flow/FlowManagerImpl.java b/src/main/java/net/onrc/onos/flow/FlowManagerImpl.java
deleted file mode 100644
index 9865deb..0000000
--- a/src/main/java/net/onrc/onos/flow/FlowManagerImpl.java
+++ /dev/null
@@ -1,331 +0,0 @@
-package net.onrc.onos.flow;
-
-import java.util.ArrayList;
-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 org.openflow.util.HexString;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.tinkerpop.blueprints.Direction;
-import com.tinkerpop.blueprints.Vertex;
-
-import net.floodlightcontroller.core.IOFSwitch;
-import net.onrc.onos.graph.GraphDBOperation;
-import net.onrc.onos.graph.LocalTopologyEventListener;
-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.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.FlowEntryAction;
-import net.onrc.onos.ofcontroller.util.FlowEntryActions;
-import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
-import net.onrc.onos.ofcontroller.util.FlowPath;
-import net.onrc.onos.ofcontroller.util.Port;
-import net.onrc.onos.ofcontroller.util.SwitchPort;
-
-public class FlowManagerImpl implements IFlowManager {
-	
-	protected final static Logger log = LoggerFactory.getLogger(LocalTopologyEventListener.class);
-	protected GraphDBOperation op;
-
-	@Override
-	public void createFlow(IPortObject src_port, IPortObject dest_port) {
-		// TODO Auto-generated method stub
-
-	}
-
-	@Override
-	public Iterable<FlowPath> getFlows(IPortObject src_port,
-			IPortObject dest_port) {
-		// TODO Auto-generated method stub
-		return null;
-	}
-
-	@Override
-	public Iterable<FlowPath> getOutFlows(IPortObject port) {
-		// TODO Auto-generated method stub
-		List<FlowPath> flowPaths = new ArrayList<FlowPath> ();
-		Iterable<IFlowEntry> flowEntries = port.getOutFlowEntries();
-
-		for(IFlowEntry fe: flowEntries) {
-			IFlowPath flow = fe.getFlow();
-			FlowPath flowPath = new FlowPath(flow);
-			flowPaths.add(flowPath);
-		}
-		return flowPaths;
-	}
-
-	@Override
-	public void reconcileFlows(IPortObject src_port) {
-		// TODO Auto-generated method stub
-
-		log.debug("Reconcile Flows for Port removed: {}:{}",src_port.getSwitch().getDPID(),src_port.getNumber());
-		Iterable<IFlowEntry> flowEntries = src_port.getOutFlowEntries();
-
-		for(IFlowEntry fe: flowEntries) {
-			IFlowPath flow = fe.getFlow();
-			reconcileFlow(flow);
-		}
-	}
-
-	private void reconcileFlow(IFlowPath flow) {
-		// TODO Auto-generated method stub
-		String src_dpid = flow.getSrcSwitch();
-		String dst_dpid = flow.getDstSwitch();
-		Short src_port = flow.getSrcPort();
-		Short dst_port = flow.getDstPort();
-		IPortObject src = null;
-		IPortObject dst = null;
-		src = op.searchPort(src_dpid, src_port);
-		dst = op.searchPort(dst_dpid, dst_port);
-		if (src != null && dst != null) {
-			FlowPath newFlow = this.computeFlowPath(src,dst);
-			installFlow(newFlow);
-			removeFlow(flow);
-		}
-		
-	}
-
-	private void removeFlow(IFlowPath flow) {
-		// TODO Auto-generated method stub
-		
-	}
-
-	private void installFlow(FlowPath newFlow) {
-		// TODO Auto-generated method stub
-		
-	}
-
-	@Override
-	public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
-		// TODO Auto-generated method stub
-
-	}
-
-	@Override
-	public FlowPath computeFlowPath(IPortObject src_port, IPortObject dest_port) {
-		// TODO Auto-generated method stub
-		DataPath dataPath = new DataPath(); 
-		
-		// FIXME: Bad idea to use FloodLight data structures (SwitchPort)
-		
-		dataPath.setSrcPort(new SwitchPort(new Dpid(src_port.getSwitch().getDPID()),
-						new Port(src_port.getNumber())));
-		dataPath.setDstPort(new SwitchPort(new Dpid(src_port.getSwitch().getDPID()),
-				new Port(src_port.getNumber())));
-		
-		if (src_port.getSwitch().equals(dest_port.getSwitch())) {
-			// on same switch create quick path
-			FlowEntry flowEntry = new FlowEntry();
-		    flowEntry.setDpid(new Dpid(src_port.getSwitch().getDPID()));
-		    flowEntry.setInPort(new Port(src_port.getNumber()));
-		    flowEntry.setOutPort(new Port(src_port.getNumber()));
-		    flowEntry.setFlowEntryMatch(new FlowEntryMatch());
-		    flowEntry.flowEntryMatch().enableInPort(flowEntry.inPort());
-
-		    // Set the outgoing port output action
-		    FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
-		    FlowEntryAction flowEntryAction = new FlowEntryAction();
-		    flowEntryAction.setActionOutput(flowEntry.outPort());
-		    flowEntryActions.addAction(flowEntryAction);
-		    dataPath.flowEntries().add(flowEntry);
-		    
-		    FlowPath flowPath = new FlowPath();
-			flowPath.setDataPath(dataPath);
-
-			return flowPath;
-		}
-		Vertex v_src = src_port.getSwitch().asVertex();	
-		Vertex v_dest = dest_port.getSwitch().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")) {
-			for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
-			    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.getNumber());
-		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);
-			flowEntry.setFlowEntryMatch(new FlowEntryMatch());
-		    flowEntry.flowEntryMatch().enableInPort(flowEntry.inPort());
-		    
-		    // Set the outgoing port output action
-		    FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
-		    FlowEntryAction flowEntryAction = new FlowEntryAction();
-		    flowEntryAction.setActionOutput(flowEntry.outPort());
-		    flowEntryActions.addAction(flowEntryAction);
-		    dataPath.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(new Port(dest_port.getNumber()));
-		    flowEntry.setFlowEntryMatch(new FlowEntryMatch());
-		    flowEntry.flowEntryMatch().enableInPort(flowEntry.inPort());
-		    
-		    // Set the outgoing port output action
-		    FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
-		    FlowEntryAction flowEntryAction = new FlowEntryAction();
-		    flowEntryAction.setActionOutput(flowEntry.outPort());
-		    flowEntryActions.addAction(flowEntryAction);
-		    dataPath.flowEntries().add(flowEntry);
-		    // TODO (BOC): why is this twice?
-		    dataPath.flowEntries().add(flowEntry);
-		}
-
-	
-		if (dataPath.flowEntries().size() > 0) {
-		    FlowPath flowPath = new FlowPath();
-			flowPath.setDataPath(dataPath);
-
-			return flowPath;
-		}
-		return null;		
-		
-	}
-
-	@Override
-	public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
-		// TODO Auto-generated method stub
-		return null;
-	}
-
-
-	@Override
-	public boolean installRemoteFlowEntry(FlowPath flowPath,
-					      FlowEntry entry) {
-		// TODO Auto-generated method stub
-		return false;
-	}
-
-	@Override
-	public boolean removeRemoteFlowEntry(FlowPath flowPath,
-					     FlowEntry entry) {
-		return false;
-		// TODO Auto-generated method stub
-
-	}
-
-	@Override
-	public boolean installFlowEntry(IOFSwitch mySwitch,
-					FlowPath flowPath,
-					FlowEntry flowEntry) {
-		// TODO Auto-generated method stub
-		return false;
-	}
-
-	@Override
-	public boolean removeFlowEntry(IOFSwitch mySwitch,
-				       FlowPath flowPath,
-				       FlowEntry flowEntry) {
-		// TODO Auto-generated method stub
-		return false;
-	}
-	
-
-}
diff --git a/src/main/java/net/onrc/onos/flow/IFlowManager.java b/src/main/java/net/onrc/onos/flow/IFlowManager.java
deleted file mode 100644
index 598da85..0000000
--- a/src/main/java/net/onrc/onos/flow/IFlowManager.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package net.onrc.onos.flow;
-
-import net.floodlightcontroller.core.IOFSwitch;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
-import net.onrc.onos.ofcontroller.util.FlowEntry;
-import net.onrc.onos.ofcontroller.util.FlowPath;
-
-public interface IFlowManager {
-    /**
-     * Create a Flow from port to port.
-     *
-     * TODO: We don't need it for now.
-     *
-     * @param src_port the source port.
-     * @param dest_port the destination port.
-     */
-    public void createFlow(IPortObject src_port, IPortObject dest_port);
-
-    /**
-     * Get all Flows matching a source and a destination port.
-     *
-     * TODO: Pankaj might be implementing it later.
-     *
-     * @param src_port the source port to match.
-     * @param dest_port the destination port to match.
-     * @return all flows matching the source and the destination port.
-     */
-    public Iterable<FlowPath> getFlows(IPortObject src_port,
-				       IPortObject dest_port);
-
-    /**
-     * Get all Flows going out from a port.
-     *
-     * TODO: We need it now: Pankaj
-     *
-     * @param port the port to match.
-     * @return the list of flows that are going out from the port.
-     */
-    public Iterable<FlowPath> getOutFlows(IPortObject port);
-
-    /**
-     * Reconcile all flows on inactive switch port.
-     *
-     * @param portObject the port that has become inactive.
-     */
-    public void reconcileFlows(IPortObject portObject);
-
-    /**
-     * Reconcile all flows between a source and a destination port.
-     *
-     * TODO: We don't need it for now.
-     *
-     * @param src_port the source port.
-     * @param dest_port the destination port.
-     */
-    public void reconcileFlow(IPortObject src_port, IPortObject dest_port);
-
-    /**
-     * Compute the shortest path between a source and a destination ports.
-     *
-     * @param src_port the source port.
-     * @param dest_port the destination port.
-     * @return the computed shortest path between the source and the
-     * destination ports. The flow entries in the path itself would
-     * contain the incoming port matching and the outgoing port output
-     * actions set. However, the path itself will NOT have the Flow ID,
-     * Installer ID, and any additional matching conditions for the
-     * flow entries (e.g., source or destination MAC address, etc).
-     */
-    public FlowPath computeFlowPath(IPortObject src_port,
-				    IPortObject dest_port);
-
-    /**
-     * Get all Flow Entries of a Flow.
-     *
-     * @param flow the flow whose flow entries should be returned.
-     * @return the flow entries of the flow.
-     */
-    public Iterable<FlowEntry> getFlowEntries(FlowPath flow);
-
-    /**
-     * Install a Flow Entry on a switch.
-     *
-     * @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.
-     */
-    public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
-				    FlowEntry flowEntry);
-
-    /**
-     * Remove a Flow Entry from a switch.
-     *
-     * @param mySwitch the switch to remove the Flow Entry from.
-     * @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 removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
-				   FlowEntry 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);
-
-    /**
-     * 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);
-}
diff --git a/src/main/java/net/onrc/onos/graph/GraphDBOperation.java b/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
index bfd9046..03b4c96 100644
--- a/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
+++ b/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
@@ -176,9 +176,14 @@
 	 */
 	public IPortObject searchPort(String dpid, Short number) {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
+		if ( fg == null ) return null;
 		String id = dpid + number.toString();
-		return (fg != null && fg.getVertices("port_id",id).iterator().hasNext()) ? 
-				fg.getVertices("port_id",id,IPortObject.class).iterator().next() : null;
+		Iterator<IPortObject> ports =  fg.getVertices("port_id",id,IPortObject.class).iterator();
+		if ( ports.hasNext() ) {
+			return ports.next();
+		} else {
+			return null;
+		}
 	}
 
 	/**
@@ -206,10 +211,14 @@
 	 * @param macAddr MAC address to search and get
 	 */
 	public IDeviceObject searchDevice(String macAddr) {
-		// TODO Auto-generated method stub
-		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
-		return (fg != null && fg.getVertices("dl_addr",macAddr).iterator().hasNext()) ?
-			fg.getVertices("dl_addr",macAddr, IDeviceObject.class).iterator().next() : null;
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
+		if ( fg == null ) return null;
+		Iterator<IDeviceObject> devices =  fg.getVertices("dl_addr",macAddr, IDeviceObject.class).iterator();
+		if ( devices.hasNext() ) {
+			return devices.next();
+		} else {
+			return null;
+		}
 	}
 
 	/**
@@ -288,10 +297,13 @@
 	 */
 	public IFlowPath searchFlowPath(FlowId flowId) {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
-		
-		return fg.getVertices("flow_id", flowId.toString()).iterator().hasNext() ? 
-		    fg.getVertices("flow_id", flowId.toString(),
-				   IFlowPath.class).iterator().next() : null;
+		if ( fg == null ) return null;
+		Iterator<IFlowPath> flowpaths = fg.getVertices("flow_id", flowId.toString(), IFlowPath.class).iterator();
+		if ( flowpaths.hasNext() ) {
+			return flowpaths.next();
+		} else {
+			return null;
+		}
 	}
 
 	/**
@@ -299,10 +311,10 @@
 	 * @param flowEntry flow entry object
 	 */
 	public IFlowPath getFlowPathByFlowEntry(IFlowEntry flowEntry) {
-		GremlinPipeline<Vertex, IFlowPath> pipe = new GremlinPipeline<Vertex, IFlowPath>();
-		pipe.start(flowEntry.asVertex());
-		pipe.out("flow");
-		FramedVertexIterable<IFlowPath> r = new FramedVertexIterable(conn.getFramedGraph(), (Iterable) pipe, IFlowPath.class);
+		GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
+		pipe.start(flowEntry.asVertex()).out("flow");
+		FramedVertexIterable<IFlowPath> r = new FramedVertexIterable<IFlowPath>(conn.getFramedGraph(),
+				(Iterable<Vertex>) pipe, IFlowPath.class);
 		return r.iterator().hasNext() ? r.iterator().next() : null;
 	}
 
@@ -348,10 +360,13 @@
 	 */
 	public IFlowEntry searchFlowEntry(FlowEntryId flowEntryId) {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
-		
-		return fg.getVertices("flow_entry_id", flowEntryId.toString()).iterator().hasNext() ? 
-		    fg.getVertices("flow_entry_id", flowEntryId.toString(),
-				   IFlowEntry.class).iterator().next() : null;
+		if ( fg == null ) return null;
+		Iterator<IFlowEntry> flowentries = fg.getVertices("flow_entry_id", flowEntryId.toString(), IFlowEntry.class).iterator();
+		if ( flowentries.hasNext() ) {
+			return flowentries.next();
+		} else {
+			return null;
+		}
 	}
 
 	/**
diff --git a/src/main/java/net/onrc/onos/graph/LocalTopologyEventListener.java b/src/main/java/net/onrc/onos/graph/LocalTopologyEventListener.java
index 5388233..40f5044 100644
--- a/src/main/java/net/onrc/onos/graph/LocalTopologyEventListener.java
+++ b/src/main/java/net/onrc/onos/graph/LocalTopologyEventListener.java
@@ -1,7 +1,5 @@
 package net.onrc.onos.graph;
 
-import net.onrc.onos.flow.FlowManagerImpl;
-import net.onrc.onos.flow.IFlowManager;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
 
 import org.slf4j.Logger;
@@ -52,9 +50,12 @@
 																src_port.getNumber(),
 																dest_port.getSwitch().getDPID(),
 																dest_port.getNumber()});
-			IFlowManager manager = new FlowManagerImpl();
 			// TODO: Find the flows and add to reconcile queue
-			manager.reconcileFlows(src_port);
+			//
+			// NOTE: Old code/logic.
+			//
+			// IFlowService flowManager = ...
+			// flowManager.reconcileFlows(src_port);
 		}
 	}
 
@@ -81,8 +82,11 @@
 			
 			IPortObject src_port = conn.getFramedGraph().frame(vertex, IPortObject.class);
 			log.debug("TopologyEvents: Port removed: {}:{}",src_port.getSwitch().getDPID(),src_port.getNumber());
-			IFlowManager manager = new FlowManagerImpl();
-			manager.reconcileFlows(src_port);			
+
+			// NOTE: Old code/logic.
+			//
+			// IFlowService flowManager = ...
+			// flowManager.reconcileFlows(src_port);
 		}
 	}
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Interface.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Interface.java
index 5db8f0a..cc454ec 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Interface.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Interface.java
@@ -14,7 +14,6 @@
 
 public class Interface {
 	private final String name;
-	private final SwitchPort switchPort;
 	private final long dpid;
 	private final short port;
 	private final InetAddress ipAddress;
@@ -31,7 +30,6 @@
 		this.port = port;
 		this.ipAddress = InetAddresses.forString(ipAddress);
 		this.prefixLength = prefixLength;
-		this.switchPort = new SwitchPort(new Dpid(this.dpid), new Port(this.port));
 	}
 	
 	public String getName() {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Ptree.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Ptree.java
index 041061c..c80d055 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Ptree.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Ptree.java
@@ -244,7 +244,6 @@
 		add.parent = node;
 	}
 	
-	@SuppressWarnings("unused")
     private PtreeNode node_common(PtreeNode node, byte [] key, int key_bits) {
 		int i;
 		int limit = Math.min(node.keyBits, key_bits) / 8;
@@ -275,8 +274,6 @@
 		}
 		
 		PtreeNode add = new PtreeNode(null, common_len, maxKeyOctets);
-		if (add == null)
-			return null;
 		
 		int j;
 		for (j = 0; j < i; j++)
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
index 869333b..29c4377 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
@@ -1,7 +1,5 @@
 package net.onrc.onos.ofcontroller.core;
 
-import net.onrc.onos.ofcontroller.flowmanager.web.DatapathSummarySerializer;
-
 import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
@@ -13,6 +11,9 @@
 import com.tinkerpop.frames.annotations.gremlin.GremlinParam;
 import com.tinkerpop.frames.VertexFrame;
 
+import net.onrc.onos.ofcontroller.flowmanager.web.DatapathSummarySerializer;
+import net.floodlightcontroller.core.web.serializers.IPv4Serializer;
+
 /*
  * This is the interfaces to make the objects for Cassandra DB.
  * They are interfaces, but it is also implementation,
@@ -117,6 +118,7 @@
 		@Adjacency(label="host")
 		public void removeDevice(final IDeviceObject device);
 		
+		
 		@JsonIgnore
 		@Adjacency(label="inport",direction = Direction.IN)
 		public Iterable<IFlowEntry> getInFlowEntries();
@@ -125,6 +127,7 @@
 		@Adjacency(label="outport",direction = Direction.IN)
 		public Iterable<IFlowEntry> getOutFlowEntries();
 		
+		
 		@JsonIgnore
 		@Adjacency(label="link")
 		public Iterable<IPortObject> getLinkedPorts();
@@ -203,6 +206,7 @@
 		
 		@JsonProperty("ipv4")
 		@Property("ipv4_address")
+		@JsonSerialize(using=IPv4Serializer.class)
 		public int getIpv4Address();
 		
 		@Property("ipv4_address")
@@ -249,6 +253,20 @@
 		@Property("flow_path_flags")
 		public void setFlowPathFlags(Long flowPathFlags);
 
+		@JsonProperty("idleTimeout")
+		@Property("idle_timeout")
+		public Integer getIdleTimeout();
+
+		@Property("idle_timeout")
+		public void setIdleTimeout(Integer idleTimeout);
+
+		@JsonProperty("hardTimeout")
+		@Property("hard_timeout")
+		public Integer getHardTimeout();
+
+		@Property("hard_timeout")
+		public void setHardTimeout(Integer hardTimeout);
+
 		@JsonProperty("srcDpid")
 		@Property("src_switch")
 		public String getSrcSwitch();
@@ -403,6 +421,20 @@
 		@Property("flow_entry_id")
 		public void setFlowEntryId(String flowEntryId);
 
+		@JsonProperty("idleTimeout")
+		@Property("idle_timeout")
+		public Integer getIdleTimeout();
+
+		@Property("idle_timeout")
+		public void setIdleTimeout(Integer idleTimeout);
+
+		@JsonProperty("hardTimeout")
+		@Property("hard_timeout")
+		public Integer getHardTimeout();
+
+		@Property("hard_timeout")
+		public void setHardTimeout(Integer hardTimeout);
+
 		@Property("switch_dpid")
 		public String getSwitchDpid();
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/config/DefaultConfiguration.java b/src/main/java/net/onrc/onos/ofcontroller/core/config/DefaultConfiguration.java
index d9a291f..c406a91 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/config/DefaultConfiguration.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/config/DefaultConfiguration.java
@@ -1,13 +1,21 @@
 package net.onrc.onos.ofcontroller.core.config;
 
 import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 
+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.floodlightcontroller.util.MACAddress;
 import net.onrc.onos.ofcontroller.bgproute.Interface;
 
 import org.openflow.util.HexString;
 
-public class DefaultConfiguration implements IConfigInfoService {
+public class DefaultConfiguration implements IConfigInfoService, IFloodlightModule {
 
 	@Override
 	public boolean isInterfaceAddress(InetAddress address) {
@@ -44,4 +52,36 @@
 		return 0;
 	}
 
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+		Collection<Class<? extends IFloodlightService>> l 
+			= new ArrayList<Class<? extends IFloodlightService>>();
+		l.add(IConfigInfoService.class);
+		return l;
+	}
+
+	@Override
+	public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+		Map<Class<? extends IFloodlightService>, IFloodlightService> m 
+			= new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
+		m.put(IConfigInfoService.class, this);
+		return m;
+	}
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+		return null;
+	}
+
+	@Override
+	public void init(FloodlightModuleContext context)
+			throws FloodlightModuleException {
+		// no-op
+	}
+
+	@Override
+	public void startUp(FloodlightModuleContext context) {
+		// no-op
+	}
+
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/config/IConfigInfoService.java b/src/main/java/net/onrc/onos/ofcontroller/core/config/IConfigInfoService.java
index 7bbf483..39e0f7c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/config/IConfigInfoService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/config/IConfigInfoService.java
@@ -2,16 +2,16 @@
 
 import java.net.InetAddress;
 
+import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.util.MACAddress;
 import net.onrc.onos.ofcontroller.bgproute.Interface;
-import net.onrc.onos.ofcontroller.core.module.IOnosService;
 
 /**
  * Provides information about the layer 3 properties of the network.
  * This is based on IP addresses configured on ports in the network.
  *
  */
-public interface IConfigInfoService extends IOnosService {
+public interface IConfigInfoService extends IFloodlightService {
 	public boolean isInterfaceAddress(InetAddress address);
 	public boolean inConnectedNetwork(InetAddress address);
 	public boolean fromExternalNetwork(long inDpid, short inPort);
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
index f5f8b00..4bbc054 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
@@ -80,6 +80,10 @@
 	                log.debug("Adding device {}: creating new device", device.getMACAddressString());
 	            }
 	 			
+	            if (obj == null) {
+	            	return null;
+	            }
+	            
 	            changeDeviceAttachments(device, obj);
 		        
 	            changeDeviceIpv4Addresses(device, obj);
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
index 7a3d43e..635e24e 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
@@ -14,10 +14,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.tinkerpop.blueprints.Vertex;
-import com.tinkerpop.pipes.PipeFunction;
-import com.tinkerpop.pipes.transform.PathPipe;
-
 /**
  * This is the class for storing the information of links into GraphDB
  */
@@ -490,33 +486,4 @@
 	    
 	 	return success;
 	}
-
-	// TODO should be moved to TopoLinkServiceImpl (never used in this class)
-	static class ExtractLink implements PipeFunction<PathPipe<Vertex>, Link> {
-	
-		@SuppressWarnings("unchecked")
-		@Override
-		public Link compute(PathPipe<Vertex> pipe ) {
-			long s_dpid = 0;
-			long d_dpid = 0;
-			short s_port = 0;
-			short d_port = 0;
-			List<Vertex> V = new ArrayList<Vertex>();
-			V = (List<Vertex>)pipe.next();
-			Vertex src_sw = V.get(0);
-			Vertex dest_sw = V.get(3);
-			Vertex src_port = V.get(1);
-			Vertex dest_port = V.get(2);
-			s_dpid = HexString.toLong((String) src_sw.getProperty("dpid"));
-			d_dpid = HexString.toLong((String) dest_sw.getProperty("dpid"));
-			s_port = (Short) src_port.getProperty("number");
-			d_port = (Short) dest_port.getProperty("number");
-			
-			Link l = new Link(s_dpid,s_port,d_dpid,d_port);
-			
-			return l;
-		}
-	}
-
-
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
index dcfdc73..5f51b58 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
@@ -348,7 +348,6 @@
 	        	IPortObject p = sw.getPort(port);
 	            if (p != null) {
 	        		log.info("SwitchStorage:deletePort dpid:{} port:{} found and set INACTIVE", dpid, port);
-	        		//deletePortImpl(p);
 	        		p.setState("INACTIVE");
 	        		
 	        		// XXX for now delete devices when we change a port to prevent
@@ -492,12 +491,4 @@
 	    			new Object[] {port.getPortId(), state, desc});
 		}
 	}
-	
-	private void deletePortImpl(IPortObject port) {
-		if (port != null) {
-			op.removePort(port);
-	    	log.info("SwitchStorage:deletePortImpl port:{} done",
-	    			port.getPortId());
-		}
-	}
 }
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoLinkServiceImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoLinkServiceImpl.java
index b692e8e..f1f015a 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoLinkServiceImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/TopoLinkServiceImpl.java
@@ -7,13 +7,15 @@
 import net.onrc.onos.graph.GraphDBOperation;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
-import net.onrc.onos.ofcontroller.core.internal.LinkStorageImpl.ExtractLink;
 
+import org.openflow.util.HexString;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.tinkerpop.blueprints.Vertex;
 import com.tinkerpop.gremlin.java.GremlinPipeline;
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.transform.PathPipe;
 
 public class TopoLinkServiceImpl implements ITopoLinkService {
 	
@@ -31,7 +33,6 @@
  
 	@Override
 	public List<Link> getActiveLinks() {
-		// TODO Auto-generated method stub
 		op = new GraphDBOperation("");
 		op.commit(); //Commit to ensure we see latest data
 		Iterable<ISwitchObject> switches = op.getActiveSwitches();
@@ -56,7 +57,6 @@
 
 	@Override
 	public List<Link> getLinksOnSwitch(String dpid) {
-		// TODO Auto-generated method stub
 		List<Link> links = new ArrayList<Link>(); 
 		ISwitchObject sw = op.searchSwitch(dpid);
 		GremlinPipeline<Vertex, Link> pipe = new GremlinPipeline<Vertex, Link>();
@@ -73,5 +73,29 @@
 		return links;
 
 	}
-	
+
+	private class ExtractLink implements PipeFunction<PathPipe<Vertex>, Link> {
+		@Override
+		public Link compute(PathPipe<Vertex> pipe) {
+			long s_dpid = 0;
+			long d_dpid = 0;
+			short s_port = 0;
+			short d_port = 0;
+			
+			@SuppressWarnings("unchecked")
+			List<Vertex> V = pipe.next();
+			Vertex src_sw = V.get(0);
+			Vertex dest_sw = V.get(3);
+			Vertex src_port = V.get(1);
+			Vertex dest_port = V.get(2);
+			s_dpid = HexString.toLong((String) src_sw.getProperty("dpid"));
+			d_dpid = HexString.toLong((String) dest_sw.getProperty("dpid"));
+			s_port = (Short) src_port.getProperty("number");
+			d_port = (Short) dest_port.getProperty("number");
+			
+			Link l = new Link(s_dpid,s_port,d_dpid,d_port);
+			
+			return l;
+		}
+	}
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/module/IOnosService.java b/src/main/java/net/onrc/onos/ofcontroller/core/module/IOnosService.java
deleted file mode 100644
index 5828366..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/core/module/IOnosService.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package net.onrc.onos.ofcontroller.core.module;
-
-import net.floodlightcontroller.core.module.IFloodlightService;
-
-public interface IOnosService extends IFloodlightService {
-
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/module/OnosModuleLoader.java b/src/main/java/net/onrc/onos/ofcontroller/core/module/OnosModuleLoader.java
deleted file mode 100644
index 6b8b514..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/core/module/OnosModuleLoader.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package net.onrc.onos.ofcontroller.core.module;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-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.floodlightcontroller.restserver.IRestApiService;
-import net.floodlightcontroller.topology.ITopologyService;
-import net.onrc.onos.datagrid.IDatagridService;
-import net.onrc.onos.ofcontroller.core.config.DefaultConfiguration;
-import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
-import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
-import net.onrc.onos.ofcontroller.forwarding.Forwarding;
-import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
-import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
-
-public class OnosModuleLoader implements IFloodlightModule {
-	private IFloodlightProviderService floodlightProvider;
-	private ITopologyService topology;
-	private IConfigInfoService config;
-	private IRestApiService restApi;
-	private IFlowService flowService;
-	private IDatagridService datagrid;
-
-	private ProxyArpManager arpManager;
-	private Forwarding forwarding;
-	
-	public OnosModuleLoader() {
-		arpManager = new ProxyArpManager();
-		forwarding = new Forwarding();
-	}
-	
-	@Override
-	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-		List<Class<? extends IFloodlightService>> services = 
-				new ArrayList<Class<? extends IFloodlightService>>();
-		services.add(IProxyArpService.class);
-		return services;
-	}
-
-	@Override
-	public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
-		Map<Class<? extends IFloodlightService>, IFloodlightService> impls = 
-				new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
-		impls.put(IProxyArpService.class, arpManager);
-		return impls;
-	}
-
-	@Override
-	public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
-		List<Class<? extends IFloodlightService>> dependencies = 
-				new ArrayList<Class<? extends IFloodlightService>>();
-		dependencies.add(IFloodlightProviderService.class);
-		dependencies.add(ITopologyService.class);
-		dependencies.add(IRestApiService.class);
-		dependencies.add(IFlowService.class);
-		dependencies.add(IDatagridService.class);
-		return dependencies;
-	}
-
-	@Override
-	public void init(FloodlightModuleContext context)
-			throws FloodlightModuleException {
-		floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
-		topology = context.getServiceImpl(ITopologyService.class);
-		restApi = context.getServiceImpl(IRestApiService.class);
-		flowService = context.getServiceImpl(IFlowService.class);
-		datagrid = context.getServiceImpl(IDatagridService.class);
-		
-		//This could be null because it's not mandatory to have an
-		//IConfigInfoService loaded.
-		config = context.getServiceImpl(IConfigInfoService.class);
-		if (config == null) {
-			config = new DefaultConfiguration();
-		}
-
-		arpManager.init(floodlightProvider, topology, datagrid, config, restApi);
-		forwarding.init(floodlightProvider, flowService, datagrid);
-	}
-
-	@Override
-	public void startUp(FloodlightModuleContext context) {
-		arpManager.startUp();
-		forwarding.startUp();
-	}
-
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/web/TopoSwitchesResource.java b/src/main/java/net/onrc/onos/ofcontroller/core/web/TopoSwitchesResource.java
index a173a70..6d3f161 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/web/TopoSwitchesResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/web/TopoSwitchesResource.java
@@ -17,12 +17,12 @@
 		String filter = (String) getRequestAttributes().get("filter");
 		
 		if (filter.equals("active")) {
-			return (Iterator<ISwitchObject>) impl.getActiveSwitches().iterator();
+			return impl.getActiveSwitches().iterator();
 		}
 		if (filter.equals("inactive")) {
-			return (Iterator<ISwitchObject>) impl.getInactiveSwitches().iterator();
+			return impl.getInactiveSwitches().iterator();
 		} else {
-		    return (Iterator<ISwitchObject>) impl.getAllSwitches().iterator();
+		    return impl.getAllSwitches().iterator();
 		}
 	}
 
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 104032b..4b31667 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
@@ -39,7 +39,6 @@
 import net.onrc.onos.ofcontroller.core.ISwitchStorage;
 import net.onrc.onos.ofcontroller.core.INetMapStorage.DM_OPERATION;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
-import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
 import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
 import net.onrc.onos.ofcontroller.core.internal.LinkStorageImpl;
 import net.onrc.onos.ofcontroller.core.internal.SwitchStorageImpl;
@@ -244,10 +243,13 @@
 			    // Publish: add the ports
 			    // TODO: Add only ports that are UP?
 			    for (OFPhysicalPort port : sw.getPorts()) {
-				TopologyElement topologyElementPort =
-				    new TopologyElement(sw.getId(),
-							port.getPortNumber());
-				datagridService.notificationSendTopologyElementAdded(topologyElementPort);
+					TopologyElement topologyElementPort =
+					    new TopologyElement(sw.getId(), port.getPortNumber());
+					datagridService.notificationSendTopologyElementAdded(topologyElementPort);
+					
+					// Allow links to be discovered on this port now that it's
+					// in the database
+					linkDiscovery.RemoveFromSuppressLLDPs(sw.getId(), port.getPortNumber());
 			    }
 
 			    // Add all links that might be connected already
@@ -316,6 +318,10 @@
 	@Override
 	public void switchPortAdded(Long switchId, OFPhysicalPort port) {
 		if (swStore.addPort(HexString.toHexString(switchId), port)) {
+			// Allow links to be discovered on this port now that it's
+			// in the database
+			linkDiscovery.RemoveFromSuppressLLDPs(switchId, port.getPortNumber());
+			
 		    // TODO publish ADD_PORT event here
 		    TopologyElement topologyElement =
 			new TopologyElement(switchId, port.getPortNumber());
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
index f623541..da407ab 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
@@ -3,11 +3,8 @@
 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;
 
@@ -25,21 +22,17 @@
 /**
  * Class for performing Flow-related operations on the Database.
  */
-class FlowDatabaseOperation {
+public class FlowDatabaseOperation {
     private final 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.
      * @return true on success, otherwise false.
      */
-    static boolean addFlow(FlowManager flowManager,
-			   GraphDBOperation dbHandler,
-			   FlowPath flowPath, FlowId flowId) {
+    static boolean addFlow(GraphDBOperation dbHandler, FlowPath flowPath) {
 	IFlowPath flowObj = null;
 	boolean found = false;
 	try {
@@ -68,6 +61,21 @@
 	}
 
 	//
+	// Remove the old Flow Entries
+	//
+	if (found) {
+	    Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
+	    LinkedList<IFlowEntry> deleteFlowEntries =
+		new LinkedList<IFlowEntry>();
+	    for (IFlowEntry flowEntryObj : flowEntries)
+		deleteFlowEntries.add(flowEntryObj);
+	    for (IFlowEntry flowEntryObj : deleteFlowEntries) {
+		flowObj.removeFlowEntry(flowEntryObj);
+		dbHandler.removeFlowEntry(flowEntryObj);
+	    }
+	}
+
+	//
 	// Set the Flow key:
 	// - flowId
 	//
@@ -80,6 +88,8 @@
 	// - flowPath.flowPathType()
 	// - flowPath.flowPathUserState()
 	// - flowPath.flowPathFlags()
+	// - flowPath.idleTimeout()
+	// - flowPath.hardTimeout()
 	// - flowPath.dataPath().srcPort()
 	// - flowPath.dataPath().dstPort()
 	// - flowPath.matchSrcMac()
@@ -99,6 +109,8 @@
 	flowObj.setFlowPathType(flowPath.flowPathType().toString());
 	flowObj.setFlowPathUserState(flowPath.flowPathUserState().toString());
 	flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
+	flowObj.setIdleTimeout(flowPath.idleTimeout());
+	flowObj.setHardTimeout(flowPath.hardTimeout());
 	flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
 	flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
 	flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
@@ -155,46 +167,33 @@
 	// flowPath.dataPath().flowEntries()
 	//
 	for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
-	    if (addFlowEntry(flowManager, dbHandler, flowObj, flowEntry) == null) {
+	    if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE)
+		continue;	// Skip: all Flow Entries were deleted earlier
+
+	    if (addFlowEntry(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,
+    static IFlowEntry addFlowEntry(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 {
@@ -228,6 +227,8 @@
 	// - InPort edge
 	// - OutPort edge
 	//
+	// - flowEntry.idleTimeout()
+	// - flowEntry.hardTimeout()
 	// - flowEntry.dpid()
 	// - flowEntry.flowEntryUserState()
 	// - flowEntry.flowEntrySwitchState()
@@ -248,6 +249,8 @@
 	// - flowEntry.actions()
 	//
 	ISwitchObject sw = dbHandler.searchSwitch(flowEntry.dpid().toString());
+	flowEntryObj.setIdleTimeout(flowEntry.idleTimeout());
+	flowEntryObj.setHardTimeout(flowEntry.hardTimeout());
 	flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
 	flowEntryObj.setSwitch(sw);
 	if (flowEntry.flowEntryMatch().matchInPort()) {
@@ -370,122 +373,6 @@
      * @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.setFlowPathUserState("FP_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
@@ -500,29 +387,29 @@
 	    allFlowIds.add(flowId);
 	}
 
-	// Clear all flows one-by-one
+	// Delete all flows one-by-one
 	for (FlowId flowId : allFlowIds) {
-	    clearFlow(dbHandler, flowId);
+	    deleteFlow(dbHandler, flowId);
 	}
 
 	return true;
     }
 
     /**
-     * Clear the state for a previously added flow.
+     * Delete a previously added flow.
      *
      * @param dbHandler the Graph Database handler to use.
-     * @param flowId the Flow ID of the flow to clear.
+     * @param flowId the Flow ID of the flow to delete.
      * @return true on success, otherwise false.
      */
-    static boolean clearFlow(GraphDBOperation dbHandler, FlowId flowId) {
+    static boolean deleteFlow(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());
+	    log.error(":deleteFlow FlowId:{} failed", flowId.toString());
 	    return false;
 	}
 	if (flowObj == null) {
@@ -614,166 +501,6 @@
     }
 
     /**
-     * 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.
@@ -788,6 +515,8 @@
 	String flowPathType = flowObj.getFlowPathType();
 	String flowPathUserState = flowObj.getFlowPathUserState();
 	Long flowPathFlags = flowObj.getFlowPathFlags();
+	Integer idleTimeout = flowObj.getIdleTimeout();
+	Integer hardTimeout = flowObj.getHardTimeout();
 	String srcSwitchStr = flowObj.getSrcSwitch();
 	Short srcPortShort = flowObj.getSrcPort();
 	String dstSwitchStr = flowObj.getDstSwitch();
@@ -798,6 +527,8 @@
 	    (flowPathType == null) ||
 	    (flowPathUserState == null) ||
 	    (flowPathFlags == null) ||
+	    (idleTimeout == null) ||
+	    (hardTimeout == null) ||
 	    (srcSwitchStr == null) ||
 	    (srcPortShort == null) ||
 	    (dstSwitchStr == null) ||
@@ -812,6 +543,8 @@
 	flowPath.setFlowPathType(FlowPathType.valueOf(flowPathType));
 	flowPath.setFlowPathUserState(FlowPathUserState.valueOf(flowPathUserState));
 	flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
+	flowPath.setIdleTimeout(idleTimeout);
+	flowPath.setHardTimeout(hardTimeout);
 	flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
 	flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
 	flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
@@ -890,11 +623,15 @@
      */
     public static FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
 	String flowEntryIdStr = flowEntryObj.getFlowEntryId();
+	Integer idleTimeout = flowEntryObj.getIdleTimeout();
+	Integer hardTimeout = flowEntryObj.getHardTimeout();
 	String switchDpidStr = flowEntryObj.getSwitchDpid();
 	String userState = flowEntryObj.getUserState();
 	String switchState = flowEntryObj.getSwitchState();
 
 	if ((flowEntryIdStr == null) ||
+	    (idleTimeout == null) ||
+	    (hardTimeout == null) ||
 	    (switchDpidStr == null) ||
 	    (userState == null) ||
 	    (switchState == null)) {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
index 0e9887a..3538eb4 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
@@ -7,6 +7,8 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 
@@ -27,24 +29,14 @@
 import net.onrc.onos.ofcontroller.util.FlowId;
 import net.onrc.onos.ofcontroller.util.FlowPath;
 import net.onrc.onos.ofcontroller.util.FlowPathUserState;
+import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
+
+import com.esotericsoftware.kryo2.Kryo;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * A class for storing a pair of Flow Path and a Flow Entry.
- */
-class FlowPathEntryPair {
-    protected FlowPath flowPath;
-    protected FlowEntry flowEntry;
-
-    protected FlowPathEntryPair(FlowPath flowPath, FlowEntry flowEntry) {
-	this.flowPath = flowPath;
-	this.flowEntry = flowEntry;
-    }
-}
-
-/**
  * Class for FlowPath Maintenance.
  * This class listens for FlowEvents to:
  * - Maintain a local cache of the Network Topology.
@@ -58,9 +50,7 @@
     private FlowManager flowManager;		// The Flow Manager to use
     private IDatagridService datagridService;	// The Datagrid Service to use
     private Topology topology;			// The network topology
-    private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
-    private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
-	new HashMap<Long, FlowEntry>();
+    private KryoFactory kryoFactory = new KryoFactory();
 
     // The queue with Flow Path and Topology Element updates
     private BlockingQueue<EventEntry<?>> networkEvents =
@@ -74,21 +64,25 @@
     private List<EventEntry<FlowEntry>> flowEntryEvents =
 	new LinkedList<EventEntry<FlowEntry>>();
 
+    // All internally computed Flow Paths
+    private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
+
+    // The Flow Entries received as notifications with unmatched Flow Paths
+    private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
+	new HashMap<Long, FlowEntry>();
+
     //
     // Transient state for processing the Flow Paths:
-    //  - The new Flow Paths
     //  - The Flow Paths that should be recomputed
     //  - The Flow Paths with modified Flow Entries
-    //  - The Flow Entries that were updated
+    //  - The Flow Paths that we should check if installed in all switches
     //
-    private List<FlowPath> newFlowPaths = new LinkedList<FlowPath>();
-    private List<FlowPath> recomputeFlowPaths = new LinkedList<FlowPath>();
-    private List<FlowPath> modifiedFlowPaths = new LinkedList<FlowPath>();
-    private List<FlowPathEntryPair> updatedFlowEntries =
-	new LinkedList<FlowPathEntryPair>();
-    private List<FlowPathEntryPair> unmatchedDeleteFlowEntries =
-	new LinkedList<FlowPathEntryPair>();
-
+    private Map<Long, FlowPath> shouldRecomputeFlowPaths =
+	new HashMap<Long, FlowPath>();
+    private Map<Long, FlowPath> modifiedFlowPaths =
+	new HashMap<Long, FlowPath>();
+    private Map<Long, FlowPath> checkIfInstalledFlowPaths =
+	new HashMap<Long, FlowPath>();
 
     /**
      * Constructor for a given Flow Manager and Datagrid Service.
@@ -144,7 +138,9 @@
 	}
 
 	// Process the initial events (if any)
-	processEvents();
+	synchronized (allFlowPaths) {
+	    processEvents();
+	}
     }
 
     /**
@@ -171,24 +167,36 @@
 		//  - EventEntry<FlowEntry>
 		//
 		for (EventEntry<?> event : collection) {
+		    // Topology event
 		    if (event.eventData() instanceof TopologyElement) {
 			EventEntry<TopologyElement> topologyEventEntry =
 			    (EventEntry<TopologyElement>)event;
 			topologyEvents.add(topologyEventEntry);
-		    } else if (event.eventData() instanceof FlowPath) {
+			continue;
+		    }
+
+		    // FlowPath event
+		    if (event.eventData() instanceof FlowPath) {
 			EventEntry<FlowPath> flowPathEventEntry =
 			    (EventEntry<FlowPath>)event;
 			flowPathEvents.add(flowPathEventEntry);
-		    } else if (event.eventData() instanceof FlowEntry) {
+			continue;
+		    }
+
+		    // FlowEntry event
+		    if (event.eventData() instanceof FlowEntry) {
 			EventEntry<FlowEntry> flowEntryEventEntry =
 			    (EventEntry<FlowEntry>)event;
 			flowEntryEvents.add(flowEntryEventEntry);
+			continue;
 		    }
 		}
 		collection.clear();
 
 		// Process the events (if any)
-		processEvents();
+		synchronized (allFlowPaths) {
+		    processEvents();
+		}
 	    }
 	} catch (Exception exception) {
 	    log.debug("Exception processing Network Events: ", exception);
@@ -199,7 +207,7 @@
      * Process the events (if any)
      */
     private void processEvents() {
-	List<FlowPathEntryPair> modifiedFlowEntries;
+	Collection<FlowEntry> modifiedFlowEntries;
 
 	if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
 	    flowEntryEvents.isEmpty()) {
@@ -208,70 +216,101 @@
 
 	processFlowPathEvents();
 	processTopologyEvents();
-	//
-	// Add all new Flows: should be done after processing the Flow Path
-	// and Topology events.
-	//
-	for (FlowPath flowPath : newFlowPaths) {
-	    allFlowPaths.put(flowPath.flowId().value(), flowPath);
-	}
-
 	processFlowEntryEvents();
 
 	// Recompute all affected Flow Paths and keep only the modified
-	for (FlowPath flowPath : recomputeFlowPaths) {
+	for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
 	    if (recomputeFlowPath(flowPath))
-		modifiedFlowPaths.add(flowPath);
+		modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
 	}
 
-	modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths);
+	// Extract the modified Flow Entries
+	modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
 
 	// Assign missing Flow Entry IDs
 	assignFlowEntryId(modifiedFlowEntries);
 
 	//
-	// Push the modified Flow Entries to switches, datagrid and database
+	// Push the modified state to the Flow Manager
 	//
-	flowManager.pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
-	flowManager.pushModifiedFlowEntriesToDatagrid(modifiedFlowEntries);
-	flowManager.pushModifiedFlowEntriesToDatabase(modifiedFlowEntries);
-	flowManager.pushModifiedFlowEntriesToDatabase(updatedFlowEntries);
-	flowManager.pushModifiedFlowEntriesToDatabase(unmatchedDeleteFlowEntries);
+	flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
+					  modifiedFlowEntries);
 
 	//
 	// Remove Flow Entries that were deleted
 	//
-	for (FlowPath flowPath : modifiedFlowPaths)
+	for (FlowPath flowPath : modifiedFlowPaths.values())
 	    flowPath.dataPath().removeDeletedFlowEntries();
 
+	//
+	// Check if Flow Paths have been installed into all switches,
+	// and generate the appropriate events.
+	//
+	checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
+
 	// Cleanup
 	topologyEvents.clear();
 	flowPathEvents.clear();
 	flowEntryEvents.clear();
 	//
-	newFlowPaths.clear();
-	recomputeFlowPaths.clear();
+	shouldRecomputeFlowPaths.clear();
 	modifiedFlowPaths.clear();
-	updatedFlowEntries.clear();
-	unmatchedDeleteFlowEntries.clear();
+	checkIfInstalledFlowPaths.clear();
+    }
+
+    /**
+     * Check if Flow Paths have been installed into all switches,
+     * and generate the appropriate events.
+     *
+     * @param flowPaths the flowPaths to process.
+     */
+    private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
+	List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
+
+	Kryo kryo = kryoFactory.newKryo();
+
+	for (FlowPath flowPath : flowPaths) {
+	    boolean isInstalled = true;
+
+	    //
+	    // Check whether all Flow Entries have been installed
+	    //
+	    for (FlowEntry flowEntry : flowPath.flowEntries()) {
+		if (flowEntry.flowEntrySwitchState() !=
+		    FlowEntrySwitchState.FE_SWITCH_UPDATED) {
+		    isInstalled = false;
+		    break;
+		}
+	    }
+
+	    if (isInstalled) {
+		// Create a copy and add it to the list
+		FlowPath copyFlowPath = kryo.copy(flowPath);
+		installedFlowPaths.add(copyFlowPath);
+	    }
+	}
+	kryoFactory.deleteKryo(kryo);
+
+	// Generate an event for the installed Flow Path.
+	flowManager.notificationFlowPathsInstalled(installedFlowPaths);
     }
 
     /**
      * Extract the modified Flow Entries.
+     *
+     * @param modifiedFlowPaths the Flow Paths to process.
+     * @return a collection with the modified Flow Entries.
      */
-    private List<FlowPathEntryPair> extractModifiedFlowEntries(
-					List<FlowPath> modifiedFlowPaths) {
-	List<FlowPathEntryPair> modifiedFlowEntries =
-	    new LinkedList<FlowPathEntryPair>();
+    private Collection<FlowEntry> extractModifiedFlowEntries(
+			Collection<FlowPath> modifiedFlowPaths) {
+	List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
 
 	// Extract only the modified Flow Entries
 	for (FlowPath flowPath : modifiedFlowPaths) {
 	    for (FlowEntry flowEntry : flowPath.flowEntries()) {
 		if (flowEntry.flowEntrySwitchState() ==
 		    FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
-		    FlowPathEntryPair flowPair =
-			new FlowPathEntryPair(flowPath, flowEntry);
-		    modifiedFlowEntries.add(flowPair);
+		    modifiedFlowEntries.add(flowEntry);
 		}
 	    }
 	}
@@ -280,8 +319,11 @@
 
     /**
      * Assign the Flow Entry ID as needed.
+     *
+     * @param modifiedFlowEnries the collection of Flow Entries that need
+     * Flow Entry ID assigned.
      */
-    private void assignFlowEntryId(List<FlowPathEntryPair> modifiedFlowEntries) {
+    private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
 	if (modifiedFlowEntries.isEmpty())
 	    return;
 
@@ -290,9 +332,7 @@
 	//
 	// Assign the Flow Entry ID only for Flow Entries for my switches
 	//
-	for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
-	    FlowEntry flowEntry = flowPair.flowEntry;
-	    // Update the Flow Entries only for my switches
+	for (FlowEntry flowEntry : modifiedFlowEntries) {
 	    IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
 	    if (mySwitch == null)
 		continue;
@@ -324,10 +364,8 @@
 		if (allFlowPaths.get(flowPath.flowId().value()) != null) {
 		    //
 		    // TODO: What to do if the Flow Path already exists?
-		    // Remove and then re-add it, or merge the info?
-		    // For now, we don't have to do anything.
+		    // Fow now, we just re-add it.
 		    //
-		    break;
 		}
 
 		switch (flowPath.flowPathType()) {
@@ -337,7 +375,8 @@
 		    // we are going to recompute it anyway.
 		    //
 		    flowPath.flowEntries().clear();
-		    recomputeFlowPaths.add(flowPath);
+		    shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
+						 flowPath);
 		    break;
 		case FP_TYPE_EXPLICIT_PATH:
 		    //
@@ -346,10 +385,13 @@
 		    for (FlowEntry flowEntry : flowPath.flowEntries()) {
 			flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
 		    }
-		    modifiedFlowPaths.add(flowPath);
+		    modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
+		    break;
+		case FP_TYPE_UNKNOWN:
+		    log.error("FlowPath event with unknown type");
 		    break;
 		}
-		newFlowPaths.add(flowPath);
+		allFlowPaths.put(flowPath.flowId().value(), flowPath);
 
 		break;
 	    }
@@ -372,8 +414,11 @@
 		    flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
 		}
 
-		allFlowPaths.remove(existingFlowPath.flowId().value());
-		modifiedFlowPaths.add(existingFlowPath);
+		// Remove the Flow Path from the internal state
+		Long key = existingFlowPath.flowId().value();
+		allFlowPaths.remove(key);
+		shouldRecomputeFlowPaths.remove(key);
+		modifiedFlowPaths.put(key, existingFlowPath);
 
 		break;
 	    }
@@ -406,7 +451,7 @@
 	}
 	if (isTopologyModified) {
 	    // TODO: For now, if the topology changes, we recompute all Flows
-	    recomputeFlowPaths.addAll(allFlowPaths.values());
+	    shouldRecomputeFlowPaths.putAll(allFlowPaths);
 	}
     }
 
@@ -414,7 +459,6 @@
      * Process the Flow Entry events.
      */
     private void processFlowEntryEvents() {
-	FlowPathEntryPair flowPair;
 	FlowPath flowPath;
 	FlowEntry updatedFlowEntry;
 
@@ -433,8 +477,7 @@
 					 flowEntry);
 		    continue;
 		}
-		flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
-		updatedFlowEntries.add(flowPair);
+		modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
 	    }
 	    unmatchedFlowEntryAdd = remainingUpdates;
 	}
@@ -470,16 +513,15 @@
 		    break;
 		}
 		// Add the updated entry to the list of updated Flow Entries
-		flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
-		updatedFlowEntries.add(flowPair);
+		modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
 		break;
 
 	    case ENTRY_REMOVE:
 		flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
 		if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
-		    continue;		// Match found
+		    continue;		// Removed previously unmatched entry
 		}
-						 
+
 		flowPath = allFlowPaths.get(flowEntry.flowId().value());
 		if (flowPath == null) {
 		    // Flow Path not found: ignore the update
@@ -487,13 +529,10 @@
 		}
 		updatedFlowEntry = updateFlowEntryRemove(flowPath, flowEntry);
 		if (updatedFlowEntry == null) {
-		    // Flow Entry not found: add to list of deleted entries
-		    flowPair = new FlowPathEntryPair(flowPath, flowEntry);
-		    unmatchedDeleteFlowEntries.add(flowPair);
+		    // Flow Entry not found: ignore it
 		    break;
 		}
-		flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
-		updatedFlowEntries.add(flowPair);
+		modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
 		break;
 	    }
 	}
@@ -537,10 +576,12 @@
 	    }
 
 	    //
-	    // Update the local Flow Entry.
+	    // Update the local Flow Entry, and keep state to check
+	    // if the Flow Path has been installed.
 	    //
 	    localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
 	    localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
+	    checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
 	    return localFlowEntry;
 	}
 
@@ -710,9 +751,24 @@
 	    //
 	    newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
 
-	    // Set the incoming port matching
-	    FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
+	    //
+	    // Copy the Flow timeouts
+	    //
+	    newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
+	    newFlowEntry.setHardTimeout(flowPath.hardTimeout());
+
+	    //
+	    // Allocate the FlowEntryMatch by copying the default one
+	    // from the FlowPath (if set).
+	    //
+	    FlowEntryMatch flowEntryMatch = null;
+	    if (flowPath.flowEntryMatch() != null)
+		flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
+	    else
+		flowEntryMatch = new FlowEntryMatch();
 	    newFlowEntry.setFlowEntryMatch(flowEntryMatch);
+
+	    // Set the incoming port matching
 	    flowEntryMatch.enableInPort(newFlowEntry.inPort());
 
 	    //
@@ -864,4 +920,31 @@
 	    new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
 	networkEvents.add(eventEntry);
     }
+
+    /**
+     * Get a sorted copy of all Flow Paths.
+     *
+     * @return a sorted copy of all Flow Paths.
+     */
+    synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
+	SortedMap<Long, FlowPath> sortedFlowPaths =
+	    new TreeMap<Long, FlowPath>();
+
+	//
+	// TODO: For now we use serialization/deserialization to create
+	// a copy of each Flow Path. In the future, we should use proper
+	// copy constructors.
+	//
+	Kryo kryo = kryoFactory.newKryo();
+	synchronized (allFlowPaths) {
+	    for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
+		FlowPath origFlowPath = entry.getValue();
+		FlowPath copyFlowPath = kryo.copy(origFlowPath);
+		sortedFlowPaths.put(entry.getKey(), copyFlowPath);
+	    }
+	}
+	kryoFactory.deleteKryo(kryo);
+
+	return sortedFlowPaths;
+    }
 }
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 174d5d7..41cf670 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
@@ -2,14 +2,14 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
-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.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
+import java.util.SortedMap;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
@@ -18,20 +18,16 @@
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.restserver.IRestApiService;
-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.floodlightlistener.INetworkGraphService;
 import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
 import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
-import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
+import net.onrc.onos.ofcontroller.forwarding.IForwardingService;
 import net.onrc.onos.ofcontroller.topology.Topology;
 import net.onrc.onos.ofcontroller.util.*;
 
-import org.openflow.protocol.OFType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -39,344 +35,30 @@
  * Flow Manager class for handling the network flows.
  */
 public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
-
-    //
-    // TODO: A temporary variable to switch between the poll-based and
-    // notification mechanism for the Flow Manager.
-    //
-    private final static boolean enableNotifications = true;
-    
-    // flag to use FlowPusher instead of FlowSwitchOperation/MessageDamper
-    private final static boolean enableFlowPusher = false;
-
     protected GraphDBOperation dbHandlerApi;
     protected GraphDBOperation dbHandlerInner;
 
     protected volatile IFloodlightProviderService floodlightProvider;
-    protected volatile ITopologyNetService topologyNetService;
     protected volatile IDatagridService datagridService;
     protected IRestApiService restApi;
     protected FloodlightModuleContext context;
     protected FlowEventHandler flowEventHandler;
 
     protected IFlowPusherService pusher;
+    protected IForwardingService forwardingService;
     
-    protected OFMessageDamper messageDamper;
-    
-    //
-    // TODO: Values copied from elsewhere (class LearningSwitch).
-    // The local copy should go away!
-    //
-    protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
-    protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250;	// ms
-
     // Flow Entry ID generation state
     private static Random randomGenerator = new Random();
     private static int nextFlowEntryIdPrefix = 0;
     private static int nextFlowEntryIdSuffix = 0;
-    private static long nextFlowEntryId = 0;
 
     /** The logger. */
     private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
 
-    // The periodic task(s)
-    private ScheduledExecutorService mapReaderScheduler;
-    private ScheduledExecutorService shortestPathReconcileScheduler;
-
-    /**
-     * Periodic task for reading the Flow Entries and pushing changes
-     * into the switches.
-     */
-    final Runnable mapReader = new Runnable() {
-	    public void run() {
-		try {
-		    runImpl();
-		} catch (Exception e) {
-		    log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
-		    dbHandlerInner.rollback();
-		    return;
-		}
-	    }
-
-	    private void runImpl() {
-		long startTime = System.nanoTime();
-		int counterAllFlowEntries = 0;
-		int counterMyNotUpdatedFlowEntries = 0;
-
-		if (floodlightProvider == null) {
-		    log.debug("FloodlightProvider service not found!");
-		    return;
-		}
-		Map<Long, IOFSwitch> mySwitches =
-		    floodlightProvider.getSwitches();
-		if (mySwitches.isEmpty()) {
-			log.trace("No switches controlled");
-			return;
-		}
-		LinkedList<IFlowEntry> addFlowEntries =
-		    new LinkedList<IFlowEntry>();
-		LinkedList<IFlowEntry> deleteFlowEntries =
-		    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.
-		//
-		Iterable<IFlowEntry> allFlowEntries =
-		    dbHandlerInner.getAllSwitchNotUpdatedFlowEntries();
-		for (IFlowEntry flowEntryObj : allFlowEntries) {
-			log.debug("flowEntryobj : {}", flowEntryObj);
-			
-		    counterAllFlowEntries++;
-
-		    String dpidStr = flowEntryObj.getSwitchDpid();
-		    if (dpidStr == null)
-			continue;
-		    Dpid dpid = new Dpid(dpidStr);
-		    IOFSwitch mySwitch = mySwitches.get(dpid.value());
-		    if (mySwitch == null)
-			continue;	// Ignore the entry: not my switch
-
-		    IFlowPath flowObj =
-			dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
-		    if (flowObj == null)
-			continue;		// Should NOT happen
-		    if (flowObj.getFlowId() == null)
-			continue;		// Invalid entry
-
-		    //
-		    // NOTE: For now we process the DELETE before the ADD
-		    // to cover the more common scenario.
-		    // TODO: This is error prone and needs to be fixed!
-		    //
-		    String userState = flowEntryObj.getUserState();
-		    if (userState == null)
-			continue;
-		    if (userState.equals("FE_USER_DELETE")) {
-			// An entry that needs to be deleted.
-			deleteFlowEntries.add(flowEntryObj);
-			installFlowEntry(mySwitch, flowObj, flowEntryObj);
-		    } else {
-			addFlowEntries.add(flowEntryObj);
-		    }
-		    counterMyNotUpdatedFlowEntries++;
-		}
-		
-		log.debug("addFlowEntries : {}", addFlowEntries);
-
-		//
-		// Process the Flow Entries that need to be added
-		//
-		for (IFlowEntry flowEntryObj : addFlowEntries) {
-		    IFlowPath flowObj =
-			dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
-		    if (flowObj == null)
-			continue;		// Should NOT happen
-		    if (flowObj.getFlowId() == null)
-			continue;		// Invalid entry
-
-		    Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
-		    IOFSwitch mySwitch = mySwitches.get(dpid.value());
-		    if (mySwitch == null)
-			continue;		// Shouldn't happen
-		    installFlowEntry(mySwitch, flowObj, flowEntryObj);
-		}
-
-		//
-		// Delete all Flow Entries marked for deletion from the
-		// Network MAP.
-		//
-		// TODO: We should use the OpenFlow Barrier mechanism
-		// to check for errors, and delete the Flow Entries after the
-		// Barrier message is received.
-		//
-		while (! deleteFlowEntries.isEmpty()) {
-		    IFlowEntry flowEntryObj = deleteFlowEntries.poll();
-		    IFlowPath flowObj =
-			dbHandlerInner.getFlowPathByFlowEntry(flowEntryObj);
-		    if (flowObj == null) {
-			log.debug("Did not find FlowPath to be deleted");
-			continue;
-		    }
-		    flowObj.removeFlowEntry(flowEntryObj);
-		    dbHandlerInner.removeFlowEntry(flowEntryObj);
-		}
-
-		dbHandlerInner.commit();
-
-		long estimatedTime = System.nanoTime() - startTime;
-		double rate = 0.0;
-		if (estimatedTime > 0)
-		    rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
-		String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
-		    counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
-		    counterMyNotUpdatedFlowEntries + " in " +
-		    (double)estimatedTime / 1000000000 + " sec: " +
-		    rate + " paths/s";
-		log.debug(logMsg);
-	    }
-	};
-
-    /**
-     * Periodic task for reading the Flow Paths and recomputing the
-     * shortest paths.
-     */
-    final Runnable shortestPathReconcile = new Runnable() {
-	    public void run() {
-		try {
-		    runImpl();
-		} catch (Exception e) {
-		    log.debug("Exception processing All Flows from the Network MAP: ", e);
-		    dbHandlerInner.rollback();
-		    return;
-		}
-	    }
-
-	    private void runImpl() {
-		long startTime = System.nanoTime();
-		int counterAllFlowPaths = 0;
-		int counterMyFlowPaths = 0;
-
-		if (floodlightProvider == null) {
-		    log.debug("FloodlightProvider service not found!");
-		    return;
-		}
-		Map<Long, IOFSwitch> mySwitches =
-		    floodlightProvider.getSwitches();
-		if (mySwitches.isEmpty()) {
-			log.trace("No switches controlled");
-			return;
-		}
-		LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
-
-		//
-		// Fetch and recompute the Shortest Path for those
-		// Flow Paths this controller is responsible for.
-		//
-		Topology topology = topologyNetService.newDatabaseTopology();
-		Iterable<IFlowPath> allFlowPaths = dbHandlerInner.getAllFlowPaths();
-		for (IFlowPath flowPathObj : allFlowPaths) {
-		    counterAllFlowPaths++;
-		    if (flowPathObj == null)
-			continue;
-
-		    String srcDpidStr = flowPathObj.getSrcSwitch();
-		    if (srcDpidStr == null)
-			continue;
-		    Dpid srcDpid = new Dpid(srcDpidStr);
-		    //
-		    // Use the source DPID as a heuristic to decide
-		    // which controller is responsible for maintaining the
-		    // shortest path.
-		    // NOTE: This heuristic is error-prone: if the switch
-		    // goes away and no controller is responsible for that
-		    // switch, then the original Flow Path is not cleaned-up
-		    //
-		    IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
-		    if (mySwitch == null)
-			continue;	// Ignore: not my responsibility
-
-		    // Test whether we need to maintain this flow
-		    String flowPathTypeStr = flowPathObj.getFlowPathType();
-		    if (flowPathTypeStr == null)
-			continue;	// Could be invalid entry?
-		    if (! flowPathTypeStr.equals("FP_TYPE_SHORTEST_PATH"))
-			continue;	// No need to maintain this flow
-
-		    //
-		    // Test whether we need to complete the Flow cleanup,
-		    // if the Flow has been deleted by the user.
-		    //
-		    String flowPathUserStateStr = flowPathObj.getFlowPathUserState();
-		    if ((flowPathUserStateStr != null)
-			&& flowPathUserStateStr.equals("FP_USER_DELETE")) {
-			Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
-			final boolean empty = !flowEntries.iterator().hasNext();
-			if (empty)
-			    deleteFlows.add(flowPathObj);
-		    }
-
-		    // Fetch the fields needed to recompute the shortest path
-		    String dataPathSummaryStr = flowPathObj.getDataPathSummary();
-		    Short srcPortShort = flowPathObj.getSrcPort();
-		    String dstDpidStr = flowPathObj.getDstSwitch();
-		    Short dstPortShort = flowPathObj.getDstPort();
-		    Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
-		    if ((dataPathSummaryStr == null) ||
-			(srcPortShort == null) ||
-			(dstDpidStr == null) ||
-			(dstPortShort == null) ||
-			(flowPathFlagsLong == null)) {
-			continue;
-		    }
-
-		    Port srcPort = new Port(srcPortShort);
-		    Dpid dstDpid = new Dpid(dstDpidStr);
-		    Port dstPort = new Port(dstPortShort);
-		    SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
-		    SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
-		    FlowPathType flowPathType = FlowPathType.valueOf(flowPathTypeStr);
-		    FlowPathUserState flowPathUserState = FlowPathUserState.valueOf(flowPathUserStateStr);
-		    FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
-
-		    counterMyFlowPaths++;
-
-		    //
-		    // 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
-		    // getDatabaseShortestPath(), we need to refactor that code
-		    // to avoid closing the transaction.
-		    //
-		    DataPath dataPath =
-			topologyNetService.getTopologyShortestPath(
-				topology,
-				srcSwitchPort,
-				dstSwitchPort);
-		    if (dataPath == null) {
-			// We need the DataPath to compare the paths
-			dataPath = new DataPath();
-			dataPath.setSrcPort(srcSwitchPort);
-			dataPath.setDstPort(dstSwitchPort);
-		    }
-		    dataPath.applyFlowPathFlags(flowPathFlags);
-
-		    String newDataPathSummaryStr = dataPath.dataPathSummary();
-		    if (dataPathSummaryStr.equals(newDataPathSummaryStr))
-			continue;	// Nothing changed
-
-		    reconcileFlow(flowPathObj, dataPath);
-		}
-
-		//
-		// Delete all leftover Flows marked for deletion from the
-		// Network MAP.
-		//
-		while (! deleteFlows.isEmpty()) {
-		    IFlowPath flowPathObj = deleteFlows.poll();
-		    dbHandlerInner.removeFlowPath(flowPathObj);
-		}
-
-		topologyNetService.dropTopology(topology);
-
-		dbHandlerInner.commit();
-
-		long estimatedTime = System.nanoTime() - startTime;
-		double rate = 0.0;
-		if (estimatedTime > 0)
-		    rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
-		String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
-		    counterAllFlowPaths + " MyFlowPaths: " +
-		    counterMyFlowPaths + " in " +
-		    (double)estimatedTime / 1000000000 + " sec: " +
-		    rate + " paths/s";
-		log.debug(logMsg);
-	    }
-	};
-
+    // The queue to write Flow Entries to the database
+    private BlockingQueue<FlowPath> flowPathsToDatabaseQueue =
+	new LinkedBlockingQueue<FlowPath>();
+    FlowDatabaseWriter flowDatabaseWriter;
 
     /**
      * Initialize the Flow Manager.
@@ -449,6 +131,8 @@
 	l.add(INetworkGraphService.class);
 	l.add(IDatagridService.class);
 	l.add(IRestApiService.class);
+	l.add(IFlowPusherService.class);
+	l.add(IForwardingService.class);
         return l;
     }
 
@@ -462,22 +146,12 @@
 	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);
-
-	if (enableFlowPusher) {
-		pusher = context.getServiceImpl(IFlowPusherService.class);
-	} else {
-		messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
-	    EnumSet.of(OFType.FLOW_MOD),
-	    OFMESSAGE_DAMPER_TIMEOUT);
-	}
+	pusher = context.getServiceImpl(IFlowPusherService.class);
+	forwardingService = context.getServiceImpl(IForwardingService.class);
 
 	this.init("");
-
-	mapReaderScheduler = Executors.newScheduledThreadPool(1);
-	shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
     }
 
     /**
@@ -515,33 +189,40 @@
 
 	// Initialize the Flow Entry ID generator
 	nextFlowEntryIdPrefix = randomGenerator.nextInt();
-	
+
 	//
-	// Create the Flow Event Handler thread and register it with the
-	// Datagrid Service
+	// The thread to write to the database
+	//
+	flowDatabaseWriter = new FlowDatabaseWriter(this,
+						flowPathsToDatabaseQueue);
+	flowDatabaseWriter.start();
+
+	//
+	// The Flow Event Handler thread:
+	//  - create
+	//  - register with the Datagrid Service
+	//  - startup
 	//
 	flowEventHandler = new FlowEventHandler(this, datagridService);
 	datagridService.registerFlowEventHandlerService(flowEventHandler);
-
-	// Schedule the threads and periodic tasks
 	flowEventHandler.start();
-	if (! enableNotifications) {
-	    mapReaderScheduler.scheduleAtFixedRate(
-			mapReader, 3, 3, TimeUnit.SECONDS);
-	    shortestPathReconcileScheduler.scheduleAtFixedRate(
-			shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
-	}
     }
 
     /**
      * Add a flow.
      *
      * @param flowPath the Flow Path to install.
-     * @param flowId the return-by-reference Flow ID as assigned internally.
-     * @return true on success, otherwise false.
+     * @return the Flow ID on success, otherwise null.
      */
     @Override
-    public boolean addFlow(FlowPath flowPath, FlowId flowId) {
+    public FlowId addFlow(FlowPath flowPath) {
+
+	// Allocate the Flow ID if necessary
+	if (! flowPath.isValidFlowId()) {
+	    long id = getNextFlowEntryId();
+	    flowPath.setFlowId(new FlowId(id));
+	}
+
 	//
 	// NOTE: We need to explicitly initialize some of the state,
 	// in case the application didn't do it.
@@ -555,35 +236,11 @@
 		flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
 	}
 
-	if (FlowDatabaseOperation.addFlow(this, dbHandlerApi, flowPath, flowId)) {
+	if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath)) {
 	    datagridService.notificationSendFlowAdded(flowPath);
-	    return true;
+	    return flowPath.flowId();
 	}
-	return false;
-    }
-
-    /**
-     * Add a flow entry to the Network MAP.
-     *
-     * @param flowObj the corresponding Flow Path object for the Flow Entry.
-     * @param flowEntry the Flow Entry to install.
-     * @return the added Flow Entry object on success, otherwise null.
-     */
-    private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
-	return FlowDatabaseOperation.addFlowEntry(this, dbHandlerInner,
-						  flowObj, flowEntry);
-    }
-
-    /**
-     * Delete a flow entry from the Network MAP.
-     *
-     * @param flowObj the corresponding Flow Path object for the Flow Entry.
-     * @param flowEntry the Flow Entry to delete.
-     * @return true on success, otherwise false.
-     */
-    private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
-	return FlowDatabaseOperation.deleteFlowEntry(dbHandlerInner,
-						     flowObj, flowEntry);
+	return null;
     }
 
     /**
@@ -593,19 +250,11 @@
      */
     @Override
     public boolean deleteAllFlows() {
-	//
-	// TODO: In the notification-based implementation,
-	// deleteFlow() is implemented by using clearFlow()
-	//
-	return clearAllFlows();
-
-	/*
 	if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
 	    datagridService.notificationSendAllFlowsRemoved();
 	    return true;
 	}
 	return false;
-	*/
     }
 
     /**
@@ -616,47 +265,11 @@
      */
     @Override
     public boolean deleteFlow(FlowId flowId) {
-	//
-	// TODO: In the notification-based implementation,
-	// deleteFlow() is implemented by using clearFlow()
-	//
-	return clearFlow(flowId);
-	/*
 	if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
 	    datagridService.notificationSendFlowRemoved(flowId);
 	    return true;
 	}
 	return false;
-	*/
-    }
-
-    /**
-     * Clear the state for all previously added flows.
-     *
-     * @return true on success, otherwise false.
-     */
-    @Override
-    public boolean clearAllFlows() {
-	if (FlowDatabaseOperation.clearAllFlows(dbHandlerApi)) {
-	    datagridService.notificationSendAllFlowsRemoved();
-	    return true;
-	}
-	return false;
-    }
-
-    /**
-     * Clear the state for a previously added flow.
-     *
-     * @param flowId the Flow ID of the flow to clear.
-     * @return true on success, otherwise false.
-     */
-    @Override
-    public boolean clearFlow(FlowId flowId) {
-	if (FlowDatabaseOperation.clearFlow(dbHandlerApi, flowId)) {
-	    datagridService.notificationSendFlowRemoved(flowId);
-	    return true;
-	}
-	return false;
     }
 
     /**
@@ -681,33 +294,6 @@
     }
 
     /**
-     * Get all previously added flows by a specific installer for a given
-     * data path endpoints.
-     *
-     * @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.
-     */
-    @Override
-    public ArrayList<FlowPath> getAllFlows(CallerId installerId,
-					   DataPathEndpoints dataPathEndpoints) {
-	return FlowDatabaseOperation.getAllFlows(dbHandlerApi, installerId,
-						 dataPathEndpoints);
-    }
-
-    /**
-     * Get all installed flows by all installers for given data path endpoints.
-     *
-     * @param dataPathEndpoints the data path endpoints of the flows to get.
-     * @return the Flow Paths if found, otherwise null.
-     */
-    @Override
-    public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
-	return FlowDatabaseOperation.getAllFlows(dbHandlerApi,
-						 dataPathEndpoints);
-    }
-
-    /**
      * Get summary of all installed flows by all installers in a given range.
      *
      * @param flowId the Flow ID of the first flow in the flow range to get.
@@ -715,42 +301,30 @@
      * @return the Flow Paths if found, otherwise null.
      */
     @Override
-    public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
-						   int maxFlows) {
-	return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
-							maxFlows);
-    }
-    
-    /**
-     * Get all Flows information, without the associated Flow Entries.
-     *
-     * @return all Flows information, without the associated Flow Entries.
-     */
-    public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
-	return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandlerApi);
-    }
+    public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
+						  int maxFlows) {
+    	ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
+	SortedMap<Long, FlowPath> sortedFlowPaths =
+	    flowEventHandler.getAllFlowPathsCopy();
 
-    /**
-     * Add and maintain a shortest-path flow.
-     *
-     * NOTE: The Flow Path argument does NOT contain flow entries.
-     *
-     * @param flowPath the Flow Path with the endpoints and the match
-     * conditions to install.
-     * @return the added shortest-path flow on success, otherwise null.
-     */
-    @Override
-    public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
 	//
-	// Don't do the shortest path computation here.
-	// Instead, let the Flow reconciliation thread take care of it.
+	// Truncate each Flow Path and Flow Entry
 	//
+	for (FlowPath flowPath : sortedFlowPaths.values()) {
+	    //
+	    // TODO: Add only the Flow Paths that have been successfully
+	    // installed.
+	    //
+	    flowPath.setFlowEntryMatch(null);
+	    flowPath.setFlowEntryActions(null);
+	    for (FlowEntry flowEntry : flowPath.flowEntries()) {
+		flowEntry.setFlowEntryMatch(null);
+		flowEntry.setFlowEntryActions(null);
+	    }
+	    flowPaths.add(flowPath);
+	}
 
-	FlowId flowId = new FlowId();
-	if (! addFlow(flowPath, flowId))
-	    return null;
-
-	return (flowPath);
+	return flowPaths;
     }
 
     /**
@@ -772,139 +346,99 @@
     }
 
     /**
-     * Reconcile a flow.
+     * Inform the Flow Manager that a Flow Entry on switch expired.
      *
-     * @param flowObj the flow that needs to be reconciled.
-     * @param newDataPath the new data path to use.
-     * @return true on success, otherwise false.
+     * @param sw the switch the Flow Entry expired on.
+     * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
      */
-    private boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
-	String flowIdStr = flowObj.getFlowId();
+    public void flowEntryOnSwitchExpired(IOFSwitch sw,
+					 FlowEntryId flowEntryId) {
+	// Find the Flow Entry
+	FlowEntry flowEntry = datagridService.getFlowEntry(flowEntryId);
+	if (flowEntryId == null)
+	    return;		// Flow Entry not found
+
+	// Find the Flow Path
+	FlowPath flowPath = datagridService.getFlow(flowEntry.flowId());
+	if (flowPath == null)
+	    return;		// Flow Path not found
 
 	//
-	// Set the incoming port matching and the outgoing port output
-	// actions for each flow entry.
+	// Remove the Flow if the Flow Entry expired on the first switch
 	//
-	int idx = 0;
-	for (FlowEntry flowEntry : newDataPath.flowEntries()) {
-	    flowEntry.setFlowId(new FlowId(flowIdStr));
-
-	    // Mark the Flow Entry as not updated in the switch
-	    flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
-	    // Set the incoming port matching
-	    FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
-	    flowEntry.setFlowEntryMatch(flowEntryMatch);
-	    flowEntryMatch.enableInPort(flowEntry.inPort());
-
-	    //
-	    // Set the actions
-	    //
-	    FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
-	    //
-	    // If the first Flow Entry, copy the Flow Path actions to it
-	    //
-	    if (idx == 0) {
-		String actionsStr = flowObj.getActions();
-		if (actionsStr != null) {
-		    FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
-		    for (FlowEntryAction action : flowActions.actions())
-			flowEntryActions.addAction(action);
-		}
-	    }
-	    idx++;
-	    //
-	    // Add the outgoing port output action
-	    //
-	    FlowEntryAction flowEntryAction = new FlowEntryAction();
-	    flowEntryAction.setActionOutput(flowEntry.outPort());
-	    flowEntryActions.addAction(flowEntryAction);
-	}
-
-	//
-	// Remove the old Flow Entries, and add the new Flow Entries
-	//
-	Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
-	for (IFlowEntry flowEntryObj : flowEntries) {
-	    flowEntryObj.setUserState("FE_USER_DELETE");
-	    flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
-	}
-	for (FlowEntry flowEntry : newDataPath.flowEntries()) {
-	    addFlowEntry(flowObj, flowEntry);
-	}
-
-	//
-	// Set the Data Path Summary
-	//
-	String dataPathSummaryStr = newDataPath.dataPathSummary();
-	flowObj.setDataPathSummary(dataPathSummaryStr);
-
-	return true;
-    }
-
-    /**
-     * Reconcile all flows in a set.
-     *
-     * @param flowObjSet the set of flows that need to be reconciliated.
-     */
-    private void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
-	if (! flowObjSet.iterator().hasNext())
+	Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
+	if (srcDpid.value() != sw.getId())
 	    return;
-	// TODO: Not implemented/used yet.
+	deleteFlow(flowPath.flowId());
     }
 
     /**
-     * Install a Flow Entry on a switch.
+     * Inform the Flow Manager that a collection of Flow Entries have been
+     * pushed to a switch.
      *
-     * @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.
+     * @param entries the collection of <IOFSwitch, FlowEntry> pairs
+     * that have been pushed.
      */
-    private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
-				    IFlowEntry flowEntryObj) {
-    	if (enableFlowPusher) {
-        	return pusher.add(mySwitch, flowObj, flowEntryObj);
-    	} else {
-    		return FlowSwitchOperation.installFlowEntry(
-    			floodlightProvider.getOFMessageFactory(),
-    			messageDamper, mySwitch, flowObj, flowEntryObj);
-    	}
-    }
+    public void flowEntriesPushedToSwitch(
+		Collection<Pair<IOFSwitch, FlowEntry>> entries) {
 
-    /**
-     * Install a Flow Entry on a switch.
-     *
-     * @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.
-     */
-    private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
-				    FlowEntry flowEntry) {
-    	if (enableFlowPusher) {
-        	return pusher.add(mySwitch, flowPath, flowEntry);
-    	} else {
-    		return FlowSwitchOperation.installFlowEntry(
-    		floodlightProvider.getOFMessageFactory(),
-    		messageDamper, mySwitch, flowPath, flowEntry);
-    	}
-    }
-
-    /**
-     * Remove a Flow Entry from a switch.
-     *
-     * @param mySwitch the switch to remove the Flow Entry from.
-     * @param flowPath the flow path for the flow entry to remove.
-     * @param flowEntry the flow entry to remove.
-     * @return true on success, otherwise false.
-     */
-    private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
-				   FlowEntry flowEntry) {
 	//
-	// The installFlowEntry() method implements both installation
-	// and removal of flow entries.
+	// Process all entries
 	//
-	return (installFlowEntry(mySwitch, flowPath, flowEntry));
+	for (Pair<IOFSwitch, FlowEntry> entry : entries) {
+	    FlowEntry flowEntry = entry.second;
+
+	    //
+	    // Mark the Flow Entry that it has been pushed to the switch
+	    //
+	    flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
+
+	    //
+	    // Write the Flow Entry to the Datagrid
+	    //
+	    switch (flowEntry.flowEntryUserState()) {
+	    case FE_USER_ADD:
+		datagridService.notificationSendFlowEntryAdded(flowEntry);
+		break;
+	    case FE_USER_MODIFY:
+		datagridService.notificationSendFlowEntryUpdated(flowEntry);
+		break;
+	    case FE_USER_DELETE:
+		datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
+		break;
+	    case FE_USER_UNKNOWN:
+		assert(false);
+		break;
+	    }
+	}
+    }
+
+    /**
+     * Generate a notification that a collection of Flow Paths has been
+     * installed in the network.
+     *
+     * @param flowPaths the collection of installed Flow Paths.
+     */
+    void notificationFlowPathsInstalled(Collection<FlowPath> flowPaths) {
+	forwardingService.flowsInstalled(flowPaths);
+    }
+
+    /**
+     * Push modified Flow-related state as appropriate.
+     *
+     * @param modifiedFlowPaths the collection of modified Flow Paths.
+     * @param modifiedFlowEntries the collection of modified Flow Entries.
+     */
+    void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
+			       Collection<FlowEntry> modifiedFlowEntries) {
+	//
+	// Push the modified Flow state:
+	//  - Flow Entries to switches and the datagrid
+	//  - Flow Paths to the database
+	//
+	pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
+	pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
+	cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
     }
 
     /**
@@ -915,137 +449,168 @@
      *
      * @param modifiedFlowEntries the collection of modified Flow Entries.
      */
-    public void pushModifiedFlowEntriesToSwitches(
-			Collection<FlowPathEntryPair> modifiedFlowEntries) {
-	// TODO: For now, the pushing of Flow Entries is disabled
-	if (! enableNotifications)
-	    return;
-
+    private void pushModifiedFlowEntriesToSwitches(
+			Collection<FlowEntry> modifiedFlowEntries) {
 	if (modifiedFlowEntries.isEmpty())
 	    return;
 
+	List<Pair<IOFSwitch, FlowEntry>> entries =
+	    new LinkedList<Pair<IOFSwitch, FlowEntry>>();
+
 	Map<Long, IOFSwitch> mySwitches = getMySwitches();
 
-	for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
-	    FlowPath flowPath = flowPair.flowPath;
-	    FlowEntry flowEntry = flowPair.flowEntry;
-
+	//
+	// Create a collection of my Flow Entries to push
+	//
+	for (FlowEntry flowEntry : modifiedFlowEntries) {
 	    IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
 	    if (mySwitch == null)
 		continue;
 
-	    log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
-
 	    //
-	    // Install the Flow Entry into the switch
+	    // Assign Flow Entry IDs if missing.
 	    //
-	    if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
-		String logMsg = "Cannot install Flow Entry " +
-		    flowEntry.flowEntryId() +
-		    " from Flow Path " + flowPath.flowId() +
-		    " on switch " + flowEntry.dpid();
-		log.error(logMsg);
-		continue;
+	    // NOTE: This is an additional safeguard, in case the
+	    // mySwitches set has changed (after the Flow Entry IDs
+	    // assignments by the caller).
+	    //
+	    if (! flowEntry.isValidFlowEntryId()) {
+		long id = getNextFlowEntryId();
+		flowEntry.setFlowEntryId(new FlowEntryId(id));
 	    }
 
-	    //
-	    // NOTE: Here we assume that the switch has been
-	    // successfully updated.
-	    //
-	    flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
+	    log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
+	    entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
 	}
+
+	pusher.pushFlowEntries(entries);
     }
 
     /**
-     * Push modified Flow Entries to the datagrid.
+     * Cleanup deleted Flow Entries from the datagrid.
+     *
+     * NOTE: We cleanup only the Flow Entries that are not for our switches.
+     * This is needed to handle the case a switch going down:
+     * It has no Master controller instance, hence no controller instance
+     * will cleanup its flow entries.
+     * This is sub-optimal: we need to elect a controller instance to handle
+     * the cleanup of such orphaned flow entries.
      *
      * @param modifiedFlowEntries the collection of modified Flow Entries.
      */
-    public void pushModifiedFlowEntriesToDatagrid(
-			Collection<FlowPathEntryPair> modifiedFlowEntries) {
-	// TODO: For now, the pushing of Flow Entries is disabled
-	if (! enableNotifications)
-	    return;
-
+    private void cleanupDeletedFlowEntriesFromDatagrid(
+			Collection<FlowEntry> modifiedFlowEntries) {
 	if (modifiedFlowEntries.isEmpty())
 	    return;
 
 	Map<Long, IOFSwitch> mySwitches = getMySwitches();
 
-	for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
-	    FlowEntry flowEntry = flowPair.flowEntry;
-
-	    IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
-
+	for (FlowEntry flowEntry : modifiedFlowEntries) {
 	    //
-	    // TODO: For now Flow Entries are removed by all instances,
-	    // even if this Flow Entry is not for our switches.
+	    // Process only Flow Entries that should be deleted and have
+	    // a valid Flow Entry ID.
 	    //
-	    // This is needed to handle the case a switch going down:
-	    // it has no Master controller instance, hence no
-	    // controller instance will cleanup its flow entries.
-	    // This is sub-optimal: we need to elect a controller
-	    // instance to handle the cleanup of such orphaned flow
-	    // entries.
-	    //
-	    if (mySwitch == null) {
-		if (flowEntry.flowEntryUserState() !=
-		    FlowEntryUserState.FE_USER_DELETE) {
-		    continue;
-		}
-		if (! flowEntry.isValidFlowEntryId())
-		    continue;
+	    if (! flowEntry.isValidFlowEntryId())
+		continue;
+	    if (flowEntry.flowEntryUserState() !=
+		FlowEntryUserState.FE_USER_DELETE) {
+		continue;
 	    }
 
-	    log.debug("Pushing Flow Entry To Datagrid: {}", flowEntry.toString());
+	    //
+	    // NOTE: The deletion of Flow Entries for my switches is handled
+	    // elsewhere.
+	    //
+	    IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
+	    if (mySwitch != null)
+		continue;
+
+	    log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry.toString());
+
 	    //
 	    // Write the Flow Entry to the Datagrid
 	    //
-	    switch (flowEntry.flowEntryUserState()) {
-	    case FE_USER_ADD:
-		if (mySwitch == null)
-		    break;	// Install only flow entries for my switches
-		datagridService.notificationSendFlowEntryAdded(flowEntry);
-		break;
-	    case FE_USER_MODIFY:
-		if (mySwitch == null)
-		    break;	// Install only flow entries for my switches
-		datagridService.notificationSendFlowEntryUpdated(flowEntry);
-		break;
-	    case FE_USER_DELETE:
-		datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
-		break;
+	    datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
+	}
+    }
+
+    /**
+     * Class to implement writing to the database in a separate thread.
+     */
+    class FlowDatabaseWriter extends Thread {
+	private FlowManager flowManager;
+	private BlockingQueue<FlowPath> blockingQueue;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param flowManager the Flow Manager to use.
+	 * @param blockingQueue the blocking queue to use.
+	 */
+	FlowDatabaseWriter(FlowManager flowManager,
+			   BlockingQueue<FlowPath> blockingQueue) {
+	    this.flowManager = flowManager;
+	    this.blockingQueue = blockingQueue;
+	}
+
+	/**
+	 * Run the thread.
+	 */
+	@Override
+	public void run() {
+	    //
+	    // The main loop
+	    //
+	    Collection<FlowPath> collection = new LinkedList<FlowPath>();
+	    try {
+		while (true) {
+		    FlowPath flowPath = blockingQueue.take();
+		    collection.add(flowPath);
+		    blockingQueue.drainTo(collection);
+		    flowManager.writeModifiedFlowPathsToDatabase(collection);
+		    collection.clear();
+		}
+	    } catch (Exception exception) {
+		log.debug("Exception writing to the Database: ", exception);
 	    }
 	}
     }
 
     /**
-     * Push Flow Entries to the Network MAP.
+     * Push Flow Paths to the Network MAP.
      *
-     * NOTE: The Flow Entries are pushed only on the instance responsible
-     * for the first switch. This is to avoid database errors when multiple
-     * instances are writing Flow Entries for the same Flow Path.
+     * NOTE: The complete Flow Paths are pushed only on the instance
+     * responsible for the first switch. This is to avoid database errors
+     * when multiple instances are writing Flow Entries for the same Flow Path.
      *
-     * @param modifiedFlowEntries the collection of Flow Entries to push.
+     * @param modifiedFlowPaths the collection of Flow Paths to push.
      */
-    public void pushModifiedFlowEntriesToDatabase(
-		Collection<FlowPathEntryPair> modifiedFlowEntries) {
-	// TODO: For now, the pushing of Flow Entries is disabled
-	if (! enableNotifications)
-	    return;
+    private void pushModifiedFlowPathsToDatabase(
+		Collection<FlowPath> modifiedFlowPaths) {
+	//
+	// We only add the Flow Paths to the Database Queue.
+	// The FlowDatabaseWriter thread is responsible for the actual writing.
+	//
+	flowPathsToDatabaseQueue.addAll(modifiedFlowPaths);
+    }
 
-	if (modifiedFlowEntries.isEmpty())
+    /**
+     * Write Flow Paths to the Network MAP.
+     *
+     * NOTE: The complete Flow Paths are pushed only on the instance
+     * responsible for the first switch. This is to avoid database errors
+     * when multiple instances are writing Flow Entries for the same Flow Path.
+     *
+     * @param modifiedFlowPaths the collection of Flow Paths to write.
+     */
+    private void writeModifiedFlowPathsToDatabase(
+		Collection<FlowPath> modifiedFlowPaths) {
+	if (modifiedFlowPaths.isEmpty())
 	    return;
 
 	Map<Long, IOFSwitch> mySwitches = getMySwitches();
 
-	for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
-	    FlowPath flowPath = flowPair.flowPath;
-	    FlowEntry flowEntry = flowPair.flowEntry;
-
-	    if (! flowEntry.isValidFlowEntryId())
-		continue;
-
+	for (FlowPath flowPath : modifiedFlowPaths) {
 	    //
 	    // Push the changes only on the instance responsible for the
 	    // first switch.
@@ -1055,69 +620,57 @@
 	    if (mySrcSwitch == null)
 		continue;
 
-	    log.debug("Pushing Flow Entry To Database: {}", flowEntry.toString());
 	    //
-	    // Write the Flow Entry to the Network Map
+	    // Delete the Flow Path from the Network Map
 	    //
-	    // NOTE: We try a number of times, in case somehow some other
-	    // instances are writing at the same time.
-	    // Apparently, if other instances are writing at the same time
-	    // this will trigger an error.
-	    //
-	    for (int i = 0; i < 6; i++) {
+	    if (flowPath.flowPathUserState() ==
+		FlowPathUserState.FP_USER_DELETE) {
+		log.debug("Deleting Flow Path From Database: {}",
+			  flowPath.toString());
+
 		try {
-		    //
-		    // Find the Flow Path in the Network MAP.
-		    //
-		    // NOTE: The Flow Path might not be found if the Flow was
-		    // just removed by some other controller instance.
-		    //
-		    IFlowPath flowObj =
-			dbHandlerInner.searchFlowPath(flowEntry.flowId());
-		    if (flowObj == null) {
-			String logMsg = "Cannot find Network MAP entry for Flow Path " + flowEntry.flowId();
-			log.error(logMsg);
-			break;
+		    if (! FlowDatabaseOperation.deleteFlow(
+					dbHandlerInner,
+					flowPath.flowId())) {
+			log.error("Cannot delete Flow Path {} from Network Map",
+				  flowPath.flowId());
 		    }
-
-		    // Write the Flow Entry
-		    switch (flowEntry.flowEntryUserState()) {
-		    case FE_USER_ADD:
-			// FALLTHROUGH
-		    case FE_USER_MODIFY:
-			if (addFlowEntry(flowObj, flowEntry) == null) {
-			    String logMsg = "Cannot write to Network MAP Flow Entry " +
-				flowEntry.flowEntryId() +
-				" from Flow Path " + flowEntry.flowId() +
-				" on switch " + flowEntry.dpid();
-			    log.error(logMsg);
-			}
-			break;
-		    case FE_USER_DELETE:
-			if (deleteFlowEntry(flowObj, flowEntry) == false) {
-			    String logMsg = "Cannot remove from Network MAP Flow Entry " +
-				flowEntry.flowEntryId() +
-				" from Flow Path " + flowEntry.flowId() +
-				" on switch " + flowEntry.dpid();
-			    log.error(logMsg);
-			}
-			break;
-		    }
-
-		    // Commit to the database
-		    dbHandlerInner.commit();
-		    break;	// Success
-
 		} catch (Exception e) {
-		    log.debug("Exception writing Flow Entry to Network MAP: ", e);
-		    dbHandlerInner.rollback();
-		    // Wait a bit (random value [1ms, 20ms] and try again
-		    int delay = 1 + randomGenerator.nextInt() % 20;
-		    try {
-			Thread.sleep(delay);
-		    } catch (Exception e0) {
-		    }
+		    log.error("Exception deleting Flow Path from Network MAP: {}", e);
 		}
+		continue;
+	    }
+
+	    //
+	    // Test whether all Flow Entries are valid
+	    //
+	    boolean allValid = true;
+	    for (FlowEntry flowEntry : flowPath.flowEntries()) {
+		if (flowEntry.flowEntryUserState() ==
+		    FlowEntryUserState.FE_USER_DELETE) {
+		    continue;
+		}
+		if (! flowEntry.isValidFlowEntryId()) {
+		    allValid = false;
+		    break;
+		}
+	    }
+	    if (! allValid)
+		continue;
+
+	    log.debug("Pushing Flow Path To Database: {}", flowPath.toString());
+
+	    //
+	    // Write the Flow Path to the Network Map
+	    //
+	    try {
+		if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
+		    String logMsg = "Cannot write to Network Map Flow Path " +
+			flowPath.flowId();
+		    log.error(logMsg);
+		}
+	    } catch (Exception e) {
+		log.error("Exception writing Flow Path to Network MAP: ", e);
 	    }
 	}
     }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowSwitchOperation.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowSwitchOperation.java
deleted file mode 100644
index 8bed120..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowSwitchOperation.java
+++ /dev/null
@@ -1,689 +0,0 @@
-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 final 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
-
-    // TODO add Pusher instance member
-    // 
-    
-    /**
-     * Install a Flow Entry on a switch.
-     *
-     * @param messageFactory the OpenFlow message factory to use.
-     * @param 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);
-	else
-	    flowEntryActions = new 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
-	//
-	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
-	//
-	log.debug("MEASUREMENT: Installing flow entry " +
-		  flowEntry.flowEntryUserState() +
-		  " into switch DPID: " +
-		  mySwitch.getStringId() +
-		  " flowEntryId: " + flowEntry.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.
-	    //
-	    // 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 f39acb5..549a0fc 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
@@ -1,14 +1,16 @@
 package net.onrc.onos.ofcontroller.flowmanager;
 
 import java.util.ArrayList;
+import java.util.Collection;
 
+import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.module.IFloodlightService;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
 import net.onrc.onos.ofcontroller.topology.Topology;
-import net.onrc.onos.ofcontroller.util.CallerId;
-import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
+import net.onrc.onos.ofcontroller.util.FlowEntry;
+import net.onrc.onos.ofcontroller.util.FlowEntryId;
 import net.onrc.onos.ofcontroller.util.FlowId;
 import net.onrc.onos.ofcontroller.util.FlowPath;
+import net.onrc.onos.ofcontroller.util.Pair;
 
 /**
  * Interface for providing Flow Service to other modules.
@@ -17,14 +19,10 @@
     /**
      * 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.
-     * @return true on success, otherwise false.
+     * @return the Flow ID on success, otherwise null.
      */
-    boolean addFlow(FlowPath flowPath, FlowId flowId);
+    FlowId addFlow(FlowPath flowPath);
 
     /**
      * Delete all previously added flows.
@@ -42,21 +40,6 @@
     boolean deleteFlow(FlowId flowId);
 
     /**
-     * Clear the state for all previously added flows.
-     *
-     * @return true on success, otherwise false.
-     */
-    boolean clearAllFlows();
-
-    /**
-     * Clear the state for a previously added flow.
-     *
-     * @param flowId the Flow ID of the flow to clear.
-     * @return true on success, otherwise false.
-     */
-    boolean clearFlow(FlowId flowId);
-
-    /**
      * Get a previously added flow.
      *
      * @param flowId the Flow ID of the flow to get.
@@ -72,47 +55,13 @@
     ArrayList<FlowPath> getAllFlows();
 
     /**
-     * Get all previously added flows by a specific installer for a given
-     * data path endpoints.
-     *
-     * @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.
-     */
-    ArrayList<FlowPath> getAllFlows(CallerId installerId,
-				 DataPathEndpoints dataPathEndpoints);
-
-    /**
-     * Get all installed flows by all installers for given data path endpoints.
-     *
-     * @param dataPathEndpoints the data path endpoints of the flows to get.
-     * @return the Flow Paths if found, otherwise null.
-     */
-    ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints);
-
-    /**
      * Get summary of all installed flows by all installers.
      *
      * @param flowId starting flow Id of the range
      * @param maxFlows number of flows to return
      * @return the Flow Paths if found, otherwise null.
      */
-    ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows);
-    
-    /**
-     * Add and maintain a shortest-path flow.
-     *
-     * NOTE: The Flow Path argument does NOT contain all flow entries.
-     * Instead, it contains a single dummy flow entry that is used to
-     * store the matching condition(s).
-     * That entry is replaced by the appropriate entries from the
-     * internally performed shortest-path computation.
-     *
-     * @param flowPath the Flow Path with the endpoints and the match
-     * conditions to install.
-     * @return the added shortest-path flow on success, otherwise null.
-     */
-    FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath);
+    ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows);
 
     /**
      * Get the network topology.
@@ -120,7 +69,7 @@
      * @return the network topology.
      */
     Topology getTopology();
-    
+
     /**
      * Get a globally unique flow ID from the flow service.
      * NOTE: Not currently guaranteed to be globally unique.
@@ -128,4 +77,22 @@
      * @return unique flow ID
      */
     public long getNextFlowEntryId();
+
+    /**
+     * Inform the Flow Manager that a Flow Entry on switch expired.
+     *
+     * @param sw the switch the Flow Entry expired on.
+     * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
+     */
+    public void flowEntryOnSwitchExpired(IOFSwitch sw, FlowEntryId flowEntryId);
+
+    /**
+     * Inform the Flow Manager that a collection of Flow Entries have been
+     * pushed to a switch.
+     *
+     * @param entries the collection of <IOFSwitch, FlowEntry> pairs
+     * that have been pushed.
+     */
+    public void flowEntriesPushedToSwitch(
+			Collection<Pair<IOFSwitch, FlowEntry>> entries);
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddFlowResource.java
index 0926f91..9afaaec 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddFlowResource.java
@@ -64,9 +64,9 @@
 
 	// Process the request
 	if (flowPath != null) {
-	    if (flowService.addFlow(flowPath, result) != true) {
-		result = new FlowId();		// Error: Return empty Flow Id
-	    }
+	    FlowId addedFlowId = flowService.addFlow(flowPath);
+	    if (addedFlowId != null)
+		result = addedFlowId;
 	}
 
         return result;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java
index 7a4e88c..4d03623 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java
@@ -64,13 +64,9 @@
 
 	// Process the request
 	if (flowPath != null) {
-	    FlowPath addedFlowPath =
-		flowService.addAndMaintainShortestPathFlow(flowPath);
-	    if (addedFlowPath == null) {
-		result = new FlowId();		// Error: Return empty Flow Id
-	    } else {
-		result = addedFlowPath.flowId();
-	    }
+	    FlowId addedFlowId = flowService.addFlow(flowPath);
+	    if (addedFlowId != null)
+		result = addedFlowId;
 	}
 
         return result;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/ClearFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/ClearFlowResource.java
deleted file mode 100644
index b8942b9..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/ClearFlowResource.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package net.onrc.onos.ofcontroller.flowmanager.web;
-
-import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
-import net.onrc.onos.ofcontroller.util.FlowId;
-
-import org.restlet.resource.Get;
-import org.restlet.resource.ServerResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Flow Manager REST API implementation: Clear internal Flow state.
- *
- * The "{flow-id}" request attribute value can be either a specific Flow ID,
- * or the keyword "all" to clear all Flows:
- *
- *   GET /wm/flow/clear/{flow-id}/json
- */
-public class ClearFlowResource extends ServerResource {
-    protected final static Logger log = LoggerFactory.getLogger(ClearFlowResource.class);
-
-    /**
-     * Implement the API.
-     *
-     * @return true on success, otehrwise false.
-     */
-    @Get("json")
-    public Boolean retrieve() {
-	Boolean result = false;
-
-        IFlowService flowService =
-                (IFlowService)getContext().getAttributes().
-                get(IFlowService.class.getCanonicalName());
-
-        if (flowService == null) {
-	    log.debug("ONOS Flow Service not found");
-            return result;
-	}
-
-	// Extract the arguments
-	String flowIdStr = (String) getRequestAttributes().get("flow-id");
-
-	// Process the request
-	if (flowIdStr.equals("all")) {
-	    log.debug("Clear All Flows");
-	    result = flowService.clearAllFlows();
-	} else {
-	    FlowId flowId = new FlowId(flowIdStr);
-	    log.debug("Clear Flow Id: " + flowIdStr);
-	    result = flowService.clearFlow(flowId);
-	}
-	return result;
-    }
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java
index e027270..c358263 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java
@@ -18,11 +18,8 @@
         Router router = new Router(context);
         router.attach("/add/json", AddFlowResource.class);
         router.attach("/add-shortest-path/json", AddShortestPathFlowResource.class);
-        router.attach("/clear/{flow-id}/json", ClearFlowResource.class);
         router.attach("/delete/{flow-id}/json", DeleteFlowResource.class);
         router.attach("/get/{flow-id}/json", GetFlowByIdResource.class);
-        router.attach("/getall-by-installer-id/{installer-id}/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json", GetAllFlowsByInstallerIdResource.class);
-        router.attach("/getall-by-endpoints/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json", GetAllFlowsByEndpointsResource.class);
         router.attach("/getall/json", GetAllFlowsResource.class);
         router.attach("/getsummary/{flow-id}/{max-flows}/json", GetSummaryFlowsResource.class);
         return router;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByEndpointsResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByEndpointsResource.java
deleted file mode 100644
index 1ac98c0..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByEndpointsResource.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package net.onrc.onos.ofcontroller.flowmanager.web;
-
-import java.util.ArrayList;
-
-import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
-import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
-import net.onrc.onos.ofcontroller.util.Dpid;
-import net.onrc.onos.ofcontroller.util.FlowPath;
-import net.onrc.onos.ofcontroller.util.Port;
-import net.onrc.onos.ofcontroller.util.SwitchPort;
-
-import org.restlet.resource.Get;
-import org.restlet.resource.ServerResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Flow Manager REST API implementation: Get all Flow state for given
- * source and destination switches and ports.
- *
- * The "{src-dpid}" request attribute value is the source DPID of the flows to
- * get.
- * The "{src-port}" request attribute value is the source port of the flows to
- * get.
- * The "{dst-dpid}" request attribute value is the destination DPID of the
- * flows to get.
- * The "{dst-port}" request attribute value is the destination port of the
- * flows to get.
- *
- *   GET /wm/flow/getall-by-endpoints/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json"
- */
-public class GetAllFlowsByEndpointsResource extends ServerResource {
-    protected final static Logger log = LoggerFactory.getLogger(GetAllFlowsByEndpointsResource.class);
-
-    /**
-     * Implement the API.
-     *
-     * @return the collection of Flow states if any found, otherwise null.
-     */
-    @Get("json")
-    public ArrayList<FlowPath> retrieve() {
-	ArrayList<FlowPath> result = null;
-
-        IFlowService flowService =
-                (IFlowService)getContext().getAttributes().
-                get(IFlowService.class.getCanonicalName());
-
-        if (flowService == null) {
-	    log.debug("ONOS Flow Service not found");
-            return result;
-	}
-
-	// Extract the arguments
-        String srcDpidStr = (String) getRequestAttributes().get("src-dpid");
-        String srcPortStr = (String) getRequestAttributes().get("src-port");
-        String dstDpidStr = (String) getRequestAttributes().get("dst-dpid");
-        String dstPortStr = (String) getRequestAttributes().get("dst-port");
-
-	log.debug("Get All Flows Endpoints: " + srcDpidStr + "--" +
-		  srcPortStr + "--" + dstDpidStr + "--" + dstPortStr);
-
-	Dpid srcDpid = new Dpid(srcDpidStr);
-	Port srcPort = new Port(Short.parseShort(srcPortStr));
-	Dpid dstDpid = new Dpid(dstDpidStr);
-	Port dstPort = new Port(Short.parseShort(dstPortStr));
-	SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
-	SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
-	DataPathEndpoints dataPathEndpoints =
-	    new DataPathEndpoints(srcSwitchPort, dstSwitchPort);
-
-	result = flowService.getAllFlows(dataPathEndpoints);
-
-        return result;
-    }
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByInstallerIdResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByInstallerIdResource.java
deleted file mode 100644
index 870548e..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetAllFlowsByInstallerIdResource.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package net.onrc.onos.ofcontroller.flowmanager.web;
-
-import java.util.ArrayList;
-
-import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
-import net.onrc.onos.ofcontroller.util.CallerId;
-import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
-import net.onrc.onos.ofcontroller.util.Dpid;
-import net.onrc.onos.ofcontroller.util.FlowPath;
-import net.onrc.onos.ofcontroller.util.Port;
-import net.onrc.onos.ofcontroller.util.SwitchPort;
-
-import org.restlet.resource.Get;
-import org.restlet.resource.ServerResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Flow Manager REST API implementation: Get all Flow state for a given
- * Installer ID and given source and destination switches and ports.
- *
- * The "{installer-id}" request attribute value is the Installer ID of the
- * flows to get.
- * The "{src-dpid}" request attribute value is the source DPID of the flows to
- * get.
- * The "{src-port}" request attribute value is the source port of the flows to
- * get.
- * The "{dst-dpid}" request attribute value is the destination DPID of the
- * flows to get.
- * The "{dst-port}" request attribute value is the destination port of the
- * flows to get.
- *
- *   GET /wm/flow/getall-by-installer-id/{installer-id}/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json"
- */
-public class GetAllFlowsByInstallerIdResource extends ServerResource {
-    protected final static Logger log = LoggerFactory.getLogger(GetAllFlowsByInstallerIdResource.class);
-
-    /**
-     * Implement the API.
-     *
-     * @return the collection of Flow states if any found, otherwise null.
-     */
-    @Get("json")
-    public ArrayList<FlowPath> retrieve() {
-	ArrayList<FlowPath> result = null;
-
-        IFlowService flowService =
-                (IFlowService)getContext().getAttributes().
-                get(IFlowService.class.getCanonicalName());
-
-        if (flowService == null) {
-	    log.debug("ONOS Flow Service not found");
-            return result;
-	}
-
-	// Extract the arguments
-        String installerIdStr = (String) getRequestAttributes().get("installer-id");
-        String srcDpidStr = (String) getRequestAttributes().get("src-dpid");
-        String srcPortStr = (String) getRequestAttributes().get("src-port");
-        String dstDpidStr = (String) getRequestAttributes().get("dst-dpid");
-        String dstPortStr = (String) getRequestAttributes().get("dst-port");
-
-	log.debug("Get All Flow By Installer: " + installerIdStr +
-		  " Endpoints: " +
-		  srcDpidStr + "--" + srcPortStr + "--" +
-		  dstDpidStr + "--" + dstPortStr);
-
-	CallerId installerId = new CallerId(installerIdStr);
-	Dpid srcDpid = new Dpid(srcDpidStr);
-	Port srcPort = new Port(Short.parseShort(srcPortStr));
-	Dpid dstDpid = new Dpid(dstDpidStr);
-	Port dstPort = new Port(Short.parseShort(dstPortStr));
-	SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
-	SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
-	DataPathEndpoints dataPathEndpoints =
-	    new DataPathEndpoints(srcSwitchPort, dstSwitchPort);
-
-	result = flowService.getAllFlows(installerId, dataPathEndpoints);
-
-        return result;
-    }
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetSummaryFlowsResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetSummaryFlowsResource.java
index 89e5b01..58f82a9 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetSummaryFlowsResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/GetSummaryFlowsResource.java
@@ -2,8 +2,8 @@
 
 import java.util.ArrayList;
 
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
 import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
+import net.onrc.onos.ofcontroller.util.FlowPath;
 import net.onrc.onos.ofcontroller.util.FlowId;
 
 import org.restlet.resource.Get;
@@ -31,8 +31,8 @@
      * @return the collection of Flow states if any found, otherwise null.
      */
     @Get("json")
-    public ArrayList<IFlowPath> retrieve() {
-    	ArrayList<IFlowPath> result = null;
+    public ArrayList<FlowPath> retrieve() {
+    	ArrayList<FlowPath> result = null;
     	
     	FlowId flowId;
     	int maxFlows = 0;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
index a59a9f9..a4f0a8c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
@@ -4,26 +4,61 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
+
+import org.openflow.protocol.OFFlowRemoved;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IOFMessageListener;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitchListener;
 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.floodlightcontroller.restserver.IRestApiService;
+import net.onrc.onos.ofcontroller.flowprogrammer.web.FlowProgrammerWebRoutable;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
+import net.onrc.onos.ofcontroller.util.FlowEntryId;
+import net.onrc.onos.registry.controller.IControllerRegistryService;
 
-public class FlowProgrammer implements IFloodlightModule {
-	private static final boolean enableFlowSync = false;
-	
+/**
+ * FlowProgrammer is a module responsible to maintain flows installed to switches.
+ * FlowProgrammer consists of FlowPusher and FlowSynchronizer.
+ * FlowPusher manages the rate of installation, and FlowSynchronizer synchronizes
+ * flows between GraphDB and switches.
+ * FlowProgrammer also watch the event of addition/deletion of switches to
+ * start/stop synchronization. When a switch is added to network, FlowProgrammer
+ * immediately kicks synchronization to keep switch's flow table latest state.
+ * Adversely, when a switch is removed from network, FlowProgrammer immediately
+ * stops synchronization.
+ * @author Brian
+ *
+ */
+public class FlowProgrammer implements IFloodlightModule, 
+				       IOFMessageListener,
+				       IOFSwitchListener {
+    // flag to enable FlowSynchronizer
+    private static final boolean enableFlowSync = true;
+    protected static Logger log = LoggerFactory.getLogger(FlowProgrammer.class);
     protected volatile IFloodlightProviderService floodlightProvider;
+    protected volatile IControllerRegistryService registryService;
+    protected volatile IRestApiService restApi;
+    protected volatile IFlowService flowManager;
 
     protected FlowPusher pusher;
     private static final int NUM_PUSHER_THREAD = 1;
 
     protected FlowSynchronizer synchronizer;
-        
+    
     public FlowProgrammer() {
 	pusher = new FlowPusher(NUM_PUSHER_THREAD);
 	if (enableFlowSync) {
-	synchronizer = new FlowSynchronizer();
+	    synchronizer = new FlowSynchronizer();
 	}
     }
     
@@ -31,18 +66,21 @@
     public void init(FloodlightModuleContext context)
 	    throws FloodlightModuleException {
 	floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
-	pusher.init(null, floodlightProvider.getOFMessageFactory(), null);
+	registryService = context.getServiceImpl(IControllerRegistryService.class);
+	restApi = context.getServiceImpl(IRestApiService.class);
+	flowManager = context.getServiceImpl(IFlowService.class);
+	pusher.init(null, context, floodlightProvider.getOFMessageFactory(), null);
 	if (enableFlowSync) {
-	synchronizer.init(context);
+	    synchronizer.init(pusher);
 	}
     }
 
     @Override
     public void startUp(FloodlightModuleContext context) {
+    restApi.addRestletRoutable(new FlowProgrammerWebRoutable());
 	pusher.start();
-	if (enableFlowSync) {
-	synchronizer.startUp(context);
-	}
+	floodlightProvider.addOFMessageListener(OFType.FLOW_REMOVED, this);
+	floodlightProvider.addOFSwitchListener(this);
     }
 
     @Override
@@ -51,7 +89,7 @@
 		new ArrayList<Class<? extends IFloodlightService>>();
 	l.add(IFlowPusherService.class);
 	if (enableFlowSync) {
-	l.add(IFlowSyncService.class);
+	    l.add(IFlowSyncService.class);
 	}
 	return l;
     }
@@ -64,7 +102,7 @@
 	    IFloodlightService>();
 	m.put(IFlowPusherService.class, pusher);
 	if (enableFlowSync) {
-	m.put(IFlowSyncService.class, synchronizer);
+	    m.put(IFlowSyncService.class, synchronizer);
 	}
 	return m;
     }
@@ -74,8 +112,67 @@
 	Collection<Class<? extends IFloodlightService>> l =
 		new ArrayList<Class<? extends IFloodlightService>>();
 	l.add(IFloodlightProviderService.class);
+	l.add(IRestApiService.class);
 	return l;
     }
-    
 
+    @Override
+    public String getName() {
+	// TODO Auto-generated method stub
+	return "FlowProgrammer";
+    }
+
+    @Override
+    public boolean isCallbackOrderingPrereq(OFType type, String name) {
+	// TODO Auto-generated method stub
+	return false;
+    }
+
+    @Override
+    public boolean isCallbackOrderingPostreq(OFType type, String name) {
+	// TODO Auto-generated method stub
+	return false;
+    }
+
+    @Override
+    public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+	switch (msg.getType()) {
+	case FLOW_REMOVED:
+	    OFFlowRemoved flowMsg = (OFFlowRemoved) msg;
+	    log.debug("Got flow removed from "+ sw.getId() +": "+ flowMsg.getCookie());
+	    FlowEntryId id = new FlowEntryId(flowMsg.getCookie());
+	    flowManager.flowEntryOnSwitchExpired(sw, id);
+	    break;
+	default:
+	    break;
+	}
+
+	return Command.CONTINUE;
+    }
+
+    @Override
+    public void addedSwitch(IOFSwitch sw) {
+	log.debug("Switch added: {}", sw.getId());
+
+	if (enableFlowSync) {
+		if (registryService.hasControl(sw.getId())) {
+		    synchronizer.synchronize(sw);
+		}
+	}
+    }
+
+    @Override
+    public void removedSwitch(IOFSwitch sw) {
+	log.debug("Switch removed: {}", sw.getId());
+	
+	if (enableFlowSync) {
+	    synchronizer.interrupt(sw);
+	}
+    }
+
+    @Override
+    public void switchPortChanged(Long switchId) {
+	// TODO Auto-generated method stub
+    }
+    
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
index 532477a..3f61248 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
@@ -3,11 +3,16 @@
 import java.io.IOException;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.EnumSet;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Semaphore;
 
 import org.openflow.protocol.*;
 import org.openflow.protocol.action.*;
@@ -16,30 +21,40 @@
 import org.slf4j.LoggerFactory;
 
 import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.internal.OFMessageFuture;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
 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.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.util.FlowEntryAction;
 import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
 import net.onrc.onos.ofcontroller.util.FlowEntry;
 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.FlowEntryUserState;
-import net.onrc.onos.ofcontroller.util.FlowPath;
 import net.onrc.onos.ofcontroller.util.IPv4Net;
+import net.onrc.onos.ofcontroller.util.Pair;
 import net.onrc.onos.ofcontroller.util.Port;
 
 /**
- * FlowPusher intermediates FlowManager/FlowSynchronizer and switches to push OpenFlow
- * messages to switches in proper rate.
+ * FlowPusher is a implementation of FlowPusherService.
+ * FlowPusher assigns one message queue instance for each one switch.
+ * Number of message processing threads is configurable by constructor, and
+ * one thread can handle multiple message queues. Each queue will be assigned to 
+ * a thread according to hash function defined by getHash().
+ * Each processing thread reads messages from queues and sends it to switches
+ * in round-robin. Processing thread also calculates rate of sending to suppress
+ * excessive message sending.
  * @author Naoki Shiota
  *
  */
-public class FlowPusher implements IFlowPusherService {
+public class FlowPusher implements IFlowPusherService, IOFMessageListener {
     private final static Logger log = LoggerFactory.getLogger(FlowPusher.class);
+    protected volatile IFlowService flowManager;
 
     // NOTE: Below are moved from FlowManager.
     // TODO: Values copied from elsewhere (class LearningSwitch).
@@ -48,31 +63,35 @@
     protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
     protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250;	// ms
     
-    // Interval of sleep when queue is empty
-    protected static final long SLEEP_MILLI_SEC = 10;
-    protected static final int SLEEP_NANO_SEC = 0;
-    
     // Number of messages sent to switch at once
     protected static final int MAX_MESSAGE_SEND = 100;
 
     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
 
 	public enum QueueState {
 		READY,
 		SUSPENDED,
 	}
 	
-	@SuppressWarnings("serial")
+	/**
+	 * SwitchQueue represents message queue attached to a switch.
+	 * This consists of queue itself and variables used for limiting sending rate.
+	 * @author Naoki Shiota
+	 *
+	 */
 	private class SwitchQueue extends ArrayDeque<OFMessage> {
+		private static final long serialVersionUID = 1L;
+
 		QueueState state;
 		
-		// Max rate of sending message (bytes/sec). 0 implies no limitation.
+		// Max rate of sending message (bytes/ms). 0 implies no limitation.
 		long max_rate = 0;	// 0 indicates no limitation
 		long last_sent_time = 0;
 		long last_sent_size = 0;
 		
+		// "To be deleted" flag
+		boolean toBeDeleted = false;
+		
 		/**
 		 * Check if sending rate is within the rate
 		 * @param current Current time
@@ -84,15 +103,20 @@
 				return true;
 			}
 			
-			long rate = last_sent_size / (current - last_sent_time);
-			
-			if (rate < max_rate) {
-				return true;
-			} else {
+			if (current == last_sent_time) {
 				return false;
 			}
+			
+			// Check if sufficient time (from aspect of rate) elapsed or not.
+			long rate = last_sent_size / (current - last_sent_time);
+			return (rate < max_rate);
 		}
 		
+		/**
+		 * Log time and size of last sent data.
+		 * @param current Time to be sent.
+		 * @param size Size of sent data (in bytes).
+		 */
 		void logSentData(long current, long size) {
 			last_sent_time = current;
 			last_sent_size = size;
@@ -100,11 +124,17 @@
 		
 	}
 	
-	private OFMessageDamper messageDamper;
+	private OFMessageDamper messageDamper = null;
+	private IThreadPoolService threadPool = null;
 
 	private FloodlightContext context = null;
 	private BasicFactory factory = null;
-	private Map<Long, FlowPusherProcess> threadMap = null;
+	
+	// Map of threads versus dpid
+	private Map<Long, FlowPusherThread> threadMap = null;
+	// Map of Future objects versus dpid and transaction ID.
+	private Map<Long, Map<Integer, OFBarrierReplyFuture>>
+		barrierFutures = new HashMap<Long, Map<Integer, OFBarrierReplyFuture>>();
 	
 	private int number_thread = 1;
 	
@@ -113,29 +143,35 @@
 	 * @author Naoki Shiota
 	 *
 	 */
-	private class FlowPusherProcess implements Runnable {
+	private class FlowPusherThread extends Thread {
 		private Map<IOFSwitch,SwitchQueue> queues
-		= new HashMap<IOFSwitch,SwitchQueue>();
+			= new HashMap<IOFSwitch,SwitchQueue>();
 		
-		private boolean isStopped = false;
-		private boolean isMsgAdded = false;
+		// reusable latch used for waiting for arrival of message
+		private Semaphore mutex = new Semaphore(0);
 		
 		@Override
 		public void run() {
-			log.debug("Begin Flow Pusher Process");
-			
 			while (true) {
-				Set< Map.Entry<IOFSwitch,SwitchQueue> > entries;
-				synchronized (queues) {
-					entries = queues.entrySet();
+				try {
+					// wait for message pushed to queue
+					mutex.acquire();
+				} catch (InterruptedException e) {
+					// not an error
+					log.debug("FlowPusherThread is interrupted");
+					return;
 				}
 				
-				// Set taint flag to false at this moment.
-				isMsgAdded = false;
+				// for safety of concurrent access, copy all key objects
+				Set<IOFSwitch> keys = new HashSet<IOFSwitch>(queues.size());
+				synchronized (queues) {
+					for (IOFSwitch sw : queues.keySet()) {
+						keys.add(sw);
+					}
+				}
 				
-				for (Map.Entry<IOFSwitch,SwitchQueue> entry : entries) {
-					IOFSwitch sw = entry.getKey();
-					SwitchQueue queue = entry.getValue();
+				for (IOFSwitch sw : keys) {
+					SwitchQueue queue = queues.get(sw);
 
 					// Skip if queue is suspended
 					if (sw == null || queue == null ||
@@ -143,76 +179,103 @@
 						continue;
 					}
 					
-					// check sending rate and determine it to be sent or not
-					long current_time = System.nanoTime();
-					long size = 0;
-					
 					synchronized (queue) {
-						if (queue.isSendable(current_time)) {
-							int i = 0;
-							while (! queue.isEmpty()) {
-								// Number of messages excess the limit
-								if (++i >= MAX_MESSAGE_SEND) {
-									// Messages remains in queue
-									isMsgAdded = true;
-									break;
-								}
-								
-								OFMessage msg = queue.poll();
-								
-								// if need to send, call IOFSwitch#write()
-								try {
-									messageDamper.write(sw, msg, context);
-									log.debug("Pusher sends message : {}", msg);
-									size += msg.getLength();
-								} catch (IOException e) {
-									e.printStackTrace();
-									log.error("Exception in sending message ({}) : {}", msg, e);
+						processQueue(sw, queue, MAX_MESSAGE_SEND);
+						if (queue.isEmpty()) {
+							// remove queue if flagged to be.
+							if (queue.toBeDeleted) {
+								synchronized (queues) {
+									queues.remove(sw);
 								}
 							}
-							sw.flush();
-							queue.logSentData(current_time, size);
+						} else {
+							// if some messages remains in queue, latch down
+							if (mutex.availablePermits() == 0) {
+								mutex.release();
+							}
 						}
 					}
 				}
-				
-				// sleep while all queues are empty
-				while (! (isMsgAdded || isStopped)) {
+			}
+		}
+		
+		/**
+		 * Read messages from queue and send them to the switch.
+		 * If number of messages excess the limit, stop sending messages.
+		 * @param sw Switch to which messages will be sent.
+		 * @param queue Queue of messages.
+		 * @param max_msg Limitation of number of messages to be sent. If set to 0,
+		 *                all messages in queue will be sent.
+		 */
+		private void processQueue(IOFSwitch sw, SwitchQueue queue, long max_msg) {
+			// check sending rate and determine it to be sent or not
+			long current_time = System.currentTimeMillis();
+			long size = 0;
+			
+			if (queue.isSendable(current_time)) {
+				int i = 0;
+				while (! queue.isEmpty()) {
+					// Number of messages excess the limit
+					if (0 < max_msg && max_msg <= i) {
+						break;
+					}
+					++i;
+					
+					OFMessage msg = queue.poll();
 					try {
-						Thread.sleep(SLEEP_MILLI_SEC, SLEEP_NANO_SEC);
-					} catch (InterruptedException e) {
+						messageDamper.write(sw, msg, context);
+//						log.debug("Pusher sends message : {}", msg);
+						size += msg.getLength();
+					} catch (IOException e) {
 						e.printStackTrace();
-						log.error("Thread.sleep failed");
+						log.error("Exception in sending message ({}) : {}", msg, e);
 					}
 				}
-				
-				log.debug("Exit sleep loop.");
-				
-				if (isStopped) {
-					log.debug("Pusher Process finished.");
-					return;
-				}
-
+				sw.flush();
+				queue.logSentData(current_time, size);
 			}
 		}
 	}
 	
+	/**
+	 * Initialize object with one thread.
+	 */
 	public FlowPusher() {
-		
 	}
 	
+	/**
+	 * Initialize object with threads of given number.
+	 * @param number_thread Number of threads to handle messages.
+	 */
 	public FlowPusher(int number_thread) {
 		this.number_thread = number_thread;
 	}
 	
-	public void init(FloodlightContext context, BasicFactory factory, OFMessageDamper damper) {
+	/**
+	 * Set parameters needed for sending messages.
+	 * @param context FloodlightContext used for sending messages.
+	 *        If null, FlowPusher uses default context.
+	 * @param modContext FloodlightModuleContext used for acquiring
+	 *        ThreadPoolService and registering MessageListener.
+	 * @param factory Factory object to create OFMessage objects.
+	 * @param damper Message damper used for sending messages.
+	 *        If null, FlowPusher creates its own damper object.
+	 */
+	public void init(FloodlightContext context,
+			FloodlightModuleContext modContext,
+			BasicFactory factory,
+			OFMessageDamper damper) {
 		this.context = context;
 		this.factory = factory;
+		this.threadPool = modContext.getServiceImpl(IThreadPoolService.class);
+		IFloodlightProviderService flservice = modContext.getServiceImpl(IFloodlightProviderService.class);
+		flservice.addOFMessageListener(OFType.BARRIER_REPLY, this);
+		flowManager = modContext.getServiceImpl(IFlowService.class);
 		
 		if (damper != null) {
 			messageDamper = damper;
 		} else {
-			// use default value
+			// use default values
 			messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
 				    EnumSet.of(OFType.FLOW_MOD),
 				    OFMESSAGE_DAMPER_TIMEOUT);
@@ -228,20 +291,15 @@
 			return;
 		}
 		
-		threadMap = new HashMap<Long,FlowPusherProcess>();
+		threadMap = new HashMap<Long,FlowPusherThread>();
 		for (long i = 0; i < number_thread; ++i) {
-			FlowPusherProcess runnable = new FlowPusherProcess();
-			threadMap.put(i, runnable);
+			FlowPusherThread thread = new FlowPusherThread();
 			
-			Thread thread = new Thread(runnable);
+			threadMap.put(i, thread);
 			thread.start();
 		}
 	}
 	
-	/**
-	 * Suspend sending messages to switch.
-	 * @param sw
-	 */
 	@Override
 	public boolean suspend(IOFSwitch sw) {
 		SwitchQueue queue = getQueue(sw);
@@ -259,9 +317,6 @@
 		}
 	}
 
-	/**
-	 * Resume sending messages to switch.
-	 */
 	@Override
 	public boolean resume(IOFSwitch sw) {
 		SwitchQueue queue = getQueue(sw);
@@ -273,15 +328,19 @@
 		synchronized (queue) {
 			if (queue.state == QueueState.SUSPENDED) {
 				queue.state = QueueState.READY;
+				
+				// Latch down if queue is not empty
+				FlowPusherThread thread = getProcess(sw);
+				if (! queue.isEmpty() &&
+						thread.mutex.availablePermits() == 0) {
+					thread.mutex.release();
+				}
 				return true;
 			}
 			return false;
 		}
 	}
 	
-	/**
-	 * Check if given switch is suspended.
-	 */
 	@Override
 	public boolean isSuspended(IOFSwitch sw) {
 		SwitchQueue queue = getQueue(sw);
@@ -302,18 +361,12 @@
 			return;
 		}
 		
-		for (FlowPusherProcess runnable : threadMap.values()) {
-			if (! runnable.isStopped) {
-				runnable.isStopped = true;
-			}
+		for (FlowPusherThread t : threadMap.values()) {
+			t.interrupt();
 		}
 	}
 	
-	/**
-	 * Set sending rate to a switch.
-	 * @param sw Switch.
-	 * @param rate Rate in bytes/sec.
-	 */
+	@Override
 	public void setRate(IOFSwitch sw, long rate) {
 		SwitchQueue queue = getQueue(sw);
 		if (queue == null) {
@@ -321,360 +374,119 @@
 		}
 		
 		if (rate > 0) {
+			log.debug("rate for {} is set to {}", sw.getId(), rate);
 			queue.max_rate = rate;
 		}
 	}
+
+	@Override
+	public boolean createQueue(IOFSwitch sw) {
+		SwitchQueue queue = getQueue(sw);
+		if (queue != null) {
+			return false;
+		}
+		
+		FlowPusherThread proc = getProcess(sw);
+		queue = new SwitchQueue();
+		queue.state = QueueState.READY;
+		synchronized (proc.queues) {
+			proc.queues.put(sw, queue);
+		}
+		
+		return true;
+	}
+
+	@Override
+	public boolean deleteQueue(IOFSwitch sw) {
+		return deleteQueue(sw, false);
+	}
 	
-	/**
-	 * Add OFMessage to the queue related to given switch.
-	 * @param sw Switch to which message is sent.
-	 * @param msg Message to be sent.
-	 * @return true if succeed.
-	 */
+	@Override
+	public boolean deleteQueue(IOFSwitch sw, boolean forceStop) {
+		FlowPusherThread proc = getProcess(sw);
+		
+		if (forceStop) {
+			synchronized (proc.queues) {
+				SwitchQueue queue = proc.queues.remove(sw);
+				if (queue == null) {
+					return false;
+				}
+			}
+			return true;
+		} else {
+			SwitchQueue queue = getQueue(sw);
+			if (queue == null) {
+				return false;
+			}
+			synchronized (queue) {
+				queue.toBeDeleted = true;
+			}
+			return true;
+		}
+	}
+	
 	@Override
 	public boolean add(IOFSwitch sw, OFMessage msg) {
-		FlowPusherProcess proc = getProcess(sw);
+		FlowPusherThread proc = getProcess(sw);
 		SwitchQueue queue = proc.queues.get(sw);
 
+		// create queue at first addition of message
 		if (queue == null) {
-			queue = new SwitchQueue();
-			queue.state = QueueState.READY;
-			synchronized (proc) {
-				proc.queues.put(sw, queue);
-			}
+			createQueue(sw);
+			queue = getQueue(sw);
 		}
 		
 		synchronized (queue) {
 			queue.add(msg);
-			log.debug("Message is pushed : {}", msg);
+//			log.debug("Message is pushed : {}", msg);
 		}
 		
-		proc.isMsgAdded = true;
-		
-		return true;
-	}
-	
-	/**
-	 * Create OFMessage from given flow information and add it to the queue.
-	 * @param sw Switch to which message is sent.
-	 * @param flowObj FlowPath.
-	 * @param flowEntryObj FlowEntry.
-	 * @return true if succeed.
-	 */
-	@Override
-	public boolean add(IOFSwitch sw, IFlowPath flowObj, IFlowEntry flowEntryObj) {
-		log.debug("sending : {}, {}", sw, flowObj);
-		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)factory.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;
+		if (proc.mutex.availablePermits() == 0) {
+			proc.mutex.release();
 		}
 
-		//
-		// 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);
-		}
-
-		// Match 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);
-		else
-		    flowEntryActions = new 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
-		//
-		log.debug("MEASUREMENT: Installing flow entry " + userState +
-			  " into switch DPID: " +
-			  sw.getStringId() +
-			  " flowEntryId: " + flowEntryId.toString() +
-			  " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
-			  " inPort: " + matchInPort + " outPort: " + actionOutputPort
-			  );
-		add(sw,fm);
-	    //
-	    // 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");
-
 		return true;
 	}
-	
-	/**
-	 * Create OFMessage from given flow information and add it to the queue.
-	 * @param sw Switch to which message is sent.
-	 * @param flowPath FlowPath.
-	 * @param flowEntry FlowEntry.
-	 * @return true if secceed.
-	 */
+
 	@Override
-	public boolean add(IOFSwitch sw, FlowPath flowPath, FlowEntry flowEntry) {
+	public void pushFlowEntries(
+		Collection<Pair<IOFSwitch, FlowEntry>> entries) {
+
+		List<Pair<IOFSwitch, FlowEntry>> pushedEntries =
+			new LinkedList<Pair<IOFSwitch, FlowEntry>>();
+
+		for (Pair<IOFSwitch, FlowEntry> entry : entries) {
+			if (add(entry.first, entry.second)) {
+				pushedEntries.add(entry);
+			}
+		}
+
+		//
+		// 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.
+		// Only after inform the Flow Manager that the entry is pushed.
+		//
+		flowManager.flowEntriesPushedToSwitch(pushedEntries);
+	}
+
+	@Override
+	public void pushFlowEntry(IOFSwitch sw, FlowEntry flowEntry) {
+	    Collection<Pair<IOFSwitch, FlowEntry>> entries = 
+		new LinkedList<Pair<IOFSwitch, FlowEntry>>();
+
+	    entries.add(new Pair<IOFSwitch, FlowEntry>(sw, flowEntry));
+	    pushFlowEntries(entries);
+	}
+
+	/**
+	 * Create a message from FlowEntry and add it to the queue of the switch.
+	 * @param sw Switch to which message is pushed.
+	 * @param flowEntry FlowEntry object used for creating message.
+	 * @return true if message is successfully added to a queue.
+	 */
+	private boolean add(IOFSwitch sw, FlowEntry flowEntry) {
 		//
 		// Create the OpenFlow Flow Modification Entry to push
 		//
@@ -706,7 +518,6 @@
 		//
 		OFMatch match = new OFMatch();
 		match.setWildcards(OFMatch.OFPFW_ALL);
-		FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
 		FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
 
 		// Match the Incoming Port
@@ -718,9 +529,6 @@
 
 		// 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);
@@ -728,9 +536,6 @@
 
 		// 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);
@@ -738,9 +543,6 @@
 
 		// 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);
@@ -748,9 +550,6 @@
 
 		// 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);
@@ -758,9 +557,6 @@
 
 		// 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()
@@ -769,27 +565,18 @@
 
 		// 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);
@@ -797,9 +584,6 @@
 
 		// 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);
@@ -807,9 +591,6 @@
 
 		// 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);
@@ -817,9 +598,6 @@
 
 		// 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);
@@ -942,8 +720,8 @@
 			}
 		}
 
-		fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
-				.setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
+		fm.setIdleTimeout((short)flowEntry.idleTimeout())
+				.setHardTimeout((short)flowEntry.hardTimeout())
 				.setPriority(PRIORITY_DEFAULT)
 				.setBufferId(OFPacketOut.BUFFER_ID_NONE).setCookie(cookie)
 				.setCommand(flowModCommand).setMatch(match)
@@ -965,27 +743,68 @@
 		//
 		// Write the message to the switch
 		//
-		log.debug("MEASUREMENT: Installing flow entry "
+		log.debug("Installing flow entry "
 				+ flowEntry.flowEntryUserState() + " into switch DPID: "
 				+ sw.getStringId() + " flowEntryId: "
 				+ flowEntry.flowEntryId().toString() + " srcMac: "
 				+ matchSrcMac + " dstMac: " + matchDstMac + " inPort: "
 				+ matchInPort + " outPort: " + actionOutputPort);
 		
-		//
-		// 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.
-		//
+		return add(sw, fm);
+	}
+	
+	@Override
+	public OFBarrierReply barrier(IOFSwitch sw) {
+		OFMessageFuture<OFBarrierReply> future = barrierAsync(sw);
+		if (future == null) {
+			return null;
+		}
 		
-		return add(sw,fm);
+		try {
+			return future.get();
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+			log.error("InterruptedException: {}", e);
+			return null;
+		} catch (ExecutionException e) {
+			e.printStackTrace();
+			log.error("ExecutionException: {}", e);
+			return null;
+		}
 	}
 
-	private SwitchQueue getQueue(IOFSwitch sw) {
+	@Override
+	public OFBarrierReplyFuture barrierAsync(IOFSwitch sw) {
+		// TODO creation of message and future should be moved to OFSwitchImpl
+
+		if (sw == null) {
+			return null;
+		}
+		
+		OFBarrierRequest msg = (OFBarrierRequest) factory.getMessage(OFType.BARRIER_REQUEST);
+		msg.setXid(sw.getNextTransactionId());
+
+		OFBarrierReplyFuture future = new OFBarrierReplyFuture(threadPool, sw, msg.getXid());
+		synchronized (barrierFutures) {
+			Map<Integer,OFBarrierReplyFuture> map = barrierFutures.get(sw.getId());
+			if (map == null) {
+				map = new HashMap<Integer,OFBarrierReplyFuture>();
+				barrierFutures.put(sw.getId(), map);
+			}
+			map.put(msg.getXid(), future);
+		}
+		
+		add(sw, msg);
+		
+		return future;
+	}
+
+	/**
+	 * Get a queue attached to a switch.
+	 * @param sw Switch object
+	 * @return Queue object
+	 */
+	protected SwitchQueue getQueue(IOFSwitch sw) {
 		if (sw == null)  {
 			return null;
 		}
@@ -993,14 +812,61 @@
 		return getProcess(sw).queues.get(sw);
 	}
 	
-	private long getHash(IOFSwitch sw) {
-		// TODO should consider equalization algorithm
+	/**
+	 * Get a hash value correspondent to a switch.
+	 * @param sw Switch object
+	 * @return Hash value
+	 */
+	protected long getHash(IOFSwitch sw) {
+		// This code assumes DPID is sequentially assigned.
+		// TODO consider equalization algorithm
 		return sw.getId() % number_thread;
 	}
-	
-	private FlowPusherProcess getProcess(IOFSwitch sw) {
+
+	/**
+	 * Get a Thread object which processes the queue attached to a switch.
+	 * @param sw Switch object
+	 * @return Thread object
+	 */
+	protected FlowPusherThread getProcess(IOFSwitch sw) {
 		long hash = getHash(sw);
 		
 		return threadMap.get(hash);
 	}
+
+	@Override
+	public String getName() {
+		return "flowpusher";
+	}
+
+	@Override
+	public boolean isCallbackOrderingPrereq(OFType type, String name) {
+		return false;
+	}
+
+	@Override
+	public boolean isCallbackOrderingPostreq(OFType type, String name) {
+		return false;
+	}
+
+	@Override
+	public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+		Map<Integer,OFBarrierReplyFuture> map = barrierFutures.get(sw.getId());
+		if (map == null) {
+			log.debug("null map for {} : {}", sw.getId(), barrierFutures);
+			return Command.CONTINUE;
+		}
+		
+		OFBarrierReplyFuture future = map.get(msg.getXid());
+		if (future == null) {
+			log.debug("null future for {} : {}", msg.getXid(), map);
+			return Command.CONTINUE;
+		}
+		
+		log.debug("Received BARRIER_REPLY : {}", msg);
+		future.deliverFuture(sw, msg);
+		
+		return Command.CONTINUE;
+	}
+
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java
index b2e4552..6ef44be 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java
@@ -2,34 +2,20 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
 
 import org.openflow.protocol.OFFlowMod;
 import org.openflow.protocol.OFMatch;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketOut;
 import org.openflow.protocol.OFPort;
 import org.openflow.protocol.OFStatisticsRequest;
-import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.action.OFActionDataLayerDestination;
-import org.openflow.protocol.action.OFActionDataLayerSource;
-import org.openflow.protocol.action.OFActionEnqueue;
-import org.openflow.protocol.action.OFActionNetworkLayerDestination;
-import org.openflow.protocol.action.OFActionNetworkLayerSource;
-import org.openflow.protocol.action.OFActionNetworkTypeOfService;
-import org.openflow.protocol.action.OFActionOutput;
-import org.openflow.protocol.action.OFActionStripVirtualLan;
-import org.openflow.protocol.action.OFActionTransportLayerDestination;
-import org.openflow.protocol.action.OFActionTransportLayerSource;
-import org.openflow.protocol.action.OFActionVirtualLanIdentifier;
-import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint;
 import org.openflow.protocol.statistics.OFFlowStatisticsReply;
 import org.openflow.protocol.statistics.OFFlowStatisticsRequest;
 import org.openflow.protocol.statistics.OFStatistics;
@@ -37,120 +23,125 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.Lists;
-import com.tinkerpop.blueprints.Direction;
-
-import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.IOFSwitchListener;
-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.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.ISwitchObject;
-import net.onrc.onos.ofcontroller.core.module.IOnosService;
-import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
+import net.onrc.onos.ofcontroller.flowmanager.FlowDatabaseOperation;
 import net.onrc.onos.ofcontroller.util.Dpid;
-import net.onrc.onos.ofcontroller.util.FlowEntryAction;
-import net.onrc.onos.ofcontroller.util.FlowEntryActions;
+import net.onrc.onos.ofcontroller.util.FlowEntry;
 import net.onrc.onos.ofcontroller.util.FlowEntryId;
-import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionEnqueue;
-import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionOutput;
-import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetEthernetAddr;
-import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetIPv4Addr;
-import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetIpToS;
-import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetTcpUdpPort;
-import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetVlanId;
-import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionSetVlanPriority;
-import net.onrc.onos.ofcontroller.util.FlowEntryAction.ActionStripVlan;
-import net.onrc.onos.registry.controller.IControllerRegistryService;
 
-public class FlowSynchronizer implements IFlowSyncService, IOFSwitchListener {
+/**
+ * FlowSynchronizer is an implementation of FlowSyncService.
+ * In addition to IFlowSyncService, FlowSynchronizer periodically reads flow
+ * tables from switches and compare them with GraphDB to drop unnecessary
+ * flows and/or to install missing flows.
+ * @author Brian
+ *
+ */
+public class FlowSynchronizer implements IFlowSyncService {
 
-    protected static Logger log = LoggerFactory.getLogger(FlowSynchronizer.class);
-    protected IFloodlightProviderService floodlightProvider;
-    protected IControllerRegistryService registryService;
-    protected IFlowPusherService pusher;
+    private static Logger log = LoggerFactory.getLogger(FlowSynchronizer.class);
 
     private GraphDBOperation dbHandler;
-    private Map<IOFSwitch, Thread> switchThread = new HashMap<IOFSwitch, Thread>();
+    protected IFlowPusherService pusher;
+    private Map<IOFSwitch, FutureTask<SyncResult>> switchThreads; 
 
     public FlowSynchronizer() {
 	dbHandler = new GraphDBOperation("");
-    }
-
-    public void synchronize(IOFSwitch sw) {
-	Synchroizer sync = new Synchroizer(sw);
-	Thread t = new Thread(sync);
-	t.start();
-	switchThread.put(sw, t);
+	switchThreads = new HashMap<IOFSwitch, FutureTask<SyncResult>>();
     }
 
     @Override
-    public void addedSwitch(IOFSwitch sw) {
-	log.debug("Switch added: {}", sw.getId());
-
-	if (registryService.hasControl(sw.getId())) {
-	    synchronize(sw);
-	}
+    public Future<SyncResult> synchronize(IOFSwitch sw) {
+	Synchronizer sync = new Synchronizer(sw);
+	FutureTask<SyncResult> task = new FutureTask<SyncResult>(sync);
+	switchThreads.put(sw, task);
+	task.run();
+	return task;
     }
-
+    
     @Override
-    public void removedSwitch(IOFSwitch sw) {
-	log.debug("Switch removed: {}", sw.getId());
-
-	Thread t = switchThread.remove(sw);
+    public void interrupt(IOFSwitch sw) {
+	FutureTask<SyncResult> t = switchThreads.remove(sw);
 	if(t != null) {
-	    t.interrupt();
-	}
-
+		t.cancel(true);
+	}	
     }
 
-    @Override
-    public void switchPortChanged(Long switchId) {
-	// TODO Auto-generated method stub
+    /**
+     * Initialize Synchronizer.
+     * @param pusherService FlowPusherService used for sending messages.
+     */
+    public void init(IFlowPusherService pusherService) {
+	pusher = pusherService;
     }
 
-    @Override
-    public String getName() {
-	return "FlowSynchronizer";
-    }
-
-    //@Override
-    public void init(FloodlightModuleContext context)
-	    throws FloodlightModuleException {
-	floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
-	registryService = context.getServiceImpl(IControllerRegistryService.class);
-	pusher = context.getServiceImpl(IFlowPusherService.class);
-    }
-
-    //@Override
-    public void startUp(FloodlightModuleContext context) {
-	floodlightProvider.addOFSwitchListener(this);
-    }
-
-    protected class Synchroizer implements Runnable {
+    /**
+     * Synchronizer represents main thread of synchronization.
+     * @author Brian
+     *
+     */
+	protected class Synchronizer implements Callable<SyncResult> {
 	IOFSwitch sw;
 	ISwitchObject swObj;
 
-	public Synchroizer(IOFSwitch sw) {
+	public Synchronizer(IOFSwitch sw) {
 	    this.sw = sw;
 	    Dpid dpid = new Dpid(sw.getId());
 	    this.swObj = dbHandler.searchSwitch(dpid.toString());
 	}
 
+	double graphIDTime, switchTime, compareTime, graphEntryTime, extractTime, pushTime, totalTime;
 	@Override
-	public void run() {
+	public SyncResult call() {
+	    // TODO: stop adding other flow entries while synchronizing
+	    //pusher.suspend(sw);
+	    long start = System.nanoTime();
 	    Set<FlowEntryWrapper> graphEntries = getFlowEntriesFromGraph();
+	    long step1 = System.nanoTime();
 	    Set<FlowEntryWrapper> switchEntries = getFlowEntriesFromSwitch();
-	    compare(graphEntries, switchEntries);
+	    long step2 = System.nanoTime();
+	    SyncResult result = compare(graphEntries, switchEntries);
+	    long step3 = System.nanoTime();
+	    graphIDTime = (step1 - start); 
+	    switchTime = (step2 - step1);
+	    compareTime = (step3 - step2);
+	    totalTime = (step3 - start);
+	    outputTime();
+	    //pusher.resume(sw);
+	    
+	    return result;
+	}
+	
+	private void outputTime() {
+	    double div = Math.pow(10, 6); //convert nanoseconds to ms
+	    graphIDTime /= div;
+	    switchTime /= div;
+	    compareTime = (compareTime - graphEntryTime - extractTime - pushTime) / div;
+	    graphEntryTime /= div;
+	    extractTime /= div;
+	    pushTime /= div;
+	    totalTime /= div;
+	    log.debug("Sync time (ms):" +
+	    		  graphIDTime + "," +
+	     		  switchTime + "," + 
+	    		  compareTime + "," +
+	     		  graphEntryTime + "," +
+	    		  extractTime + "," + 
+	     		  pushTime + "," +
+	              totalTime);
 	}
 
-	private void compare(Set<FlowEntryWrapper> graphEntries, Set<FlowEntryWrapper> switchEntries) {
+	/**
+	 * Compare flows entries in GraphDB and switch to pick up necessary
+	 * messages.
+	 * After picking up, picked messages are added to FlowPusher.
+	 * @param graphEntries Flow entries in GraphDB.
+	 * @param switchEntries Flow entries in switch.
+	 */
+	private SyncResult compare(Set<FlowEntryWrapper> graphEntries, Set<FlowEntryWrapper> switchEntries) {
 	    int added = 0, removed = 0, skipped = 0;
 	    for(FlowEntryWrapper entry : switchEntries) {
 		if(graphEntries.contains(entry)) {
@@ -166,13 +157,22 @@
 	    for(FlowEntryWrapper entry : graphEntries) {
 		// add flow entry to switch
 		entry.addToSwitch(sw);
+		graphEntryTime += entry.dbTime;
+		extractTime += entry.extractTime;
+		pushTime += entry.pushTime;
 		added++;
 	    }	  
 	    log.debug("Flow entries added "+ added + ", " +
 		      "Flow entries removed "+ removed + ", " +
 		      "Flow entries skipped " + skipped);
+	    
+	    return new SyncResult(added, removed, skipped);
 	}
 
+	/**
+	 * Read GraphDB to get FlowEntries associated with a switch.
+	 * @return set of FlowEntries
+	 */
 	private Set<FlowEntryWrapper> getFlowEntriesFromGraph() {
 	    Set<FlowEntryWrapper> entries = new HashSet<FlowEntryWrapper>();
 	    for(IFlowEntry entry : swObj.getFlowEntries()) {
@@ -182,6 +182,10 @@
 	    return entries;	    
 	}
 
+	/**
+	 * Read flow table from switch and derive FlowEntries from table.
+	 * @return set of FlowEntries
+	 */
 	private Set<FlowEntryWrapper> getFlowEntriesFromSwitch() {
 
 	    int lengthU = 0;
@@ -228,48 +232,90 @@
 
     }
 
+    /**
+     * FlowEntryWrapper represents abstract FlowEntry which is embodied
+     * by FlowEntryId (from GraphDB) or OFFlowStatisticsReply (from switch).
+     * @author Brian
+     *
+     */
     class FlowEntryWrapper {
-	FlowEntryId id;
-	IFlowEntry iflowEntry;
+	FlowEntryId flowEntryId;
 	OFFlowStatisticsReply statisticsReply;
 
 	public FlowEntryWrapper(IFlowEntry entry) {
-	    iflowEntry = entry;
-	    id = new FlowEntryId(entry.getFlowEntryId());
+	    flowEntryId = new FlowEntryId(entry.getFlowEntryId());
 	}
 
 	public FlowEntryWrapper(OFFlowStatisticsReply entry) {
+	    flowEntryId = new FlowEntryId(entry.getCookie());
 	    statisticsReply = entry;
-	    id = new FlowEntryId(entry.getCookie());
 	}
 
+	/**
+	 * Install this FlowEntry to a switch via FlowPusher.
+	 * @param sw Switch to which flow will be installed.
+	 */
+	double dbTime, extractTime, pushTime;
 	public void addToSwitch(IOFSwitch sw) {
-	    if(iflowEntry != null) {
-		pusher.add(sw, iflowEntry.getFlow(), iflowEntry);
-	    }
-	    else if(statisticsReply != null) {
-		log.error("Adding existing flow entry {} to sw {}", 
+	    if (statisticsReply != null) {
+		log.error("Error adding existing flow entry {} to sw {}", 
 			  statisticsReply.getCookie(), sw.getId());
+		return;
 	    }
+
+	    double startDB = System.nanoTime();
+	    // Get the Flow Entry state from the Network Graph
+	    IFlowEntry iFlowEntry = null;
+	    try {
+		iFlowEntry = dbHandler.searchFlowEntry(flowEntryId);
+	    } catch (Exception e) {
+		log.error("Error finding flow entry {} in Network Graph",
+			  flowEntryId);
+		return;
+	    }
+	    if (iFlowEntry == null) {
+		log.error("Cannot add flow entry {} to sw {} : flow entry not found",
+			  flowEntryId, sw.getId());
+		return;
+	    }
+	    dbTime = System.nanoTime() - startDB;
+
+	    double startExtract = System.nanoTime();
+	    FlowEntry flowEntry =
+		FlowDatabaseOperation.extractFlowEntry(iFlowEntry);
+	    if (flowEntry == null) {
+		log.error("Cannot add flow entry {} to sw {} : flow entry cannot be extracted",
+			  flowEntryId, sw.getId());
+		return;
+	    }
+	    extractTime = System.nanoTime() - startExtract;
+	    
+	    double startPush = System.nanoTime();
+	    pusher.pushFlowEntry(sw, flowEntry);
+	    pushTime = System.nanoTime() - startPush;
 	}
 	
-	public void removeFromSwitch(IOFSwitch sw){
-	    if(iflowEntry != null) {
-		log.error("Removing non-existent flow entry {} from sw {}", 
-			  iflowEntry.getFlowEntryId(), sw.getId());
+	/**
+	 * Remove this FlowEntry from a switch via FlowPusher.
+	 * @param sw Switch from which flow will be removed.
+	 */
+	public void removeFromSwitch(IOFSwitch sw) {
+	    if (statisticsReply == null) {
+		log.error("Error removing non-existent flow entry {} from sw {}", 
+			  flowEntryId, sw.getId());
+		return;
+	    }
 
-	    }
-	    else if(statisticsReply != null) {
-		// Convert Statistics Reply to Flow Mod, then write it
-		OFFlowMod fm = new OFFlowMod();
-		fm.setCookie(statisticsReply.getCookie());
-		fm.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
-		fm.setLengthU(OFFlowMod.MINIMUM_LENGTH);
-		fm.setMatch(statisticsReply.getMatch());
-		fm.setPriority(statisticsReply.getPriority());
-		fm.setOutPort(OFPort.OFPP_NONE);
-		pusher.add(sw, fm);
-	    }
+	    // Convert Statistics Reply to Flow Mod, then write it
+	    OFFlowMod fm = new OFFlowMod();
+	    fm.setCookie(statisticsReply.getCookie());
+	    fm.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
+	    fm.setLengthU(OFFlowMod.MINIMUM_LENGTH);
+	    fm.setMatch(statisticsReply.getMatch());
+	    fm.setPriority(statisticsReply.getPriority());
+	    fm.setOutPort(OFPort.OFPP_NONE);
+
+	    pusher.add(sw, fm);
 	}
 
 	/**
@@ -277,7 +323,7 @@
 	 */
 	@Override
 	public int hashCode() {
-	    return id.hashCode();
+	    return flowEntryId.hashCode();
 	}
 
 	/**
@@ -285,22 +331,21 @@
 	 * the same value; otherwise, returns false.
 	 * 
 	 * @param Object to compare
+	 * @return true if the object has the same Flow Entry ID.
 	 */
 	@Override
 	public boolean equals(Object obj){
 	    if(obj.getClass() == this.getClass()) {
 		FlowEntryWrapper entry = (FlowEntryWrapper) obj;
 		// TODO: we need to actually compare the match + actions
-		return this.id.equals(entry.id);
+		return this.flowEntryId.equals(entry.flowEntryId);
 	    }
 	    return false;
 	}
 
 	@Override
 	public String toString() {
-	    return id.toString();
+	    return flowEntryId.toString();
 	}
     }
 }
-
-
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/IFlowPusherService.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/IFlowPusherService.java
index e16dd20..6bf20d9 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/IFlowPusherService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/IFlowPusherService.java
@@ -1,43 +1,127 @@
 package net.onrc.onos.ofcontroller.flowprogrammer;
 
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.module.IFloodlightService;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
-import net.onrc.onos.ofcontroller.util.FlowEntry;
-import net.onrc.onos.ofcontroller.util.FlowPath;
+import java.util.Collection;
 
+import org.openflow.protocol.OFBarrierReply;
 import org.openflow.protocol.OFMessage;
 
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.internal.OFMessageFuture;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.onrc.onos.ofcontroller.util.FlowEntry;
+import net.onrc.onos.ofcontroller.util.Pair;
+
+/**
+ * FlowPusherService is a service to send message to switches in proper rate.
+ * Conceptually a queue is attached to each switch, and FlowPusherService
+ * read a message from queue and send it to switch in order.
+ * To guarantee message has been installed, FlowPusherService can add barrier
+ * message to queue and can notify when barrier message is sent to switch.
+ * @author Naoki Shiota
+ *
+ */
 public interface IFlowPusherService extends IFloodlightService {
 	/**
-	 * Add a message to the queue of a switch.
-	 * @param sw
-	 * @param msg
-	 * @return
+	 * Create a queue correspondent to the switch.
+	 * @param sw Switch to which new queue is attached.
+	 * @return true if new queue is successfully created.
+	 */
+	boolean createQueue(IOFSwitch sw);
+
+	/**
+	 * Delete a queue correspondent to the switch.
+	 * Messages remains in queue will be all sent before queue is deleted.
+	 * @param sw Switch of which queue is deleted.
+	 * @return true if queue is successfully deleted.
+	 */
+	boolean deleteQueue(IOFSwitch sw);
+	
+	/**
+	 * Delete a queue correspondent to the switch.
+	 * By setting force flag on, queue will be deleted immediately.
+	 * @param sw Switch of which queue is deleted.
+	 * @param forceStop If this flag is set to true, queue will be deleted
+	 *        immediately regardless of any messages in the queue.
+	 *        If false, all messages will be sent to switch and queue will
+	 *        be deleted after that.
+	 * @return true if queue is successfully deleted or flagged to be deleted.
+	 */
+	boolean deleteQueue(IOFSwitch sw, boolean forceStop);
+	
+	/**
+	 * Add a message to the queue of the switch.
+	 *
+	 * Note: Notification is NOT delivered for the pushed message.
+	 *
+	 * @param sw Switch to which message is pushed.
+	 * @param msg Message object to be added.
+	 * @return true if message is successfully added to a queue.
 	 */
 	boolean add(IOFSwitch sw, OFMessage msg);
-	boolean add(IOFSwitch sw, FlowPath flowPath, FlowEntry flowEntry);
-	boolean add(IOFSwitch sw, IFlowPath flowObj, IFlowEntry flowEntryObj);
+
+	/**
+	 * Push a collection of Flow Entries to the corresponding switches.
+	 *
+	 * Note: Notification is delivered for the Flow Entries that
+	 * are pushed successfully.
+	 *
+	 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
+	 * to push.
+	 */
+	void pushFlowEntries(Collection<Pair<IOFSwitch, FlowEntry>> entries);
+
+	/**
+	 * Create a message from FlowEntry and add it to the queue of the
+	 * switch.
+	 *
+	 * Note: Notification is delivered for the Flow Entries that
+	 * are pushed successfully.
+	 *
+	 * @param sw Switch to which message is pushed.
+	 * @param flowEntry FlowEntry object used for creating message.
+	 * @return true if message is successfully added to a queue.
+	 */
+	void pushFlowEntry(IOFSwitch sw, FlowEntry flowEntry);
+
+	/**
+	 * Set sending rate to a switch.
+	 * @param sw Switch.
+	 * @param rate Rate in bytes/ms.
+	 */
+	public void setRate(IOFSwitch sw, long rate);
+	
+	/**
+	 * Add BARRIER message to queue and wait for reply.
+	 * @param sw Switch to which barrier message is pushed.
+	 * @return BARRIER_REPLY message sent from switch.
+	 */
+	OFBarrierReply barrier(IOFSwitch sw);
+	
+	/**
+	 * Add BARRIER message to queue asynchronously.
+	 * @param sw Switch to which barrier message is pushed.
+	 * @return Future object of BARRIER_REPLY message which will be sent from switch.
+	 */
+	OFMessageFuture<OFBarrierReply> barrierAsync(IOFSwitch sw);
 	
 	/**
 	 * Suspend pushing message to a switch.
-	 * @param sw
+	 * @param sw Switch to be suspended pushing message.
 	 * @return true if success
 	 */
 	boolean suspend(IOFSwitch sw);
 	
 	/**
 	 * Resume pushing message to a switch.
-	 * @param sw
+	 * @param sw Switch to be resumed pushing message.
 	 * @return true if success
 	 */
 	boolean resume(IOFSwitch sw);
 	
 	/**
 	 * Get whether pushing of message is suspended or not.
-	 * @param sw
-	 * @return true if suspended
+	 * @param sw Switch to be checked.
+	 * @return true if suspended.
 	 */
 	boolean isSuspended(IOFSwitch sw);
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/IFlowSyncService.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/IFlowSyncService.java
index 1e71f6a..4fe0857 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/IFlowSyncService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/IFlowSyncService.java
@@ -1,13 +1,30 @@
 package net.onrc.onos.ofcontroller.flowprogrammer;
 
+import java.util.concurrent.Future;
+
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.IOFSwitchListener;
 import net.floodlightcontroller.core.module.IFloodlightService;
 
 /**
- * @author bocon
+ * FlowSyncService is a service to synchronize GraphDB and switch's flow table.
+ * FlowSyncService offers APIs to trigger and interrupt synchronization explicitly.
+ * @author Brian
  *
  */
 public interface IFlowSyncService extends IFloodlightService {
-    public void synchronize(IOFSwitch sw);
+    public Future<SyncResult> synchronize(IOFSwitch sw);
+    
+    public void interrupt(IOFSwitch sw);
+    
+    public class SyncResult {
+    	public final int flowAdded;
+    	public final int flowRemoved;
+    	public final int flowSkipped;
+    	
+    	public SyncResult(int added, int removed, int skipped) {
+    		flowAdded = added;
+    		flowRemoved = removed;
+    		flowSkipped = skipped;
+    	}
+    }
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/OFBarrierReplyFuture.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/OFBarrierReplyFuture.java
new file mode 100644
index 0000000..3013f5a
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/OFBarrierReplyFuture.java
@@ -0,0 +1,49 @@
+package net.onrc.onos.ofcontroller.flowprogrammer;
+
+import java.util.concurrent.TimeUnit;
+
+import org.openflow.protocol.OFBarrierReply;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
+
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.internal.OFMessageFuture;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+
+public class OFBarrierReplyFuture extends OFMessageFuture<OFBarrierReply> {
+
+    protected volatile boolean finished;
+
+    public OFBarrierReplyFuture(IThreadPoolService tp,
+            IOFSwitch sw, int transactionId) {
+        super(tp, sw, OFType.FEATURES_REPLY, transactionId);
+        init();
+    }
+
+    public OFBarrierReplyFuture(IThreadPoolService tp,
+            IOFSwitch sw, int transactionId, long timeout, TimeUnit unit) {
+        super(tp, sw, OFType.FEATURES_REPLY, transactionId, timeout, unit);
+        init();
+    }
+
+    private void init() {
+        this.finished = false;
+        this.result = null;
+    }
+
+    @Override
+    protected void handleReply(IOFSwitch sw, OFMessage msg) {
+        this.result = (OFBarrierReply) msg;
+        this.finished = true;
+    }
+
+    @Override
+    protected boolean isFinished() {
+        return finished;
+    }
+
+    @Override
+    protected void unRegister() {
+        super.unRegister();
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/DoInterruptResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/DoInterruptResource.java
new file mode 100644
index 0000000..3c2920d
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/DoInterruptResource.java
@@ -0,0 +1,44 @@
+package net.onrc.onos.ofcontroller.flowprogrammer.web;
+
+import net.floodlightcontroller.core.IOFSwitch;
+
+import org.openflow.util.HexString;
+import org.restlet.resource.Get;
+
+/**
+ * FlowProgrammer REST API implementation: Interrupt synchronization to a switch.
+ *
+ *   GET /wm/fprog/synchronizer/interrupt/{dpid}/json"
+ */
+public class DoInterruptResource extends SynchronizerResource {
+
+    /**
+     * Implement the API.
+     *
+     * @return true if succeeded, false if failed.
+     */
+    @Get("json")
+    public boolean retrieve() {
+    	if (! init()) {
+    		return false;
+    	}
+    	
+    	long dpid;
+    	try {
+    		dpid = HexString.toLong((String)getRequestAttributes().get("dpid"));
+    	} catch (NumberFormatException e) {
+    		log.error("Invalid number format");
+    		return false;
+    	}
+
+    	IOFSwitch sw = provider.getSwitches().get(dpid);
+    	if (sw == null) {
+    		log.error("Invalid dpid");
+    		return false;
+    	}
+    	
+    	synchronizer.interrupt(sw);
+    	
+    	return true;
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/DoSynchronizeResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/DoSynchronizeResource.java
new file mode 100644
index 0000000..dc8d431
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/DoSynchronizeResource.java
@@ -0,0 +1,44 @@
+package net.onrc.onos.ofcontroller.flowprogrammer.web;
+
+import net.floodlightcontroller.core.IOFSwitch;
+
+import org.openflow.util.HexString;
+import org.restlet.resource.Get;
+
+/**
+ * FlowProgrammer REST API implementation: Begin synchronization to a switch.
+ *
+ *   GET /wm/fprog/synchronizer/sync/{dpid}/json"
+ */
+public class DoSynchronizeResource extends SynchronizerResource {
+    /**
+     * Implement the API.
+     *
+     * @return true if succeeded, false if failed.
+     */
+    @Get("json")
+    public boolean retrieve() {
+    	if (! init()) {
+    		return false;
+    	}
+    	
+    	long dpid;
+    	try {
+    		dpid = HexString.toLong((String)getRequestAttributes().get("dpid"));
+    	} catch (NumberFormatException e) {
+    		log.error("Invalid number format");
+    		return false;
+    	}
+
+    	IOFSwitch sw = provider.getSwitches().get(dpid);
+    	if (sw == null) {
+    		log.error("Invalid dpid");
+    		return false;
+    	}
+    	
+    	synchronizer.synchronize(sw);
+    	
+    	return true;
+    }
+
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/FlowProgrammerWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/FlowProgrammerWebRoutable.java
new file mode 100644
index 0000000..22450f7
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/FlowProgrammerWebRoutable.java
@@ -0,0 +1,28 @@
+package net.onrc.onos.ofcontroller.flowprogrammer.web;
+
+import org.restlet.Context;
+import org.restlet.Restlet;
+import org.restlet.routing.Router;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+
+public class FlowProgrammerWebRoutable implements RestletRoutable {
+
+	@Override
+	public Restlet getRestlet(Context context) {
+		Router router = new Router(context);
+		router.attach("/pusher/setrate/{dpid}/{rate}/json", SetPushRateResource.class);
+		router.attach("/pusher/suspend/{dpid}/json", SuspendPusherResource.class);
+		router.attach("/pusher/resume/{dpid}/json", ResumePusherResource.class);
+		router.attach("/pusher/barrier/{dpid}/json", SendBarrierResource.class);
+		router.attach("/synchronizer/sync/{dpid}/json", DoSynchronizeResource.class);
+		router.attach("/synchronizer/interrupt/{dpid}/json", DoInterruptResource.class);
+		return router;
+	}
+
+	@Override
+	public String basePath() {
+		return "/wm/fprog";
+	}
+
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/PusherResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/PusherResource.java
new file mode 100644
index 0000000..4e1c0fc
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/PusherResource.java
@@ -0,0 +1,33 @@
+package net.onrc.onos.ofcontroller.flowprogrammer.web;
+
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
+
+public class PusherResource extends ServerResource {
+    protected final static Logger log = LoggerFactory.getLogger(PusherResource.class);
+
+    protected IFloodlightProviderService provider;
+	protected IFlowPusherService pusher;
+	
+	protected boolean init() {
+    	provider = (IFloodlightProviderService)
+    			getContext().getAttributes().
+    			get(IFloodlightProviderService.class.getCanonicalName());
+    	if (provider == null) {
+		    log.debug("ONOS FloodlightProvider not found");
+		    return false;
+		}
+    	
+    	pusher = (IFlowPusherService)getContext().getAttributes().
+    			get(IFlowPusherService.class.getCanonicalName());
+    	if (pusher == null) {
+		    log.debug("ONOS FlowPusherService not found");
+		    return false;
+		}
+    	return true;
+	}
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/ResumePusherResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/ResumePusherResource.java
new file mode 100644
index 0000000..dcbe3e9
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/ResumePusherResource.java
@@ -0,0 +1,41 @@
+package net.onrc.onos.ofcontroller.flowprogrammer.web;
+
+import net.floodlightcontroller.core.IOFSwitch;
+
+import org.openflow.util.HexString;
+import org.restlet.resource.Get;
+
+/**
+ * FlowProgrammer REST API implementation: Resume sending message to switch.
+ *
+ *   GET /wm/fprog/pusher/resume/{dpid}/json"
+ */
+public class ResumePusherResource extends PusherResource {
+    /**
+     * Implement the API.
+     *
+     * @return true if succeeded, false if failed.
+     */
+    @Get("json")
+    public boolean retrieve() {
+    	if (! init()) {
+    		return false;
+    	}
+    	
+    	long dpid;
+    	try {
+    		dpid = HexString.toLong((String)getRequestAttributes().get("dpid"));
+    	} catch (NumberFormatException e) {
+    		log.error("Invalid number format");
+    		return false;
+    	}
+
+    	IOFSwitch sw = provider.getSwitches().get(dpid);
+    	if (sw == null) {
+    		log.error("Invalid dpid");
+    		return false;
+    	}
+    	
+    	return pusher.resume(sw);
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/SendBarrierResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/SendBarrierResource.java
new file mode 100644
index 0000000..33b666a
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/SendBarrierResource.java
@@ -0,0 +1,41 @@
+package net.onrc.onos.ofcontroller.flowprogrammer.web;
+
+import net.floodlightcontroller.core.IOFSwitch;
+
+import org.openflow.protocol.OFBarrierReply;
+import org.openflow.util.HexString;
+import org.restlet.resource.Get;
+
+/**
+ * FlowProgrammer REST API implementation: Send barrier message to switch.
+ *
+ *   GET /wm/fprog/pusher/barrier/{dpid}/json"
+ */
+public class SendBarrierResource extends PusherResource {
+    /**
+     * Implement the API.
+     *
+     * @return true if succeeded, false if failed.
+     */
+    @Get("json")
+    public OFBarrierReply retrieve() {
+    	if (! init()) {
+    		return null;
+    	}
+    	long dpid;
+    	try {
+    		dpid = HexString.toLong((String)getRequestAttributes().get("dpid"));
+    	} catch (NumberFormatException e) {
+    		log.error("Invalid number format");
+    		return null;
+    	}
+
+    	IOFSwitch sw = provider.getSwitches().get(dpid);
+    	if (sw == null) {
+    		log.error("Invalid dpid");
+    		return null;
+    	}
+    	
+    	return pusher.barrier(sw);
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/SetPushRateResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/SetPushRateResource.java
new file mode 100644
index 0000000..9431d65
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/SetPushRateResource.java
@@ -0,0 +1,47 @@
+package net.onrc.onos.ofcontroller.flowprogrammer.web;
+
+import net.floodlightcontroller.core.IOFSwitch;
+
+import org.openflow.util.HexString;
+import org.restlet.resource.Get;
+
+/**
+ * FlowProgrammer REST API implementation: Set sending rate to the switch.
+ *
+ *   GET /wm/fprog/pusher/setrate/{dpid}/{rate}/json"
+ */
+public class SetPushRateResource extends PusherResource {
+
+    /**
+     * Implement the API.
+     *
+     * @return true if succeeded, false if failed.
+     */
+    @Get("json")
+    public boolean retrieve() {
+    	if (! init()) {
+    		return false;
+    	}
+    	
+    	long dpid;
+    	long rate;
+    	
+    	try {
+    		dpid = HexString.toLong((String)getRequestAttributes().get("dpid"));
+        	rate = Long.valueOf((String)getRequestAttributes().get("rate"));
+    	} catch (NumberFormatException e) {
+    		log.error("Invalid number format");
+    		return false;
+    	}
+
+    	IOFSwitch sw = provider.getSwitches().get(dpid);
+    	if (sw == null) {
+    		log.error("Invalid dpid");
+    		return false;
+    	}
+    	
+    	pusher.setRate(sw, rate);
+    	
+    	return true;
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/SuspendPusherResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/SuspendPusherResource.java
new file mode 100644
index 0000000..1a5266b
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/SuspendPusherResource.java
@@ -0,0 +1,46 @@
+package net.onrc.onos.ofcontroller.flowprogrammer.web;
+
+import net.floodlightcontroller.core.IOFSwitch;
+
+import org.openflow.util.HexString;
+import org.restlet.resource.Get;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * FlowProgrammer REST API implementation: Suspend sending message to switch.
+ *
+ *   GET /wm/fprog/pusher/suspend/{dpid}/json"
+ */
+public class SuspendPusherResource extends PusherResource {
+
+    protected final static Logger log = LoggerFactory.getLogger(SetPushRateResource.class);
+
+    /**
+     * Implement the API.
+     *
+     * @return true if succeeded, false if failed.
+     */
+    @Get("json")
+    public boolean retrieve() {
+    	if (! init()) {
+    		return false;
+    	}
+    	
+    	long dpid;
+    	try {
+    		dpid = HexString.toLong((String)getRequestAttributes().get("dpid"));
+    	} catch (NumberFormatException e) {
+    		log.error("Invalid number format");
+    		return false;
+    	}
+
+    	IOFSwitch sw = provider.getSwitches().get(dpid);
+    	if (sw == null) {
+    		log.error("Invalid dpid");
+    		return false;
+    	}
+    	
+    	return pusher.suspend(sw);
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/SynchronizerResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/SynchronizerResource.java
new file mode 100644
index 0000000..12bf8f3
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/SynchronizerResource.java
@@ -0,0 +1,35 @@
+package net.onrc.onos.ofcontroller.flowprogrammer.web;
+
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.onrc.onos.ofcontroller.flowprogrammer.IFlowSyncService;
+
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SynchronizerResource extends ServerResource {
+    protected final static Logger log = LoggerFactory.getLogger(SynchronizerResource.class);
+    
+    protected IFloodlightProviderService provider;
+    protected IFlowSyncService synchronizer;
+
+    protected boolean init() {
+    	provider = (IFloodlightProviderService)
+    			getContext().getAttributes().
+    			get(IFloodlightProviderService.class.getCanonicalName());
+    	if (provider == null) {
+		    log.debug("ONOS FloodlightProvider not found");
+		    return false;
+		}
+    	
+    	synchronizer = (IFlowSyncService)
+    			getContext().getAttributes().
+    			get(IFlowSyncService.class.getCanonicalName());
+    	if (synchronizer == null) {
+		    log.debug("ONOS FlowSyncService not found");
+		    return false;
+		}
+    	
+    	return true;
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java b/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java
index ea6e384..3725d5e 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java
@@ -2,13 +2,20 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.util.MACAddress;
 import net.onrc.onos.datagrid.IDatagridService;
@@ -41,35 +48,113 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class Forwarding implements IOFMessageListener {
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+
+public class Forwarding implements IOFMessageListener, IFloodlightModule,
+									IForwardingService {
 	private final static Logger log = LoggerFactory.getLogger(Forwarding.class);
 
 	private IFloodlightProviderService floodlightProvider;
 	private IFlowService flowService;
+	@SuppressWarnings("unused")
 	private IDatagridService datagridService;
 	
 	private IDeviceStorage deviceStorage;
 	private TopologyManager topologyService;
 	
-	public Forwarding() {
+	private Map<Path, Long> pendingFlows;
+	private Multimap<Long, PacketToPush> waitingPackets;
+	
+	public class PacketToPush {
+		public final OFPacketOut packet;
+		public final long dpid;
 		
+		public PacketToPush(OFPacketOut packet, long dpid) {
+			this.packet = packet;
+			this.dpid = dpid;
+		}
 	}
 	
-	public void init(IFloodlightProviderService floodlightProvider, 
-			IFlowService flowService, IDatagridService datagridService) {
-		this.floodlightProvider = floodlightProvider;
-		this.flowService = flowService;
-		this.datagridService = datagridService;
+	public final class Path {
+		public final SwitchPort srcPort;
+		public final SwitchPort dstPort;
+		
+		public Path(SwitchPort src, SwitchPort dst) {
+			srcPort = new SwitchPort(new Dpid(src.dpid().value()), 
+					new Port(src.port().value()));
+			dstPort = new SwitchPort(new Dpid(dst.dpid().value()), 
+					new Port(dst.port().value()));
+		}
+		
+		@Override
+		public boolean equals(Object other) {
+			if (!(other instanceof Path)) {
+				return false;
+			}
+			
+			Path otherPath = (Path) other;
+			return srcPort.equals(otherPath.srcPort) && 
+					dstPort.equals(otherPath.dstPort);
+		}
+		
+		@Override
+		public int hashCode() {
+			int hash = 17;
+			hash = 31 * hash + srcPort.hashCode();
+			hash = 31 * hash + dstPort.hashCode();
+			return hash;
+		}
+	}
+	
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+		List<Class<? extends IFloodlightService>> services = 
+				new ArrayList<Class<? extends IFloodlightService>>(1);
+		services.add(IForwardingService.class);
+		return services;
+	}
+
+	@Override
+	public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+		Map<Class<? extends IFloodlightService>, IFloodlightService> impls = 
+				new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(1);
+		impls.put(IForwardingService.class, this);
+		return impls;
+	}
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+		List<Class<? extends IFloodlightService>> dependencies = 
+				new ArrayList<Class<? extends IFloodlightService>>();
+		dependencies.add(IFloodlightProviderService.class);
+		dependencies.add(IFlowService.class);
+		dependencies.add(IDatagridService.class);
+		return dependencies;
+	}
+	
+	@Override
+	public void init(FloodlightModuleContext context) {
+		this.floodlightProvider = 
+				context.getServiceImpl(IFloodlightProviderService.class);
+		this.flowService = context.getServiceImpl(IFlowService.class);
+		this.datagridService = context.getServiceImpl(IDatagridService.class);
 		
 		floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
 		
+		pendingFlows = new ConcurrentHashMap<Path, Long>();
+		waitingPackets = Multimaps.synchronizedSetMultimap(
+				HashMultimap.<Long, PacketToPush>create());
+		
 		deviceStorage = new DeviceStorageImpl();
 		deviceStorage.init("");
 		topologyService = new TopologyManager();
 		topologyService.init("");
 	}
 	
-	public void startUp() {
+	@Override
+	public void startUp(FloodlightModuleContext context) {
 		// no-op
 	}
 
@@ -114,7 +199,8 @@
 	}
 	
 	private void handlePacketIn(IOFSwitch sw, OFPacketIn pi, Ethernet eth) {
-		String destinationMac = HexString.toHexString(eth.getDestinationMACAddress()); 
+		String destinationMac = 
+				HexString.toHexString(eth.getDestinationMACAddress()); 
 		
 		IDeviceObject deviceObject = deviceStorage.getDeviceByMac(
 				destinationMac);
@@ -124,7 +210,7 @@
 			return;
 		}
 		
-		Iterator<IPortObject> ports = deviceObject.getAttachedPorts().iterator();
+		Iterator<IPortObject> ports = deviceObject.getAttachedPorts().iterator();	
 		if (!ports.hasNext()) {
 			log.debug("No attachment point found for device {}", destinationMac);
 			return;
@@ -144,52 +230,39 @@
 		MACAddress srcMacAddress = MACAddress.valueOf(eth.getSourceMACAddress());
 		MACAddress dstMacAddress = MACAddress.valueOf(eth.getDestinationMACAddress());
 		
-		if (flowExists(srcSwitchPort, srcMacAddress, 
-				dstSwitchPort, dstMacAddress)) {
-			log.debug("Not adding flow because it already exists");
+		
+		DataPath datapath = new DataPath();
+		datapath.setSrcPort(srcSwitchPort);
+		datapath.setDstPort(dstSwitchPort);
+		
+		
+		
+		Path pathspec = new Path(srcSwitchPort, dstSwitchPort);
+		// TODO check concurrency
+		Long existingFlowId = pendingFlows.get(pathspec);
+		
+		if (existingFlowId != null) {
+			log.debug("Found existing flow {}", 
+					HexString.toHexString(existingFlowId));
 			
-			// TODO check reverse flow as well
-			
-			DataPath shortestPath = 
-					topologyService.getDatabaseShortestPath(srcSwitchPort, dstSwitchPort);
-			
-			if (shortestPath == null || shortestPath.flowEntries().isEmpty()) {
-				log.warn("No path found between {} and {} - not handling packet",
-						srcSwitchPort, dstSwitchPort);
-				return;
-			}
-			
-			Port outPort = shortestPath.flowEntries().get(0).outPort();
-			forwardPacket(pi, sw, outPort.value());
+			// TODO do stuff.
+			OFPacketOut po = constructPacketOut(datapath, pi, sw);
+			waitingPackets.put(existingFlowId, new PacketToPush(po, sw.getId()));
 			return;
 		}
 		
-		// Calculate a shortest path before pushing flow mods.
-		// This will be used later by the packet-out processing, but it uses
-		// the database so will be slow, and we should do it before flow mods.
-		DataPath shortestPath = 
-				topologyService.getDatabaseShortestPath(srcSwitchPort, dstSwitchPort);
-		
-		if (shortestPath == null || shortestPath.flowEntries().isEmpty()) {
-			log.warn("No path found between {} and {} - not handling packet",
-					srcSwitchPort, dstSwitchPort);
-			return;
-		}
 		
 		log.debug("Adding new flow between {} at {} and {} at {}",
 				new Object[]{srcMacAddress, srcSwitchPort, dstMacAddress, dstSwitchPort});
 		
 		
-		DataPath dataPath = new DataPath();
-		dataPath.setSrcPort(srcSwitchPort);
-		dataPath.setDstPort(dstSwitchPort);
-		
 		CallerId callerId = new CallerId("Forwarding");
 		
-		FlowId flowId = new FlowId(flowService.getNextFlowEntryId());
+		//FlowId flowId = new FlowId(flowService.getNextFlowEntryId());
 		FlowPath flowPath = new FlowPath();
-		flowPath.setFlowId(flowId);
+		//flowPath.setFlowId(flowId);
 		flowPath.setInstallerId(callerId);
+
 		flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
 		flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
 		flowPath.setFlowEntryMatch(new FlowEntryMatch());
@@ -198,20 +271,16 @@
 		// For now just forward IPv4 packets. This prevents accidentally
 		// forwarding other stuff like ARP.
 		flowPath.flowEntryMatch().enableEthernetFrameType(Ethernet.TYPE_IPv4);
-		flowPath.setDataPath(dataPath);
-		
-		flowService.addFlow(flowPath, flowId);
-		
-		
+		flowPath.setDataPath(datapath);
+			
 		DataPath reverseDataPath = new DataPath();
 		// Reverse the ports for the reverse path
 		reverseDataPath.setSrcPort(dstSwitchPort);
 		reverseDataPath.setDstPort(srcSwitchPort);
 		
-		FlowId reverseFlowId = new FlowId(flowService.getNextFlowEntryId());
 		// TODO implement copy constructor for FlowPath
 		FlowPath reverseFlowPath = new FlowPath();
-		reverseFlowPath.setFlowId(reverseFlowId);
+		//reverseFlowPath.setFlowId(reverseFlowId);
 		reverseFlowPath.setInstallerId(callerId);
 		reverseFlowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
 		reverseFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
@@ -224,13 +293,25 @@
 		reverseFlowPath.dataPath().srcPort().dpid().toString();
 		
 		// TODO what happens if no path exists?
-		flowService.addFlow(reverseFlowPath, reverseFlowId);
+		FlowId flowId = new FlowId(flowService.getNextFlowEntryId());
+		FlowId reverseFlowId = new FlowId(flowService.getNextFlowEntryId());
 		
-
-		Port outPort = shortestPath.flowEntries().get(0).outPort();
-		forwardPacket(pi, sw, outPort.value());
+		flowPath.setFlowId(flowId);
+		reverseFlowPath.setFlowId(reverseFlowId);
+		
+		OFPacketOut po = constructPacketOut(datapath, pi, sw);
+		Path reversePathSpec = new Path(dstSwitchPort, srcSwitchPort);
+		
+		// Add to waiting lists
+		pendingFlows.put(pathspec, flowId.value());
+		pendingFlows.put(reversePathSpec, reverseFlowId.value());
+		waitingPackets.put(flowId.value(), new PacketToPush(po, sw.getId()));
+		
+		flowService.addFlow(reverseFlowPath);
+		flowService.addFlow(flowPath);
 	}
 	
+	/*
 	private boolean flowExists(SwitchPort srcPort, MACAddress srcMac, 
 			SwitchPort dstPort, MACAddress dstMac) {
 		for (FlowPath flow : datagridService.getAllFlows()) {
@@ -256,17 +337,18 @@
 		
 		return false;
 	}
+	*/
 
-	private void forwardPacket(OFPacketIn pi, IOFSwitch sw, short port) {
-		List<OFAction> actions = new ArrayList<OFAction>(1);
-		actions.add(new OFActionOutput(port));
+	private OFPacketOut constructPacketOut(DataPath datapath, OFPacketIn pi, 
+			IOFSwitch sw) {
+		//List<OFAction> actions = new ArrayList<OFAction>(1);
+		//actions.add(new OFActionOutput(port));
 		
 		OFPacketOut po = new OFPacketOut();
 		po.setInPort(OFPort.OFPP_NONE)
 		.setInPort(pi.getInPort())
-		.setActions(actions)
-		.setActionsLength((short)OFActionOutput.MINIMUM_LENGTH)
-		.setLengthU(OFPacketOut.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
+		.setActions(new ArrayList<OFAction>())
+		.setLengthU(OFPacketOut.MINIMUM_LENGTH);
 		
 		if (sw.getBuffers() == 0) {
 			po.setBufferId(OFPacketOut.BUFFER_ID_NONE)
@@ -277,11 +359,45 @@
 			po.setBufferId(pi.getBufferId());
 		}
 		
-		try {
-			sw.write(po, null);
-			sw.flush();
-		} catch (IOException e) {
-			log.error("Error writing packet out to switch: {}", e);
+		return po;
+	}
+
+	@Override
+	public void flowsInstalled(Collection<FlowPath> installedFlowPaths) {
+		for (FlowPath flowPath : installedFlowPaths) {
+			flowInstalled(flowPath);
+		}
+	}
+
+	private void flowInstalled(FlowPath installedFlowPath) {
+		// TODO check concurrency
+		// will need to sync and access both collections at once.
+		long flowId = installedFlowPath.flowId().value();
+		Collection<PacketToPush> packets = waitingPackets.removeAll(flowId);
+		
+		//remove pending flows entry
+		Path pathToRemove = new Path(installedFlowPath.dataPath().srcPort(),
+				installedFlowPath.dataPath().dstPort());
+		pendingFlows.remove(pathToRemove);
+		
+		for (PacketToPush packet : packets) {
+			IOFSwitch sw = floodlightProvider.getSwitches().get(packet.dpid);
+			
+			OFPacketOut po = packet.packet;
+			short outPort = 
+					installedFlowPath.flowEntries().get(0).outPort().value();
+			po.getActions().add(new OFActionOutput(outPort));
+			po.setActionsLength((short)
+					(po.getActionsLength() + OFActionOutput.MINIMUM_LENGTH));
+			po.setLengthU(po.getLengthU() + OFActionOutput.MINIMUM_LENGTH);
+			
+			try {
+				sw.write(packet.packet, null);
+				sw.flush();
+			} catch (IOException e) {
+				log.error("Error writing packet out to switch {}:", 
+						sw.getId(), e);
+			}
 		}
 	}
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/forwarding/IForwardingService.java b/src/main/java/net/onrc/onos/ofcontroller/forwarding/IForwardingService.java
new file mode 100644
index 0000000..e5bd714
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/forwarding/IForwardingService.java
@@ -0,0 +1,25 @@
+package net.onrc.onos.ofcontroller.forwarding;
+
+import java.util.Collection;
+
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.onrc.onos.ofcontroller.util.FlowPath;
+
+/**
+ * Temporary interface that allows the Forwarding module to be
+ * notified when a flow has been installed by the FlowManager.
+ * 
+ * This should be refactored to a listener framework in the future.
+ * @author jono
+ *
+ */
+public interface IForwardingService extends IFloodlightService {
+	/**
+	 * Notify the Forwarding module that a collection of flows has been
+	 * installed in the network.
+	 *
+	 * @param installedFlowPaths the collection of FlowPaths that have
+	 * been installed in the network.
+	 */
+	public void flowsInstalled(Collection<FlowPath> installedFlowPaths);
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpMessage.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpMessage.java
index 53891ef..5f22ca2 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpMessage.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpMessage.java
@@ -2,10 +2,6 @@
 
 import java.io.Serializable;
 import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.List;
-
-import net.onrc.onos.ofcontroller.util.SwitchPort;
 
 public class ArpMessage implements Serializable {
 
@@ -18,8 +14,6 @@
 	private final InetAddress forAddress;
 	private final byte[] packetData;
 	
-	private final List<SwitchPort> switchPorts = new ArrayList<SwitchPort>();
-	
 	public enum Type {
 		REQUEST,
 		REPLY
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java
index 71546a1..2029513 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java
@@ -3,11 +3,11 @@
 import java.net.InetAddress;
 import java.util.List;
 
+import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.util.MACAddress;
-import net.onrc.onos.ofcontroller.core.module.IOnosService;
 
 //Extends IFloodlightService so we can access it from REST API resources
-public interface IProxyArpService extends IOnosService{
+public interface IProxyArpService extends IFloodlightService {
 	/**
 	 * Returns the MAC address if there is a valid entry in the cache.
 	 * Otherwise returns null.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
index 3bf6c4e..415d697 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
@@ -5,6 +5,7 @@
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -17,6 +18,9 @@
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.packet.ARP;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPv4;
@@ -28,11 +32,9 @@
 import net.onrc.onos.ofcontroller.core.IDeviceStorage;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoSwitchService;
 import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
 import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
-import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
 import net.onrc.onos.ofcontroller.core.internal.TopoSwitchServiceImpl;
 import net.onrc.onos.ofcontroller.util.Dpid;
 import net.onrc.onos.ofcontroller.util.Port;
@@ -55,7 +57,7 @@
 import com.google.common.net.InetAddresses;
 
 public class ProxyArpManager implements IProxyArpService, IOFMessageListener,
-										IArpEventHandler {
+										IArpEventHandler, IFloodlightModule {
 	private final static Logger log = LoggerFactory.getLogger(ProxyArpManager.class);
 	
 	private final long ARP_TIMER_PERIOD = 60000; //ms (== 1 min) 
@@ -70,7 +72,6 @@
 	
 	private IDeviceStorage deviceStorage;
 	private volatile ITopoSwitchService topoSwitchService;
-	private ITopoLinkService topoLinkService;
 	
 	private short vlan;
 	private static final short NO_VLAN = 0;
@@ -126,22 +127,42 @@
 		}
 	}
 	
-	/*
-	public ProxyArpManager(IFloodlightProviderService floodlightProvider,
-				ITopologyService topology, IConfigInfoService configService,
-				IRestApiService restApi){
-
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+		Collection<Class<? extends IFloodlightService>> l 
+			= new ArrayList<Class<? extends IFloodlightService>>();
+		l.add(IProxyArpService.class);
+		return l;
 	}
-	*/
+
+	@Override
+	public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+		Map<Class<? extends IFloodlightService>, IFloodlightService> m 
+			= new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
+		m.put(IProxyArpService.class, this);
+		return m;
+	}
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+		Collection<Class<? extends IFloodlightService>> dependencies 
+			= new ArrayList<Class<? extends IFloodlightService>>();
+		dependencies.add(IFloodlightProviderService.class);
+		dependencies.add(ITopologyService.class);
+		dependencies.add(IRestApiService.class);
+		dependencies.add(IDatagridService.class);
+		dependencies.add(IConfigInfoService.class);
+		return dependencies;
+	}
 	
-	public void init(IFloodlightProviderService floodlightProvider,
-			ITopologyService topology, IDatagridService datagrid,
-			IConfigInfoService config, IRestApiService restApi){
-		this.floodlightProvider = floodlightProvider;
-		this.topology = topology;
-		this.datagrid = datagrid;
-		this.configService = config;
-		this.restApi = restApi;
+	@Override
+	public void init(FloodlightModuleContext context){
+		this.floodlightProvider = 
+				context.getServiceImpl(IFloodlightProviderService.class);
+		this.topology = context.getServiceImpl(ITopologyService.class);
+		this.datagrid = context.getServiceImpl(IDatagridService.class);
+		this.configService = context.getServiceImpl(IConfigInfoService.class);
+		this.restApi = context.getServiceImpl(IRestApiService.class);
 		
 		arpCache = new ArpCache();
 
@@ -149,10 +170,10 @@
 				HashMultimap.<InetAddress, ArpRequest>create());
 		
 		topoSwitchService = new TopoSwitchServiceImpl();
-		topoLinkService = new TopoLinkServiceImpl();
 	}
 	
-	public void startUp() {
+	@Override
+	public void startUp(FloodlightModuleContext context) {
 		this.vlan = configService.getVlan();
 		log.info("vlan set to {}", this.vlan);
 		
@@ -354,6 +375,7 @@
 		}*/
 	}
 	
+	@SuppressWarnings("unused")
 	private void handleArpReply(IOFSwitch sw, OFPacketIn pi, ARP arp){
 		if (log.isTraceEnabled()) {
 			log.trace("ARP reply recieved: {} => {}, on {}/{}", new Object[] { 
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 9585366..4269eac 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/ITopologyNetService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/ITopologyNetService.java
@@ -1,7 +1,5 @@
 package net.onrc.onos.ofcontroller.topology;
 
-import java.util.Map;
-
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.onrc.onos.ofcontroller.util.DataPath;
 import net.onrc.onos.ofcontroller.util.SwitchPort;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java b/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java
index dbf9ada..fc75591 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java
@@ -265,6 +265,9 @@
 
 	    break;
 	}
+	case ELEMENT_UNKNOWN:
+	    // TODO: Adding "assert(false);" here can be dangerous
+	    break;
 	}
 
 	return isModified;
@@ -315,6 +318,9 @@
 	    }
 	    break;
 	}
+	case ELEMENT_UNKNOWN:
+	    // TODO: Adding "assert(false);" here can be dangerous
+	    break;
 	}
 
 	return isModified;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyElement.java b/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyElement.java
index b01c7d3..0fefa3a 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyElement.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyElement.java
@@ -1,8 +1,5 @@
 package net.onrc.onos.ofcontroller.topology;
 
-import java.util.Map;
-import java.util.TreeMap;
-
 /**
  * Class for storing information about a Topology Element: Switch, Port or
  * Link.
@@ -165,6 +162,8 @@
 	    return "Link=" +
 		Long.toHexString(fromSwitchDpid) + "/" + fromSwitchPort + "/" +
 		Long.toHexString(toSwitchDpid) + "/" + toSwitchPort;
+	case ELEMENT_UNKNOWN:
+	    return "Element=UNKNOWN";
 	}
 
 	assert(false);
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 c0e04f2..02e0ffb 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java
@@ -225,8 +225,12 @@
 	    SwitchPort dest = flowPath.dataPath().dstPort();
 	    return ShortestPath.getTopologyShortestPath(topology, src, dest);
 	}
+
 	case FP_TYPE_EXPLICIT_PATH:
 	    return flowPath.dataPath();
+
+	case FP_TYPE_UNKNOWN:
+	    return null;
 	}
 
 	return 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 0d33b27..d8997dc 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
@@ -2,7 +2,6 @@
 
 import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
-import net.onrc.onos.ofcontroller.topology.TopologyManager;
 import net.onrc.onos.ofcontroller.util.DataPath;
 import net.onrc.onos.ofcontroller.util.Dpid;
 import net.onrc.onos.ofcontroller.util.Port;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
index 15a6233..c8b206f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntry.java
@@ -13,6 +13,8 @@
 public class FlowEntry {
     private FlowId flowId;			// FlowID of the Flow Entry
     private FlowEntryId flowEntryId;		// The Flow Entry ID
+    private int		idleTimeout;		// The Flow idle timeout
+    private int		hardTimeout;		// The Flow hard timeout
     private FlowEntryMatch flowEntryMatch;	// The Flow Entry Match
     private FlowEntryActions flowEntryActions;	// The Flow Entry Actions
     private Dpid dpid;				// The Switch DPID
@@ -136,10 +138,11 @@
      *
      * @return true if the Flow ID is valid, otherwise false.
      */
+    @JsonIgnore
     public boolean isValidFlowId() {
 	if (this.flowId == null)
 	    return false;
-	return (this.flowId.value() != 0);
+	return (this.flowId.isValid());
     }
 
     /**
@@ -165,10 +168,59 @@
      *
      * @return true if the Flow Entry ID is valid, otherwise false.
      */
+    @JsonIgnore
     public boolean isValidFlowEntryId() {
 	if (this.flowEntryId == null)
 	    return false;
-	return (this.flowEntryId.value() != 0);
+	return (this.flowEntryId.isValid());
+    }
+
+    /**
+     * Get the flow idle timeout in seconds.
+     *
+     * It should be an unsigned integer in the interval [0, 65535].
+     * If zero, the timeout is not set.
+     *
+     * @return the flow idle timeout.
+     */
+    @JsonProperty("idleTimeout")
+    public int idleTimeout() { return idleTimeout; }
+
+    /**
+     * Set the flow idle timeout in seconds.
+     *
+     * It should be an unsigned integer in the interval [0, 65535].
+     * If zero, the timeout is not set.
+     *
+     * @param idleTimeout the flow idle timeout to set.
+     */
+    @JsonProperty("idleTimeout")
+    public void setIdleTimeout(int idleTimeout) {
+	this.idleTimeout = 0xffff & idleTimeout;
+    }
+
+    /**
+     * Get the flow hard timeout in seconds.
+     *
+     * It should be an unsigned integer in the interval [0, 65535].
+     * If zero, the timeout is not set.
+     *
+     * @return the flow hard timeout.
+     */
+    @JsonProperty("hardTimeout")
+    public int hardTimeout() { return hardTimeout; }
+
+    /**
+     * Set the flow hard timeout in seconds.
+     *
+     * It should be an unsigned integer in the interval [0, 65535].
+     * If zero, the timeout is not set.
+     *
+     * @param hardTimeout the flow hard timeout to set.
+     */
+    @JsonProperty("hardTimeout")
+    public void setHardTimeout(int hardTimeout) {
+	this.hardTimeout = 0xffff & hardTimeout;
     }
 
     /**
@@ -341,7 +393,8 @@
      * Convert the flow entry to a string.
      *
      * The string has the following form:
-     *  [flowEntryId=XXX flowEntryMatch=XXX flowEntryActions=XXX dpid=XXX
+     *  [flowEntryId=XXX idleTimeout=XXX hardTimeout=XXX
+     *   flowEntryMatch=XXX flowEntryActions=XXX dpid=XXX
      *   inPort=XXX outPort=XXX flowEntryUserState=XXX flowEntrySwitchState=XXX
      *   flowEntryErrorState=XXX]
      * @return the flow entry as a string.
@@ -357,10 +410,12 @@
 	if ( flowId != null ) {
 		ret.append(" flowId=" + this.flowId.toString());
 	}
+	ret.append(" idleTimeout=" + this.idleTimeout);
+	ret.append(" hardTimeout=" + this.hardTimeout);
 	if ( flowEntryMatch != null ) {
 		ret.append(" flowEntryMatch=" + this.flowEntryMatch.toString());
 	}
-	ret.append( " flowEntryActions=" + this.flowEntryActions.toString() );
+	ret.append(" flowEntryActions=" + this.flowEntryActions.toString() );
 	if ( dpid != null ) {
 		ret.append(" dpid=" + this.dpid.toString());
 	}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
index a1163c8..e431f8a 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryAction.java
@@ -43,6 +43,13 @@
 	private ActionValues(short value) {
 	    this.value = value;
 	}
+
+	/**
+	 * Get the value.
+	 *
+	 * @return the value.
+	 */
+	public short getValue() { return value; }
     }
 
     /**
@@ -1564,6 +1571,9 @@
 	case ACTION_ENQUEUE:
 	    ret += " action=" + actionEnqueue.toString();
 	    break;
+	case ACTION_VENDOR:
+	    ret += " action=VENDOR";
+	    break;
 	}
 	ret += "]";
 
@@ -1656,6 +1666,9 @@
 	    case ACTION_ENQUEUE:
 		actionEnqueue = new ActionEnqueue(decode);
 		break;
+	    case ACTION_VENDOR:
+		// TODO: Handle it as appropriate
+		break;
 	    }
 	} catch (IllegalArgumentException e) {
 	    throw new IllegalArgumentException("Invalid action string");
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryActions.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryActions.java
index 53aab66..7d9688b 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryActions.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryActions.java
@@ -2,6 +2,7 @@
 
 import java.util.ArrayList;
 
+import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.annotate.JsonProperty;
 
 /**
@@ -79,6 +80,7 @@
      *
      * @return true if the set of actions is empty, otherwise false.
      */
+    @JsonIgnore
     public Boolean isEmpty() {
 	return actions.isEmpty();
     }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryId.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryId.java
index 29efe4c..f5728b0 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryId.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowEntryId.java
@@ -5,6 +5,7 @@
 import net.onrc.onos.ofcontroller.util.serializers.FlowEntryIdDeserializer;
 import net.onrc.onos.ofcontroller.util.serializers.FlowEntryIdSerializer;
 
+import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.map.annotate.JsonDeserialize;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
 
@@ -20,7 +21,7 @@
      * Default constructor.
      */
     public FlowEntryId() {
-	this.value = 0;
+	this.value = -1;
     }
 
     /**
@@ -66,7 +67,17 @@
     public void setValue(long value) {
 	this.value = value;
     }
-    
+
+    /**
+     * Test whether the Flow Entry ID is valid.
+     *
+     * @return true if the Flow Entry ID is valid, otherwise false.
+     */
+    @JsonIgnore
+    public boolean isValid() {
+	return (this.value() != -1);
+    }
+
     /**
      * Returns true of the object is another Flow Entry ID with 
      * the same value; otherwise, returns false.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowId.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowId.java
index de955ba..d90e96f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowId.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowId.java
@@ -5,6 +5,7 @@
 import net.onrc.onos.ofcontroller.util.serializers.FlowIdDeserializer;
 import net.onrc.onos.ofcontroller.util.serializers.FlowIdSerializer;
 
+import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.map.annotate.JsonDeserialize;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
 
@@ -20,7 +21,7 @@
      * Default constructor.
      */
     public FlowId() {
-	this.value = 0;
+	this.value = -1;
     }
 
     /**
@@ -68,6 +69,16 @@
     }
 
     /**
+     * Test whether the Flow ID is valid.
+     *
+     * @return true if the Flow ID is valid, otherwise false.
+     */
+    @JsonIgnore
+    public boolean isValid() {
+	return (this.value() != -1);
+    }
+
+    /**
      * Convert the Flow ID value to a hexadecimal string.
      *
      * @return the Flow ID value to a hexadecimal string.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
index a720fc6..7c87a10 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPath.java
@@ -6,6 +6,7 @@
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
 
+import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.annotate.JsonProperty;
 
 /**
@@ -17,7 +18,9 @@
     private FlowPathType flowPathType;	// The Flow Path type
     private FlowPathUserState flowPathUserState; // The Flow Path User state
     private FlowPathFlags flowPathFlags; // The Flow Path flags
-    private DataPath dataPath;		// The data path
+    private int		idleTimeout;	// The Flow idle timeout
+    private int		hardTimeout;	// The Flow hard timeout
+    private DataPath	dataPath;	// The data path
     private FlowEntryMatch flowEntryMatch; // Common Flow Entry Match for all
 					// Flow Entries
     private FlowEntryActions flowEntryActions; // The Flow Entry Actions for
@@ -44,6 +47,8 @@
 	this.setFlowPathType(FlowPathType.valueOf(flowObj.getFlowPathType()));
 	this.setFlowPathUserState(FlowPathUserState.valueOf(flowObj.getFlowPathUserState()));
 	this.setFlowPathFlags(new FlowPathFlags(flowObj.getFlowPathFlags()));
+	this.setIdleTimeout(flowObj.getIdleTimeout());
+	this.setHardTimeout(flowObj.getHardTimeout());
     	this.dataPath().srcPort().setDpid(new Dpid(flowObj.getSrcSwitch()));
     	this.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
     	this.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
@@ -210,6 +215,18 @@
     }
 
     /**
+     * Test whether the Flow ID is valid.
+     *
+     * @return true if the Flow ID is valid, otherwise false.
+     */
+    @JsonIgnore
+    public boolean isValidFlowId() {
+	if (this.flowId == null)
+	    return false;
+	return (this.flowId.isValid());
+    }
+
+    /**
      * Get the Caller ID of the flow path installer.
      *
      * @return the Caller ID of the flow path installer.
@@ -282,6 +299,54 @@
     }
 
     /**
+     * Get the flow idle timeout in seconds.
+     *
+     * It should be an unsigned integer in the interval [0, 65535].
+     * If zero, the timeout is not set.
+     *
+     * @return the flow idle timeout.
+     */
+    @JsonProperty("idleTimeout")
+    public int idleTimeout() { return idleTimeout; }
+
+    /**
+     * Set the flow idle timeout in seconds.
+     *
+     * It should be an unsigned integer in the interval [0, 65535].
+     * If zero, the timeout is not set.
+     *
+     * @param idleTimeout the flow idle timeout to set.
+     */
+    @JsonProperty("idleTimeout")
+    public void setIdleTimeout(int idleTimeout) {
+	this.idleTimeout = 0xffff & idleTimeout;
+    }
+
+    /**
+     * Get the flow hard timeout in seconds.
+     *
+     * It should be an unsigned integer in the interval [0, 65535].
+     * If zero, the timeout is not set.
+     *
+     * @return the flow hard timeout.
+     */
+    @JsonProperty("hardTimeout")
+    public int hardTimeout() { return hardTimeout; }
+
+    /**
+     * Set the flow hard timeout.
+     *
+     * It should be an unsigned integer in the interval [0, 65535].
+     * If zero, the timeout is not set.
+     *
+     * @param hardTimeout the flow hard timeout to set.
+     */
+    @JsonProperty("hardTimeout")
+    public void setHardTimeout(int hardTimeout) {
+	this.hardTimeout = 0xffff & hardTimeout;
+    }
+
+    /**
      * Get the flow path's data path.
      *
      * @return the flow path's data path.
@@ -353,8 +418,8 @@
      *
      * The string has the following form:
      *  [flowId=XXX installerId=XXX flowPathType = XXX flowPathUserState = XXX
-     *   flowPathFlags=XXX dataPath=XXX flowEntryMatch=XXX
-     *   flowEntryActions=XXX]
+     *   flowPathFlags=XXX idleTimeout=XXX hardTimeout=XXX dataPath=XXX
+     *   flowEntryMatch=XXX flowEntryActions=XXX]
      *
      * @return the flow path as a string.
      */
@@ -365,6 +430,8 @@
 	ret += " flowPathType=" + this.flowPathType;
 	ret += " flowPathUserState=" + this.flowPathUserState;
 	ret += " flowPathFlags=" + this.flowPathFlags.toString();
+	ret += " idleTimeout=" + this.idleTimeout;
+	ret += " hardTimeout=" + this.hardTimeout;
 	if (dataPath != null)
 	    ret += " dataPath=" + this.dataPath.toString();
 	if (flowEntryMatch != null)
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java
index 4bbd399..595eb5f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java
@@ -112,8 +112,6 @@
 
 	// Test all flags
 	if ((this.flags & DISCARD_FIRST_HOP_ENTRY) != 0) {
-	    if (flagsStr != null)
-		flagsStr += ",";
 	    flagsStr += "DISCARD_FIRST_HOP_ENTRY";
 	}
 	if ((this.flags & KEEP_ONLY_FIRST_HOP_ENTRY) != 0) {
@@ -121,6 +119,8 @@
 		flagsStr += ",";
 	    flagsStr += "KEEP_ONLY_FIRST_HOP_ENTRY";
 	}
+	if (flagsStr != null)
+	    ret += flagsStr;
 	ret += "]";
 
 	return ret;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/Pair.java b/src/main/java/net/onrc/onos/ofcontroller/util/Pair.java
new file mode 100644
index 0000000..2245758
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/Pair.java
@@ -0,0 +1,20 @@
+package net.onrc.onos.ofcontroller.util;
+
+/**
+ * A generic class representing a pair of two values.
+ */
+public class Pair<F, S> {
+    public F first;		// The first value in the pair
+    public S second;		// The second value in the pair
+
+    /**
+     * Constructor for a pair of two values.
+     *
+     * @param first the first value in the pair.
+     * @param second the second value in the pair.
+     */
+    public Pair(F first, S second) {
+	this.first = first;
+	this.second = second;
+    }
+}
diff --git a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
index 12fd261..7a53cff 100644
--- a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
+++ b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
@@ -4,10 +4,6 @@
 net.onrc.onos.ofcontroller.linkdiscovery.internal.LinkDiscoveryManager
 net.floodlightcontroller.topology.TopologyManager
 net.floodlightcontroller.forwarding.Forwarding
-net.floodlightcontroller.flowcache.FlowReconcileManager
-net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher
-net.floodlightcontroller.perfmon.PktInProcessingTime
-net.floodlightcontroller.perfmon.NullPktInProcessingTime
 net.floodlightcontroller.restserver.RestApiServer
 net.floodlightcontroller.counter.CounterStore
 net.floodlightcontroller.counter.NullCounterStore
@@ -24,4 +20,6 @@
 net.onrc.onos.ofcontroller.bgproute.BgpRoute
 net.onrc.onos.registry.controller.ZookeeperRegistry
 net.onrc.onos.registry.controller.StandaloneRegistry
-net.onrc.onos.ofcontroller.core.module.OnosModuleLoader
+net.onrc.onos.ofcontroller.forwarding.Forwarding
+net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager
+net.onrc.onos.ofcontroller.core.config.DefaultConfiguration
diff --git a/src/main/resources/hazelcast.xml b/src/main/resources/hazelcast.xml
new file mode 120000
index 0000000..f8f4972
--- /dev/null
+++ b/src/main/resources/hazelcast.xml
@@ -0,0 +1 @@
+/home/mininet/ONOS/conf/hazelcast.xml
\ No newline at end of file
diff --git a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
index 48dfcfb..b790a8e 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
@@ -57,8 +57,6 @@
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPacket;
 import net.floodlightcontroller.packet.IPv4;
-import net.floodlightcontroller.perfmon.IPktInProcessingTimeService;
-import net.floodlightcontroller.perfmon.PktInProcessingTime;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.restserver.RestApiServer;
 import net.floodlightcontroller.test.FloodlightTestCase;
@@ -66,6 +64,8 @@
 import net.onrc.onos.ofcontroller.core.IOFSwitchPortListener;
 import net.onrc.onos.ofcontroller.flowmanager.FlowManager;
 import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
+import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
+import net.onrc.onos.ofcontroller.linkdiscovery.internal.LinkDiscoveryManager;
 import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
 import net.onrc.onos.ofcontroller.topology.TopologyManager;
 import net.onrc.onos.registry.controller.IControllerRegistryService;
@@ -121,9 +121,7 @@
         CounterStore cs = new CounterStore();
         fmc.addService(ICounterStoreService.class, cs);
         
-        PktInProcessingTime ppt = new PktInProcessingTime();
-        fmc.addService(IPktInProcessingTimeService.class, ppt);
-        
+   
         tp = new MockThreadPoolService();
         fmc.addService(IThreadPoolService.class, tp);
         
@@ -133,18 +131,20 @@
         fmc.addService(ITopologyNetService.class, new TopologyManager() );
         StandaloneRegistry sr = new StandaloneRegistry();
         fmc.addService(IControllerRegistryService.class, sr );
+        LinkDiscoveryManager linkDiscovery = new LinkDiscoveryManager();
+        fmc.addService(ILinkDiscoveryService.class, linkDiscovery);
 
         
-        ppt.init(fmc);
         restApi.init(fmc);
         cm.init(fmc);
         tp.init(fmc);
         sr.init(fmc);
-        ppt.startUp(fmc);
+        linkDiscovery.init(fmc);
         restApi.startUp(fmc);
         cm.startUp(fmc);
         tp.startUp(fmc);
         sr.startUp(fmc);
+        linkDiscovery.startUp(fmc);
     }
 
     public Controller getController() {
@@ -399,7 +399,7 @@
         //Channel channel2 = createMock(Channel.class);
         //expect(newsw.getChannel()).andReturn(channel2);
         //expect(channel2.getRemoteAddress()).andReturn(null);
-        //expect(newsw.getPorts()).andReturn(new ArrayList<OFPhysicalPort>());
+        expect(newsw.getPorts()).andReturn(new ArrayList<OFPhysicalPort>());
         expect(newsw.getCapabilities()).andReturn(0).anyTimes();
         expect(newsw.getBuffers()).andReturn(0).anyTimes();
         expect(newsw.getTables()).andReturn((byte)0).anyTimes();
@@ -452,6 +452,10 @@
         }
         DummySwitchListener switchListener = new DummySwitchListener();
         IOFSwitch sw = createMock(IOFSwitch.class);
+        expect(sw.getId()).andReturn(1L).anyTimes();
+        expect(sw.getEnabledPorts()).andReturn(null);
+        expect(sw.getChannel()).andReturn(null).anyTimes();
+        replay(sw);
         ControllerRunThread t = new ControllerRunThread();
         t.start();
         
@@ -1137,6 +1141,7 @@
     @Test 
     public void testHandlePortStatus() throws Exception {
         IOFSwitch sw = createMock(IOFSwitch.class);
+        expect(sw.getId()).andReturn(1L).anyTimes();
         OFPhysicalPort port = new OFPhysicalPort();
         port.setName("myPortName1");
         port.setPortNumber((short)42);
diff --git a/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java b/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java
index d938abe..a4fba5d 100644
--- a/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java
+++ b/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java
@@ -9,7 +9,6 @@
 import net.floodlightcontroller.counter.NullCounterStore;
 import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier;
 import net.floodlightcontroller.devicemanager.test.MockDeviceManager;
-import net.floodlightcontroller.perfmon.NullPktInProcessingTime;
 import net.floodlightcontroller.topology.TopologyManager;
 
 import org.slf4j.Logger;
@@ -31,8 +30,7 @@
 			MockThreadPoolService.class;
 	public static final Class<? extends IFloodlightModule> DEFAULT_ENTITY_CLASSIFIER =
 			DefaultEntityClassifier.class;
-	public static final Class<? extends IFloodlightModule> DEFAULT_PERFMON =
-			NullPktInProcessingTime.class;
+	
 	
 	protected static final Collection<Class<? extends IFloodlightModule>> DEFAULT_MODULE_LIST;
 	
@@ -44,7 +42,7 @@
 		DEFAULT_MODULE_LIST.add(DEFAULT_COUNTER_STORE);
 		DEFAULT_MODULE_LIST.add(DEFAULT_THREADPOOL);
 		DEFAULT_MODULE_LIST.add(DEFAULT_ENTITY_CLASSIFIER);
-		DEFAULT_MODULE_LIST.add(DEFAULT_PERFMON);
+
 	}
 	
 	protected IFloodlightModuleContext fmc;
diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
index 3fccd0f..b37efe3 100644
--- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
+++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
@@ -57,8 +57,6 @@
 import net.floodlightcontroller.devicemanager.test.MockEntityClassifier;
 import net.floodlightcontroller.devicemanager.test.MockEntityClassifierMac;
 import net.floodlightcontroller.devicemanager.test.MockFlexEntityClassifier;
-import net.floodlightcontroller.flowcache.FlowReconcileManager;
-import net.floodlightcontroller.flowcache.IFlowReconcileService;
 import net.floodlightcontroller.packet.ARP;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPacket;
@@ -95,8 +93,6 @@
     private byte[] testARPReplyPacket_3_Serialized;
     MockFloodlightProvider mockFloodlightProvider;
     DeviceManagerImpl deviceManager;
-    //MemoryStorageSource storageSource;
-    FlowReconcileManager flowReconcileMgr;
 
     private IOFSwitch makeSwitchMock(long id) {
         IOFSwitch mockSwitch = createMock(IOFSwitch.class);
@@ -121,25 +117,25 @@
         fmc.addService(IThreadPoolService.class, tp);
         mockFloodlightProvider = getMockFloodlightProvider();
         deviceManager = new DeviceManagerImpl();
-        flowReconcileMgr = new FlowReconcileManager();
+       
         DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier();
         fmc.addService(IDeviceService.class, deviceManager);
         //storageSource = new MemoryStorageSource();
         //fmc.addService(IStorageSourceService.class, storageSource);
         fmc.addService(IFloodlightProviderService.class, mockFloodlightProvider);
         fmc.addService(IRestApiService.class, restApi);
-        fmc.addService(IFlowReconcileService.class, flowReconcileMgr);
+ 
         fmc.addService(IEntityClassifierService.class, entityClassifier);
         fmc.addService(ITopologyService.class, topology);
         tp.init(fmc);
         restApi.init(fmc);
         //storageSource.init(fmc);
         deviceManager.init(fmc);
-        flowReconcileMgr.init(fmc);
+
         entityClassifier.init(fmc);
         //storageSource.startUp(fmc);
         deviceManager.startUp(fmc);
-        flowReconcileMgr.startUp(fmc);
+
         tp.startUp(fmc);
         entityClassifier.startUp(fmc);
 
diff --git a/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java b/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java
deleted file mode 100644
index 0427828..0000000
--- a/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java
+++ /dev/null
@@ -1,500 +0,0 @@
-package net.floodlightcontroller.flowcache;
-
-import static org.easymock.EasyMock.*;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.ListIterator;
-
-import net.floodlightcontroller.core.IListener.Command;
-import net.floodlightcontroller.core.module.FloodlightModuleContext;
-import net.floodlightcontroller.core.test.MockFloodlightProvider;
-import net.floodlightcontroller.core.test.MockThreadPoolService;
-import net.floodlightcontroller.counter.ICounterStoreService;
-import net.floodlightcontroller.counter.SimpleCounter;
-import net.floodlightcontroller.counter.CounterValue.CounterType;
-import net.floodlightcontroller.flowcache.IFlowReconcileListener;
-import net.floodlightcontroller.flowcache.OFMatchReconcile;
-import net.floodlightcontroller.test.FloodlightTestCase;
-import net.floodlightcontroller.threadpool.IThreadPoolService;
-
-import org.easymock.EasyMock;
-import org.easymock.IAnswer;
-import org.junit.Before;
-import org.junit.Test;
-import org.openflow.protocol.OFStatisticsRequest;
-import org.openflow.protocol.OFType;
-
-public class FlowReconcileMgrTest extends FloodlightTestCase {
-
-    protected MockFloodlightProvider mockFloodlightProvider;
-    protected FlowReconcileManager flowReconcileMgr;
-    protected MockThreadPoolService threadPool;
-    protected ICounterStoreService counterStore;
-    protected FloodlightModuleContext fmc;
-    
-    OFStatisticsRequest ofStatsRequest;
-
-    protected int NUM_FLOWS_PER_THREAD = 100;
-    protected int NUM_THREADS = 100;
-    
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-
-        fmc = new FloodlightModuleContext();
-        flowReconcileMgr = new FlowReconcileManager();
-        threadPool = new MockThreadPoolService();
-        counterStore = createMock(ICounterStoreService.class);
-        
-        fmc.addService(ICounterStoreService.class, counterStore);
-        fmc.addService(IThreadPoolService.class, threadPool);
-        
-        threadPool.init(fmc);
-        flowReconcileMgr.init(fmc);
-
-        threadPool.startUp(fmc);
-        flowReconcileMgr.startUp(fmc);
-    }
-
-    /** Verify pipeline listener registration and ordering
-     * 
-     * @throws Exception
-     */
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testFlowReconcilePipeLine() throws Exception {
-        flowReconcileMgr.flowReconcileEnabled = true;
-    
-        IFlowReconcileListener r1 =
-            EasyMock.createNiceMock(IFlowReconcileListener.class);
-        IFlowReconcileListener r2 =
-            EasyMock.createNiceMock(IFlowReconcileListener.class);
-        IFlowReconcileListener r3 =
-            EasyMock.createNiceMock(IFlowReconcileListener.class);
-        
-        expect(r1.getName()).andReturn("r1").anyTimes();
-        expect(r2.getName()).andReturn("r2").anyTimes();
-        expect(r3.getName()).andReturn("r3").anyTimes();
-        
-        // Set the listeners' order: r1 -> r2 -> r3
-        expect(r1.isCallbackOrderingPrereq((OFType)anyObject(),
-            (String)anyObject())).andReturn(false).anyTimes();
-        expect(r1.isCallbackOrderingPostreq((OFType)anyObject(),
-            (String)anyObject())).andReturn(false).anyTimes();
-        expect(r2.isCallbackOrderingPrereq((OFType)anyObject(),
-            eq("r1"))).andReturn(true).anyTimes();
-        expect(r2.isCallbackOrderingPrereq((OFType)anyObject(),
-            eq("r3"))).andReturn(false).anyTimes();
-        expect(r2.isCallbackOrderingPostreq((OFType)anyObject(),
-            eq("r1"))).andReturn(false).anyTimes();
-        expect(r2.isCallbackOrderingPostreq((OFType)anyObject(),
-            eq("r3"))).andReturn(true).anyTimes();
-        expect(r3.isCallbackOrderingPrereq((OFType)anyObject(),
-            eq("r1"))).andReturn(false).anyTimes();
-        expect(r3.isCallbackOrderingPrereq((OFType)anyObject(),
-            eq("r2"))).andReturn(true).anyTimes();
-        expect(r3.isCallbackOrderingPostreq((OFType)anyObject(),
-            (String)anyObject())).andReturn(false).anyTimes();
-        
-        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())).
-                  andThrow(new RuntimeException("This is NOT an error! " +
-                            "We are testing exception catching."));
-        
-        SimpleCounter cnt = (SimpleCounter)SimpleCounter.createCounter(
-                            new Date(),
-                            CounterType.LONG);
-        cnt.increment();
-        expect(counterStore.getCounter(
-                flowReconcileMgr.controllerPktInCounterName))
-                .andReturn(cnt)
-                .anyTimes();
-        
-        replay(r1, r2, r3, counterStore);
-        flowReconcileMgr.clearFlowReconcileListeners();
-        flowReconcileMgr.addFlowReconcileListener(r1);
-        flowReconcileMgr.addFlowReconcileListener(r2);
-        flowReconcileMgr.addFlowReconcileListener(r3);
-        
-        int pre_flowReconcileThreadRunCount =
-                flowReconcileMgr.flowReconcileThreadRunCount;
-        Date startTime = new Date();
-        OFMatchReconcile ofmRcIn = new OFMatchReconcile();
-        try {
-            flowReconcileMgr.reconcileFlow(ofmRcIn);
-            flowReconcileMgr.doReconcile();
-        } catch (RuntimeException e) {
-            assertEquals(e.getMessage()
-                .startsWith("This is NOT an error!"), true);
-        }
-        
-        verify(r1, r2, r3);
-
-        // verify STOP works
-        reset(r1, r2, r3);
-        
-        // restart reconcileThread since it exited due to previous runtime
-        // exception.
-        flowReconcileMgr.startUp(fmc);
-        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
-        .andReturn(Command.STOP).times(1);
-        expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()));
-        expectLastCall().andAnswer(new IAnswer<Object>() {
-            public Object answer() {
-                fail("Unexpected call");
-                return Command.STOP;
-            }
-        }).anyTimes();
-        
-        pre_flowReconcileThreadRunCount =
-            flowReconcileMgr.flowReconcileThreadRunCount;
-        startTime = new Date();
-        replay(r1, r2, r3);
-        flowReconcileMgr.reconcileFlow(ofmRcIn);
-        while (flowReconcileMgr.flowReconcileThreadRunCount <=
-                pre_flowReconcileThreadRunCount) {
-            Thread.sleep(10);
-            Date currTime = new Date();
-            assertTrue((currTime.getTime() - startTime.getTime()) < 1000);
-        }
-        verify(r1, r2, r3);
-        
-        // verify CONTINUE works
-        reset(r1, r2, r3);
-        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
-        .andReturn(Command.CONTINUE).times(1);
-        expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
-        .andReturn(Command.STOP).times(1);
-        expect(r3.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()));
-        expectLastCall().andAnswer(new IAnswer<Object>() {
-            public Object answer() {
-                fail("Unexpected call");
-                return Command.STOP;
-            }
-        }).anyTimes();
-        
-        pre_flowReconcileThreadRunCount =
-            flowReconcileMgr.flowReconcileThreadRunCount;
-        startTime = new Date();
-        
-        replay(r1, r2, r3);
-        flowReconcileMgr.reconcileFlow(ofmRcIn);
-        while (flowReconcileMgr.flowReconcileThreadRunCount <=
-                pre_flowReconcileThreadRunCount) {
-            Thread.sleep(10);
-            Date currTime = new Date();
-            assertTrue((currTime.getTime() - startTime.getTime()) < 1000);
-        }
-        verify(r1, r2, r3);
-        
-        // verify CONTINUE works
-        reset(r1, r2, r3);
-        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
-        .andReturn(Command.CONTINUE).times(1);
-        expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
-        .andReturn(Command.CONTINUE).times(1);
-        expect(r3.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
-        .andReturn(Command.STOP).times(1);
-        
-        pre_flowReconcileThreadRunCount =
-            flowReconcileMgr.flowReconcileThreadRunCount;
-        startTime = new Date();
-        
-        replay(r1, r2, r3);
-        flowReconcileMgr.reconcileFlow(ofmRcIn);
-        while (flowReconcileMgr.flowReconcileThreadRunCount <=
-                pre_flowReconcileThreadRunCount) {
-            Thread.sleep(10);
-            Date currTime = new Date();
-            assertTrue((currTime.getTime() - startTime.getTime()) < 1000);
-        }
-        verify(r1, r2, r3);
-        
-        // Verify removeFlowReconcileListener
-        flowReconcileMgr.removeFlowReconcileListener(r1);
-        reset(r1, r2, r3);
-        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()));
-        expectLastCall().andAnswer(new IAnswer<Object>() {
-            public Object answer() {
-                fail("Unexpected call to a listener that is " +
-                        "removed from the chain.");
-                return Command.STOP;
-            }
-        }).anyTimes();
-        expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
-        .andReturn(Command.CONTINUE).times(1);
-        expect(r3.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
-        .andReturn(Command.STOP).times(1);
-        
-        pre_flowReconcileThreadRunCount =
-            flowReconcileMgr.flowReconcileThreadRunCount;
-        startTime = new Date();
-        replay(r1, r2, r3);
-        flowReconcileMgr.reconcileFlow(ofmRcIn);
-        while (flowReconcileMgr.flowReconcileThreadRunCount <=
-                pre_flowReconcileThreadRunCount) {
-            Thread.sleep(10);
-            Date currTime = new Date();
-            assertTrue((currTime.getTime() - startTime.getTime()) < 1000);
-        }
-        verify(r1, r2, r3);
-    }
-    
-    @Test
-    public void testGetPktInRate() {
-        internalTestGetPktInRate(CounterType.LONG);
-        internalTestGetPktInRate(CounterType.DOUBLE);
-    }
-    
-    protected void internalTestGetPktInRate(CounterType type) {
-        Date currentTime = new Date();
-        SimpleCounter newCnt = (SimpleCounter)SimpleCounter.createCounter(
-                                currentTime, type);
-        newCnt.increment(currentTime, 1);
-    
-        // Set the lastCounter time in the future of the current time
-        Date lastCounterTime = new Date(currentTime.getTime() + 1000);
-        flowReconcileMgr.lastPacketInCounter =
-                (SimpleCounter)SimpleCounter.createCounter(
-                    lastCounterTime, type);
-        flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, 1);
-    
-        assertEquals(FlowReconcileManager.MAX_SYSTEM_LOAD_PER_SECOND,
-                flowReconcileMgr.getPktInRate(newCnt, new Date()));
-    
-        // Verify the rate == 0 time difference is zero.
-        lastCounterTime = new Date(currentTime.getTime() - 1000);
-        flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, 1);
-        assertEquals(0, flowReconcileMgr.getPktInRate(newCnt, lastCounterTime));
-    
-        /** verify the computation is correct.
-         *  new = 2000, old = 1000, Tdiff = 1 second.
-         *  rate should be 1000/second
-         */
-        newCnt = (SimpleCounter)SimpleCounter.createCounter(
-                currentTime, type);
-        newCnt.increment(currentTime, 2000);
-    
-        lastCounterTime = new Date(currentTime.getTime() - 1000);
-        flowReconcileMgr.lastPacketInCounter =
-                (SimpleCounter)SimpleCounter.createCounter(
-                    lastCounterTime, type);
-        flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, 1000);
-        assertEquals(1000, flowReconcileMgr.getPktInRate(newCnt, currentTime));
-    
-        /** verify the computation is correct.
-         *  new = 2,000,000, old = 1,000,000, Tdiff = 2 second.
-         *  rate should be 1000/second
-         */
-        newCnt = (SimpleCounter)SimpleCounter.createCounter(
-                currentTime, type);
-        newCnt.increment(currentTime, 2000000);
-    
-        lastCounterTime = new Date(currentTime.getTime() - 2000);
-        flowReconcileMgr.lastPacketInCounter =
-                (SimpleCounter)SimpleCounter.createCounter(
-                    lastCounterTime, type);
-        flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime,
-                1000000);
-        assertEquals(500000, flowReconcileMgr.getPktInRate(newCnt,
-                    currentTime));
-    }
-    
-    @Test
-    public void testGetCurrentCapacity() throws Exception {
-        // Disable the reconcile thread.
-        flowReconcileMgr.flowReconcileEnabled = false;
-    
-        int minFlows = FlowReconcileManager.MIN_FLOW_RECONCILE_PER_SECOND *
-                FlowReconcileManager.FLOW_RECONCILE_DELAY_MILLISEC / 1000;
-    
-        /** Verify the initial state, when packetIn counter has not
-         *  been created.
-         */
-        expect(counterStore.getCounter(
-                flowReconcileMgr.controllerPktInCounterName))
-        .andReturn(null)
-        .times(1);
-    
-        replay(counterStore);
-        assertEquals(minFlows, flowReconcileMgr.getCurrentCapacity());
-        verify(counterStore);
-    
-        /** Verify the initial state, when lastPacketInCounter is null */
-        reset(counterStore);
-        Date currentTime = new Date();
-        SimpleCounter newCnt = (SimpleCounter)SimpleCounter.createCounter(
-                        currentTime, CounterType.LONG);
-    
-        expect(counterStore.getCounter(
-            flowReconcileMgr.controllerPktInCounterName))
-        .andReturn(newCnt)
-        .times(1);
-        long initPktInCount = 10000;
-        newCnt.increment(currentTime, initPktInCount);
-    
-        replay(counterStore);
-        assertEquals(minFlows, flowReconcileMgr.getCurrentCapacity());
-        verify(counterStore);
-    
-        /** Now the lastPacketInCounter has been set.
-         *  lastCounter = 100,000 and newCounter = 300,000, t = 1 second
-         *  packetInRate = 200,000/sec.
-         *  capacity should be 500k - 200k = 300k
-         */
-        reset(counterStore);
-        newCnt = (SimpleCounter)SimpleCounter.createCounter(
-                    currentTime, CounterType.LONG);
-        currentTime = new Date(currentTime.getTime() + 200);
-        long nextPktInCount = 30000;
-        newCnt.increment(currentTime, nextPktInCount);
-    
-        expect(counterStore.getCounter(
-                flowReconcileMgr.controllerPktInCounterName))
-        .andReturn(newCnt)
-        .times(1);
-    
-        replay(counterStore);
-        // Wait for 1 second so that enough elapsed time to compute capacity.
-        Thread.sleep(1000);
-        int capacity = flowReconcileMgr.getCurrentCapacity();
-        verify(counterStore);
-        long expectedCap = (FlowReconcileManager.MAX_SYSTEM_LOAD_PER_SECOND -
-                (nextPktInCount - initPktInCount)) *
-                FlowReconcileManager.FLOW_RECONCILE_DELAY_MILLISEC / 1000;
-        assertEquals(expectedCap, capacity);
-    }
-    
-    private class FlowReconcileWorker implements Runnable {
-    @Override
-        public void run() {
-            OFMatchReconcile ofmRc = new OFMatchReconcile();
-            // push large number of flows to be reconciled.
-            for (int i = 0; i < NUM_FLOWS_PER_THREAD; i++) {
-                flowReconcileMgr.reconcileFlow(ofmRc);
-            }
-        }
-    }
-    
-    /** Verify the flows are sent to the reconcile pipeline in order.
-     */
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testQueueFlowsOrder() {
-        flowReconcileMgr.flowReconcileEnabled = false;
-        
-        IFlowReconcileListener r1 =
-            EasyMock.createNiceMock(IFlowReconcileListener.class);
-        
-        expect(r1.getName()).andReturn("r1").anyTimes();
-        
-        // Set the listeners' order: r1 -> r2 -> r3
-        expect(r1.isCallbackOrderingPrereq((OFType)anyObject(),
-            (String)anyObject())).andReturn(false).anyTimes();
-        expect(r1.isCallbackOrderingPostreq((OFType)anyObject(),
-            (String)anyObject())).andReturn(false).anyTimes();
-        
-        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
-        .andAnswer(new IAnswer<Command>() {
-            @Override
-            public Command answer() throws Throwable {
-                ArrayList<OFMatchReconcile> ofmList =
-                    (ArrayList<OFMatchReconcile>)EasyMock.
-                        getCurrentArguments()[0];
-                ListIterator<OFMatchReconcile> lit = ofmList.listIterator();
-                int index = 0;
-                while (lit.hasNext()) {
-                    OFMatchReconcile ofm = lit.next();
-                    assertEquals(index++, ofm.cookie);
-                }
-                return Command.STOP;
-            }
-        }).times(1);
-        
-        SimpleCounter cnt = (SimpleCounter)SimpleCounter.createCounter(
-                            new Date(),
-                            CounterType.LONG);
-        cnt.increment();
-        expect(counterStore.getCounter(
-                flowReconcileMgr.controllerPktInCounterName))
-                .andReturn(cnt)
-                .anyTimes();
-        
-        replay(r1, counterStore);
-        flowReconcileMgr.clearFlowReconcileListeners();
-        flowReconcileMgr.addFlowReconcileListener(r1);
-        
-        OFMatchReconcile ofmRcIn = new OFMatchReconcile();
-        int index = 0;
-        for (index = 0; index < 10; index++) {
-            ofmRcIn.cookie = index;
-            flowReconcileMgr.reconcileFlow(ofmRcIn);
-        }
-        flowReconcileMgr.flowReconcileEnabled = true;
-        flowReconcileMgr.doReconcile();
-        
-        verify(r1);
-    }
-    
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testQueueFlowsByManyThreads() {
-        // Disable the reconcile thread so that the queue won't be emptied.
-        flowQueueTest(false);
-    
-        // Enable the reconcile thread. The queue should be empty.
-        Date currentTime = new Date();
-        SimpleCounter newCnt = (SimpleCounter)SimpleCounter.createCounter(
-                    currentTime, CounterType.LONG);
-    
-        expect(counterStore.getCounter(
-                    flowReconcileMgr.controllerPktInCounterName))
-        .andReturn(newCnt)
-        .anyTimes();
-        long initPktInCount = 10000;
-        newCnt.increment(currentTime, initPktInCount);
-    
-        IFlowReconcileListener r1 =
-                EasyMock.createNiceMock(IFlowReconcileListener.class);
-        
-        expect(r1.getName()).andReturn("r1").anyTimes();
-        
-        // Set the listeners' order: r1 -> r2 -> r3
-        expect(r1.isCallbackOrderingPrereq((OFType)anyObject(),
-                (String)anyObject())).andReturn(false).anyTimes();
-        expect(r1.isCallbackOrderingPostreq((OFType)anyObject(),
-                (String)anyObject())).andReturn(false).anyTimes();
-        
-        expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()))
-        .andReturn(Command.CONTINUE).anyTimes();
-        
-        flowReconcileMgr.clearFlowReconcileListeners();
-        replay(r1, counterStore);
-        flowQueueTest(true);
-        verify(r1, counterStore);
-    }
-    
-    protected void flowQueueTest(boolean enableReconcileThread) {
-        flowReconcileMgr.flowReconcileEnabled = enableReconcileThread;
-    
-        // Simulate flow
-        for (int i = 0; i < NUM_THREADS; i++) {
-            Runnable worker = this.new FlowReconcileWorker();
-            Thread t = new Thread(worker);
-            t.start();
-        }
-    
-        Date startTime = new Date();
-        int totalFlows = NUM_THREADS * NUM_FLOWS_PER_THREAD;
-        if (enableReconcileThread) {
-            totalFlows = 0;
-        }
-        while (flowReconcileMgr.flowQueue.size() != totalFlows) {
-            Date currTime = new Date();
-            assertTrue((currTime.getTime() - startTime.getTime()) < 2000);
-        }
-    
-        // Make sure all flows are in the queue.
-        assertEquals(totalFlows, flowReconcileMgr.flowQueue.size());
-    }
-}
diff --git a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
index 7a37589..3e262af 100644
--- a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
+++ b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
@@ -50,8 +50,6 @@
 import net.floodlightcontroller.topology.ITopologyListener;
 import net.floodlightcontroller.topology.ITopologyService;
 import net.floodlightcontroller.topology.NodePortTuple;
-import net.floodlightcontroller.flowcache.FlowReconcileManager;
-import net.floodlightcontroller.flowcache.IFlowReconcileService;
 import net.floodlightcontroller.forwarding.Forwarding;
 
 import org.easymock.Capture;
@@ -77,7 +75,6 @@
     protected MockDeviceManager deviceManager;
     protected IRoutingService routingEngine;
     protected Forwarding forwarding;
-    protected FlowReconcileManager flowReconcileMgr;
     protected ITopologyService topology;
     protected MockThreadPoolService threadPool;
     protected IOFSwitch sw1, sw2;
@@ -121,7 +118,6 @@
         forwarding = new Forwarding();
         threadPool = new MockThreadPoolService();
         deviceManager = new MockDeviceManager();
-        flowReconcileMgr = new FlowReconcileManager();
         routingEngine = createMock(IRoutingService.class);
         topology = createMock(ITopologyService.class);
         DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier();
@@ -135,7 +131,6 @@
         fmc.addService(IRoutingService.class, routingEngine);
         fmc.addService(ICounterStoreService.class, new CounterStore());
         fmc.addService(IDeviceService.class, deviceManager);
-        fmc.addService(IFlowReconcileService.class, flowReconcileMgr);
         fmc.addService(IEntityClassifierService.class, entityClassifier);
 
         topology.addListener(anyObject(ITopologyListener.class));
@@ -144,12 +139,10 @@
         threadPool.init(fmc);
         forwarding.init(fmc);
         deviceManager.init(fmc);
-        flowReconcileMgr.init(fmc);
         entityClassifier.init(fmc);
         threadPool.startUp(fmc);
         deviceManager.startUp(fmc);
         forwarding.startUp(fmc);
-        flowReconcileMgr.startUp(fmc);
         entityClassifier.startUp(fmc);
         verify(topology);
         
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowEntryTest.java b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowEntryTest.java
index 06d8522..f1c2c71 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowEntryTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowEntryTest.java
@@ -78,6 +78,38 @@
 		flowEntry.setFlowEntryId(flowEntryId);
 		assertEquals(flowEntry.getFlowEntryId(), flowEntryId);
 	}
+
+	/**
+	 * Desc:
+	 *  Test method for set and get Idle Timeout.
+	 * Condition:
+	 *  N/A
+	 * Expect:
+	 * 1. Should set Idle Timeout.
+	 * 2. Should get Idle Timeout.
+	 */
+	@Test
+	public void testSetGetIdleTimeout() {
+		Integer idleTimeout = 5;
+		flowEntry.setIdleTimeout(idleTimeout);
+		assertEquals(flowEntry.getIdleTimeout(), idleTimeout);
+	}
+
+	/**
+	 * Desc:
+	 *  Test method for set and get Hard Timeout.
+	 * Condition:
+	 *  N/A
+	 * Expect:
+	 * 1. Should set Hard Timeout.
+	 * 2. Should get Hard Timeout.
+	 */
+	@Test
+	public void testSetGetHardTimeout() {
+		Integer hardTimeout = 5;
+		flowEntry.setHardTimeout(hardTimeout);
+		assertEquals(flowEntry.getHardTimeout(), hardTimeout);
+	}
 	
 	/**
 	 * Desc:
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowPathTest.java b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowPathTest.java
index 9a1e34a..39e4955 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowPathTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjectsIFlowPathTest.java
@@ -158,6 +158,42 @@
 
 	/**
 	 * Desc:
+	 *  Test method for get and set Idle Timeout method.
+	 * Condition:
+	 *  N/A
+	 * Expect:
+	 * 1. Should set the Idle Timeout.
+	 * 2. Should get the Idle Timeout.
+	 */
+	@Test
+	public void testSetGetIdleTimeout() {
+		String flowId = "xx";
+		Integer idleTimeout = 5;
+		flowPath.setFlowId(flowId);
+		flowPath.setIdleTimeout(idleTimeout);
+		assertEquals(flowPath.getIdleTimeout(), idleTimeout);
+	}
+
+	/**
+	 * Desc:
+	 *  Test method for get and set Hard Timeout method.
+	 * Condition:
+	 *  N/A
+	 * Expect:
+	 * 1. Should set the Hard Timeout.
+	 * 2. Should get the Hard Timeout.
+	 */
+	@Test
+	public void testSetGetHardTimeout() {
+		String flowId = "xx";
+		Integer hardTimeout = 5;
+		flowPath.setFlowId(flowId);
+		flowPath.setHardTimeout(hardTimeout);
+		assertEquals(flowPath.getHardTimeout(), hardTimeout);
+	}
+
+	/**
+	 * Desc:
 	 *  Test method for get and set SourceSwitch method.
 	 * Condition:
 	 *  N/A
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImplTest.java b/src/test/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImplTest.java
index 4aea22a..8034d44 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImplTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImplTest.java
@@ -37,6 +37,7 @@
  */
 @RunWith(PowerMockRunner.class)
 @PrepareForTest({LinkStorageImpl.class, GraphDBConnection.class, GraphDBOperation.class})
+@SuppressWarnings("serial")
 public class LinkStorageImplTest {
 	protected final static Logger log = LoggerFactory.getLogger(LinkStorageImplTest.class);
 
@@ -519,7 +520,6 @@
 	 * Create a mock {@link GraphDBOperation} which hooks port-related methods.
 	 * @return EasyMock-wrapped GraphDBOperation object.
 	 */
-	@SuppressWarnings("serial")
 	private GraphDBOperation createMockGraphDBOperation() {
 		GraphDBOperation mockDBOpe = EasyMock.createNiceMock(GraphDBOperation.class);
 		
@@ -672,7 +672,6 @@
 	 * @param dpid DPID of the switch
 	 * @return List of port number
 	 */
-	@SuppressWarnings("serial")
 	private List<Short> getPorts(long dpid) {
 		List<Short> ports;
 		
@@ -699,7 +698,6 @@
 	 * Returns list of DPIDs in test topology.
 	 * @return List of DPIDs
 	 */
-	@SuppressWarnings("serial")
 	private List<Long> getDpids() {
 		List<Long> dpids = new ArrayList<Long>() {{
 			add(Long.decode("0x0000000000000a01"));
@@ -726,12 +724,6 @@
 		return new Link(Long.decode("0x0000000000000a01"), 3, Long.decode("0x0000000000000a03"), 1);
 	}
 	
-	// make NO sense while test-network data doesn't define physical network (i.e. any link is feasible)
-	@SuppressWarnings("unused")
-	private Link createInfeasibleLink() {
-		return new Link(Long.decode("0x0000000000000a01"), 1, Long.decode("0x0000000000000a03"), 3);
-	}
-
 	/**
 	 * Returns list of existing {@link Link} objects
 	 * @return ArrayList of new Link objects
diff --git a/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java b/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java
index d7724ae..8da306f 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/core/internal/TestableGraphDBOperation.java
@@ -326,6 +326,7 @@
 	 * tests in net.onrc.onos.ofcontroller.core.*
 	 */
 	public static class TestDeviceObject implements IDeviceObject {
+		@SuppressWarnings("unused")
 		private String state,type,mac,ipaddr;
 		private List<IPortObject> ports;
 		private List<ISwitchObject> switches;
@@ -456,6 +457,8 @@
 		private String flowPathType;
 		private String flowPathUserState;
 		private Long flowPathFlags;
+		private Integer idleTimeout;
+		private Integer hardTimeout;
 		private String dataPathSummary;
 		private Short srcPort,dstPort;
 		private String matchSrcMac,matchDstMac;
@@ -474,6 +477,8 @@
 		private String flowPathTypeToUpdate;
 		private String flowPathUserStateToUpdate;
 		private Long flowPathFlagsToUpdate;
+		private Integer idleTimeoutToUpdate;
+		private Integer hardTimeoutToUpdate;
 		private String dataPathSummaryToUpdate;
 		private Short srcPortToUpdate,dstPortToUpdate;
 		private String matchSrcMacToUpdate,matchDstMacToUpdate;
@@ -514,6 +519,8 @@
 			if(flowPathTypeToUpdate != null) { flowPathType = flowPathTypeToUpdate; }
 			if(flowPathUserStateToUpdate != null) { flowPathUserState = flowPathUserStateToUpdate; }
 			if(flowPathFlagsToUpdate != null) { flowPathFlags = flowPathFlagsToUpdate; }
+			if(idleTimeoutToUpdate != null) { idleTimeout = idleTimeoutToUpdate; }
+			if(hardTimeoutToUpdate != null) { hardTimeout = hardTimeoutToUpdate; }
 			if(srcSwToUpdate != null) { srcSw = srcSwToUpdate; }
 			if(dstSwToUpdate != null) { dstSw = dstSwToUpdate; }
 			if(dataPathSummaryToUpdate != null) { dataPathSummary = dataPathSummaryToUpdate; }
@@ -545,6 +552,8 @@
 			flowPathTypeToUpdate = null;
 			flowPathUserStateToUpdate = null;
 			flowPathFlagsToUpdate = null;
+			idleTimeoutToUpdate = null;
+			hardTimeoutToUpdate = null;
 			srcSwToUpdate = dstSwToUpdate = dataPathSummaryToUpdate = null;
 			srcPortToUpdate = dstPortToUpdate = null;
 			matchSrcMacToUpdate = matchDstMacToUpdate = null;
@@ -565,6 +574,8 @@
 		public void setFlowPathTypeForTest(String flowPathType) { this.flowPathType = flowPathType; }
 		public void setFlowPathUserStateForTest(String flowPathUserState) { this.flowPathUserState = flowPathUserState; }
 		public void setFlowPathFlagsForTest(Long flowPathFlags) { this.flowPathFlags = flowPathFlags; }
+		public void setIdleTimeoutForTest(Integer idleTimeout) { this.idleTimeout = idleTimeout; }
+		public void setHardTimeoutForTest(Integer hardTimeout) { this.hardTimeout = hardTimeout; }
 		public void setSrcSwForTest(String srcSw) { this.srcSw = srcSw; }
 		public void setDstSwForTest(String dstSw) { this.dstSw = dstSw; }
 		public void setDataPathSummaryForTest(String dataPathSummary) { this.dataPathSummary = dataPathSummary; }
@@ -634,6 +645,18 @@
 		public void setFlowPathFlags(Long flowPathFlags) { flowPathFlagsToUpdate = flowPathFlags; }
 
 		@Override
+		public Integer getIdleTimeout() { return idleTimeout; }
+
+		@Override
+		public void setIdleTimeout(Integer idleTimeout) { idleTimeoutToUpdate = idleTimeout; }
+
+		@Override
+		public Integer getHardTimeout() { return hardTimeout; }
+
+		@Override
+		public void setHardTimeout(Integer hardTimeout) { hardTimeoutToUpdate = hardTimeout; }
+
+		@Override
 		public String getSrcSwitch() { return srcSw; }
 
 		@Override
@@ -768,6 +791,8 @@
 
 	public static class TestFlowEntry implements IFlowEntry {
 		private String state,type,entryId,dpid,userState,switchState,errorStateType,errorStateCode;
+		private Integer idleTimeout;
+		private Integer hardTimeout;
 		private Short matchInPort;
 		private String matchSrcMac,matchDstMac;
 		private Short matchEtherFrameType;
@@ -785,6 +810,8 @@
 	
 		private String stateToUpdate,typeToUpdate,entryIdToUpdate,dpidToUpdate,
 			userStateToUpdate,switchStateToUpdate,errorStateTypeToUpdate,errorStateCodeToUpdate;
+		private Integer idleTimeoutToUpdate;
+		private Integer hardTimeoutToUpdate;
 		private Short matchInPortToUpdate;
 		private String matchSrcMacToUpdate,matchDstMacToUpdate;
 		private Short matchEtherFrameTypeToUpdate;
@@ -810,6 +837,8 @@
 			if(stateToUpdate != null) { state = stateToUpdate; }
 			if(typeToUpdate != null) { type = typeToUpdate; }
 			if(entryIdToUpdate != null) { entryId = entryIdToUpdate; }
+			if(idleTimeoutToUpdate != null) { idleTimeout = idleTimeoutToUpdate; }
+			if(hardTimeoutToUpdate != null) { hardTimeout = hardTimeoutToUpdate; }
 			if(dpidToUpdate != null) { dpid = dpidToUpdate; }
 			if(userStateToUpdate != null) { userState = userStateToUpdate; }
 			if(switchStateToUpdate != null) { switchState = switchStateToUpdate; }
@@ -844,6 +873,7 @@
 		
 		public void clearUncommitedData() {
 			stateToUpdate = typeToUpdate = entryIdToUpdate = dpidToUpdate = null;
+			idleTimeoutToUpdate = hardTimeoutToUpdate = null;
 			userStateToUpdate = switchStateToUpdate = errorStateTypeToUpdate = errorStateCodeToUpdate = null;
 			matchInPortToUpdate = null;
 			matchSrcMacToUpdate = matchDstMacToUpdate = null;
@@ -864,6 +894,8 @@
 		public void setStateForTest(String state) { this.state = state; }
 		public void setTypeForTest(String type) { this.type = type; }
 		public void setEntryIdForTest(String entryId) { this.entryId = entryId; }
+		public void setIdleTimeoutForTest(Integer idleTimeout) { this.idleTimeout = idleTimeout; }
+		public void setHardTimeoutForTest(Integer hardTimeout) { this.hardTimeout = hardTimeout; }
 		public void setDpidForTest(String dpid) { this.dpid = dpid; }
 		public void setUserStateForTest(String userState) { this.userState = userState; }
 		public void setSwitchStateForTest(String switchState) { this.switchState = switchState; }
@@ -911,6 +943,18 @@
 	
 		@Override
 		public void setFlowEntryId(String flowEntryId) { entryIdToUpdate = flowEntryId; }
+
+		@Override
+		public Integer getIdleTimeout() { return idleTimeout; }
+	
+		@Override
+		public void setIdleTimeout(Integer idleTimeout) { idleTimeoutToUpdate = idleTimeout; }
+
+		@Override
+		public Integer getHardTimeout() { return hardTimeout; }
+	
+		@Override
+		public void setHardTimeout(Integer hardTimeout) { hardTimeoutToUpdate = hardTimeout; }
 	
 		@Override
 		public String getSwitchDpid() { return dpid; }
diff --git a/src/test/java/net/onrc/onos/ofcontroller/devicemanager/internal/DeviceStorageImplTestBB.java b/src/test/java/net/onrc/onos/ofcontroller/devicemanager/internal/DeviceStorageImplTestBB.java
index c7c74a5..9964ec3 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/devicemanager/internal/DeviceStorageImplTestBB.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/devicemanager/internal/DeviceStorageImplTestBB.java
@@ -2,6 +2,8 @@
 
 import static org.junit.Assert.*;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.Arrays;
 import java.util.List;
 
@@ -485,9 +487,10 @@
 			IDeviceObject dev1 = ope.searchDevice(macAddr);
 			assertEquals(macAddr, dev1.getMACAddress());
 
+			int ip_int = getPackedIPv4Address(ip);
 			//XXX not updated to new interface
-		    //IDeviceObject dev = deviceImpl.getDeviceByIP(ip);
-			IDeviceObject dev = null;
+		    IDeviceObject dev = deviceImpl.getDeviceByIP(ip_int);
+			//IDeviceObject dev = null;
 			
 		    assertNotNull(dev);
 		    
@@ -656,4 +659,14 @@
 		}
 	}
 
+	int getPackedIPv4Address(String ip) throws UnknownHostException {
+		byte[] bytes = InetAddress.getByName(ip).getAddress();
+
+		int val = 0;
+		  for (int i = 0; i < bytes.length; i++) {
+		    val <<= 8;
+		    val |= bytes[i] & 0xff;
+		  }
+		  return val;
+	}
 }
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 7fd0f67..b43ce1c 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/flowmanager/FlowManagerTest.java
@@ -26,7 +26,6 @@
 import net.onrc.onos.ofcontroller.util.*;
 
 import org.easymock.EasyMock;
-import org.easymock.IAnswer;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
@@ -124,6 +123,7 @@
 		return flowPath;
 	}
 	
+	/*
 	private ArrayList<FlowPath> createTestFlowPaths() {
 		FlowPath flowPath1 = createTestFlowPath(1, "foo caller id", "FP_TYPE_SHORTEST_PATH", "FP_USER_ADD", 0, 1, 1, 2, 2); 
 		FlowPath flowPath2 = createTestFlowPath(2, "caller id", "FP_TYPE_SHORTEST_PATH", "FP_USER_ADD", 0, 1, 1, 2, 2); 
@@ -136,13 +136,14 @@
 		
 		return flowPaths;
 	}
+	*/
 	
 
 	// IFlowService methods
 
 
 	/**
-	 * Test method for {@link FlowManager#addFlow(FlowPath, FlowId, String)}.
+	 * Test method for {@link FlowManager#addFlow(FlowPath)}.
 	 * @throws Exception 
 	 */
 	@Test
@@ -163,15 +164,15 @@
 		replayAll();
 
 		fm.init(context);
-		Boolean result = fm.addFlow(flowPath, flowId);
+		FlowId result = fm.addFlow(flowPath);
 
 		// verify the test
 		verifyAll();
-		assertFalse(result);
+		assertNotNull(result);
 	}
 
 	/**
-	 * Test method for {@link FlowManager#addFlow(FlowPath, FlowId)}.
+	 * Test method for {@link FlowManager#addFlow(FlowPath)}.
 	 * @throws Exception 
 	 */
 	@Test
@@ -233,55 +234,54 @@
 		replayAll();
 		
 		fm.init(context);
-		Boolean result = fm.addFlow(flowPath, new FlowId(0x100));
+		FlowId result = fm.addFlow(flowPath);
 
 		// verify the test
 		verifyAll();
-		assertTrue(result);
+		assertNotNull(result);
 	}
-	
+
 	/**
-	 * Test method for {@link FlowManager#deleteAllFlows()}.
-	 * @throws Exception 
+	 * Test method for {@link FlowManager#deleteFlow(FlowId)}.
+	 * @throws Exception
 	 */
 	@Test
-	public final void testDeleteAllFlowsSuccessNormally() throws Exception {
+	public final void testDeleteFlowSuccessNormally() throws Exception {
 		// create mock objects
-		IFlowPath flowPath1 = createNiceMock(IFlowPath.class);
-		IFlowPath flowPath2 = createNiceMock(IFlowPath.class);
+		IFlowPath flowPath = createIFlowPathMock(123, "id", "FP_TYPE_SHORTEST_PATH", "FP_USER_ADD", 0, 1, 2, 3, 4);
+		IFlowEntry flowEntry1 = createMock(IFlowEntry.class);
+		IFlowEntry flowEntry2 = createMock(IFlowEntry.class);
+		IFlowEntry flowEntry3 = createMock(IFlowEntry.class);
 		
 		// instantiate required objects
-		ArrayList<IFlowPath> flowPaths = new ArrayList<IFlowPath>();
-		flowPaths.add(flowPath1);
-		flowPaths.add(flowPath2);
 		FlowManager fm = new FlowManager();
-		
+		FlowId flowId = new FlowId(123);
+		ArrayList<IFlowEntry> flowEntries = new ArrayList<IFlowEntry>();
+		flowEntries.add(flowEntry1);
+		flowEntries.add(flowEntry2);
+		flowEntries.add(flowEntry3);
+
 		// setup expectations
 		expectInitWithContext();
-		expect(op.getAllFlowPaths()).andReturn(flowPaths);
-
-		expect(flowPath1.getFlowId()).andReturn("1").anyTimes();
-		expect(op.searchFlowPath(cmpEq(new FlowId(1)))).andReturn(flowPath1);
-		expect(flowPath1.getFlowEntries()).andReturn(new ArrayList<IFlowEntry>());
-		op.removeFlowPath(flowPath1);
-		
-		expect(flowPath2.getFlowId()).andReturn("2").anyTimes();
-		expect(op.searchFlowPath(cmpEq(new FlowId(2)))).andReturn(flowPath2);
-		expect(flowPath2.getFlowEntries()).andReturn(new ArrayList<IFlowEntry>());
-		op.removeFlowPath(flowPath2);
-
+		expect(op.searchFlowPath(cmpEq(flowId))).andReturn(flowPath);
+		expect(flowPath.getFlowEntries()).andReturn(flowEntries);
+		flowPath.removeFlowEntry(flowEntry1);
+		flowPath.removeFlowEntry(flowEntry2);
+		flowPath.removeFlowEntry(flowEntry3);
+		op.removeFlowEntry(flowEntry1);
+		op.removeFlowEntry(flowEntry2);
+		op.removeFlowEntry(flowEntry3);
+		op.removeFlowPath(flowPath);
 		op.commit();
-		expectLastCall().anyTimes();
 
 		// start the test
 		replayAll();
 		
 		fm.init(context);
-		Boolean result = fm.deleteAllFlows();
+		fm.deleteFlow(flowId);
 
 		// verify the test
 		verifyAll();
-		assertTrue(result);
 	}
 	
 	/**
@@ -316,16 +316,16 @@
 	}
 	
 	/**
-	 * Test method for {@link FlowManager#clearAllFlows()}.
+	 * Test method for {@link FlowManager#deleteAllFlows()}.
 	 * @throws Exception 
 	 */
 	@Test
-	public final void testClearAllFlowsSuccessNormally() throws Exception {
+	public final void testDeleteAllFlowsSuccessNormally() throws Exception {
 		// create mock objects
 		IFlowPath flowPath1 = createNiceMock(IFlowPath.class);
 		IFlowPath flowPath2 = createNiceMock(IFlowPath.class);
 		IFlowPath flowPath3 = createNiceMock(IFlowPath.class);
-		FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, "clearFlow");
+		FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, "deleteFlow");
 		
 		// instantiate required objects
 		ArrayList<IFlowPath> flowPaths = new ArrayList<IFlowPath>();
@@ -340,16 +340,16 @@
 		expect(flowPath1.getFlowId()).andReturn(new FlowId(1).toString());
 		expect(flowPath2.getFlowId()).andReturn(null);
 		expect(flowPath3.getFlowId()).andReturn(new FlowId(3).toString());
-		expect(fm.clearFlow(cmpEq(new FlowId(1)))).andReturn(true);
-		expect(fm.clearFlow(cmpEq(new FlowId(3)))).andReturn(true);
+		expect(fm.deleteFlow(cmpEq(new FlowId(1)))).andReturn(true);
+		expect(fm.deleteFlow(cmpEq(new FlowId(3)))).andReturn(true);
 		
 		// start the test
 		replayAll();
 
 		fm.init(context);
-		Boolean result = fm.clearAllFlows();
+		Boolean result = fm.deleteAllFlows();
 		
-		//verify the test
+		// verify the test
 		verifyAll();
 		assertTrue(result);
 	}
@@ -389,110 +389,40 @@
 	}
 	
 	/**
-	 * Test method for {@link FlowManager#getAllFlows(CallerId, DataPathEndpoints)}.
-	 * @throws Exception 
-	 */ 
-	@Test
-	public final void testGetAllFlowsWithCallerIdAndDataPathEndpointsSuccessNormally() throws Exception {
-		final String getAllFlows = "getAllFlows";
-		// create mock objects
-		FlowManager fm = createPartialMock(FlowManager.class, getAllFlows,
-				new Class<?>[]{}, new Object[]{});
-
-		// instantiate required objects
-		DataPathEndpoints dataPathEndpoints = new DataPathEndpoints(
-				new SwitchPort(new Dpid(1), new Port((short)1)),
-				new SwitchPort(new Dpid(2), new Port((short)2)));
-
-		ArrayList<FlowPath> obtainedAllFlows = createTestFlowPaths();
-			
-		//setup expectations
-		expectInitWithContext();
-		expectPrivate(fm, getAllFlows).andReturn(obtainedAllFlows);
-		
-		//start the test
-		replayAll();
-		
-		fm.init(context);
-		ArrayList<FlowPath> flows = fm.getAllFlows(new CallerId("caller id"), dataPathEndpoints);
-
-		// verify the test
-		verifyAll();
-		assertEquals(1, flows.size());
-		assertEquals(obtainedAllFlows.get(1), flows.get(0));
-	}
-	
-	/**
-	 * Test method for {@link FlowManager#getAllFlows(DataPathEndpoints)}.
-	 * @throws Exception 
-	 */
-	@Test
-	public final void testGetAllFlowsWithDataPathEndpointsSuccessNormally() throws Exception {
-		final String getAllFlows = "getAllFlows";
-		// create mock objects
-		FlowManager fm = createPartialMock(FlowManager.class, getAllFlows,
-				new Class<?>[]{}, new Object[]{});
-
-		// instantiate required objects
-		DataPathEndpoints dataPathEndpoints = new DataPathEndpoints(
-				new SwitchPort(new Dpid(1), new Port((short)1)),
-				new SwitchPort(new Dpid(2), new Port((short)2)));
-
-		ArrayList<FlowPath> obtainedAllFlows = createTestFlowPaths();
-			
-		//setup expectations
-		expectInitWithContext();
-		expectPrivate(fm, getAllFlows).andReturn(obtainedAllFlows);
-		
-		//start the test
-		replayAll();
-		
-		fm.init(context);
-		ArrayList<FlowPath> flows = fm.getAllFlows(dataPathEndpoints);
-
-		// verify the test
-		verifyAll();
-		assertEquals(2, flows.size());
-		assertEquals(obtainedAllFlows.get(0), flows.get(0));
-		assertEquals(obtainedAllFlows.get(1), flows.get(1));
-		// TODO: ignore the order of flows in the list
-	}
-	
-	/**
 	 * Test method for {@link FlowManager#getAllFlowsSummary(FlowId, int)}.
 	 * @throws Exception 
 	 */
 	@Test
 	public final void testGetAllFlowsSummarySuccessNormally() throws Exception {
-		final String getAllFlowsWithoutFlowEntries = "getAllFlowsWithoutFlowEntries";
+		final String getAllFlowsWithDataPathSummary = "getAllFlowsWithDataPathSummary";
 		// create mock objects
-		FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, getAllFlowsWithoutFlowEntries);
-		IFlowPath flowPath1 = createIFlowPathMock(1, "", "FP_TYPE_SHORTEST_PATH", "FP_USER_ADD", 0, 1, 2, 3, 4);
-		IFlowPath flowPath2 = createIFlowPathMock(5, "", "FP_TYPE_SHORTEST_PATH", "FP_USER_ADD", 0, 2, 3, 4, 5);
-		IFlowPath flowPath3 = createIFlowPathMock(10, "", "FP_TYPE_SHORTEST_PATH", "FP_USER_ADD", 0, 3, 4, 5, 6);
+		FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, getAllFlowsWithDataPathSummary);
+		FlowPath flowPath1 = createTestFlowPath(1, "", "FP_TYPE_SHORTEST_PATH", "FP_USER_ADD", 0, 1, 2, 3, 4);
+		FlowPath flowPath2 = createTestFlowPath(5, "", "FP_TYPE_SHORTEST_PATH", "FP_USER_ADD", 0, 2, 3, 4, 5);
+		FlowPath flowPath3 = createTestFlowPath(10, "", "FP_TYPE_SHORTEST_PATH", "FP_USER_ADD", 0, 3, 4, 5, 6);
 
 		// instantiate required objects
-		ArrayList<IFlowPath> flows = new ArrayList<IFlowPath>();
+		ArrayList<FlowPath> flows = new ArrayList<FlowPath>();
 		flows.add(flowPath3);
 		flows.add(flowPath1);
 		flows.add(flowPath2);
 		
 		// setup expectations
 		expectInitWithContext();
-		expectPrivate(fm, getAllFlowsWithoutFlowEntries).andReturn(flows);
+		expectPrivate(fm, getAllFlowsWithDataPathSummary).andReturn(flows);
 
 		// start the test
 		replayAll();
 		
 		fm.init(context);
-		ArrayList<IFlowPath> returnedFlows = fm.getAllFlowsSummary(null, 0);
+		ArrayList<FlowPath> returnedFlows = fm.getAllFlowsSummary(null, 0);
 		
 		// verify the test
 		verifyAll();
 		assertEquals(3, returnedFlows.size());
-		assertEquals(1, new FlowId(returnedFlows.get(0).getFlowId()).value());
-		assertEquals(5, new FlowId(returnedFlows.get(1).getFlowId()).value());
-		assertEquals(10, new FlowId(returnedFlows.get(2).getFlowId()).value());
+		assertEquals(1, new FlowId(returnedFlows.get(0).flowId().value()).value());
+		assertEquals(5, new FlowId(returnedFlows.get(1).flowId().value()).value());
+		assertEquals(10, new FlowId(returnedFlows.get(2).flowId().value()).value());
 	}
 
 	/**
@@ -534,72 +464,6 @@
 		// TODO: more asserts
 		// TODO: ignore seq. of the list
 	}
-	
-	/**
-	 * Test method for {@link FlowManager#addAndMaintainShortestPathFlow(FlowPath)}.
-	 * @throws Exception 
-	 */
-	@Test
-	public final void testAddAndMaintainShortestPathFlowSuccessNormally() throws Exception {
-		final String addFlow = "addFlow";
-
-		// create mock objects
-		FlowManager fm = createPartialMockAndInvokeDefaultConstructor(FlowManager.class, addFlow);
-
-		// instantiate required objects
-		DataPath dataPath = new DataPath();
-		dataPath.setSrcPort(new SwitchPort(new Dpid(1), new Port((short)3)));
-		dataPath.setDstPort(new SwitchPort(new Dpid(2), new Port((short)4)));
-		FlowEntryMatch match = new FlowEntryMatch();
-		FlowPath paramFlow = new FlowPath();
-		paramFlow.setFlowId(new FlowId(100));
-		paramFlow.setInstallerId(new CallerId("installer id"));
-		paramFlow.setFlowPathType(FlowPathType.valueOf("FP_TYPE_SHORTEST_PATH"));
-		paramFlow.setFlowPathUserState(FlowPathUserState.valueOf("FP_USER_ADD"));
-		paramFlow.setFlowPathFlags(new FlowPathFlags(0));
-		paramFlow.setDataPath(dataPath);
-		paramFlow.setFlowEntryMatch(match);
-		
-		// setup expectations
-		expectInitWithContext();
-		expectPrivate(fm, addFlow,
-				EasyMock.anyObject(FlowPath.class),
-				EasyMock.anyObject(FlowId.class),
-				EasyMock.anyObject(String.class)
-				).andAnswer(new IAnswer<Object>() {
-					public Object answer() throws Exception {
-						FlowPath flowPath = (FlowPath)EasyMock.getCurrentArguments()[0];
-						assertEquals(flowPath.flowId().value(), 100);
-						assertEquals(flowPath.installerId().toString(), "installer id");
-						assertEquals(flowPath.flowPathType().toString(), "PF_TYPE_SHORTEST_PATH");
-						assertEquals(flowPath.flowPathUserState().toString(), "PF_USER_STATE");
-						assertEquals(flowPath.flowPathFlags().flags(), 0);
-						assertEquals(flowPath.dataPath().srcPort().toString(),
-								new SwitchPort(new Dpid(1), new Port((short)3)).toString());
-
-						String dataPathSummary = (String)EasyMock.getCurrentArguments()[2];
-						assertEquals(dataPathSummary, "X");
-						
-						return true;
-					}
-				});
-		
-		// start the test
-		replayAll();
-
-		fm.init(context);
-		FlowPath resultFlow = fm.addAndMaintainShortestPathFlow(paramFlow);
-				
-		// verify the test
-		verifyAll();
-		assertEquals(paramFlow.flowId().value(), resultFlow.flowId().value());
-		assertEquals(paramFlow.installerId().toString(), resultFlow.installerId().toString());
-		assertEquals(paramFlow.flowPathType().toString(), resultFlow.flowPathType().toString());
-		assertEquals(paramFlow.flowPathUserState().toString(), resultFlow.flowPathUserState().toString());
-		assertEquals(paramFlow.flowPathFlags().flags(), resultFlow.flowPathFlags().flags());
-		assertEquals(paramFlow.dataPath().toString(), resultFlow.dataPath().toString());
-		assertEquals(paramFlow.flowEntryMatch().toString(), resultFlow.flowEntryMatch().toString());
-	}
 		
 	// INetMapStorage methods
 	
@@ -786,85 +650,6 @@
 	
 	// other methods
 	
-	
-	/**
-	 * Test method for {@link FlowManager#clearFlow(FlowId)}.
-	 * @throws Exception
-	 */
-	@Test
-	public final void testClearFlowSuccessNormally() throws Exception {
-		// create mock objects
-		IFlowPath flowPath = createIFlowPathMock(123, "id", "FP_TYPE_SHORTEST_PATH", "FP_USER_ADD", 0, 1, 2, 3, 4);
-		IFlowEntry flowEntry1 = createMock(IFlowEntry.class);
-		IFlowEntry flowEntry2 = createMock(IFlowEntry.class);
-		IFlowEntry flowEntry3 = createMock(IFlowEntry.class);
-		
-		// instantiate required objects
-		FlowManager fm = new FlowManager();
-		FlowId flowId = new FlowId(123);
-		ArrayList<IFlowEntry> flowEntries = new ArrayList<IFlowEntry>();
-		flowEntries.add(flowEntry1);
-		flowEntries.add(flowEntry2);
-		flowEntries.add(flowEntry3);
-
-		// setup expectations
-		expectInitWithContext();
-		expect(op.searchFlowPath(cmpEq(flowId))).andReturn(flowPath);
-		expect(flowPath.getFlowEntries()).andReturn(flowEntries);
-		flowPath.removeFlowEntry(flowEntry1);
-		flowPath.removeFlowEntry(flowEntry2);
-		flowPath.removeFlowEntry(flowEntry3);
-		op.removeFlowEntry(flowEntry1);
-		op.removeFlowEntry(flowEntry2);
-		op.removeFlowEntry(flowEntry3);
-		op.removeFlowPath(flowPath);
-		op.commit();
-
-		// start the test
-		replayAll();
-		
-		fm.init(context);
-		fm.clearFlow(flowId);
-
-		// verify the test
-		verifyAll();
-	}
-	
-	/**
-	 * Test method for {@link FlowManager#getAllFlowsWithoutFlowEntries()}.
-	 * @throws Exception 
-	 */
-	@Test
-	public final void testGetAllFlowsWithoutFlowEntriesSuccessNormally() throws Exception {
-		// create mock objects
-		IFlowPath iFlowPath1 = createIFlowPathMock(1, "caller id", "FP_TYPE_SHORTEST_PATH", "FP_USER_ADD", 0, 1, 1, 2, 2); 
-		IFlowPath iFlowPath2 = createIFlowPathMock(2, "caller id", "FP_TYPE_SHORTEST_PATH", "FP_USER_ADD", 0, 2, 5, 3, 5);
-		
-		// instantiate required objects
-		ArrayList<IFlowPath> flowPaths = new ArrayList<IFlowPath>();
-		flowPaths.add(iFlowPath1);
-		flowPaths.add(iFlowPath2);
-		FlowManager fm = new FlowManager();
-		
-		// setup expectations
-		expectInitWithContext();
-		op.commit();
-		expect(op.getAllFlowPaths()).andReturn(flowPaths);
-		
-		// start the test
-		replayAll();
-		
-		fm.init(context);
-		ArrayList<IFlowPath> result = fm.getAllFlowsWithoutFlowEntries();
-		
-		// verify the test
-		verifyAll();
-		assertEquals(iFlowPath1, result.get(0));
-		assertEquals(iFlowPath2, result.get(1));
-		
-		// TODO: does this method just return the replica of the flow paths?
-	}
-	
 	/**
 	 * Test method for {@link FlowManager#reconcileFlow(IFlowPath, DataPath)}.
 	 * @throws Exception
@@ -926,7 +711,7 @@
 		fm.init(context);
 		// Use reflection to test the private method
 		// Boolean result = fm.reconcileFlow(iFlowPath1, dataPath);
-		Class fmClass = FlowManager.class;
+		Class<?> fmClass = FlowManager.class;
 		Method method = fmClass.getDeclaredMethod(
 			"reconcileFlow",
 			new Class[] { IFlowPath.class, DataPath.class });
@@ -988,7 +773,7 @@
 		fm.init(context);
 		// Use reflection to test the private method
 		// Boolean result = fm.installFlowEntry(iofSwitch, iFlowPath, iFlowEntry);
-		Class fmClass = FlowManager.class;
+		Class<?> fmClass = FlowManager.class;
 		Method method = fmClass.getDeclaredMethod(
 			"installFlowEntry",
 			new Class[] { IOFSwitch.class, IFlowPath.class, IFlowEntry.class });
diff --git a/src/test/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusherTest.java b/src/test/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusherTest.java
new file mode 100644
index 0000000..4779b75
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusherTest.java
@@ -0,0 +1,544 @@
+package net.onrc.onos.ofcontroller.flowprogrammer;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.floodlightcontroller.util.OFMessageDamper;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
+import net.onrc.onos.ofcontroller.util.Dpid;
+import net.onrc.onos.ofcontroller.util.FlowEntry;
+import net.onrc.onos.ofcontroller.util.FlowEntryActions;
+import net.onrc.onos.ofcontroller.util.FlowEntryErrorState;
+import net.onrc.onos.ofcontroller.util.FlowEntryId;
+import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
+import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
+import net.onrc.onos.ofcontroller.util.FlowId;
+import net.onrc.onos.ofcontroller.util.Port;
+
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.junit.Test;
+import org.openflow.protocol.OFBarrierRequest;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.factory.BasicFactory;
+
+public class FlowPusherTest {
+	private FlowPusher pusher;
+	private FloodlightContext context;
+	private FloodlightModuleContext modContext;
+	private BasicFactory factory;
+	private OFMessageDamper damper;
+	private IFloodlightProviderService flProviderService;
+	private IThreadPoolService threadPoolService;
+	private IFlowService flowService;
+
+	/**
+	 * Test single OFMessage is correctly sent to single switch via MessageDamper.
+	 */
+	@Test
+	public void testAddMessage() {
+		beginInitMock();
+		
+		OFMessage msg = EasyMock.createMock(OFMessage.class);
+		EasyMock.expect(msg.getXid()).andReturn(1).anyTimes();
+		EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
+		EasyMock.replay(msg);
+		
+		IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+		EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
+		sw.flush();
+		EasyMock.expectLastCall().once();
+		EasyMock.replay(sw);
+		
+		try {
+			EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
+				.andReturn(true).once();
+		} catch (IOException e1) {
+			fail("Failed in OFMessageDamper#write()");
+		}
+		
+		endInitMock();
+		initPusher(1);
+		
+		boolean add_result = pusher.add(sw, msg);
+		assertTrue(add_result);
+		
+		try {
+			// wait until message is processed.
+			Thread.sleep(1000);
+		} catch (InterruptedException e) {
+			fail("Failed in Thread.sleep()");
+		}
+		
+		EasyMock.verify(msg);
+		EasyMock.verify(sw);
+		
+		pusher.stop();
+	}
+	
+	/**
+	 * Test bunch of OFMessages are correctly sent to single switch via MessageDamper.
+	 */
+	@Test
+	public void testMassiveAddMessage() {
+		final int NUM_MSG = 10000;
+		
+		beginInitMock();
+
+		IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+		EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
+		sw.flush();
+		EasyMock.expectLastCall().atLeastOnce();
+		EasyMock.replay(sw);
+		
+		List<OFMessage> messages = new ArrayList<OFMessage>();
+		
+		for (int i = 0; i < NUM_MSG; ++i) {
+			OFMessage msg = EasyMock.createMock(OFMessage.class);
+			EasyMock.expect(msg.getXid()).andReturn(i).anyTimes();
+			EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
+			EasyMock.replay(msg);
+			messages.add(msg);
+			
+			try {
+				EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
+					.andReturn(true).once();
+			} catch (IOException e1) {
+				fail("Failed in OFMessageDamper#write()");
+			}
+		}
+		
+		endInitMock();
+		initPusher(1);
+		
+		for (OFMessage msg : messages) {
+			boolean add_result = pusher.add(sw, msg);
+			assertTrue(add_result);
+		}
+		
+		try {
+			// wait until message is processed.
+			Thread.sleep(1000);
+		} catch (InterruptedException e) {
+			fail("Failed in Thread.sleep()");
+		}
+		
+		for (OFMessage msg : messages) {
+			EasyMock.verify(msg);
+		}
+		EasyMock.verify(sw);
+		
+		pusher.stop();
+	}
+	
+	/**
+	 * Test bunch of OFMessages are correctly sent to multiple switches with single threads.
+	 */
+	@Test
+	public void testMultiSwitchAddMessage() {
+		final int NUM_SWITCH = 10;
+		final int NUM_MSG = 100;	// messages per thread
+		
+		beginInitMock();
+
+		Map<IOFSwitch, List<OFMessage>> sw_map = new HashMap<IOFSwitch, List<OFMessage>>();
+		for (int i = 0; i < NUM_SWITCH; ++i) {
+			IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+			EasyMock.expect(sw.getId()).andReturn((long)i).anyTimes();
+			sw.flush();
+			EasyMock.expectLastCall().atLeastOnce();
+			EasyMock.replay(sw);
+			
+			List<OFMessage> messages = new ArrayList<OFMessage>();
+			
+			for (int j = 0; j < NUM_MSG; ++j) {
+				OFMessage msg = EasyMock.createMock(OFMessage.class);
+				EasyMock.expect(msg.getXid()).andReturn(j).anyTimes();
+				EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
+				EasyMock.replay(msg);
+				messages.add(msg);
+				
+				try {
+					EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
+						.andReturn(true).once();
+				} catch (IOException e1) {
+					fail("Failed in OFMessageDamper#write()");
+				}
+			}
+			sw_map.put(sw, messages);
+		}
+		
+		endInitMock();
+		initPusher(1);
+		
+		for (IOFSwitch sw : sw_map.keySet()) {
+			for (OFMessage msg : sw_map.get(sw)) {
+				boolean add_result = pusher.add(sw, msg);
+				assertTrue(add_result);
+			}
+		}
+		
+		try {
+			// wait until message is processed.
+			Thread.sleep(1000);
+		} catch (InterruptedException e) {
+			fail("Failed in Thread.sleep()");
+		}
+		
+		for (IOFSwitch sw : sw_map.keySet()) {
+			for (OFMessage msg : sw_map.get(sw)) {
+				EasyMock.verify(msg);
+			}
+			
+			EasyMock.verify(sw);
+		}
+		
+		pusher.stop();
+	}
+	
+	/**
+	 * Test bunch of OFMessages are correctly sent to multiple switches using multiple threads.
+	 */
+	@Test
+	public void testMultiThreadedAddMessage() {
+		final int NUM_THREAD = 10;
+		final int NUM_MSG = 100;	// messages per thread
+		
+		beginInitMock();
+
+		Map<IOFSwitch, List<OFMessage>> sw_map = new HashMap<IOFSwitch, List<OFMessage>>();
+		for (int i = 0; i < NUM_THREAD; ++i) {
+			IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+			EasyMock.expect(sw.getId()).andReturn((long)i).anyTimes();
+			sw.flush();
+			EasyMock.expectLastCall().atLeastOnce();
+			EasyMock.replay(sw);
+			
+			List<OFMessage> messages = new ArrayList<OFMessage>();
+			
+			for (int j = 0; j < NUM_MSG; ++j) {
+				OFMessage msg = EasyMock.createMock(OFMessage.class);
+				EasyMock.expect(msg.getXid()).andReturn(j).anyTimes();
+				EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
+				EasyMock.replay(msg);
+				messages.add(msg);
+				
+				try {
+					EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
+						.andReturn(true).once();
+				} catch (IOException e1) {
+					fail("Failed in OFMessageDamper#write()");
+				}
+			}
+			sw_map.put(sw, messages);
+		}
+		
+		endInitMock();
+		initPusher(NUM_THREAD);
+		
+		for (IOFSwitch sw : sw_map.keySet()) {
+			for (OFMessage msg : sw_map.get(sw)) {
+				boolean add_result = pusher.add(sw, msg);
+				assertTrue(add_result);
+			}
+		}
+		
+		try {
+			// wait until message is processed.
+			Thread.sleep(1000);
+		} catch (InterruptedException e) {
+			fail("Failed in Thread.sleep()");
+		}
+		
+		for (IOFSwitch sw : sw_map.keySet()) {
+			for (OFMessage msg : sw_map.get(sw)) {
+				EasyMock.verify(msg);
+			}
+			
+			EasyMock.verify(sw);
+		}
+		
+		pusher.stop();
+	}
+	
+	private long barrierTime = 0;
+	/**
+	 * Test rate limitation of messages works correctly.
+	 */
+	@Test
+	public void testRateLimitedAddMessage() {
+		final long LIMIT_RATE = 100; // [bytes/ms]
+		final int NUM_MSG = 1000;
+		
+		// Accuracy of FlowPusher's rate calculation can't be measured by unit test
+		// because switch doesn't return BARRIER_REPLY.
+		// In unit test we use approximate way to measure rate. This value is 
+		// acceptable margin of measured rate.
+		final double ACCEPTABLE_RATE = LIMIT_RATE * 1.2;
+		
+		beginInitMock();
+
+		IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+		EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
+		sw.flush();
+		EasyMock.expectLastCall().atLeastOnce();
+		prepareBarrier(sw);
+		EasyMock.replay(sw);
+		
+		List<OFMessage> messages = new ArrayList<OFMessage>();
+		
+		for (int i = 0; i < NUM_MSG; ++i) {
+			OFMessage msg = EasyMock.createMock(OFMessage.class);
+			EasyMock.expect(msg.getXid()).andReturn(1).anyTimes();
+			EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
+			EasyMock.expect(msg.getLengthU()).andReturn(100).anyTimes();
+			EasyMock.replay(msg);
+			messages.add(msg);
+			
+			try {
+				EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
+					.andReturn(true).once();
+			} catch (IOException e) {
+				fail("Failed in OFMessageDamper#write()");
+			}
+		}
+		
+		try {
+			EasyMock.expect(damper.write(EasyMock.eq(sw), (OFMessage)EasyMock.anyObject(), EasyMock.eq(context)))
+				.andAnswer(new IAnswer<Boolean>() {
+					@Override
+					public Boolean answer() throws Throwable {
+						OFMessage msg = (OFMessage)EasyMock.getCurrentArguments()[1];
+						if (msg.getType() == OFType.BARRIER_REQUEST) {
+							barrierTime = System.currentTimeMillis();
+						}
+						return true;
+					}
+				}).once();
+		} catch (IOException e1) {
+			fail("Failed in OFMessageDamper#write()");
+		}
+
+		endInitMock();
+		initPusher(1);
+		
+		pusher.createQueue(sw);
+		pusher.setRate(sw, LIMIT_RATE);
+		
+		long beginTime = System.currentTimeMillis();
+		for (OFMessage msg : messages) {
+			boolean add_result = pusher.add(sw, msg);
+			assertTrue(add_result);
+		}
+		
+		pusher.barrierAsync(sw);
+
+		try {
+			do {
+				Thread.sleep(1000);
+			} while (barrierTime == 0);
+		} catch (InterruptedException e) {
+			fail("Failed to sleep");
+		}
+		
+		double measured_rate = NUM_MSG * 100 /  (barrierTime - beginTime);
+		assertTrue(measured_rate < ACCEPTABLE_RATE);
+		
+		for (OFMessage msg : messages) {
+			EasyMock.verify(msg);
+		}
+		EasyMock.verify(sw);
+		
+		pusher.stop();
+	}
+
+	/**
+	 * Test barrier message is correctly sent to a switch.
+	 */
+	@Test
+	public void testBarrierMessage() {
+		beginInitMock();
+		
+		IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+		EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
+		sw.flush();
+		EasyMock.expectLastCall().atLeastOnce();
+		prepareBarrier(sw);
+		EasyMock.replay(sw);
+
+		try {
+			EasyMock.expect(damper.write(EasyMock.eq(sw), (OFMessage)EasyMock.anyObject(), EasyMock.eq(context)))
+				.andReturn(true).once();
+		} catch (IOException e1) {
+			fail("Failed in OFMessageDamper#write()");
+		}
+
+		endInitMock();
+		initPusher(1);
+
+		OFBarrierReplyFuture future = pusher.barrierAsync(sw);
+		
+		assertNotNull(future);
+		pusher.stop();
+	}
+	
+	/**
+	 * Test FlowObject is correctly converted to message and is sent to a switch.
+	 */
+	@SuppressWarnings("unchecked")
+	@Test
+	public void testAddFlow() {
+		// Code below are copied from FlowManagerTest
+		
+		// instantiate required objects
+		FlowEntry flowEntry1 = new FlowEntry();
+		flowEntry1.setDpid(new Dpid(1));
+		flowEntry1.setFlowId(new FlowId(1));
+		flowEntry1.setInPort(new Port((short) 1));
+		flowEntry1.setOutPort(new Port((short) 11));
+		flowEntry1.setFlowEntryId(new FlowEntryId(1));
+		flowEntry1.setFlowEntryMatch(new FlowEntryMatch());
+		flowEntry1.setFlowEntryActions(new FlowEntryActions());
+		flowEntry1.setFlowEntryErrorState(new FlowEntryErrorState());
+		flowEntry1.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
+		
+		beginInitMock();
+		
+		OFFlowMod msg = EasyMock.createMock(OFFlowMod.class);
+		EasyMock.expect(msg.setIdleTimeout(EasyMock.anyShort())).andReturn(msg);
+		EasyMock.expect(msg.setHardTimeout(EasyMock.anyShort())).andReturn(msg);
+		EasyMock.expect(msg.setPriority(EasyMock.anyShort())).andReturn(msg);
+		EasyMock.expect(msg.setBufferId(EasyMock.anyInt())).andReturn(msg);
+		EasyMock.expect(msg.setCookie(EasyMock.anyLong())).andReturn(msg);
+		EasyMock.expect(msg.setCommand(EasyMock.anyShort())).andReturn(msg);
+		EasyMock.expect(msg.setMatch(EasyMock.anyObject(OFMatch.class))).andReturn(msg);
+		EasyMock.expect(msg.setActions((List<OFAction>)EasyMock.anyObject())).andReturn(msg);
+		EasyMock.expect(msg.setLengthU(EasyMock.anyShort())).andReturn(msg);
+		EasyMock.expect(msg.setOutPort(EasyMock.anyShort())).andReturn(msg).atLeastOnce();
+		EasyMock.expect(msg.getXid()).andReturn(1).anyTimes();
+		EasyMock.expect(msg.getType()).andReturn(OFType.FLOW_MOD).anyTimes();
+		EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
+		EasyMock.replay(msg);
+		
+		EasyMock.expect(factory.getMessage(EasyMock.eq(OFType.FLOW_MOD))).andReturn(msg);
+		
+		ScheduledExecutorService executor = EasyMock.createMock(ScheduledExecutorService.class);
+		EasyMock.expect(executor.schedule((Runnable)EasyMock.anyObject(), EasyMock.anyLong(),
+				(TimeUnit)EasyMock.anyObject())).andReturn(null).once();
+		EasyMock.replay(executor);
+		EasyMock.expect(threadPoolService.getScheduledExecutor()).andReturn(executor);
+
+		IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+		EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
+		EasyMock.expect(sw.getStringId()).andReturn("1").anyTimes();
+		sw.flush();
+		EasyMock.expectLastCall().once();
+		EasyMock.replay(sw);
+		
+		try {
+			EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.anyObject(OFMessage.class), EasyMock.eq(context)))
+				.andAnswer(new IAnswer<Boolean>() {
+					@Override
+					public Boolean answer() throws Throwable {
+						OFMessage msg = (OFMessage)EasyMock.getCurrentArguments()[1];
+						assertEquals(msg.getType(), OFType.FLOW_MOD);
+						return true;
+					}
+				}).once();
+		} catch (IOException e1) {
+			fail("Failed in OFMessageDamper#write()");
+		}
+		
+		endInitMock();
+		initPusher(1);
+
+		pusher.pushFlowEntry(sw, flowEntry1);
+		
+		try {
+			Thread.sleep(1000);
+		} catch (InterruptedException e) {
+			fail("Failed to sleep");
+		}
+		
+		EasyMock.verify(sw);
+		
+		pusher.stop();
+	}
+	
+	@SuppressWarnings("unchecked")
+	private void beginInitMock() {
+		context = EasyMock.createMock(FloodlightContext.class);
+		modContext = EasyMock.createMock(FloodlightModuleContext.class);
+		factory = EasyMock.createMock(BasicFactory.class);
+		damper = EasyMock.createMock(OFMessageDamper.class);
+		flProviderService = EasyMock.createMock(IFloodlightProviderService.class);
+		threadPoolService = EasyMock.createMock(IThreadPoolService.class);
+		flowService = EasyMock.createMock(IFlowService.class);
+		
+		flowService.flowEntriesPushedToSwitch(EasyMock.anyObject(Collection.class));
+		EasyMock.expectLastCall().anyTimes();
+		
+		EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IThreadPoolService.class)))
+			.andReturn(threadPoolService).once();
+		EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IFloodlightProviderService.class)))
+			.andReturn(flProviderService).once();
+		EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IFlowService.class)))
+			.andReturn(flowService).once();
+		flProviderService.addOFMessageListener(EasyMock.eq(OFType.BARRIER_REPLY),
+				(FlowPusher) EasyMock.anyObject());
+		EasyMock.expectLastCall().once();
+	}
+	
+	private void endInitMock() {
+		EasyMock.replay(flowService);
+		EasyMock.replay(threadPoolService);
+		EasyMock.replay(flProviderService);
+		EasyMock.replay(damper);
+		EasyMock.replay(factory);
+		EasyMock.replay(modContext);
+		EasyMock.replay(context);
+	}
+	
+	private void initPusher(int num_thread) {
+		pusher = new FlowPusher(num_thread);
+		pusher.init(context, modContext, factory, damper);
+		pusher.start();
+	}
+	
+	private void prepareBarrier(IOFSwitch sw) {
+		OFBarrierRequest req = EasyMock.createMock(OFBarrierRequest.class);
+		req.setXid(EasyMock.anyInt());
+		EasyMock.expectLastCall().once();
+		EasyMock.expect(req.getXid()).andReturn(1).anyTimes();
+		EasyMock.expect(req.getType()).andReturn(OFType.BARRIER_REQUEST).anyTimes();
+		EasyMock.expect(req.getLength()).andReturn((short)100).anyTimes();
+		EasyMock.replay(req);
+		EasyMock.expect(factory.getMessage(EasyMock.eq(OFType.BARRIER_REQUEST))).andReturn(req);
+		
+		ScheduledExecutorService executor = EasyMock.createMock(ScheduledExecutorService.class);
+		EasyMock.expect(executor.schedule((Runnable)EasyMock.anyObject(), EasyMock.anyLong(),
+				(TimeUnit)EasyMock.anyObject())).andReturn(null).once();
+		EasyMock.replay(executor);
+		EasyMock.expect(threadPoolService.getScheduledExecutor()).andReturn(executor);
+
+		EasyMock.expect(sw.getNextTransactionId()).andReturn(1);
+	}
+	
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizerTest.java b/src/test/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizerTest.java
new file mode 100644
index 0000000..68b4f1f
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizerTest.java
@@ -0,0 +1,313 @@
+package net.onrc.onos.ofcontroller.flowprogrammer;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import net.floodlightcontroller.core.IOFSwitch;
+import net.onrc.onos.graph.GraphDBOperation;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
+import net.onrc.onos.ofcontroller.flowmanager.FlowDatabaseOperation;
+import net.onrc.onos.ofcontroller.flowprogrammer.IFlowSyncService.SyncResult;
+import net.onrc.onos.ofcontroller.util.FlowEntry;
+import net.onrc.onos.ofcontroller.util.FlowEntryId;
+
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFStatisticsRequest;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.statistics.OFFlowStatisticsReply;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.powermock.api.easymock.PowerMock;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({FlowSynchronizer.class, GraphDBOperation.class, FlowDatabaseOperation.class})
+public class FlowSynchronizerTest {
+	private FlowPusher pusher;
+	private FlowSynchronizer sync;
+	private List<Long> idAdded;
+	private List<Long> idRemoved;
+
+	@Before
+	public void setUp() throws Exception {
+		idAdded = new ArrayList<Long>();
+		idRemoved = new ArrayList<Long>();
+		
+		pusher = EasyMock.createMock(FlowPusher.class);
+		pusher.add(EasyMock.anyObject(IOFSwitch.class), EasyMock.anyObject(OFMessage.class));
+		EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+				@Override
+				public Object answer() throws Throwable {
+					OFMessage msg = (OFMessage)EasyMock.getCurrentArguments()[1];
+					if (msg.getType().equals(OFType.FLOW_MOD)) {
+						OFFlowMod fm = (OFFlowMod)msg;
+						if (fm.getCommand() == OFFlowMod.OFPFC_DELETE_STRICT) {
+							idRemoved.add(fm.getCookie());
+						}
+					}
+					return null;
+				}
+			}).anyTimes();
+		pusher.pushFlowEntry(EasyMock.anyObject(IOFSwitch.class), EasyMock.anyObject(FlowEntry.class));
+		EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+			@Override
+			public Object answer() throws Throwable {
+				FlowEntry flow = (FlowEntry)EasyMock.getCurrentArguments()[1];
+				idAdded.add(flow.flowEntryId().value());
+				return null;
+			}
+		}).anyTimes();
+		EasyMock.replay(pusher);
+	}
+
+	@After
+	public void tearDown() throws Exception {
+	}
+
+	/**
+	 * Test that synchronization doesn't affect anything in case either DB and
+	 * flow table has the same entries.
+	 */
+	@Test
+	public void testStable() {
+		// Create mock of flow table : flow 1
+		IOFSwitch sw = createMockSwitch(new long[] {1});
+		
+		// Create mock of flow entries : flow 1
+		initMockGraph(new long[] {1});
+		
+		// synchronize
+		doSynchronization(sw);
+		
+		// check if flow is not changed
+		assertEquals(0, idAdded.size());
+		assertEquals(0, idRemoved.size());
+	}
+
+	/**
+	 * Test that an flow is added in case DB has an extra FlowEntry.
+	 */
+	@Test
+	public void testSingleAdd() {
+		// Create mock of flow table : null
+		IOFSwitch sw = createMockSwitch(new long[] {});
+		
+		// Create mock of flow entries : flow 1
+		initMockGraph(new long[] {1});
+		
+		// synchronize
+		doSynchronization(sw);
+		
+		// check if single flow is installed
+		assertEquals(1, idAdded.size());
+		assertTrue(idAdded.contains((long)1));
+		assertEquals(0, idRemoved.size());
+	}
+
+	/**
+	 * Test that an flow is deleted in case switch has an extra FlowEntry.
+	 */
+	@Test
+	public void testSingleDelete() {
+		// Create mock of flow table : flow 1
+		IOFSwitch sw = createMockSwitch(new long[] {1});
+		
+		// Create mock of flow entries : null
+		initMockGraph(new long[] {});
+		
+		// synchronize
+		doSynchronization(sw);
+		
+		// check if single flow is deleted
+		assertEquals(0, idAdded.size());
+		assertEquals(1, idRemoved.size());
+		assertTrue(idRemoved.contains((long)1));
+	}
+	
+	/**
+	 * Test that appropriate flows are added and other appropriate flows are deleted
+	 * in case flows in DB are overlapping flows in switch.
+	 */
+	@Test
+	public void testMixed() {
+		// Create mock of flow table : flow 1,2,3
+		IOFSwitch sw = createMockSwitch(new long[] {1,2,3});
+		
+		// Create mock of flow entries : flow 2,3,4,5
+		initMockGraph(new long[] {2,3,4,5});
+		
+		// synchronize
+		doSynchronization(sw);
+		
+		// check if two flows {4,5} is installed and one flow {1} is deleted
+		assertEquals(2, idAdded.size());
+		assertTrue(idAdded.contains((long)4));
+		assertTrue(idAdded.contains((long)5));
+		assertEquals(1, idRemoved.size());
+		assertTrue(idRemoved.contains((long)1));
+	}
+	
+
+	@Test
+	public void testMassive() {
+		// Create mock of flow table : flow 0-1999
+		long [] swIdList = new long [2000];
+		for (long i = 0; i < 2000; ++i) {
+			swIdList[(int)i] = i;
+		}
+		IOFSwitch sw = createMockSwitch(swIdList);
+		
+		// Create mock of flow entries : flow 1500-3499
+		long [] dbIdList = new long [2000];
+		for (long i = 0; i < 2000; ++i) {
+			dbIdList[(int)i] = 1500 + i;
+		}
+		initMockGraph(dbIdList);
+
+		// synchronize
+		doSynchronization(sw);
+		
+		// check if 1500 flows {2000-3499} is installed and 1500 flows {0,...,1499} is deleted
+		assertEquals(1500, idAdded.size());
+		for (long i = 2000; i < 3500; ++i) {
+			assertTrue(idAdded.contains(i));
+		}
+		assertEquals(1500, idRemoved.size());
+		for (long i = 0; i < 1500; ++i) {
+			assertTrue(idRemoved.contains(i));
+		}
+	}
+
+	/**
+	 * Create mock IOFSwitch with flow table which has arbitrary flows.
+	 * @param cookieList List of FlowEntry IDs switch has.
+	 * @return Mock object.
+	 */
+	private IOFSwitch createMockSwitch(long[] cookieList) {
+		IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+		EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
+		
+		List<OFStatistics> stats = new ArrayList<OFStatistics>();
+		for (long cookie : cookieList) {
+			stats.add(createReply(cookie));
+		}
+		
+		@SuppressWarnings("unchecked")
+		Future<List<OFStatistics>> future = EasyMock.createMock(Future.class);
+		try {
+			EasyMock.expect(future.get()).andReturn(stats).once();
+		} catch (InterruptedException e1) {
+			fail("Failed in Future#get()");
+		} catch (ExecutionException e1) {
+			fail("Failed in Future#get()");
+		}
+		EasyMock.replay(future);
+		
+		try {
+			EasyMock.expect(sw.getStatistics(EasyMock.anyObject(OFStatisticsRequest.class)))
+				.andReturn(future).once();
+		} catch (IOException e) {
+			fail("Failed in IOFSwitch#getStatistics()");
+		}
+		
+		EasyMock.replay(sw);
+		return sw;
+	}
+	
+	/**
+	 * Create single OFFlowStatisticsReply object which is actually obtained from switch.
+	 * @param cookie Cookie value, which indicates ID of FlowEntry installed to switch.
+	 * @return Created object.
+	 */
+	private OFFlowStatisticsReply createReply(long cookie) {
+		OFFlowStatisticsReply stat = new OFFlowStatisticsReply();
+		OFMatch match = new OFMatch();
+		
+		stat.setCookie(cookie);
+		stat.setMatch(match);
+		stat.setPriority((short)1);
+
+		return stat;
+	}
+	
+	/**
+	 * Create mock GraphDBOperation and FlowDatabaseOperation to mock DB.
+	 * @param idList List of FlowEntry IDs stored in DB.
+	 */
+	private void initMockGraph(long[] idList) {
+		List<IFlowEntry> flowEntryList = new ArrayList<IFlowEntry>();
+		
+		for (long id : idList) {
+			IFlowEntry entry = EasyMock.createMock(IFlowEntry.class);
+			EasyMock.expect(entry.getFlowEntryId()).andReturn(String.valueOf(id)).anyTimes();
+			EasyMock.replay(entry);
+			flowEntryList.add(entry);
+		}
+		
+		ISwitchObject swObj = EasyMock.createMock(ISwitchObject.class);
+		EasyMock.expect(swObj.getFlowEntries()).andReturn(flowEntryList).once();
+		EasyMock.replay(swObj);
+		
+		GraphDBOperation mockOp = PowerMock.createMock(GraphDBOperation.class);
+		EasyMock.expect(mockOp.searchSwitch(EasyMock.anyObject(String.class))).andReturn(swObj).once();
+		
+		PowerMock.mockStatic(FlowDatabaseOperation.class);
+		for (IFlowEntry entry : flowEntryList) {
+			EasyMock.expect(FlowDatabaseOperation.extractFlowEntry(EasyMock.eq(entry)))
+				.andAnswer(new IAnswer<FlowEntry>() {
+					@Override
+					public FlowEntry answer() throws Throwable {
+						IFlowEntry iflow = (IFlowEntry)EasyMock.getCurrentArguments()[0];
+						long flowEntryId = Long.valueOf(iflow.getFlowEntryId());
+						
+						FlowEntry flow = EasyMock.createMock(FlowEntry.class);
+						EasyMock.expect(flow.flowEntryId()).andReturn(new FlowEntryId(flowEntryId)).anyTimes();
+						EasyMock.replay(flow);
+						return flow;
+					}
+					
+				}).anyTimes();
+			EasyMock.expect(mockOp.searchFlowEntry(EasyMock.eq(new FlowEntryId(entry.getFlowEntryId()))))
+				.andReturn(entry);
+		}
+		PowerMock.replay(FlowDatabaseOperation.class);
+		EasyMock.replay(mockOp);
+		
+		try {
+			PowerMock.expectNew(GraphDBOperation.class, "").andReturn(mockOp);
+		} catch (Exception e) {
+			fail("Failed to create GraphDBOperation");
+		}
+		PowerMock.replay(GraphDBOperation.class);
+	}
+	
+	/**
+	 * Instantiate FlowSynchronizer and sync flows.
+	 * @param sw Target IOFSwitch object
+	 */
+	private void doSynchronization(IOFSwitch sw) {
+		sync = new FlowSynchronizer();
+		sync.init(pusher);
+		Future<SyncResult> future = sync.synchronize(sw);
+		try {
+			future.get();
+		} catch (Exception e) {
+			fail("Failed to Future#get()");
+		}
+	}
+}
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 09d0a00..e054e05 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/topology/TopologyManagerTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/topology/TopologyManagerTest.java
@@ -2,7 +2,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import java.util.Map;
 
 import org.easymock.EasyMock;
 
diff --git a/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryTest.java b/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryTest.java
index fc17178..696f9e5 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/util/FlowEntryTest.java
@@ -13,6 +13,8 @@
 	
 	FlowId flowId = new FlowId(0x1234);
 	FlowEntryId flowEntryId = new FlowEntryId(0x5678);
+	int idleTimeout = 5;
+	int hardTimeout = 10;
 	FlowEntryMatch match;
 	FlowEntryActions actions;
 	
@@ -50,6 +52,9 @@
 
 		flowEntryId = new FlowEntryId("0x5678");
 		entry.setFlowEntryId(flowEntryId);
+
+		entry.setIdleTimeout(5);
+		entry.setHardTimeout(10);
 		
 		dpid = new Dpid("CA:FE");
 		entry.setDpid( dpid );
@@ -188,6 +193,16 @@
 	}
 
 	@Test
+	public void testIdleTimeout(){
+		assertEquals("idleTimeout", idleTimeout, entry.idleTimeout() );
+	}
+
+	@Test
+	public void testHardTimeout(){
+		assertEquals("hardTimeout", hardTimeout, entry.hardTimeout() );
+	}
+
+	@Test
 	public void testFlowEntryMatch(){
 		assertEquals("flowEntryMatch", match, entry.flowEntryMatch() );
 	}
@@ -237,8 +252,8 @@
 	@Test
 	public void testToString(){
 		FlowEntry def = new FlowEntry();
-		assertEquals("toString", def.toString(), "[ flowEntryActions=[] flowEntryUserState=FE_USER_UNKNOWN flowEntrySwitchState=FE_SWITCH_UNKNOWN]" );
-		assertEquals("toString", entry.toString(), "[flowEntryId=0x5678 flowId=0x1234 flowEntryMatch=[inPort=1 srcMac=01:02:03:04:05:06 dstMac=06:05:04:03:02:01 ethernetFrameType=2 vlanId=3 vlanPriority=4 srcIPv4Net=127.0.0.1/32 dstIPv4Net=127.0.0.2/32 ipProto=5 ipToS=6 srcTcpUdpPort=7 dstTcpUdpPort=8] flowEntryActions=[[type=ACTION_OUTPUT action=[port=9 maxLen=0]];[type=ACTION_OUTPUT action=[port=-3 maxLen=0]];[type=ACTION_SET_VLAN_VID action=[vlanId=3]];[type=ACTION_SET_VLAN_PCP action=[vlanPriority=4]];[type=ACTION_STRIP_VLAN action=[stripVlan=true]];[type=ACTION_SET_DL_SRC action=[addr=01:02:03:04:05:06]];[type=ACTION_SET_DL_DST action=[addr=06:05:04:03:02:01]];[type=ACTION_SET_NW_SRC action=[addr=127.0.0.3]];[type=ACTION_SET_NW_DST action=[addr=127.0.0.4]];[type=ACTION_SET_NW_TOS action=[ipToS=6]];[type=ACTION_SET_TP_SRC action=[port=7]];[type=ACTION_SET_TP_DST action=[port=8]];[type=ACTION_ENQUEUE action=[port=10 queueId=11]];] dpid=00:00:00:00:00:00:ca:fe inPort=1 outPort=9 flowEntryUserState=FE_USER_ADD flowEntrySwitchState=FE_SWITCH_UPDATED flowEntryErrorState=[type=12 code=13]]" );
+		assertEquals("toString", def.toString(), "[ idleTimeout=0 hardTimeout=0 flowEntryActions=[] flowEntryUserState=FE_USER_UNKNOWN flowEntrySwitchState=FE_SWITCH_UNKNOWN]" );
+		assertEquals("toString", entry.toString(), "[flowEntryId=0x5678 flowId=0x1234 idleTimeout=5 hardTimeout=10 flowEntryMatch=[inPort=1 srcMac=01:02:03:04:05:06 dstMac=06:05:04:03:02:01 ethernetFrameType=2 vlanId=3 vlanPriority=4 srcIPv4Net=127.0.0.1/32 dstIPv4Net=127.0.0.2/32 ipProto=5 ipToS=6 srcTcpUdpPort=7 dstTcpUdpPort=8] flowEntryActions=[[type=ACTION_OUTPUT action=[port=9 maxLen=0]];[type=ACTION_OUTPUT action=[port=-3 maxLen=0]];[type=ACTION_SET_VLAN_VID action=[vlanId=3]];[type=ACTION_SET_VLAN_PCP action=[vlanPriority=4]];[type=ACTION_STRIP_VLAN action=[stripVlan=true]];[type=ACTION_SET_DL_SRC action=[addr=01:02:03:04:05:06]];[type=ACTION_SET_DL_DST action=[addr=06:05:04:03:02:01]];[type=ACTION_SET_NW_SRC action=[addr=127.0.0.3]];[type=ACTION_SET_NW_DST action=[addr=127.0.0.4]];[type=ACTION_SET_NW_TOS action=[ipToS=6]];[type=ACTION_SET_TP_SRC action=[port=7]];[type=ACTION_SET_TP_DST action=[port=8]];[type=ACTION_ENQUEUE action=[port=10 queueId=11]];] dpid=00:00:00:00:00:00:ca:fe inPort=1 outPort=9 flowEntryUserState=FE_USER_ADD flowEntrySwitchState=FE_SWITCH_UPDATED flowEntryErrorState=[type=12 code=13]]" );
 	}
 
 }
diff --git a/src/test/java/net/onrc/onos/ofcontroller/util/FlowPathTest.java b/src/test/java/net/onrc/onos/ofcontroller/util/FlowPathTest.java
index bd42ac8..76ccf9f 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/util/FlowPathTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/util/FlowPathTest.java
@@ -19,6 +19,8 @@
 		iFlowPath.setFlowPathTypeForTest("FP_TYPE_SHORTEST_PATH");
 		iFlowPath.setFlowPathUserStateForTest("FP_USER_ADD");
 		iFlowPath.setFlowPathFlagsForTest(0L);
+		iFlowPath.setIdleTimeoutForTest(5);
+		iFlowPath.setHardTimeoutForTest(10);
 		iFlowPath.setSrcSwForTest("CA:FE");
 		iFlowPath.setSrcPortForTest((short)1);
 		iFlowPath.setDstSwForTest("BA:BE");
@@ -44,6 +46,8 @@
 		assertTrue ( flowPath.flowPathUserState() == FlowPathUserState.FP_USER_UNKNOWN);
 		assertFalse( flowPath.flowPathFlags().isDiscardFirstHopEntry() );
 		assertFalse( flowPath.flowPathFlags().isKeepOnlyFirstHopEntry() );
+		assertTrue (flowPath.idleTimeout() == 0);
+		assertTrue (flowPath.hardTimeout() == 0);
 		assertTrue( flowPath.flowEntryActions().isEmpty() );
 	}
 
@@ -55,6 +59,8 @@
 		iFlowPath.setFlowPathTypeForTest("FP_TYPE_SHORTEST_PATH");
 		iFlowPath.setFlowPathUserStateForTest("FP_USER_ADD");
 		iFlowPath.setFlowPathFlagsForTest(0L);
+		iFlowPath.setIdleTimeoutForTest(5);
+		iFlowPath.setHardTimeoutForTest(10);
 		iFlowPath.setSrcSwForTest("CA:FE");
 		iFlowPath.setSrcPortForTest((short)1);
 		iFlowPath.setDstSwForTest("BA:BE");
@@ -100,6 +106,8 @@
 		assertEquals(flowPath.flowPathType(), FlowPathType.FP_TYPE_SHORTEST_PATH);
 		assertEquals(flowPath.flowPathUserState(), FlowPathUserState.FP_USER_ADD);
 		assertEquals(flowPath.flowPathFlags().flags(), 0);
+		assertEquals(flowPath.idleTimeout(), 5);
+		assertEquals(flowPath.hardTimeout(), 10);
 		assertEquals(flowPath.dataPath().srcPort().dpid().value(), 0xCAFE);
 		assertEquals(flowPath.dataPath().srcPort().port().value(), 1);
 		assertEquals(flowPath.dataPath().dstPort().dpid().value(), 0xBABE);
@@ -123,6 +131,8 @@
 		
 		assertEquals(0x14, flowPath.dataPath().flowEntries().get(0).flowEntryId().value() );
 		assertEquals(0xBEEF, flowPath.dataPath().flowEntries().get(0).dpid().value() );
+		assertEquals(0, flowPath.dataPath().flowEntries().get(0).idleTimeout() );
+		assertEquals(0, flowPath.dataPath().flowEntries().get(0).hardTimeout() );
 		assertEquals(15, flowPath.dataPath().flowEntries().get(0).flowEntryMatch().inPort().value() );
 		assertEquals("11:22:33:44:55:66", flowPath.dataPath().flowEntries().get(0).flowEntryMatch().srcMac().toString());
 		assertEquals("66:55:44:33:22:11", flowPath.dataPath().flowEntries().get(0).flowEntryMatch().dstMac().toString());
@@ -179,6 +189,22 @@
 	}
 
 	@Test
+	public void testSetIdleTimeout(){
+		FlowPath flowPath = new FlowPath();
+		int idleTimeout = 15;
+		flowPath.setIdleTimeout( idleTimeout );
+		assertTrue( flowPath.idleTimeout() == 15 );
+	}
+
+	@Test
+	public void testSetHardTimeout(){
+		FlowPath flowPath = new FlowPath();
+		int hardTimeout = 20;
+		flowPath.setHardTimeout( hardTimeout );
+		assertTrue( flowPath.hardTimeout() == 20 );
+	}
+
+	@Test
 	public void testSetDataPath(){
 		FlowPath flowPath = new FlowPath();
 		DataPath dataPath = new DataPath();
@@ -189,7 +215,7 @@
 	@Test
 	public void testToString(){
 
-		assertEquals("[flowId=0x1234 installerId=installerId flowPathType=FP_TYPE_SHORTEST_PATH flowPathUserState=FP_USER_ADD flowPathFlags=[flags=] dataPath=[src=00:00:00:00:00:00:ca:fe/1 flowEntry=[flowEntryId=0x14 flowEntryMatch=[] flowEntryActions=[[type=ACTION_OUTPUT action=[port=23 maxLen=24]];[type=ACTION_OUTPUT action=[port=25 maxLen=26]];] dpid=00:00:00:00:00:00:be:ef flowEntryUserState=FE_USER_MODIFY flowEntrySwitchState=FE_SWITCH_UPDATE_IN_PROGRESS] dst=00:00:00:00:00:00:ba:be/2] flowEntryMatch=[] flowEntryActions=[[type=ACTION_OUTPUT action=[port=10 maxLen=11]];[type=ACTION_OUTPUT action=[port=12 maxLen=13]];]]", flowPath.toString());
+		assertEquals("[flowId=0x1234 installerId=installerId flowPathType=FP_TYPE_SHORTEST_PATH flowPathUserState=FP_USER_ADD flowPathFlags=[flags=] idleTimeout=5 hardTimeout=10 dataPath=[src=00:00:00:00:00:00:ca:fe/1 flowEntry=[flowEntryId=0x14 idleTimeout=0 hardTimeout=0 flowEntryMatch=[] flowEntryActions=[[type=ACTION_OUTPUT action=[port=23 maxLen=24]];[type=ACTION_OUTPUT action=[port=25 maxLen=26]];] dpid=00:00:00:00:00:00:be:ef flowEntryUserState=FE_USER_MODIFY flowEntrySwitchState=FE_SWITCH_UPDATE_IN_PROGRESS] dst=00:00:00:00:00:00:ba:be/2] flowEntryMatch=[] flowEntryActions=[[type=ACTION_OUTPUT action=[port=10 maxLen=11]];[type=ACTION_OUTPUT action=[port=12 maxLen=13]];]]", flowPath.toString());
 	}
 
 	@Test
diff --git a/start-onos-embedded.sh b/start-onos-embedded.sh
index 8688f69..6fc9362 100755
--- a/start-onos-embedded.sh
+++ b/start-onos-embedded.sh
@@ -17,7 +17,7 @@
 #JVM_OPTS="$JVM_OPTS -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods"
 JVM_OPTS="$JVM_OPTS -XX:+UseConcMarkSweepGC -XX:+UseAdaptiveSizePolicy -XX:+AggressiveOpts -XX:+UseFastAccessorMethods"
 JVM_OPTS="$JVM_OPTS -XX:MaxInlineSize=8192 -XX:FreqInlineSize=8192"
-JVM_OPTS="$JVM_OPTS -javaagent:lib/jamm-0.2.5.jar"
+JVM_OPTS="$JVM_OPTS -javaagent:$ONOS_HOME/lib/jamm-0.2.5.jar"
 JVM_OPTS="$JVM_OPTS -XX:CompileThreshold=1500 -XX:PreBlockSpin=8 \
 		-XX:+UseThreadPriorities \
 		-XX:ThreadPriorityPolicy=42 \
@@ -90,7 +90,7 @@
 </configuration>
 EOF_LOGBACK
 
-  # Run floodlight
+  # Run ONOS
   echo "Starting ONOS controller ..."
   echo 
 
diff --git a/start-onos-jacoco.sh b/start-onos-jacoco.sh
new file mode 100755
index 0000000..2e04216
--- /dev/null
+++ b/start-onos-jacoco.sh
@@ -0,0 +1,184 @@
+#!/bin/bash
+
+# Set paths
+if [ -z "${ONOS_HOME}" ]; then
+        ONOS_HOME=`dirname $0`
+fi
+
+## Because the script change dir to $ONOS_HOME, we can set ONOS_LOGBACK and LOGDIR relative to $ONOS_HOME
+#ONOS_LOGBACK="${ONOS_HOME}/logback.`hostname`.xml"
+#LOGDIR=${ONOS_HOME}/onos-logs
+ONOS_LOGBACK="./logback.`hostname`.xml"
+LOGDIR=./onos-logs
+ONOS_LOG="${LOGDIR}/onos.`hostname`.log"
+PCAP_LOG="${LOGDIR}/onos.`hostname`.pcap"
+LOGS="$ONOS_LOG $PCAP_LOG"
+
+# Set JVM options
+JVM_OPTS=""
+## If you want JaCoCo Code Coverage reports... uncomment line below
+JVM_OPTS="$JVM_OPTS -javaagent:${ONOS_HOME}/lib/jacocoagent.jar=dumponexit=true,output=file,destfile=${LOGDIR}/jacoco.exec"
+JVM_OPTS="$JVM_OPTS -server -d64"
+#JVM_OPTS="$JVM_OPTS -Xmx2g -Xms2g -Xmn800m"
+JVM_OPTS="$JVM_OPTS -Xmx1g -Xms1g -Xmn800m"
+#JVM_OPTS="$JVM_OPTS -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods"
+JVM_OPTS="$JVM_OPTS -XX:+UseConcMarkSweepGC -XX:+UseAdaptiveSizePolicy -XX:+AggressiveOpts -XX:+UseFastAccessorMethods"
+JVM_OPTS="$JVM_OPTS -XX:MaxInlineSize=8192 -XX:FreqInlineSize=8192"
+JVM_OPTS="$JVM_OPTS -XX:CompileThreshold=1500 -XX:PreBlockSpin=8"
+JVM_OPTS="$JVM_OPTS -XX:OnError=crash-logger" ;# For dumping core
+#JVM_OPTS="$JVM_OPTS -Dpython.security.respectJavaAccessibility=false"
+JVM_OPTS="$JVM_OPTS -XX:CompileThreshold=1500 -XX:PreBlockSpin=8 \
+		-XX:+UseThreadPriorities \
+		-XX:ThreadPriorityPolicy=42 \
+		-XX:+UseCompressedOops \
+		-Dcom.sun.management.jmxremote.port=7189 \
+		-Dcom.sun.management.jmxremote.ssl=false \
+		-Dcom.sun.management.jmxremote.authenticate=false"
+JVM_OPTS="$JVM_OPTS -Dhazelcast.logging.type=slf4j"
+
+# Set ONOS core main class
+MAIN_CLASS="net.onrc.onos.ofcontroller.core.Main"
+
+if [ -z "${MVN}" ]; then
+    MVN="mvn -o"
+fi
+
+#<logger name="net.floodlightcontroller.linkdiscovery.internal" level="TRACE"/>
+#<appender-ref ref="STDOUT" />
+
+function lotate {
+    logfile=$1
+    nr_max=${2:-10}
+    if [ -f $logfile ]; then
+	for i in `seq $(expr $nr_max - 1) -1 1`; do
+	    if [ -f ${logfile}.${i} ]; then
+		mv -f ${logfile}.${i} ${logfile}.`expr $i + 1`
+	    fi
+	done
+	mv $logfile $logfile.1
+    fi
+}
+
+function start {
+  if [ ! -d ${LOGDIR} ]; then
+    mkdir -p ${LOGDIR}
+  fi
+  # Backup log files
+  for log in ${LOGS}; do
+    echo "rotate log: $log"
+    if [ -f ${log} ]; then
+      lotate ${log}
+    fi
+  done
+
+# Create a logback file if required
+  if [ ! -f ${ONOS_LOGBACK} ]; then
+    cat <<EOF_LOGBACK >${ONOS_LOGBACK}
+<configuration scan="true" debug="true">
+<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+<encoder>
+<pattern>%level [%logger:%thread] %msg%n</pattern>
+</encoder>
+</appender>
+
+<appender name="FILE" class="ch.qos.logback.core.FileAppender">
+<file>${ONOS_LOG}</file>
+<encoder>
+<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
+</encoder>
+</appender>
+
+<logger name="org" level="WARN"/>
+<logger name="LogService" level="WARN"/> <!-- Restlet access logging -->
+<logger name="net.floodlightcontroller.logging" level="WARN"/>
+
+<root level="DEBUG">
+<appender-ref ref="FILE" />
+</root>
+</configuration>
+EOF_LOGBACK
+  fi
+
+  # Run ONOS
+  echo "Starting ONOS controller ..."
+  echo 
+
+  # XXX : MVN has to run at the project top dir 
+  echo $ONOS_HOME
+  cd ${ONOS_HOME}
+  pwd 
+  echo "${MVN} exec:exec -Dexec.executable=\"java\" -Dexec.args=\"${JVM_OPTS} -Dlogback.configurationFile=${ONOS_LOGBACK} -cp %classpath ${MAIN_CLASS} -cf ./conf/onos.properties\""
+
+  ${MVN} exec:exec -Dexec.executable="java" -Dexec.args="${JVM_OPTS} -Dlogback.configurationFile=${ONOS_LOGBACK} -cp %classpath ${MAIN_CLASS} -cf ./conf/onos.properties" > ${LOGDIR}/onos.`hostname`.stdout 2>${LOGDIR}/onos.`hostname`.stderr &
+
+  echo "Waiting for ONOS to start..."
+  COUNT=0
+  ESTATE=0
+  while [ "$COUNT" != "10" ]; do
+    echo -n "."
+    sleep 1
+#    COUNT=$((COUNT + 1))
+#    sleep $COUNT
+    n=`jps -l |grep "${MAIN_CLASS}" | wc -l`
+    if [ "$n" -ge "1" ]; then
+      echo ""
+      exit 0
+    fi
+  done
+  echo "Timed out"
+  exit 1
+
+#  echo "java ${JVM_OPTS} -Dlogback.configurationFile=${ONOS_LOGBACK} -jar ${ONOS_JAR} -cf ./onos.properties > /dev/null 2>&1 &"
+#  sudo -b /usr/sbin/tcpdump -n -i eth0 -s0 -w ${PCAP_LOG} 'tcp port 6633' > /dev/null  2>&1
+}
+
+function stop {
+  # Kill the existing processes
+  flpid=`jps -l |grep ${MAIN_CLASS} | awk '{print $1}'`
+  tdpid=`ps -edalf |grep tcpdump |grep ${PCAP_LOG} | awk '{print $4}'`
+  pids="$flpid $tdpid"
+  for p in ${pids}; do
+    if [ x$p != "x" ]; then
+      kill -TERM $p
+      echo "Killed existing process (pid: $p)"
+    fi
+  done
+}
+
+function check_db {
+   if [ -d "/tmp/cassandra.titan" ]; then
+      echo "Cassandra is running on local berkely db. Exitting"
+      exit
+   fi
+   n=`ps -edalf |grep java |grep apache-cassandra | wc -l`
+   if [ x$n == "x0" ]; then
+      echo "Cassandra is not running. Exitting"
+      exit
+   fi
+}
+
+case "$1" in
+  start)
+    stop
+    check_db
+    start 
+    ;;
+  startifdown)
+    n=`jps -l |grep "${MAIN_CLASS}" | wc -l`
+    if [ $n == 0 ]; then
+      start
+    else 
+      echo "$n instance of onos running"
+    fi
+    ;;
+  stop)
+    stop
+    ;;
+  status)
+    n=`jps -l |grep "${MAIN_CLASS}" | wc -l`
+    echo "$n instance of onos running"
+    ;;
+  *)
+    echo "Usage: $0 {start|stop|restart|status|startifdown}"
+    exit 1
+esac
diff --git a/start-onos.sh b/start-onos.sh
index 495141d..29a108c 100755
--- a/start-onos.sh
+++ b/start-onos.sh
@@ -17,7 +17,7 @@
 # Set JVM options
 JVM_OPTS=""
 ## If you want JaCoCo Code Coverage reports... uncomment line below
-JVM_OPTS="$JVM_OPTS -javaagent:${ONOS_HOME}/lib/jacocoagent.jar=dumponexit=true,output=file,destfile=${LOGDIR}/jacoco.exec"
+#JVM_OPTS="$JVM_OPTS -javaagent:${ONOS_HOME}/lib/jacocoagent.jar=dumponexit=true,output=file,destfile=${LOGDIR}/jacoco.exec"
 JVM_OPTS="$JVM_OPTS -server -d64"
 #JVM_OPTS="$JVM_OPTS -Xmx2g -Xms2g -Xmn800m"
 JVM_OPTS="$JVM_OPTS -Xmx1g -Xms1g -Xmn800m"
@@ -99,7 +99,7 @@
 EOF_LOGBACK
   fi
 
-  # Run floodlight
+  # Run ONOS
   echo "Starting ONOS controller ..."
   echo 
 
diff --git a/web/add_flow.py b/web/add_flow.py
index eed75f9..9690024 100755
--- a/web/add_flow.py
+++ b/web/add_flow.py
@@ -129,9 +129,12 @@
   my_dst_port = my_args[5]
 
   #
-  # Extract the "flowPathFlags", "match" and "action" arguments
+  # Extract the "flowPathFlags", "idleTimeout", "hardTimeout",
+  # "match" and "action" arguments.
   #
   flowPathFlags = 0L
+  idleTimeout = 0
+  hardTimeout = 0
   match = {}
   matchInPortEnabled = True		# NOTE: Enabled by default
   actions = []
@@ -155,6 +158,10 @@
 	flowPathFlags = flowPathFlags + 0x1
       if "KEEP_ONLY_FIRST_HOP_ENTRY" in arg2:
 	flowPathFlags = flowPathFlags + 0x2
+    elif arg1 == "idleTimeout":
+     idleTimeout = arg2
+    elif arg1 == "hardTimeout":
+     hardTimeout = arg2
     elif arg1 == "matchInPort":
       # Just mark whether inPort matching is enabled
       matchInPortEnabled = arg2 in ['True', 'true']
@@ -310,6 +317,8 @@
     'my_dst_dpid' : my_dst_dpid,
     'my_dst_port' : my_dst_port,
     'flowPathFlags' : flowPathFlags,
+    'idleTimeout' : idleTimeout,
+    'hardTimeout' : hardTimeout,
     'match' : match,
     'matchInPortEnabled' : matchInPortEnabled,
     'actions' : actions,
@@ -334,6 +343,8 @@
   my_flow_id = parsed_args['my_flow_id']
   my_installer_id = parsed_args['my_installer_id']
   myFlowPathFlags = parsed_args['flowPathFlags']
+  myIdleTimeout = parsed_args['idleTimeout']
+  myHardTimeout = parsed_args['hardTimeout']
   match = parsed_args['match']
   matchInPortEnabled = parsed_args['matchInPortEnabled']
   actions = parsed_args['actions']
@@ -356,6 +367,8 @@
   flow_path['flowPathType'] = 'FP_TYPE_EXPLICIT_PATH'
   flow_path['flowPathUserState'] = 'FP_USER_ADD'
   flow_path['flowPathFlags'] = flowPathFlags
+  flow_path['idleTimeout'] = myIdleTimeout
+  flow_path['hardTimeout'] = myHardTimeout
 
   if (len(match) > 0):
     flow_path['flowEntryMatch'] = copy.deepcopy(match)
@@ -488,6 +501,8 @@
 if __name__ == "__main__":
   usage_msg = "Usage: %s [Flags] <flow-id> <installer-id> <src-dpid> <src-port> <dest-dpid> <dest-port> [Flow Path Flags] [Match Conditions] [Actions]\n" % (sys.argv[0])
   usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "    <flow-id>             The Flow ID, or -1 if it should be assigned by ONOS\n"
+  usage_msg = usage_msg + "\n"
   usage_msg = usage_msg + "    Flags:\n"
   usage_msg = usage_msg + "        -m [monitorname]  Monitor and maintain the installed shortest path(s)\n"
   usage_msg = usage_msg + "                          If 'monitorname' is specified and is set to 'ONOS'\n"
@@ -504,6 +519,10 @@
   usage_msg = usage_msg + "            DISCARD_FIRST_HOP_ENTRY    : Discard the first-hop flow entry\n"
   usage_msg = usage_msg + "            KEEP_ONLY_FIRST_HOP_ENTRY  : Keep only the first-hop flow entry\n"
   usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "    Timeouts (in seconds in the [0, 65535] interval):\n"
+  usage_msg = usage_msg + "        idleTimeout <idleTimeoutInSeconds> (default to 0: no timeout)\n"
+  usage_msg = usage_msg + "        hardTimeout <hardTimeoutInSeconds> (default to 0: no timeout)\n"
+  usage_msg = usage_msg + "\n"
   usage_msg = usage_msg + "    Match Conditions:\n"
   usage_msg = usage_msg + "        matchInPort <True|False> (default to True)\n"
   usage_msg = usage_msg + "        matchSrcMac <source MAC address>\n"
@@ -514,7 +533,7 @@
   usage_msg = usage_msg + "        matchSrcIPv4Net <source IPv4 network address>\n"
   usage_msg = usage_msg + "        matchDstIPv4Net <destination IPv4 network address>\n"
   usage_msg = usage_msg + "        matchIpProto <IP protocol>\n"
-  usage_msg = usage_msg + "        matchIpToS <IP ToS (DSCP field, 6 bits)>\n"
+  usage_msg = usage_msg + "        matchIpToS <IP ToS> (DSCP field, 6 bits)\n"
   usage_msg = usage_msg + "        matchSrcTcpUdpPort <source TCP/UDP port>\n"
   usage_msg = usage_msg + "        matchDstTcpUdpPort <destination TCP/UDP port>\n"
   usage_msg = usage_msg + "\n"
@@ -527,7 +546,7 @@
   usage_msg = usage_msg + "        actionSetEthernetDstAddr <destination MAC address>\n"
   usage_msg = usage_msg + "        actionSetIPv4SrcAddr <source IPv4 address>\n"
   usage_msg = usage_msg + "        actionSetIPv4DstAddr <destination IPv4 address>\n"
-  usage_msg = usage_msg + "        actionSetIpToS <IP ToS (DSCP field, 6 bits)>\n"
+  usage_msg = usage_msg + "        actionSetIpToS <IP ToS> (DSCP field, 6 bits)\n"
   usage_msg = usage_msg + "        actionSetTcpUdpSrcPort <source TCP/UDP port>\n"
   usage_msg = usage_msg + "        actionSetTcpUdpDstPort <destination TCP/UDP port>\n"
   usage_msg = usage_msg + "    Actions (not implemented yet):\n"
diff --git a/web/clear_flow.py b/web/clear_flow.py
deleted file mode 100755
index db70d40..0000000
--- a/web/clear_flow.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#! /usr/bin/env python
-# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
-
-import pprint
-import os
-import sys
-import subprocess
-import json
-import argparse
-import io
-import time
-
-from flask import Flask, json, Response, render_template, make_response, request
-
-#
-# TODO: remove this! We don't use JSON argument here!
-# curl http://127.0.0.1:8080/wm/flow/clear/{"value":"0xf"}/json'
-#
-
-## Global Var ##
-ControllerIP="127.0.0.1"
-ControllerPort=8080
-
-DEBUG=0
-pp = pprint.PrettyPrinter(indent=4)
-
-app = Flask(__name__)
-
-## Worker Functions ##
-def log_error(txt):
-  print '%s' % (txt)
-
-def debug(txt):
-  if DEBUG:
-    print '%s' % (txt)
-
-# @app.route("/wm/flow/clear/<flow-id>/json")
-def clear_flow_path(flow_id):
-  command = "curl -s \"http://%s:%s/wm/flow/clear/%s/json\"" % (ControllerIP, ControllerPort, flow_id)
-  debug("clear_flow_path %s" % command)
-  result = os.popen(command).read()
-  debug("result %s" % result)
-  # parsedResult = json.loads(result)
-  # debug("parsed %s" % parsedResult)
-
-if __name__ == "__main__":
-  usage_msg = "Clear flow state from the ONOS Network Map\n"
-  usage_msg = usage_msg + "Usage: %s <begin-flow-id> <end-flow-id>\n" % (sys.argv[0])
-  usage_msg = usage_msg + "       %s <flow-id>\n" % (sys.argv[0])
-  usage_msg = usage_msg + "\n"
-  usage_msg = usage_msg + "    Arguments:\n"
-  usage_msg = usage_msg + "        <begin-flow-id> <end-flow-id>      Clear all flows in the flow ID range\n"
-  usage_msg = usage_msg + "        <flow-id>                          Clear a single flow with the flow ID\n"
-  usage_msg = usage_msg + "        all                                Clear all flows\n"
-
-  # app.debug = False;
-
-  # Usage info
-  if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
-    print(usage_msg)
-    exit(0)
-
-  # Check arguments
-  if len(sys.argv) < 2:
-    log_error(usage_msg)
-    exit(1)
-
-  if (sys.argv[1] == "all"):
-    clear_flow_path(sys.argv[1])
-  else:
-    begin_flow_id = int(sys.argv[1], 0)
-    if len(sys.argv) >= 3:
-      end_flow_id = int(sys.argv[2], 0)
-    else:
-      end_flow_id = begin_flow_id
-
-    # Do the work
-    flow_id = begin_flow_id
-    while flow_id <= end_flow_id:
-      clear_flow_path(flow_id)
-      flow_id = flow_id + 1
diff --git a/web/flowsync.py b/web/flowsync.py
new file mode 100755
index 0000000..51399d5
--- /dev/null
+++ b/web/flowsync.py
@@ -0,0 +1,103 @@
+#! /usr/bin/env python
+
+
+import pprint
+import os
+import sys
+import subprocess
+import json
+import argparse
+import io
+import time
+
+from flask import Flask, json, Response, render_template, make_response, request
+
+## Global Var ##
+ControllerIP="127.0.0.1"
+ControllerPort=8080
+
+DEBUG=0
+pp = pprint.PrettyPrinter(indent=4)
+
+app = Flask(__name__)
+
+## Worker Functions ##
+def log_error(txt):
+  print '%s' % (txt)
+
+def debug(txt):
+  if DEBUG:
+    print '%s' % (txt)
+
+# @app.route("/wm/fprog/synchronizer/sync/<dpid>/json")
+# Sample output:
+#  "true"
+def synchronize(dpid):
+  try:
+    command = "curl -s \"http://%s:%s/wm/fprog/synchronizer/sync/%s/json\"" % (ControllerIP, ControllerPort, dpid)
+    debug("synchronize %s" % command)
+     
+    result = os.popen(command).read()
+    debug("result %s" % result)
+    if result == "false":
+      print "Failed to synchronize"
+      return;
+  except:
+    log_error("Controller IF has issue")
+    exit(1)
+  
+  print "Synchronization of switch %s has successfully began" % (dpid)
+
+# @app.route("/wm/fprog/synchronizer/interrupt/<dpid>/json")
+# Sample output:
+#  "true"
+def interrupt(dpid):
+  try:
+    command = "curl -s \"http://%s:%s/wm/fprog/synchronizer/interrupt/%s/json\"" % (ControllerIP, ControllerPort, dpid)
+    debug("interrupt %s" % command)
+     
+    result = os.popen(command).read()
+    debug("result %s" % result)
+    if result == "false":
+      print "Failed to interrupt synchronization"
+      return;
+  except:
+    log_error("Controller IF has issue")
+    exit(1)
+  
+  print "Synchronization of switch %s has successfully interrupted" % (dpid)
+
+
+if __name__ == "__main__":
+  usage_msg1 = "Usage:\n"
+  usage_msg2 = "%s sync <dpid>      : Start synchronization of the switch\n" % (sys.argv[0])
+  usage_msg3 = "                interrupt <dpid> : Interrupt synchronization of the switch\n"
+  usage_msg = usage_msg1 + usage_msg2 + usage_msg3;
+  
+  app.debug = True;
+
+  # Usage info
+  if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
+    print(usage_msg)
+    exit(0)
+
+  # Check arguments
+  if len(sys.argv) < 2:
+    log_error(usage_msg)
+    exit(1)
+
+  # Do the work
+  if sys.argv[1] == "sync":
+    if len(sys.argv) < 3:
+      log_error(usage_msg)
+      exit(1)
+    synchronize(sys.argv[2])
+  elif sys.argv[1] == "interrupt":
+    if len(sys.argv) < 3:
+      log_error(usage_msg)
+      exit(1)
+    interrupt(sys.argv[2])
+  else:
+    log_error(usage_msg)
+    exit(1)
+ 
\ No newline at end of file
diff --git a/web/get_flow.py b/web/get_flow.py
index c45d853..94b9a61 100755
--- a/web/get_flow.py
+++ b/web/get_flow.py
@@ -164,6 +164,8 @@
   flowPathType = parsedResult['flowPathType']
   flowPathUserState = parsedResult['flowPathUserState']
   flowPathFlags = parsedResult['flowPathFlags']['flags']
+  idleTimeout = parsedResult['idleTimeout']
+  hardTimeout = parsedResult['hardTimeout']
   srcSwitch = parsedResult['dataPath']['srcPort']['dpid']['value']
   srcPort = parsedResult['dataPath']['srcPort']['port']['value']
   dstSwitch = parsedResult['dataPath']['dstPort']['dpid']['value']
@@ -181,7 +183,7 @@
       flowPathFlagsStr += ","
     flowPathFlagsStr += "KEEP_ONLY_FIRST_HOP_ENTRY"
 
-  print "FlowPath: (flowId = %s installerId = %s flowPathType = %s flowPathUserState = %s flowPathFlags = 0x%x(%s) src = %s/%s dst = %s/%s)" % (flowId, installerId, flowPathType, flowPathUserState, flowPathFlags, flowPathFlagsStr, srcSwitch, srcPort, dstSwitch, dstPort)
+  print "FlowPath: (flowId = %s installerId = %s flowPathType = %s flowPathUserState = %s flowPathFlags = 0x%x(%s) src = %s/%s dst = %s/%s idleTimeout = %s hardTimeout = %s)" % (flowId, installerId, flowPathType, flowPathUserState, flowPathFlags, flowPathFlagsStr, srcSwitch, srcPort, dstSwitch, dstPort, idleTimeout, hardTimeout)
 
   #
   # Print the common match conditions
@@ -205,13 +207,15 @@
   #
   for f in parsedResult['dataPath']['flowEntries']:
     flowEntryId = f['flowEntryId']
+    idleTimeout = f['idleTimeout']
+    hardTimeout = f['hardTimeout']
     dpid = f['dpid']['value']
     userState = f['flowEntryUserState']
     switchState = f['flowEntrySwitchState']
     match = f['flowEntryMatch'];
     actions = f['flowEntryActions']['actions']
 
-    print "  FlowEntry: (%s, %s, %s, %s)" % (flowEntryId, dpid, userState, switchState)
+    print "  FlowEntry: (%s, %s, %s, %s, idleTimeout = %s, hardTimeout = %s)" % (flowEntryId, dpid, userState, switchState, idleTimeout, hardTimeout)
 
     #
     # Print the match conditions
@@ -250,48 +254,6 @@
   print_flow_path(parsedResult)
 
 
-def get_installer_flow_paths(installer_id, v1, p1, v2, p2):
-  try:
-    command = "curl -s \"http://%s:%s/wm/flow/getall-by-installer-id/%s/%s/%s/%s/%s/json\"" % (ControllerIP, ControllerPort, installer_id, v1, p1, v2, p2)
-    debug("get_installer_flow_paths %s" % command)
-
-    result = os.popen(command).read()
-    debug("result %s" % result)
-    if len(result) == 0:
-	print "No Flows found"
-	return;
-
-    parsedResult = json.loads(result)
-    debug("parsed %s" % parsedResult)
-  except:
-    log_error("Controller IF has issue")
-    exit(1)
-
-  for flowPath in parsedResult:
-    print_flow_path(flowPath)
-
-
-def get_endpoints_flow_paths(v1, p1, v2, p2):
-  try:
-    command = "curl -s \"http://%s:%s/wm/flow/getall-by-endpoints/%s/%s/%s/%s/json\"" % (ControllerIP, ControllerPort, v1, p1, v2, p2)
-    debug("get_endpoints_flow_paths %s" % command)
-
-    result = os.popen(command).read()
-    debug("result %s" % result)
-    if len(result) == 0:
-	print "No Flows found"
-	return;
-
-    parsedResult = json.loads(result)
-    debug("parsed %s" % parsedResult)
-  except:
-    log_error("Controller IF has issue")
-    exit(1)
-
-  for flowPath in parsedResult:
-    print_flow_path(flowPath)
-
-
 def get_all_flow_paths():
   try:
     command = "curl -s \"http://%s:%s/wm/flow/getall/json\"" % (ControllerIP, ControllerPort)
@@ -316,9 +278,7 @@
   usage_msg1 = "Usage:\n"
   usage_msg2 = "%s <flow_id> : Print flow with Flow ID of <flow_id>\n" % (sys.argv[0])
   usage_msg3 = "                   all    : Print all flows\n"
-  usage_msg4 = "                   installer <installer-id> <src-dpid> <src-port> <dest-dpid> <dest-port>\n"
-  usage_msg5 = "                   endpoints <src-dpid> <src-port> <dest-dpid> <dest-port>"
-  usage_msg = usage_msg1 + usage_msg2 + usage_msg3 + usage_msg4 + usage_msg5;
+  usage_msg = usage_msg1 + usage_msg2 + usage_msg3;
 
   # app.debug = False;
 
@@ -335,17 +295,5 @@
   # Do the work
   if sys.argv[1] == "all":
     get_all_flow_paths()
-  elif sys.argv[1] == "installer":
-    if len(sys.argv) < 7:
-      log_error(usage_msg)
-      exit(1)
-    get_installer_flow_paths(sys.argv[2], sys.argv[3], sys.argv[4],
-			     sys.argv[5], sys.argv[6])
-  elif sys.argv[1] == "endpoints":
-    if len(sys.argv) < 6:
-      log_error(usage_msg)
-      exit(1)
-    get_endpoints_flow_paths(sys.argv[2], sys.argv[3], sys.argv[4],
-			     sys.argv[5])
   else:
     get_flow_path(sys.argv[1])
diff --git a/web/ons-demo/js/app.js b/web/ons-demo/js/app.js
index 94c41e2..d869de7 100644
--- a/web/ons-demo/js/app.js
+++ b/web/ons-demo/js/app.js
@@ -1,6 +1,17 @@
 /*global d3, document∆*/
 
 
+function updateFlow(model) {
+    model.flows.forEach(function (flow) {
+	flow.flowId = flow.flowId.value;
+	flow.installerId = flow.installerId.value;
+	flow.dstDpid = flow.dataPath.dstPort.dpid.value;
+	flow.srcDpid = flow.dataPath.srcPort.dpid.value;
+	flow.dstPort = flow.dataPath.dstPort.port.value;
+	flow.srcPort = flow.dataPath.srcPort.port.value;
+    });
+}
+
 function sync() {
 	var d = Date.now();
 
@@ -8,6 +19,7 @@
 //		console.log('Update time: ' + (Date.now() - d)/1000 + 's');
 
 		if (newModel) {
+			updateFlow(newModel);
 			var modelChanged = false;
 			var newModelString = JSON.stringify(newModel);
 			if (!modelString || newModelString != modelString) {
diff --git a/web/pusher.py b/web/pusher.py
new file mode 100755
index 0000000..2a3528b
--- /dev/null
+++ b/web/pusher.py
@@ -0,0 +1,152 @@
+#! /usr/bin/env python
+
+
+import pprint
+import os
+import sys
+import subprocess
+import json
+import argparse
+import io
+import time
+
+from flask import Flask, json, Response, render_template, make_response, request
+
+## Global Var ##
+ControllerIP="127.0.0.1"
+ControllerPort=8080
+
+DEBUG=0
+pp = pprint.PrettyPrinter(indent=4)
+
+app = Flask(__name__)
+
+## Worker Functions ##
+def log_error(txt):
+  print '%s' % (txt)
+
+def debug(txt):
+  if DEBUG:
+    print '%s' % (txt)
+
+# @app.route("/wm/fprog/pusher/setrate/<dpid>/<rate>/json")
+# Sample output:
+#  "true"
+def set_rate(dpid,rate):
+  try:
+    command = "curl -s \"http://%s:%s/wm/fprog/pusher/setrate/%s/%s/json\"" % (ControllerIP, ControllerPort, dpid, rate)
+    debug("set_rate %s" % command)
+     
+    result = os.popen(command).read()
+    debug("result %s" % result)
+    if result == "false":
+      print "Failed to set rate"
+      return;
+  except:
+    log_error("Controller IF has issue")
+    exit(1)
+  
+  print "Sending rate to %s is successfully set to %s" % (dpid, rate)
+
+# @app.route("/wm/fprog/pusher/suspend/<dpid>/json")
+# Sample output:
+#  "true"
+def suspend(dpid):
+  try:
+    command = "curl -s \"http://%s:%s/wm/fprog/pusher/suspend/%s/json\"" % (ControllerIP, ControllerPort, dpid)
+    debug("suspend %s" % command)
+     
+    result = os.popen(command).read()
+    debug("result %s" % result)
+    if result == "false":
+      print "Failed to suspend"
+      return;
+  except:
+    log_error("Controller IF has issue")
+    exit(1)
+  
+  print "DPID %s is successfully suspended" % dpid
+
+# @app.route("/wm/fprog/pusher/resume/<dpid>/json")
+# Sample output:
+#  "true"
+def resume(dpid):
+  try:
+    command = "curl -s \"http://%s:%s/wm/fprog/pusher/resume/%s/json\"" % (ControllerIP, ControllerPort, dpid)
+    debug("resume %s" % command)
+     
+    result = os.popen(command).read()
+    debug("result %s" % result)
+    if result == "false":
+      print "Failed to resume"
+      return;
+  except:
+    log_error("Controller IF has issue")
+    exit(1)
+  
+  print "DPID %s is successfully resumed" % dpid
+
+# @app.route("/wm/fprog/pusher/barrier/<dpid>/json")
+# Sample output:
+#  "{"version":1,"type":"BARRIER_REPLY","length":8,"xid":4,"lengthU":8}"
+def barrier(dpid):
+  try:
+    command = "curl -s \"http://%s:%s/wm/fprog/pusher/barrier/%s/json\"" % (ControllerIP, ControllerPort, dpid)
+    debug("barrier %s" % command)
+     
+    result = os.popen(command).read()
+    debug("result %s" % result)
+    if result == "false":
+      print "Failed to send barrier"
+      return;
+  except:
+    log_error("Controller IF has issue")
+    exit(1)
+  
+  print "Barrier reply from %s : %s" % (dpid, result)
+
+
+if __name__ == "__main__":
+  usage_msg1 = "Usage:\n"
+  usage_msg2 = "%s rate <dpid> <rate> : Set sending rate[bytes/ms] to the switch\n" % (sys.argv[0])
+  usage_msg3 = "                   suspend <dpid>    : Suspend sending message to the switch\n"
+  usage_msg4 = "                   resume <dpid>     : Resume sending message to the switch\n"
+  usage_msg5 = "                   barrier <dpid>    : Send barrier message to the switch\n"
+  usage_msg = usage_msg1 + usage_msg2 + usage_msg3 + usage_msg4 + usage_msg5;
+
+  app.debug = True;
+
+  # Usage info
+  if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
+    print(usage_msg)
+    exit(0)
+
+  # Check arguments
+  if len(sys.argv) < 2:
+    log_error(usage_msg)
+    exit(1)
+
+  # Do the work
+  if sys.argv[1] == "rate":
+    if len(sys.argv) < 4:
+      log_error(usage_msg)
+      exit(1)
+    set_rate(sys.argv[2], sys.argv[3])
+  elif sys.argv[1] == "suspend":
+    if len(sys.argv) < 3:
+      log_error(usage_msg)
+      exit(1)
+    suspend(sys.argv[2])
+  elif sys.argv[1] == "resume":
+    if len(sys.argv) < 3:
+      log_error(usage_msg)
+      exit(1)
+    resume(sys.argv[2])
+  elif sys.argv[1] == "barrier":
+    if len(sys.argv) < 3:
+      log_error(usage_msg)
+      exit(1)
+    barrier(sys.argv[2])
+  else:
+    log_error(usage_msg)
+    exit(1)
diff --git a/web/topology_rest.py b/web/topology_rest.py
index bac3113..b3a415e 100755
--- a/web/topology_rest.py
+++ b/web/topology_rest.py
@@ -720,8 +720,8 @@
 #    print "Debug: Controller command %s called %s" % (cmd, controller_name)
   else:
     # No longer use -i to specify keys (use .ssh/config to specify it)
-    start_onos="ssh %s ONOS/start-onos.sh start" % (controller_name)
-    stop_onos="ssh %s ONOS/start-onos.sh stop" % (controller_name)
+    start_onos="ssh %s \"cd ONOS; ./start-onos.sh start\"" % (controller_name)
+    stop_onos="ssh %s \"cd ONOS; ./start-onos.sh stop\"" % (controller_name)
 #    start_onos="ssh -i ~/.ssh/onlabkey.pem %s ONOS/start-onos.sh start" % (controller_name)
 #    stop_onos="ssh -i ~/.ssh/onlabkey.pem %s ONOS/start-onos.sh stop" % (controller_name)
 
@@ -960,7 +960,7 @@
   parsedResult = json.loads(result)
   if len(parsedResult) > 0:
     if parsedResult[-1].has_key('flowId'):
-      flow_nr = int(parsedResult[-1]['flowId'], 16)
+      flow_nr = int(parsedResult[-1]['flowId']['value'], 16)
   else:
     flow_nr = -1  # first flow
     print "first flow"