Merge in Pavlin's changes from master
diff --git a/lib/jamm-0.2.5.jar b/lib/jamm-0.2.5.jar
new file mode 100644
index 0000000..ef8750d
--- /dev/null
+++ 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
index d552404..f0af050 100755
--- a/perf-scripts/flow-sync-perf.py
+++ b/perf-scripts/flow-sync-perf.py
@@ -31,6 +31,8 @@
   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():
@@ -42,7 +44,7 @@
   print "Doing nothing with %d flows..." % n
 
 def addFakeFlows(n):
-  print "Adding %d random flows..." % 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
@@ -56,19 +58,20 @@
 
 
 # ----------------- Utility Functions -------------------------
-def disconnect():
-  tail = Popen( "exec tail -0f ../onos-logs/onos.onosdev1.log", stdout=PIPE, shell=True )
-  tcp  = Popen( 'exec tcpkill -i lo -9 port 6633 > /dev/null 2>&1', shell=True )
-  tcp  = Popen( 'exec tcpkill -i lo -9 port 6633 > /tmp/tcp 2>&1', shell=True )
-  sleep(1)
-  tcp.kill()
-  results = waitForResult(tail)
-  tail.kill()
-  return results
+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-logs/onos.onosdev1.log' % ONOS_HOME )
+  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'
@@ -80,43 +83,71 @@
   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 )
+  #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)
-  count = 0
+  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():
-  call( '%s/web/delete_flow.py all' % ONOS_HOME, shell=True )
-  while True:
-    output = check_output( 'ovs-ofctl dump-flows s1', shell=True )
-    lines = len(output.split('\n'))
-    if lines == 2:
-      break
+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-logs/onos.onosdev1.log" % ONOS_HOME )
+  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
@@ -129,9 +160,9 @@
   tcp.terminate()
   tail.expect('Sync time \(ms\):', timeout=6000)
   tail.expect('([\d.]+,?)+\s')
-  print tail.match.group(0)
+  print "* Results:", tail.match.group(0)
   tail.terminate()
-  sleep(3)
+  wait(3, "Waiting for 3 seconds between tests")
   return tail.match.group(0).strip().split(',')
 
 def initResults(files):
@@ -144,7 +175,6 @@
 
 def outputResults(filename, n, results):
   results.insert(0, n)
-  print results
   with open(filename, 'a') as csvfile:
     writer = csv.writer(csvfile)
     writer.writerow(results)
@@ -154,12 +184,13 @@
               '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)
-  removeFlowsFromONOS() # clear ONOS before starting
-  sleep(30) # let ONOS "warm-up"
+  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))
@@ -168,18 +199,6 @@
     outputResults(fileMap['add'],    i, test(i, addFakeFlows)) # test needs empty DB
   net.stop()
 
-def waitForResult(tail):
-  while True:
-    line = tail.stdout.readline()
-    index = line.find('n.o.o.o.f.FlowSynchronizer')
-    if index > 0:
-      print line,
-    index = line.find('Sync time (ms):')
-    if index > 0:
-      line = line[index + 15:].strip()
-      line = line.replace('-->', '')
-      return line.split() # graph, switch, compare, total
-
 if __name__ == '__main__':
   setLogLevel( 'output' )
   resultDir = strftime( '%Y%m%d-%H%M%S' )
@@ -189,6 +208,3 @@
     tests = [1, 10, 100, 1000, 10000]
   runPerf( resultDir, tests )
 
-exit()
-
-# ---------------------------
diff --git a/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java b/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
index 775f952..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
 	}
     }
diff --git a/src/main/java/net/onrc/onos/graph/GraphDBOperation.java b/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
index bfd9046..316cde6 100644
--- a/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
+++ b/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
@@ -299,10 +299,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;
 	}
 
diff --git a/src/main/java/net/onrc/onos/graph/LocalTopologyEventListener.java b/src/main/java/net/onrc/onos/graph/LocalTopologyEventListener.java
index c34ba69..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 java.util.Map;
-
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
 
 import org.slf4j.Logger;
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/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/floodlightlistener/NetworkGraphPublisher.java b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
index 50fe8f8..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;
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 c8fd56f..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,10 +3,8 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.concurrent.ConcurrentLinkedQueue;
 
 import net.floodlightcontroller.util.MACAddress;
 
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 49ec46a..3538eb4 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
@@ -75,11 +75,14 @@
     // Transient state for processing the Flow Paths:
     //  - The Flow Paths that should be recomputed
     //  - The Flow Paths with modified Flow Entries
+    //  - The Flow Paths that we should check if installed in all switches
     //
     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.
@@ -239,6 +242,12 @@
 	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();
@@ -246,6 +255,44 @@
 	//
 	shouldRecomputeFlowPaths.clear();
 	modifiedFlowPaths.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);
     }
 
     /**
@@ -340,6 +387,9 @@
 		    }
 		    modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
 		    break;
+		case FP_TYPE_UNKNOWN:
+		    log.error("FlowPath event with unknown type");
+		    break;
 		}
 		allFlowPaths.put(flowPath.flowId().value(), flowPath);
 
@@ -526,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;
 	}
 
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 7ef49ef..41cf670 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
@@ -10,8 +10,6 @@
 import java.util.SortedMap;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
@@ -23,15 +21,13 @@
 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.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;
 
@@ -49,6 +45,7 @@
     protected FlowEventHandler flowEventHandler;
 
     protected IFlowPusherService pusher;
+    protected IForwardingService forwardingService;
     
     // Flow Entry ID generation state
     private static Random randomGenerator = new Random();
@@ -134,7 +131,8 @@
 	l.add(INetworkGraphService.class);
 	l.add(IDatagridService.class);
 	l.add(IRestApiService.class);
-		l.add(IFlowPusherService.class);
+	l.add(IFlowPusherService.class);
+	l.add(IForwardingService.class);
         return l;
     }
 
@@ -151,6 +149,7 @@
 	datagridService = context.getServiceImpl(IDatagridService.class);
 	restApi = context.getServiceImpl(IRestApiService.class);
 	pusher = context.getServiceImpl(IFlowPusherService.class);
+	forwardingService = context.getServiceImpl(IForwardingService.class);
 
 	this.init("");
     }
@@ -352,8 +351,25 @@
      * @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) {
-	// TODO: Not implemented yet
+    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
+
+	//
+	// Remove the Flow if the Flow Entry expired on the first switch
+	//
+	Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
+	if (srcDpid.value() != sw.getId())
+	    return;
+	deleteFlow(flowPath.flowId());
     }
 
     /**
@@ -370,7 +386,6 @@
 	// Process all entries
 	//
 	for (Pair<IOFSwitch, FlowEntry> entry : entries) {
-	    IOFSwitch sw = entry.first;
 	    FlowEntry flowEntry = entry.second;
 
 	    //
@@ -391,11 +406,24 @@
 	    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.
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 a25602d..549a0fc 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
@@ -6,8 +6,6 @@
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.module.IFloodlightService;
 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;
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 f7d7b0e..a4f0a8c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
@@ -42,7 +42,6 @@
 public class FlowProgrammer implements IFloodlightModule, 
 				       IOFMessageListener,
 				       IOFSwitchListener {
-    @SuppressWarnings("unused")
     // flag to enable FlowSynchronizer
     private static final boolean enableFlowSync = true;
     protected static Logger log = LoggerFactory.getLogger(FlowProgrammer.class);
@@ -155,8 +154,10 @@
     public void addedSwitch(IOFSwitch sw) {
 	log.debug("Switch added: {}", sw.getId());
 
-	if (enableFlowSync && registryService.hasControl(sw.getId())) {
-	    synchronizer.synchronize(sw);
+	if (enableFlowSync) {
+		if (registryService.hasControl(sw.getId())) {
+		    synchronizer.synchronize(sw);
+		}
 	}
     }
 
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 630d0f4..3f61248 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
@@ -34,7 +34,6 @@
 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.IPv4Net;
@@ -80,8 +79,9 @@
 	 * @author Naoki Shiota
 	 *
 	 */
-	@SuppressWarnings("serial")
 	private class SwitchQueue extends ArrayDeque<OFMessage> {
+		private static final long serialVersionUID = 1L;
+
 		QueueState state;
 		
 		// Max rate of sending message (bytes/ms). 0 implies no limitation.
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 64f6cac..6ef44be 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java
@@ -123,6 +123,7 @@
 	    graphEntryTime /= div;
 	    extractTime /= div;
 	    pushTime /= div;
+	    totalTime /= div;
 	    log.debug("Sync time (ms):" +
 	    		  graphIDTime + "," +
 	     		  switchTime + "," + 
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 2370936..c70d4db 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java
@@ -250,7 +250,6 @@
 				return;
 			}
 			
-			
 			log.debug("Adding new flow between {} at {} and {} at {}",
 					new Object[]{srcMacAddress, srcSwitchPort, dstMacAddress, dstSwitchPort});
 			
@@ -364,9 +363,15 @@
 		
 		return po;
 	}
-	
+
 	@Override
-	public void flowInstalled(FlowPath installedFlowPath) {
+	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();
diff --git a/src/main/java/net/onrc/onos/ofcontroller/forwarding/IForwardingService.java b/src/main/java/net/onrc/onos/ofcontroller/forwarding/IForwardingService.java
index 07f6733..e5bd714 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/forwarding/IForwardingService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/forwarding/IForwardingService.java
@@ -1,5 +1,7 @@
 package net.onrc.onos.ofcontroller.forwarding;
 
+import java.util.Collection;
+
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.onrc.onos.ofcontroller.util.FlowPath;
 
@@ -13,9 +15,11 @@
  */
 public interface IForwardingService extends IFloodlightService {
 	/**
-	 * Notify the Forwarding module that a flow has been installed
-	 * in the network. 
-	 * @param flowPath The FlowPath object describing the installed flow
+	 * 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 flowInstalled(FlowPath flowPath);
+	public void flowsInstalled(Collection<FlowPath> installedFlowPaths);
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscovery.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscovery.java
index 0b4437b..cdb71be 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscovery.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/ILinkDiscovery.java
@@ -3,7 +3,7 @@
 import net.floodlightcontroller.core.IUpdate;
 
 import org.codehaus.jackson.map.annotate.JsonSerialize;
-import org.codehaus.jackson.map.ser.ToStringSerializer;
+import org.codehaus.jackson.map.ser.std.ToStringSerializer;
 import org.openflow.util.HexString;
 
 public interface ILinkDiscovery {
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/ProxyArpManager.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
index 0b46778..415d697 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
@@ -375,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/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/FlowPathFlags.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java
index 4bbd399..97113ca 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,7 +119,7 @@
 		flagsStr += ",";
 	    flagsStr += "KEEP_ONLY_FIRST_HOP_ENTRY";
 	}
-	ret += "]";
+	ret += flagsStr + "]";
 
 	return ret;
     }
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 03418c8..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;
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 c54e89d..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,6 +136,7 @@
 		
 		return flowPaths;
 	}
+	*/
 	
 
 	// IFlowService methods
@@ -710,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 });
@@ -772,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/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/start-onos-embedded.sh b/start-onos-embedded.sh
index 25929c6..6fc9362 100755
--- a/start-onos-embedded.sh
+++ b/start-onos-embedded.sh
@@ -17,6 +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:$ONOS_HOME/lib/jamm-0.2.5.jar"
 JVM_OPTS="$JVM_OPTS -XX:CompileThreshold=1500 -XX:PreBlockSpin=8 \
 		-XX:+UseThreadPriorities \
 		-XX:ThreadPriorityPolicy=42 \
@@ -89,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