Implement IntentMap and IntentOperation
Change-Id: I8ef5ddb37ae2694a984c190465e86026fa643e7b
diff --git a/src/main/java/net/onrc/onos/intent/Intent.java b/src/main/java/net/onrc/onos/intent/Intent.java
index a31cbde..de960f0 100644
--- a/src/main/java/net/onrc/onos/intent/Intent.java
+++ b/src/main/java/net/onrc/onos/intent/Intent.java
@@ -3,12 +3,19 @@
/**
* @author Toshio Koide (t-koide@onlab.us)
*/
-public abstract class Intent {
+public class Intent {
enum IntentState {
- // TODO;
+ CREATED,
+ INST_REQ,
+ INST_NACK,
+ INST_ACK,
+ DEL_REQ,
+ DEL_PENDING,
+ DEL_ACK,
}
+
protected String id;
- protected IntentState state;
+ protected IntentState state = IntentState.CREATED;
/**
* Default constructor for Kryo deserialization
@@ -20,20 +27,25 @@
this.id = id;
}
+ public Intent(String id, IntentState state) {
+ this.id = id;
+ this.state = state;
+ }
+
public String getId() {
return id;
}
-
+
public IntentState getState() {
return state;
}
-
+
public IntentState setState(IntentState newState) {
IntentState oldState = state;
state = newState;
return oldState;
}
-
+
@Override
public int hashCode() {
return id.hashCode();
diff --git a/src/main/java/net/onrc/onos/intent/IntentMap.java b/src/main/java/net/onrc/onos/intent/IntentMap.java
new file mode 100644
index 0000000..f9d8b9f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/intent/IntentMap.java
@@ -0,0 +1,109 @@
+package net.onrc.onos.intent;
+
+import java.util.Collection;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import net.onrc.onos.intent.Intent.IntentState;
+
+/**
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class IntentMap {
+ public enum ChangedEventType {
+ /**
+ * Added new intent.
+ */
+ ADDED,
+
+ /**
+ * Removed existing intent.
+ * The specified intent is an instance of Intent class (not a child class)
+ * Only id and state are valid.
+ */
+ REMOVED,
+
+ /**
+ * Changed state of existing intent.
+ * The specified intent is an instance of Intent class (not a child class)
+ * Only id and state are valid.
+ */
+ STATE_CHANGED,
+ }
+
+ public class ChangedEvent {
+ public ChangedEvent(ChangedEventType eventType, Intent intent) {
+ this.eventType = eventType;
+ this.intent = intent;
+ }
+ public ChangedEventType eventType;
+ public Intent intent;
+ }
+
+ public interface ChangedListener extends EventListener {
+ void intentsChange(LinkedList<ChangedEvent> events);
+ }
+
+ private HashSet<ChangedListener> listeners = new HashSet<>();
+ protected HashMap<String, Intent> intents = new HashMap<>();
+
+ public void executeOperations(List<IntentOperation> operations) {
+ LinkedList<ChangedEvent> events = new LinkedList<>();
+ for (IntentOperation operation: operations) {
+ switch (operation.operator) {
+ case ADD:
+ intents.put(operation.intent.getId(), operation.intent);
+ events.add(new ChangedEvent(ChangedEventType.ADDED, operation.intent));
+ break;
+ case REMOVE:
+ Intent intent = intents.get(operation.intent.getId());
+ if (intent == null) {
+ // TODO throw exception
+ }
+ else {
+ intent.setState(Intent.IntentState.DEL_REQ);
+ events.add(new ChangedEvent(ChangedEventType.STATE_CHANGED,
+ new Intent(intent.getId(), Intent.IntentState.DEL_REQ)));
+ }
+ break;
+ }
+ }
+ for (ChangedListener listener: listeners) {
+ listener.intentsChange(events);
+ }
+ }
+
+ public void purge() {
+ Iterator<Entry<String, Intent>> i = intents.entrySet().iterator();
+ while (i.hasNext()) {
+ Entry<String, Intent> entry = i.next();
+ Intent intent = entry.getValue();
+ if (intent.getState() == IntentState.DEL_ACK
+ || intent.getState() == IntentState.INST_NACK) {
+ i.remove();
+ }
+ }
+ }
+
+ public Collection<Intent> getAllIntents() {
+ return intents.values();
+ }
+
+ public Intent getIntent(String key) {
+ return intents.get(key);
+ }
+
+
+ public void addChangeListener(ChangedListener listener) {
+ listeners.add(listener);
+ }
+
+ public void removeChangedListener(ChangedListener listener) {
+ listeners.remove(listener);
+ }
+}
diff --git a/src/main/java/net/onrc/onos/intent/IntentOperation.java b/src/main/java/net/onrc/onos/intent/IntentOperation.java
new file mode 100644
index 0000000..8ac45c9
--- /dev/null
+++ b/src/main/java/net/onrc/onos/intent/IntentOperation.java
@@ -0,0 +1,29 @@
+package net.onrc.onos.intent;
+
+/**
+ * @author Toshio Koide (t-koide@onlab.us)
+ */
+public class IntentOperation {
+ public enum Operator {
+ /**
+ * Add new intent specified by intent field
+ */
+ ADD,
+
+ /**
+ * Remove existing intent specified by intent field.
+ * The specified intent should be an instance of Intent class (not a child class)
+ */
+ REMOVE,
+ }
+
+ public IntentOperation() {}
+
+ public IntentOperation(Operator operator, Intent intent) {
+ this.operator = operator;
+ this.intent = intent;
+ }
+
+ public Operator operator;
+ public Intent intent;
+}
diff --git a/src/test/java/net/onrc/onos/intent/IntentMapTest.java b/src/test/java/net/onrc/onos/intent/IntentMapTest.java
new file mode 100644
index 0000000..7879206
--- /dev/null
+++ b/src/test/java/net/onrc/onos/intent/IntentMapTest.java
@@ -0,0 +1,75 @@
+package net.onrc.onos.intent;
+
+import static org.junit.Assert.*;
+
+import java.util.LinkedList;
+
+import net.onrc.onos.intent.Intent.IntentState;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class IntentMapTest {
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void test() {
+ IntentMap intents = new IntentMap();
+ LinkedList<IntentOperation> operations = new LinkedList<>();
+
+ // add three intents
+
+ ShortestPathIntent intent1 =
+ new ShortestPathIntent("1", 11L, 12L, 13L, 14L, 15L, 16L);
+ ShortestPathIntent intent2 =
+ new ShortestPathIntent("2", 21L, 22L, 23L, 24L, 25L, 26L);
+ ConstrainedShortestPathIntent intent3 =
+ new ConstrainedShortestPathIntent("3", 31L, 32L, 33L, 34L, 35L, 36L, 1000.0);
+
+ operations.add(new IntentOperation(IntentOperation.Operator.ADD, intent1));
+ operations.add(new IntentOperation(IntentOperation.Operator.ADD, intent2));
+ operations.add(new IntentOperation(IntentOperation.Operator.ADD, intent3));
+ intents.executeOperations(operations);
+
+ // check
+
+ assertEquals(3, intents.getAllIntents().size());
+ assertEquals(intent1, intents.getIntent("1"));
+ assertEquals(intent2, intents.getIntent("2"));
+ assertEquals(intent3, intents.getIntent("3"));
+
+ // request removal of an intent
+
+ Intent intent4 = new Intent("1");
+ operations.clear();
+ operations.add(new IntentOperation(IntentOperation.Operator.REMOVE, intent4));
+ intents.executeOperations(operations);
+
+ // check
+
+ assertEquals(3, intents.getAllIntents().size());
+ assertEquals(IntentState.DEL_REQ, intent1.getState());
+
+ // change intents' state which will be purged
+
+ intent2.setState(IntentState.INST_NACK);
+ intent3.setState(IntentState.DEL_ACK);
+
+ // purge
+
+ intents.purge();
+
+ // check
+
+ assertEquals(1, intents.getAllIntents().size());
+ assertEquals("1", intents.getAllIntents().iterator().next().getId());
+ }
+}