blob: 3a3d4764baa3b3f023dde4036f273721eb91db30 [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
Thomas Vachuska83e090e2014-10-22 14:25:35 -0700129 public void replace(IntentId oldIntentId, Intent newIntent) {
130 throw new UnsupportedOperationException("execute() is not implemented yet");
131 }
132
133 // FIXME: implement this method
134 @Override
Thomas Vachuska1fb982f2014-10-22 14:09:17 -0700135 public Future<IntentOperations> execute(IntentOperations operations) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700136 throw new UnsupportedOperationException("execute() is not implemented yet");
137 }
138
139 @Override
140 public Iterable<Intent> getIntents() {
141 return store.getIntents();
142 }
143
144 @Override
145 public long getIntentCount() {
146 return store.getIntentCount();
147 }
148
149 @Override
150 public Intent getIntent(IntentId id) {
151 checkNotNull(id, INTENT_ID_NULL);
152 return store.getIntent(id);
153 }
154
155 @Override
156 public IntentState getIntentState(IntentId id) {
157 checkNotNull(id, INTENT_ID_NULL);
158 return store.getIntentState(id);
159 }
160
161 @Override
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700162 public List<Intent> getInstallableIntents(IntentId intentId) {
163 checkNotNull(intentId, INTENT_ID_NULL);
164 return store.getInstallableIntents(intentId);
165 }
166
167 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700168 public void addListener(IntentListener listener) {
169 listenerRegistry.addListener(listener);
170 }
171
172 @Override
173 public void removeListener(IntentListener listener) {
174 listenerRegistry.removeListener(listener);
175 }
176
177 @Override
178 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
179 compilers.put(cls, compiler);
180 }
181
182 @Override
183 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
184 compilers.remove(cls);
185 }
186
187 @Override
188 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
189 return ImmutableMap.copyOf(compilers);
190 }
191
192 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700193 public <T extends Intent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700194 installers.put(cls, installer);
195 }
196
197 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700198 public <T extends Intent> void unregisterInstaller(Class<T> cls) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700199 installers.remove(cls);
200 }
201
202 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700203 public Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> getInstallers() {
Brian O'Connor66630c82014-10-02 21:08:19 -0700204 return ImmutableMap.copyOf(installers);
205 }
206
207 /**
Brian O'Connor66630c82014-10-02 21:08:19 -0700208 * Returns the corresponding intent compiler to the specified intent.
209 *
210 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700211 * @param <T> the type of intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700212 * @return intent compiler corresponding to the specified intent
213 */
214 private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
215 @SuppressWarnings("unchecked")
216 IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
217 if (compiler == null) {
218 throw new IntentException("no compiler for class " + intent.getClass());
219 }
220 return compiler;
221 }
222
223 /**
224 * Returns the corresponding intent installer to the specified installable intent.
tom95329eb2014-10-06 08:40:06 -0700225 *
Brian O'Connor66630c82014-10-02 21:08:19 -0700226 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700227 * @param <T> the type of installable intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700228 * @return intent installer corresponding to the specified installable intent
229 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700230 private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700231 @SuppressWarnings("unchecked")
232 IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass());
233 if (installer == null) {
234 throw new IntentException("no installer for class " + intent.getClass());
235 }
236 return installer;
237 }
238
239 /**
tom85258ee2014-10-07 00:10:02 -0700240 * Compiles the specified intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700241 *
tom85258ee2014-10-07 00:10:02 -0700242 * @param intent intent to be compiled
Brian O'Connor66630c82014-10-02 21:08:19 -0700243 */
tom85258ee2014-10-07 00:10:02 -0700244 private void executeCompilingPhase(Intent intent) {
245 // Indicate that the intent is entering the compiling phase.
246 store.setState(intent, COMPILING);
247
248 try {
249 // Compile the intent into installable derivatives.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700250 List<Intent> installable = compileIntent(intent);
tom85258ee2014-10-07 00:10:02 -0700251
252 // If all went well, associate the resulting list of installable
253 // intents with the top-level intent and proceed to install.
254 store.addInstallableIntents(intent.id(), installable);
255 executeInstallingPhase(intent);
256
257 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700258 log.warn("Unable to compile intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700259
tom85258ee2014-10-07 00:10:02 -0700260 // If compilation failed, mark the intent as failed.
261 store.setState(intent, FAILED);
262 }
263 }
264
Brian O'Connorcb900f42014-10-07 21:55:33 -0700265 /**
266 * Compiles an intent recursively.
267 *
268 * @param intent intent
269 * @return result of compilation
270 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700271 private List<Intent> compileIntent(Intent intent) {
Thomas Vachuska4926c1b2014-10-21 00:44:10 -0700272 if (intent.isInstallable()) {
273 return ImmutableList.of(intent);
Brian O'Connor66630c82014-10-02 21:08:19 -0700274 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700275
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700276 List<Intent> installable = new ArrayList<>();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700277 // TODO do we need to registerSubclassCompiler?
278 for (Intent compiled : getCompiler(intent).compile(intent)) {
279 installable.addAll(compileIntent(compiled));
280 }
281
tom85258ee2014-10-07 00:10:02 -0700282 return installable;
Brian O'Connor66630c82014-10-02 21:08:19 -0700283 }
284
285 /**
tom85258ee2014-10-07 00:10:02 -0700286 * Installs all installable intents associated with the specified top-level
287 * intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700288 *
tom85258ee2014-10-07 00:10:02 -0700289 * @param intent intent to be installed
Brian O'Connor66630c82014-10-02 21:08:19 -0700290 */
tom85258ee2014-10-07 00:10:02 -0700291 private void executeInstallingPhase(Intent intent) {
292 // Indicate that the intent is entering the installing phase.
293 store.setState(intent, INSTALLING);
294
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700295 List<FlowRuleBatchOperation> installWork = Lists.newArrayList();
tom85258ee2014-10-07 00:10:02 -0700296 try {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700297 List<Intent> installables = store.getInstallableIntents(intent.id());
tom85258ee2014-10-07 00:10:02 -0700298 if (installables != null) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700299 for (Intent installable : installables) {
tom85258ee2014-10-07 00:10:02 -0700300 registerSubclassInstallerIfNeeded(installable);
tom53945d52014-10-07 11:01:36 -0700301 trackerService.addTrackedResources(intent.id(),
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700302 installable.resources());
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700303 List<FlowRuleBatchOperation> batch = getInstaller(installable).install(installable);
304 installWork.addAll(batch);
tom85258ee2014-10-07 00:10:02 -0700305 }
tom95329eb2014-10-06 08:40:06 -0700306 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700307 // FIXME we have to wait for the installable intents
308 //eventDispatcher.post(store.setState(intent, INSTALLED));
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700309 monitorExecutor.execute(new IntentInstallMonitor(intent, installWork, INSTALLED));
tom85258ee2014-10-07 00:10:02 -0700310 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700311 log.warn("Unable to install intent {} due to:", intent.id(), e);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700312 uninstallIntent(intent, RECOMPILING);
tom53945d52014-10-07 11:01:36 -0700313
tom85258ee2014-10-07 00:10:02 -0700314 // If compilation failed, kick off the recompiling phase.
Brian O'Connorcb900f42014-10-07 21:55:33 -0700315 // FIXME
316 //executeRecompilingPhase(intent);
tom85258ee2014-10-07 00:10:02 -0700317 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700318 }
319
320 /**
tom85258ee2014-10-07 00:10:02 -0700321 * Recompiles the specified intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700322 *
tom85258ee2014-10-07 00:10:02 -0700323 * @param intent intent to be recompiled
Brian O'Connor66630c82014-10-02 21:08:19 -0700324 */
tom85258ee2014-10-07 00:10:02 -0700325 private void executeRecompilingPhase(Intent intent) {
326 // Indicate that the intent is entering the recompiling phase.
327 store.setState(intent, RECOMPILING);
328
329 try {
330 // Compile the intent into installable derivatives.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700331 List<Intent> installable = compileIntent(intent);
tom85258ee2014-10-07 00:10:02 -0700332
333 // If all went well, compare the existing list of installable
334 // intents with the newly compiled list. If they are the same,
335 // bail, out since the previous approach was determined not to
336 // be viable.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700337 List<Intent> originalInstallable = store.getInstallableIntents(intent.id());
tom85258ee2014-10-07 00:10:02 -0700338
339 if (Objects.equals(originalInstallable, installable)) {
340 eventDispatcher.post(store.setState(intent, FAILED));
341 } else {
342 // Otherwise, re-associate the newly compiled installable intents
343 // with the top-level intent and kick off installing phase.
344 store.addInstallableIntents(intent.id(), installable);
345 executeInstallingPhase(intent);
346 }
347 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700348 log.warn("Unable to recompile intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700349
tom85258ee2014-10-07 00:10:02 -0700350 // If compilation failed, mark the intent as failed.
351 eventDispatcher.post(store.setState(intent, FAILED));
352 }
353 }
354
355 /**
356 * Uninstalls the specified intent by uninstalling all of its associated
357 * installable derivatives.
358 *
359 * @param intent intent to be installed
360 */
361 private void executeWithdrawingPhase(Intent intent) {
362 // Indicate that the intent is being withdrawn.
363 store.setState(intent, WITHDRAWING);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700364 uninstallIntent(intent, WITHDRAWN);
tom85258ee2014-10-07 00:10:02 -0700365
366 // If all went well, disassociate the top-level intent with its
367 // installable derivatives and mark it as withdrawn.
Brian O'Connorcb900f42014-10-07 21:55:33 -0700368 // FIXME need to clean up
369 //store.removeInstalledIntents(intent.id());
370 // FIXME
371 //eventDispatcher.post(store.setState(intent, WITHDRAWN));
Brian O'Connor66630c82014-10-02 21:08:19 -0700372 }
373
374 /**
tom53945d52014-10-07 11:01:36 -0700375 * Uninstalls all installable intents associated with the given intent.
376 *
377 * @param intent intent to be uninstalled
378 */
Brian O'Connorcb900f42014-10-07 21:55:33 -0700379 private void uninstallIntent(Intent intent, IntentState nextState) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700380 List<FlowRuleBatchOperation> uninstallWork = Lists.newArrayList();
tom53945d52014-10-07 11:01:36 -0700381 try {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700382 List<Intent> installables = store.getInstallableIntents(intent.id());
tom53945d52014-10-07 11:01:36 -0700383 if (installables != null) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700384 for (Intent installable : installables) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700385 List<FlowRuleBatchOperation> batches = getInstaller(installable).uninstall(installable);
386 uninstallWork.addAll(batches);
tom53945d52014-10-07 11:01:36 -0700387 }
388 }
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700389 monitorExecutor.execute(new IntentInstallMonitor(intent, uninstallWork, nextState));
tom53945d52014-10-07 11:01:36 -0700390 } catch (IntentException e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700391 log.warn("Unable to uninstall intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700392 }
393 }
394
395 /**
Brian O'Connor66630c82014-10-02 21:08:19 -0700396 * Registers an intent compiler of the specified intent if an intent compiler
397 * for the intent is not registered. This method traverses the class hierarchy of
398 * the intent. Once an intent compiler for a parent type is found, this method
399 * registers the found intent compiler.
400 *
401 * @param intent intent
402 */
403 private void registerSubclassCompilerIfNeeded(Intent intent) {
404 if (!compilers.containsKey(intent.getClass())) {
405 Class<?> cls = intent.getClass();
406 while (cls != Object.class) {
407 // As long as we're within the Intent class descendants
408 if (Intent.class.isAssignableFrom(cls)) {
409 IntentCompiler<?> compiler = compilers.get(cls);
410 if (compiler != null) {
411 compilers.put(intent.getClass(), compiler);
412 return;
413 }
414 }
415 cls = cls.getSuperclass();
416 }
417 }
418 }
419
420 /**
421 * Registers an intent installer of the specified intent if an intent installer
422 * for the intent is not registered. This method traverses the class hierarchy of
423 * the intent. Once an intent installer for a parent type is found, this method
424 * registers the found intent installer.
425 *
426 * @param intent intent
427 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700428 private void registerSubclassInstallerIfNeeded(Intent intent) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700429 if (!installers.containsKey(intent.getClass())) {
430 Class<?> cls = intent.getClass();
431 while (cls != Object.class) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700432 // As long as we're within the Intent class descendants
433 if (Intent.class.isAssignableFrom(cls)) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700434 IntentInstaller<?> installer = installers.get(cls);
435 if (installer != null) {
436 installers.put(intent.getClass(), installer);
437 return;
438 }
439 }
440 cls = cls.getSuperclass();
441 }
442 }
443 }
444
Brian O'Connor66630c82014-10-02 21:08:19 -0700445 // Store delegate to re-post events emitted from the store.
446 private class InternalStoreDelegate implements IntentStoreDelegate {
447 @Override
448 public void notify(IntentEvent event) {
tom85258ee2014-10-07 00:10:02 -0700449 eventDispatcher.post(event);
450 if (event.type() == IntentEvent.Type.SUBMITTED) {
451 executor.execute(new IntentTask(COMPILING, event.subject()));
452 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700453 }
454 }
455
tom95329eb2014-10-06 08:40:06 -0700456 // Topology change delegate
457 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
458 @Override
tom85258ee2014-10-07 00:10:02 -0700459 public void triggerCompile(Iterable<IntentId> intentIds,
460 boolean compileAllFailed) {
461 // Attempt recompilation of the specified intents first.
tom95329eb2014-10-06 08:40:06 -0700462 for (IntentId intentId : intentIds) {
tom53945d52014-10-07 11:01:36 -0700463 Intent intent = getIntent(intentId);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700464 uninstallIntent(intent, RECOMPILING);
alshabib8ca53902014-10-07 13:11:17 -0700465
Brian O'Connorcb900f42014-10-07 21:55:33 -0700466 //FIXME
467 //executeRecompilingPhase(intent);
tom85258ee2014-10-07 00:10:02 -0700468 }
469
470 if (compileAllFailed) {
471 // If required, compile all currently failed intents.
472 for (Intent intent : getIntents()) {
473 if (getIntentState(intent.id()) == FAILED) {
474 executeCompilingPhase(intent);
475 }
476 }
tom95329eb2014-10-06 08:40:06 -0700477 }
478 }
tom95329eb2014-10-06 08:40:06 -0700479 }
tom85258ee2014-10-07 00:10:02 -0700480
481 // Auxiliary runnable to perform asynchronous tasks.
482 private class IntentTask implements Runnable {
483 private final IntentState state;
484 private final Intent intent;
485
486 public IntentTask(IntentState state, Intent intent) {
487 this.state = state;
488 this.intent = intent;
489 }
490
491 @Override
492 public void run() {
493 if (state == COMPILING) {
494 executeCompilingPhase(intent);
495 } else if (state == RECOMPILING) {
496 executeRecompilingPhase(intent);
497 } else if (state == WITHDRAWING) {
498 executeWithdrawingPhase(intent);
499 }
500 }
501 }
502
Brian O'Connorcb900f42014-10-07 21:55:33 -0700503 private class IntentInstallMonitor implements Runnable {
504
505 private final Intent intent;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700506 private final List<FlowRuleBatchOperation> work;
Brian O'Connorcb900f42014-10-07 21:55:33 -0700507 private final List<Future<CompletedBatchOperation>> futures;
508 private final IntentState nextState;
509
510 public IntentInstallMonitor(Intent intent,
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700511 List<FlowRuleBatchOperation> work,
512 IntentState nextState) {
Brian O'Connorcb900f42014-10-07 21:55:33 -0700513 this.intent = intent;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700514 this.work = work;
515 // TODO how many Futures can be outstanding? one?
516 this.futures = Lists.newLinkedList();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700517 this.nextState = nextState;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700518
519 // TODO need to kick off the first batch sometime, why not now?
520 futures.add(applyNextBatch());
Brian O'Connorcb900f42014-10-07 21:55:33 -0700521 }
522
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700523 /**
524 * Update the intent store with the next status for this intent.
525 */
526 private void updateIntent() {
Brian O'Connorcb900f42014-10-07 21:55:33 -0700527 if (nextState == RECOMPILING) {
528 executor.execute(new IntentTask(nextState, intent));
529 } else if (nextState == INSTALLED || nextState == WITHDRAWN) {
530 eventDispatcher.post(store.setState(intent, nextState));
531 } else {
532 log.warn("Invalid next intent state {} for intent {}", nextState, intent);
533 }
534 }
535
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700536 /**
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700537 * Applies the next batch.
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700538 */
539 private Future<CompletedBatchOperation> applyNextBatch() {
540 if (work.isEmpty()) {
541 return null;
542 }
543 FlowRuleBatchOperation batch = work.remove(0);
544 return flowRuleService.applyBatch(batch);
545 }
546
547 /**
548 * Iterate through the pending futures, and remove them when they have completed.
549 */
550 private void processFutures() {
551 List<Future<CompletedBatchOperation>> newFutures = Lists.newArrayList();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700552 for (Iterator<Future<CompletedBatchOperation>> i = futures.iterator(); i.hasNext();) {
553 Future<CompletedBatchOperation> future = i.next();
alshabib26834582014-10-08 20:15:46 -0700554 try {
555 // TODO: we may want to get the future here and go back to the future.
alshabibc7e1cb62014-10-08 20:20:03 -0700556 CompletedBatchOperation completed = future.get(100, TimeUnit.NANOSECONDS);
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700557 if (completed.isSuccess()) {
558 Future<CompletedBatchOperation> newFuture = applyNextBatch();
559 if (newFuture != null) {
560 // we'll add this later so that we don't get a ConcurrentModException
561 newFutures.add(newFuture);
562 }
563 } else {
564 // TODO check if future succeeded and if not report fail items
565 log.warn("Failed items: {}", completed.failedItems());
566 // TODO revert....
567 //uninstallIntent(intent, RECOMPILING);
568 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700569 i.remove();
alshabib26834582014-10-08 20:15:46 -0700570 } catch (TimeoutException | InterruptedException | ExecutionException te) {
571 log.debug("Intallations of intent {} is still pending", intent);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700572 }
573 }
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700574 futures.addAll(newFutures);
575 }
576
577 @Override
578 public void run() {
579 processFutures();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700580 if (futures.isEmpty()) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700581 // woohoo! we are done!
582 updateIntent();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700583 } else {
584 // resubmit ourselves if we are not done yet
585 monitorExecutor.submit(this);
586 }
587 }
588 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700589}