Merge "Mark constructors provided for Serializers, deprecated" into dev/ramcloud-new-datamodel
diff --git a/src/main/java/net/onrc/onos/intent/FlowEntry.java b/src/main/java/net/onrc/onos/intent/FlowEntry.java
index 374e5d6..7aa3d76 100644
--- a/src/main/java/net/onrc/onos/intent/FlowEntry.java
+++ b/src/main/java/net/onrc/onos/intent/FlowEntry.java
@@ -51,7 +51,7 @@
 	public net.onrc.onos.ofcontroller.util.FlowEntry getFlowEntry() {
 		net.onrc.onos.ofcontroller.util.FlowEntry entry = new net.onrc.onos.ofcontroller.util.FlowEntry();
 		entry.setDpid(new Dpid(sw));
-		entry.setFlowEntryId(new FlowEntryId(0)); // all zero for now
+		entry.setFlowEntryId(new FlowEntryId(hashCode())); // naive, but useful for now
 		entry.setFlowEntryMatch(match.getFlowEntryMatch());
 		FlowEntryActions flowEntryActions = new FlowEntryActions();
 		for(Action action : actions) {
@@ -71,6 +71,19 @@
 		return entry;
 	}
 	
-	//TODO: implement hash for cookie
-	//TODO: implement equals (don't include operator!)
-}
\ No newline at end of file
+	
+	public int hashCode() {
+	    return match.hashCode();
+	}
+	
+	public boolean equals(Object o) {
+	    if(!(o instanceof FlowEntry)) {
+		return false;
+	    }
+	    FlowEntry other = (FlowEntry) o;
+	    // Note: we should not consider the operator for this comparison
+	    return this.match.equals(other.match) 
+		&& this.actions.containsAll(other.actions)
+		&& other.actions.containsAll(this.actions);
+	}
+}
diff --git a/src/main/java/net/onrc/onos/intent/ForwardAction.java b/src/main/java/net/onrc/onos/intent/ForwardAction.java
index 6ca514d..9344d8c 100644
--- a/src/main/java/net/onrc/onos/intent/ForwardAction.java
+++ b/src/main/java/net/onrc/onos/intent/ForwardAction.java
@@ -25,5 +25,16 @@
 	    action.setActionOutput(new net.onrc.onos.ofcontroller.util.Port((short) dstPort));
 	    return action;
 	}
+
+	public int hashCode() {
+	    return (int) dstPort;
+	}
 	
-}
\ No newline at end of file
+	public boolean equals(Object o) {
+	    if(!(o instanceof ForwardAction)) {
+		return false;
+	    }
+  	    ForwardAction action = (ForwardAction) o;
+	    return this.dstPort == action.dstPort;
+	}
+}
diff --git a/src/main/java/net/onrc/onos/intent/Match.java b/src/main/java/net/onrc/onos/intent/Match.java
index 5adb598..886fb64 100644
--- a/src/main/java/net/onrc/onos/intent/Match.java
+++ b/src/main/java/net/onrc/onos/intent/Match.java
@@ -1,5 +1,7 @@
 package net.onrc.onos.intent;
 
+import java.util.Arrays;
+
 import net.floodlightcontroller.util.MACAddress;
 //import net.onrc.onos.ofcontroller.networkgraph.Port;
 //import net.onrc.onos.ofcontroller.networkgraph.Switch;
@@ -30,9 +32,9 @@
 		if(obj instanceof Match) {
 			Match other = (Match) obj;
 			return this.sw == other.sw &&
-					this.srcMac.equals(other.srcMac) &&
-					this.dstMac.equals(other.dstMac) &&
-					this.srcPort == other.srcPort;
+			       this.srcMac.equals(other.srcMac) &&
+			       this.dstMac.equals(other.dstMac) &&
+			       this.srcPort == other.srcPort;
 		}
 		else {
 			return false;
@@ -51,4 +53,14 @@
 	public String toString() {
 		return "Sw:" + sw + " (" + srcPort + "," + srcMac + "," + dstMac + ")";
 	}
+	
+	@Override
+	public int hashCode() {
+	    long[] nums = new long[4];
+	    nums[0] = sw;
+	    nums[1] = srcPort;
+	    nums[2] = srcMac.toLong();
+	    nums[3] = dstMac.toLong();
+	    return Arrays.hashCode(nums);
+	}
 }
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java
index 6ff92db..abd68d1 100644
--- a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntime.java
@@ -107,6 +107,19 @@
 					pathIntentOpList.add(Operator.REMOVE, new Intent(oldPathIntentId));
 				}
 
+				// remove old path-intent if exists
+				Intent oldIntent = appIntents.getIntent(spIntent.getId());
+				if (oldIntent != null) {
+					ShortestPathIntent oldSpIntent = (ShortestPathIntent)oldIntent;
+					String pathIntentId = oldSpIntent.getPathIntentId();
+					if (pathIntentId != null) {
+						Intent targetPathIntent = pathIntents.getIntent(pathIntentId);
+						if (targetPathIntent != null) {
+							pathIntentOpList.add(Operator.REMOVE, targetPathIntent);
+						}
+					}
+				}
+
 				// create new path-intent
 				PathIntent pathIntent = new PathIntent(newPathIntentId, path, bandwidth, spIntent);
 				pathIntent.setState(IntentState.INST_REQ);
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PlanInstallModule.java b/src/main/java/net/onrc/onos/intent/runtime/PlanInstallModule.java
index 4d4e437..d9f1b0f 100644
--- a/src/main/java/net/onrc/onos/intent/runtime/PlanInstallModule.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PlanInstallModule.java
@@ -2,6 +2,7 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -69,6 +70,9 @@
 		    IntentOperationList intents = intentQueue.take();
 		    //TODO: consider draining the remaining intent lists 
 		    //      and processing in one big batch
+//		    List<IntentOperationList> remaining = new LinkedList<>();
+//		    intentQueue.drainTo(remaining);
+		    
 		    processIntents(intents);
 		} catch (InterruptedException e) {
 		    log.warn("Error taking from intent queue: {}", e.getMessage());
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PlanInstallRuntime.java b/src/main/java/net/onrc/onos/intent/runtime/PlanInstallRuntime.java
index a524875..abd82ed 100644
--- a/src/main/java/net/onrc/onos/intent/runtime/PlanInstallRuntime.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PlanInstallRuntime.java
@@ -1,17 +1,21 @@
 package net.onrc.onos.intent.runtime;
 
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ExecutionException;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.internal.OFMessageFuture;
 import net.onrc.onos.intent.FlowEntry;
 import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
 //import net.onrc.onos.ofcontroller.networkgraph.NetworkGraph;
 import net.onrc.onos.ofcontroller.util.Pair;
 
+import org.openflow.protocol.OFBarrierReply;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -61,9 +65,23 @@
 	    
 	    // TODO: insert a barrier after each phase on each modifiedSwitch
 	    // TODO: wait for confirmation messages before proceeding
+	    List<Pair<IOFSwitch,OFMessageFuture<OFBarrierReply>>> barriers = new ArrayList<>();
+	    for(IOFSwitch sw : modifiedSwitches) {
+		barriers.add(new Pair<>(sw, pusher.barrierAsync(sw)));
+	    }
+	    for(Pair<IOFSwitch,OFMessageFuture<OFBarrierReply>> pair : barriers) {
+		IOFSwitch sw = pair.first;
+		OFMessageFuture<OFBarrierReply> future = pair.second;
+		try {
+		    future.get();
+		} catch (InterruptedException | ExecutionException e) {
+		    log.error("Barrier message not received for sw: {}", sw);
+		}
+	    }
 	}
 	long end = System.nanoTime();
 	log.error("MEASUREMENT: Install plan: {} ns", (end-start));
+	
 	// TODO: we assume that the plan installation succeeds for now
 	return true;
     }