Sho SHIMIZU

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
/*
* 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();
}
}
}
}
/*
* 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);
}
......@@ -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<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));
}
}
}
......
......@@ -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));
......
......@@ -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<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);
}
......
......@@ -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<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?
......
......@@ -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<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));
......
......@@ -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));
}
}
......
......@@ -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<IntentProcessPhase> execute() {
intentManager.flowRuleService.apply(flowRules);
processor.applyFlowRules(flowRules);
return Optional.of(new Withdrawn(pending));
}
}
......