blob: d528ed613049eef31f599f44ddee908b9e0642b3 [file] [log] [blame]
Brian O'Connor66630c82014-10-02 21:08:19 -07001package org.onlab.onos.net.intent.impl;
2
Brian O'Connor9cfe8292014-10-24 14:14:08 -07003import static com.google.common.base.Preconditions.checkNotNull;
4import static java.util.concurrent.Executors.newSingleThreadExecutor;
5import static org.onlab.onos.net.intent.IntentState.COMPILING;
6import static org.onlab.onos.net.intent.IntentState.FAILED;
7import static org.onlab.onos.net.intent.IntentState.INSTALLED;
8import static org.onlab.onos.net.intent.IntentState.INSTALLING;
9import static org.onlab.onos.net.intent.IntentState.RECOMPILING;
10import static org.onlab.onos.net.intent.IntentState.WITHDRAWING;
11import static org.onlab.onos.net.intent.IntentState.WITHDRAWN;
12import static org.onlab.util.Tools.namedThreads;
13import static org.slf4j.LoggerFactory.getLogger;
14
15import java.util.ArrayList;
16import java.util.Iterator;
17import java.util.List;
18import java.util.Map;
19import java.util.Objects;
20import java.util.concurrent.ConcurrentHashMap;
21import java.util.concurrent.ConcurrentMap;
22import java.util.concurrent.ExecutionException;
23import java.util.concurrent.ExecutorService;
24import java.util.concurrent.Future;
25import java.util.concurrent.TimeUnit;
26import java.util.concurrent.TimeoutException;
27
Brian O'Connor66630c82014-10-02 21:08:19 -070028import org.apache.felix.scr.annotations.Activate;
29import org.apache.felix.scr.annotations.Component;
30import org.apache.felix.scr.annotations.Deactivate;
31import org.apache.felix.scr.annotations.Reference;
32import org.apache.felix.scr.annotations.ReferenceCardinality;
33import org.apache.felix.scr.annotations.Service;
34import org.onlab.onos.event.AbstractListenerRegistry;
35import org.onlab.onos.event.EventDeliveryService;
Brian O'Connorcb900f42014-10-07 21:55:33 -070036import org.onlab.onos.net.flow.CompletedBatchOperation;
Brian O'Connorf2dbde52014-10-10 16:20:24 -070037import org.onlab.onos.net.flow.FlowRuleBatchOperation;
38import org.onlab.onos.net.flow.FlowRuleService;
Brian O'Connor66630c82014-10-02 21:08:19 -070039import org.onlab.onos.net.intent.Intent;
40import org.onlab.onos.net.intent.IntentCompiler;
41import org.onlab.onos.net.intent.IntentEvent;
42import org.onlab.onos.net.intent.IntentException;
43import org.onlab.onos.net.intent.IntentExtensionService;
44import org.onlab.onos.net.intent.IntentId;
45import org.onlab.onos.net.intent.IntentInstaller;
46import org.onlab.onos.net.intent.IntentListener;
47import org.onlab.onos.net.intent.IntentOperations;
48import org.onlab.onos.net.intent.IntentService;
49import org.onlab.onos.net.intent.IntentState;
50import org.onlab.onos.net.intent.IntentStore;
51import org.onlab.onos.net.intent.IntentStoreDelegate;
52import org.slf4j.Logger;
53
Brian O'Connor9cfe8292014-10-24 14:14:08 -070054import com.google.common.collect.ImmutableList;
55import com.google.common.collect.ImmutableMap;
56import com.google.common.collect.Lists;
Brian O'Connor66630c82014-10-02 21:08:19 -070057
58/**
59 * An implementation of Intent Manager.
60 */
61@Component(immediate = true)
62@Service
63public class IntentManager
64 implements IntentService, IntentExtensionService {
65 private final Logger log = getLogger(getClass());
66
67 public static final String INTENT_NULL = "Intent cannot be null";
68 public static final String INTENT_ID_NULL = "Intent ID cannot be null";
69
70 // Collections for compiler, installer, and listener are ONOS instance local
71 private final ConcurrentMap<Class<? extends Intent>,
72 IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>();
Thomas Vachuskab97cf282014-10-20 23:31:12 -070073 private final ConcurrentMap<Class<? extends Intent>,
74 IntentInstaller<? extends Intent>> installers = new ConcurrentHashMap<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070075
76 private final AbstractListenerRegistry<IntentEvent, IntentListener>
tom95329eb2014-10-06 08:40:06 -070077 listenerRegistry = new AbstractListenerRegistry<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070078
Brian O'Connorcb900f42014-10-07 21:55:33 -070079 private ExecutorService executor;
80 private ExecutorService monitorExecutor;
tom85258ee2014-10-07 00:10:02 -070081
Brian O'Connor66630c82014-10-02 21:08:19 -070082 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
tom95329eb2014-10-06 08:40:06 -070083 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
Brian O'Connor66630c82014-10-02 21:08:19 -070084
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected IntentStore store;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -070089 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -070090
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Brian O'Connor66630c82014-10-02 21:08:19 -070092 protected EventDeliveryService eventDispatcher;
93
Brian O'Connorf2dbde52014-10-10 16:20:24 -070094 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected FlowRuleService flowRuleService;
96
Brian O'Connor66630c82014-10-02 21:08:19 -070097 @Activate
98 public void activate() {
99 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700100 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700101 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700102 executor = newSingleThreadExecutor(namedThreads("onos-intents"));
103 monitorExecutor = newSingleThreadExecutor(namedThreads("onos-intent-monitor"));
Brian O'Connor66630c82014-10-02 21:08:19 -0700104 log.info("Started");
105 }
106
107 @Deactivate
108 public void deactivate() {
109 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700110 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700111 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700112 executor.shutdown();
113 monitorExecutor.shutdown();
Brian O'Connor66630c82014-10-02 21:08:19 -0700114 log.info("Stopped");
115 }
116
117 @Override
118 public void submit(Intent intent) {
119 checkNotNull(intent, INTENT_NULL);
120 registerSubclassCompilerIfNeeded(intent);
121 IntentEvent event = store.createIntent(intent);
tom85258ee2014-10-07 00:10:02 -0700122 if (event != null) {
123 eventDispatcher.post(event);
124 executor.execute(new IntentTask(COMPILING, intent));
125 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700126 }
127
128 @Override
129 public void withdraw(Intent intent) {
130 checkNotNull(intent, INTENT_NULL);
tom85258ee2014-10-07 00:10:02 -0700131 executor.execute(new IntentTask(WITHDRAWING, intent));
Brian O'Connor66630c82014-10-02 21:08:19 -0700132 }
133
134 // FIXME: implement this method
135 @Override
Thomas Vachuska83e090e2014-10-22 14:25:35 -0700136 public void replace(IntentId oldIntentId, Intent newIntent) {
137 throw new UnsupportedOperationException("execute() is not implemented yet");
138 }
139
140 // FIXME: implement this method
141 @Override
Thomas Vachuska1fb982f2014-10-22 14:09:17 -0700142 public Future<IntentOperations> execute(IntentOperations operations) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700143 throw new UnsupportedOperationException("execute() is not implemented yet");
144 }
145
146 @Override
147 public Iterable<Intent> getIntents() {
148 return store.getIntents();
149 }
150
151 @Override
152 public long getIntentCount() {
153 return store.getIntentCount();
154 }
155
156 @Override
157 public Intent getIntent(IntentId id) {
158 checkNotNull(id, INTENT_ID_NULL);
159 return store.getIntent(id);
160 }
161
162 @Override
163 public IntentState getIntentState(IntentId id) {
164 checkNotNull(id, INTENT_ID_NULL);
165 return store.getIntentState(id);
166 }
167
168 @Override
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700169 public List<Intent> getInstallableIntents(IntentId intentId) {
170 checkNotNull(intentId, INTENT_ID_NULL);
171 return store.getInstallableIntents(intentId);
172 }
173
174 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700175 public void addListener(IntentListener listener) {
176 listenerRegistry.addListener(listener);
177 }
178
179 @Override
180 public void removeListener(IntentListener listener) {
181 listenerRegistry.removeListener(listener);
182 }
183
184 @Override
185 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
186 compilers.put(cls, compiler);
187 }
188
189 @Override
190 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
191 compilers.remove(cls);
192 }
193
194 @Override
195 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
196 return ImmutableMap.copyOf(compilers);
197 }
198
199 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700200 public <T extends Intent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700201 installers.put(cls, installer);
202 }
203
204 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700205 public <T extends Intent> void unregisterInstaller(Class<T> cls) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700206 installers.remove(cls);
207 }
208
209 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700210 public Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> getInstallers() {
Brian O'Connor66630c82014-10-02 21:08:19 -0700211 return ImmutableMap.copyOf(installers);
212 }
213
214 /**
Brian O'Connor66630c82014-10-02 21:08:19 -0700215 * Returns the corresponding intent compiler to the specified intent.
216 *
217 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700218 * @param <T> the type of intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700219 * @return intent compiler corresponding to the specified intent
220 */
221 private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
222 @SuppressWarnings("unchecked")
223 IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
224 if (compiler == null) {
225 throw new IntentException("no compiler for class " + intent.getClass());
226 }
227 return compiler;
228 }
229
230 /**
231 * Returns the corresponding intent installer to the specified installable intent.
tom95329eb2014-10-06 08:40:06 -0700232 *
Brian O'Connor66630c82014-10-02 21:08:19 -0700233 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700234 * @param <T> the type of installable intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700235 * @return intent installer corresponding to the specified installable intent
236 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700237 private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700238 @SuppressWarnings("unchecked")
239 IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass());
240 if (installer == null) {
241 throw new IntentException("no installer for class " + intent.getClass());
242 }
243 return installer;
244 }
245
246 /**
tom85258ee2014-10-07 00:10:02 -0700247 * Compiles the specified intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700248 *
tom85258ee2014-10-07 00:10:02 -0700249 * @param intent intent to be compiled
Brian O'Connor66630c82014-10-02 21:08:19 -0700250 */
tom85258ee2014-10-07 00:10:02 -0700251 private void executeCompilingPhase(Intent intent) {
252 // Indicate that the intent is entering the compiling phase.
253 store.setState(intent, COMPILING);
254
255 try {
256 // Compile the intent into installable derivatives.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700257 List<Intent> installable = compileIntent(intent);
tom85258ee2014-10-07 00:10:02 -0700258
259 // If all went well, associate the resulting list of installable
260 // intents with the top-level intent and proceed to install.
261 store.addInstallableIntents(intent.id(), installable);
262 executeInstallingPhase(intent);
263
264 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700265 log.warn("Unable to compile intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700266
tom85258ee2014-10-07 00:10:02 -0700267 // If compilation failed, mark the intent as failed.
weibit50eb95b2014-10-25 21:47:54 -0700268 IntentEvent event = store.setState(intent, FAILED);
269 if (event != null) {
270 eventDispatcher.post(event);
271 }
tom85258ee2014-10-07 00:10:02 -0700272 }
273 }
274
Brian O'Connorcb900f42014-10-07 21:55:33 -0700275 /**
276 * Compiles an intent recursively.
277 *
278 * @param intent intent
279 * @return result of compilation
280 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700281 private List<Intent> compileIntent(Intent intent) {
Thomas Vachuska4926c1b2014-10-21 00:44:10 -0700282 if (intent.isInstallable()) {
283 return ImmutableList.of(intent);
Brian O'Connor66630c82014-10-02 21:08:19 -0700284 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700285
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700286 List<Intent> installable = new ArrayList<>();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700287 // TODO do we need to registerSubclassCompiler?
288 for (Intent compiled : getCompiler(intent).compile(intent)) {
289 installable.addAll(compileIntent(compiled));
290 }
291
tom85258ee2014-10-07 00:10:02 -0700292 return installable;
Brian O'Connor66630c82014-10-02 21:08:19 -0700293 }
294
295 /**
tom85258ee2014-10-07 00:10:02 -0700296 * Installs all installable intents associated with the specified top-level
297 * intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700298 *
tom85258ee2014-10-07 00:10:02 -0700299 * @param intent intent to be installed
Brian O'Connor66630c82014-10-02 21:08:19 -0700300 */
tom85258ee2014-10-07 00:10:02 -0700301 private void executeInstallingPhase(Intent intent) {
302 // Indicate that the intent is entering the installing phase.
303 store.setState(intent, INSTALLING);
304
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700305 List<FlowRuleBatchOperation> installWork = Lists.newArrayList();
tom85258ee2014-10-07 00:10:02 -0700306 try {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700307 List<Intent> installables = store.getInstallableIntents(intent.id());
tom85258ee2014-10-07 00:10:02 -0700308 if (installables != null) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700309 for (Intent installable : installables) {
tom85258ee2014-10-07 00:10:02 -0700310 registerSubclassInstallerIfNeeded(installable);
tom53945d52014-10-07 11:01:36 -0700311 trackerService.addTrackedResources(intent.id(),
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700312 installable.resources());
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700313 List<FlowRuleBatchOperation> batch = getInstaller(installable).install(installable);
314 installWork.addAll(batch);
tom85258ee2014-10-07 00:10:02 -0700315 }
tom95329eb2014-10-06 08:40:06 -0700316 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700317 // FIXME we have to wait for the installable intents
318 //eventDispatcher.post(store.setState(intent, INSTALLED));
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700319 monitorExecutor.execute(new IntentInstallMonitor(intent, installWork, INSTALLED));
tom85258ee2014-10-07 00:10:02 -0700320 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700321 log.warn("Unable to install intent {} due to:", intent.id(), e);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700322 uninstallIntent(intent, RECOMPILING);
tom53945d52014-10-07 11:01:36 -0700323
tom85258ee2014-10-07 00:10:02 -0700324 // If compilation failed, kick off the recompiling phase.
Brian O'Connorcb900f42014-10-07 21:55:33 -0700325 // FIXME
326 //executeRecompilingPhase(intent);
tom85258ee2014-10-07 00:10:02 -0700327 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700328 }
329
330 /**
tom85258ee2014-10-07 00:10:02 -0700331 * Recompiles the specified intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700332 *
tom85258ee2014-10-07 00:10:02 -0700333 * @param intent intent to be recompiled
Brian O'Connor66630c82014-10-02 21:08:19 -0700334 */
tom85258ee2014-10-07 00:10:02 -0700335 private void executeRecompilingPhase(Intent intent) {
336 // Indicate that the intent is entering the recompiling phase.
337 store.setState(intent, RECOMPILING);
338
339 try {
340 // Compile the intent into installable derivatives.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700341 List<Intent> installable = compileIntent(intent);
tom85258ee2014-10-07 00:10:02 -0700342
343 // If all went well, compare the existing list of installable
344 // intents with the newly compiled list. If they are the same,
345 // bail, out since the previous approach was determined not to
346 // be viable.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700347 List<Intent> originalInstallable = store.getInstallableIntents(intent.id());
tom85258ee2014-10-07 00:10:02 -0700348
349 if (Objects.equals(originalInstallable, installable)) {
350 eventDispatcher.post(store.setState(intent, FAILED));
351 } else {
352 // Otherwise, re-associate the newly compiled installable intents
353 // with the top-level intent and kick off installing phase.
354 store.addInstallableIntents(intent.id(), installable);
355 executeInstallingPhase(intent);
356 }
357 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700358 log.warn("Unable to recompile intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700359
tom85258ee2014-10-07 00:10:02 -0700360 // If compilation failed, mark the intent as failed.
361 eventDispatcher.post(store.setState(intent, FAILED));
362 }
363 }
364
365 /**
366 * Uninstalls the specified intent by uninstalling all of its associated
367 * installable derivatives.
368 *
369 * @param intent intent to be installed
370 */
371 private void executeWithdrawingPhase(Intent intent) {
372 // Indicate that the intent is being withdrawn.
373 store.setState(intent, WITHDRAWING);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700374 uninstallIntent(intent, WITHDRAWN);
tom85258ee2014-10-07 00:10:02 -0700375
376 // If all went well, disassociate the top-level intent with its
377 // installable derivatives and mark it as withdrawn.
Brian O'Connorcb900f42014-10-07 21:55:33 -0700378 // FIXME need to clean up
379 //store.removeInstalledIntents(intent.id());
380 // FIXME
381 //eventDispatcher.post(store.setState(intent, WITHDRAWN));
Brian O'Connor66630c82014-10-02 21:08:19 -0700382 }
383
384 /**
tom53945d52014-10-07 11:01:36 -0700385 * Uninstalls all installable intents associated with the given intent.
386 *
387 * @param intent intent to be uninstalled
388 */
Brian O'Connorcb900f42014-10-07 21:55:33 -0700389 private void uninstallIntent(Intent intent, IntentState nextState) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700390 List<FlowRuleBatchOperation> uninstallWork = Lists.newArrayList();
tom53945d52014-10-07 11:01:36 -0700391 try {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700392 List<Intent> installables = store.getInstallableIntents(intent.id());
tom53945d52014-10-07 11:01:36 -0700393 if (installables != null) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700394 for (Intent installable : installables) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700395 List<FlowRuleBatchOperation> batches = getInstaller(installable).uninstall(installable);
396 uninstallWork.addAll(batches);
tom53945d52014-10-07 11:01:36 -0700397 }
398 }
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700399 monitorExecutor.execute(new IntentInstallMonitor(intent, uninstallWork, nextState));
tom53945d52014-10-07 11:01:36 -0700400 } catch (IntentException e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700401 log.warn("Unable to uninstall intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700402 }
403 }
404
405 /**
Brian O'Connor66630c82014-10-02 21:08:19 -0700406 * Registers an intent compiler of the specified intent if an intent compiler
407 * for the intent is not registered. This method traverses the class hierarchy of
408 * the intent. Once an intent compiler for a parent type is found, this method
409 * registers the found intent compiler.
410 *
411 * @param intent intent
412 */
413 private void registerSubclassCompilerIfNeeded(Intent intent) {
414 if (!compilers.containsKey(intent.getClass())) {
415 Class<?> cls = intent.getClass();
416 while (cls != Object.class) {
417 // As long as we're within the Intent class descendants
418 if (Intent.class.isAssignableFrom(cls)) {
419 IntentCompiler<?> compiler = compilers.get(cls);
420 if (compiler != null) {
421 compilers.put(intent.getClass(), compiler);
422 return;
423 }
424 }
425 cls = cls.getSuperclass();
426 }
427 }
428 }
429
430 /**
431 * Registers an intent installer of the specified intent if an intent installer
432 * for the intent is not registered. This method traverses the class hierarchy of
433 * the intent. Once an intent installer for a parent type is found, this method
434 * registers the found intent installer.
435 *
436 * @param intent intent
437 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700438 private void registerSubclassInstallerIfNeeded(Intent intent) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700439 if (!installers.containsKey(intent.getClass())) {
440 Class<?> cls = intent.getClass();
441 while (cls != Object.class) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700442 // As long as we're within the Intent class descendants
443 if (Intent.class.isAssignableFrom(cls)) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700444 IntentInstaller<?> installer = installers.get(cls);
445 if (installer != null) {
446 installers.put(intent.getClass(), installer);
447 return;
448 }
449 }
450 cls = cls.getSuperclass();
451 }
452 }
453 }
454
Brian O'Connor66630c82014-10-02 21:08:19 -0700455 // Store delegate to re-post events emitted from the store.
456 private class InternalStoreDelegate implements IntentStoreDelegate {
457 @Override
458 public void notify(IntentEvent event) {
tom85258ee2014-10-07 00:10:02 -0700459 eventDispatcher.post(event);
460 if (event.type() == IntentEvent.Type.SUBMITTED) {
461 executor.execute(new IntentTask(COMPILING, event.subject()));
462 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700463 }
464 }
465
tom95329eb2014-10-06 08:40:06 -0700466 // Topology change delegate
467 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
468 @Override
tom85258ee2014-10-07 00:10:02 -0700469 public void triggerCompile(Iterable<IntentId> intentIds,
470 boolean compileAllFailed) {
471 // Attempt recompilation of the specified intents first.
tom95329eb2014-10-06 08:40:06 -0700472 for (IntentId intentId : intentIds) {
tom53945d52014-10-07 11:01:36 -0700473 Intent intent = getIntent(intentId);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700474 uninstallIntent(intent, RECOMPILING);
alshabib8ca53902014-10-07 13:11:17 -0700475
Brian O'Connorcb900f42014-10-07 21:55:33 -0700476 //FIXME
477 //executeRecompilingPhase(intent);
tom85258ee2014-10-07 00:10:02 -0700478 }
479
480 if (compileAllFailed) {
481 // If required, compile all currently failed intents.
482 for (Intent intent : getIntents()) {
483 if (getIntentState(intent.id()) == FAILED) {
484 executeCompilingPhase(intent);
485 }
486 }
tom95329eb2014-10-06 08:40:06 -0700487 }
488 }
tom95329eb2014-10-06 08:40:06 -0700489 }
tom85258ee2014-10-07 00:10:02 -0700490
491 // Auxiliary runnable to perform asynchronous tasks.
492 private class IntentTask implements Runnable {
493 private final IntentState state;
494 private final Intent intent;
495
496 public IntentTask(IntentState state, Intent intent) {
497 this.state = state;
498 this.intent = intent;
499 }
500
501 @Override
502 public void run() {
503 if (state == COMPILING) {
504 executeCompilingPhase(intent);
505 } else if (state == RECOMPILING) {
506 executeRecompilingPhase(intent);
507 } else if (state == WITHDRAWING) {
508 executeWithdrawingPhase(intent);
509 }
510 }
511 }
512
Brian O'Connorcb900f42014-10-07 21:55:33 -0700513 private class IntentInstallMonitor implements Runnable {
514
515 private final Intent intent;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700516 private final List<FlowRuleBatchOperation> work;
Brian O'Connorcb900f42014-10-07 21:55:33 -0700517 private final List<Future<CompletedBatchOperation>> futures;
518 private final IntentState nextState;
519
520 public IntentInstallMonitor(Intent intent,
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700521 List<FlowRuleBatchOperation> work,
522 IntentState nextState) {
Brian O'Connorcb900f42014-10-07 21:55:33 -0700523 this.intent = intent;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700524 this.work = work;
525 // TODO how many Futures can be outstanding? one?
526 this.futures = Lists.newLinkedList();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700527 this.nextState = nextState;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700528
529 // TODO need to kick off the first batch sometime, why not now?
530 futures.add(applyNextBatch());
Brian O'Connorcb900f42014-10-07 21:55:33 -0700531 }
532
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700533 /**
534 * Update the intent store with the next status for this intent.
535 */
536 private void updateIntent() {
Brian O'Connorcb900f42014-10-07 21:55:33 -0700537 if (nextState == RECOMPILING) {
538 executor.execute(new IntentTask(nextState, intent));
539 } else if (nextState == INSTALLED || nextState == WITHDRAWN) {
540 eventDispatcher.post(store.setState(intent, nextState));
541 } else {
542 log.warn("Invalid next intent state {} for intent {}", nextState, intent);
543 }
544 }
545
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700546 /**
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700547 * Applies the next batch.
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700548 */
549 private Future<CompletedBatchOperation> applyNextBatch() {
550 if (work.isEmpty()) {
551 return null;
552 }
553 FlowRuleBatchOperation batch = work.remove(0);
554 return flowRuleService.applyBatch(batch);
555 }
556
557 /**
558 * Iterate through the pending futures, and remove them when they have completed.
559 */
560 private void processFutures() {
561 List<Future<CompletedBatchOperation>> newFutures = Lists.newArrayList();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700562 for (Iterator<Future<CompletedBatchOperation>> i = futures.iterator(); i.hasNext();) {
563 Future<CompletedBatchOperation> future = i.next();
alshabib26834582014-10-08 20:15:46 -0700564 try {
565 // TODO: we may want to get the future here and go back to the future.
alshabibc7e1cb62014-10-08 20:20:03 -0700566 CompletedBatchOperation completed = future.get(100, TimeUnit.NANOSECONDS);
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700567 if (completed.isSuccess()) {
568 Future<CompletedBatchOperation> newFuture = applyNextBatch();
569 if (newFuture != null) {
570 // we'll add this later so that we don't get a ConcurrentModException
571 newFutures.add(newFuture);
572 }
573 } else {
574 // TODO check if future succeeded and if not report fail items
575 log.warn("Failed items: {}", completed.failedItems());
576 // TODO revert....
577 //uninstallIntent(intent, RECOMPILING);
578 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700579 i.remove();
alshabib26834582014-10-08 20:15:46 -0700580 } catch (TimeoutException | InterruptedException | ExecutionException te) {
581 log.debug("Intallations of intent {} is still pending", intent);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700582 }
583 }
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700584 futures.addAll(newFutures);
585 }
586
587 @Override
588 public void run() {
589 processFutures();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700590 if (futures.isEmpty()) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700591 // woohoo! we are done!
592 updateIntent();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700593 } else {
594 // resubmit ourselves if we are not done yet
595 monitorExecutor.submit(this);
596 }
597 }
598 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700599}