Avoid race conditions using one big lock (testing)

Change-Id: Id4f779757b5f4edc003abad529b5dfce2ea6b0ba
diff --git a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java
index 042f08b..fe76714 100755
--- a/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java
+++ b/src/main/java/net/onrc/onos/intent/runtime/PathCalcRuntimeModule.java
@@ -7,6 +7,7 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.concurrent.locks.ReentrantLock;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -49,6 +50,7 @@
 	private PersistIntent persistIntent;
 
 	private IEventChannel<Long, IntentOperationList> opEventChannel;
+	private final ReentrantLock lock = new ReentrantLock();
 	private static final String INTENT_OP_EVENT_CHANNEL_NAME = "onos.pathintent";
 	private static final String INTENT_STATE_EVENT_CHANNEL_NAME = "onos.pathintent_state";
 	private static final Logger log = LoggerFactory.getLogger(PathCalcRuntimeModule.class);
@@ -126,63 +128,72 @@
 
 	@Override
 	public IntentOperationList executeIntentOperations(IntentOperationList list) {
-		// update the map of high-level intents
-		log("begin_updateInMemoryIntents");
-		highLevelIntents.executeOperations(list);
+		lock.lock(); // TODO optimize locking using smaller steps
+		try {
+			// update the map of high-level intents
+			log("begin_updateInMemoryIntents");
+			highLevelIntents.executeOperations(list);
 
-		// change states of high-level intents
-		IntentStateList states = new IntentStateList();
-		for (IntentOperation op : list) {
-			if (op.intent.getState().equals(IntentState.INST_ACK))
-				states.put(op.intent.getId(), IntentState.REROUTE_REQ);
-		}
-		highLevelIntents.changeStates(states);
-		log("end_updateInMemoryIntents");
-
-		// calculate path-intents (low-level operations)
-		log("begin_calcPathIntents");
-		IntentOperationList pathIntentOperations = runtime.calcPathIntents(list, highLevelIntents, pathIntents);
-		log("end_calcPathIntents");
-
-		// persist calculated low-level operations into data store
-		log("begin_persistPathIntents");
-		long key = persistIntent.getKey();
-		persistIntent.persistIfLeader(key, pathIntentOperations);
-		log("end_persistPathIntents");
-
-		// remove error-intents and reflect them to high-level intents
-		log("begin_removeErrorIntents");
-		states.clear();
-		Iterator<IntentOperation> i = pathIntentOperations.iterator();
-		while (i.hasNext()) {
-			IntentOperation op = i.next();
-			if (op.operator.equals(Operator.ERROR)) {
-				states.put(op.intent.getId(), IntentState.INST_NACK);
-				i.remove();
+			// change states of high-level intents
+			IntentStateList states = new IntentStateList();
+			for (IntentOperation op : list) {
+				if (op.intent.getState().equals(IntentState.INST_ACK))
+					states.put(op.intent.getId(), IntentState.REROUTE_REQ);
 			}
-		}
-		highLevelIntents.changeStates(states);
-		log("end_removeErrorIntents");
+			highLevelIntents.changeStates(states);
+			log("end_updateInMemoryIntents");
 
-		// update the map of path intents and publish the path operations
-		log("begin_updateInMemoryPathIntents");
-		pathIntents.executeOperations(pathIntentOperations);
-		log("end_updateInMemoryPathIntents");
+			// calculate path-intents (low-level operations)
+			log("begin_calcPathIntents");
+			IntentOperationList pathIntentOperations = runtime.calcPathIntents(list, highLevelIntents, pathIntents);
+			log("end_calcPathIntents");
 
-		// Demo special: add a complete path to remove operation
-		log("begin_addPathToRemoveOperation");
-		for (IntentOperation op: pathIntentOperations) {
-			if(op.operator.equals(Operator.REMOVE)) {
-				op.intent = pathIntents.getIntent(op.intent.getId());
+			// persist calculated low-level operations into data store
+			log("begin_persistPathIntents");
+			long key = persistIntent.getKey();
+			persistIntent.persistIfLeader(key, pathIntentOperations);
+			log("end_persistPathIntents");
+
+			// remove error-intents and reflect them to high-level intents
+			log("begin_removeErrorIntents");
+			states.clear();
+			Iterator<IntentOperation> i = pathIntentOperations.iterator();
+			while (i.hasNext()) {
+				IntentOperation op = i.next();
+				if (op.operator.equals(Operator.ERROR)) {
+					states.put(op.intent.getId(), IntentState.INST_NACK);
+					i.remove();
+				}
 			}
-		}
-		log("end_addPathToRemoveOperation");
+			highLevelIntents.changeStates(states);
+			log("end_removeErrorIntents");
 
-		// send notification
-		log("begin_sendNotification");
-		opEventChannel.addEntry(key, pathIntentOperations);
-		log("end_sendNotification");
-		return pathIntentOperations;
+			// update the map of path intents and publish the path operations
+			log("begin_updateInMemoryPathIntents");
+			pathIntents.executeOperations(pathIntentOperations);
+			log("end_updateInMemoryPathIntents");
+
+			// Demo special: add a complete path to remove operation
+			log("begin_addPathToRemoveOperation");
+			for (IntentOperation op: pathIntentOperations) {
+				if(op.operator.equals(Operator.REMOVE)) {
+					op.intent = pathIntents.getIntent(op.intent.getId());
+				}
+				if (op.intent instanceof PathIntent) {
+					log.debug("operation: {}, intent:{}", op.operator, op.intent);
+				}
+			}
+			log("end_addPathToRemoveOperation");
+
+			// send notification
+			log("begin_sendNotification");
+			opEventChannel.addEntry(key, pathIntentOperations);
+			log("end_sendNotification");
+			return pathIntentOperations;
+		}
+		finally {
+			lock.unlock();
+		}
 	}
 
 	@Override
@@ -263,37 +274,42 @@
 	@Override
 	public void entryUpdated(IntentStateList value) {
 		// TODO draw state transition diagram in multiple ONOS instances and update this method
+		lock.lock(); // TODO optimize locking using smaller steps
+		try {
+			log("called_EntryUpdated");
+			// reflect state changes of path-level intent into application-level intents
+			log("begin_changeStateByNotification");
+			IntentStateList parentStates = new IntentStateList();
+			for (Entry<String, IntentState> entry: value.entrySet()) {
+				PathIntent pathIntent = (PathIntent) pathIntents.getIntent(entry.getKey());
+				if (pathIntent == null) continue;
 
-		log("called_EntryUpdated");
-		// reflect state changes of path-level intent into application-level intents
-		log("begin_changeStateByNotification");
-		IntentStateList parentStates = new IntentStateList();
-		for (Entry<String, IntentState> entry: value.entrySet()) {
-			PathIntent pathIntent = (PathIntent) pathIntents.getIntent(entry.getKey());
-			if (pathIntent == null) continue;
+				Intent parentIntent = pathIntent.getParentIntent();
+				if (parentIntent == null ||
+						!(parentIntent instanceof ShortestPathIntent) ||
+						!((ShortestPathIntent) parentIntent).getPathIntentId().equals(pathIntent.getId()))
+					continue;
 
-			Intent parentIntent = pathIntent.getParentIntent();
-			if (parentIntent == null ||
-					!(parentIntent instanceof ShortestPathIntent) ||
-					!((ShortestPathIntent) parentIntent).getPathIntentId().equals(pathIntent.getId()))
-				continue;
-
-			IntentState state = entry.getValue();
-			switch (state) {
-			case INST_REQ:
-			case INST_ACK:
-			case INST_NACK:
-			case DEL_REQ:
-			case DEL_ACK:
-			case DEL_PENDING:
-				parentStates.put(parentIntent.getId(), state);
-				break;
-			default:
-				break;
+				IntentState state = entry.getValue();
+				switch (state) {
+				case INST_REQ:
+				case INST_ACK:
+				case INST_NACK:
+				case DEL_REQ:
+				case DEL_ACK:
+				case DEL_PENDING:
+					parentStates.put(parentIntent.getId(), state);
+					break;
+				default:
+					break;
+				}
 			}
+			highLevelIntents.changeStates(parentStates);
+			pathIntents.changeStates(value);
+			log("end_changeStateByNotification");
 		}
-		highLevelIntents.changeStates(parentStates);
-		pathIntents.changeStates(value);
-		log("end_changeStateByNotification");
+		finally {
+			lock.unlock();
+		}
 	}
 }