Merge branch 'topodev' of https://github.com/n-shiota/ONOS into topodev
diff --git a/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java b/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
index 33091b9..effbe81 100644
--- a/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
+++ b/src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
@@ -73,6 +73,12 @@
     private MapFlowEntryListener mapFlowEntryListener = null;
     private String mapFlowEntryListenerId = null;
 
+    // State related to the Flow ID map
+    protected static final String mapFlowIdName = "mapFlowId";
+    private IMap<Long, byte[]> mapFlowId = null;
+    private MapFlowIdListener mapFlowIdListener = null;
+    private String mapFlowIdListenerId = null;
+
     // State related to the Network Topology map
     protected static final String mapTopologyName = "mapTopology";
     private IMap<String, byte[]> mapTopology = null;
@@ -238,6 +244,78 @@
     }
 
     /**
+     * Class for receiving notifications for FlowId state.
+     *
+     * The datagrid map is:
+     *  - Key : FlowId (Long)
+     *  - Value : Serialized FlowId (byte[])
+     */
+    class MapFlowIdListener implements EntryListener<Long, byte[]> {
+	/**
+	 * Receive a notification that an entry is added.
+	 *
+	 * @param event the notification event for the entry.
+	 */
+	public void entryAdded(EntryEvent<Long, byte[]> event) {
+	    byte[] valueBytes = (byte[])event.getValue();
+
+	    //
+	    // Decode the value and deliver the notification
+	    //
+	    Kryo kryo = kryoFactory.newKryo();
+	    Input input = new Input(valueBytes);
+	    FlowId flowId = kryo.readObject(input, FlowId.class);
+	    kryoFactory.deleteKryo(kryo);
+	    flowEventHandlerService.notificationRecvFlowIdAdded(flowId);
+	}
+
+	/**
+	 * Receive a notification that an entry is removed.
+	 *
+	 * @param event the notification event for the entry.
+	 */
+	public void entryRemoved(EntryEvent<Long, byte[]> event) {
+	    byte[] valueBytes = (byte[])event.getValue();
+
+	    //
+	    // Decode the value and deliver the notification
+	    //
+	    Kryo kryo = kryoFactory.newKryo();
+	    Input input = new Input(valueBytes);
+	    FlowId flowId = kryo.readObject(input, FlowId.class);
+	    kryoFactory.deleteKryo(kryo);
+	    flowEventHandlerService.notificationRecvFlowIdRemoved(flowId);
+	}
+
+	/**
+	 * Receive a notification that an entry is updated.
+	 *
+	 * @param event the notification event for the entry.
+	 */
+	public void entryUpdated(EntryEvent<Long, byte[]> event) {
+	    byte[] valueBytes = (byte[])event.getValue();
+
+	    //
+	    // Decode the value and deliver the notification
+	    //
+	    Kryo kryo = kryoFactory.newKryo();
+	    Input input = new Input(valueBytes);
+	    FlowId flowId = kryo.readObject(input, FlowId.class);
+	    kryoFactory.deleteKryo(kryo);
+	    flowEventHandlerService.notificationRecvFlowIdUpdated(flowId);
+	}
+
+	/**
+	 * Receive a notification that an entry is evicted.
+	 *
+	 * @param event the notification event for the entry.
+	 */
+	public void entryEvicted(EntryEvent<Long, byte[]> event) {
+	    // NOTE: We don't use eviction for this map
+	}
+    }
+
+    /**
      * Class for receiving notifications for Network Topology state.
      *
      * The datagrid map is:
@@ -521,6 +599,11 @@
 	mapFlowEntry = hazelcastInstance.getMap(mapFlowEntryName);
 	mapFlowEntryListenerId = mapFlowEntry.addEntryListener(mapFlowEntryListener, true);
 
+	// Initialize the FlowId-related map state
+	mapFlowIdListener = new MapFlowIdListener();
+	mapFlowId = hazelcastInstance.getMap(mapFlowIdName);
+	mapFlowIdListenerId = mapFlowId.addEntryListener(mapFlowIdListener, true);
+
 	// Initialize the Topology-related map state
 	mapTopologyListener = new MapTopologyListener();
 	mapTopology = hazelcastInstance.getMap(mapTopologyName);
@@ -548,6 +631,11 @@
 	mapFlowEntry = null;
 	mapFlowEntryListener = null;
 
+	// Clear the FlowId-related map state
+	mapFlowId.removeEntryListener(mapFlowIdListenerId);
+	mapFlowId = null;
+	mapFlowIdListener = null;
+
 	// Clear the Topology-related map state
 	mapTopology.removeEntryListener(mapTopologyListenerId);
 	mapTopology = null;
@@ -805,6 +893,101 @@
     }
 
     /**
+     * Get all Flow IDs that are currently in the datagrid.
+     *
+     * @return all Flow IDs that are currently in the datagrid.
+     */
+    @Override
+    public Collection<FlowId> getAllFlowIds() {
+	Collection<FlowId> allFlowIds = new LinkedList<FlowId>();
+
+	//
+	// Get all current entries
+	//
+	Collection<byte[]> values = mapFlowId.values();
+	Kryo kryo = kryoFactory.newKryo();
+	for (byte[] valueBytes : values) {
+	    //
+	    // Decode the value
+	    //
+	    Input input = new Input(valueBytes);
+	    FlowId flowId = kryo.readObject(input, FlowId.class);
+	    allFlowIds.add(flowId);
+	}
+	kryoFactory.deleteKryo(kryo);
+
+	return allFlowIds;
+    }
+
+    /**
+     * Send a notification that a FlowId is added.
+     *
+     * @param flowId the FlowId that is added.
+     */
+    @Override
+    public void notificationSendFlowIdAdded(FlowId flowId) {
+	//
+	// Encode the value
+	//
+	byte[] buffer = new byte[MAX_BUFFER_SIZE];
+	Kryo kryo = kryoFactory.newKryo();
+	Output output = new Output(buffer, -1);
+	kryo.writeObject(output, flowId);
+	byte[] valueBytes = output.toBytes();
+	kryoFactory.deleteKryo(kryo);
+
+	//
+	// Put the entry:
+	//  - Key : FlowId (Long)
+	//  - Value : Serialized FlowId (byte[])
+	//
+	mapFlowId.putAsync(flowId.value(), valueBytes);
+    }
+
+    /**
+     * Send a notification that a FlowId is removed.
+     *
+     * @param flowId the FlowId that is removed.
+     */
+    @Override
+    public void notificationSendFlowIdRemoved(FlowId flowId) {
+	//
+	// Remove the entry:
+	//  - Key : FlowId (Long)
+	//  - Value : Serialized FlowId (byte[])
+	//
+	mapFlowId.removeAsync(flowId.value());
+    }
+
+    /**
+     * Send a notification that a FlowId is updated.
+     *
+     * @param flowId the FlowId that is updated.
+     */
+    @Override
+    public void notificationSendFlowIdUpdated(FlowId flowId) {
+	// NOTE: Adding an entry with an existing key automatically updates it
+	notificationSendFlowIdAdded(flowId);
+    }
+
+    /**
+     * Send a notification that all Flow IDs are removed.
+     */
+    @Override
+    public void notificationSendAllFlowIdsRemoved() {
+	//
+	// Remove all entries
+	// NOTE: We remove the entries one-by-one so the per-entry
+	// notifications will be delivered.
+	//
+	// mapFlowId.clear();
+	Set<Long> keySet = mapFlowId.keySet();
+	for (Long key : keySet) {
+	    mapFlowId.removeAsync(key);
+	}
+    }
+
+    /**
      * Get all Topology Elements that are currently in the datagrid.
      *
      * @return all Topology Elements that are currently in the datagrid.
diff --git a/src/main/java/net/onrc/onos/datagrid/IDatagridService.java b/src/main/java/net/onrc/onos/datagrid/IDatagridService.java
index 0f03d77..d4e7b00 100644
--- a/src/main/java/net/onrc/onos/datagrid/IDatagridService.java
+++ b/src/main/java/net/onrc/onos/datagrid/IDatagridService.java
@@ -134,6 +134,39 @@
     void notificationSendAllFlowEntriesRemoved();
 
     /**
+     * Get all Flow IDs that are currently in the datagrid.
+     *
+     * @return all Flow IDs that are currently in the datagrid.
+     */
+    Collection<FlowId> getAllFlowIds();
+
+    /**
+     * Send a notification that a FlowId is added.
+     *
+     * @param flowId the FlowId that is added.
+     */
+    void notificationSendFlowIdAdded(FlowId flowId);
+
+    /**
+     * Send a notification that a FlowId is removed.
+     *
+     * @param flowId the FlowId that is removed.
+     */
+    void notificationSendFlowIdRemoved(FlowId flowId);
+
+    /**
+     * Send a notification that a FlowId is updated.
+     *
+     * @param flowId the FlowId that is updated.
+     */
+    void notificationSendFlowIdUpdated(FlowId flowId);
+
+    /**
+     * Send a notification that all Flow IDs are removed.
+     */
+    void notificationSendAllFlowIdsRemoved();
+
+    /**
      * Get all Topology Elements that are currently in the datagrid.
      *
      * @return all Topology Elements that are currently in the datagrid.
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 8b1f7c0..4c801d6 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
@@ -14,6 +14,7 @@
 
 import net.floodlightcontroller.core.IOFSwitch;
 import net.onrc.onos.datagrid.IDatagridService;
+import net.onrc.onos.graph.GraphDBOperation;
 import net.onrc.onos.ofcontroller.topology.Topology;
 import net.onrc.onos.ofcontroller.topology.TopologyElement;
 import net.onrc.onos.ofcontroller.topology.TopologyManager;
@@ -46,7 +47,11 @@
 class FlowEventHandler extends Thread implements IFlowEventHandlerService {
     /** The logger. */
     private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
+    
+    // Flag to enable feature of acquiring topology information from DB instead of datagrid.
+    private final boolean accessDBFlag = false;
 
+    private GraphDBOperation dbHandler;
     private FlowManager flowManager;		// The Flow Manager to use
     private IDatagridService datagridService;	// The Datagrid Service to use
     private Topology topology;			// The network topology
@@ -63,6 +68,8 @@
 	new LinkedList<EventEntry<FlowPath>>();
     private List<EventEntry<FlowEntry>> flowEntryEvents =
 	new LinkedList<EventEntry<FlowEntry>>();
+    private List<EventEntry<FlowId>> flowIdEvents =
+	new LinkedList<EventEntry<FlowId>>();
 
     // All internally computed Flow Paths
     private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
@@ -91,10 +98,12 @@
      * @param datagridService the Datagrid Service to use.
      */
     FlowEventHandler(FlowManager flowManager,
-		     IDatagridService datagridService) {
+		     IDatagridService datagridService,
+		     GraphDBOperation dbHandler) {
 	this.flowManager = flowManager;
 	this.datagridService = datagridService;
 	this.topology = new Topology();
+	this.dbHandler = dbHandler;
     }
 
     /**
@@ -137,6 +146,16 @@
 	    flowEntryEvents.add(eventEntry);
 	}
 
+	//
+	// Obtain the initial FlowId state
+	//
+	Collection<FlowId> flowIds = datagridService.getAllFlowIds();
+	for (FlowId flowId : flowIds) {
+	    EventEntry<FlowId> eventEntry =
+		new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
+	    flowIdEvents.add(eventEntry);
+	}
+
 	// Process the initial events (if any)
 	synchronized (allFlowPaths) {
 	    processEvents();
@@ -166,12 +185,14 @@
 		//  - EventEntry<TopologyElement>
 		//  - EventEntry<FlowPath>
 		//  - EventEntry<FlowEntry>
+		//  - EventEntry<FlowId>
 		//
 		for (EventEntry<?> event : collection) {
 		    // Topology event
 		    if (event.eventData() instanceof TopologyElement) {
 			EventEntry<TopologyElement> topologyEventEntry =
 			    (EventEntry<TopologyElement>)event;
+			
 			topologyEvents.add(topologyEventEntry);
 			continue;
 		    }
@@ -191,6 +212,14 @@
 			flowEntryEvents.add(flowEntryEventEntry);
 			continue;
 		    }
+
+		    // FlowId event
+		    if (event.eventData() instanceof FlowId) {
+			EventEntry<FlowId> flowIdEventEntry =
+			    (EventEntry<FlowId>)event;
+			flowIdEvents.add(flowIdEventEntry);
+			continue;
+		    }
 		}
 		collection.clear();
 
@@ -203,7 +232,7 @@
 	    log.debug("Exception processing Network Events: ", exception);
 	}
     }
-
+    
     /**
      * Process the events (if any)
      */
@@ -215,6 +244,7 @@
 	    return;		// Nothing to do
 	}
 
+	processFlowIdEvents();
 	processFlowPathEvents();
 	processTopologyEvents();
 	processUnmatchedFlowEntryAdd();
@@ -254,6 +284,7 @@
 	topologyEvents.clear();
 	flowPathEvents.clear();
 	flowEntryEvents.clear();
+	flowIdEvents.clear();
 	//
 	shouldRecomputeFlowPaths.clear();
 	modifiedFlowPaths.clear();
@@ -346,6 +377,41 @@
     }
 
     /**
+     * Process the Flow ID events.
+     */
+    private void processFlowIdEvents() {
+	//
+	// Process all Flow ID events and update the appropriate state
+	//
+	for (EventEntry<FlowId> eventEntry : flowIdEvents) {
+	    FlowId flowId = eventEntry.eventData();
+
+	    log.debug("Flow ID Event: {} {}", eventEntry.eventType(), flowId);
+
+	    switch (eventEntry.eventType()) {
+	    case ENTRY_ADD: {
+		//
+		// Add a new Flow ID
+		//
+		// TODO: Implement it!
+
+		break;
+	    }
+
+	    case ENTRY_REMOVE: {
+		//
+		// Remove an existing Flow ID.
+		//
+		// TODO: Implement it!
+
+		break;
+	    }
+	    }
+	}
+    }
+
+
+    /**
      * Process the Flow Path events.
      */
     private void processFlowPathEvents() {
@@ -435,20 +501,28 @@
 	// Process all Topology events and update the appropriate state
 	//
 	boolean isTopologyModified = false;
-	for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
-	    TopologyElement topologyElement = eventEntry.eventData();
+	if (accessDBFlag) {
+		log.debug("[BEFORE] {}", topology.toString());
+		if (! topology.readFromDatabase(dbHandler)) {
+			isTopologyModified = true;
+		}
+		log.debug("[AFTER] {}", topology.toString());
+	} else {
+		for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
+		    TopologyElement topologyElement = eventEntry.eventData();
+			
+		    log.debug("Topology Event: {} {}", eventEntry.eventType(),
+				      topologyElement.toString());
 
-	    log.debug("Topology Event: {} {}", eventEntry.eventType(),
-		      topologyElement);
-
-	    switch (eventEntry.eventType()) {
-	    case ENTRY_ADD:
-		isTopologyModified |= topology.addTopologyElement(topologyElement);
-		break;
-	    case ENTRY_REMOVE:
-		isTopologyModified |= topology.removeTopologyElement(topologyElement);
-		break;
-	    }
+		    switch (eventEntry.eventType()) {
+		    case ENTRY_ADD:
+			isTopologyModified |= topology.addTopologyElement(topologyElement);
+			break;
+		    case ENTRY_REMOVE:
+			isTopologyModified |= topology.removeTopologyElement(topologyElement);
+			break;
+		    }
+		}
 	}
 	if (isTopologyModified) {
 	    // TODO: For now, if the topology changes, we recompute all Flows
@@ -972,6 +1046,43 @@
     }
 
     /**
+     * Receive a notification that a FlowId is added.
+     *
+     * @param flowId the FlowId that is added.
+     */
+    @Override
+    public void notificationRecvFlowIdAdded(FlowId flowId) {
+	EventEntry<FlowId> eventEntry =
+	    new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
+	networkEvents.add(eventEntry);
+    }
+
+    /**
+     * Receive a notification that a FlowId is removed.
+     *
+     * @param flowId the FlowId that is removed.
+     */
+    @Override
+    public void notificationRecvFlowIdRemoved(FlowId flowId) {
+	EventEntry<FlowId> eventEntry =
+	    new EventEntry<FlowId>(EventEntry.Type.ENTRY_REMOVE, flowId);
+	networkEvents.add(eventEntry);
+    }
+
+    /**
+     * Receive a notification that a FlowId is updated.
+     *
+     * @param flowId the FlowId that is updated.
+     */
+    @Override
+    public void notificationRecvFlowIdUpdated(FlowId flowId) {
+	// NOTE: The ADD and UPDATE events are processed in same way
+	EventEntry<FlowId> eventEntry =
+	    new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
+	networkEvents.add(eventEntry);
+    }
+
+    /**
      * Receive a notification that a Topology Element is added.
      *
      * @param topologyElement the Topology Element that is added.
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 dd98f4e..1c9db0c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
@@ -224,7 +224,7 @@
 	//  - register with the Datagrid Service
 	//  - startup
 	//
-	flowEventHandler = new FlowEventHandler(this, datagridService);
+	flowEventHandler = new FlowEventHandler(this, datagridService, dbHandlerInner);
 	datagridService.registerFlowEventHandlerService(flowEventHandler);
 	flowEventHandler.start();
     }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowEventHandlerService.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowEventHandlerService.java
index 78562e1..62edf70 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowEventHandlerService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowEventHandlerService.java
@@ -2,6 +2,7 @@
 
 import net.onrc.onos.ofcontroller.topology.TopologyElement;
 import net.onrc.onos.ofcontroller.util.FlowEntry;
+import net.onrc.onos.ofcontroller.util.FlowId;
 import net.onrc.onos.ofcontroller.util.FlowPath;
 
 /**
@@ -51,6 +52,27 @@
     void notificationRecvFlowEntryUpdated(FlowEntry flowEntry);
 
     /**
+     * Receive a notification that a FlowId is added.
+     *
+     * @param flowId the FlowId that is added.
+     */
+    void notificationRecvFlowIdAdded(FlowId flowId);
+
+    /**
+     * Receive a notification that a FlowId is removed.
+     *
+     * @param flowId the FlowId that is removed.
+     */
+    void notificationRecvFlowIdRemoved(FlowId flowId);
+
+    /**
+     * Receive a notification that a FlowId is updated.
+     *
+     * @param flowId the FlowId that is updated.
+     */
+    void notificationRecvFlowIdUpdated(FlowId flowId);
+
+    /**
      * Receive a notification that a Topology Element is added.
      *
      * @param topologyElement the Topology Element that is added.
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 fc75591..dedb589 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/Topology.java
@@ -381,12 +381,18 @@
      * Read topology state from the database.
      *
      * @param dbHandler the Graph Database handler to use.
+     * @return true if topology is updated. In other words,
+     * 		topology read from database is different from current topology.
      */
-    public void readFromDatabase(GraphDBOperation dbHandler) {
+    public boolean readFromDatabase(GraphDBOperation dbHandler) {
 	//
 	// Fetch the relevant info from the Switch and Port vertices
 	// from the Titan Graph.
 	//
+    
+	Map<Long,Node> oldNodesMap = nodesMap;
+	nodesMap = new TreeMap<Long,Node>();
+	
 	Iterable<ISwitchObject> activeSwitches = dbHandler.getActiveSwitches();
 	for (ISwitchObject switchObj : activeSwitches) {
 	    Vertex nodeVertex = switchObj.asVertex();
@@ -450,5 +456,76 @@
 	    }
 	}
 	dbHandler.commit();
+	return ! compareTopology(oldNodesMap, nodesMap);
+    }
+    
+    // TODO Merge into loops in readFromDatabase() can reduce execution time.
+    /**
+     * Check given two topology are identical or not.
+     * @param topo1
+     * @param topo2
+     * @return true if identical
+     */
+    private boolean compareTopology(Map<Long,Node> topo1, Map<Long,Node> topo2) {
+    	if (topo1.size() != topo2.size()) {
+    		return false;
+    	}
+    	
+    	for (Map.Entry<Long,Node> nodeEntry : topo1.entrySet()) {
+    		Long dpid = nodeEntry.getKey();
+    		if (! topo2.containsKey(dpid)) {
+    			return false;
+    		}
+    		
+    		Node n1 = nodeEntry.getValue();
+    		Node n2 = topo2.get(dpid);
+    		
+    		// check port identity
+    		if (n1.ports().size() != n2.ports().size()) {
+    			return false;
+    		}
+    		for (Integer port : n1.ports().keySet()) {
+    			if (! n2.ports().containsKey(port)) {
+    				return false;
+    			}
+    		}
+    		
+    		// check link identity
+    		if (n1.links.size() != n2.links.size()) {
+    			return false;
+    		}
+    		for (Map.Entry<Integer, Node.Link> linkEntry : n1.links.entrySet()) {
+    			Integer p1 = linkEntry.getKey();
+    			Node.Link l1 = linkEntry.getValue();
+    			
+    			if (! n2.links.containsKey(p1)) {
+    				return false;
+    			}
+    			Node.Link l2 = n2.links.get(p1);
+    			
+    		   	// Supposition: Link's "me" and "neighbor" is properly set.
+    			if (l1.myPort != l2.myPort ||
+    				l1.neighborPort != l2.neighborPort) {
+    				return false;
+    			}
+    		}
+    	}
+    	return true;
+    }
+    
+    // Only for debug use
+    @Override
+    public String toString() {
+    	long numNodes = nodesMap.size();
+    	long numLinks = 0;
+    	for (Map.Entry<Long, Node> entry : nodesMap.entrySet()) {
+    		Node n = entry.getValue();
+    		for (Map.Entry<Integer, Node.Link> linkEntry : n.links.entrySet()) {
+    			if (n.nodeId > linkEntry.getValue().neighbor.nodeId) {
+    				++numLinks;
+    			}
+    		}
+    	}
+    	return "Topology has " + numNodes + " Nodes and " + numLinks + " Links.";
     }
 }