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 0000000000..0ee149aec8 --- /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, + IntentCompiler> compilers = new ConcurrentHashMap<>(); + + /** + * Registers the specified compiler for the given intent class. + * + * @param cls intent class + * @param compiler intent compiler + * @param the type of intent + */ + public void registerCompiler(Class cls, IntentCompiler compiler) { + compilers.put(cls, compiler); + } + + /** + * Unregisters the compiler for the specified intent class. + * + * @param cls intent class + * @param the type of intent + */ + public void unregisterCompiler(Class cls) { + compilers.remove(cls); + } + + /** + * Returns immutable set of bindings of currently registered intent compilers. + * + * @return the set of compiler bindings + */ + public Map, IntentCompiler> getCompilers() { + return ImmutableMap.copyOf(compilers); + } + + /** + * Compiles an intent recursively. + * + * @param intent intent + * @param previousInstallables previous intent installables + * @return result of compilation + */ + List compile(Intent intent, List previousInstallables) { + if (intent.isInstallable()) { + return ImmutableList.of(intent); + } + + registerSubclassCompilerIfNeeded(intent); + // FIXME: get previous resources + List 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 the type of intent + * @return intent compiler corresponding to the specified intent + */ + private IntentCompiler getCompiler(T intent) { + @SuppressWarnings("unchecked") + IntentCompiler compiler = (IntentCompiler) 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 0000000000..e0103ce8fc --- /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, + IntentInstaller> installers = new ConcurrentHashMap<>(); + /** + * Registers the specified installer for the given installable intent class. + * + * @param cls installable intent class + * @param installer intent installer + * @param the type of installable intent + */ + void registerInstaller(Class cls, IntentInstaller installer) { + installers.put(cls, installer); + } + + /** + * Unregisters the installer for the given installable intent class. + * + * @param cls installable intent class + * @param the type of installable intent + */ + void unregisterInstaller(Class cls) { + installers.remove(cls); + } + + /** + * Returns immutable set of bindings of currently registered intent installers. + * + * @return the set of installer bindings + */ + Map, IntentInstaller> getInstallers() { + return ImmutableMap.copyOf(installers); + } + + /** + * Returns the corresponding intent installer to the specified installable intent. + * + * @param intent intent + * @param the type of installable intent + * @return intent installer corresponding to the specified installable intent + */ + private IntentInstaller getInstaller(T intent) { + @SuppressWarnings("unchecked") + IntentInstaller installer = (IntentInstaller) 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 oldInstallables = (current != null) ? current.installables() : null; + List newInstallables = pending.installables(); + + checkState(isNullOrEmpty(oldInstallables) || + oldInstallables.size() == newInstallables.size(), + "Old and New Intent must have equivalent installable intents."); + + List>> 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 installables = current.installables(); + List>> 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>> 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) + for (Iterator>> itr = plans.iterator(); itr.hasNext();) { + List> 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 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 8fa8b3f544..3699df6364 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.CoreService; 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.WithdrawRequest; 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 @@ public class IntentManager private static final EnumSet RECOMPILE = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ); - // Collections for compiler, installer, and listener are ONOS instance local - private final ConcurrentMap, - IntentCompiler> compilers = new ConcurrentHashMap<>(); - private final ConcurrentMap, - IntentInstaller> installers = new ConcurrentHashMap<>(); - private final AbstractListenerRegistry listenerRegistry = new AbstractListenerRegistry<>(); @@ -124,6 +111,9 @@ public class IntentManager 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 @@ public class IntentManager @Override public void registerCompiler(Class cls, IntentCompiler compiler) { - compilers.put(cls, compiler); + compilerRegistry.registerCompiler(cls, compiler); } @Override public void unregisterCompiler(Class cls) { - compilers.remove(cls); + compilerRegistry.unregisterCompiler(cls); } @Override public Map, IntentCompiler> getCompilers() { - return ImmutableMap.copyOf(compilers); + return compilerRegistry.getCompilers(); } @Override public void registerInstaller(Class cls, IntentInstaller installer) { - installers.put(cls, installer); + installerRegistry.registerInstaller(cls, installer); } @Override public void unregisterInstaller(Class cls) { - installers.remove(cls); + installerRegistry.unregisterInstaller(cls); } @Override public Map, IntentInstaller> getInstallers() { - return ImmutableMap.copyOf(installers); - } - - /** - * Returns the corresponding intent compiler to the specified intent. - * - * @param intent intent - * @param the type of intent - * @return intent compiler corresponding to the specified intent - */ - private IntentCompiler getCompiler(T intent) { - @SuppressWarnings("unchecked") - IntentCompiler compiler = (IntentCompiler) 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 the type of installable intent - * @return intent installer corresponding to the specified installable intent - */ - private IntentInstaller getInstaller(T intent) { - @SuppressWarnings("unchecked") - IntentInstaller installer = (IntentInstaller) 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 compileIntent(Intent intent, List previousInstallables) { - if (intent.isInstallable()) { - return ImmutableList.of(intent); - } - - registerSubclassCompilerIfNeeded(intent); - // FIXME: get previous resources - List 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 oldInstallables = (current != null) ? current.installables() : null; - List newInstallables = pending.installables(); - - checkState(isNullOrEmpty(oldInstallables) || - oldInstallables.size() == newInstallables.size(), - "Old and New Intent must have equivalent installable intents."); - - List>> 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 installables = current.installables(); - List>> 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>> 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) - for (Iterator>> itr = plans.iterator(); itr.hasNext();) { - List> 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 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 @@ public class IntentManager 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 @@ public class IntentManager // TODO ensure that only one batch is in flight at a time } } + + private class InternalIntentProcessor implements IntentProcessor { + @Override + public List compile(Intent intent, List 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 0000000000..c613a8dbcf --- /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 compile(Intent intent, List 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 b68230a908..97ea18e88f 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 @@ package org.onosproject.net.intent.impl.phase; 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 @@ final class Compiling implements IntentProcessPhase { 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 @@ final class Compiling implements IntentProcessPhase { public Optional execute() { try { List 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 5fd82ec0f3..ef76888edb 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 @@ package org.onosproject.net.intent.impl.phase; 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 @@ final class InstallCoordinating implements IntentProcessPhase { 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 @@ final class InstallCoordinating implements IntentProcessPhase { 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 e54b10a5ad..90e0fd28ab 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 @@ import static com.google.common.base.Preconditions.checkNotNull; */ 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 current; - public InstallRequest(IntentManager intentManager, IntentData intentData, Optional current) { - this.intentManager = checkNotNull(intentManager); + public InstallRequest(IntentProcessor processor, IntentData intentData, Optional 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 05c499f4ad..3a290ae176 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 @@ package org.onosproject.net.intent.impl.phase; 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 @@ final class Installing implements IntentProcessPhase { 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 @@ final class Installing implements IntentProcessPhase { @Override public Optional 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 24d6dd5575..ee854c8660 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 @@ package org.onosproject.net.intent.impl.phase; 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 @@ final class WithdrawCoordinating implements IntentProcessPhase { 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 @@ final class WithdrawCoordinating implements IntentProcessPhase { public Optional 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 bbc7f3428f..f2e120ff01 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 @@ import static com.google.common.base.Preconditions.checkNotNull; */ 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 @@ public final class WithdrawRequest implements IntentProcessPhase { //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 676c3c7c6c..9198d0eeb6 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 @@ package org.onosproject.net.intent.impl.phase; 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 @@ import static com.google.common.base.Preconditions.checkNotNull; */ 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 execute() { - intentManager.flowRuleService.apply(flowRules); + processor.applyFlowRules(flowRules); return Optional.of(new Withdrawn(pending)); } }