blob: 7d87fa20f2c90390d7aec3da6ff2426706333992 [file] [log] [blame]
Jonathan Hartaa380972014-04-03 10:24:46 -07001package net.onrc.onos.core.intent;
Toshio Koideb609b3b2014-02-14 18:25:52 -08002
3import java.util.Collection;
4import java.util.EventListener;
5import java.util.HashMap;
6import java.util.HashSet;
Toshio Koideb609b3b2014-02-14 18:25:52 -08007import java.util.LinkedList;
Toshio Koideb609b3b2014-02-14 18:25:52 -08008import java.util.Map.Entry;
9
Jonathan Hartaa380972014-04-03 10:24:46 -070010import net.onrc.onos.core.intent.Intent.IntentState;
11import net.onrc.onos.core.intent.runtime.IntentStateList;
Ray Milkey0b122ed2014-04-14 10:06:03 -070012import org.slf4j.Logger;
13import org.slf4j.LoggerFactory;
Toshio Koideb609b3b2014-02-14 18:25:52 -080014
15/**
16 * @author Toshio Koide (t-koide@onlab.us)
17 */
18public class IntentMap {
Ray Milkey269ffb92014-04-03 14:43:30 -070019 private HashSet<ChangedListener> listeners = new HashSet<>();
20 private HashMap<String, Intent> intents = new HashMap<>();
21 private LinkedList<ChangedEvent> events = new LinkedList<>();
Ray Milkey0b122ed2014-04-14 10:06:03 -070022 private static final Logger log = LoggerFactory.getLogger(IntentMap.class);
Toshio Koidedf2eab92014-02-20 11:24:59 -080023
Ray Milkey269ffb92014-04-03 14:43:30 -070024 public enum ChangedEventType {
25 /**
26 * Added new intent.
27 */
28 ADDED,
Toshio Koideb609b3b2014-02-14 18:25:52 -080029
Ray Milkey269ffb92014-04-03 14:43:30 -070030 /**
31 * Removed existing intent.
32 * The specified intent is an instance of Intent class (not a child class)
33 * Only id and state are valid.
34 */
35 REMOVED,
Toshio Koideb609b3b2014-02-14 18:25:52 -080036
Ray Milkey269ffb92014-04-03 14:43:30 -070037 /**
38 * Changed state of existing intent.
39 * The specified intent is an instance of Intent class (not a child class)
40 * Only id and state are valid.
41 */
42 STATE_CHANGED,
43 }
Toshio Koideb609b3b2014-02-14 18:25:52 -080044
Pavlin Radoslavovfee80982014-04-10 12:12:04 -070045 public static class ChangedEvent {
Ray Milkey269ffb92014-04-03 14:43:30 -070046 public ChangedEvent(ChangedEventType eventType, Intent intent) {
47 this.eventType = eventType;
48 this.intent = intent;
49 }
Toshio Koideb609b3b2014-02-14 18:25:52 -080050
Ray Milkey269ffb92014-04-03 14:43:30 -070051 public ChangedEventType eventType;
52 public Intent intent;
Pavlin Radoslavovb6309292014-04-11 03:25:47 -070053
54 /**
55 * Get a string representation of the object.
56 * <p/>
57 * The string has the following form:
58 * [eventType=XXX intent=XXX]
59 *
60 * @return a string representation of the object.
61 */
62 @Override
63 public String toString() {
64 StringBuilder ret = new StringBuilder();
65 ret.append("[eventType=");
66 ret.append(this.eventType.toString());
67 ret.append(" intent=");
68 ret.append(this.intent.toString());
69 ret.append("]");
70 return ret.toString();
71 }
Ray Milkey269ffb92014-04-03 14:43:30 -070072 }
Toshio Koideb609b3b2014-02-14 18:25:52 -080073
Ray Milkey269ffb92014-04-03 14:43:30 -070074 public interface ChangedListener extends EventListener {
75 void intentsChange(LinkedList<ChangedEvent> events);
76 }
Toshio Koideb609b3b2014-02-14 18:25:52 -080077
Ray Milkey269ffb92014-04-03 14:43:30 -070078 //================================================================================
79 // public methods
80 //================================================================================
Toshio Koideb609b3b2014-02-14 18:25:52 -080081
Ray Milkey269ffb92014-04-03 14:43:30 -070082 public void executeOperations(IntentOperationList operations) {
83 for (IntentOperation operation : operations) {
84 switch (operation.operator) {
85 case ADD:
86 handleAddOperation(operation);
87 break;
88 case REMOVE:
89 handleRemoveOperation(operation);
90 break;
91 case ERROR:
92 handleErrorOperation(operation);
93 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -070094 default:
95 log.error("Unknown intent operation {}", operation.operator);
96 break;
Ray Milkey269ffb92014-04-03 14:43:30 -070097 }
98 }
99 notifyEvents();
100 }
Toshio Koidedf2eab92014-02-20 11:24:59 -0800101
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700102 /**
103 * Purge all Intents that are in a state allowing them to be removed.
104 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700105 public void purge() {
106 LinkedList<String> removeIds = new LinkedList<>();
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700107
108 // Collect the IDs of all intents that can be removed
Ray Milkey269ffb92014-04-03 14:43:30 -0700109 for (Entry<String, Intent> entry : intents.entrySet()) {
110 Intent intent = entry.getValue();
111 if (intent.getState() == IntentState.DEL_ACK
112 || intent.getState() == IntentState.INST_NACK) {
113 removeIds.add(intent.getId());
114 }
115 }
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700116
117 purge(removeIds);
118 }
119
120 /**
121 * Purge a collection of Intents specified by Intent IDs.
122 *
123 * NOTE: The caller needs to make sure those intents are in a state
124 * that allows them to be removed.
125 *
126 * @param removeIds the collection of Intent IDs to purge.
127 */
128 public void purge(Collection<String> removeIds) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700129 for (String intentId : removeIds) {
130 removeIntent(intentId);
131 }
132 notifyEvents();
133 }
Toshio Koidedf2eab92014-02-20 11:24:59 -0800134
Ray Milkey269ffb92014-04-03 14:43:30 -0700135 public void changeStates(IntentStateList states) {
136 for (Entry<String, IntentState> state : states.entrySet()) {
137 setState(state.getKey(), state.getValue());
138 }
139 notifyEvents();
140 }
Toshio Koideb609b3b2014-02-14 18:25:52 -0800141
Ray Milkey269ffb92014-04-03 14:43:30 -0700142 public Intent getIntent(String intentId) {
143 return intents.get(intentId);
144 }
Toshio Koideb609b3b2014-02-14 18:25:52 -0800145
Ray Milkey269ffb92014-04-03 14:43:30 -0700146 public Collection<Intent> getAllIntents() {
147 return intents.values();
148 }
Toshio Koideb609b3b2014-02-14 18:25:52 -0800149
Ray Milkey269ffb92014-04-03 14:43:30 -0700150 public void addChangeListener(ChangedListener listener) {
151 listeners.add(listener);
152 }
Toshio Koidedf2eab92014-02-20 11:24:59 -0800153
Ray Milkey269ffb92014-04-03 14:43:30 -0700154 public void removeChangedListener(ChangedListener listener) {
155 listeners.remove(listener);
156 }
Toshio Koidedf2eab92014-02-20 11:24:59 -0800157
Ray Milkey269ffb92014-04-03 14:43:30 -0700158 //================================================================================
159 // methods that affect intents map (protected)
160 //================================================================================
Toshio Koidedf2eab92014-02-20 11:24:59 -0800161
Ray Milkey269ffb92014-04-03 14:43:30 -0700162 protected void putIntent(Intent intent) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700163 if (intents.containsKey(intent.getId())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700164 removeIntent(intent.getId());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700165 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700166 intents.put(intent.getId(), intent);
167 events.add(new ChangedEvent(ChangedEventType.ADDED, intent));
168 }
Toshio Koidedf2eab92014-02-20 11:24:59 -0800169
Ray Milkey269ffb92014-04-03 14:43:30 -0700170 protected void removeIntent(String intentId) {
171 Intent intent = intents.remove(intentId);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700172 if (intent == null) {
173 return;
174 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700175 events.add(new ChangedEvent(ChangedEventType.REMOVED, intent));
176 }
Toshio Koidedf2eab92014-02-20 11:24:59 -0800177
Ray Milkey269ffb92014-04-03 14:43:30 -0700178 protected void setState(String intentId, IntentState state) {
179 Intent intent = intents.get(intentId);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700180 if (intent == null) {
181 return;
182 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700183 intent.setState(state);
184 events.add(new ChangedEvent(ChangedEventType.STATE_CHANGED, intent));
185 }
Toshio Koidedf2eab92014-02-20 11:24:59 -0800186
Ray Milkey269ffb92014-04-03 14:43:30 -0700187 //================================================================================
188 // helper methods (protected)
189 //================================================================================
Toshio Koidedf2eab92014-02-20 11:24:59 -0800190
Ray Milkey269ffb92014-04-03 14:43:30 -0700191 protected void handleAddOperation(IntentOperation operation) {
192 putIntent(operation.intent);
193 }
Toshio Koidedf2eab92014-02-20 11:24:59 -0800194
Ray Milkey269ffb92014-04-03 14:43:30 -0700195 protected void handleRemoveOperation(IntentOperation operation) {
196 Intent intent = getIntent(operation.intent.getId());
197 if (intent == null) {
198 // TODO error handling
Ray Milkey1aa71f82014-04-08 16:23:24 -0700199 return;
Ray Milkey269ffb92014-04-03 14:43:30 -0700200 } else {
201 setState(intent.getId(), IntentState.DEL_REQ);
202 }
203 }
Toshio Koidedf2eab92014-02-20 11:24:59 -0800204
Ray Milkey269ffb92014-04-03 14:43:30 -0700205 protected void handleErrorOperation(IntentOperation operation) {
206 //TODO put error message into the intent
Toshio Koidedf2eab92014-02-20 11:24:59 -0800207
Ray Milkey269ffb92014-04-03 14:43:30 -0700208 ErrorIntent errorIntent = (ErrorIntent) operation.intent;
209 Intent targetIntent = intents.get(errorIntent.getId());
210 if (targetIntent == null) {
211 // TODO error handling
212 return;
213 }
Toshio Koidedf2eab92014-02-20 11:24:59 -0800214
Ray Milkey269ffb92014-04-03 14:43:30 -0700215 switch (targetIntent.getState()) {
216 case CREATED:
217 case INST_REQ:
218 case INST_ACK:
219 case REROUTE_REQ:
220 setState(targetIntent.getId(), IntentState.INST_NACK);
221 break;
222 case DEL_REQ:
223 setState(targetIntent.getId(), IntentState.DEL_PENDING);
224 break;
225 case INST_NACK:
226 case DEL_PENDING:
227 case DEL_ACK:
228 // do nothing
229 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -0700230 default:
231 log.error("Unknown intent state {}", targetIntent.getState());
232 break;
Ray Milkey269ffb92014-04-03 14:43:30 -0700233 }
234 }
235
236 protected void notifyEvents() {
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700237 if (events.isEmpty()) {
238 return;
239 }
240
Ray Milkey269ffb92014-04-03 14:43:30 -0700241 for (ChangedListener listener : listeners) {
242 listener.intentsChange(events);
243 }
244 events.clear();
245 }
Toshio Koideb609b3b2014-02-14 18:25:52 -0800246}