Merge in refactored FlowManager API which caused confict as I had updated Forwarding recently
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 a67ce7a..a96f5dc 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
@@ -31,15 +31,11 @@
     /**
      * 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 {
@@ -173,32 +169,25 @@
 	    if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE)
 		continue;	// Skip: all Flow Entries were deleted earlier
 
-	    if (addFlowEntry(flowManager, dbHandler, flowObj, flowEntry) == null) {
+	    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
@@ -507,91 +496,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.
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 feb80e1..47ef3b7 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
@@ -32,19 +32,6 @@
 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.
@@ -207,7 +194,7 @@
      * Process the events (if any)
      */
     private void processEvents() {
-	List<FlowPathEntryPair> modifiedFlowEntries;
+	Collection<FlowEntry> modifiedFlowEntries;
 
 	if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
 	    flowEntryEvents.isEmpty()) {
@@ -225,17 +212,16 @@
 	}
 
 	// Extract the modified Flow Entries
-	modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths);
+	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.pushModifiedFlowPathsToDatabase(modifiedFlowPaths.values());
+	flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
+					  modifiedFlowEntries);
 
 	//
 	// Remove Flow Entries that were deleted
@@ -254,20 +240,20 @@
 
     /**
      * Extract the modified Flow Entries.
+     *
+     * @param modifiedFlowPaths the Flow Paths to process.
+     * @return a collection with the modified Flow Entries.
      */
-    private List<FlowPathEntryPair> extractModifiedFlowEntries(
-				Map<Long, 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.values()) {
+	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);
 		}
 	    }
 	}
@@ -276,8 +262,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;
 
@@ -286,9 +275,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;
@@ -412,7 +399,6 @@
      * Process the Flow Entry events.
      */
     private void processFlowEntryEvents() {
-	FlowPathEntryPair flowPair;
 	FlowPath flowPath;
 	FlowEntry updatedFlowEntry;
 
@@ -431,7 +417,6 @@
 					 flowEntry);
 		    continue;
 		}
-		flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
 		modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
 	    }
 	    unmatchedFlowEntryAdd = remainingUpdates;
@@ -468,7 +453,6 @@
 		    break;
 		}
 		// Add the updated entry to the list of updated Flow Entries
-		flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
 		modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
 		break;
 
@@ -488,7 +472,6 @@
 		    // Flow Entry not found: ignore it
 		    break;
 		}
-		flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
 		modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
 		break;
 	    }
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 7f43fe9..f4b1f8f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
@@ -4,6 +4,7 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.Random;
 import java.util.concurrent.BlockingQueue;
@@ -210,11 +211,17 @@
      * 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.flowId().isValid()) {
+	    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.
@@ -228,35 +235,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;
     }
 
     /**
@@ -310,33 +293,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.
@@ -349,29 +305,6 @@
 	return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
 							maxFlows);
     }
-    
-    /**
-     * 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.
-	//
-
-	FlowId flowId = new FlowId();
-	if (! addFlow(flowPath, flowId))
-	    return null;
-
-	return (flowPath);
-    }
 
     /**
      * Get the collection of my switches.
@@ -402,6 +335,63 @@
     }
 
     /**
+     * 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) {
+
+	//
+	// Process all entries
+	//
+	for (Pair<IOFSwitch, FlowEntry> entry : entries) {
+	    IOFSwitch sw = entry.first;
+	    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;
+	    }
+	}
+    }
+
+    /**
+     * 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);
+    }
+
+    /**
      * Push modified Flow Entries to switches.
      *
      * NOTE: Only the Flow Entries to switches controlled by this instance
@@ -409,99 +399,88 @@
      *
      * @param modifiedFlowEntries the collection of modified Flow Entries.
      */
-    public void pushModifiedFlowEntriesToSwitches(
-			Collection<FlowPathEntryPair> modifiedFlowEntries) {
+    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) {
-	    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());
-
 	    //
-	    // Push the Flow Entry into the switch
+	    // Assign Flow Entry IDs if missing.
 	    //
-	    if (! pusher.add(mySwitch, flowEntry)) {
-		String logMsg = "Cannot install Flow Entry " +
-		    flowEntry.flowEntryId() +
-		    " from Flow Path " + flowEntry.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) {
+    private void cleanupDeletedFlowEntriesFromDatagrid(
+			Collection<FlowEntry> modifiedFlowEntries) {
 	if (modifiedFlowEntries.isEmpty())
 	    return;
 
 	Map<Long, IOFSwitch> mySwitches = getMySwitches();
 
-	for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
-	    FlowEntry flowEntry = flowPair.flowEntry;
-
+	for (FlowEntry flowEntry : modifiedFlowEntries) {
+	    //
+	    // Process only Flow Entries that should be deleted and have
+	    // a valid Flow Entry ID.
+	    //
 	    if (! flowEntry.isValidFlowEntryId())
 		continue;
-
-	    IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
-
-	    //
-	    // TODO: For now Flow Entries are removed by all instances,
-	    // even if this Flow Entry is 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.
-	    //
-	    if (mySwitch == null) {
-		if (flowEntry.flowEntryUserState() !=
-		    FlowEntryUserState.FE_USER_DELETE) {
-		    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());
 	}
     }
 
@@ -556,7 +535,7 @@
      *
      * @param modifiedFlowPaths the collection of Flow Paths to push.
      */
-    void pushModifiedFlowPathsToDatabase(
+    private void pushModifiedFlowPathsToDatabase(
 		Collection<FlowPath> modifiedFlowPaths) {
 	//
 	// We only add the Flow Paths to the Database Queue.
@@ -579,8 +558,6 @@
 	if (modifiedFlowPaths.isEmpty())
 	    return;
 
-	FlowId dummyFlowId = new FlowId();
-
 	Map<Long, IOFSwitch> mySwitches = getMySwitches();
 
 	for (FlowPath flowPath : modifiedFlowPaths) {
@@ -594,6 +571,27 @@
 		continue;
 
 	    //
+	    // Delete the Flow Path from the Network Map
+	    //
+	    if (flowPath.flowPathUserState() ==
+		FlowPathUserState.FP_USER_DELETE) {
+		log.debug("Deleting Flow Path From Database: {}",
+			  flowPath.toString());
+
+		try {
+		    if (! FlowDatabaseOperation.deleteFlow(
+					dbHandlerInner,
+					flowPath.flowId())) {
+			log.error("Cannot delete Flow Path {} from Network Map",
+				  flowPath.flowId());
+		    }
+		} catch (Exception e) {
+		    log.error("Exception deleting Flow Path from Network MAP: {}", e);
+		}
+		continue;
+	    }
+
+	    //
 	    // Test whether all Flow Entries are valid
 	    //
 	    boolean allValid = true;
@@ -616,8 +614,7 @@
 	    // Write the Flow Path to the Network Map
 	    //
 	    try {
-		if (! FlowDatabaseOperation.addFlow(this, dbHandlerInner,
-						    flowPath, dummyFlowId)) {
+		if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
 		    String logMsg = "Cannot write to Network Map Flow Path " +
 			flowPath.flowId();
 		    log.error(logMsg);
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 8d2b797..a25602d 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/IFlowService.java
@@ -1,15 +1,18 @@
 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.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.
@@ -18,14 +21,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.
@@ -58,25 +57,6 @@
     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
@@ -84,21 +64,6 @@
      * @return the Flow Paths if found, otherwise null.
      */
     ArrayList<FlowPath> 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);
 
     /**
      * Get the network topology.
@@ -106,7 +71,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.
@@ -122,4 +87,14 @@
      * @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/FlowWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java
index 81d26dd..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
@@ -20,8 +20,6 @@
         router.attach("/add-shortest-path/json", AddShortestPathFlowResource.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/flowprogrammer/FlowPusher.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
index 438f478..c3c7107 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
@@ -3,9 +3,11 @@
 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;
@@ -27,6 +29,7 @@
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.floodlightcontroller.util.MACAddress;
 import net.floodlightcontroller.util.OFMessageDamper;
+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;
@@ -35,6 +38,7 @@
 import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
 import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
 import net.onrc.onos.ofcontroller.util.IPv4Net;
+import net.onrc.onos.ofcontroller.util.Pair;
 import net.onrc.onos.ofcontroller.util.Port;
 
 /**
@@ -51,6 +55,7 @@
  */
 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).
@@ -267,6 +272,7 @@
 		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;
@@ -443,9 +449,46 @@
 
 		return true;
 	}
-	
+
 	@Override
-	public boolean add(IOFSwitch sw, 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
 		//
@@ -709,17 +752,7 @@
 				+ 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);
+		return add(sw, fm);
 	}
 	
 	@Override
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 c357e7c..7d5527b 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowSynchronizer.java
@@ -246,7 +246,7 @@
 		return;
 	    }
 
-	    pusher.add(sw, flowEntry);
+	    pusher.pushFlowEntry(sw, flowEntry);
 	}
 	
 	/**
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 2f550a7..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,5 +1,7 @@
 package net.onrc.onos.ofcontroller.flowprogrammer;
 
+import java.util.Collection;
+
 import org.openflow.protocol.OFBarrierReply;
 import org.openflow.protocol.OFMessage;
 
@@ -7,6 +9,7 @@
 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.
@@ -47,6 +50,9 @@
 	
 	/**
 	 * 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.
@@ -54,12 +60,28 @@
 	boolean add(IOFSwitch sw, OFMessage msg);
 
 	/**
-	 * Create a message from FlowEntry and add it to the queue of the switch.
+	 * 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.
 	 */
-	boolean add(IOFSwitch sw, FlowEntry flowEntry);
+	void pushFlowEntry(IOFSwitch sw, FlowEntry flowEntry);
 
 	/**
 	 * Set sending rate to a switch.
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
index 00d7fc9..22450f7 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/FlowProgrammerWebRoutable.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/FlowProgrammerWebRoutable.java
@@ -15,6 +15,8 @@
 		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;
 	}
 
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..b6dffd8 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java
@@ -186,10 +186,11 @@
 		
 		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());
@@ -199,8 +200,9 @@
 		// forwarding other stuff like ARP.
 		flowPath.flowEntryMatch().enableEthernetFrameType(Ethernet.TYPE_IPv4);
 		flowPath.setDataPath(dataPath);
-		
-		flowService.addFlow(flowPath, flowId);
+			
+		FlowId flowId = flowService.addFlow(flowPath);
+		//flowService.addFlow(flowPath, flowId);
 		
 		
 		DataPath reverseDataPath = new DataPath();
@@ -208,10 +210,10 @@
 		reverseDataPath.setSrcPort(dstSwitchPort);
 		reverseDataPath.setDstPort(srcSwitchPort);
 		
-		FlowId reverseFlowId = new FlowId(flowService.getNextFlowEntryId());
+		//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,9 +226,9 @@
 		reverseFlowPath.dataPath().srcPort().dpid().toString();
 		
 		// TODO what happens if no path exists?
-		flowService.addFlow(reverseFlowPath, reverseFlowId);
+		//flowService.addFlow(reverseFlowPath, reverseFlowId);
+		FlowId reverseFlowId = flowService.addFlow(reverseFlowPath);
 		
-
 		Port outPort = shortestPath.flowEntries().get(0).outPort();
 		forwardPacket(pi, sw, outPort.value());
 	}
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;
+    }
+}