blob: 18388146271f371bf38c9e23b355b333862b0f33 [file] [log] [blame]
Brian O'Connor66630c82014-10-02 21:08:19 -07001package org.onlab.onos.net.intent.impl;
2
Thomas Vachuskab97cf282014-10-20 23:31:12 -07003import com.google.common.collect.ImmutableList;
4import com.google.common.collect.ImmutableMap;
5import com.google.common.collect.Lists;
Brian O'Connor66630c82014-10-02 21:08:19 -07006import org.apache.felix.scr.annotations.Activate;
7import org.apache.felix.scr.annotations.Component;
8import org.apache.felix.scr.annotations.Deactivate;
9import org.apache.felix.scr.annotations.Reference;
10import org.apache.felix.scr.annotations.ReferenceCardinality;
11import org.apache.felix.scr.annotations.Service;
12import org.onlab.onos.event.AbstractListenerRegistry;
13import org.onlab.onos.event.EventDeliveryService;
Brian O'Connorcb900f42014-10-07 21:55:33 -070014import org.onlab.onos.net.flow.CompletedBatchOperation;
Brian O'Connorf2dbde52014-10-10 16:20:24 -070015import org.onlab.onos.net.flow.FlowRuleBatchOperation;
16import org.onlab.onos.net.flow.FlowRuleService;
Brian O'Connor66630c82014-10-02 21:08:19 -070017import org.onlab.onos.net.intent.Intent;
18import org.onlab.onos.net.intent.IntentCompiler;
19import org.onlab.onos.net.intent.IntentEvent;
20import org.onlab.onos.net.intent.IntentException;
21import org.onlab.onos.net.intent.IntentExtensionService;
22import org.onlab.onos.net.intent.IntentId;
23import org.onlab.onos.net.intent.IntentInstaller;
24import org.onlab.onos.net.intent.IntentListener;
25import org.onlab.onos.net.intent.IntentOperations;
26import org.onlab.onos.net.intent.IntentService;
27import org.onlab.onos.net.intent.IntentState;
28import org.onlab.onos.net.intent.IntentStore;
29import org.onlab.onos.net.intent.IntentStoreDelegate;
30import org.slf4j.Logger;
31
Thomas Vachuskab97cf282014-10-20 23:31:12 -070032import java.util.ArrayList;
33import java.util.Iterator;
34import java.util.List;
35import java.util.Map;
36import java.util.Objects;
37import java.util.concurrent.ConcurrentHashMap;
38import java.util.concurrent.ConcurrentMap;
39import java.util.concurrent.ExecutionException;
40import java.util.concurrent.ExecutorService;
41import java.util.concurrent.Future;
42import java.util.concurrent.TimeUnit;
43import java.util.concurrent.TimeoutException;
44
45import static com.google.common.base.Preconditions.checkNotNull;
46import static java.util.concurrent.Executors.newSingleThreadExecutor;
47import static org.onlab.onos.net.intent.IntentState.*;
48import static org.onlab.util.Tools.namedThreads;
49import static org.slf4j.LoggerFactory.getLogger;
Brian O'Connor66630c82014-10-02 21:08:19 -070050
51/**
52 * An implementation of Intent Manager.
53 */
54@Component(immediate = true)
55@Service
56public class IntentManager
57 implements IntentService, IntentExtensionService {
58 private final Logger log = getLogger(getClass());
59
60 public static final String INTENT_NULL = "Intent cannot be null";
61 public static final String INTENT_ID_NULL = "Intent ID cannot be null";
62
63 // Collections for compiler, installer, and listener are ONOS instance local
64 private final ConcurrentMap<Class<? extends Intent>,
65 IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>();
Thomas Vachuskab97cf282014-10-20 23:31:12 -070066 private final ConcurrentMap<Class<? extends Intent>,
67 IntentInstaller<? extends Intent>> installers = new ConcurrentHashMap<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070068
69 private final AbstractListenerRegistry<IntentEvent, IntentListener>
tom95329eb2014-10-06 08:40:06 -070070 listenerRegistry = new AbstractListenerRegistry<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070071
Brian O'Connorcb900f42014-10-07 21:55:33 -070072 private ExecutorService executor;
73 private ExecutorService monitorExecutor;
tom85258ee2014-10-07 00:10:02 -070074
Brian O'Connor66630c82014-10-02 21:08:19 -070075 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
tom95329eb2014-10-06 08:40:06 -070076 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
Brian O'Connor66630c82014-10-02 21:08:19 -070077
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected IntentStore store;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -070082 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -070083
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Brian O'Connor66630c82014-10-02 21:08:19 -070085 protected EventDeliveryService eventDispatcher;
86
Brian O'Connorf2dbde52014-10-10 16:20:24 -070087 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected FlowRuleService flowRuleService;
89
Brian O'Connor66630c82014-10-02 21:08:19 -070090 @Activate
91 public void activate() {
92 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -070093 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -070094 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorcb900f42014-10-07 21:55:33 -070095 executor = newSingleThreadExecutor(namedThreads("onos-intents"));
96 monitorExecutor = newSingleThreadExecutor(namedThreads("onos-intent-monitor"));
Brian O'Connor66630c82014-10-02 21:08:19 -070097 log.info("Started");
98 }
99
100 @Deactivate
101 public void deactivate() {
102 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700103 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700104 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700105 executor.shutdown();
106 monitorExecutor.shutdown();
Brian O'Connor66630c82014-10-02 21:08:19 -0700107 log.info("Stopped");
108 }
109
110 @Override
111 public void submit(Intent intent) {
112 checkNotNull(intent, INTENT_NULL);
113 registerSubclassCompilerIfNeeded(intent);
114 IntentEvent event = store.createIntent(intent);
tom85258ee2014-10-07 00:10:02 -0700115 if (event != null) {
116 eventDispatcher.post(event);
117 executor.execute(new IntentTask(COMPILING, intent));
118 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700119 }
120
121 @Override
122 public void withdraw(Intent intent) {
123 checkNotNull(intent, INTENT_NULL);
tom85258ee2014-10-07 00:10:02 -0700124 executor.execute(new IntentTask(WITHDRAWING, intent));
Brian O'Connor66630c82014-10-02 21:08:19 -0700125 }
126
127 // FIXME: implement this method
128 @Override
129 public void execute(IntentOperations operations) {
130 throw new UnsupportedOperationException("execute() is not implemented yet");
131 }
132
133 @Override
134 public Iterable<Intent> getIntents() {
135 return store.getIntents();
136 }
137
138 @Override
139 public long getIntentCount() {
140 return store.getIntentCount();
141 }
142
143 @Override
144 public Intent getIntent(IntentId id) {
145 checkNotNull(id, INTENT_ID_NULL);
146 return store.getIntent(id);
147 }
148
149 @Override
150 public IntentState getIntentState(IntentId id) {
151 checkNotNull(id, INTENT_ID_NULL);
152 return store.getIntentState(id);
153 }
154
155 @Override
156 public void addListener(IntentListener listener) {
157 listenerRegistry.addListener(listener);
158 }
159
160 @Override
161 public void removeListener(IntentListener listener) {
162 listenerRegistry.removeListener(listener);
163 }
164
165 @Override
166 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
167 compilers.put(cls, compiler);
168 }
169
170 @Override
171 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
172 compilers.remove(cls);
173 }
174
175 @Override
176 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
177 return ImmutableMap.copyOf(compilers);
178 }
179
180 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700181 public <T extends Intent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700182 installers.put(cls, installer);
183 }
184
185 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700186 public <T extends Intent> void unregisterInstaller(Class<T> cls) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700187 installers.remove(cls);
188 }
189
190 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700191 public Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> getInstallers() {
Brian O'Connor66630c82014-10-02 21:08:19 -0700192 return ImmutableMap.copyOf(installers);
193 }
194
195 /**
Brian O'Connor66630c82014-10-02 21:08:19 -0700196 * Returns the corresponding intent compiler to the specified intent.
197 *
198 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700199 * @param <T> the type of intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700200 * @return intent compiler corresponding to the specified intent
201 */
202 private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
203 @SuppressWarnings("unchecked")
204 IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
205 if (compiler == null) {
206 throw new IntentException("no compiler for class " + intent.getClass());
207 }
208 return compiler;
209 }
210
211 /**
212 * Returns the corresponding intent installer to the specified installable intent.
tom95329eb2014-10-06 08:40:06 -0700213 *
Brian O'Connor66630c82014-10-02 21:08:19 -0700214 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700215 * @param <T> the type of installable intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700216 * @return intent installer corresponding to the specified installable intent
217 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700218 private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700219 @SuppressWarnings("unchecked")
220 IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass());
221 if (installer == null) {
222 throw new IntentException("no installer for class " + intent.getClass());
223 }
224 return installer;
225 }
226
227 /**
tom85258ee2014-10-07 00:10:02 -0700228 * Compiles the specified intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700229 *
tom85258ee2014-10-07 00:10:02 -0700230 * @param intent intent to be compiled
Brian O'Connor66630c82014-10-02 21:08:19 -0700231 */
tom85258ee2014-10-07 00:10:02 -0700232 private void executeCompilingPhase(Intent intent) {
233 // Indicate that the intent is entering the compiling phase.
234 store.setState(intent, COMPILING);
235
236 try {
237 // Compile the intent into installable derivatives.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700238 List<Intent> installable = compileIntent(intent);
tom85258ee2014-10-07 00:10:02 -0700239
240 // If all went well, associate the resulting list of installable
241 // intents with the top-level intent and proceed to install.
242 store.addInstallableIntents(intent.id(), installable);
243 executeInstallingPhase(intent);
244
245 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700246 log.warn("Unable to compile intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700247
tom85258ee2014-10-07 00:10:02 -0700248 // If compilation failed, mark the intent as failed.
249 store.setState(intent, FAILED);
250 }
251 }
252
Brian O'Connorcb900f42014-10-07 21:55:33 -0700253 /**
254 * Compiles an intent recursively.
255 *
256 * @param intent intent
257 * @return result of compilation
258 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700259 private List<Intent> compileIntent(Intent intent) {
260 if (intent instanceof Intent) {
261 return ImmutableList.of((Intent) intent);
Brian O'Connor66630c82014-10-02 21:08:19 -0700262 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700263
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700264 List<Intent> installable = new ArrayList<>();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700265 // TODO do we need to registerSubclassCompiler?
266 for (Intent compiled : getCompiler(intent).compile(intent)) {
267 installable.addAll(compileIntent(compiled));
268 }
269
tom85258ee2014-10-07 00:10:02 -0700270 return installable;
Brian O'Connor66630c82014-10-02 21:08:19 -0700271 }
272
273 /**
tom85258ee2014-10-07 00:10:02 -0700274 * Installs all installable intents associated with the specified top-level
275 * intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700276 *
tom85258ee2014-10-07 00:10:02 -0700277 * @param intent intent to be installed
Brian O'Connor66630c82014-10-02 21:08:19 -0700278 */
tom85258ee2014-10-07 00:10:02 -0700279 private void executeInstallingPhase(Intent intent) {
280 // Indicate that the intent is entering the installing phase.
281 store.setState(intent, INSTALLING);
282
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700283 List<FlowRuleBatchOperation> installWork = Lists.newArrayList();
tom85258ee2014-10-07 00:10:02 -0700284 try {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700285 List<Intent> installables = store.getInstallableIntents(intent.id());
tom85258ee2014-10-07 00:10:02 -0700286 if (installables != null) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700287 for (Intent installable : installables) {
tom85258ee2014-10-07 00:10:02 -0700288 registerSubclassInstallerIfNeeded(installable);
tom53945d52014-10-07 11:01:36 -0700289 trackerService.addTrackedResources(intent.id(),
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700290 installable.resources());
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700291 List<FlowRuleBatchOperation> batch = getInstaller(installable).install(installable);
292 installWork.addAll(batch);
tom85258ee2014-10-07 00:10:02 -0700293 }
tom95329eb2014-10-06 08:40:06 -0700294 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700295 // FIXME we have to wait for the installable intents
296 //eventDispatcher.post(store.setState(intent, INSTALLED));
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700297 monitorExecutor.execute(new IntentInstallMonitor(intent, installWork, INSTALLED));
tom85258ee2014-10-07 00:10:02 -0700298 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700299 log.warn("Unable to install intent {} due to:", intent.id(), e);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700300 uninstallIntent(intent, RECOMPILING);
tom53945d52014-10-07 11:01:36 -0700301
tom85258ee2014-10-07 00:10:02 -0700302 // If compilation failed, kick off the recompiling phase.
Brian O'Connorcb900f42014-10-07 21:55:33 -0700303 // FIXME
304 //executeRecompilingPhase(intent);
tom85258ee2014-10-07 00:10:02 -0700305 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700306 }
307
308 /**
tom85258ee2014-10-07 00:10:02 -0700309 * Recompiles the specified intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700310 *
tom85258ee2014-10-07 00:10:02 -0700311 * @param intent intent to be recompiled
Brian O'Connor66630c82014-10-02 21:08:19 -0700312 */
tom85258ee2014-10-07 00:10:02 -0700313 private void executeRecompilingPhase(Intent intent) {
314 // Indicate that the intent is entering the recompiling phase.
315 store.setState(intent, RECOMPILING);
316
317 try {
318 // Compile the intent into installable derivatives.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700319 List<Intent> installable = compileIntent(intent);
tom85258ee2014-10-07 00:10:02 -0700320
321 // If all went well, compare the existing list of installable
322 // intents with the newly compiled list. If they are the same,
323 // bail, out since the previous approach was determined not to
324 // be viable.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700325 List<Intent> originalInstallable = store.getInstallableIntents(intent.id());
tom85258ee2014-10-07 00:10:02 -0700326
327 if (Objects.equals(originalInstallable, installable)) {
328 eventDispatcher.post(store.setState(intent, FAILED));
329 } else {
330 // Otherwise, re-associate the newly compiled installable intents
331 // with the top-level intent and kick off installing phase.
332 store.addInstallableIntents(intent.id(), installable);
333 executeInstallingPhase(intent);
334 }
335 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700336 log.warn("Unable to recompile intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700337
tom85258ee2014-10-07 00:10:02 -0700338 // If compilation failed, mark the intent as failed.
339 eventDispatcher.post(store.setState(intent, FAILED));
340 }
341 }
342
343 /**
344 * Uninstalls the specified intent by uninstalling all of its associated
345 * installable derivatives.
346 *
347 * @param intent intent to be installed
348 */
349 private void executeWithdrawingPhase(Intent intent) {
350 // Indicate that the intent is being withdrawn.
351 store.setState(intent, WITHDRAWING);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700352 uninstallIntent(intent, WITHDRAWN);
tom85258ee2014-10-07 00:10:02 -0700353
354 // If all went well, disassociate the top-level intent with its
355 // installable derivatives and mark it as withdrawn.
Brian O'Connorcb900f42014-10-07 21:55:33 -0700356 // FIXME need to clean up
357 //store.removeInstalledIntents(intent.id());
358 // FIXME
359 //eventDispatcher.post(store.setState(intent, WITHDRAWN));
Brian O'Connor66630c82014-10-02 21:08:19 -0700360 }
361
362 /**
tom53945d52014-10-07 11:01:36 -0700363 * Uninstalls all installable intents associated with the given intent.
364 *
365 * @param intent intent to be uninstalled
366 */
Brian O'Connorcb900f42014-10-07 21:55:33 -0700367 private void uninstallIntent(Intent intent, IntentState nextState) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700368 List<FlowRuleBatchOperation> uninstallWork = Lists.newArrayList();
tom53945d52014-10-07 11:01:36 -0700369 try {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700370 List<Intent> installables = store.getInstallableIntents(intent.id());
tom53945d52014-10-07 11:01:36 -0700371 if (installables != null) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700372 for (Intent installable : installables) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700373 List<FlowRuleBatchOperation> batches = getInstaller(installable).uninstall(installable);
374 uninstallWork.addAll(batches);
tom53945d52014-10-07 11:01:36 -0700375 }
376 }
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700377 monitorExecutor.execute(new IntentInstallMonitor(intent, uninstallWork, nextState));
tom53945d52014-10-07 11:01:36 -0700378 } catch (IntentException e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700379 log.warn("Unable to uninstall intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700380 }
381 }
382
383 /**
Brian O'Connor66630c82014-10-02 21:08:19 -0700384 * Registers an intent compiler of the specified intent if an intent compiler
385 * for the intent is not registered. This method traverses the class hierarchy of
386 * the intent. Once an intent compiler for a parent type is found, this method
387 * registers the found intent compiler.
388 *
389 * @param intent intent
390 */
391 private void registerSubclassCompilerIfNeeded(Intent intent) {
392 if (!compilers.containsKey(intent.getClass())) {
393 Class<?> cls = intent.getClass();
394 while (cls != Object.class) {
395 // As long as we're within the Intent class descendants
396 if (Intent.class.isAssignableFrom(cls)) {
397 IntentCompiler<?> compiler = compilers.get(cls);
398 if (compiler != null) {
399 compilers.put(intent.getClass(), compiler);
400 return;
401 }
402 }
403 cls = cls.getSuperclass();
404 }
405 }
406 }
407
408 /**
409 * Registers an intent installer of the specified intent if an intent installer
410 * for the intent is not registered. This method traverses the class hierarchy of
411 * the intent. Once an intent installer for a parent type is found, this method
412 * registers the found intent installer.
413 *
414 * @param intent intent
415 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700416 private void registerSubclassInstallerIfNeeded(Intent intent) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700417 if (!installers.containsKey(intent.getClass())) {
418 Class<?> cls = intent.getClass();
419 while (cls != Object.class) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700420 // As long as we're within the Intent class descendants
421 if (Intent.class.isAssignableFrom(cls)) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700422 IntentInstaller<?> installer = installers.get(cls);
423 if (installer != null) {
424 installers.put(intent.getClass(), installer);
425 return;
426 }
427 }
428 cls = cls.getSuperclass();
429 }
430 }
431 }
432
Brian O'Connor66630c82014-10-02 21:08:19 -0700433 // Store delegate to re-post events emitted from the store.
434 private class InternalStoreDelegate implements IntentStoreDelegate {
435 @Override
436 public void notify(IntentEvent event) {
tom85258ee2014-10-07 00:10:02 -0700437 eventDispatcher.post(event);
438 if (event.type() == IntentEvent.Type.SUBMITTED) {
439 executor.execute(new IntentTask(COMPILING, event.subject()));
440 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700441 }
442 }
443
tom95329eb2014-10-06 08:40:06 -0700444 // Topology change delegate
445 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
446 @Override
tom85258ee2014-10-07 00:10:02 -0700447 public void triggerCompile(Iterable<IntentId> intentIds,
448 boolean compileAllFailed) {
449 // Attempt recompilation of the specified intents first.
tom95329eb2014-10-06 08:40:06 -0700450 for (IntentId intentId : intentIds) {
tom53945d52014-10-07 11:01:36 -0700451 Intent intent = getIntent(intentId);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700452 uninstallIntent(intent, RECOMPILING);
alshabib8ca53902014-10-07 13:11:17 -0700453
Brian O'Connorcb900f42014-10-07 21:55:33 -0700454 //FIXME
455 //executeRecompilingPhase(intent);
tom85258ee2014-10-07 00:10:02 -0700456 }
457
458 if (compileAllFailed) {
459 // If required, compile all currently failed intents.
460 for (Intent intent : getIntents()) {
461 if (getIntentState(intent.id()) == FAILED) {
462 executeCompilingPhase(intent);
463 }
464 }
tom95329eb2014-10-06 08:40:06 -0700465 }
466 }
tom95329eb2014-10-06 08:40:06 -0700467 }
tom85258ee2014-10-07 00:10:02 -0700468
469 // Auxiliary runnable to perform asynchronous tasks.
470 private class IntentTask implements Runnable {
471 private final IntentState state;
472 private final Intent intent;
473
474 public IntentTask(IntentState state, Intent intent) {
475 this.state = state;
476 this.intent = intent;
477 }
478
479 @Override
480 public void run() {
481 if (state == COMPILING) {
482 executeCompilingPhase(intent);
483 } else if (state == RECOMPILING) {
484 executeRecompilingPhase(intent);
485 } else if (state == WITHDRAWING) {
486 executeWithdrawingPhase(intent);
487 }
488 }
489 }
490
Brian O'Connorcb900f42014-10-07 21:55:33 -0700491 private class IntentInstallMonitor implements Runnable {
492
493 private final Intent intent;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700494 private final List<FlowRuleBatchOperation> work;
Brian O'Connorcb900f42014-10-07 21:55:33 -0700495 private final List<Future<CompletedBatchOperation>> futures;
496 private final IntentState nextState;
497
498 public IntentInstallMonitor(Intent intent,
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700499 List<FlowRuleBatchOperation> work,
500 IntentState nextState) {
Brian O'Connorcb900f42014-10-07 21:55:33 -0700501 this.intent = intent;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700502 this.work = work;
503 // TODO how many Futures can be outstanding? one?
504 this.futures = Lists.newLinkedList();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700505 this.nextState = nextState;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700506
507 // TODO need to kick off the first batch sometime, why not now?
508 futures.add(applyNextBatch());
Brian O'Connorcb900f42014-10-07 21:55:33 -0700509 }
510
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700511 /**
512 * Update the intent store with the next status for this intent.
513 */
514 private void updateIntent() {
Brian O'Connorcb900f42014-10-07 21:55:33 -0700515 if (nextState == RECOMPILING) {
516 executor.execute(new IntentTask(nextState, intent));
517 } else if (nextState == INSTALLED || nextState == WITHDRAWN) {
518 eventDispatcher.post(store.setState(intent, nextState));
519 } else {
520 log.warn("Invalid next intent state {} for intent {}", nextState, intent);
521 }
522 }
523
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700524 /**
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700525 * Applies the next batch.
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700526 */
527 private Future<CompletedBatchOperation> applyNextBatch() {
528 if (work.isEmpty()) {
529 return null;
530 }
531 FlowRuleBatchOperation batch = work.remove(0);
532 return flowRuleService.applyBatch(batch);
533 }
534
535 /**
536 * Iterate through the pending futures, and remove them when they have completed.
537 */
538 private void processFutures() {
539 List<Future<CompletedBatchOperation>> newFutures = Lists.newArrayList();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700540 for (Iterator<Future<CompletedBatchOperation>> i = futures.iterator(); i.hasNext();) {
541 Future<CompletedBatchOperation> future = i.next();
alshabib26834582014-10-08 20:15:46 -0700542 try {
543 // TODO: we may want to get the future here and go back to the future.
alshabibc7e1cb62014-10-08 20:20:03 -0700544 CompletedBatchOperation completed = future.get(100, TimeUnit.NANOSECONDS);
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700545 if (completed.isSuccess()) {
546 Future<CompletedBatchOperation> newFuture = applyNextBatch();
547 if (newFuture != null) {
548 // we'll add this later so that we don't get a ConcurrentModException
549 newFutures.add(newFuture);
550 }
551 } else {
552 // TODO check if future succeeded and if not report fail items
553 log.warn("Failed items: {}", completed.failedItems());
554 // TODO revert....
555 //uninstallIntent(intent, RECOMPILING);
556 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700557 i.remove();
alshabib26834582014-10-08 20:15:46 -0700558 } catch (TimeoutException | InterruptedException | ExecutionException te) {
559 log.debug("Intallations of intent {} is still pending", intent);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700560 }
561 }
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700562 futures.addAll(newFutures);
563 }
564
565 @Override
566 public void run() {
567 processFutures();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700568 if (futures.isEmpty()) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700569 // woohoo! we are done!
570 updateIntent();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700571 } else {
572 // resubmit ourselves if we are not done yet
573 monitorExecutor.submit(this);
574 }
575 }
576 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700577}