blob: eabee8079a11dfce55fc7e57695079d765c68a82 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brian O'Connor66630c82014-10-02 21:08:19 -070016package org.onlab.onos.net.intent.impl;
17
Brian O'Connor9cfe8292014-10-24 14:14:08 -070018import static com.google.common.base.Preconditions.checkNotNull;
19import static java.util.concurrent.Executors.newSingleThreadExecutor;
20import static org.onlab.onos.net.intent.IntentState.COMPILING;
21import static org.onlab.onos.net.intent.IntentState.FAILED;
22import static org.onlab.onos.net.intent.IntentState.INSTALLED;
23import static org.onlab.onos.net.intent.IntentState.INSTALLING;
24import static org.onlab.onos.net.intent.IntentState.RECOMPILING;
25import static org.onlab.onos.net.intent.IntentState.WITHDRAWING;
26import static org.onlab.onos.net.intent.IntentState.WITHDRAWN;
27import static org.onlab.util.Tools.namedThreads;
28import static org.slf4j.LoggerFactory.getLogger;
29
30import java.util.ArrayList;
31import java.util.Iterator;
32import java.util.List;
33import java.util.Map;
34import java.util.Objects;
35import java.util.concurrent.ConcurrentHashMap;
36import java.util.concurrent.ConcurrentMap;
37import java.util.concurrent.ExecutionException;
38import java.util.concurrent.ExecutorService;
39import java.util.concurrent.Future;
40import java.util.concurrent.TimeUnit;
41import java.util.concurrent.TimeoutException;
42
Brian O'Connor66630c82014-10-02 21:08:19 -070043import org.apache.felix.scr.annotations.Activate;
44import org.apache.felix.scr.annotations.Component;
45import org.apache.felix.scr.annotations.Deactivate;
46import org.apache.felix.scr.annotations.Reference;
47import org.apache.felix.scr.annotations.ReferenceCardinality;
48import org.apache.felix.scr.annotations.Service;
49import org.onlab.onos.event.AbstractListenerRegistry;
50import org.onlab.onos.event.EventDeliveryService;
Brian O'Connorcb900f42014-10-07 21:55:33 -070051import org.onlab.onos.net.flow.CompletedBatchOperation;
Brian O'Connorf2dbde52014-10-10 16:20:24 -070052import org.onlab.onos.net.flow.FlowRuleBatchOperation;
53import org.onlab.onos.net.flow.FlowRuleService;
Brian O'Connor66630c82014-10-02 21:08:19 -070054import org.onlab.onos.net.intent.Intent;
55import org.onlab.onos.net.intent.IntentCompiler;
56import org.onlab.onos.net.intent.IntentEvent;
57import org.onlab.onos.net.intent.IntentException;
58import org.onlab.onos.net.intent.IntentExtensionService;
59import org.onlab.onos.net.intent.IntentId;
60import org.onlab.onos.net.intent.IntentInstaller;
61import org.onlab.onos.net.intent.IntentListener;
62import org.onlab.onos.net.intent.IntentOperations;
63import org.onlab.onos.net.intent.IntentService;
64import org.onlab.onos.net.intent.IntentState;
65import org.onlab.onos.net.intent.IntentStore;
66import org.onlab.onos.net.intent.IntentStoreDelegate;
67import org.slf4j.Logger;
68
Brian O'Connor9cfe8292014-10-24 14:14:08 -070069import com.google.common.collect.ImmutableList;
70import com.google.common.collect.ImmutableMap;
71import com.google.common.collect.Lists;
Brian O'Connor66630c82014-10-02 21:08:19 -070072
73/**
74 * An implementation of Intent Manager.
75 */
76@Component(immediate = true)
77@Service
78public class IntentManager
79 implements IntentService, IntentExtensionService {
80 private final Logger log = getLogger(getClass());
81
82 public static final String INTENT_NULL = "Intent cannot be null";
83 public static final String INTENT_ID_NULL = "Intent ID cannot be null";
84
85 // Collections for compiler, installer, and listener are ONOS instance local
86 private final ConcurrentMap<Class<? extends Intent>,
87 IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>();
Thomas Vachuskab97cf282014-10-20 23:31:12 -070088 private final ConcurrentMap<Class<? extends Intent>,
89 IntentInstaller<? extends Intent>> installers = new ConcurrentHashMap<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070090
91 private final AbstractListenerRegistry<IntentEvent, IntentListener>
tom95329eb2014-10-06 08:40:06 -070092 listenerRegistry = new AbstractListenerRegistry<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070093
Brian O'Connorcb900f42014-10-07 21:55:33 -070094 private ExecutorService executor;
95 private ExecutorService monitorExecutor;
tom85258ee2014-10-07 00:10:02 -070096
Brian O'Connor66630c82014-10-02 21:08:19 -070097 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
tom95329eb2014-10-06 08:40:06 -070098 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
Brian O'Connor66630c82014-10-02 21:08:19 -070099
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected IntentStore store;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -0700104 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -0700105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Brian O'Connor66630c82014-10-02 21:08:19 -0700107 protected EventDeliveryService eventDispatcher;
108
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected FlowRuleService flowRuleService;
111
Brian O'Connor66630c82014-10-02 21:08:19 -0700112 @Activate
113 public void activate() {
114 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700115 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700116 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700117 executor = newSingleThreadExecutor(namedThreads("onos-intents"));
118 monitorExecutor = newSingleThreadExecutor(namedThreads("onos-intent-monitor"));
Brian O'Connor66630c82014-10-02 21:08:19 -0700119 log.info("Started");
120 }
121
122 @Deactivate
123 public void deactivate() {
124 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700125 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700126 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700127 executor.shutdown();
128 monitorExecutor.shutdown();
Brian O'Connor66630c82014-10-02 21:08:19 -0700129 log.info("Stopped");
130 }
131
132 @Override
133 public void submit(Intent intent) {
134 checkNotNull(intent, INTENT_NULL);
135 registerSubclassCompilerIfNeeded(intent);
136 IntentEvent event = store.createIntent(intent);
tom85258ee2014-10-07 00:10:02 -0700137 if (event != null) {
138 eventDispatcher.post(event);
139 executor.execute(new IntentTask(COMPILING, intent));
140 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700141 }
142
143 @Override
144 public void withdraw(Intent intent) {
145 checkNotNull(intent, INTENT_NULL);
tom85258ee2014-10-07 00:10:02 -0700146 executor.execute(new IntentTask(WITHDRAWING, intent));
Brian O'Connor66630c82014-10-02 21:08:19 -0700147 }
148
149 // FIXME: implement this method
150 @Override
Thomas Vachuska83e090e2014-10-22 14:25:35 -0700151 public void replace(IntentId oldIntentId, Intent newIntent) {
152 throw new UnsupportedOperationException("execute() is not implemented yet");
153 }
154
155 // FIXME: implement this method
156 @Override
Thomas Vachuska1fb982f2014-10-22 14:09:17 -0700157 public Future<IntentOperations> execute(IntentOperations operations) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700158 throw new UnsupportedOperationException("execute() is not implemented yet");
159 }
160
161 @Override
162 public Iterable<Intent> getIntents() {
163 return store.getIntents();
164 }
165
166 @Override
167 public long getIntentCount() {
168 return store.getIntentCount();
169 }
170
171 @Override
172 public Intent getIntent(IntentId id) {
173 checkNotNull(id, INTENT_ID_NULL);
174 return store.getIntent(id);
175 }
176
177 @Override
178 public IntentState getIntentState(IntentId id) {
179 checkNotNull(id, INTENT_ID_NULL);
180 return store.getIntentState(id);
181 }
182
183 @Override
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700184 public List<Intent> getInstallableIntents(IntentId intentId) {
185 checkNotNull(intentId, INTENT_ID_NULL);
186 return store.getInstallableIntents(intentId);
187 }
188
189 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700190 public void addListener(IntentListener listener) {
191 listenerRegistry.addListener(listener);
192 }
193
194 @Override
195 public void removeListener(IntentListener listener) {
196 listenerRegistry.removeListener(listener);
197 }
198
199 @Override
200 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
201 compilers.put(cls, compiler);
202 }
203
204 @Override
205 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
206 compilers.remove(cls);
207 }
208
209 @Override
210 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
211 return ImmutableMap.copyOf(compilers);
212 }
213
214 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700215 public <T extends Intent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700216 installers.put(cls, installer);
217 }
218
219 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700220 public <T extends Intent> void unregisterInstaller(Class<T> cls) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700221 installers.remove(cls);
222 }
223
224 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700225 public Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> getInstallers() {
Brian O'Connor66630c82014-10-02 21:08:19 -0700226 return ImmutableMap.copyOf(installers);
227 }
228
229 /**
Brian O'Connor66630c82014-10-02 21:08:19 -0700230 * Returns the corresponding intent compiler to the specified intent.
231 *
232 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700233 * @param <T> the type of intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700234 * @return intent compiler corresponding to the specified intent
235 */
236 private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
237 @SuppressWarnings("unchecked")
238 IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
239 if (compiler == null) {
240 throw new IntentException("no compiler for class " + intent.getClass());
241 }
242 return compiler;
243 }
244
245 /**
246 * Returns the corresponding intent installer to the specified installable intent.
tom95329eb2014-10-06 08:40:06 -0700247 *
Brian O'Connor66630c82014-10-02 21:08:19 -0700248 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700249 * @param <T> the type of installable intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700250 * @return intent installer corresponding to the specified installable intent
251 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700252 private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700253 @SuppressWarnings("unchecked")
254 IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass());
255 if (installer == null) {
256 throw new IntentException("no installer for class " + intent.getClass());
257 }
258 return installer;
259 }
260
261 /**
tom85258ee2014-10-07 00:10:02 -0700262 * Compiles the specified intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700263 *
tom85258ee2014-10-07 00:10:02 -0700264 * @param intent intent to be compiled
Brian O'Connor66630c82014-10-02 21:08:19 -0700265 */
tom85258ee2014-10-07 00:10:02 -0700266 private void executeCompilingPhase(Intent intent) {
267 // Indicate that the intent is entering the compiling phase.
268 store.setState(intent, COMPILING);
269
270 try {
271 // Compile the intent into installable derivatives.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700272 List<Intent> installable = compileIntent(intent);
tom85258ee2014-10-07 00:10:02 -0700273
274 // If all went well, associate the resulting list of installable
275 // intents with the top-level intent and proceed to install.
276 store.addInstallableIntents(intent.id(), installable);
277 executeInstallingPhase(intent);
278
279 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700280 log.warn("Unable to compile intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700281
tom85258ee2014-10-07 00:10:02 -0700282 // If compilation failed, mark the intent as failed.
weibit50eb95b2014-10-25 21:47:54 -0700283 IntentEvent event = store.setState(intent, FAILED);
284 if (event != null) {
285 eventDispatcher.post(event);
286 }
tom85258ee2014-10-07 00:10:02 -0700287 }
288 }
289
Brian O'Connorcb900f42014-10-07 21:55:33 -0700290 /**
291 * Compiles an intent recursively.
292 *
293 * @param intent intent
294 * @return result of compilation
295 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700296 private List<Intent> compileIntent(Intent intent) {
Thomas Vachuska4926c1b2014-10-21 00:44:10 -0700297 if (intent.isInstallable()) {
298 return ImmutableList.of(intent);
Brian O'Connor66630c82014-10-02 21:08:19 -0700299 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700300
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700301 List<Intent> installable = new ArrayList<>();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700302 // TODO do we need to registerSubclassCompiler?
303 for (Intent compiled : getCompiler(intent).compile(intent)) {
304 installable.addAll(compileIntent(compiled));
305 }
306
tom85258ee2014-10-07 00:10:02 -0700307 return installable;
Brian O'Connor66630c82014-10-02 21:08:19 -0700308 }
309
310 /**
tom85258ee2014-10-07 00:10:02 -0700311 * Installs all installable intents associated with the specified top-level
312 * intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700313 *
tom85258ee2014-10-07 00:10:02 -0700314 * @param intent intent to be installed
Brian O'Connor66630c82014-10-02 21:08:19 -0700315 */
tom85258ee2014-10-07 00:10:02 -0700316 private void executeInstallingPhase(Intent intent) {
317 // Indicate that the intent is entering the installing phase.
318 store.setState(intent, INSTALLING);
319
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700320 List<FlowRuleBatchOperation> installWork = Lists.newArrayList();
tom85258ee2014-10-07 00:10:02 -0700321 try {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700322 List<Intent> installables = store.getInstallableIntents(intent.id());
tom85258ee2014-10-07 00:10:02 -0700323 if (installables != null) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700324 for (Intent installable : installables) {
tom85258ee2014-10-07 00:10:02 -0700325 registerSubclassInstallerIfNeeded(installable);
tom53945d52014-10-07 11:01:36 -0700326 trackerService.addTrackedResources(intent.id(),
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700327 installable.resources());
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700328 List<FlowRuleBatchOperation> batch = getInstaller(installable).install(installable);
329 installWork.addAll(batch);
tom85258ee2014-10-07 00:10:02 -0700330 }
tom95329eb2014-10-06 08:40:06 -0700331 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700332 // FIXME we have to wait for the installable intents
333 //eventDispatcher.post(store.setState(intent, INSTALLED));
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700334 monitorExecutor.execute(new IntentInstallMonitor(intent, installWork, INSTALLED));
tom85258ee2014-10-07 00:10:02 -0700335 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700336 log.warn("Unable to install intent {} due to:", intent.id(), e);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700337 uninstallIntent(intent, RECOMPILING);
tom53945d52014-10-07 11:01:36 -0700338
tom85258ee2014-10-07 00:10:02 -0700339 // If compilation failed, kick off the recompiling phase.
Brian O'Connorcb900f42014-10-07 21:55:33 -0700340 // FIXME
341 //executeRecompilingPhase(intent);
tom85258ee2014-10-07 00:10:02 -0700342 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700343 }
344
345 /**
tom85258ee2014-10-07 00:10:02 -0700346 * Recompiles the specified intent.
Brian O'Connor66630c82014-10-02 21:08:19 -0700347 *
tom85258ee2014-10-07 00:10:02 -0700348 * @param intent intent to be recompiled
Brian O'Connor66630c82014-10-02 21:08:19 -0700349 */
tom85258ee2014-10-07 00:10:02 -0700350 private void executeRecompilingPhase(Intent intent) {
351 // Indicate that the intent is entering the recompiling phase.
352 store.setState(intent, RECOMPILING);
353
354 try {
355 // Compile the intent into installable derivatives.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700356 List<Intent> installable = compileIntent(intent);
tom85258ee2014-10-07 00:10:02 -0700357
358 // If all went well, compare the existing list of installable
359 // intents with the newly compiled list. If they are the same,
360 // bail, out since the previous approach was determined not to
361 // be viable.
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700362 List<Intent> originalInstallable = store.getInstallableIntents(intent.id());
tom85258ee2014-10-07 00:10:02 -0700363
364 if (Objects.equals(originalInstallable, installable)) {
365 eventDispatcher.post(store.setState(intent, FAILED));
366 } else {
367 // Otherwise, re-associate the newly compiled installable intents
368 // with the top-level intent and kick off installing phase.
369 store.addInstallableIntents(intent.id(), installable);
370 executeInstallingPhase(intent);
371 }
372 } catch (Exception e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700373 log.warn("Unable to recompile intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700374
tom85258ee2014-10-07 00:10:02 -0700375 // If compilation failed, mark the intent as failed.
376 eventDispatcher.post(store.setState(intent, FAILED));
377 }
378 }
379
380 /**
381 * Uninstalls the specified intent by uninstalling all of its associated
382 * installable derivatives.
383 *
384 * @param intent intent to be installed
385 */
386 private void executeWithdrawingPhase(Intent intent) {
387 // Indicate that the intent is being withdrawn.
388 store.setState(intent, WITHDRAWING);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700389 uninstallIntent(intent, WITHDRAWN);
tom85258ee2014-10-07 00:10:02 -0700390
391 // If all went well, disassociate the top-level intent with its
392 // installable derivatives and mark it as withdrawn.
Brian O'Connorcb900f42014-10-07 21:55:33 -0700393 // FIXME need to clean up
394 //store.removeInstalledIntents(intent.id());
395 // FIXME
396 //eventDispatcher.post(store.setState(intent, WITHDRAWN));
Brian O'Connor66630c82014-10-02 21:08:19 -0700397 }
398
399 /**
tom53945d52014-10-07 11:01:36 -0700400 * Uninstalls all installable intents associated with the given intent.
401 *
402 * @param intent intent to be uninstalled
403 */
Brian O'Connorcb900f42014-10-07 21:55:33 -0700404 private void uninstallIntent(Intent intent, IntentState nextState) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700405 List<FlowRuleBatchOperation> uninstallWork = Lists.newArrayList();
tom53945d52014-10-07 11:01:36 -0700406 try {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700407 List<Intent> installables = store.getInstallableIntents(intent.id());
tom53945d52014-10-07 11:01:36 -0700408 if (installables != null) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700409 for (Intent installable : installables) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700410 List<FlowRuleBatchOperation> batches = getInstaller(installable).uninstall(installable);
411 uninstallWork.addAll(batches);
tom53945d52014-10-07 11:01:36 -0700412 }
413 }
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700414 monitorExecutor.execute(new IntentInstallMonitor(intent, uninstallWork, nextState));
tom53945d52014-10-07 11:01:36 -0700415 } catch (IntentException e) {
Jonathan Hart11096402014-10-20 17:31:49 -0700416 log.warn("Unable to uninstall intent {} due to:", intent.id(), e);
tom53945d52014-10-07 11:01:36 -0700417 }
418 }
419
420 /**
Brian O'Connor66630c82014-10-02 21:08:19 -0700421 * Registers an intent compiler of the specified intent if an intent compiler
422 * for the intent is not registered. This method traverses the class hierarchy of
423 * the intent. Once an intent compiler for a parent type is found, this method
424 * registers the found intent compiler.
425 *
426 * @param intent intent
427 */
428 private void registerSubclassCompilerIfNeeded(Intent intent) {
429 if (!compilers.containsKey(intent.getClass())) {
430 Class<?> cls = intent.getClass();
431 while (cls != Object.class) {
432 // As long as we're within the Intent class descendants
433 if (Intent.class.isAssignableFrom(cls)) {
434 IntentCompiler<?> compiler = compilers.get(cls);
435 if (compiler != null) {
436 compilers.put(intent.getClass(), compiler);
437 return;
438 }
439 }
440 cls = cls.getSuperclass();
441 }
442 }
443 }
444
445 /**
446 * Registers an intent installer of the specified intent if an intent installer
447 * for the intent is not registered. This method traverses the class hierarchy of
448 * the intent. Once an intent installer for a parent type is found, this method
449 * registers the found intent installer.
450 *
451 * @param intent intent
452 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700453 private void registerSubclassInstallerIfNeeded(Intent intent) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700454 if (!installers.containsKey(intent.getClass())) {
455 Class<?> cls = intent.getClass();
456 while (cls != Object.class) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700457 // As long as we're within the Intent class descendants
458 if (Intent.class.isAssignableFrom(cls)) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700459 IntentInstaller<?> installer = installers.get(cls);
460 if (installer != null) {
461 installers.put(intent.getClass(), installer);
462 return;
463 }
464 }
465 cls = cls.getSuperclass();
466 }
467 }
468 }
469
Brian O'Connor66630c82014-10-02 21:08:19 -0700470 // Store delegate to re-post events emitted from the store.
471 private class InternalStoreDelegate implements IntentStoreDelegate {
472 @Override
473 public void notify(IntentEvent event) {
tom85258ee2014-10-07 00:10:02 -0700474 eventDispatcher.post(event);
475 if (event.type() == IntentEvent.Type.SUBMITTED) {
476 executor.execute(new IntentTask(COMPILING, event.subject()));
477 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700478 }
479 }
480
tom95329eb2014-10-06 08:40:06 -0700481 // Topology change delegate
482 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
483 @Override
tom85258ee2014-10-07 00:10:02 -0700484 public void triggerCompile(Iterable<IntentId> intentIds,
485 boolean compileAllFailed) {
486 // Attempt recompilation of the specified intents first.
tom95329eb2014-10-06 08:40:06 -0700487 for (IntentId intentId : intentIds) {
tom53945d52014-10-07 11:01:36 -0700488 Intent intent = getIntent(intentId);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700489 uninstallIntent(intent, RECOMPILING);
alshabib8ca53902014-10-07 13:11:17 -0700490
Brian O'Connorcb900f42014-10-07 21:55:33 -0700491 //FIXME
492 //executeRecompilingPhase(intent);
tom85258ee2014-10-07 00:10:02 -0700493 }
494
495 if (compileAllFailed) {
496 // If required, compile all currently failed intents.
497 for (Intent intent : getIntents()) {
498 if (getIntentState(intent.id()) == FAILED) {
499 executeCompilingPhase(intent);
500 }
501 }
tom95329eb2014-10-06 08:40:06 -0700502 }
503 }
tom95329eb2014-10-06 08:40:06 -0700504 }
tom85258ee2014-10-07 00:10:02 -0700505
506 // Auxiliary runnable to perform asynchronous tasks.
507 private class IntentTask implements Runnable {
508 private final IntentState state;
509 private final Intent intent;
510
511 public IntentTask(IntentState state, Intent intent) {
512 this.state = state;
513 this.intent = intent;
514 }
515
516 @Override
517 public void run() {
518 if (state == COMPILING) {
519 executeCompilingPhase(intent);
520 } else if (state == RECOMPILING) {
521 executeRecompilingPhase(intent);
522 } else if (state == WITHDRAWING) {
523 executeWithdrawingPhase(intent);
524 }
525 }
526 }
527
Brian O'Connorcb900f42014-10-07 21:55:33 -0700528 private class IntentInstallMonitor implements Runnable {
529
530 private final Intent intent;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700531 private final List<FlowRuleBatchOperation> work;
Brian O'Connorcb900f42014-10-07 21:55:33 -0700532 private final List<Future<CompletedBatchOperation>> futures;
533 private final IntentState nextState;
534
535 public IntentInstallMonitor(Intent intent,
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700536 List<FlowRuleBatchOperation> work,
537 IntentState nextState) {
Brian O'Connorcb900f42014-10-07 21:55:33 -0700538 this.intent = intent;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700539 this.work = work;
540 // TODO how many Futures can be outstanding? one?
541 this.futures = Lists.newLinkedList();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700542 this.nextState = nextState;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700543
544 // TODO need to kick off the first batch sometime, why not now?
545 futures.add(applyNextBatch());
Brian O'Connorcb900f42014-10-07 21:55:33 -0700546 }
547
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700548 /**
549 * Update the intent store with the next status for this intent.
550 */
551 private void updateIntent() {
Brian O'Connorcb900f42014-10-07 21:55:33 -0700552 if (nextState == RECOMPILING) {
553 executor.execute(new IntentTask(nextState, intent));
554 } else if (nextState == INSTALLED || nextState == WITHDRAWN) {
555 eventDispatcher.post(store.setState(intent, nextState));
556 } else {
557 log.warn("Invalid next intent state {} for intent {}", nextState, intent);
558 }
559 }
560
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700561 /**
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700562 * Applies the next batch.
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700563 */
564 private Future<CompletedBatchOperation> applyNextBatch() {
565 if (work.isEmpty()) {
566 return null;
567 }
568 FlowRuleBatchOperation batch = work.remove(0);
569 return flowRuleService.applyBatch(batch);
570 }
571
572 /**
573 * Iterate through the pending futures, and remove them when they have completed.
574 */
575 private void processFutures() {
576 List<Future<CompletedBatchOperation>> newFutures = Lists.newArrayList();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700577 for (Iterator<Future<CompletedBatchOperation>> i = futures.iterator(); i.hasNext();) {
578 Future<CompletedBatchOperation> future = i.next();
alshabib26834582014-10-08 20:15:46 -0700579 try {
580 // TODO: we may want to get the future here and go back to the future.
alshabibc7e1cb62014-10-08 20:20:03 -0700581 CompletedBatchOperation completed = future.get(100, TimeUnit.NANOSECONDS);
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700582 if (completed.isSuccess()) {
583 Future<CompletedBatchOperation> newFuture = applyNextBatch();
584 if (newFuture != null) {
585 // we'll add this later so that we don't get a ConcurrentModException
586 newFutures.add(newFuture);
587 }
588 } else {
589 // TODO check if future succeeded and if not report fail items
590 log.warn("Failed items: {}", completed.failedItems());
591 // TODO revert....
592 //uninstallIntent(intent, RECOMPILING);
593 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700594 i.remove();
alshabib26834582014-10-08 20:15:46 -0700595 } catch (TimeoutException | InterruptedException | ExecutionException te) {
596 log.debug("Intallations of intent {} is still pending", intent);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700597 }
598 }
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700599 futures.addAll(newFutures);
600 }
601
602 @Override
603 public void run() {
604 processFutures();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700605 if (futures.isEmpty()) {
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700606 // woohoo! we are done!
607 updateIntent();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700608 } else {
609 // resubmit ourselves if we are not done yet
610 monitorExecutor.submit(this);
611 }
612 }
613 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700614}