From 6d35a41bd686db2a16769bf41dbc027cc833c1b6 Mon Sep 17 00:00:00 2001 From: Tom Pantelis Date: Fri, 15 Apr 2016 15:19:50 -0400 Subject: [PATCH] Add config system API to recreate a module instance For the blueprint work, I need to be able to restart/recreate a config module, ie close the previous instance and create a new instance, when the corresponding service instance is recreated/re-advertised via blueprint container restart. The ConfigSubsystemFacade has no API to restart a config module. One can push a new configuration but there has to be an actual change in order for a new instance to be created otherwise it reuses the prior instance. Therefore I added a new EditStrategyType enum, recreate, with a corresponding EditConfigStrategy class that forces re-creation of a config module instance. This strategy calls a new method, reCreateModule, on the ConfigTransactionController interface. The decision logic to reuse or create a new instance is in the AbstractModule class and generated derived classes. Therefore the reCreateModule method sets a canReuseInstance flag on the real AbstractModule instance. This is probably not the cleanest approach but I wanted to avoid changing the Module interface as that looked to be too invasive. The AbstractModule getInstance and canReuse methods check the canReuseInstance override flag to determine if the old module/instance can be reused. Change-Id: I8cfb8408bae0127331676dcf32519b176f0a8844 Signed-off-by: Tom Pantelis --- .../api/ConfigTransactionController.java | 14 ++++++ .../controller/config/spi/AbstractModule.java | 9 +++- .../facade/xml/mapping/config/Config.java | 7 ++- .../facade/xml/strategy/EditStrategyType.java | 5 +- .../strategy/ReCreateEditConfigStrategy.java | 48 +++++++++++++++++++ .../impl/ConfigTransactionControllerImpl.java | 16 +++++++ .../util/ConfigTransactionJMXClient.java | 5 ++ .../TestingConfigTransactionController.java | 4 ++ 8 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 opendaylight/config/config-manager-facade-xml/src/main/java/org/opendaylight/controller/config/facade/xml/strategy/ReCreateEditConfigStrategy.java diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigTransactionController.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigTransactionController.java index 8afc80a4f3..bd9002c624 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigTransactionController.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigTransactionController.java @@ -29,6 +29,20 @@ public interface ConfigTransactionController extends LookupRegistry, ServiceRefe ObjectName createModule(String moduleName, String instanceName) throws InstanceAlreadyExistsException; + /** + * Re-creates an existing module configuration bean. + * + * @param objectName + * can be either read-only module name that can be obtained using + * {@link ConfigRegistry#lookupConfigBean(String, String)} or + * writable module name that must contain current transaction name. + * @throws InstanceNotFoundException + * if module is not found + * @throws IllegalArgumentException + * if object name contains wrong transaction name or domain + */ + void reCreateModule(ObjectName objectName) throws InstanceNotFoundException; + /** * Destroy existing module. * diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/AbstractModule.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/AbstractModule.java index e60a047379..7fcc0cc5c0 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/AbstractModule.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/AbstractModule.java @@ -27,6 +27,7 @@ public abstract class AbstractModule> implements org private AutoCloseable oldInstance; private M oldModule; private AutoCloseable instance; + private boolean canReuseInstance = true; /** * Called when module is configured. @@ -58,6 +59,10 @@ public abstract class AbstractModule> implements org return identifier; } + public final void setCanReuseInstance(boolean canReuseInstance) { + this.canReuseInstance = canReuseInstance; + } + /** * * General algorithm for spawning/closing and reusing wrapped instances. @@ -67,7 +72,7 @@ public abstract class AbstractModule> implements org @Override public final AutoCloseable getInstance() { if (instance == null) { - if (oldInstance != null && canReuseInstance(oldModule)) { + if (oldInstance != null && canReuseInstance && canReuseInstance(oldModule)) { resolveDependencies(); instance = reuseInstance(oldInstance); } else { @@ -102,7 +107,7 @@ public abstract class AbstractModule> implements org public final boolean canReuse(final Module oldModule) { // Just cast into a specific instance // TODO unify this method with canReuseInstance (required Module interface to be generic which requires quite a lot of changes) - return getClass().isInstance(oldModule) ? canReuseInstance((M) oldModule) : false; + return canReuseInstance && getClass().isInstance(oldModule) ? canReuseInstance((M) oldModule) : false; } /** diff --git a/opendaylight/config/config-manager-facade-xml/src/main/java/org/opendaylight/controller/config/facade/xml/mapping/config/Config.java b/opendaylight/config/config-manager-facade-xml/src/main/java/org/opendaylight/controller/config/facade/xml/mapping/config/Config.java index 3ecee286d3..9bee7a1085 100644 --- a/opendaylight/config/config-manager-facade-xml/src/main/java/org/opendaylight/controller/config/facade/xml/mapping/config/Config.java +++ b/opendaylight/config/config-manager-facade-xml/src/main/java/org/opendaylight/controller/config/facade/xml/mapping/config/Config.java @@ -9,7 +9,6 @@ package org.opendaylight.controller.config.facade.xml.mapping.config; import static com.google.common.base.Preconditions.checkState; - import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.HashMultimap; @@ -130,6 +129,12 @@ public class Config { return dataElement; } + public Element moduleToXml(String moduleNamespace, String factoryName, String instanceName, + ObjectName instanceON, Document document) { + ModuleConfig moduleConfig = getModuleMapping(moduleNamespace, instanceName, factoryName); + return moduleConfig.toXml(instanceON, document, moduleNamespace, enumResolver); + } + // TODO refactor, replace string representing namespace with namespace class // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved // class diff --git a/opendaylight/config/config-manager-facade-xml/src/main/java/org/opendaylight/controller/config/facade/xml/strategy/EditStrategyType.java b/opendaylight/config/config-manager-facade-xml/src/main/java/org/opendaylight/controller/config/facade/xml/strategy/EditStrategyType.java index c5af3ec065..47f5078967 100644 --- a/opendaylight/config/config-manager-facade-xml/src/main/java/org/opendaylight/controller/config/facade/xml/strategy/EditStrategyType.java +++ b/opendaylight/config/config-manager-facade-xml/src/main/java/org/opendaylight/controller/config/facade/xml/strategy/EditStrategyType.java @@ -17,7 +17,7 @@ public enum EditStrategyType { // can be default merge, replace, none, // additional per element - delete, remove; + delete, remove, recreate; private static final Set defaultStrats = EnumSet.of(merge, replace, none); @@ -31,6 +31,7 @@ public enum EditStrategyType { case none: case remove: case delete: + case recreate: return false; case replace: return true; @@ -64,6 +65,8 @@ public enum EditStrategyType { return new DeleteEditConfigStrategy(); case remove: return new RemoveEditConfigStrategy(); + case recreate: + return new ReCreateEditConfigStrategy(); case none: return new NoneEditConfigStrategy(); default: diff --git a/opendaylight/config/config-manager-facade-xml/src/main/java/org/opendaylight/controller/config/facade/xml/strategy/ReCreateEditConfigStrategy.java b/opendaylight/config/config-manager-facade-xml/src/main/java/org/opendaylight/controller/config/facade/xml/strategy/ReCreateEditConfigStrategy.java new file mode 100644 index 0000000000..5d695ac171 --- /dev/null +++ b/opendaylight/config/config-manager-facade-xml/src/main/java/org/opendaylight/controller/config/facade/xml/strategy/ReCreateEditConfigStrategy.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.config.facade.xml.strategy; + +import java.util.Map; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import org.opendaylight.controller.config.facade.xml.exception.ConfigHandlingException; +import org.opendaylight.controller.config.facade.xml.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.config.facade.xml.mapping.config.ServiceRegistryWrapper; +import org.opendaylight.controller.config.util.ConfigTransactionClient; +import org.opendaylight.controller.config.util.xml.DocumentedException; + +/** + * Edit strategy that forces re-creation of a module instance even if the config didn't change. + * + * @author Thomas Pantelis + */ +public class ReCreateEditConfigStrategy extends AbstractEditConfigStrategy { + + @Override + void handleMissingInstance(Map configuration, ConfigTransactionClient ta, + String module, String instance, ServiceRegistryWrapper services) throws ConfigHandlingException { + throw new ConfigHandlingException( + String.format("Unable to recreate %s : %s, Existing module instance not found", module, instance), + DocumentedException.ErrorType.application, + DocumentedException.ErrorTag.operation_failed, + DocumentedException.ErrorSeverity.error); + } + + @Override + void executeStrategy(Map configuration, ConfigTransactionClient ta, + ObjectName objectName, ServiceRegistryWrapper services) throws ConfigHandlingException { + try { + ta.reCreateModule(objectName); + } catch(InstanceNotFoundException e) { + throw new ConfigHandlingException(String.format("Unable to recreate instance for %s", objectName), + DocumentedException.ErrorType.application, + DocumentedException.ErrorTag.operation_failed, + DocumentedException.ErrorSeverity.error); + } + } +} diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java index ebf6266540..e426d70df7 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java @@ -41,6 +41,7 @@ import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXR import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration; import org.opendaylight.controller.config.manager.impl.osgi.mapping.BindingContextProvider; import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper; +import org.opendaylight.controller.config.spi.AbstractModule; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.controller.config.spi.ModuleFactory; import org.opendaylight.yangtools.concepts.Identifiable; @@ -242,6 +243,21 @@ class ConfigTransactionControllerImpl implements moduleFactory, null, dependencyResolver, defaultBean, bundleContext); } + @Override + public synchronized void reCreateModule(ObjectName objectName) throws InstanceNotFoundException { + transactionStatus.checkNotCommitStarted(); + transactionStatus.checkNotAborted(); + checkTransactionName(objectName); + ObjectNameUtil.checkDomain(objectName); + ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(objectName, ObjectNameUtil.TYPE_MODULE); + + ModuleInternalTransactionalInfo txInfo = dependencyResolverManager.findModuleInternalTransactionalInfo(moduleIdentifier); + Module realModule = txInfo.getRealModule(); + if(realModule instanceof AbstractModule) { + ((AbstractModule)realModule).setCanReuseInstance(false); + } + } + private synchronized ObjectName putConfigBeanToJMXAndInternalMaps( ModuleIdentifier moduleIdentifier, Module module, ModuleFactory moduleFactory, diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java index 26ca1391ad..d49c37ddd8 100644 --- a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java +++ b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java @@ -88,6 +88,11 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { return configTransactionControllerMXBeanProxy.createModule(moduleName, instanceName); } + @Override + public void reCreateModule(ObjectName objectName) throws InstanceNotFoundException { + configTransactionControllerMXBeanProxy.reCreateModule(objectName); + } + @Override public void destroyModule(ObjectName objectName) throws InstanceNotFoundException { diff --git a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java index e69019405d..73ab6dad7b 100644 --- a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java +++ b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java @@ -62,6 +62,10 @@ public class TestingConfigTransactionController implements + "=" + moduleName); } + @Override + public void reCreateModule(ObjectName objectName) { + } + @Override public void destroyModule(ObjectName objectName) throws InstanceNotFoundException { -- 2.36.6