ONOS-1048 - Define interfaces instead of using IntentManager
- Define IntentProcessor interface containing methods to process an intent
- Pull out IntentCompiler related tasks to CompilerRegistry
- Pull out IntentInstaller related tasks to InstallerRegistry
- Create an IntentProcessor subclass as inner class in IntentManager
Change-Id: Ia3e8d574a1053e7ddc9b961873ef758c9e0b1b26
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/CompilerRegistry.java b/core/net/src/main/java/org/onosproject/net/intent/impl/CompilerRegistry.java
new file mode 100644
index 0000000..0ee149a
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/CompilerRegistry.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.intent.impl;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentCompiler;
+import org.onosproject.net.intent.IntentException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+// TODO: consider a better name
+class CompilerRegistry {
+
+ private final ConcurrentMap<Class<? extends Intent>,
+ IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>();
+
+ /**
+ * Registers the specified compiler for the given intent class.
+ *
+ * @param cls intent class
+ * @param compiler intent compiler
+ * @param <T> the type of intent
+ */
+ public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
+ compilers.put(cls, compiler);
+ }
+
+ /**
+ * Unregisters the compiler for the specified intent class.
+ *
+ * @param cls intent class
+ * @param <T> the type of intent
+ */
+ public <T extends Intent> void unregisterCompiler(Class<T> cls) {
+ compilers.remove(cls);
+ }
+
+ /**
+ * Returns immutable set of bindings of currently registered intent compilers.
+ *
+ * @return the set of compiler bindings
+ */
+ public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
+ return ImmutableMap.copyOf(compilers);
+ }
+
+ /**
+ * Compiles an intent recursively.
+ *
+ * @param intent intent
+ * @param previousInstallables previous intent installables
+ * @return result of compilation
+ */
+ List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
+ if (intent.isInstallable()) {
+ return ImmutableList.of(intent);
+ }
+
+ registerSubclassCompilerIfNeeded(intent);
+ // FIXME: get previous resources
+ List<Intent> installable = new ArrayList<>();
+ for (Intent compiled : getCompiler(intent).compile(intent, previousInstallables, null)) {
+ installable.addAll(compile(compiled, previousInstallables));
+ }
+ return installable;
+ }
+
+ /**
+ * Returns the corresponding intent compiler to the specified intent.
+ *
+ * @param intent intent
+ * @param <T> the type of intent
+ * @return intent compiler corresponding to the specified intent
+ */
+ private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
+ @SuppressWarnings("unchecked")
+ IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
+ if (compiler == null) {
+ throw new IntentException("no compiler for class " + intent.getClass());
+ }
+ return compiler;
+ }
+
+ /**
+ * Registers an intent compiler of the specified intent if an intent compiler
+ * for the intent is not registered. This method traverses the class hierarchy of
+ * the intent. Once an intent compiler for a parent type is found, this method
+ * registers the found intent compiler.
+ *
+ * @param intent intent
+ */
+ private void registerSubclassCompilerIfNeeded(Intent intent) {
+ if (!compilers.containsKey(intent.getClass())) {
+ Class<?> cls = intent.getClass();
+ while (cls != Object.class) {
+ // As long as we're within the Intent class descendants
+ if (Intent.class.isAssignableFrom(cls)) {
+ IntentCompiler<?> compiler = compilers.get(cls);
+ if (compiler != null) {
+ compilers.put(intent.getClass(), compiler);
+ return;
+ }
+ }
+ cls = cls.getSuperclass();
+ }
+ }
+ }
+}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/InstallerRegistry.java b/core/net/src/main/java/org/onosproject/net/intent/impl/InstallerRegistry.java
new file mode 100644
index 0000000..e0103ce
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/InstallerRegistry.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.intent.impl;
+
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.net.flow.FlowRuleOperation;
+import org.onosproject.net.flow.FlowRuleOperations;
+import org.onosproject.net.flow.FlowRuleOperationsContext;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentException;
+import org.onosproject.net.intent.IntentInstaller;
+import org.onosproject.net.intent.IntentStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import static com.google.common.base.Preconditions.checkState;
+import static org.onlab.util.Tools.isNullOrEmpty;
+import static org.onosproject.net.intent.IntentState.FAILED;
+import static org.onosproject.net.intent.IntentState.INSTALLED;
+import static org.onosproject.net.intent.IntentState.WITHDRAWN;
+
+// TODO: consider a better name
+class InstallerRegistry {
+
+ private static final Logger log = LoggerFactory.getLogger(InstallerRegistry.class);
+
+ private final ConcurrentMap<Class<? extends Intent>,
+ IntentInstaller<? extends Intent>> installers = new ConcurrentHashMap<>();
+ /**
+ * Registers the specified installer for the given installable intent class.
+ *
+ * @param cls installable intent class
+ * @param installer intent installer
+ * @param <T> the type of installable intent
+ */
+ <T extends Intent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
+ installers.put(cls, installer);
+ }
+
+ /**
+ * Unregisters the installer for the given installable intent class.
+ *
+ * @param cls installable intent class
+ * @param <T> the type of installable intent
+ */
+ <T extends Intent> void unregisterInstaller(Class<T> cls) {
+ installers.remove(cls);
+ }
+
+ /**
+ * Returns immutable set of bindings of currently registered intent installers.
+ *
+ * @return the set of installer bindings
+ */
+ Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> getInstallers() {
+ return ImmutableMap.copyOf(installers);
+ }
+
+ /**
+ * Returns the corresponding intent installer to the specified installable intent.
+ *
+ * @param intent intent
+ * @param <T> the type of installable intent
+ * @return intent installer corresponding to the specified installable intent
+ */
+ private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
+ @SuppressWarnings("unchecked")
+ IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass());
+ if (installer == null) {
+ throw new IntentException("no installer for class " + intent.getClass());
+ }
+ return installer;
+ }
+
+ /**
+ * Registers an intent installer of the specified intent if an intent installer
+ * for the intent is not registered. This method traverses the class hierarchy of
+ * the intent. Once an intent installer for a parent type is found, this method
+ * registers the found intent installer.
+ *
+ * @param intent intent
+ */
+ private void registerSubclassInstallerIfNeeded(Intent intent) {
+ if (!installers.containsKey(intent.getClass())) {
+ Class<?> cls = intent.getClass();
+ while (cls != Object.class) {
+ // As long as we're within the Intent class descendants
+ if (Intent.class.isAssignableFrom(cls)) {
+ IntentInstaller<?> installer = installers.get(cls);
+ if (installer != null) {
+ installers.put(intent.getClass(), installer);
+ return;
+ }
+ }
+ cls = cls.getSuperclass();
+ }
+ }
+ }
+
+ /**
+ * Generate a {@link FlowRuleOperations} instance from the specified intent data.
+ *
+ * @param current intent data stored in the store
+ * @param pending intent data being processed
+ * @param store intent store saving the intent state in this method
+ * @param trackerService objective tracker that is used in this method
+ * @return flow rule operations
+ */
+ public FlowRuleOperations coordinate(IntentData current, IntentData pending,
+ IntentStore store, ObjectiveTrackerService trackerService) {
+ List<Intent> oldInstallables = (current != null) ? current.installables() : null;
+ List<Intent> newInstallables = pending.installables();
+
+ checkState(isNullOrEmpty(oldInstallables) ||
+ oldInstallables.size() == newInstallables.size(),
+ "Old and New Intent must have equivalent installable intents.");
+
+ List<List<Collection<FlowRuleOperation>>> plans = new ArrayList<>();
+ for (int i = 0; i < newInstallables.size(); i++) {
+ Intent newInstallable = newInstallables.get(i);
+ registerSubclassInstallerIfNeeded(newInstallable);
+ //TODO consider migrating installers to FlowRuleOperations
+ /* FIXME
+ - we need to do another pass on this method about that doesn't
+ require the length of installables to be equal, and also doesn't
+ depend on ordering
+ - we should also reconsider when to start/stop tracking resources
+ */
+ if (isNullOrEmpty(oldInstallables)) {
+ plans.add(getInstaller(newInstallable).install(newInstallable));
+ } else {
+ Intent oldInstallable = oldInstallables.get(i);
+ checkState(oldInstallable.getClass().equals(newInstallable.getClass()),
+ "Installable Intent type mismatch.");
+ trackerService.removeTrackedResources(pending.key(), oldInstallable.resources());
+ plans.add(getInstaller(newInstallable).replace(oldInstallable, newInstallable));
+ }
+ trackerService.addTrackedResources(pending.key(), newInstallable.resources());
+// } catch (IntentException e) {
+// log.warn("Unable to update intent {} due to:", oldIntent.id(), e);
+// //FIXME... we failed. need to uninstall (if same) or revert (if different)
+// trackerService.removeTrackedResources(newIntent.id(), newInstallable.resources());
+// exception = e;
+// batches = uninstallIntent(oldIntent, oldInstallables);
+// }
+ }
+
+ return merge(plans).build(new FlowRuleOperationsContext() { // TODO move this out
+ @Override
+ public void onSuccess(FlowRuleOperations ops) {
+ log.debug("Completed installing: {}", pending.key());
+ pending.setState(INSTALLED);
+ store.write(pending);
+ }
+
+ @Override
+ public void onError(FlowRuleOperations ops) {
+ log.warn("Failed installation: {} {} on {}", pending.key(),
+ pending.intent(), ops);
+ //TODO store.write(pending.setState(BROKEN));
+ pending.setState(FAILED);
+ store.write(pending);
+ }
+ });
+ }
+
+ /**
+ * Generate a {@link FlowRuleOperations} instance from the specified intent data.
+ *
+ * @param current intent data stored in the store
+ * @param pending intent date being processed
+ * @param store intent store saving the intent state in this method
+ * @param trackerService objective tracker that is used in this method
+ * @return flow rule operations
+ */
+ FlowRuleOperations uninstallCoordinate(IntentData current, IntentData pending,
+ IntentStore store, ObjectiveTrackerService trackerService) {
+ List<Intent> installables = current.installables();
+ List<List<Collection<FlowRuleOperation>>> plans = new ArrayList<>();
+ for (Intent installable : installables) {
+ plans.add(getInstaller(installable).uninstall(installable));
+ trackerService.removeTrackedResources(pending.key(), installable.resources());
+ }
+
+ return merge(plans).build(new FlowRuleOperationsContext() {
+ @Override
+ public void onSuccess(FlowRuleOperations ops) {
+ log.debug("Completed withdrawing: {}", pending.key());
+ pending.setState(WITHDRAWN);
+ pending.setInstallables(Collections.emptyList());
+ store.write(pending);
+ }
+
+ @Override
+ public void onError(FlowRuleOperations ops) {
+ log.warn("Failed withdraw: {}", pending.key());
+ pending.setState(FAILED);
+ store.write(pending);
+ }
+ });
+ }
+
+
+ // TODO needs tests... or maybe it's just perfect
+ private FlowRuleOperations.Builder merge(List<List<Collection<FlowRuleOperation>>> plans) {
+ FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
+ // Build a batch one stage at a time
+ for (int stageNumber = 0;; stageNumber++) {
+ // Get the sub-stage from each plan (List<Set<FlowRuleOperation>)
+ for (Iterator<List<Collection<FlowRuleOperation>>> itr = plans.iterator(); itr.hasNext();) {
+ List<Collection<FlowRuleOperation>> plan = itr.next();
+ if (plan.size() <= stageNumber) {
+ // we have consumed all stages from this plan, so remove it
+ itr.remove();
+ continue;
+ }
+ // write operations from this sub-stage into the builder
+ Collection<FlowRuleOperation> stage = plan.get(stageNumber);
+ for (FlowRuleOperation entry : stage) {
+ builder.operation(entry);
+ }
+ }
+ // we are done with the stage, start the next one...
+ if (plans.isEmpty()) {
+ break; // we don't need to start a new stage, we are done.
+ }
+ builder.newStage();
+ }
+ return builder;
+ }
+}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
index 8fa8b3f..3699df6 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
@@ -16,7 +16,6 @@
package org.onosproject.net.intent.impl;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -27,16 +26,13 @@
import org.onosproject.core.IdGenerator;
import org.onosproject.event.AbstractListenerRegistry;
import org.onosproject.event.EventDeliveryService;
-import org.onosproject.net.flow.FlowRuleOperation;
import org.onosproject.net.flow.FlowRuleOperations;
-import org.onosproject.net.flow.FlowRuleOperationsContext;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentBatchDelegate;
import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentEvent;
-import org.onosproject.net.intent.IntentException;
import org.onosproject.net.intent.IntentExtensionService;
import org.onosproject.net.intent.IntentInstaller;
import org.onosproject.net.intent.IntentListener;
@@ -53,29 +49,26 @@
import org.onosproject.net.intent.impl.phase.Withdrawn;
import org.slf4j.Logger;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.EnumSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
import static java.util.concurrent.Executors.newFixedThreadPool;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.util.Tools.groupedThreads;
import static org.onlab.util.Tools.isNullOrEmpty;
-import static org.onosproject.net.intent.IntentState.*;
+import static org.onosproject.net.intent.IntentState.FAILED;
+import static org.onosproject.net.intent.IntentState.INSTALL_REQ;
+import static org.onosproject.net.intent.IntentState.WITHDRAWN;
+import static org.onosproject.net.intent.IntentState.WITHDRAW_REQ;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -95,12 +88,6 @@
private static final EnumSet<IntentState> RECOMPILE
= EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
- // Collections for compiler, installer, and listener are ONOS instance local
- private final ConcurrentMap<Class<? extends Intent>,
- IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>();
- private final ConcurrentMap<Class<? extends Intent>,
- IntentInstaller<? extends Intent>> installers = new ConcurrentHashMap<>();
-
private final AbstractListenerRegistry<IntentEvent, IntentListener>
listenerRegistry = new AbstractListenerRegistry<>();
@@ -124,6 +111,9 @@
private ExecutorService batchExecutor;
private ExecutorService workerExecutor;
+ private final CompilerRegistry compilerRegistry = new CompilerRegistry();
+ private final InstallerRegistry installerRegistry = new InstallerRegistry();
+ private final InternalIntentProcessor processor = new InternalIntentProcessor();
private final IntentStoreDelegate delegate = new InternalStoreDelegate();
private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
@@ -211,259 +201,32 @@
@Override
public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
- compilers.put(cls, compiler);
+ compilerRegistry.registerCompiler(cls, compiler);
}
@Override
public <T extends Intent> void unregisterCompiler(Class<T> cls) {
- compilers.remove(cls);
+ compilerRegistry.unregisterCompiler(cls);
}
@Override
public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
- return ImmutableMap.copyOf(compilers);
+ return compilerRegistry.getCompilers();
}
@Override
public <T extends Intent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
- installers.put(cls, installer);
+ installerRegistry.registerInstaller(cls, installer);
}
@Override
public <T extends Intent> void unregisterInstaller(Class<T> cls) {
- installers.remove(cls);
+ installerRegistry.unregisterInstaller(cls);
}
@Override
public Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> getInstallers() {
- return ImmutableMap.copyOf(installers);
- }
-
- /**
- * Returns the corresponding intent compiler to the specified intent.
- *
- * @param intent intent
- * @param <T> the type of intent
- * @return intent compiler corresponding to the specified intent
- */
- private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
- @SuppressWarnings("unchecked")
- IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
- if (compiler == null) {
- throw new IntentException("no compiler for class " + intent.getClass());
- }
- return compiler;
- }
-
- /**
- * Returns the corresponding intent installer to the specified installable intent.
- *
- * @param intent intent
- * @param <T> the type of installable intent
- * @return intent installer corresponding to the specified installable intent
- */
- private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
- @SuppressWarnings("unchecked")
- IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass());
- if (installer == null) {
- throw new IntentException("no installer for class " + intent.getClass());
- }
- return installer;
- }
-
- /**
- * Compiles an intent recursively.
- *
- * @param intent intent
- * @param previousInstallables previous intent installables
- * @return result of compilation
- */
- // TODO: make this non-public due to short term hack for ONOS-1051
- public List<Intent> compileIntent(Intent intent, List<Intent> previousInstallables) {
- if (intent.isInstallable()) {
- return ImmutableList.of(intent);
- }
-
- registerSubclassCompilerIfNeeded(intent);
- // FIXME: get previous resources
- List<Intent> installable = new ArrayList<>();
- for (Intent compiled : getCompiler(intent).compile(intent, previousInstallables, null)) {
- installable.addAll(compileIntent(compiled, previousInstallables));
- }
- return installable;
- }
-
- //TODO javadoc
- //FIXME
- // TODO: make this non-public due to short term hack for ONOS-1051
- public FlowRuleOperations coordinate(IntentData current, IntentData pending) {
- List<Intent> oldInstallables = (current != null) ? current.installables() : null;
- List<Intent> newInstallables = pending.installables();
-
- checkState(isNullOrEmpty(oldInstallables) ||
- oldInstallables.size() == newInstallables.size(),
- "Old and New Intent must have equivalent installable intents.");
-
- List<List<Collection<FlowRuleOperation>>> plans = new ArrayList<>();
- for (int i = 0; i < newInstallables.size(); i++) {
- Intent newInstallable = newInstallables.get(i);
- registerSubclassInstallerIfNeeded(newInstallable);
- //TODO consider migrating installers to FlowRuleOperations
- /* FIXME
- - we need to do another pass on this method about that doesn't
- require the length of installables to be equal, and also doesn't
- depend on ordering
- - we should also reconsider when to start/stop tracking resources
- */
- if (isNullOrEmpty(oldInstallables)) {
- plans.add(getInstaller(newInstallable).install(newInstallable));
- } else {
- Intent oldInstallable = oldInstallables.get(i);
- checkState(oldInstallable.getClass().equals(newInstallable.getClass()),
- "Installable Intent type mismatch.");
- trackerService.removeTrackedResources(pending.key(), oldInstallable.resources());
- plans.add(getInstaller(newInstallable).replace(oldInstallable, newInstallable));
- }
- trackerService.addTrackedResources(pending.key(), newInstallable.resources());
-// } catch (IntentException e) {
-// log.warn("Unable to update intent {} due to:", oldIntent.id(), e);
-// //FIXME... we failed. need to uninstall (if same) or revert (if different)
-// trackerService.removeTrackedResources(newIntent.id(), newInstallable.resources());
-// exception = e;
-// batches = uninstallIntent(oldIntent, oldInstallables);
-// }
- }
-
- return merge(plans).build(new FlowRuleOperationsContext() { // TODO move this out
- @Override
- public void onSuccess(FlowRuleOperations ops) {
- log.debug("Completed installing: {}", pending.key());
- pending.setState(INSTALLED);
- store.write(pending);
- }
-
- @Override
- public void onError(FlowRuleOperations ops) {
- log.warn("Failed installation: {} {} on {}", pending.key(),
- pending.intent(), ops);
- //TODO store.write(pending.setState(BROKEN));
- pending.setState(FAILED);
- store.write(pending);
- }
- });
- }
-
- /**
- * Generate a {@link FlowRuleOperations} instance from the specified intent data.
- *
- * @param current intent data stored in the store
- * @param pending intent data that is pending
- * @return flow rule operations
- */
- // TODO: make this non-public due to short term hack for ONOS-1051
- public FlowRuleOperations uninstallCoordinate(IntentData current, IntentData pending) {
- List<Intent> installables = current.installables();
- List<List<Collection<FlowRuleOperation>>> plans = new ArrayList<>();
- for (Intent installable : installables) {
- plans.add(getInstaller(installable).uninstall(installable));
- trackerService.removeTrackedResources(pending.key(), installable.resources());
- }
-
- return merge(plans).build(new FlowRuleOperationsContext() {
- @Override
- public void onSuccess(FlowRuleOperations ops) {
- log.debug("Completed withdrawing: {}", pending.key());
- pending.setState(WITHDRAWN);
- pending.setInstallables(Collections.emptyList());
- store.write(pending);
- }
-
- @Override
- public void onError(FlowRuleOperations ops) {
- log.warn("Failed withdraw: {}", pending.key());
- pending.setState(FAILED);
- store.write(pending);
- }
- });
- }
-
-
- // TODO needs tests... or maybe it's just perfect
- private FlowRuleOperations.Builder merge(List<List<Collection<FlowRuleOperation>>> plans) {
- FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
- // Build a batch one stage at a time
- for (int stageNumber = 0;; stageNumber++) {
- // Get the sub-stage from each plan (List<Set<FlowRuleOperation>)
- for (Iterator<List<Collection<FlowRuleOperation>>> itr = plans.iterator(); itr.hasNext();) {
- List<Collection<FlowRuleOperation>> plan = itr.next();
- if (plan.size() <= stageNumber) {
- // we have consumed all stages from this plan, so remove it
- itr.remove();
- continue;
- }
- // write operations from this sub-stage into the builder
- Collection<FlowRuleOperation> stage = plan.get(stageNumber);
- for (FlowRuleOperation entry : stage) {
- builder.operation(entry);
- }
- }
- // we are done with the stage, start the next one...
- if (plans.isEmpty()) {
- break; // we don't need to start a new stage, we are done.
- }
- builder.newStage();
- }
- return builder;
- }
-
- /**
- * Registers an intent compiler of the specified intent if an intent compiler
- * for the intent is not registered. This method traverses the class hierarchy of
- * the intent. Once an intent compiler for a parent type is found, this method
- * registers the found intent compiler.
- *
- * @param intent intent
- */
- private void registerSubclassCompilerIfNeeded(Intent intent) {
- if (!compilers.containsKey(intent.getClass())) {
- Class<?> cls = intent.getClass();
- while (cls != Object.class) {
- // As long as we're within the Intent class descendants
- if (Intent.class.isAssignableFrom(cls)) {
- IntentCompiler<?> compiler = compilers.get(cls);
- if (compiler != null) {
- compilers.put(intent.getClass(), compiler);
- return;
- }
- }
- cls = cls.getSuperclass();
- }
- }
- }
-
- /**
- * Registers an intent installer of the specified intent if an intent installer
- * for the intent is not registered. This method traverses the class hierarchy of
- * the intent. Once an intent installer for a parent type is found, this method
- * registers the found intent installer.
- *
- * @param intent intent
- */
- private void registerSubclassInstallerIfNeeded(Intent intent) {
- if (!installers.containsKey(intent.getClass())) {
- Class<?> cls = intent.getClass();
- while (cls != Object.class) {
- // As long as we're within the Intent class descendants
- if (Intent.class.isAssignableFrom(cls)) {
- IntentInstaller<?> installer = installers.get(cls);
- if (installer != null) {
- installers.put(intent.getClass(), installer);
- return;
- }
- }
- cls = cls.getSuperclass();
- }
- }
+ return installerRegistry.getInstallers();
}
// Store delegate to re-post events emitted from the store.
@@ -525,12 +288,12 @@
IntentData current = store.getIntentData(intentData.key());
switch (intentData.state()) {
case INSTALL_REQ:
- return new InstallRequest(this, intentData, Optional.ofNullable(current));
+ return new InstallRequest(processor, intentData, Optional.ofNullable(current));
case WITHDRAW_REQ:
if (current == null || isNullOrEmpty(current.installables())) {
return new Withdrawn(intentData, WITHDRAWN);
} else {
- return new WithdrawRequest(this, intentData, current);
+ return new WithdrawRequest(processor, intentData, current);
}
default:
// illegal state
@@ -648,4 +411,26 @@
// TODO ensure that only one batch is in flight at a time
}
}
+
+ private class InternalIntentProcessor implements IntentProcessor {
+ @Override
+ public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
+ return compilerRegistry.compile(intent, previousInstallables);
+ }
+
+ @Override
+ public FlowRuleOperations coordinate(IntentData current, IntentData pending) {
+ return installerRegistry.coordinate(current, pending, store, trackerService);
+ }
+
+ @Override
+ public FlowRuleOperations uninstallCoordinate(IntentData current, IntentData pending) {
+ return installerRegistry.uninstallCoordinate(current, pending, store, trackerService);
+ }
+
+ @Override
+ public void applyFlowRules(FlowRuleOperations flowRules) {
+ flowRuleService.apply(flowRules);
+ }
+ }
}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentProcessor.java b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentProcessor.java
new file mode 100644
index 0000000..c613a8d
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentProcessor.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.intent.impl;
+
+import org.onosproject.net.flow.FlowRuleOperations;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+
+import java.util.List;
+
+/**
+ * A collection of methods to process an intent.
+ *
+ * This interface is public, but intended to be used only by IntentManager and
+ * IntentProcessPhase subclasses stored under phase package.
+ */
+public interface IntentProcessor {
+
+ /**
+ * Compiles an intent recursively.
+ *
+ * @param intent intent
+ * @param previousInstallables previous intent installables
+ * @return result of compilation
+ */
+ List<Intent> compile(Intent intent, List<Intent> previousInstallables);
+
+ /**
+ * Generate a {@link FlowRuleOperations} instance from the specified intent data.
+ *
+ * @param current intent data stored in the store
+ * @param pending intent data being processed
+ * @return flow rule operations
+ */
+ FlowRuleOperations coordinate(IntentData current, IntentData pending);
+
+ /**
+ * Generate a {@link FlowRuleOperations} instance from the specified intent data.
+ *
+ * @param current intent data stored in the store
+ * @param pending intent data being processed
+ * @return flow rule operations
+ */
+ FlowRuleOperations uninstallCoordinate(IntentData current, IntentData pending);
+
+ /**
+ * Applies a batch operation of FlowRules.
+ *
+ * @param flowRules batch operation to apply
+ */
+ // TODO: consider a better name
+ // This methods gives strangeness a bit because
+ // it doesn't receive/return intent related information
+ void applyFlowRules(FlowRuleOperations flowRules);
+}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Compiling.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Compiling.java
index b68230a..97ea18e 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Compiling.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Compiling.java
@@ -18,7 +18,7 @@
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentException;
-import org.onosproject.net.intent.impl.IntentManager;
+import org.onosproject.net.intent.impl.IntentProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,13 +34,12 @@
private static final Logger log = LoggerFactory.getLogger(Compiling.class);
- // TODO: define an interface and use it, instead of IntentManager
- private final IntentManager intentManager;
+ private final IntentProcessor processor;
private final IntentData pending;
private final IntentData current;
- Compiling(IntentManager intentManager, IntentData pending, IntentData current) {
- this.intentManager = checkNotNull(intentManager);
+ Compiling(IntentProcessor processor, IntentData pending, IntentData current) {
+ this.processor = checkNotNull(processor);
this.pending = checkNotNull(pending);
this.current = current;
}
@@ -49,11 +48,12 @@
public Optional<IntentProcessPhase> execute() {
try {
List<Intent> installables = (current != null) ? current.installables() : null;
- pending.setInstallables(intentManager.compileIntent(pending.intent(), installables));
- return Optional.of(new InstallCoordinating(intentManager, pending, current));
+ pending.setInstallables(processor.compile(pending.intent(), installables));
+ return Optional.of(new InstallCoordinating(processor, pending, current));
} catch (IntentException e) {
log.debug("Unable to compile intent {} due to: {}", pending.intent(), e);
return Optional.of(new CompilingFailed(pending));
}
}
+
}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallCoordinating.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallCoordinating.java
index 5fd82ec..ef76888 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallCoordinating.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallCoordinating.java
@@ -18,7 +18,7 @@
import org.onosproject.net.flow.FlowRuleOperations;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentException;
-import org.onosproject.net.intent.impl.IntentManager;
+import org.onosproject.net.intent.impl.IntentProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,13 +34,13 @@
private static final Logger log = LoggerFactory.getLogger(InstallCoordinating.class);
- private final IntentManager intentManager;
+ private final IntentProcessor processor;
private final IntentData pending;
private final IntentData current;
// TODO: define an interface and use it, instead of IntentManager
- InstallCoordinating(IntentManager intentManager, IntentData pending, IntentData current) {
- this.intentManager = checkNotNull(intentManager);
+ InstallCoordinating(IntentProcessor processor, IntentData pending, IntentData current) {
+ this.processor = checkNotNull(processor);
this.pending = checkNotNull(pending);
this.current = current;
}
@@ -50,8 +50,8 @@
try {
//FIXME we orphan flow rules that are currently on the data plane
// ... should either reuse them or remove them
- FlowRuleOperations flowRules = intentManager.coordinate(current, pending);
- return Optional.of(new Installing(intentManager, pending, flowRules));
+ FlowRuleOperations flowRules = processor.coordinate(current, pending);
+ return Optional.of(new Installing(processor, pending, flowRules));
} catch (IntentException e) {
log.warn("Unable to generate a FlowRuleOperations from intent {} due to:", pending.intent().id(), e);
return Optional.of(new InstallingFailed(pending));
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallRequest.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallRequest.java
index e54b10a..90e0fd2 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallRequest.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallRequest.java
@@ -16,7 +16,7 @@
package org.onosproject.net.intent.impl.phase;
import org.onosproject.net.intent.IntentData;
-import org.onosproject.net.intent.impl.IntentManager;
+import org.onosproject.net.intent.impl.IntentProcessor;
import java.util.Optional;
@@ -27,13 +27,12 @@
*/
public final class InstallRequest implements IntentProcessPhase {
- // TODO: define an interface and use it, instead of IntentManager
- private final IntentManager intentManager;
+ private final IntentProcessor intentManager;
private final IntentData pending;
private final Optional<IntentData> current;
- public InstallRequest(IntentManager intentManager, IntentData intentData, Optional<IntentData> current) {
- this.intentManager = checkNotNull(intentManager);
+ public InstallRequest(IntentProcessor processor, IntentData intentData, Optional<IntentData> current) {
+ this.intentManager = checkNotNull(processor);
this.pending = checkNotNull(intentData);
this.current = checkNotNull(current);
}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Installing.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Installing.java
index 05c499f..3a290ae 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Installing.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Installing.java
@@ -18,7 +18,7 @@
import org.onosproject.net.flow.FlowRuleOperations;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentException;
-import org.onosproject.net.intent.impl.IntentManager;
+import org.onosproject.net.intent.impl.IntentProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,13 +34,12 @@
private static final Logger log = LoggerFactory.getLogger(Installing.class);
- private final IntentManager intentManager;
+ private final IntentProcessor processor;
private final IntentData pending;
private final FlowRuleOperations flowRules;
- // TODO: define an interface and use it, instead of IntentManager
- Installing(IntentManager intentManager, IntentData pending, FlowRuleOperations flowRules) {
- this.intentManager = checkNotNull(intentManager);
+ Installing(IntentProcessor processor, IntentData pending, FlowRuleOperations flowRules) {
+ this.processor = checkNotNull(processor);
this.pending = checkNotNull(pending);
this.flowRules = flowRules;
}
@@ -48,7 +47,7 @@
@Override
public Optional<IntentProcessPhase> execute() {
try {
- intentManager.flowRuleService.apply(flowRules); // FIXME we need to provide a context
+ processor.applyFlowRules(flowRules);
return Optional.of(new Installed(pending));
// What kinds of exceptions are thrown by FlowRuleService.apply()?
// Is IntentException a correct exception abstraction?
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawCoordinating.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawCoordinating.java
index 24d6dd5..ee854c8 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawCoordinating.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawCoordinating.java
@@ -18,7 +18,7 @@
import org.onosproject.net.flow.FlowRuleOperations;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentException;
-import org.onosproject.net.intent.impl.IntentManager;
+import org.onosproject.net.intent.impl.IntentProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,13 +34,12 @@
private static final Logger log = LoggerFactory.getLogger(WithdrawCoordinating.class);
- // TODO: define an interface and use it, instead of IntentManager
- private final IntentManager intentManager;
+ private final IntentProcessor processor;
private final IntentData pending;
private final IntentData current;
- WithdrawCoordinating(IntentManager intentManager, IntentData pending, IntentData current) {
- this.intentManager = checkNotNull(intentManager);
+ WithdrawCoordinating(IntentProcessor processor, IntentData pending, IntentData current) {
+ this.processor = checkNotNull(processor);
this.pending = checkNotNull(pending);
this.current = checkNotNull(current);
}
@@ -49,9 +48,9 @@
public Optional<IntentProcessPhase> execute() {
try {
// Note: current.installables() are not null or empty due to createIntentUpdate check
- FlowRuleOperations flowRules = intentManager.uninstallCoordinate(current, pending);
+ FlowRuleOperations flowRules = processor.uninstallCoordinate(current, pending);
pending.setInstallables(current.installables());
- return Optional.of(new Withdrawing(intentManager, pending, flowRules));
+ return Optional.of(new Withdrawing(processor, pending, flowRules));
} catch (IntentException e) {
log.warn("Unable to generate generate a FlowRuleOperations from intent {} due to:", pending.intent(), e);
return Optional.of(new WithdrawingFailed(pending));
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawRequest.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawRequest.java
index bbc7f34..f2e120f 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawRequest.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawRequest.java
@@ -16,7 +16,7 @@
package org.onosproject.net.intent.impl.phase;
import org.onosproject.net.intent.IntentData;
-import org.onosproject.net.intent.impl.IntentManager;
+import org.onosproject.net.intent.impl.IntentProcessor;
import java.util.Optional;
@@ -27,13 +27,12 @@
*/
public final class WithdrawRequest implements IntentProcessPhase {
- // TODO: define an interface and use it, instead of IntentManager
- private final IntentManager intentManager;
+ private final IntentProcessor processor;
private final IntentData pending;
private final IntentData current;
- public WithdrawRequest(IntentManager intentManager, IntentData intentData, IntentData current) {
- this.intentManager = checkNotNull(intentManager);
+ public WithdrawRequest(IntentProcessor processor, IntentData intentData, IntentData current) {
+ this.processor = checkNotNull(processor);
this.pending = checkNotNull(intentData);
this.current = checkNotNull(current);
}
@@ -43,6 +42,6 @@
//TODO perhaps we want to validate that the pending and current are the
// same version i.e. they are the same
// Note: this call is not just the symmetric version of submit
- return Optional.of(new WithdrawCoordinating(intentManager, pending, current));
+ return Optional.of(new WithdrawCoordinating(processor, pending, current));
}
}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawing.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawing.java
index 676c3c7..9198d0e 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawing.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawing.java
@@ -17,7 +17,7 @@
import org.onosproject.net.flow.FlowRuleOperations;
import org.onosproject.net.intent.IntentData;
-import org.onosproject.net.intent.impl.IntentManager;
+import org.onosproject.net.intent.impl.IntentProcessor;
import java.util.Optional;
@@ -29,20 +29,19 @@
*/
class Withdrawing implements IntentProcessPhase {
- // TODO: define an interface and use it, instead of IntentManager
- private final IntentManager intentManager;
+ private final IntentProcessor processor;
private final IntentData pending;
private final FlowRuleOperations flowRules;
- Withdrawing(IntentManager intentManager, IntentData pending, FlowRuleOperations flowRules) {
- this.intentManager = checkNotNull(intentManager);
+ Withdrawing(IntentProcessor processor, IntentData pending, FlowRuleOperations flowRules) {
+ this.processor = checkNotNull(processor);
this.pending = checkNotNull(pending);
this.flowRules = checkNotNull(flowRules);
}
@Override
public Optional<IntentProcessPhase> execute() {
- intentManager.flowRuleService.apply(flowRules);
+ processor.applyFlowRules(flowRules);
return Optional.of(new Withdrawn(pending));
}
}