blob: bfdc57e15199e1816aedc46af1e7ef549616795b [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
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700156 public List<Intent> getInstallableIntents(IntentId intentId) {
157 checkNotNull(intentId, INTENT_ID_NULL);
158 return store.getInstallableIntents(intentId);
159 }
160
161 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700162 public void addListener(IntentListener listener) {
163 listenerRegistry.addListener(listener);
164 }
165
166 @Override
167 public void removeListener(IntentListener listener) {
168 listenerRegistry.removeListener(listener);
169 }
170
171 @Override
172 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
173 compilers.put(cls, compiler);
174 }
175
176 @Override
177 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
178 compilers.remove(cls);
179 }
180
181 @Override
182 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
183 return ImmutableMap.copyOf(compilers);
184 }
185
186 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700187 public <T extends Intent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700188 installers.put(cls, installer);
189 }
190
191 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700192 public <T extends Intent> void unregisterInstaller(Class<T> cls) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700193 installers.remove(cls);
194 }
195
196 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700197 public Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> getInstallers() {
Brian O'Connor66630c82014-10-02 21:08:19 -0700198 return ImmutableMap.copyOf(installers);
199 }
200
201 /**
Brian O'Connor66630c82014-10-02 21:08:19 -0700202 * Returns the corresponding intent compiler to the specified intent.
203 *
204 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700205 * @param <T> the type of intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700206 * @return intent compiler corresponding to the specified intent
207 */
208 private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
209 @SuppressWarnings("unchecked")
210 IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
211 if (compiler == null) {
212 throw new IntentException("no compiler for class " + intent.getClass());
213 }
214 return compiler;
215 }
216
217 /**
218 * Returns the corresponding intent installer to the specified installable intent.
tom95329eb2014-10-06 08:40:06 -0700219 *
Brian O'Connor66630c82014-10-02 21:08:19 -0700220 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700221 * @param <T> the type of installable intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700222 * @return intent installer corresponding to the specified installable intent
223 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700224 private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700225 @SuppressWarnings("unchecked")
226 IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass());
227 if (installer == null) {
228 throw new IntentException("no installer for class " + intent.getClass());
229 }
230 return installer;
231 }
232
233 /**
tom85258ee2014-10-07 00:10:02 -0700234 * Compiles the specified intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700235 *
tom85258ee2014-10-07 00:10:02 -0700236 * @param intent intent to be compiled
Brian O'Connor66630c82014-10-02 21:08:19 -0700237 */
tom85258ee2014-10-07 00:10:02 -0700238 private void executeCompilingPhase(Intent intent) {
239 // Indicate that the intent is entering the compiling phase.
240 store.setState(intent, COMPILING);
241
242 try {
243 // Compile the intent into installable derivatives.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700244 List<Intent> installable = compileIntent(intent);
tom85258ee2014-10-07 00:10:02 -0700245
246 // If all went well, associate the resulting list of installable
247 // intents with the top-level intent and proceed to install.
248 store.addInstallableIntents(intent.id(), installable);
249 executeInstallingPhase(intent);
250
251 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700252 log.warn("Unable to compile intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700253
tom85258ee2014-10-07 00:10:02 -0700254 // If compilation failed, mark the intent as failed.
255 store.setState(intent, FAILED);
256 }
257 }
258
Brian O'Connorcb900f42014-10-07 21:55:33 -0700259 /**
260 * Compiles an intent recursively.
261 *
262 * @param intent intent
263 * @return result of compilation
264 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700265 private List<Intent> compileIntent(Intent intent) {
Thomas Vachuska4926c1b2014-10-21 00:44:10 -0700266 if (intent.isInstallable()) {
267 return ImmutableList.of(intent);
Brian O'Connor66630c82014-10-02 21:08:19 -0700268 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700269
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700270 List<Intent> installable = new ArrayList<>();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700271 // TODO do we need to registerSubclassCompiler?
272 for (Intent compiled : getCompiler(intent).compile(intent)) {
273 installable.addAll(compileIntent(compiled));
274 }
275
tom85258ee2014-10-07 00:10:02 -0700276 return installable;
Brian O'Connor66630c82014-10-02 21:08:19 -0700277 }
278
279 /**
tom85258ee2014-10-07 00:10:02 -0700280 * Installs all installable intents associated with the specified top-level
281 * intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700282 *
tom85258ee2014-10-07 00:10:02 -0700283 * @param intent intent to be installed
Brian O'Connor66630c82014-10-02 21:08:19 -0700284 */
tom85258ee2014-10-07 00:10:02 -0700285 private void executeInstallingPhase(Intent intent) {
286 // Indicate that the intent is entering the installing phase.
287 store.setState(intent, INSTALLING);
288
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700289 List<FlowRuleBatchOperation> installWork = Lists.newArrayList();
tom85258ee2014-10-07 00:10:02 -0700290 try {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700291 List<Intent> installables = store.getInstallableIntents(intent.id());
tom85258ee2014-10-07 00:10:02 -0700292 if (installables != null) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700293 for (Intent installable : installables) {
tom85258ee2014-10-07 00:10:02 -0700294 registerSubclassInstallerIfNeeded(installable);
tom53945d52014-10-07 11:01:36 -0700295 trackerService.addTrackedResources(intent.id(),
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700296 installable.resources());
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700297 List<FlowRuleBatchOperation> batch = getInstaller(installable).install(installable);
298 installWork.addAll(batch);
tom85258ee2014-10-07 00:10:02 -0700299 }
tom95329eb2014-10-06 08:40:06 -0700300 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700301 // FIXME we have to wait for the installable intents
302 //eventDispatcher.post(store.setState(intent, INSTALLED));
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700303 monitorExecutor.execute(new IntentInstallMonitor(intent, installWork, INSTALLED));
tom85258ee2014-10-07 00:10:02 -0700304 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700305 log.warn("Unable to install intent {} due to:", intent.id(), e);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700306 uninstallIntent(intent, RECOMPILING);
tom53945d52014-10-07 11:01:36 -0700307
tom85258ee2014-10-07 00:10:02 -0700308 // If compilation failed, kick off the recompiling phase.
Brian O'Connorcb900f42014-10-07 21:55:33 -0700309 // FIXME
310 //executeRecompilingPhase(intent);
tom85258ee2014-10-07 00:10:02 -0700311 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700312 }
313
314 /**
tom85258ee2014-10-07 00:10:02 -0700315 * Recompiles the specified intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700316 *
tom85258ee2014-10-07 00:10:02 -0700317 * @param intent intent to be recompiled
Brian O'Connor66630c82014-10-02 21:08:19 -0700318 */
tom85258ee2014-10-07 00:10:02 -0700319 private void executeRecompilingPhase(Intent intent) {
320 // Indicate that the intent is entering the recompiling phase.
321 store.setState(intent, RECOMPILING);
322
323 try {
324 // Compile the intent into installable derivatives.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700325 List<Intent> installable = compileIntent(intent);
tom85258ee2014-10-07 00:10:02 -0700326
327 // If all went well, compare the existing list of installable
328 // intents with the newly compiled list. If they are the same,
329 // bail, out since the previous approach was determined not to
330 // be viable.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700331 List<Intent> originalInstallable = store.getInstallableIntents(intent.id());
tom85258ee2014-10-07 00:10:02 -0700332
333 if (Objects.equals(originalInstallable, installable)) {
334 eventDispatcher.post(store.setState(intent, FAILED));
335 } else {
336 // Otherwise, re-associate the newly compiled installable intents
337 // with the top-level intent and kick off installing phase.
338 store.addInstallableIntents(intent.id(), installable);
339 executeInstallingPhase(intent);
340 }
341 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700342 log.warn("Unable to recompile intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700343
tom85258ee2014-10-07 00:10:02 -0700344 // If compilation failed, mark the intent as failed.
345 eventDispatcher.post(store.setState(intent, FAILED));
346 }
347 }
348
349 /**
350 * Uninstalls the specified intent by uninstalling all of its associated
351 * installable derivatives.
352 *
353 * @param intent intent to be installed
354 */
355 private void executeWithdrawingPhase(Intent intent) {
356 // Indicate that the intent is being withdrawn.
357 store.setState(intent, WITHDRAWING);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700358 uninstallIntent(intent, WITHDRAWN);
tom85258ee2014-10-07 00:10:02 -0700359
360 // If all went well, disassociate the top-level intent with its
361 // installable derivatives and mark it as withdrawn.
Brian O'Connorcb900f42014-10-07 21:55:33 -0700362 // FIXME need to clean up
363 //store.removeInstalledIntents(intent.id());
364 // FIXME
365 //eventDispatcher.post(store.setState(intent, WITHDRAWN));
Brian O'Connor66630c82014-10-02 21:08:19 -0700366 }
367
368 /**
tom53945d52014-10-07 11:01:36 -0700369 * Uninstalls all installable intents associated with the given intent.
370 *
371 * @param intent intent to be uninstalled
372 */
Brian O'Connorcb900f42014-10-07 21:55:33 -0700373 private void uninstallIntent(Intent intent, IntentState nextState) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700374 List<FlowRuleBatchOperation> uninstallWork = Lists.newArrayList();
tom53945d52014-10-07 11:01:36 -0700375 try {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700376 List<Intent> installables = store.getInstallableIntents(intent.id());
tom53945d52014-10-07 11:01:36 -0700377 if (installables != null) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700378 for (Intent installable : installables) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700379 List<FlowRuleBatchOperation> batches = getInstaller(installable).uninstall(installable);
380 uninstallWork.addAll(batches);
tom53945d52014-10-07 11:01:36 -0700381 }
382 }
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700383 monitorExecutor.execute(new IntentInstallMonitor(intent, uninstallWork, nextState));
tom53945d52014-10-07 11:01:36 -0700384 } catch (IntentException e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700385 log.warn("Unable to uninstall intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700386 }
387 }
388
389 /**
Brian O'Connor66630c82014-10-02 21:08:19 -0700390 * Registers an intent compiler of the specified intent if an intent compiler
391 * for the intent is not registered. This method traverses the class hierarchy of
392 * the intent. Once an intent compiler for a parent type is found, this method
393 * registers the found intent compiler.
394 *
395 * @param intent intent
396 */
397 private void registerSubclassCompilerIfNeeded(Intent intent) {
398 if (!compilers.containsKey(intent.getClass())) {
399 Class<?> cls = intent.getClass();
400 while (cls != Object.class) {
401 // As long as we're within the Intent class descendants
402 if (Intent.class.isAssignableFrom(cls)) {
403 IntentCompiler<?> compiler = compilers.get(cls);
404 if (compiler != null) {
405 compilers.put(intent.getClass(), compiler);
406 return;
407 }
408 }
409 cls = cls.getSuperclass();
410 }
411 }
412 }
413
414 /**
415 * Registers an intent installer of the specified intent if an intent installer
416 * for the intent is not registered. This method traverses the class hierarchy of
417 * the intent. Once an intent installer for a parent type is found, this method
418 * registers the found intent installer.
419 *
420 * @param intent intent
421 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700422 private void registerSubclassInstallerIfNeeded(Intent intent) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700423 if (!installers.containsKey(intent.getClass())) {
424 Class<?> cls = intent.getClass();
425 while (cls != Object.class) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700426 // As long as we're within the Intent class descendants
427 if (Intent.class.isAssignableFrom(cls)) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700428 IntentInstaller<?> installer = installers.get(cls);
429 if (installer != null) {
430 installers.put(intent.getClass(), installer);
431 return;
432 }
433 }
434 cls = cls.getSuperclass();
435 }
436 }
437 }
438
Brian O'Connor66630c82014-10-02 21:08:19 -0700439 // Store delegate to re-post events emitted from the store.
440 private class InternalStoreDelegate implements IntentStoreDelegate {
441 @Override
442 public void notify(IntentEvent event) {
tom85258ee2014-10-07 00:10:02 -0700443 eventDispatcher.post(event);
444 if (event.type() == IntentEvent.Type.SUBMITTED) {
445 executor.execute(new IntentTask(COMPILING, event.subject()));
446 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700447 }
448 }
449
tom95329eb2014-10-06 08:40:06 -0700450 // Topology change delegate
451 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
452 @Override
tom85258ee2014-10-07 00:10:02 -0700453 public void triggerCompile(Iterable<IntentId> intentIds,
454 boolean compileAllFailed) {
455 // Attempt recompilation of the specified intents first.
tom95329eb2014-10-06 08:40:06 -0700456 for (IntentId intentId : intentIds) {
tom53945d52014-10-07 11:01:36 -0700457 Intent intent = getIntent(intentId);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700458 uninstallIntent(intent, RECOMPILING);
alshabib8ca53902014-10-07 13:11:17 -0700459
Brian O'Connorcb900f42014-10-07 21:55:33 -0700460 //FIXME
461 //executeRecompilingPhase(intent);
tom85258ee2014-10-07 00:10:02 -0700462 }
463
464 if (compileAllFailed) {
465 // If required, compile all currently failed intents.
466 for (Intent intent : getIntents()) {
467 if (getIntentState(intent.id()) == FAILED) {
468 executeCompilingPhase(intent);
469 }
470 }
tom95329eb2014-10-06 08:40:06 -0700471 }
472 }
tom95329eb2014-10-06 08:40:06 -0700473 }
tom85258ee2014-10-07 00:10:02 -0700474
475 // Auxiliary runnable to perform asynchronous tasks.
476 private class IntentTask implements Runnable {
477 private final IntentState state;
478 private final Intent intent;
479
480 public IntentTask(IntentState state, Intent intent) {
481 this.state = state;
482 this.intent = intent;
483 }
484
485 @Override
486 public void run() {
487 if (state == COMPILING) {
488 executeCompilingPhase(intent);
489 } else if (state == RECOMPILING) {
490 executeRecompilingPhase(intent);
491 } else if (state == WITHDRAWING) {
492 executeWithdrawingPhase(intent);
493 }
494 }
495 }
496
Brian O'Connorcb900f42014-10-07 21:55:33 -0700497 private class IntentInstallMonitor implements Runnable {
498
499 private final Intent intent;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700500 private final List<FlowRuleBatchOperation> work;
Brian O'Connorcb900f42014-10-07 21:55:33 -0700501 private final List<Future<CompletedBatchOperation>> futures;
502 private final IntentState nextState;
503
504 public IntentInstallMonitor(Intent intent,
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700505 List<FlowRuleBatchOperation> work,
506 IntentState nextState) {
Brian O'Connorcb900f42014-10-07 21:55:33 -0700507 this.intent = intent;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700508 this.work = work;
509 // TODO how many Futures can be outstanding? one?
510 this.futures = Lists.newLinkedList();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700511 this.nextState = nextState;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700512
513 // TODO need to kick off the first batch sometime, why not now?
514 futures.add(applyNextBatch());
Brian O'Connorcb900f42014-10-07 21:55:33 -0700515 }
516
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700517 /**
518 * Update the intent store with the next status for this intent.
519 */
520 private void updateIntent() {
Brian O'Connorcb900f42014-10-07 21:55:33 -0700521 if (nextState == RECOMPILING) {
522 executor.execute(new IntentTask(nextState, intent));
523 } else if (nextState == INSTALLED || nextState == WITHDRAWN) {
524 eventDispatcher.post(store.setState(intent, nextState));
525 } else {
526 log.warn("Invalid next intent state {} for intent {}", nextState, intent);
527 }
528 }
529
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700530 /**
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700531 * Applies the next batch.
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700532 */
533 private Future<CompletedBatchOperation> applyNextBatch() {
534 if (work.isEmpty()) {
535 return null;
536 }
537 FlowRuleBatchOperation batch = work.remove(0);
538 return flowRuleService.applyBatch(batch);
539 }
540
541 /**
542 * Iterate through the pending futures, and remove them when they have completed.
543 */
544 private void processFutures() {
545 List<Future<CompletedBatchOperation>> newFutures = Lists.newArrayList();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700546 for (Iterator<Future<CompletedBatchOperation>> i = futures.iterator(); i.hasNext();) {
547 Future<CompletedBatchOperation> future = i.next();
alshabib26834582014-10-08 20:15:46 -0700548 try {
549 // TODO: we may want to get the future here and go back to the future.
alshabibc7e1cb62014-10-08 20:20:03 -0700550 CompletedBatchOperation completed = future.get(100, TimeUnit.NANOSECONDS);
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700551 if (completed.isSuccess()) {
552 Future<CompletedBatchOperation> newFuture = applyNextBatch();
553 if (newFuture != null) {
554 // we'll add this later so that we don't get a ConcurrentModException
555 newFutures.add(newFuture);
556 }
557 } else {
558 // TODO check if future succeeded and if not report fail items
559 log.warn("Failed items: {}", completed.failedItems());
560 // TODO revert....
561 //uninstallIntent(intent, RECOMPILING);
562 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700563 i.remove();
alshabib26834582014-10-08 20:15:46 -0700564 } catch (TimeoutException | InterruptedException | ExecutionException te) {
565 log.debug("Intallations of intent {} is still pending", intent);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700566 }
567 }
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700568 futures.addAll(newFutures);
569 }
570
571 @Override
572 public void run() {
573 processFutures();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700574 if (futures.isEmpty()) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700575 // woohoo! we are done!
576 updateIntent();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700577 } else {
578 // resubmit ourselves if we are not done yet
579 monitorExecutor.submit(this);
580 }
581 }
582 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700583}