Work toward implementing Shortest Path Flow installation and
maintenance within ONOS itself.

This is a checkpoint commit. The new code is not used yet.
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index 405af1a..f49eec9 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -22,6 +22,7 @@
 import net.floodlightcontroller.core.INetMapStorage;
 import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
 import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
+import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
 import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
@@ -48,6 +49,7 @@
 import net.floodlightcontroller.util.OFMessageDamper;
 import net.floodlightcontroller.util.Port;
 import net.floodlightcontroller.util.SwitchPort;
+import net.onrc.onos.flow.IFlowManager;
 import net.onrc.onos.util.GraphDBConnection;
 import net.onrc.onos.util.GraphDBConnection.Transaction;
 
@@ -62,12 +64,13 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
+public class FlowManager implements IFloodlightModule, IFlowService, IFlowManager, INetMapStorage {
 
     public GraphDBConnection conn;
 
     protected IRestApiService restApi;
     protected IFloodlightProviderService floodlightProvider;
+    protected ITopoRouteService topoRouteService;
     protected FloodlightModuleContext context;
 
     protected OFMessageDamper messageDamper;
@@ -142,8 +145,6 @@
 		    return;
 		}
 
-		ITopoRouteService topoRouteService =
-		    context.getServiceImpl(ITopoRouteService.class);
 		if (topoRouteService == null) {
 		    log.debug("Topology Route Service not found");
 		    return;
@@ -310,7 +311,7 @@
 		//
 		// Process my Flow Entries
 		//
-		Boolean processed_measurement_flow = false;
+		boolean processed_measurement_flow = false;
 		for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
 		    IFlowEntry flowEntryObj = entry.getValue();
 		    // Code for measurement purpose
@@ -337,6 +338,7 @@
 		    if (mySwitch == null)
 			continue;		// Shouldn't happen
 
+		    // TODO: PAVPAVPAV: FROM HERE...
 		    //
 		    // Create the Open Flow Flow Modification Entry to push
 		    //
@@ -444,6 +446,9 @@
 		    } catch (IOException e) {
 			log.error("Failure writing flow mod from network map", e);
 		    }
+		    // TODO: XXX: PAVPAVPAV: TO HERE.
+		    // TODO: XXX: PAVPAVPAV: Update the flowEntryObj
+		    // to "FE_SWITCH_UPDATED" in the new (refactored) code.
 		}
 
 		//
@@ -540,6 +545,7 @@
 	Collection<Class<? extends IFloodlightService>> l =
 	    new ArrayList<Class<? extends IFloodlightService>>();
 	l.add(IFloodlightProviderService.class);
+	l.add(ITopoRouteService.class);
 	l.add(IRestApiService.class);
         return l;
     }
@@ -549,6 +555,7 @@
 	throws FloodlightModuleException {
 	this.context = context;
 	floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
+	topoRouteService = context.getServiceImpl(ITopoRouteService.class);
 	restApi = context.getServiceImpl(IRestApiService.class);
 	messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
 					    EnumSet.of(OFType.FLOW_MOD),
@@ -1157,4 +1164,396 @@
 
 	return flowPath;
     }
+
+    /**
+     * Add and maintain a shortest-path flow.
+     *
+     * NOTE: The Flow Path 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.
+     * @param flowId the return-by-reference Flow ID as assigned internally.
+     * @return true on success, otherwise false.
+     */
+    @Override
+    public boolean addAndMaintainShortestPathFlow(FlowPath flowPath,
+						  FlowId flowId) {
+	//
+	// Do the shortest path computation
+	//
+	DataPath dataPath =
+	    topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
+					     flowPath.dataPath().dstPort());
+	if (dataPath == null)
+	    return false;
+
+	FlowEntryMatch userFlowEntryMatch = null;
+	if (! flowPath.dataPath().flowEntries().isEmpty()) {
+	    userFlowEntryMatch = flowPath.dataPath().flowEntries().get(0).flowEntryMatch();
+	}
+
+	//
+	// Set the incoming port matching and the outgoing port output
+	// actions for each flow entry.
+	//
+	for (FlowEntry flowEntry : dataPath.flowEntries()) {
+	    // Set the incoming port matching
+	    FlowEntryMatch flowEntryMatch = null;
+	    if (userFlowEntryMatch != null)
+		flowEntryMatch = new FlowEntryMatch(userFlowEntryMatch);
+	    else
+		flowEntryMatch = new FlowEntryMatch();
+	    flowEntry.setFlowEntryMatch(flowEntryMatch);
+	    flowEntryMatch.enableInPort(flowEntry.inPort());
+
+	    // Set the outgoing port output action
+	    ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
+	    if (flowEntryActions == null) {
+		flowEntryActions = new ArrayList<FlowEntryAction>();
+		flowEntry.setFlowEntryActions(flowEntryActions);
+	    }
+	    FlowEntryAction flowEntryAction = new FlowEntryAction();
+	    flowEntryAction.setActionOutput(flowEntry.outPort());
+	    flowEntryActions.add(flowEntryAction);
+	}
+
+	//
+	// Prepare the computed Flow Path
+	//
+	FlowPath resultFlowPath = new FlowPath();
+	resultFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
+	resultFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
+	resultFlowPath.setDataPath(dataPath);
+
+	boolean returnValue = addFlow(resultFlowPath, flowId);
+
+	// TODO: Mark the flow for maintenance purpose
+
+	return (returnValue);
+    }
+
+    /**
+     * Create a Flow from port to port.
+     *
+     * TODO: We don't need it for now.
+     *
+     * @param src_port the source port.
+     * @param dest_port the destination port.
+     */
+    public void createFlow(IPortObject src_port, IPortObject dest_port) {
+	// TODO: We don't need it for now.
+    }
+
+    /**
+     * Get all Flows matching a source and a destination port.
+     *
+     * TODO: Pankaj might be implementing it later.
+     *
+     * @param src_port the source port to match.
+     * @param dest_port the destination port to match.
+     * @return all flows matching the source and the destination port.
+     */
+    public Iterable<FlowPath> getFlows(IPortObject src_port,
+				       IPortObject dest_port) {
+	// TODO: Pankaj might be implementing it later.
+	return null;
+    }
+
+    /**
+     * Get all Flows going out from a port.
+     *
+     * TODO: We need it now: Pankaj
+     *
+     * @param port the port to match.
+     * @return the list of flows that are going out from the port.
+     */
+    public Iterable<FlowPath> getFlows(IPortObject port) {
+	// TODO: We need it now: Pankaj
+	return null;
+    }
+
+    /**
+     * Reconcile all flows on inactive port (src port of link which might be
+     * broken).
+     *
+     * TODO: We need it now: Pavlin
+     *
+     * @param src_port the port that has become inactive.
+     */
+    public void reconcileFlows(IPortObject src_port) {
+	// TODO: We need it now: Pavlin
+
+	// TODO: It should call installFlowEntry() as appropriate.
+    }
+
+    /**
+     * Reconcile all flows between a source and a destination port.
+     *
+     * TODO: We don't need it for now.
+     *
+     * @param src_port the source port.
+     * @param dest_port the destination port.
+     */
+    public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
+	// TODO: We don't need it for now.
+    }
+
+    /**
+     * Compute the shortest path between a source and a destination ports.
+     *
+     * @param src_port the source port.
+     * @param dest_port the destination port.
+     * @return the computed shortest path between the source and the
+     * destination ports. The flow entries in the path itself would
+     * contain the incoming port matching and the outgoing port output
+     * actions set. However, the path itself will NOT have the Flow ID,
+     * Installer ID, and any additional matching conditions for the
+     * flow entries (e.g., source or destination MAC address, etc).
+     */
+    public FlowPath computeFlowPath(IPortObject src_port,
+				    IPortObject dest_port) {
+	//
+	// Prepare the arguments
+	//
+	String dpidStr = src_port.getSwitch().getDPID();
+	Dpid srcDpid = new Dpid(dpidStr);
+	Port srcPort = new Port(src_port.getNumber());
+
+	dpidStr = dest_port.getSwitch().getDPID();
+	Dpid dstDpid = new Dpid(dpidStr);
+	Port dstPort = new Port(dest_port.getNumber());
+
+	SwitchPort src = new SwitchPort(srcDpid, srcPort);
+	SwitchPort dst = new SwitchPort(dstDpid, dstPort);
+
+	//
+	// Do the shortest path computation
+	//
+	DataPath dataPath = topoRouteService.getShortestPath(src, dst);
+	if (dataPath == null)
+	    return null;
+
+	//
+	// Set the incoming port matching and the outgoing port output
+	// actions for each flow entry.
+	//
+	for (FlowEntry flowEntry : dataPath.flowEntries()) {
+	    // Set the incoming port matching
+	    FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
+	    if (flowEntryMatch == null) {
+		flowEntryMatch = new FlowEntryMatch();
+		flowEntry.setFlowEntryMatch(flowEntryMatch);
+	    }
+	    flowEntryMatch.enableInPort(flowEntry.inPort());
+
+	    // Set the outgoing port output action
+	    ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
+	    if (flowEntryActions == null) {
+		flowEntryActions = new ArrayList<FlowEntryAction>();
+		flowEntry.setFlowEntryActions(flowEntryActions);
+	    }
+	    FlowEntryAction flowEntryAction = new FlowEntryAction();
+	    flowEntryAction.setActionOutput(flowEntry.outPort());
+	    flowEntryActions.add(flowEntryAction);
+	}
+
+	//
+	// Prepare the return result
+	//
+	FlowPath flowPath = new FlowPath();
+	flowPath.setDataPath(dataPath);
+
+	return flowPath;
+    }
+
+    /**
+     * Get all Flow Entries of a Flow.
+     *
+     * @param flow the flow whose flow entries should be returned.
+     * @return the flow entries of the flow.
+     */
+    public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
+	return flow.dataPath().flowEntries();
+    }
+
+    /**
+     * Install a Flow Entry on a switch.
+     *
+     * @param mySwitches the DPID-to-Switch mapping for the switches
+     * controlled by this controller.
+     * @param flowEntry the flow entry to install.
+     * @return true on success, otherwise false.
+     */
+    public boolean installFlowEntry(Map<Long, IOFSwitch> mySwitches,
+				    FlowEntry flowEntry) {
+	IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
+	if (mySwitch == null) {
+	    // Not my switch
+	    return (installRemoteFlowEntry(flowEntry));
+	}
+
+	//
+	// Create the OpenFlow Flow Modification Entry to push
+	//
+	OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
+	    .getMessage(OFType.FLOW_MOD);
+	long cookie = flowEntry.flowEntryId().value();
+
+	short flowModCommand = OFFlowMod.OFPFC_ADD;
+	if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
+	    flowModCommand = OFFlowMod.OFPFC_ADD;
+	} else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
+	    flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
+	} else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
+	    flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
+	} else {
+	    // Unknown user state. Ignore the entry
+	    log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
+		      flowEntry.flowEntryId().toString(),
+		      flowEntry.flowEntryUserState());
+	    return false;
+	}
+
+	//
+	// Fetch the match conditions
+	//
+	OFMatch match = new OFMatch();
+	match.setWildcards(OFMatch.OFPFW_ALL);
+	Port matchInPort = flowEntry.flowEntryMatch().inPort();
+	if (matchInPort != null) {
+	    match.setInputPort(matchInPort.value());
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
+	}
+	Short matchEthernetFrameType =
+	    flowEntry.flowEntryMatch().ethernetFrameType();
+	if (matchEthernetFrameType != null) {
+	    match.setDataLayerType(matchEthernetFrameType);
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
+	}
+	IPv4Net matchSrcIPv4Net = flowEntry.flowEntryMatch().srcIPv4Net();
+	if (matchSrcIPv4Net != null) {
+	    match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
+	}
+	IPv4Net matchDstIPv4Net = flowEntry.flowEntryMatch().dstIPv4Net();
+	if (matchDstIPv4Net != null) {
+	    match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
+	}
+	MACAddress matchSrcMac = flowEntry.flowEntryMatch().srcMac();
+	if (matchSrcMac != null) {
+	    match.setDataLayerSource(matchSrcMac.toString());
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
+	}
+	MACAddress matchDstMac = flowEntry.flowEntryMatch().dstMac();
+	if (matchDstMac != null) {
+	    match.setDataLayerDestination(matchDstMac.toString());
+	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
+	}
+
+	//
+	// Fetch the actions
+	//
+	// TODO: For now we support only the "OUTPUT" actions.
+	//
+	fm.setOutPort(OFPort.OFPP_NONE.getValue());
+	List<OFAction> actions = new ArrayList<OFAction>();
+	ArrayList<FlowEntryAction> flowEntryActions =
+	    flowEntry.flowEntryActions();
+	for (FlowEntryAction flowEntryAction : flowEntryActions) {
+	    FlowEntryAction.ActionOutput actionOutput =
+		flowEntryAction.actionOutput();
+	    if (actionOutput != null) {
+		short actionOutputPort = actionOutput.port().value();
+		OFActionOutput action = new OFActionOutput();
+		// XXX: The max length is hard-coded for now
+		action.setMaxLength((short)0xffff);
+		action.setPort(actionOutputPort);
+		actions.add(action);
+		if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
+		    (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
+		    fm.setOutPort(actionOutputPort);
+		}
+	    }
+	}
+
+	fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
+	    .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
+	    .setPriority(PRIORITY_DEFAULT)
+	    .setBufferId(OFPacketOut.BUFFER_ID_NONE)
+	    .setCookie(cookie)
+	    .setCommand(flowModCommand)
+	    .setMatch(match)
+	    .setActions(actions)
+	    .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
+
+	//
+	// TODO: Set the following flag
+	// fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
+	// See method ForwardingBase::pushRoute()
+	//
+
+	//
+	// Write the message to the switch
+	//
+	try {
+	    messageDamper.write(mySwitch, fm, null);
+	    mySwitch.flush();
+	} catch (IOException e) {
+	    log.error("Failure writing flow mod from network map", e);
+	    return false;
+	}
+	return true;
+    }
+
+    /**
+     * Remove a Flow Entry from a switch.
+     *
+     * TODO: We need it now: Pavlin
+     * - Remove only for local switches
+     * - It will call the removeRemoteFlowEntry() for remote switches.
+     * - To be called by reconcileFlow()
+     *
+     * @param entry the flow entry to remove.
+     */
+    public void removeFlowEntry(FlowEntry entry) {
+	// TODO: We need it now: Pavlin
+	//  - Remove only for local switches
+	//  - It will call the removeRemoteFlowEntry() for remote switches.
+	//  - To be called by reconcileFlow()
+    }
+
+    /**
+     * Install a Flow Entry on a remote controller.
+     *
+     * TODO: We need it now: Jono
+     * - For now it will make a REST call to the remote controller.
+     * - Internally, it needs to know the name of the remote controller.
+     *
+     * @param entry the flow entry to install.
+     * @return true on success, otherwise false.
+     */
+    public boolean installRemoteFlowEntry(FlowEntry entry) {
+	// TODO: We need it now: Jono
+	//  - For now it will make a REST call to the remote controller.
+	//  - Internally, it needs to know the name of the remote controller.
+	return true;
+    }
+
+    /**
+     * Remove a flow entry on a remote controller.
+     *
+     * TODO: We need it now: Jono
+     * - For now it will make a REST call to the remote controller.
+     * - Internally, it needs to know the name of the remote controller.
+     *
+     * @param entry the flow entry to remove.
+     */
+    public void removeRemoteFlowEntry(FlowEntry entry) {
+	// TODO: We need it now: Jono
+	//  - For now it will make a REST call to the remote controller.
+	//  - Internally, it needs to know the name of the remote controller.
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
index 41c0f57..45cdde0 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
@@ -82,4 +82,21 @@
      * @return the Flow Paths if found, otherwise null.
      */
     ArrayList<FlowPath> getAllFlows();
+
+    /**
+     * Add and maintain a shortest-path flow.
+     *
+     * NOTE: The Flow Path 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.
+     * @param flowId the return-by-reference Flow ID as assigned internally.
+     * @return true on success, otherwise false.
+     */
+    public boolean addAndMaintainShortestPathFlow(FlowPath flowPath,
+						  FlowId flowId);
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/AddShortestPathFlowResource.java b/src/main/java/net/floodlightcontroller/flowcache/web/AddShortestPathFlowResource.java
new file mode 100644
index 0000000..e00a4b5
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/AddShortestPathFlowResource.java
@@ -0,0 +1,63 @@
+package net.floodlightcontroller.flowcache.web;
+
+import java.io.IOException;
+
+import net.floodlightcontroller.flowcache.IFlowService;
+import net.floodlightcontroller.util.FlowId;
+import net.floodlightcontroller.util.FlowPath;
+
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.restlet.resource.Post;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AddShortestPathFlowResource extends ServerResource {
+
+    protected static Logger log = LoggerFactory.getLogger(AddShortestPathFlowResource.class);
+
+    @Post("json")
+    public FlowId store(String flowJson) {
+	FlowId result = new FlowId();
+
+        IFlowService flowService =
+                (IFlowService)getContext().getAttributes().
+                get(IFlowService.class.getCanonicalName());
+
+        if (flowService == null) {
+	    log.debug("ONOS Flow Service not found");
+            return result;
+	}
+
+	//
+	// Extract the arguments
+	// NOTE: The "flow" is specified in JSON format.
+	//
+	ObjectMapper mapper = new ObjectMapper();
+	String flowPathStr = flowJson;
+	FlowPath flowPath = null;
+	log.debug("Add Shortest Path Flow Path: " + flowPathStr);
+	try {
+	    flowPath = mapper.readValue(flowPathStr, FlowPath.class);
+	} catch (JsonGenerationException e) {
+	    e.printStackTrace();
+	} catch (JsonMappingException e) {
+	    e.printStackTrace();
+	} catch (IOException e) {
+	    e.printStackTrace();
+	}
+
+	// Process the request
+	if (flowPath != null) {
+	    if (flowService.addAndMaintainShortestPathFlow(flowPath, result)
+		!= true) {
+		result = new FlowId();		// Error: Return empty Flow Id
+	    }
+	}
+
+        return result;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java b/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java
index 19f9e14..962dbbb 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java
@@ -14,6 +14,7 @@
     public Restlet getRestlet(Context context) {
         Router router = new Router(context);
         router.attach("/add/json", AddFlowResource.class);
+        router.attach("/add-shortest-path/json", AddShortestPathFlowResource.class);
         router.attach("/clear/{flow-id}/json", ClearFlowResource.class);
         router.attach("/delete/{flow-id}/json", DeleteFlowResource.class);
         router.attach("/get/{flow-id}/json", GetFlowByIdResource.class);
diff --git a/src/main/java/net/floodlightcontroller/util/FlowEntryMatch.java b/src/main/java/net/floodlightcontroller/util/FlowEntryMatch.java
index 64527c5..6c8e71e 100644
--- a/src/main/java/net/floodlightcontroller/util/FlowEntryMatch.java
+++ b/src/main/java/net/floodlightcontroller/util/FlowEntryMatch.java
@@ -27,6 +27,8 @@
 
 	/**
 	 * Constructor for a given value to match.
+	 *
+	 * @param value the value to match.
 	 */
 	public Field(T value) {
 	    this.value = value;
@@ -88,6 +90,38 @@
     }
 
     /**
+     * Copy constructor.
+     *
+     * @param other the object to copy from.
+     */
+    public FlowEntryMatch(FlowEntryMatch other) {
+	if ((other.inPort != null) && other.inPort.enabled())
+	    this.enableInPort(other.inPort.value());
+	if ((other.srcMac != null) && other.srcMac.enabled())
+	    this.enableSrcMac(other.srcMac.value());
+	if ((other.dstMac != null) && other.dstMac.enabled())
+	    this.enableDstMac(other.dstMac.value());
+	if ((other.vlanId != null) && other.vlanId.enabled())
+	    this.enableVlanId(other.vlanId.value());
+	if ((other.vlanPriority != null) && other.vlanPriority.enabled())
+	    this.enableVlanPriority(other.vlanPriority.value());
+	if ((other.ethernetFrameType != null) && other.ethernetFrameType.enabled())
+	    this.enableEthernetFrameType(other.ethernetFrameType.value());
+	if ((other.ipToS != null) && other.ipToS.enabled())
+	    this.enableIpToS(other.ipToS.value());
+	if ((other.ipProto != null) && other.ipProto.enabled())
+	    this.enableIpProto(other.ipProto.value());
+	if ((other.srcIPv4Net != null) && other.srcIPv4Net.enabled())
+	    this.enableSrcIPv4Net(other.srcIPv4Net.value());
+	if ((other.dstIPv4Net != null) && other.dstIPv4Net.enabled())
+	    this.enableDstIPv4Net(other.dstIPv4Net.value());
+	if ((other.srcTcpUdpPort != null) && other.srcTcpUdpPort.enabled())
+	    this.enableSrcTcpUdpPort(other.srcTcpUdpPort.value());
+	if ((other.dstTcpUdpPort != null) && other.dstTcpUdpPort.enabled())
+	    this.enableDstTcpUdpPort(other.dstTcpUdpPort.value());
+    }
+
+    /**
      * Get the matching input switch port.
      *
      * @return the matching input switch port.
diff --git a/src/main/java/net/onrc/onos/flow/IFlowManager.java b/src/main/java/net/onrc/onos/flow/IFlowManager.java
index da6448c..f2f9d49 100644
--- a/src/main/java/net/onrc/onos/flow/IFlowManager.java
+++ b/src/main/java/net/onrc/onos/flow/IFlowManager.java
@@ -1,53 +1,136 @@
 package net.onrc.onos.flow;
 
+import java.util.Map;
+
+import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
 import net.floodlightcontroller.util.FlowEntry;
 import net.floodlightcontroller.util.FlowPath;
 
 public interface IFlowManager {
-	
-	/*
-	 * Generic create Flow from port to port
-	 */
-	public void createFlow(IPortObject src_port, IPortObject dest_port);
-	/*
-	 * get Flows matching a src_port & dest_port
-	 */
-	public Iterable<FlowPath> getFlows(IPortObject src_port, IPortObject dest_port);
-	/*
-	 * get all Flows going out from port
-	 */
-	public Iterable<FlowPath> getFlows(IPortObject port);
-	/*
-	 * Reconcile all flows on inactive port (src port of link which might be broken)
-	 */
-	public void reconcileFlows(IPortObject src_port);
-	/*
-	 * Reconcile flow based on flow
-	 */
-	public void reconcileFlow(IPortObject src_port, IPortObject dest_port);
-	/*
-	 * compute a flow path using src/dest port
-	 */
-	public FlowPath computeFlowPath(IPortObject src_port, IPortObject dest_port);
-	/*
-	 * Get all FlowEntries of a Flow
-	 */
-    public Iterable<FlowEntry> getFlowEntries(FlowPath flow);
-    /*
-     * install a flow entry on switch
+    /**
+     * Create a Flow from port to port.
+     *
+     * TODO: We don't need it for now.
+     *
+     * @param src_port the source port.
+     * @param dest_port the destination port.
      */
-    public void installFlowEntry(FlowEntry entry);
-    /*
-     * remove a flowEntry from switch
+    public void createFlow(IPortObject src_port, IPortObject dest_port);
+
+    /**
+     * Get all Flows matching a source and a destination port.
+     *
+     * TODO: Pankaj might be implementing it later.
+     *
+     * @param src_port the source port to match.
+     * @param dest_port the destination port to match.
+     * @return all flows matching the source and the destination port.
+     */
+    public Iterable<FlowPath> getFlows(IPortObject src_port,
+				       IPortObject dest_port);
+
+    /**
+     * Get all Flows going out from a port.
+     *
+     * TODO: We need it now: Pankaj
+     *
+     * @param port the port to match.
+     * @return the list of flows that are going out from the port.
+     */
+    public Iterable<FlowPath> getFlows(IPortObject port);
+
+    /**
+     * Reconcile all flows on inactive port (src port of link which might be
+     * broken).
+     *
+     * TODO: We need it now: Pavlin
+     *
+     * @param src_port the port that has become inactive.
+     */
+    public void reconcileFlows(IPortObject src_port);
+
+    /**
+     * Reconcile all flows between a source and a destination port.
+     *
+     * TODO: We don't need it for now.
+     *
+     * @param src_port the source port.
+     * @param dest_port the destination port.
+     */
+    public void reconcileFlow(IPortObject src_port, IPortObject dest_port);
+
+    /**
+     * Compute the shortest path between a source and a destination ports.
+     *
+     * TODO: We need it now: Pavlin
+     *
+     * @param src_port the source port.
+     * @param dest_port the destination port.
+     * @return the computed shortest path between the source and the
+     * destination ports.
+     */
+    public FlowPath computeFlowPath(IPortObject src_port,
+				    IPortObject dest_port);
+
+    /**
+     * Get all Flow Entries of a Flow.
+     *
+     * TODO: We need it now: Pavlin
+     *
+     * @param flow the flow whose flow entries should be returned.
+     * @return the flow entries of the flow.
+     */
+    public Iterable<FlowEntry> getFlowEntries(FlowPath flow);
+
+    /**
+     * Install a Flow Entry on a switch.
+     *
+     * TODO: We need it now: Pavlin
+     * - Install only for local switches
+     * - It will call the installRemoteFlowEntry() for remote switches.
+     * - To be called by reconcileFlow()
+     *
+     * @param mySwitches the DPID-to-Switch mapping for the switches
+     * controlled by this controller.
+     * @param flowEntry the flow entry to install.
+     * @return true on success, otherwise false.
+     */
+    public boolean installFlowEntry(Map<Long, IOFSwitch> mySwitches,
+				    FlowEntry flowEntry);
+
+    /**
+     * Remove a Flow Entry from a switch.
+     *
+     * TODO: We need it now: Pavlin
+     * - Remove only for local switches
+     * - It will call the removeRemoteFlowEntry() for remote switches.
+     * - To be called by reconcileFlow()
+     *
+     * @param entry the flow entry to remove.
      */
     public void removeFlowEntry(FlowEntry entry);
-    /*
-     * install flow entry on remote controller
+
+    /**
+     * Install a Flow Entry on a remote controller.
+     *
+     * TODO: We need it now: Jono
+     * - For now it will make a REST call to the remote controller.
+     * - Internally, it needs to know the name of the remote controller.
+     *
+     * @param entry the flow entry to install.
+     * @return true on success, otherwise false.
      */
-    public void installFlowEntry(String ctrlId, FlowEntry entry);
-    /*
-     * remove flow entry on remote controller
+    public boolean installRemoteFlowEntry(FlowEntry entry);
+
+    /**
+     * Remove a flow entry on a remote controller.
+     *
+     * TODO: We need it now: Jono
+     * - For now it will make a REST call to the remote controller.
+     * - Internally, it needs to know the name of the remote controller.
+     *
+     * @param entry the flow entry to remove.
      */
-    public void removeFlowEntry(String ctrlId, FlowEntry entry);        
+    public void removeRemoteFlowEntry(FlowEntry entry);        
 }