From: Ed Warnicke Date: Thu, 28 Nov 2013 09:45:10 +0000 (+0000) Subject: Merge "Table features : modified yang model. Patch set 2: Modified match types as... X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-1~322 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=b2d4575c4425e3b3d5aeaf1190e01e5d5a5286aa;hp=137d8db856cf5231391c86a6324288b53c2c16cb Merge "Table features : modified yang model. Patch set 2: Modified match types as identity for extensibility." --- diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java index 84c2c6dd4d..0fd6c52794 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java @@ -114,8 +114,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe BundleContext bundleContext, MBeanServer configMBeanServer, BaseJMXRegistrator baseJMXRegistrator) { this.resolver = resolver; - this.beanToOsgiServiceManager = new BeanToOsgiServiceManager( - bundleContext); + this.beanToOsgiServiceManager = new BeanToOsgiServiceManager(); this.bundleContext = bundleContext; this.configMBeanServer = configMBeanServer; this.baseJMXRegistrator = baseJMXRegistrator; @@ -138,7 +137,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe String transactionName = "ConfigTransaction-" + version + "-" + versionCounter; TransactionJMXRegistrator transactionRegistrator = baseJMXRegistrator .createTransactionJMXRegistrator(transactionName); - List allCurrentFactories = Collections.unmodifiableList(resolver.getAllFactories()); + Map> allCurrentFactories = Collections.unmodifiableMap(resolver.getAllFactories()); ConfigTransactionControllerInternal transactionController = new ConfigTransactionControllerImpl( transactionName, transactionRegistrator, version, versionCounter, allCurrentFactories, transactionsMBeanServer, configMBeanServer, bundleContext); @@ -320,8 +319,16 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe // register to OSGi if (osgiRegistration == null) { - osgiRegistration = beanToOsgiServiceManager.registerToOsgi(module.getClass(), - newReadableConfigBean.getInstance(), entry.getName()); + ModuleFactory moduleFactory = entry.getModuleFactory(); + if(moduleFactory != null) { + BundleContext bc = configTransactionController. + getModuleFactoryBundleContext(moduleFactory.getImplementationName()); + osgiRegistration = beanToOsgiServiceManager.registerToOsgi(module.getClass(), + newReadableConfigBean.getInstance(), entry.getName(), bc); + } else { + throw new NullPointerException(entry.getIdentifier().getFactoryName() + " ModuleFactory not found."); + } + } RootRuntimeBeanRegistratorImpl runtimeBeanRegistrator = runtimeRegistrators 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 3f569ae324..a9ab664fd6 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 @@ -34,12 +34,13 @@ import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; import javax.management.ObjectName; -import java.util.ArrayList; -import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.ArrayList; +import java.util.Collection; import java.util.concurrent.atomic.AtomicBoolean; import static java.lang.String.format; @@ -64,7 +65,7 @@ class ConfigTransactionControllerImpl implements private final DependencyResolverManager dependencyResolverManager; private final TransactionStatus transactionStatus; private final MBeanServer transactionsMBeanServer; - private final List currentlyRegisteredFactories; + private final Map> currentlyRegisteredFactories; /** * Disables ability of {@link DynamicWritableWrapper} to change attributes @@ -82,7 +83,7 @@ class ConfigTransactionControllerImpl implements public ConfigTransactionControllerImpl(String transactionName, TransactionJMXRegistrator transactionRegistrator, long parentVersion, long currentVersion, - List currentlyRegisteredFactories, + Map> currentlyRegisteredFactories, MBeanServer transactionsMBeanServer, MBeanServer configMBeanServer, BundleContext bundleContext) { this.transactionIdentifier = new TransactionIdentifier(transactionName); @@ -120,11 +121,11 @@ class ConfigTransactionControllerImpl implements transactionStatus.checkNotAborted(); Set oldSet = new HashSet<>(lastListOfFactories); - Set newSet = new HashSet<>(currentlyRegisteredFactories); + Set newSet = new HashSet<>(factoriesHolder.getModuleFactories()); List toBeAdded = new ArrayList<>(); List toBeRemoved = new ArrayList<>(); - for(ModuleFactory moduleFactory: currentlyRegisteredFactories) { + for(ModuleFactory moduleFactory: factoriesHolder.getModuleFactories()) { if (oldSet.contains(moduleFactory) == false){ toBeAdded.add(moduleFactory); } @@ -136,7 +137,8 @@ class ConfigTransactionControllerImpl implements } // add default modules for (ModuleFactory moduleFactory : toBeAdded) { - Set defaultModules = moduleFactory.getDefaultModules(dependencyResolverManager, bundleContext); + Set defaultModules = moduleFactory.getDefaultModules(dependencyResolverManager, + getModuleFactoryBundleContext(moduleFactory.getImplementationName())); for (Module module : defaultModules) { // ensure default module to be registered to jmx even if its module factory does not use dependencyResolverFactory DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(module.getIdentifier()); @@ -173,9 +175,10 @@ class ConfigTransactionControllerImpl implements DependencyResolver dependencyResolver = dependencyResolverManager .getOrCreate(moduleIdentifier); try { + BundleContext bc = getModuleFactoryBundleContext(moduleFactory.getImplementationName()); module = moduleFactory.createModule( moduleIdentifier.getInstanceName(), dependencyResolver, - oldConfigBeanInfo.getReadableModule(), bundleContext); + oldConfigBeanInfo.getReadableModule(), bc); } catch (Exception e) { throw new IllegalStateException(format( "Error while copying old configuration from %s to %s", @@ -196,7 +199,8 @@ class ConfigTransactionControllerImpl implements // find factory ModuleFactory moduleFactory = factoriesHolder.findByModuleName(factoryName); DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(moduleIdentifier); - Module module = moduleFactory.createModule(instanceName, dependencyResolver, bundleContext); + Module module = moduleFactory.createModule(instanceName, dependencyResolver, + getModuleFactoryBundleContext(moduleFactory.getImplementationName())); return putConfigBeanToJMXAndInternalMaps(moduleIdentifier, module, moduleFactory, null, dependencyResolver); } @@ -466,11 +470,20 @@ class ConfigTransactionControllerImpl implements @Override public List getCurrentlyRegisteredFactories() { - return currentlyRegisteredFactories; + return new ArrayList<>(factoriesHolder.getModuleFactories()); } @Override public TransactionIdentifier getIdentifier() { return transactionIdentifier; } + + @Override + public BundleContext getModuleFactoryBundleContext(String factoryName) { + Map.Entry factoryBundleContextEntry = this.currentlyRegisteredFactories.get(factoryName); + if (factoryBundleContextEntry == null || factoryBundleContextEntry.getValue() == null) { + throw new NullPointerException("Bundle context of " + factoryName + " ModuleFactory not found."); + } + return factoryBundleContextEntry.getValue(); + } } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java index 556639c3ab..4dc877c62b 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java @@ -15,6 +15,7 @@ import javax.management.ObjectName; import org.opendaylight.controller.config.api.ModuleIdentifier; import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.spi.ModuleFactory; +import org.osgi.framework.BundleContext; /** * Defines contract between {@link ConfigTransactionControllerImpl} (producer) @@ -68,4 +69,6 @@ interface ConfigTransactionControllerInternal extends boolean isClosed(); List getCurrentlyRegisteredFactories(); + + BundleContext getModuleFactoryBundleContext(String factoryName); } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java index 8f1c69eee3..f82a7295aa 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java @@ -7,17 +7,20 @@ */ package org.opendaylight.controller.config.manager.impl.factoriesresolver; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; import org.opendaylight.controller.config.spi.ModuleFactory; +import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Set; +import java.util.List; +import java.util.Map; +import java.util.Collections; +import java.util.TreeSet; +import java.util.Collection; +import java.util.ArrayList; + /** * Hold sorted ConfigMBeanFactories by their module names. Check that module * names are globally unique. @@ -26,8 +29,9 @@ public class HierarchicalConfigMBeanFactoriesHolder { private static final Logger logger = LoggerFactory .getLogger(HierarchicalConfigMBeanFactoriesHolder.class); - private final Map moduleNamesToConfigBeanFactories; + private final Map> moduleNamesToConfigBeanFactories; private final Set moduleNames; + private final List moduleFactories; /** * Create instance. @@ -36,40 +40,17 @@ public class HierarchicalConfigMBeanFactoriesHolder { * if unique constraint on module names is violated */ public HierarchicalConfigMBeanFactoriesHolder( - List list) { - Map moduleNamesToConfigBeanFactories = new HashMap<>(); - StringBuffer errors = new StringBuffer(); - for (ModuleFactory factory : list) { - String moduleName = factory.getImplementationName(); - if (moduleName == null || moduleName.isEmpty()) { - throw new IllegalStateException( - "Invalid implementation name for " + factory); - } - logger.debug("Reading factory {} {}", moduleName, factory); - String error = null; - ModuleFactory conflicting = moduleNamesToConfigBeanFactories - .get(moduleName); - if (conflicting != null) { - error = String - .format("Module name is not unique. Found two conflicting factories with same name '%s': " + - "\n\t%s\n\t%s\n", moduleName, conflicting, factory); - - } - - if (error == null) { - moduleNamesToConfigBeanFactories.put(moduleName, factory); - } else { - errors.append(error); - } - - } - if (errors.length() > 0) { - throw new IllegalArgumentException(errors.toString()); - } + Map> factoriesMap) { this.moduleNamesToConfigBeanFactories = Collections - .unmodifiableMap(moduleNamesToConfigBeanFactories); + .unmodifiableMap(factoriesMap); moduleNames = Collections.unmodifiableSet(new TreeSet<>( moduleNamesToConfigBeanFactories.keySet())); + List factories = new ArrayList<>(this.moduleNamesToConfigBeanFactories.size()); + Collection> entryCollection = this.moduleNamesToConfigBeanFactories.values(); + for (Map.Entry entry : entryCollection) { + factories.add(entry.getKey()); + } + this.moduleFactories = Collections.unmodifiableList(factories); } /** @@ -79,16 +60,20 @@ public class HierarchicalConfigMBeanFactoriesHolder { * if factory is not found */ public ModuleFactory findByModuleName(String moduleName) { - ModuleFactory result = moduleNamesToConfigBeanFactories.get(moduleName); + Map.Entry result = moduleNamesToConfigBeanFactories.get(moduleName); if (result == null) { throw new IllegalArgumentException( "ModuleFactory not found with module name: " + moduleName); } - return result; + return result.getKey(); } public Set getModuleNames() { return moduleNames; } + public List getModuleFactories() { + return moduleFactories; + } + } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/ModuleFactoriesResolver.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/ModuleFactoriesResolver.java index 4c6697e6b2..fc39fab1fb 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/ModuleFactoriesResolver.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/ModuleFactoriesResolver.java @@ -7,9 +7,10 @@ */ package org.opendaylight.controller.config.manager.impl.factoriesresolver; -import java.util.List; - import org.opendaylight.controller.config.spi.ModuleFactory; +import org.osgi.framework.BundleContext; + +import java.util.Map; /** * {@link org.opendaylight.controller.config.manager.impl.ConfigTransactionControllerImpl} @@ -20,6 +21,6 @@ import org.opendaylight.controller.config.spi.ModuleFactory; */ public interface ModuleFactoriesResolver { - List getAllFactories(); + Map> getAllFactories(); } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BeanToOsgiServiceManager.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BeanToOsgiServiceManager.java index 42f8b8790b..41f577844a 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BeanToOsgiServiceManager.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BeanToOsgiServiceManager.java @@ -7,11 +7,6 @@ */ package org.opendaylight.controller.config.manager.impl.osgi; -import java.util.Dictionary; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Set; - import org.opendaylight.controller.config.api.ModuleIdentifier; import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper; @@ -19,6 +14,11 @@ import org.opendaylight.controller.config.spi.Module; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; +import java.util.Dictionary; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Set; + /** * Registers instantiated beans as OSGi services and unregisters these services * if beans are destroyed. @@ -28,12 +28,6 @@ public class BeanToOsgiServiceManager { static final String INSTANCE_NAME_OSGI_PROP = "instanceName"; static final String IMPLEMENTATION_NAME_OSGI_PROP = "implementationName"; - private final BundleContext bundleContext; - - public BeanToOsgiServiceManager(BundleContext context) { - this.bundleContext = context; - } - /** * To be called for every created, reconfigured and recreated config bean. * It is expected that before using this method OSGi service registry will @@ -41,7 +35,7 @@ public class BeanToOsgiServiceManager { */ public OsgiRegistration registerToOsgi( Class configBeanClass, AutoCloseable instance, - ModuleIdentifier moduleIdentifier) { + ModuleIdentifier moduleIdentifier, BundleContext bundleContext) { try { final Set> configuresInterfaces = InterfacesHelper .getOsgiRegistrationTypes(configBeanClass); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolver.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolver.java index 7c8c4e6008..2a533ab9a3 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolver.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolver.java @@ -7,21 +7,26 @@ */ package org.opendaylight.controller.config.manager.impl.osgi; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver; import org.opendaylight.controller.config.spi.ModuleFactory; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.AbstractMap; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; /** * Retrieves list of currently registered Module Factories using bundlecontext. */ public class BundleContextBackedModuleFactoriesResolver implements ModuleFactoriesResolver { + private static final Logger logger = LoggerFactory + .getLogger(BundleContextBackedModuleFactoriesResolver.class); private final BundleContext bundleContext; public BundleContextBackedModuleFactoriesResolver( @@ -30,7 +35,7 @@ public class BundleContextBackedModuleFactoriesResolver implements } @Override - public List getAllFactories() { + public Map> getAllFactories() { Collection> serviceReferences; try { serviceReferences = bundleContext.getServiceReferences( @@ -38,15 +43,43 @@ public class BundleContextBackedModuleFactoriesResolver implements } catch (InvalidSyntaxException e) { throw new IllegalStateException(e); } - List result = new ArrayList<>(serviceReferences.size()); + Map> result = new HashMap<>(serviceReferences.size()); for (ServiceReference serviceReference : serviceReferences) { - ModuleFactory service = bundleContext.getService(serviceReference); + ModuleFactory factory = bundleContext.getService(serviceReference); // null if the service is not registered, the service object // returned by a ServiceFactory does not // implement the classes under which it was registered or the // ServiceFactory threw an exception. - if (service != null) { - result.add(service); + if(factory == null) { + throw new NullPointerException("ServiceReference of class" + serviceReference.getClass() + "not found."); + } + StringBuffer errors = new StringBuffer(); + String moduleName = factory.getImplementationName(); + if (moduleName == null || moduleName.isEmpty()) { + throw new IllegalStateException( + "Invalid implementation name for " + factory); + } + if (serviceReference.getBundle() == null || serviceReference.getBundle().getBundleContext() == null) { + throw new NullPointerException("Bundle context of " + factory + " ModuleFactory not found."); + } + logger.debug("Reading factory {} {}", moduleName, factory); + String error = null; + Map.Entry conflicting = result.get(moduleName); + if (conflicting != null) { + error = String + .format("Module name is not unique. Found two conflicting factories with same name '%s': " + + "\n\t%s\n\t%s\n", moduleName, conflicting.getKey(), factory); + + } + + if (error == null) { + result.put(moduleName, new AbstractMap.SimpleImmutableEntry<>(factory, + serviceReference.getBundle().getBundleContext())); + } else { + errors.append(error); + } + if (errors.length() > 0) { + throw new IllegalArgumentException(errors.toString()); } } return result; diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java index f567f1b31e..ab81143170 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java @@ -16,6 +16,7 @@ import org.opendaylight.controller.config.manager.impl.jmx.ConfigRegistryJMXRegi import org.opendaylight.controller.config.spi.ModuleFactory; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; import org.osgi.util.tracker.ServiceTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,6 +28,7 @@ public class ConfigManagerActivator implements BundleActivator { private ExtenderBundleTracker extenderBundleTracker; private ConfigRegistryImpl configRegistry; private ConfigRegistryJMXRegistrator configRegistryJMXRegistrator; + private ServiceRegistration configRegistryServiceRegistration; @Override public void start(BundleContext context) throws Exception { @@ -37,6 +39,9 @@ public class ConfigManagerActivator implements BundleActivator { bundleContextBackedModuleFactoriesResolver, context, configMBeanServer); + // register config registry to OSGi + configRegistryServiceRegistration = context.registerService(ConfigRegistryImpl.class, configRegistry, null); + // register config registry to jmx configRegistryJMXRegistrator = new ConfigRegistryJMXRegistrator(configMBeanServer); configRegistryJMXRegistrator.registerToJMX(configRegistry); @@ -69,5 +74,10 @@ public class ConfigManagerActivator implements BundleActivator { "Exception while closing config registry jmx registrator", e); } + try { + configRegistryServiceRegistration.unregister(); + } catch (Exception e) { + logger.warn("Exception while unregistering config registry", e); + } } } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelper.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelper.java index 6cd855450d..76cb64cf93 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelper.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelper.java @@ -87,6 +87,7 @@ public class InterfacesHelper { */ public static Set> getOsgiRegistrationTypes( Class configBeanClass) { + // TODO test with service interface hierarchy Set> serviceInterfaces = getServiceInterfaces(configBeanClass); Set> result = new HashSet<>(); for (Class clazz : serviceInterfaces) { diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/ConfigRegistryImplTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/ConfigRegistryImplTest.java index 928f2c1879..ccb67d371e 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/ConfigRegistryImplTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/ConfigRegistryImplTest.java @@ -33,14 +33,15 @@ public class ConfigRegistryImplTest extends @Test public void testFailOnTwoFactoriesExportingSameImpl() { ModuleFactory factory = new TestingFixedThreadPoolModuleFactory(); - ModuleFactoriesResolver resolver = new HardcodedModuleFactoriesResolver( - factory, factory); - BundleContext context = mock(BundleContext.class); - - ConfigRegistryImpl configRegistry = new ConfigRegistryImpl(resolver, - context, ManagementFactory.getPlatformMBeanServer()); + ConfigRegistryImpl configRegistry = null; try { + ModuleFactoriesResolver resolver = new HardcodedModuleFactoriesResolver( + factory, factory); + + configRegistry = new ConfigRegistryImpl(resolver, + context, ManagementFactory.getPlatformMBeanServer()); + configRegistry.beginConfig(); fail(); } catch (IllegalArgumentException e) { diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java index 18a22bb26f..5ed56bd2bf 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java @@ -7,21 +7,6 @@ */ package org.opendaylight.controller.config.manager.impl; -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; - -import java.io.Closeable; -import java.lang.management.ManagementFactory; -import java.util.Dictionary; -import java.util.Set; - -import javax.management.InstanceAlreadyExistsException; -import javax.management.MBeanServer; -import javax.management.ObjectName; - import org.junit.After; import org.mockito.Matchers; import org.opendaylight.controller.config.api.jmx.CommitStatus; @@ -35,6 +20,20 @@ import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; +import javax.management.InstanceAlreadyExistsException; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import java.io.Closeable; +import java.lang.management.ManagementFactory; +import java.util.Dictionary; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + /** * Each test that relies on * {@link org.opendaylight.controller.config.manager.impl.ConfigRegistryImpl} @@ -51,7 +50,7 @@ public abstract class AbstractConfigTest extends protected ConfigRegistryJMXClient configRegistryClient; protected BaseJMXRegistrator baseJmxRegistrator; protected InternalJMXRegistrator internalJmxRegistrator; - protected BundleContext mockedContext; + protected BundleContext mockedContext = mock(BundleContext.class); protected ServiceRegistration mockedServiceRegistration; // this method should be called in @Before @@ -62,12 +61,12 @@ public abstract class AbstractConfigTest extends configRegistryJMXRegistrator = new ConfigRegistryJMXRegistrator( platformMBeanServer); - this.mockedContext = mock(BundleContext.class); this.mockedServiceRegistration = mock(ServiceRegistration.class); doNothing().when(mockedServiceRegistration).unregister(); doReturn(mockedServiceRegistration).when(mockedContext).registerService( Matchers.any(String[].class), any(Closeable.class), any(Dictionary.class)); + internalJmxRegistrator = new InternalJMXRegistrator(platformMBeanServer); baseJmxRegistrator = new BaseJMXRegistrator(internalJmxRegistrator); diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImplTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImplTest.java index c77c97b8f0..3cb0f447b4 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImplTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImplTest.java @@ -17,13 +17,14 @@ import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistr import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator; import org.opendaylight.controller.config.manager.impl.runtimembean.TestingRuntimeBean; import org.opendaylight.controller.config.spi.ModuleFactory; +import org.osgi.framework.BundleContext; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.ObjectName; import java.lang.management.ManagementFactory; -import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import static org.junit.Assert.assertEquals; @@ -59,7 +60,7 @@ public class ConfigTransactionControllerImplTest extends baseJMXRegistrator = new BaseJMXRegistrator( ManagementFactory.getPlatformMBeanServer()); transactionsMBeanServer = MBeanServerFactory.createMBeanServer(); - List currentlyRegisteredFactories = new ArrayList<>(); + Map> currentlyRegisteredFactories = new HashMap<>(); TransactionJMXRegistrator jmxRegistrator123 = baseJMXRegistrator .createTransactionJMXRegistrator(transactionName123); diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HardcodedModuleFactoriesResolver.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HardcodedModuleFactoriesResolver.java index 04f651f6d3..3c2230735e 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HardcodedModuleFactoriesResolver.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HardcodedModuleFactoriesResolver.java @@ -7,21 +7,76 @@ */ package org.opendaylight.controller.config.manager.impl.factoriesresolver; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.opendaylight.controller.config.spi.ModuleFactory; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; + +import java.io.Closeable; import java.util.Arrays; +import java.util.Dictionary; import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.AbstractMap; -import org.opendaylight.controller.config.spi.ModuleFactory; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; public class HardcodedModuleFactoriesResolver implements ModuleFactoriesResolver { - private final List list; + private Map> factories; + + public HardcodedModuleFactoriesResolver(BundleContext bundleContext, ModuleFactory... list) { + List factoryList = Arrays.asList(list); + this.factories = new HashMap<>(factoryList.size()); + for (ModuleFactory moduleFactory : list) { + StringBuffer errors = new StringBuffer(); + String moduleName = moduleFactory.getImplementationName(); + if (moduleName == null || moduleName.isEmpty()) { + throw new IllegalStateException( + "Invalid implementation name for " + moduleFactory); + } + String error = null; + Map.Entry conflicting = factories.get(moduleName); + if (conflicting != null) { + error = String + .format("Module name is not unique. Found two conflicting factories with same name '%s': " + + "\n\t%s\n\t%s\n", moduleName, conflicting.getKey(), moduleFactory); + + } + + if (error == null) { + factories.put(moduleName, new AbstractMap.SimpleEntry<>(moduleFactory, + bundleContext)); + } else { + errors.append(error); + } + if (errors.length() > 0) { + throw new IllegalArgumentException(errors.toString()); + } + } + } public HardcodedModuleFactoriesResolver(ModuleFactory... list) { - this.list = Arrays.asList(list); + this(mockBundleContext(),list); + } + + private static BundleContext mockBundleContext() { + BundleContext bundleContext = Mockito.mock(BundleContext.class); + ServiceRegistration serviceRegistration = mock(ServiceRegistration.class); + doNothing().when(serviceRegistration).unregister(); + doReturn(serviceRegistration).when(bundleContext).registerService( + Matchers.any(String[].class), any(Closeable.class), + any(Dictionary.class)); + return bundleContext; } @Override - public List getAllFactories() { - return list; + public Map> getAllFactories() { + return factories; } } diff --git a/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleFactory.java b/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleFactory.java index a157e1ed5d..5e8612f7b9 100644 --- a/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleFactory.java +++ b/opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleFactory.java @@ -8,6 +8,22 @@ */ package org.opendaylight.controller.config.yang.logback.config; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.DependencyResolverFactory; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.osgi.framework.BundleContext; +import org.slf4j.LoggerFactory; + import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.encoder.PatternLayoutEncoder; @@ -17,21 +33,10 @@ import ch.qos.logback.core.Appender; import ch.qos.logback.core.rolling.FixedWindowRollingPolicy; import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy; import ch.qos.logback.core.rolling.TimeBasedRollingPolicy; + import com.google.common.base.Preconditions; import com.google.common.collect.Lists; -import org.apache.commons.lang3.StringUtils; -import org.opendaylight.controller.config.api.DependencyResolver; -import org.opendaylight.controller.config.api.ModuleIdentifier; -import org.osgi.framework.BundleContext; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; +import com.google.common.collect.Sets; /** * @@ -39,15 +44,15 @@ import java.util.Map.Entry; public class LogbackModuleFactory extends org.opendaylight.controller.config.yang.logback.config.AbstractLogbackModuleFactory { - private static final String INSTANCE_NAME = "singleton"; + public static final String INSTANCE_NAME = "singleton"; private Map loggersDTOs; private Map rollingDTOs; private Map consoleDTOs; private Map fileDTOs; @Override - public LogbackModule instantiateModule(String instanceName, - DependencyResolver dependencyResolver, BundleContext bundleContext) { + public LogbackModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, + BundleContext bundleContext) { Preconditions.checkArgument(instanceName.equals(INSTANCE_NAME), "There should be just one instance of logback, named " + INSTANCE_NAME); prepareDTOs(); @@ -61,9 +66,8 @@ public class LogbackModuleFactory extends } @Override - public LogbackModule instantiateModule(String instanceName, - DependencyResolver dependencyResolver, LogbackModule oldModule, - AutoCloseable oldInstance, BundleContext bundleContext) { + public LogbackModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, + LogbackModule oldModule, AutoCloseable oldInstance, BundleContext bundleContext) { Preconditions.checkArgument(instanceName.equals(INSTANCE_NAME), "There should be just one instance of logback, named " + INSTANCE_NAME); prepareDTOs(); @@ -220,4 +224,14 @@ public class LogbackModuleFactory extends return Lists.newArrayList(loggersToReturn.values()); } + @Override + public Set getDefaultModules(DependencyResolverFactory dependencyResolverFactory, + BundleContext bundleContext) { + DependencyResolver resolver = dependencyResolverFactory.createDependencyResolver(new ModuleIdentifier( + getImplementationName(), INSTANCE_NAME)); + LogbackModule defaultLogback = instantiateModule(INSTANCE_NAME, resolver, bundleContext); + Set defaultModules = Sets.newHashSet(defaultLogback); + return defaultModules; + } + } diff --git a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java index 846b9cd352..296ce79f6e 100644 --- a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java +++ b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java @@ -7,29 +7,24 @@ */ package org.opendaylight.controller.config.yang.logback.config; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.junit.matchers.JUnitMatchers.containsString; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.ObjectName; - import org.junit.Before; import org.junit.Ignore; import org.junit.Test; -import org.opendaylight.controller.config.api.ConflictingVersionException; import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.jmx.CommitStatus; import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; +import javax.management.ObjectName; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.junit.matchers.JUnitMatchers.containsString; + public class LogbackModuleTest extends AbstractConfigTest { private static final String INSTANCE_NAME = "singleton"; @@ -37,14 +32,14 @@ public class LogbackModuleTest extends AbstractConfigTest { private LogbackModuleFactory factory; @Before - public void setUp() throws IOException, ClassNotFoundException, InterruptedException { + public void setUp() throws Exception { factory = new LogbackModuleFactory(); super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(factory)); } @Test - public void testCreateBean() throws InstanceAlreadyExistsException { + public void testCreateBean() throws Exception { CommitStatus status = createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", @@ -55,7 +50,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testReusingInstance() throws InstanceAlreadyExistsException { + public void testReusingInstance() throws Exception { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", 0, "FileAppender").commit(); @@ -70,8 +65,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testRecreateInstance() throws InstanceAlreadyExistsException, ValidationException, - ConflictingVersionException, InstanceNotFoundException { + public void testRecreateInstance() throws Exception { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", 0, "FileAppender").commit(); @@ -88,7 +82,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testDestroyInstance() throws InstanceNotFoundException, InstanceAlreadyExistsException { + public void testDestroyInstance() throws Exception { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", 0, "FileAppender").commit(); @@ -104,7 +98,7 @@ public class LogbackModuleTest extends AbstractConfigTest { @Ignore @Test - public void testValidation1() throws InstanceAlreadyExistsException { + public void testValidation1() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", @@ -116,7 +110,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation2() throws InstanceAlreadyExistsException { + public void testValidation2() throws Exception { try { createBeans(true, "target/rollingApp", null, "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", 0, "FileAppender").commit(); @@ -127,7 +121,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation4() throws InstanceAlreadyExistsException { + public void testValidation4() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", null, 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", @@ -139,7 +133,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation6() throws InstanceAlreadyExistsException { + public void testValidation6() throws Exception { try { createBeans(true, "", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", 0, "FileAppender") @@ -151,7 +145,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation7() throws InstanceAlreadyExistsException { + public void testValidation7() throws Exception { try { createBeans( @@ -164,7 +158,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation8() throws InstanceAlreadyExistsException { + public void testValidation8() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", null, "DEBUG", "FixedWindowRollingPolicy", 0, @@ -176,7 +170,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation9() throws InstanceAlreadyExistsException { + public void testValidation9() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "", "DEBUG", "FixedWindowRollingPolicy", 0, @@ -188,7 +182,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation10() throws InstanceAlreadyExistsException { + public void testValidation10() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", null, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", @@ -200,7 +194,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation11() throws InstanceAlreadyExistsException { + public void testValidation11() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, null, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", @@ -212,7 +206,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation12() throws InstanceAlreadyExistsException { + public void testValidation12() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, null, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", null, 1, "FileAppender") @@ -224,7 +218,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation13() throws InstanceAlreadyExistsException { + public void testValidation13() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, null, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "", 1, "FileAppender") @@ -236,7 +230,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation14() throws InstanceAlreadyExistsException { + public void testValidation14() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, null, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "RollingPolicy", 1, @@ -248,7 +242,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testTimeBasedRollingPolicy() throws InstanceAlreadyExistsException { + public void testTimeBasedRollingPolicy() throws Exception { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", null, null, "target/%d.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "TimeBasedRollingPolicy", 1, "FileAppender").commit(); @@ -257,10 +251,10 @@ public class LogbackModuleTest extends AbstractConfigTest { private ConfigTransactionJMXClient createBeans(Boolean isAppend, String rollingFileName, String encoderPattern, String maxFileSize, Integer minIndex, Integer maxIndex, String fileNamePattern, String rollingName, String consoleName, String thresholdFilter, String loggerName, String level, String rollingPolicyType, - int maxHistory, String fileAppName) throws InstanceAlreadyExistsException { + int maxHistory, String fileAppName) throws Exception { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), INSTANCE_NAME); - LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameCreated, LogbackModuleMXBean.class); + ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), INSTANCE_NAME); + LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameRetrieved, LogbackModuleMXBean.class); List rollingAppenders = new ArrayList<>(); RollingFileAppenderTO rollingAppender = new RollingFileAppenderTO(); diff --git a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java index 79e46ae6d2..eeb8289e86 100644 --- a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java +++ b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java @@ -17,7 +17,9 @@ import java.util.Arrays; import java.util.List; import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; import javax.management.JMX; +import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.apache.commons.io.FileUtils; @@ -142,7 +144,8 @@ public class LogbackModuleWithInitialConfigurationTest extends AbstractConfigTes } - public ObjectName createBeans() throws JoranException, InstanceAlreadyExistsException, IOException { + public ObjectName createBeans() throws JoranException, InstanceAlreadyExistsException, IOException, + MalformedObjectNameException, InstanceNotFoundException { LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); @@ -200,8 +203,8 @@ public class LogbackModuleWithInitialConfigurationTest extends AbstractConfigTes loggersDTOs.add(log); ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), "singleton"); - LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameCreated, LogbackModuleMXBean.class); + ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), LogbackModuleFactory.INSTANCE_NAME); + LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameRetrieved, LogbackModuleMXBean.class); bean.setLoggerTO(loggersDTOs); bean.setRollingFileAppenderTO(rollingAppenders); @@ -210,6 +213,6 @@ public class LogbackModuleWithInitialConfigurationTest extends AbstractConfigTes transaction.commit(); - return nameCreated; + return nameRetrieved; } } diff --git a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java index 004c18c5e0..8718f8a9ce 100644 --- a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java +++ b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java @@ -17,6 +17,7 @@ import java.util.List; import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.JMX; +import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.apache.commons.io.FileUtils; @@ -27,12 +28,12 @@ import org.opendaylight.controller.config.manager.impl.factoriesresolver.Hardcod import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; import org.slf4j.LoggerFactory; -import com.google.common.collect.Lists; - import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; +import com.google.common.collect.Lists; + public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { private LogbackModuleFactory factory; @@ -56,14 +57,16 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { /** * Tests configuration of Logger factory. + * + * @throws MalformedObjectNameException */ @Test - public void test() throws InstanceAlreadyExistsException, InstanceNotFoundException { + public void test() throws InstanceAlreadyExistsException, InstanceNotFoundException, MalformedObjectNameException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), "singleton"); + ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), LogbackModuleFactory.INSTANCE_NAME); - LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameCreated, LogbackModuleMXBean.class); + LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameRetrieved, LogbackModuleMXBean.class); assertEquals(1, bean.getConsoleAppenderTO().size()); @@ -73,9 +76,9 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { transaction = configRegistryClient.createTransaction(); - nameCreated = transaction.lookupConfigBean(factory.getImplementationName(), "singleton"); + nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), "singleton"); - bean = JMX.newMXBeanProxy(platformMBeanServer, nameCreated, LogbackModuleMXBean.class); + bean = JMX.newMXBeanProxy(platformMBeanServer, nameRetrieved, LogbackModuleMXBean.class); assertEquals(1, bean.getConsoleAppenderTO().size()); assertEquals(1, bean.getRollingFileAppenderTO().size()); @@ -89,11 +92,6 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { @Test public void testAllLoggers() throws InstanceAlreadyExistsException, InstanceNotFoundException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - transaction.createModule(factory.getImplementationName(), "singleton"); - - transaction.commit(); - - transaction = configRegistryClient.createTransaction(); LogbackModuleMXBean bean = JMX.newMXBeanProxy(ManagementFactory.getPlatformMBeanServer(), transaction.lookupConfigBean("logback", "singleton"), LogbackModuleMXBean.class); @@ -103,13 +101,16 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { /** * Add new logger using FileAppender + * + * @throws MalformedObjectNameException */ @Test - public void testAddNewLogger() throws InstanceAlreadyExistsException, InstanceNotFoundException { + public void testAddNewLogger() throws InstanceAlreadyExistsException, InstanceNotFoundException, + MalformedObjectNameException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), "singleton"); - LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameCreated, LogbackModuleMXBean.class); + ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), LogbackModuleFactory.INSTANCE_NAME); + LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameRetrieved, LogbackModuleMXBean.class); assertEquals(5, bean.getLoggerTO().size()); @@ -124,8 +125,8 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { transaction.commit(); transaction = configRegistryClient.createTransaction(); - nameCreated = transaction.lookupConfigBean(factory.getImplementationName(), "singleton"); - bean = JMX.newMXBeanProxy(platformMBeanServer, nameCreated, LogbackModuleMXBean.class); + nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), "singleton"); + bean = JMX.newMXBeanProxy(platformMBeanServer, nameRetrieved, LogbackModuleMXBean.class); assertEquals(6, bean.getLoggerTO().size()); } diff --git a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java index aed3a0cc15..02cbd247a7 100644 --- a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java +++ b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java @@ -14,7 +14,9 @@ import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.EventExecutorGroup; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GlobalEventExecutor; +import io.netty.util.concurrent.ScheduledFuture; +import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; /** @@ -108,5 +110,24 @@ public final class GlobalEventExecutorModule extends this.executor.shutdown(); } + @Override + public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { + return this.executor.scheduleWithFixedDelay(command, initialDelay, delay, unit); + } + + @Override + public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { + return this.executor.schedule(command, delay, unit); + } + + @Override + public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { + return this.executor.schedule(callable, delay, unit); + } + + @Override + public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { + return this.executor.scheduleAtFixedRate(command, initialDelay, period, unit); + } } } diff --git a/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTracker.java b/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTracker.java index fcdc10f109..9356dd3752 100644 --- a/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTracker.java +++ b/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTracker.java @@ -125,7 +125,7 @@ public class ExtenderYangTracker extends BundleTracker implements YangSt // inconsistent state inconsistentBundlesToYangURLs.putAll(bundle, addedURLs); - logger.debug("Yang store is falling back on last consistent state containing {}, inconsistent yang files {}, reason {}", + logger.debug("Yang store is falling back on last consistent state containing {}, inconsistent yang files {}", consistentBundlesToYangURLs, inconsistentBundlesToYangURLs, failureReason); logger.warn("Yang store is falling back on last consistent state containing {} files, inconsistent yang files size is {}, reason {}", consistentBundlesToYangURLs.size(), inconsistentBundlesToYangURLs.size(), failureReason.toString()); diff --git a/opendaylight/containermanager/api/src/main/java/org/opendaylight/controller/containermanager/ContainerConfig.java b/opendaylight/containermanager/api/src/main/java/org/opendaylight/controller/containermanager/ContainerConfig.java index b82d2dae3c..99568dfcce 100644 --- a/opendaylight/containermanager/api/src/main/java/org/opendaylight/controller/containermanager/ContainerConfig.java +++ b/opendaylight/containermanager/api/src/main/java/org/opendaylight/controller/containermanager/ContainerConfig.java @@ -35,7 +35,7 @@ import org.opendaylight.controller.sal.utils.StatusCode; * files through java serialization API when saving to/reading from Container * Manager startup configuration file. */ -@XmlRootElement(name = "container-config") +@XmlRootElement(name = "containerConfig") @XmlAccessorType(XmlAccessType.NONE) public class ContainerConfig implements Serializable { private static final long serialVersionUID = 2L; diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index 55ab5caeeb..5b08af79f8 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -39,6 +39,11 @@ sal-common-util ${mdsal.version} + + org.opendaylight.controller + sal-netconf-connector + ${mdsal.version} + org.opendaylight.controller sal-core-api @@ -129,7 +134,11 @@ forwardingrules-manager ${mdsal.version} - + + org.opendaylight.controller.md + statistics-manager + ${mdsal.version} + org.opendaylight.controller concepts @@ -157,6 +166,31 @@ yang-jmx-generator ${config.version} + + org.opendaylight.controller + netty-event-executor-config + ${config.version} + + + org.opendaylight.controller + netty-threadgroup-config + ${config.version} + + + org.opendaylight.controller + threadpool-config-api + ${config.version} + + + org.opendaylight.controller + threadpool-config-impl + ${config.version} + + + org.opendaylight.controller + yang-store-api + ${config.version} + org.opendaylight.controller yang-store-api diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/controller.config b/opendaylight/distribution/opendaylight/src/main/resources/configuration/controller.config index fa0b5893d5..947c15b35c 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/controller.config +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/controller.config @@ -123,7 +123,5 @@ urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logg urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09 urn:opendaylight:params:xml:ns:yang:iana?module=iana&revision=2013-08-16 urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28 -http://netconfcentral.org/ns/toaster?module=toaster&revision=2009-11-20 urn:opendaylight:params:xml:ns:yang:ieee754?module=ieee754&revision=2013-08-19 -urn:opendaylight:params:xml:ns:yang:nps-concepts?module=nps-concepts&revision=2013-09-30 //END OF CONFIG diff --git a/opendaylight/md-sal/forwardingrules-manager/pom.xml b/opendaylight/md-sal/forwardingrules-manager/pom.xml index b5f540222a..597483ef65 100644 --- a/opendaylight/md-sal/forwardingrules-manager/pom.xml +++ b/opendaylight/md-sal/forwardingrules-manager/pom.xml @@ -63,6 +63,10 @@ model-flow-management 1.0-SNAPSHOT + + org.opendaylight.yangtools + yang-common + org.opendaylight.controller sal-binding-broker-impl diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FRMUtil.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FRMUtil.java index 522b09681b..ae6ce2f800 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FRMUtil.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FRMUtil.java @@ -21,6 +21,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.acti import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpSrcAction; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdAction; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanPcpAction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActions; @@ -57,7 +58,7 @@ public class FRMUtil { } - public static boolean validateMatch(NodeFlow flow) { + public static boolean validateMatch(Flow flow) { Match match = flow.getMatch(); if (match != null) { EthernetMatch ethernetmatch = match.getEthernetMatch(); @@ -198,9 +199,12 @@ public class FRMUtil { return true; } - public static boolean validateInstructions(NodeFlow flow) { + public static boolean validateInstructions(Flow flow) { List instructionsList = new ArrayList<>(); Instructions instructions = flow.getInstructions(); + if( instructions == null ) { + return false; + } instructionsList = instructions.getInstruction(); for (Instruction instruction : instructionsList) { diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FlowConsumerImpl.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FlowConsumerImpl.java index 2ffe0ecd87..9d2a6a0b11 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FlowConsumerImpl.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FlowConsumerImpl.java @@ -1,8 +1,10 @@ package org.opendaylight.controller.forwardingrulesmanager.consumer.impl; import java.util.ArrayList; +import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -20,12 +22,7 @@ import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.Data import org.opendaylight.controller.md.sal.common.api.data.DataModification; import org.opendaylight.controller.sal.common.util.Rpcs; import org.opendaylight.controller.sal.core.IContainer; -import org.opendaylight.controller.sal.utils.GlobalConstants; import org.opendaylight.controller.sal.utils.ServiceHelper; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; -import org.opendaylight.controller.switchmanager.ISwitchManager; -import org.opendaylight.controller.switchmanager.Switch; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; @@ -54,6 +51,7 @@ import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.NotificationListener; +import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -86,8 +84,7 @@ public class FlowConsumerImpl implements IForwardingRulesManager { private boolean inContainerMode; // being used by global instance only public FlowConsumerImpl() { - InstanceIdentifier path = InstanceIdentifier.builder(Flows.class).child(Flow.class) - .toInstance(); + InstanceIdentifier path = InstanceIdentifier.builder(Flows.class).toInstance(); flowService = FRMConsumerImpl.getProviderSession().getRpcService(SalFlowService.class); if (null == flowService) { @@ -116,12 +113,11 @@ public class FlowConsumerImpl implements IForwardingRulesManager { } // addFlowTest(); System.out.println("-------------------------------------------------------------------"); - allocateCaches(); commitHandler = new FlowDataCommitHandler(); FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler); clusterContainerService = (IClusterContainerServices) ServiceHelper.getGlobalInstance( IClusterContainerServices.class, this); - container = (IContainer) ServiceHelper.getGlobalInstance(IContainer.class, this); + allocateCaches(); /* * If we are not the first cluster node to come up, do not initialize * the static flow entries ordinal @@ -204,13 +200,20 @@ public class FlowConsumerImpl implements IForwardingRulesManager { System.out.println("Instruction list" + (dataObject).getInstructions().getInstruction().toString()); // updating the staticflow cache + /* + * Commented out... as in many other places... use of ClusteringServices is breaking things + * insufficient time to debug Integer ordinal = staticFlowsOrdinal.get(0); staticFlowsOrdinal.put(0, ++ordinal); staticFlows.put(ordinal, dataObject); + */ // We send flow to the sounthbound plugin flowService.addFlow(input.build()); + /* + * Commented out as this will also break due to improper use of ClusteringServices updateLocalDatabase((NodeFlow) dataObject, true); + */ } /** @@ -237,13 +240,19 @@ public class FlowConsumerImpl implements IForwardingRulesManager { System.out.println("Instruction list" + (dataObject).getInstructions().getInstruction().toString()); // updating the staticflow cache + /* + * Commented out due to problems caused by improper use of ClusteringServices Integer ordinal = staticFlowsOrdinal.get(0); staticFlowsOrdinal.put(0, ++ordinal); staticFlows.put(ordinal, dataObject); + */ // We send flow to the sounthbound plugin flowService.removeFlow(input.build()); + /* + * Commented out due to problems caused by improper use of ClusteringServices updateLocalDatabase((NodeFlow) dataObject, false); + */ } /** @@ -257,33 +266,60 @@ public class FlowConsumerImpl implements IForwardingRulesManager { UpdateFlowInputBuilder input = new UpdateFlowInputBuilder(); UpdatedFlowBuilder updatedflowbuilder = new UpdatedFlowBuilder(); updatedflowbuilder.fieldsFrom(dataObject); + input.setNode(dataObject.getNode()); input.setUpdatedFlow(updatedflowbuilder.build()); // updating the staticflow cache + /* + * Commented out due to problems caused by improper use of ClusteringServices. Integer ordinal = staticFlowsOrdinal.get(0); staticFlowsOrdinal.put(0, ++ordinal); staticFlows.put(ordinal, dataObject); + */ // We send flow to the sounthbound plugin flowService.updateFlow(input.build()); + /* + * Commented out due to problems caused by improper use of ClusteringServices. updateLocalDatabase((NodeFlow) dataObject, true); + */ } @SuppressWarnings("unchecked") private void commitToPlugin(internalTransaction transaction) { - for (Entry, Flow> entry : transaction.additions.entrySet()) { - System.out.println("Coming add cc in FlowDatacommitHandler"); - addFlow(entry.getKey(), entry.getValue()); + Set, DataObject>> createdEntries = transaction.getModification().getCreatedConfigurationData().entrySet(); + + /* + * This little dance is because updatedEntries contains both created and modified entries + * The reason I created a new HashSet is because the collections we are returned are immutable. + */ + Set, DataObject>> updatedEntries = new HashSet, DataObject>>(); + updatedEntries.addAll(transaction.getModification().getUpdatedConfigurationData().entrySet()); + updatedEntries.removeAll(createdEntries); + + Set> removeEntriesInstanceIdentifiers = transaction.getModification().getRemovedConfigurationData(); + transaction.getModification().getOriginalConfigurationData(); + for (Entry, DataObject> entry : createdEntries) { + if(entry.getValue() instanceof Flow) { + System.out.println("Coming add cc in FlowDatacommitHandler"); + addFlow(entry.getKey(), (Flow) entry.getValue()); + } } for (@SuppressWarnings("unused") - Entry, Flow> entry : transaction.updates.entrySet()) { - System.out.println("Coming update cc in FlowDatacommitHandler"); - updateFlow(entry.getKey(), entry.getValue()); + Entry, DataObject> entry : updatedEntries) { + if(entry.getValue() instanceof Flow) { + System.out.println("Coming update cc in FlowDatacommitHandler"); + updateFlow(entry.getKey(), (Flow) entry.getValue()); + } } - for (Entry, Flow> entry : transaction.removals.entrySet()) { - System.out.println("Coming remove cc in FlowDatacommitHandler"); - removeFlow(entry.getKey(), entry.getValue()); + for (InstanceIdentifier instanceId : removeEntriesInstanceIdentifiers ) { + DataObject removeValue = transaction.getModification().getOriginalConfigurationData().get(instanceId); + if(removeValue instanceof Flow) { + System.out.println("Coming remove cc in FlowDatacommitHandler"); + removeFlow(instanceId, (Flow) removeValue); + + } } } @@ -329,39 +365,42 @@ public class FlowConsumerImpl implements IForwardingRulesManager { for (Entry, DataObject> entry : puts) { // validating the DataObject - - Status status = validate(container, (NodeFlow) entry); - if (!status.isSuccess()) { - logger.warn("Invalid Configuration for flow {}. The failure is {}", entry, status.getDescription()); - String error = "Invalid Configuration (" + status.getDescription() + ")"; - logger.error(error); - return; - } - // Presence check - if (flowEntryExists((NodeFlow) entry)) { - String error = "Entry with this name on specified table already exists"; - logger.warn("Entry with this name on specified table already exists: {}", entry); - logger.error(error); - return; - } - if (originalSwView.containsKey(entry)) { - logger.warn("Operation Rejected: A flow with same match and priority exists on the target node"); - logger.trace("Aborting to install {}", entry); - continue; - } - if (!FRMUtil.validateMatch((NodeFlow) entry)) { - logger.error("Not a valid Match"); - return; - } - if (!FRMUtil.validateInstructions((NodeFlow) entry)) { - logger.error("Not a valid Instruction"); - return; - } - if (entry.getValue() instanceof Flow) { - Flow flow = (Flow) entry.getValue(); - preparePutEntry(entry.getKey(), flow); + DataObject value = entry.getValue(); + if(value instanceof Flow ) { + Flow flow = (Flow)value; + boolean status = validate(flow); + if (!status) { + return; + } + // Presence check + /* + * This is breaking due to some improper use of caches... + * + if (flowEntryExists(flow)) { + String error = "Entry with this name on specified table already exists"; + logger.warn("Entry with this name on specified table already exists: {}", entry); + logger.error(error); + return; + } + if (originalSwView.containsKey(entry)) { + logger.warn("Operation Rejected: A flow with same match and priority exists on the target node"); + logger.trace("Aborting to install {}", entry); + continue; + } + */ + if (!FRMUtil.validateMatch(flow)) { + logger.error("Not a valid Match"); + return; + } + if (!FRMUtil.validateInstructions(flow)) { + logger.error("Not a valid Instruction"); + return; + } + /* + * Commented out due to Clustering Services issues + * preparePutEntry(entry.getKey(), flow); + */ } - } // removals = modification.getRemovedConfigurationData(); @@ -398,7 +437,7 @@ public class FlowConsumerImpl implements IForwardingRulesManager { commitToPlugin(this); // We return true if internal transaction is successful. // return Rpcs.getRpcResult(true, null, Collections.emptySet()); - return Rpcs.getRpcResult(true, null, null); + return Rpcs.getRpcResult(true, null, Collections.emptySet()); } /** @@ -411,58 +450,48 @@ public class FlowConsumerImpl implements IForwardingRulesManager { // NOOP - we did not modified any internal state during // requestCommit phase // return Rpcs.getRpcResult(true, null, Collections.emptySet()); - return Rpcs.getRpcResult(true, null, null); + return Rpcs.getRpcResult(true, null, Collections.emptySet()); } - public Status validate(IContainer container, NodeFlow dataObject) { + public boolean validate(Flow flow) { + + String msg = ""; // Specific part of warn/error log - // container validation - Switch sw = null; - Node node = null; - String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container.getName(); - ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, - containerName, this); + boolean result = true; // flow Name validation - if (dataObject.getFlowName() == null || dataObject.getFlowName().trim().isEmpty() - || !dataObject.getFlowName().matches(NAMEREGEX)) { - return new Status(StatusCode.BADREQUEST, "Invalid Flow name"); + if (flow.getFlowName() == null || flow.getFlowName().trim().isEmpty() + || !flow.getFlowName().matches(NAMEREGEX)) { + msg = "Invalid Flow name"; + result = false; } // Node Validation - if (dataObject.getNode() == null) { - return new Status(StatusCode.BADREQUEST, "Node is null"); + if (result == true && flow.getNode() == null) { + msg = "Node is null"; + result = false; } - if (switchManager != null) { - for (Switch device : switchManager.getNetworkDevices()) { - node = (Node) device.getNode(); - if (device.getNode().equals(dataObject.getNode())) { - sw = device; - break; - } - } - if (sw == null) { - return new Status(StatusCode.BADREQUEST, String.format("Node %s not found", node)); - } - } else { - logger.debug("switchmanager is not set yet"); - } + // TODO: Validate we are seeking to program a flow against a valid Node - if (dataObject.getPriority() != null) { - if (dataObject.getPriority() < 0 || dataObject.getPriority() > 65535) { - return new Status(StatusCode.BADREQUEST, String.format("priority %s is not in the range 0 - 65535", - dataObject.getPriority())); + if (result == true && flow.getPriority() != null) { + if (flow.getPriority() < 0 || flow.getPriority() > 65535) { + msg = String.format("priority %s is not in the range 0 - 65535", + flow.getPriority()); + result = false; } } - - return new Status(StatusCode.SUCCESS); + if (result == false) { + logger.warn("Invalid Configuration for flow {}. The failure is {}",flow,msg); + logger.error("Invalid Configuration ({})",msg); + } + return result; } - private boolean flowEntryExists(NodeFlow config) { + private boolean flowEntryExists(Flow flow) { // Flow name has to be unique on per table id basis for (ConcurrentMap.Entry entry : originalSwView.entrySet()) { - if (entry.getValue().getFlowName().equals(config.getFlowName()) - && entry.getValue().getTableId().equals(config.getTableId())) { + if (entry.getValue().getFlowName().equals(flow.getFlowName()) + && entry.getValue().getTableId().equals(flow.getTableId())) { return true; } } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/GroupConsumerImpl.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/GroupConsumerImpl.java index 851e7d9b26..714ac89ba1 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/GroupConsumerImpl.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/GroupConsumerImpl.java @@ -2,6 +2,7 @@ package org.opendaylight.controller.forwardingrulesmanager.consumer.impl; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; @@ -33,6 +34,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.Add import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.GroupAdded; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.GroupRemoved; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.GroupUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder; + import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder; @@ -40,10 +43,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.gro import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes.GroupType; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.Meter; import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.NotificationListener; +import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -225,7 +230,7 @@ public class GroupConsumerImpl implements IForwardingRulesManager { return new Status(StatusCode.BADREQUEST, "Group Name is invalid"); } - returnResult = doesGroupEntryExists(group.getKey(), groupName, containerName); + /* returnResult = doesGroupEntryExists(group.getKey(), groupName, containerName); if (FRMUtil.operation.ADD == operation && returnResult) { logger.error("Record with same Group Name exists"); @@ -233,7 +238,7 @@ public class GroupConsumerImpl implements IForwardingRulesManager { } else if (!returnResult) { logger.error("Group record does not exist"); return new Status(StatusCode.BADREQUEST, "Group record does not exist"); - } + }*/ if (!(group.getGroupType().getIntValue() >= GroupType.GroupAll.getIntValue() && group.getGroupType() .getIntValue() <= GroupType.GroupFf.getIntValue())) { @@ -259,7 +264,7 @@ public class GroupConsumerImpl implements IForwardingRulesManager { } - private boolean doesGroupEntryExists(GroupKey key, String groupName, String containerName) { + /* private boolean doesGroupEntryExists(GroupKey key, String groupName, String containerName) { if (!originalSwGroupView.containsKey(key)) { return false; } @@ -271,8 +276,8 @@ public class GroupConsumerImpl implements IForwardingRulesManager { } } } - return false; - } + return true; + }*/ /** * Update Group entries to the southbound plugin/inventory and our internal @@ -292,11 +297,11 @@ public class GroupConsumerImpl implements IForwardingRulesManager { return groupOperationStatus; } - if (originalSwGroupView.containsKey(groupKey)) { + /*if (originalSwGroupView.containsKey(groupKey)) { originalSwGroupView.remove(groupKey); originalSwGroupView.put(groupKey, groupUpdateDataObject); } - +*/ if (groupUpdateDataObject.isInstall()) { UpdateGroupInputBuilder groupData = new UpdateGroupInputBuilder(); updateGroupBuilder = new UpdatedGroupBuilder(); @@ -304,10 +309,10 @@ public class GroupConsumerImpl implements IForwardingRulesManager { groupData.setUpdatedGroup(updateGroupBuilder.build()); // TODO how to get original group and modified group. - if (installedSwGroupView.containsKey(groupKey)) { + /* if (installedSwGroupView.containsKey(groupKey)) { installedSwGroupView.remove(groupKey); installedSwGroupView.put(groupKey, groupUpdateDataObject); - } + }*/ groupService.updateGroup(groupData.build()); } @@ -330,7 +335,7 @@ public class GroupConsumerImpl implements IForwardingRulesManager { return groupOperationStatus; } - originalSwGroupView.put(groupKey, groupAddDataObject); + //originalSwGroupView.put(groupKey, groupAddDataObject); if (groupAddDataObject.isInstall()) { AddGroupInputBuilder groupData = new AddGroupInputBuilder(); @@ -339,19 +344,49 @@ public class GroupConsumerImpl implements IForwardingRulesManager { groupData.setGroupId(groupAddDataObject.getGroupId()); groupData.setGroupType(groupAddDataObject.getGroupType()); groupData.setNode(groupAddDataObject.getNode()); - installedSwGroupView.put(groupKey, groupAddDataObject); + // installedSwGroupView.put(groupKey, groupAddDataObject); groupService.addGroup(groupData.build()); } return groupOperationStatus; } - private RpcResult commitToPlugin(internalTransaction transaction) { + /** + * Remove Group to the southbound plugin and our internal database + * + * @param path + * @param dataObject + */ + private Status removeGroup(InstanceIdentifier path, Group groupRemoveDataObject) { + GroupKey groupKey = groupRemoveDataObject.getKey(); + Status groupOperationStatus = validateGroup(groupRemoveDataObject, FRMUtil.operation.ADD); + + if (!groupOperationStatus.isSuccess()) { + logger.error("Group data object validation failed %s" + groupRemoveDataObject.getGroupName()); + return groupOperationStatus; + } + //originalSwGroupView.put(groupKey, groupAddDataObject); + + if (groupRemoveDataObject.isInstall()) { + RemoveGroupInputBuilder groupData = new RemoveGroupInputBuilder(); + groupData.setBuckets(groupRemoveDataObject.getBuckets()); + groupData.setContainerName(groupRemoveDataObject.getContainerName()); + groupData.setGroupId(groupRemoveDataObject.getGroupId()); + groupData.setGroupType(groupRemoveDataObject.getGroupType()); + groupData.setNode(groupRemoveDataObject.getNode()); + // installedSwGroupView.put(groupKey, groupAddDataObject); + groupService.removeGroup(groupData.build()); + } + + return groupOperationStatus; + } + + private RpcResult commitToPlugin(InternalTransaction transaction) { for (Entry, Group> entry : transaction.additions.entrySet()) { if (!addGroup(entry.getKey(), entry.getValue()).isSuccess()) { transaction.additions.remove(entry.getKey()); - return Rpcs.getRpcResult(false, null, null); + return Rpcs.getRpcResult(false, null, Collections.emptySet()); } } @@ -359,12 +394,18 @@ public class GroupConsumerImpl implements IForwardingRulesManager { if (!updateGroup(entry.getKey(), entry.getValue()).isSuccess()) { transaction.updates.remove(entry.getKey()); - return Rpcs.getRpcResult(false, null, null); + return Rpcs.getRpcResult(false, null, Collections.emptySet()); } } - for (InstanceIdentifier removal : transaction.removals) { - // removeFlow(removal); + for (InstanceIdentifier groupId : transaction.removals) { + DataObject removeValue = transaction.getModification().getOriginalConfigurationData().get(groupId); + + if(removeValue instanceof Group) { + if(!removeGroup(groupId, (Group)removeValue).isSuccess()) { + return Rpcs.getRpcResult(false, null, Collections.emptySet()); + } + } } return Rpcs.getRpcResult(true, null, null); @@ -372,19 +413,18 @@ public class GroupConsumerImpl implements IForwardingRulesManager { private final class GroupDataCommitHandler implements DataCommitHandler, DataObject> { - @SuppressWarnings("unchecked") @Override public DataCommitTransaction, DataObject> requestCommit( DataModification, DataObject> modification) { // We should verify transaction System.out.println("Coming in GroupDatacommitHandler"); - internalTransaction transaction = new internalTransaction(modification); + InternalTransaction transaction = new InternalTransaction(modification); transaction.prepareUpdate(); return transaction; } } - private final class internalTransaction implements DataCommitTransaction, DataObject> { + private final class InternalTransaction implements DataCommitTransaction, DataObject> { private final DataModification, DataObject> modification; @@ -393,7 +433,7 @@ public class GroupConsumerImpl implements IForwardingRulesManager { return modification; } - public internalTransaction(DataModification, DataObject> modification) { + public InternalTransaction(DataModification, DataObject> modification) { this.modification = modification; } @@ -407,33 +447,31 @@ public class GroupConsumerImpl implements IForwardingRulesManager { * */ void prepareUpdate() { - - Set, DataObject>> puts = modification.getUpdatedConfigurationData().entrySet(); - for (Entry, DataObject> entry : puts) { + + Set, DataObject>> groupAdded = modification.getCreatedConfigurationData().entrySet(); + for (Entry, DataObject> entry : groupAdded) { + if (entry.getValue() instanceof Group) { + Group group = (Group) entry.getValue(); + additions.put(entry.getKey(), group); + } + + } + + Set, DataObject>> groupUpdate = modification.getUpdatedConfigurationData().entrySet(); + for (Entry, DataObject> entry : groupUpdate) { if (entry.getValue() instanceof Group) { Group group = (Group) entry.getValue(); - preparePutEntry(entry.getKey(), group); + ///will be fixed once getUpdatedConfigurationData returns only updated data not created data with it. + if (additions.containsKey(entry.getKey())) { + updates.put(entry.getKey(), group); + } } } removals = modification.getRemovedConfigurationData(); } - - private void preparePutEntry(InstanceIdentifier key, Group group) { - - Group original = originalSwGroupView.get(key); - if (original != null) { - // It is update for us - - updates.put(key, group); - } else { - // It is addition for us - - additions.put(key, group); - } - } - + /** * We are OK to go with execution of plan * @@ -457,7 +495,7 @@ public class GroupConsumerImpl implements IForwardingRulesManager { // NOOP - we did not modified any internal state during // requestCommit phase // return Rpcs.getRpcResult(true, null, Collections.emptySet()); - return Rpcs.getRpcResult(true, null, null); + return Rpcs.getRpcResult(true, null, Collections.emptySet()); } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/MeterConsumerImpl.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/MeterConsumerImpl.java index bd0ceb3fea..483b9a4719 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/MeterConsumerImpl.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/MeterConsumerImpl.java @@ -2,6 +2,7 @@ package org.opendaylight.controller.forwardingrulesmanager.consumer.impl; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; @@ -33,6 +34,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.Add import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterAdded; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterRemoved; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder; @@ -45,6 +47,7 @@ import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.NotificationListener; +import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,13 +60,17 @@ public class MeterConsumerImpl implements IForwardingRulesManager { private MeterDataCommitHandler commitHandler; private ConcurrentMap originalSwMeterView; + @SuppressWarnings("unused") private ConcurrentMap installedSwMeterView; - + @SuppressWarnings("unused") private ConcurrentMap> nodeMeters; + @SuppressWarnings("unused") private ConcurrentMap inactiveMeters; + @SuppressWarnings("unused") + private IContainer container; private IClusterContainerServices clusterMeterContainerService = null; - private IContainer container; + public MeterConsumerImpl() { InstanceIdentifier path = InstanceIdentifier.builder(Meters.class).child(Meter.class) @@ -218,11 +225,11 @@ public class MeterConsumerImpl implements IForwardingRulesManager { meterBuilder.setMeterBandHeaders(meterAddDataObject.getMeterBandHeaders()); meterBuilder.setMeterId(meterAddDataObject.getMeterId()); meterBuilder.setNode(meterAddDataObject.getNode()); - originalSwMeterView.put(meterKey, meterAddDataObject); + // originalSwMeterView.put(meterKey, meterAddDataObject); meterService.addMeter(meterBuilder.build()); } - originalSwMeterView.put(meterKey, meterAddDataObject); + // originalSwMeterView.put(meterKey, meterAddDataObject); } else { return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed"); } @@ -243,10 +250,10 @@ public class MeterConsumerImpl implements IForwardingRulesManager { if (null != meterKey && validateMeter(meterUpdateDataObject, FRMUtil.operation.UPDATE).isSuccess()) { - if (originalSwMeterView.containsKey(meterKey)) { + /* if (originalSwMeterView.containsKey(meterKey)) { originalSwMeterView.remove(meterKey); originalSwMeterView.put(meterKey, meterUpdateDataObject); - } + }*/ if (meterUpdateDataObject.isInstall()) { UpdateMeterInputBuilder updateMeterInputBuilder = new UpdateMeterInputBuilder(); @@ -254,10 +261,10 @@ public class MeterConsumerImpl implements IForwardingRulesManager { updateMeterBuilder.fieldsFrom(meterUpdateDataObject); updateMeterInputBuilder.setUpdatedMeter(updateMeterBuilder.build()); - if (installedSwMeterView.containsKey(meterKey)) { + /* if (installedSwMeterView.containsKey(meterKey)) { installedSwMeterView.remove(meterKey); installedSwMeterView.put(meterKey, meterUpdateDataObject); - } + }*/ meterService.updateMeter(updateMeterInputBuilder.build()); } @@ -276,18 +283,23 @@ public class MeterConsumerImpl implements IForwardingRulesManager { * * @param dataObject */ - private Status RemoveMeter(InstanceIdentifier path, Meter meterUpdateDataObject) { - MeterKey meterKey = meterUpdateDataObject.getKey(); - - if (null != meterKey && validateMeter(meterUpdateDataObject, FRMUtil.operation.ADD).isSuccess()) { - if (meterUpdateDataObject.isInstall()) { - UpdateMeterInputBuilder updateMeterBuilder = new UpdateMeterInputBuilder(); - - installedSwMeterView.put(meterKey, meterUpdateDataObject); - meterService.updateMeter(updateMeterBuilder.build()); + private Status removeMeter(InstanceIdentifier path, Meter meterRemoveDataObject) { + MeterKey meterKey = meterRemoveDataObject.getKey(); + + if (null != meterKey && validateMeter(meterRemoveDataObject, FRMUtil.operation.DELETE).isSuccess()) { + if (meterRemoveDataObject.isInstall()) { + RemoveMeterInputBuilder meterBuilder = new RemoveMeterInputBuilder(); + meterBuilder.setContainerName(meterRemoveDataObject.getContainerName()); + meterBuilder.setNode(meterRemoveDataObject.getNode()); + meterBuilder.setFlags(meterRemoveDataObject.getFlags()); + meterBuilder.setMeterBandHeaders(meterRemoveDataObject.getMeterBandHeaders()); + meterBuilder.setMeterId(meterRemoveDataObject.getMeterId()); + meterBuilder.setNode(meterRemoveDataObject.getNode()); + // originalSwMeterView.put(meterKey, meterAddDataObject); + meterService.removeMeter(meterBuilder.build()); } - originalSwMeterView.put(meterKey, meterUpdateDataObject); + // originalSwMeterView.put(meterKey, meterAddDataObject); } else { return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed"); } @@ -299,7 +311,6 @@ public class MeterConsumerImpl implements IForwardingRulesManager { String containerName; String meterName; Status returnStatus = null; - boolean returnResult; if (null != meter) { containerName = meter.getContainerName(); @@ -319,7 +330,7 @@ public class MeterConsumerImpl implements IForwardingRulesManager { return returnStatus; } - returnResult = doesMeterEntryExists(meter.getKey(), meterName, containerName); + /* returnResult = doesMeterEntryExists(meter.getKey(), meterName, containerName); if (FRMUtil.operation.ADD == operation && returnResult) { logger.error("Record with same Meter Name exists"); @@ -329,7 +340,7 @@ public class MeterConsumerImpl implements IForwardingRulesManager { logger.error("Group record does not exist"); returnStatus = new Status(StatusCode.BADREQUEST, "Meter record does not exist"); return returnStatus; - } + }*/ for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) { if (!meter.getFlags().isMeterBurst()) { @@ -367,7 +378,7 @@ public class MeterConsumerImpl implements IForwardingRulesManager { return new Status(StatusCode.SUCCESS); } - private boolean doesMeterEntryExists(MeterKey key, String meterName, String containerName) { + /*private boolean doesMeterEntryExists(MeterKey key, String meterName, String containerName) { if (!originalSwMeterView.containsKey(key)) { return false; } @@ -380,34 +391,9 @@ public class MeterConsumerImpl implements IForwardingRulesManager { } } return false; - } - - private RpcResult commitToPlugin(internalTransaction transaction) { - for (Entry, Meter> entry : transaction.additions.entrySet()) { - - if (!addMeter(entry.getKey(), entry.getValue()).isSuccess()) { - return Rpcs.getRpcResult(false, null, null); - } - } - for (@SuppressWarnings("unused") - Entry, Meter> entry : transaction.updates.entrySet()) { - - if (!updateMeter(entry.getKey(), entry.getValue()).isSuccess()) { - return Rpcs.getRpcResult(false, null, null); - } - } - - for (InstanceIdentifier removal : transaction.removals) { - /* - * if (!removeMeter(entry.getKey(),entry.getValue()).isSuccess()) { - * return Rpcs.getRpcResult(false, null, null); } - */ - } - - return Rpcs.getRpcResult(true, null, null); - } + }*/ - private final class internalTransaction implements DataCommitTransaction, DataObject> { + private final class InternalTransaction implements DataCommitTransaction, DataObject> { private final DataModification, DataObject> modification; @@ -416,7 +402,7 @@ public class MeterConsumerImpl implements IForwardingRulesManager { return modification; } - public internalTransaction(DataModification, DataObject> modification) { + public InternalTransaction(DataModification, DataObject> modification) { this.modification = modification; } @@ -430,33 +416,30 @@ public class MeterConsumerImpl implements IForwardingRulesManager { * */ void prepareUpdate() { - - Set, DataObject>> puts = modification.getUpdatedConfigurationData().entrySet(); - for (Entry, DataObject> entry : puts) { + + Set, DataObject>> addMeter = modification.getCreatedConfigurationData().entrySet(); + for (Entry, DataObject> entry : addMeter) { if (entry.getValue() instanceof Meter) { - Meter Meter = (Meter) entry.getValue(); - preparePutEntry(entry.getKey(), Meter); + Meter meter = (Meter) entry.getValue(); + additions.put(entry.getKey(), meter); } } + + Set, DataObject>> updateMeter = modification.getUpdatedConfigurationData().entrySet(); + for (Entry, DataObject> entry : updateMeter) { + if (entry.getValue() instanceof Meter) { + Meter meter = (Meter) entry.getValue(); + ///will be fixed once getUpdatedConfigurationData returns only updated data not created data with it. + if (!additions.containsKey(entry.getKey())) { + updates.put(entry.getKey(), meter); + } + } + } removals = modification.getRemovedConfigurationData(); } - private void preparePutEntry(InstanceIdentifier key, Meter meter) { - - Meter original = originalSwMeterView.get(key); - if (original != null) { - // It is update for us - - updates.put(key, meter); - } else { - // It is addition for us - - additions.put(key, meter); - } - } - /** * We are OK to go with execution of plan * @@ -480,10 +463,37 @@ public class MeterConsumerImpl implements IForwardingRulesManager { // NOOP - we did not modified any internal state during // requestCommit phase // return Rpcs.getRpcResult(true, null, Collections.emptySet()); - return Rpcs.getRpcResult(true, null, null); + return Rpcs.getRpcResult(true, null, Collections.emptySet()); + + } + + } + + private RpcResult commitToPlugin(InternalTransaction transaction) { + for (Entry, Meter> entry : transaction.additions.entrySet()) { + + if (!addMeter(entry.getKey(), entry.getValue()).isSuccess()) { + return Rpcs.getRpcResult(false, null, Collections.emptySet()); + } + } + for (Entry, Meter> entry : transaction.updates.entrySet()) { + + if (!updateMeter(entry.getKey(), entry.getValue()).isSuccess()) { + return Rpcs.getRpcResult(false, null, Collections.emptySet()); + } + } + for (InstanceIdentifier meterId : transaction.removals) { + DataObject removeValue = transaction.getModification().getOriginalConfigurationData().get(meterId); + + if(removeValue instanceof Meter) { + if(!removeMeter(meterId, (Meter)removeValue).isSuccess()) { + return Rpcs.getRpcResult(false, null, Collections.emptySet()); + } + } } + return Rpcs.getRpcResult(true, null, Collections.emptySet()); } private final class MeterDataCommitHandler implements DataCommitHandler, DataObject> { @@ -492,7 +502,7 @@ public class MeterConsumerImpl implements IForwardingRulesManager { DataModification, DataObject> modification) { // We should verify transaction System.out.println("Coming in MeterDataCommitHandler"); - internalTransaction transaction = new internalTransaction(modification); + InternalTransaction transaction = new InternalTransaction(modification); transaction.prepareUpdate(); return transaction; } diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/flow-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/flow-types.yang index 67c6933cc7..29ea8ddf18 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/flow-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/flow-types.yang @@ -4,7 +4,7 @@ module opendaylight-flow-types { import ietf-inet-types {prefix inet; revision-date "2010-09-24";} import ietf-yang-types {prefix yang; revision-date "2010-09-24";} - import opendaylight-match-types {prefix match; revision-date 2013-10-26";} + import opendaylight-match-types {prefix match; revision-date "2013-10-26";} import opendaylight-action-types {prefix action;} revision "2013-10-26" { diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/queue-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/queue-types.yang new file mode 100644 index 0000000000..57a92378c0 --- /dev/null +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/queue-types.yang @@ -0,0 +1,77 @@ +module opendaylight-queue-types { + namespace "urn:opendaylight:flow:types:queue"; + prefix queue-types; + + import ietf-inet-types {prefix inet; revision-date "2010-09-24";} + import ietf-yang-types {prefix yang; revision-date "2010-09-24";} + + revision "2013-09-25" { + description "Initial revision of Queue Inventory model"; + } + + typedef queue-properties { + type enumeration { + enum min_rate; + enum max_rate; + } + } + + + grouping common-queue { + + leaf property { + type uint16; + description "One of OFPQT_."; + } + + } + + + grouping queue-prop-min-rate { + + uses common-queue; + + leaf rate { + type uint16; + description "OFPQT_MIN, len: 16"; + } + + } + + + + grouping queue-prop-max-rate { + + uses common-queue; + + leaf rate { + type uint16; + description "OFPQT_MAX, len: 16"; + } + + } + grouping queue-packet { + + + leaf queue-id { + type uint32; + description "id for the specific queue."; + } + + leaf port { + type uint32; + description "Port this queue is attached to."; + } + uses common-queue; + } + + grouping queue-config-request + { + leaf port { + type uint32; + description "Port to be queried."; + } + + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/table-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/table-types.yang index 52629516f3..3774f950fc 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/table-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/table-types.yang @@ -4,7 +4,7 @@ module opendaylight-table-types { import ietf-inet-types {prefix inet; revision-date "2010-09-24";} import ietf-yang-types {prefix yang; revision-date "2010-09-24";} - import opendaylight-flow-types {prefix flow;revision-date 2013-10-26";} + import opendaylight-flow-types {prefix flow;revision-date "2013-10-26";} import opendaylight-action-types {prefix action;} revision "2013-10-26" { @@ -325,4 +325,4 @@ module opendaylight-table-types { } } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/model/model-flow-management/src/main/yang/queue-config.yang b/opendaylight/md-sal/model/model-flow-management/src/main/yang/queue-config.yang new file mode 100644 index 0000000000..b362e3f080 --- /dev/null +++ b/opendaylight/md-sal/model/model-flow-management/src/main/yang/queue-config.yang @@ -0,0 +1,34 @@ +module queue-management { + namespace "urn:opendaylight:queue:config"; + prefix queue-cfg; + + import yang-ext {prefix ext; revision-date "2013-07-09";} + import opendaylight-inventory {prefix inv;revision-date "2013-08-19";} + + import opendaylight-queue-types {prefix queue; revision-date "2013-09-25";} + + + revision "2013-10-24" { + description "Initial revision of queue service"; + } + + grouping queue-entry { + leaf node { + type inv:node-connector-ref; + + } + uses queue:queue-config-request; + } + + container queues { + list queue { + key "id node"; + + leaf id { + type uint32; + } + + uses queue-entry; + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/group-service.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/group-service.yang index bb01035328..b21423b7d4 100644 --- a/opendaylight/md-sal/model/model-flow-service/src/main/yang/group-service.yang +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/group-service.yang @@ -41,7 +41,7 @@ module sal-group { rpc remove-group { input { - uses group-update; + uses node-group; uses tr:transaction-aware; } output { diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/port-service.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/port-service.yang index 9588652a1c..d49675ad39 100644 --- a/opendaylight/md-sal/model/model-flow-service/src/main/yang/port-service.yang +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/port-service.yang @@ -5,6 +5,7 @@ module sal-port { import yang-ext {prefix ext; revision-date "2013-07-09";} import opendaylight-inventory {prefix inv;revision-date "2013-08-19";} import opendaylight-port-types {prefix port-type;revision-date "2013-09-25";} + import flow-capable-transaction {prefix tr;} revision "2013-11-07" { description "Initial revision of port service"; @@ -31,6 +32,10 @@ module sal-port { rpc update-port { input { uses port-update; + uses tr:transaction-aware; + } + output { + uses tr:transaction-aware; } } diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/queue-service.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/queue-service.yang new file mode 100644 index 0000000000..bf79cbf635 --- /dev/null +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/queue-service.yang @@ -0,0 +1,29 @@ +module sal-queue { + namespace "urn:opendaylight:queue:service"; + prefix queue; + + import yang-ext {prefix ext; revision-date "2013-07-09";} + import opendaylight-inventory {prefix inv; revision-date "2013-08-19";} + import opendaylight-queue-types {prefix queue-type; revision-date "2013-09-25";} + + revision "2013-11-07" { + description "Initial revision of queue service"; + } + + grouping node-queue { + uses "inv:node-context-ref"; + + uses queue-type:queue-packet; + } + + + rpc get-queue { + output { + uses queue-type:queue-packet; + } + } + + notification queue-get-config-reply { + uses node-queue; + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/model/pom.xml b/opendaylight/md-sal/model/pom.xml index eccb691fa7..34ad23844f 100644 --- a/opendaylight/md-sal/model/pom.xml +++ b/opendaylight/md-sal/model/pom.xml @@ -63,6 +63,10 @@ target/generated-sources/sal + + org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl + target/site/restconf + true diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index bdbcce0950..94c31dd041 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -40,7 +40,8 @@ sal-connector-api sal-rest-connector - + sal-netconf-connector + clustered-data-store/implementation diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend index 0ddc2c88c8..ec69fd3b68 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend @@ -33,6 +33,8 @@ import org.opendaylight.yangtools.binding.generator.util.Types import org.osgi.framework.BundleContext import java.util.Hashtable import org.osgi.framework.ServiceRegistration +import org.opendaylight.controller.sal.binding.impl.connect.dom.DeserializationException +import java.util.concurrent.Callable class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable { @@ -59,7 +61,7 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer val promisedTypeDefinitions = HashMultimap.>create; val promisedSchemas = HashMultimap.>create; - + ServiceRegistration listenerRegistration override onGlobalContextUpdated(SchemaContext arg0) { @@ -79,7 +81,6 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer val context = entry.value; updateBindingFor(context.childNodes, schemaContext); updateBindingFor(context.cases, schemaContext); - val typedefs = context.typedefs; for (typedef : typedefs.values) { @@ -89,7 +90,7 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer for (augmentation : augmentations) { binding.typeToDefinition.put(augmentation, augmentation); } - + binding.typeToAugmentation.putAll(context.typeToAugmentation); } } @@ -127,22 +128,36 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer } override dataObjectFromDataDom(InstanceIdentifier path, CompositeNode node) { - if (node == null) { - return null; - } - val targetType = path.targetType - val transformer = registry.getCodecForDataObject(targetType); - val ret = transformer.deserialize(node)?.value as DataObject; - return ret; + return tryDeserialization[ | + if (node == null) { + return null; + } + val targetType = path.targetType + val transformer = registry.getCodecForDataObject(targetType); + val ret = transformer.deserialize(node)?.value as DataObject; + return ret; + ] } - + override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) { - return registry.instanceIdentifierCodec.deserialize(entry); + return tryDeserialization[ | + registry.instanceIdentifierCodec.deserialize(entry); + ] + } + + private static def T tryDeserialization(Callable deserializationBlock) throws DeserializationException { + try { + deserializationBlock.call() + } catch (Exception e) { + // FIXME: Make this block providing more information. + throw new DeserializationException(e); + } } private def void updateBindingFor(Map map, SchemaContext module) { for (entry : map.entrySet) { val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key); + //LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName) if (schemaNode != null) { typeToSchemaNode.put(entry.value, schemaNode); @@ -162,8 +177,8 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer binding.typeToDefinition = typeToDefinition binding.typeToSchemaNode = typeToSchemaNode binding.typeDefinitions = typeDefinitions - if(ctx !== null) { - listenerRegistration = ctx.registerService(SchemaServiceListener,this,new Hashtable()); + if (ctx !== null) { + listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable()); } } @@ -217,9 +232,9 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer } promisedSchemas.removeAll(builder); } - + override close() throws Exception { listenerRegistration?.unregister(); } - + } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java index ccd6079cc9..7a72afc885 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java @@ -32,7 +32,7 @@ import org.slf4j.LoggerFactory; public class BindingIndependentDataServiceConnector implements // RuntimeDataProvider, // - Provider { + Provider, AutoCloseable { private final Logger LOG = LoggerFactory.getLogger(BindingIndependentDataServiceConnector.class); @@ -59,16 +59,24 @@ public class BindingIndependentDataServiceConnector implements // @Override public DataObject readOperationalData(InstanceIdentifier path) { - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path); - CompositeNode result = biDataService.readOperationalData(biPath); - return mappingService.dataObjectFromDataDom(path, result); + try { + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path); + CompositeNode result = biDataService.readOperationalData(biPath); + return mappingService.dataObjectFromDataDom(path, result); + } catch (DeserializationException e) { + throw new IllegalStateException(e); + } } @Override public DataObject readConfigurationData(InstanceIdentifier path) { - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path); - CompositeNode result = biDataService.readConfigurationData(biPath); - return mappingService.dataObjectFromDataDom(path, result); + try { + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path); + CompositeNode result = biDataService.readConfigurationData(biPath); + return mappingService.dataObjectFromDataDom(path, result); + } catch (DeserializationException e) { + throw new IllegalStateException(e); + } } private DataModificationTransaction createBindingToDomTransaction( @@ -103,23 +111,42 @@ public class BindingIndependentDataServiceConnector implements // .beginTransaction(); for (Entry entry : source .getUpdatedConfigurationData().entrySet()) { - InstanceIdentifier baKey = mappingService.fromDataDom(entry.getKey()); - DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue()); - target.putConfigurationData(baKey, baData); + try { + InstanceIdentifier baKey = mappingService.fromDataDom(entry.getKey()); + DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue()); + target.putConfigurationData(baKey, baData); + } catch (DeserializationException e) { + LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry.getKey(), e); + } } for (Entry entry : source .getUpdatedOperationalData().entrySet()) { - InstanceIdentifier baKey = mappingService.fromDataDom(entry.getKey()); - DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue()); - target.putOperationalData(baKey, baData); + try { + + InstanceIdentifier baKey = mappingService.fromDataDom(entry.getKey()); + DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue()); + target.putOperationalData(baKey, baData); + } catch (DeserializationException e) { + LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry.getKey(), e); + } } for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) { - InstanceIdentifier baEntry = mappingService.fromDataDom(entry); - target.removeConfigurationData(baEntry); + try { + + InstanceIdentifier baEntry = mappingService.fromDataDom(entry); + target.removeConfigurationData(baEntry); + } catch (DeserializationException e) { + LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry, e); + } } for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) { - InstanceIdentifier baEntry = mappingService.fromDataDom(entry); - target.removeOperationalData(baEntry); + try { + + InstanceIdentifier baEntry = mappingService.fromDataDom(entry); + target.removeOperationalData(baEntry); + } catch (DeserializationException e) { + LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry, e); + } } return target; } @@ -162,6 +189,18 @@ public class BindingIndependentDataServiceConnector implements // start(); } + @Override + public void close() throws Exception { + + if (baCommitHandlerRegistration != null) { + baCommitHandlerRegistration.close(); + } + if (biCommitHandlerRegistration != null) { + biCommitHandlerRegistration.close(); + } + + } + private class DomToBindingTransaction implements DataCommitTransaction { @@ -271,10 +310,11 @@ public class BindingIndependentDataServiceConnector implements // @Override public void onRegister(DataCommitHandlerRegistration, DataObject> registration) { - - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration.getPath()); + + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration + .getPath()); // FIXME: do registration based on only active commit handlers. - + } @Override diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java index 9e175b8cb0..b1983fe224 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java @@ -16,8 +16,8 @@ public interface BindingIndependentMappingService { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(InstanceIdentifier path); - DataObject dataObjectFromDataDom(InstanceIdentifier path, CompositeNode result); + DataObject dataObjectFromDataDom(InstanceIdentifier path, CompositeNode result) throws DeserializationException; - InstanceIdentifier fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry); + InstanceIdentifier fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) throws DeserializationException; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/DeserializationException.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/DeserializationException.java new file mode 100644 index 0000000000..9331899686 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/DeserializationException.java @@ -0,0 +1,24 @@ +package org.opendaylight.controller.sal.binding.impl.connect.dom; + +public class DeserializationException extends Exception { + + public DeserializationException() { + } + + public DeserializationException(String message) { + super(message); + } + + public DeserializationException(Throwable cause) { + super(cause); + } + + public DeserializationException(String message, Throwable cause) { + super(message, cause); + } + + public DeserializationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java index 5b35861e9d..9f3a6e8652 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java @@ -8,6 +8,7 @@ import java.util.Set; import javassist.ClassPool; +import org.junit.After; import org.junit.Before; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl; @@ -15,78 +16,96 @@ import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndepende import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService; import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl; import org.opendaylight.controller.sal.core.api.data.DataBrokerService; +import org.opendaylight.controller.sal.core.api.data.DataStore; +import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper; import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore; +import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; import org.reflections.Reflections; import org.reflections.scanners.ResourcesScanner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.Predicate; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; -public abstract class AbstractDataServiceTest { +public abstract class AbstractDataServiceTest { + private static Logger log = LoggerFactory.getLogger(AbstractDataServiceTest.class); + protected org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService; protected DataProviderService baDataService; - + /** * Workaround for JUNIT sharing classloaders * */ protected static final ClassPool POOL = new ClassPool(); - + protected RuntimeGeneratedMappingServiceImpl mappingServiceImpl; protected BindingIndependentMappingService mappingService; protected DataBrokerImpl baDataImpl; protected org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl; protected ListeningExecutorService executor; protected BindingIndependentDataServiceConnector connectorServiceImpl; - protected HashMapDataStore dataStore; - - + protected HashMapDataStore rawDataStore; + private SchemaAwareDataStoreAdapter schemaAwareDataStore; + private DataStoreStatsWrapper dataStoreStats; + + protected DataStore dataStore; + @Before public void setUp() { executor = MoreExecutors.sameThreadExecutor(); baDataImpl = new DataBrokerImpl(); baDataService = baDataImpl; baDataImpl.setExecutor(executor); - + biDataImpl = new org.opendaylight.controller.sal.dom.broker.DataBrokerImpl(); - biDataService = biDataImpl; + biDataService = biDataImpl; biDataImpl.setExecutor(executor); - - dataStore = new HashMapDataStore(); - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier treeRoot = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder().toInstance(); + + rawDataStore = new HashMapDataStore(); + schemaAwareDataStore = new SchemaAwareDataStoreAdapter(); + schemaAwareDataStore.changeDelegate(rawDataStore); + dataStoreStats = new DataStoreStatsWrapper(schemaAwareDataStore); + dataStore = dataStoreStats; + + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier treeRoot = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier + .builder().toInstance(); biDataImpl.registerConfigurationReader(treeRoot, dataStore); biDataImpl.registerOperationalReader(treeRoot, dataStore); biDataImpl.registerCommitHandler(treeRoot, dataStore); - + mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl(); mappingServiceImpl.setPool(POOL); mappingService = mappingServiceImpl; File pathname = new File("target/gen-classes-debug"); - //System.out.println("Generated classes are captured in " + pathname.getAbsolutePath()); + // System.out.println("Generated classes are captured in " + + // pathname.getAbsolutePath()); mappingServiceImpl.start(null); - //mappingServiceImpl.getBinding().setClassFileCapturePath(pathname); - + // mappingServiceImpl.getBinding().setClassFileCapturePath(pathname); + connectorServiceImpl = new BindingIndependentDataServiceConnector(); connectorServiceImpl.setBaDataService(baDataService); connectorServiceImpl.setBiDataService(biDataService); connectorServiceImpl.setMappingService(mappingServiceImpl); connectorServiceImpl.start(); - - String[] yangFiles= getModelFilenames(); - if(yangFiles != null && yangFiles.length > 0) { - mappingServiceImpl.onGlobalContextUpdated(getContext(yangFiles)); + + String[] yangFiles = getModelFilenames(); + if (yangFiles != null && yangFiles.length > 0) { + SchemaContext context = getContext(yangFiles); + mappingServiceImpl.onGlobalContextUpdated(context); + schemaAwareDataStore.onGlobalContextUpdated(context); } } - - protected String[] getModelFilenames() { + protected String[] getModelFilenames() { return getAllModelFilenames(); } - + public static String[] getAllModelFilenames() { Predicate predicate = new Predicate() { @Override @@ -94,11 +113,11 @@ public abstract class AbstractDataServiceTest { return input.endsWith(".yang"); } }; - Reflections reflection= new Reflections("META-INF.yang", new ResourcesScanner()); + Reflections reflection = new Reflections("META-INF.yang", new ResourcesScanner()); Set result = reflection.getResources(predicate); return (String[]) result.toArray(new String[result.size()]); } - + public static SchemaContext getContext(String[] yangFiles) { ClassLoader loader = AbstractDataServiceTest.class.getClassLoader(); @@ -114,4 +133,21 @@ public abstract class AbstractDataServiceTest { Set modules = parser.parseYangModelsFromStreams(streams); return parser.resolveSchemaContext(modules); } + + @After + public void afterTest() { + + log.info("BIDataStore Statistics: Configuration Read Count: {} TotalTime: {} ns AverageTime (ns): {} ns", + dataStoreStats.getConfigurationReadCount(), dataStoreStats.getConfigurationReadTotalTime(), + dataStoreStats.getConfigurationReadAverageTime()); + + log.info("BIDataStore Statistics: Operational Read Count: {} TotalTime: {} ns AverageTime (ns): {} ns", + dataStoreStats.getOperationalReadCount(), dataStoreStats.getOperationalReadTotalTime(), + dataStoreStats.getOperationalReadAverageTime()); + + log.info("BIDataStore Statistics: Request Commit Count: {} TotalTime: {} ns AverageTime (ns): {} ns", + dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(), + dataStoreStats.getRequestCommitAverageTime()); + + } } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeEvent.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeEvent.java index 144a81b256..d62e176e62 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeEvent.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeEvent.java @@ -11,15 +11,31 @@ import org.opendaylight.yangtools.concepts.Immutable; public interface DataChangeEvent extends DataChange, Immutable { + /** + * Returns a orignal subtree of data, which starts at the path + * where listener was registered. + * + */ + D getOriginalConfigurationSubtree(); + /** * Returns a new subtree of data, which starts at the path * where listener was registered. * */ + D getOriginalOperationalSubtree(); + + + + /** + * Returns a updated subtree of data, which starts at the path + * where listener was registered. + * + */ D getUpdatedConfigurationSubtree(); /** - * Returns a new subtree of data, which starts at the path + * Returns a udpated subtree of data, which starts at the path * where listener was registered. * */ diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend index e3d2b567a7..a18e5a9c82 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend @@ -38,6 +38,7 @@ import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegis import org.opendaylight.controller.md.sal.common.api.RegistrationListener import org.opendaylight.yangtools.concepts.util.ListenerRegistry import java.util.concurrent.atomic.AtomicLong +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent abstract class AbstractDataBroker

, D, DCL extends DataChangeListener> implements DataModificationTransactionFactory, // DataReader, // @@ -91,6 +92,10 @@ DataProvisionService { override final def registerDataChangeListener(P path, DCL listener) { val reg = new DataChangeListenerRegistration(path, listener, this); listeners.put(path, reg); + val initialConfig = dataReadRouter.readConfigurationData(path); + val initialOperational = dataReadRouter.readOperationalData(path); + val event = createInitialListenerEvent(path,initialConfig,initialOperational); + listener.onDataChanged(event); return reg; } @@ -108,6 +113,10 @@ DataProvisionService { return ret; } + protected def DataChangeEvent createInitialListenerEvent(P path,D initialConfig,D initialOperational) { + return new InitialDataChangeEventImpl(initialConfig,initialOperational); + + } protected final def removeListener(DataChangeListenerRegistration registration) { listeners.remove(registration.path, registration); diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java index 4eb9586fdf..68f9506c56 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java @@ -11,6 +11,8 @@ public class DataChangeEventImpl implements DataChangeEvent { private final DataChange dataChange; private final D originalConfigurationSubtree; + + private final D originalOperationalSubtree; private final D updatedOperationalSubtree; private final D updatedConfigurationSubtree; @@ -28,6 +30,16 @@ public class DataChangeEventImpl implements DataChangeEvent { this.updatedConfigurationSubtree = updatedConfigurationSubtree; } + @Override + public D getOriginalConfigurationSubtree() { + return originalConfigurationSubtree; + } + + @Override + public D getOriginalOperationalSubtree() { + return originalOperationalSubtree; + } + @Override public D getUpdatedOperationalSubtree() { return updatedOperationalSubtree; diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java new file mode 100644 index 0000000000..2764635720 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java @@ -0,0 +1,75 @@ +package org.opendaylight.controller.md.sal.common.impl.service; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; + +public class InitialDataChangeEventImpl implements DataChangeEvent { + + private final D originalOperationalTree; + private final D originalConfigurationTree; + + public InitialDataChangeEventImpl(D configTree, D operTree) { + originalConfigurationTree = configTree; + originalOperationalTree = operTree; + } + + @Override + public Map getCreatedConfigurationData() { + return Collections.emptyMap(); + } + + @Override + public Map getCreatedOperationalData() { + return Collections.emptyMap(); + } + + @Override + public Map getOriginalConfigurationData() { + return Collections.emptyMap(); + } + @Override + public Map getOriginalOperationalData() { + return Collections.emptyMap(); + } + @Override + public Set

getRemovedConfigurationData() { + return Collections.emptySet(); + } + @Override + public Set

getRemovedOperationalData() { + return Collections.emptySet(); + } + @Override + public Map getUpdatedConfigurationData() { + return Collections.emptyMap(); + } + + @Override + public D getUpdatedConfigurationSubtree() { + return originalConfigurationTree; + } + @Override + public D getUpdatedOperationalSubtree() { + return originalOperationalTree; + } + + @Override + public D getOriginalConfigurationSubtree() { + return originalConfigurationTree; + } + + @Override + public D getOriginalOperationalSubtree() { + return originalOperationalTree; + } + + @Override + public Map getUpdatedOperationalData() { + return Collections.emptyMap(); + } + + +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java new file mode 100644 index 0000000000..61abe664aa --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java @@ -0,0 +1,76 @@ +package org.opendaylight.controller.md.sal.common.impl.util; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; + +import org.opendaylight.yangtools.concepts.Delegator; + +import com.google.common.base.Preconditions; + +public class AbstractLockableDelegator implements Delegator { + + private final ReentrantReadWriteLock delegateLock = new ReentrantReadWriteLock(); + private final ReadLock delegateReadLock = delegateLock.readLock(); + private final WriteLock delegateWriteLock = delegateLock.writeLock(); + + + protected Lock getDelegateReadLock() { + return delegateReadLock; + } + + private T delegate; + + public AbstractLockableDelegator() { + // NOOP + } + + public AbstractLockableDelegator(T initialDelegate) { + delegate = initialDelegate; + } + + @Override + public T getDelegate() { + try { + delegateReadLock.lock(); + return delegate; + } finally { + delegateReadLock.unlock(); + } + } + + public T retrieveDelegate() { + try { + delegateReadLock.lock(); + Preconditions.checkState(delegate != null,"Delegate is null"); + return delegate; + } finally { + delegateReadLock.unlock(); + } + } + + /** + * + * @param newDelegate + * @return oldDelegate + */ + public final T changeDelegate(T newDelegate) { + try { + delegateWriteLock.lock(); + T oldDelegate = delegate; + delegate = newDelegate; + onDelegateChanged(oldDelegate, newDelegate); + return oldDelegate; + } finally { + delegateWriteLock.unlock(); + } + } + + + protected void onDelegateChanged(T oldDelegate, T newDelegate) { + // NOOP in abstract calss; + } +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java index 1062f5e535..87129d6863 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java @@ -8,5 +8,12 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; public interface DataStore extends // DataReader, DataCommitHandler { + + + Iterable getStoredConfigurationPaths(); + Iterable getStoredOperationalPaths(); + + boolean containsConfigurationPath(InstanceIdentifier path); + boolean containsOperationalPath(InstanceIdentifier path); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java index 9a4fc6ddc1..050966faa0 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java @@ -13,6 +13,7 @@ import org.opendaylight.controller.sal.core.api.data.DataStore; import org.opendaylight.controller.sal.dom.broker.BrokerConfigActivator; import org.opendaylight.controller.sal.dom.broker.BrokerImpl; import org.osgi.framework.BundleContext; +import static com.google.common.base.Preconditions.*; /** * @@ -33,8 +34,10 @@ public final class DomBrokerImplModule extends org.opendaylight.controller.confi @Override public void validate(){ super.validate(); - // Add custom validation for module attributes here. + checkArgument(getDataStore() != null, "Data Store needs to be provided for DomBroker"); } + + @Override public java.lang.AutoCloseable createInstance() { diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend index a6aa0ce32e..54c94dca9f 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend @@ -12,6 +12,7 @@ import java.util.Hashtable import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier import org.opendaylight.controller.sal.core.api.data.DataStore +import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter class BrokerConfigActivator implements AutoCloseable { @@ -27,6 +28,8 @@ class BrokerConfigActivator implements AutoCloseable { private var SchemaServiceImpl schemaService; private var DataBrokerImpl dataService; private var MountPointManagerImpl mountService; + + SchemaAwareDataStoreAdapter wrappedStore public def void start(BrokerImpl broker,DataStore store,BundleContext context) { val emptyProperties = new Hashtable(); @@ -45,9 +48,13 @@ class BrokerConfigActivator implements AutoCloseable { dataReg = context.registerService(DataBrokerService, dataService, emptyProperties); dataProviderReg = context.registerService(DataProviderService, dataService, emptyProperties); - dataService.registerConfigurationReader(ROOT, store); - dataService.registerCommitHandler(ROOT, store); - dataService.registerOperationalReader(ROOT, store); + wrappedStore = new SchemaAwareDataStoreAdapter(); + wrappedStore.changeDelegate(store); + wrappedStore.setValidationEnabled(false); + + dataService.registerConfigurationReader(ROOT, wrappedStore); + dataService.registerCommitHandler(ROOT, wrappedStore); + dataService.registerOperationalReader(ROOT, wrappedStore); mountService = new MountPointManagerImpl(); mountService.setDataBroker(dataService); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java index 1197ef34bd..ac5313a9ca 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java @@ -2,6 +2,7 @@ package org.opendaylight.controller.sal.dom.broker; import java.util.concurrent.atomic.AtomicLong; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker; import org.opendaylight.controller.sal.common.DataStoreIdentifier; diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataReaderRouter.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataReaderRouter.xtend index fbed2ca113..504a3d6394 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataReaderRouter.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataReaderRouter.xtend @@ -4,15 +4,100 @@ import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRo import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier import org.opendaylight.yangtools.yang.data.api.CompositeNode import org.opendaylight.controller.md.sal.common.api.data.DataReader +import org.opendaylight.yangtools.yang.common.QName +import java.net.URI +import java.util.List +import org.opendaylight.yangtools.yang.data.api.Node +import java.util.ArrayList +import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl +import java.util.Map +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier +import org.opendaylight.yangtools.yang.data.api.SimpleNode +import java.util.Collections +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates +import java.util.HashMap +import static com.google.common.base.Preconditions.*; +import java.util.Collection +import java.util.Set +import java.util.Map.Entry +import org.slf4j.LoggerFactory +import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl class DataReaderRouter extends AbstractDataReadRouter { + private static val LOG = LoggerFactory.getLogger(DataReaderRouter); + private static val NETCONF_NAMESPACE = URI.create("urn:ietf:params:xml:ns:netconf:base:1.0") + private static val NETCONF_DATA = new QName(NETCONF_NAMESPACE,"data"); override protected merge(InstanceIdentifier path, Iterable data) { + val pathArgument = path.path.last; + var empty = true; + var name = pathArgument?.nodeType; + val nodes = new ArrayList>(); + val keyNodes = new HashMap>(); val iterator = data.iterator; - if(iterator.hasNext) { - return data.iterator.next + for(dataBit : data) { + try { + if(pathArgument != null && dataBit != null) { + empty = false; + val keyNodesLocal = getKeyNodes(pathArgument,dataBit); + nodes.addAll(dataBit.childrenWithout(keyNodesLocal.entrySet)); + } else if (dataBit != null) { + empty = false; + nodes.addAll(dataBit.children) + } + } catch (IllegalStateException e) { + LOG.error("BUG: Readed data for path {} was invalid",path,e); + } } - return null; + if(empty) { + return null; + } + /** + * Reading from Root + * + */ + if(pathArgument == null) { + return new CompositeNodeTOImpl(NETCONF_DATA,null,nodes); + } + val finalNodes = new ArrayList>(); + finalNodes.addAll(keyNodes.values); + finalNodes.addAll(nodes); + return new CompositeNodeTOImpl(name,null,finalNodes); } - + + + + dispatch def Map> getKeyNodes(PathArgument argument, CompositeNode node) { + return Collections.emptyMap(); + } + + dispatch def getKeyNodes(NodeIdentifierWithPredicates argument, CompositeNode node) { + val ret = new HashMap>(); + for (keyValue : argument.keyValues.entrySet) { + val simpleNode = node.getSimpleNodesByName(keyValue.key); + if(simpleNode !== null && !simpleNode.empty) { + checkState(simpleNode.size <= 1,"Only one simple node for key $s is allowed in node $s",keyValue.key,node); + checkState(simpleNode.get(0).value == keyValue.value,"Key node must equals to instance identifier value"); + ret.put(keyValue.key,simpleNode.get(0)); + } + val compositeNode = node.getCompositesByName(keyValue.key); + checkState(compositeNode === null || compositeNode.empty,"Key node must be Simple Node, not composite node."); + } + return ret; + } + + def Collection> childrenWithout(CompositeNode node, Set>> entries) { + if(entries.empty) { + return node.children; + } + val filteredNodes = new ArrayList>(); + for(scannedNode : node.children) { + if(!entries.contains(scannedNode.nodeType)) { + filteredNodes.add(scannedNode); + } + } + return filteredNodes; + } + } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataStoreStatsWrapper.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataStoreStatsWrapper.java new file mode 100644 index 0000000000..9116d50d9c --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataStoreStatsWrapper.java @@ -0,0 +1,137 @@ +package org.opendaylight.controller.sal.dom.broker.impl; + +import java.util.concurrent.atomic.AtomicLong; + +import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.controller.sal.core.api.data.DataStore; +import org.opendaylight.yangtools.concepts.Delegator; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +public class DataStoreStatsWrapper implements Delegator, DataStore { + + private final DataStore delegate; + + private AtomicLong cfgReadCount = new AtomicLong(); + private AtomicLong cfgReadTimeTotal = new AtomicLong(); + + private AtomicLong operReadCount = new AtomicLong(); + private AtomicLong operReadTimeTotal = new AtomicLong(); + + private AtomicLong requestCommitCount = new AtomicLong(); + private AtomicLong requestCommitTimeTotal = new AtomicLong(); + + public DataStoreStatsWrapper(DataStore store) { + delegate = store; + } + + @Override + public DataStore getDelegate() { + return delegate; + } + + @Override + public CompositeNode readConfigurationData(InstanceIdentifier path) { + cfgReadCount.incrementAndGet(); + final long startTime = System.nanoTime(); + try { + return delegate.readConfigurationData(path); + } finally { + final long endTime = System.nanoTime(); + final long runTime = endTime - startTime; + cfgReadTimeTotal.addAndGet(runTime); + } + } + + @Override + public CompositeNode readOperationalData(InstanceIdentifier path) { + operReadCount.incrementAndGet(); + final long startTime = System.nanoTime(); + try { + return delegate.readOperationalData(path); + } finally { + final long endTime = System.nanoTime(); + final long runTime = endTime - startTime; + cfgReadTimeTotal.addAndGet(runTime); + } + } + + public DataCommitTransaction requestCommit( + DataModification modification) { + requestCommitCount.incrementAndGet(); + final long startTime = System.nanoTime(); + try { + return delegate.requestCommit(modification); + } finally { + final long endTime = System.nanoTime(); + final long runTime = endTime - startTime; + requestCommitTimeTotal.addAndGet(runTime); + } + }; + + @Override + public boolean containsConfigurationPath(InstanceIdentifier path) { + return delegate.containsConfigurationPath(path); + } + + public Iterable getStoredConfigurationPaths() { + return delegate.getStoredConfigurationPaths(); + } + + public Iterable getStoredOperationalPaths() { + return delegate.getStoredOperationalPaths(); + } + + public boolean containsOperationalPath(InstanceIdentifier path) { + return delegate.containsOperationalPath(path); + } + + public final long getConfigurationReadCount() { + return cfgReadCount.get(); + } + + public final long getOperationalReadCount() { + return operReadCount.get(); + } + + public final long getRequestCommitCount() { + return requestCommitCount.get(); + } + + public final long getConfigurationReadTotalTime() { + return cfgReadTimeTotal.get(); + } + + public final long getOperationalReadTotalTime() { + return operReadTimeTotal.get(); + } + + public final long getRequestCommitTotalTime() { + return requestCommitTimeTotal.get(); + } + + public final long getConfigurationReadAverageTime() { + long readCount = cfgReadCount.get(); + if(readCount == 0) { + return 0; + } + return cfgReadTimeTotal.get() / readCount; + } + + public final long getOperationalReadAverageTime() { + long readCount = operReadCount.get(); + if(readCount == 0) { + return 0; + } + return operReadTimeTotal.get() / readCount; + } + + public final long getRequestCommitAverageTime() { + long count = requestCommitCount.get(); + if(count == 0) { + return 0; + } + return requestCommitTimeTotal.get() / count; + } + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataUtils.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataUtils.xtend deleted file mode 100644 index 1a2f947270..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataUtils.xtend +++ /dev/null @@ -1,50 +0,0 @@ -package org.opendaylight.controller.sal.dom.broker.impl - -import org.opendaylight.yangtools.yang.data.api.CompositeNode -import java.util.Map -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier -import java.util.Map.Entry -import java.util.HashSet -import java.util.ArrayList -import org.opendaylight.yangtools.yang.data.api.Node -import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl - -class DataUtils { - - static def CompositeNode read(Map map, InstanceIdentifier path) { - val root = map.get(path); - val childs = map.getChilds(path); - if(root === null && childs.empty) { - return null; - } - - return merge(path, root, childs); - } - - static def CompositeNode merge(InstanceIdentifier path, CompositeNode node, - HashSet> entries) { - val it = new ArrayList>(); - val qname = path.path.last.nodeType; - if (node != null) { - addAll(node.children); - } - for (entry : entries) { - val nesting = entry.key.path.size - path.path.size; - if (nesting === 1) { - add(entry.value); - } - } - return new CompositeNodeTOImpl(qname, null, it); - } - - static def getChilds(Map map, InstanceIdentifier path) { - val it = new HashSet>(); - for (entry : map.entrySet) { - if (path.contains(entry.key)) { - add(entry); - } - } - return it; - } - -} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend index e7445e6965..e9ed71a052 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend @@ -9,23 +9,41 @@ import org.opendaylight.controller.sal.common.util.Rpcs import java.util.Collections import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier import org.opendaylight.yangtools.yang.data.api.CompositeNode -import static extension org.opendaylight.controller.sal.dom.broker.impl.DataUtils.*; import org.opendaylight.controller.sal.core.api.data.DataStore import java.util.HashSet class HashMapDataStore implements DataStore, AutoCloseable { + val Map configuration = new ConcurrentHashMap(); val Map operational = new ConcurrentHashMap(); + + + + override containsConfigurationPath(InstanceIdentifier path) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + + } + + override containsOperationalPath(InstanceIdentifier path) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override getStoredConfigurationPaths() { + configuration.keySet + } + + override getStoredOperationalPaths() { + operational.keySet + } override readConfigurationData(InstanceIdentifier path) { - configuration.read(path); + configuration.get(path); } override readOperationalData(InstanceIdentifier path) { - operational.read(path); + operational.get(path); } - diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataMerger.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataMerger.xtend new file mode 100644 index 0000000000..8cdbf9225d --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataMerger.xtend @@ -0,0 +1,13 @@ +package org.opendaylight.controller.sal.dom.broker.impl + +import org.opendaylight.yangtools.yang.model.api.SchemaContext +import org.opendaylight.yangtools.yang.data.api.CompositeNode + +class SchemaAwareDataMerger { + + private SchemaContext schema; + + + + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java new file mode 100644 index 0000000000..1f908140b0 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java @@ -0,0 +1,245 @@ +package org.opendaylight.controller.sal.dom.broker.impl; + +import java.awt.PageAttributes.OriginType; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; + +import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.controller.md.sal.common.api.data.DataReader; +import org.opendaylight.controller.md.sal.common.impl.util.AbstractLockableDelegator; +import org.opendaylight.controller.sal.core.api.data.DataStore; +import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; + +import static com.google.common.base.Preconditions.*; + +public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator implements // + DataStore, // + SchemaServiceListener, // + AutoCloseable { + + private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class); + + private SchemaContext schema = null; + private boolean validationEnabled = false; + private SchemaAwareDataMerger dataMerger = null; + private DataReader reader = new MergeFirstLevelReader(); + + @Override + public boolean containsConfigurationPath(InstanceIdentifier path) { + try { + getDelegateReadLock().lock(); + return getDelegate().containsConfigurationPath(path); + + } finally { + getDelegateReadLock().unlock(); + } + } + + @Override + public boolean containsOperationalPath(InstanceIdentifier path) { + try { + getDelegateReadLock().lock(); + return getDelegate().containsOperationalPath(path); + + } finally { + getDelegateReadLock().unlock(); + } + } + + @Override + public Iterable getStoredConfigurationPaths() { + try { + getDelegateReadLock().lock(); + return getDelegate().getStoredConfigurationPaths(); + + } finally { + getDelegateReadLock().unlock(); + } + } + + @Override + public Iterable getStoredOperationalPaths() { + try { + getDelegateReadLock().lock(); + return getDelegate().getStoredOperationalPaths(); + + } finally { + getDelegateReadLock().unlock(); + } + } + + @Override + public CompositeNode readConfigurationData(InstanceIdentifier path) { + return reader.readConfigurationData(path); + } + + @Override + public CompositeNode readOperationalData(InstanceIdentifier path) { + return reader.readOperationalData(path); + } + + @Override + public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction requestCommit( + DataModification modification) { + validateAgainstSchema(modification); + DataModification cleanedUp = prepareMergedTransaction(modification); + return retrieveDelegate().requestCommit(cleanedUp); + } + + public boolean isValidationEnabled() { + return validationEnabled; + } + + public void setValidationEnabled(boolean validationEnabled) { + this.validationEnabled = validationEnabled; + } + + private void validateAgainstSchema(DataModification modification) { + if (!validationEnabled) { + return; + } + + if (schema == null) { + LOG.info("Validation not performed for {}. Reason: YANG Schema not present.", modification.getIdentifier()); + return; + } + } + + @Override + protected void onDelegateChanged(DataStore oldDelegate, DataStore newDelegate) { + // NOOP + } + + @Override + public void onGlobalContextUpdated(SchemaContext context) { + this.schema = context; + } + + @Override + public void close() throws Exception { + this.schema = null; + } + + private DataModification prepareMergedTransaction( + DataModification original) { + // NOOP for now + return original; + } + + private final Comparator> preparationComparator = new Comparator>() { + @Override + public int compare(Entry o1, Entry o2) { + InstanceIdentifier o1Key = o1.getKey(); + InstanceIdentifier o2Key = o2.getKey(); + return Integer.compare(o1Key.getPath().size(), o2Key.getPath().size()); + } + }; + + private class MergeFirstLevelReader implements DataReader { + + @Override + public CompositeNode readConfigurationData(final InstanceIdentifier path) { + getDelegateReadLock().lock(); + try { + if (path.getPath().isEmpty()) { + return null; + } + QName qname = null; + CompositeNode original = getDelegate().readConfigurationData(path); + ArrayList> childNodes = new ArrayList>(); + if (original != null) { + childNodes.addAll(original.getChildren()); + qname = original.getNodeType(); + } else { + qname = path.getPath().get(path.getPath().size() - 1).getNodeType(); + } + + FluentIterable directChildren = FluentIterable.from(getStoredConfigurationPaths()) + .filter(new Predicate() { + @Override + public boolean apply(InstanceIdentifier input) { + if (path.contains(input)) { + int nesting = input.getPath().size() - path.getPath().size(); + if (nesting == 1) { + return true; + } + } + return false; + } + }); + for (InstanceIdentifier instanceIdentifier : directChildren) { + childNodes.add(getDelegate().readConfigurationData(instanceIdentifier)); + } + if (original == null && childNodes.isEmpty()) { + return null; + } + + return new CompositeNodeTOImpl(qname, null, childNodes); + } finally { + getDelegateReadLock().unlock(); + } + } + + @Override + public CompositeNode readOperationalData(final InstanceIdentifier path) { + getDelegateReadLock().lock(); + try { + if (path.getPath().isEmpty()) { + return null; + } + QName qname = null; + CompositeNode original = getDelegate().readOperationalData(path); + ArrayList> childNodes = new ArrayList>(); + if (original != null) { + childNodes.addAll(original.getChildren()); + qname = original.getNodeType(); + } else { + qname = path.getPath().get(path.getPath().size() - 1).getNodeType(); + } + + FluentIterable directChildren = FluentIterable.from(getStoredOperationalPaths()) + .filter(new Predicate() { + @Override + public boolean apply(InstanceIdentifier input) { + if (path.contains(input)) { + int nesting = input.getPath().size() - path.getPath().size(); + if (nesting == 1) { + return true; + } + } + return false; + } + }); + + for (InstanceIdentifier instanceIdentifier : directChildren) { + childNodes.add(getDelegate().readOperationalData(instanceIdentifier)); + } + if (original == null && childNodes.isEmpty()) { + return null; + } + + return new CompositeNodeTOImpl(qname, null, childNodes); + } finally { + getDelegateReadLock().unlock(); + } + } + } +} diff --git a/opendaylight/md-sal/sal-netconf-connector/pom.xml b/opendaylight/md-sal/sal-netconf-connector/pom.xml index 6ef5780c8a..e790a9dbb1 100644 --- a/opendaylight/md-sal/sal-netconf-connector/pom.xml +++ b/opendaylight/md-sal/sal-netconf-connector/pom.xml @@ -30,6 +30,11 @@ org.eclipse.xtend org.eclipse.xtend.lib + + org.opendaylight.controller + netty-threadgroup-config + 0.2.3-SNAPSHOT + org.opendaylight.controller netconf-client @@ -62,7 +67,7 @@ ${project.groupId} config-api ${netconf.version} - test + provided ${project.groupId} @@ -76,12 +81,6 @@ ${netconf.version} test - - ${project.groupId} - netconf-api - ${netconf.version} - test - org.opendaylight.bgpcep util @@ -91,7 +90,6 @@ ${project.groupId} netconf-client - test ${netconf.version} @@ -172,6 +170,21 @@ org.slf4j slf4j-api + + org.opendaylight.yangtools.model + ietf-inet-types + 2010.09.24.2-SNAPSHOT + + + org.opendaylight.controller + threadpool-config-api + 0.2.3-SNAPSHOT + + + org.opendaylight.controller + netty-config-api + 0.2.3-SNAPSHOT + bundle @@ -181,11 +194,65 @@ org.apache.felix maven-bundle-plugin - - - org.opendaylight.controller.sal.connect.netconf.NetconfProvider - - + + + org.opendaylight.yangtools + yang-maven-plugin + 0.5.9-SNAPSHOT + + + + generate-sources + + + + + + org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + + ${project.build.directory}/generated-sources/config + + + urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang + + + + + true + + + + + + org.opendaylight.controller + yang-jmx-generator-plugin + 0.2.3-SNAPSHOT + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/config + + + + + + + + org.eclipse.xtend + xtend-maven-plugin diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java new file mode 100644 index 0000000000..2a556c9be4 --- /dev/null +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java @@ -0,0 +1,89 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-netconf-connector yang module local name: sal-netconf-connector +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Mon Nov 18 09:44:16 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.connector.netconf; + +import io.netty.channel.EventLoopGroup; + +import java.net.InetAddress; +import java.net.InetSocketAddress; + +import javax.net.ssl.SSLContext; + +import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; +import org.opendaylight.controller.sal.connect.netconf.NetconfDevice; +import org.osgi.framework.BundleContext; + +import static com.google.common.base.Preconditions.*; + +import com.google.common.base.Optional; +import com.google.common.net.InetAddresses; + +/** +* +*/ +public final class NetconfConnectorModule extends org.opendaylight.controller.config.yang.md.sal.connector.netconf.AbstractNetconfConnectorModule +{ + + private BundleContext bundleContext; + + public NetconfConnectorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public NetconfConnectorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, NetconfConnectorModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate(){ + super.validate(); + checkState(getAddress() != null,"Address must be set."); + //checkState(getAddress().getIpv4Address() != null || getAddress().getIpv6Address() != null,"Address must be set."); + checkState(getPort() != null,"Port must be set."); + checkState(getDomRegistry() != null,"Dom Registry must be provided."); + } + + + @Override + public java.lang.AutoCloseable createInstance() { + + getDomRegistryDependency(); + NetconfDevice device = new NetconfDevice(getIdentifier().getInstanceName()); + String addressValue = getAddress(); + + + /* + * Uncomment after Switch to IP Address + if(getAddress().getIpv4Address() != null) { + addressValue = getAddress().getIpv4Address().getValue(); + } else { + addressValue = getAddress().getIpv6Address().getValue(); + } + + */ + InetAddress addr = InetAddresses.forString(addressValue); + InetSocketAddress socketAddress = new InetSocketAddress(addr , getPort().intValue()); + device.setSocketAddress(socketAddress); + + EventLoopGroup bossGroup = getBossThreadGroupDependency(); + EventLoopGroup workerGroup = getWorkerThreadGroupDependency(); + Optional maybeContext = Optional.absent(); + NetconfClientDispatcher dispatcher = new NetconfClientDispatcher(maybeContext , bossGroup, workerGroup); + + getDomRegistryDependency().registerProvider(device, bundleContext); + + device.start(dispatcher); + return device; + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } +} diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModuleFactory.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModuleFactory.java new file mode 100644 index 0000000000..51e288d597 --- /dev/null +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModuleFactory.java @@ -0,0 +1,39 @@ +/** + * Generated file + + * Generated from: yang module name: opendaylight-sal-netconf-connector yang module local name: sal-netconf-connector + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Mon Nov 18 09:44:16 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.md.sal.connector.netconf; + +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; +import org.opendaylight.controller.config.spi.Module; +import org.osgi.framework.BundleContext; + +/** +* +*/ +public class NetconfConnectorModuleFactory extends + org.opendaylight.controller.config.yang.md.sal.connector.netconf.AbstractNetconfConnectorModuleFactory { + + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, + DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception { + NetconfConnectorModule module = (NetconfConnectorModule) super.createModule(instanceName, dependencyResolver, + old, bundleContext); + module.setBundleContext(bundleContext); + return module; + } + + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) { + NetconfConnectorModule module = (NetconfConnectorModule) super.createModule(instanceName, dependencyResolver, + bundleContext); + module.setBundleContext(bundleContext); + return module; + } +} diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend index 0171c1f9e3..49d9757f42 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend @@ -14,8 +14,16 @@ import org.opendaylight.yangtools.yang.common.QName import java.util.Collections import org.opendaylight.controller.netconf.client.NetconfClientDispatcher import org.opendaylight.yangtools.concepts.Registration +import org.opendaylight.controller.sal.core.api.Provider +import org.opendaylight.controller.sal.core.api.Broker.ProviderSession +import org.opendaylight.controller.sal.core.api.mount.MountProvisionService +import static org.opendaylight.controller.sal.connect.netconf.InventoryUtils.*; +import org.opendaylight.controller.sal.core.api.data.DataBrokerService +import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction +import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl +import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl -class NetconfDevice implements DataReader, RpcImplementation { +class NetconfDevice implements Provider, DataReader, RpcImplementation, AutoCloseable { var NetconfClient client; @@ -23,25 +31,29 @@ class NetconfDevice implements DataReader, Rp var InetSocketAddress socketAddress; @Property - val MountProvisionInstance mountInstance; + var MountProvisionInstance mountInstance; @Property - val InstanceIdentifier path; - - Registration> operReaderReg - - Registration> confReaderReg - - public new(MountProvisionInstance mount,InstanceIdentifier path) { - _mountInstance = mount; - _path = path; + var InstanceIdentifier path; + + Registration> operReaderReg + + Registration> confReaderReg + + String name + + MountProvisionService mountService + + public new(String name) { + this.name = name; + this.path = InstanceIdentifier.builder(INVENTORY_PATH).nodeWithKey(INVENTORY_NODE, + Collections.singletonMap(INVENTORY_ID, name)).toInstance; } def start(NetconfClientDispatcher dispatcher) { - client = new NetconfClient("sal-netconf-connector", socketAddress, dispatcher); - - confReaderReg = mountInstance.registerConfigurationReader(path,this); - operReaderReg = mountInstance.registerOperationalReader(path,this); + client = new NetconfClient(name, socketAddress, dispatcher); + confReaderReg = mountInstance.registerConfigurationReader(path, this); + operReaderReg = mountInstance.registerOperationalReader(path, this); } override readConfigurationData(InstanceIdentifier path) { @@ -66,6 +78,40 @@ class NetconfDevice implements DataReader, Rp return result.toRpcResult(); } + override getProviderFunctionality() { + Collections.emptySet + } + + override onSessionInitiated(ProviderSession session) { + val dataBroker = session.getService(DataBrokerService); + + + + val transaction = dataBroker.beginTransaction + if(transaction.operationalNodeNotExisting) { + transaction.putOperationalData(path,nodeWithId) + } + if(transaction.configurationNodeNotExisting) { + transaction.putConfigurationData(path,nodeWithId) + } + transaction.commit().get(); + mountService = session.getService(MountProvisionService); + mountInstance = mountService.createOrGetMountPoint(path); + } + + def getNodeWithId() { + val id = new SimpleNodeTOImpl(INVENTORY_ID,null,name); + return new CompositeNodeTOImpl(INVENTORY_NODE,null,Collections.singletonList(id)); + } + + def boolean configurationNodeNotExisting(DataModificationTransaction transaction) { + return null === transaction.readConfigurationData(path); + } + + def boolean operationalNodeNotExisting(DataModificationTransaction transaction) { + return null === transaction.readOperationalData(path); + } + def Node findNode(CompositeNode node, InstanceIdentifier identifier) { var Node current = node; @@ -86,10 +132,11 @@ class NetconfDevice implements DataReader, Rp } return current; } - - public def stop() { + + override close() { confReaderReg?.close() operReaderReg?.close() + client?.close() } } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceManager.xtend b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceManager.xtend deleted file mode 100644 index 2fe145e18a..0000000000 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceManager.xtend +++ /dev/null @@ -1,84 +0,0 @@ -package org.opendaylight.controller.sal.connect.netconf - -import org.opendaylight.controller.sal.core.api.Broker.ProviderSession -import org.opendaylight.controller.sal.core.api.mount.MountProvisionService -import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService -import org.opendaylight.controller.sal.core.api.data.DataProviderService -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier -import org.opendaylight.yangtools.yang.common.QName -import static org.opendaylight.controller.sal.connect.netconf.InventoryUtils.*; -import static extension org.opendaylight.controller.sal.connect.netconf.NetconfInventoryUtils.*; - -import org.opendaylight.controller.sal.core.api.data.DataChangeListener -import org.opendaylight.yangtools.yang.data.api.CompositeNode -import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent -import java.util.Map -import java.util.concurrent.ConcurrentHashMap -import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance -import org.opendaylight.controller.netconf.client.NetconfClientDispatcher -import java.io.OptionalDataException -import com.google.common.base.Optional -import java.net.SocketAddress -import java.net.InetSocketAddress - -class NetconfDeviceManager { - - val Map devices = new ConcurrentHashMap; - - var ProviderSession session; - - @Property - var DataProviderService dataService; - - @Property - var MountProvisionService mountService; - - val nodeUpdateListener = new NetconfInventoryListener(this); - - - @Property - var NetconfClientDispatcher dispatcher; - - def void start() { - dataService?.registerDataChangeListener(INVENTORY_PATH, nodeUpdateListener); - if(dispatcher == null) { - dispatcher = new NetconfClientDispatcher(Optional.absent); - } - } - - def netconfNodeAdded(InstanceIdentifier path, CompositeNode node) { - val address = node.endpointAddress; - val port = Integer.parseInt(node.endpointPort); - netconfNodeAdded(path,new InetSocketAddress(address,port)) - - } - - def netconfNodeAdded(InstanceIdentifier path, InetSocketAddress address) { - - val mountPointPath = path; - val mountPoint = mountService.createOrGetMountPoint(mountPointPath); - val localPath = InstanceIdentifier.builder().toInstance; - val netconfDevice = new NetconfDevice(mountPoint,localPath); - netconfDevice.setSocketAddress(address); - netconfDevice.start(dispatcher); - } - - def netconfNodeRemoved(InstanceIdentifier path) { - - } - -} - -class NetconfInventoryListener implements DataChangeListener { - - val NetconfDeviceManager manager; - - new(NetconfDeviceManager manager) { - this.manager = manager; - } - - override onDataChanged(DataChangeEvent change) { - - //manager.netconfNodeAdded(path, change); - } -} diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfProvider.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfProvider.java deleted file mode 100644 index 8cf5f0274c..0000000000 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfProvider.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.opendaylight.controller.sal.connect.netconf; - -import java.util.Hashtable; - -import org.opendaylight.controller.sal.core.api.AbstractProvider; -import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; -import org.opendaylight.controller.sal.core.api.data.DataProviderService; -import org.opendaylight.controller.sal.core.api.mount.MountProvisionService; -import org.osgi.framework.BundleContext; - -public class NetconfProvider extends AbstractProvider { - - private NetconfDeviceManager netconfDeviceManager; - - @Override - protected void startImpl(BundleContext context) { - netconfDeviceManager = new NetconfDeviceManager(); - context.registerService(NetconfDeviceManager.class, netconfDeviceManager, new Hashtable()); - } - - - @Override - public void onSessionInitiated(ProviderSession session) { - MountProvisionService mountService = session.getService(MountProvisionService.class); - - - netconfDeviceManager.setMountService(mountService); - netconfDeviceManager.start(); - } - - @Override - protected void stopImpl(BundleContext context) { - - } -} diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang b/opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang new file mode 100644 index 0000000000..45f10162ca --- /dev/null +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang @@ -0,0 +1,75 @@ +module odl-sal-netconf-connector-cfg { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf"; + prefix "sal-netconf"; + + import config { prefix config; revision-date 2013-04-05; } + import threadpool {prefix th;} + import netty {prefix netty;} + import ietf-inet-types {prefix inet;} + import opendaylight-md-sal-dom {prefix dom;} + + description + "Service definition for Binding Aware MD-SAL."; + + revision "2013-10-28" { + description + "Initial revision"; + } + + identity sal-netconf-connector { + base config:module-type; + config:java-name-prefix NetconfConnector; + } + + + grouping server { + leaf address { + type string; + } + + leaf port { + type uint32; + } + } + + + augment "/config:modules/config:module/config:configuration" { + case sal-netconf-connector { + when "/config:modules/config:module/config:type = 'sal-netconf-connector'"; + + leaf address { + type string; + } + + leaf port { + type uint32; + } + + container dom-registry { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity dom:dom-broker-osgi-registry; + } + } + } + + container boss-thread-group { + uses config:service-ref { + refine type { + config:required-identity netty:netty-threadgroup; + } + } + } + + container worker-thread-group { + uses config:service-ref { + refine type { + config:required-identity netty:netty-threadgroup; + } + } + } + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/Draft01.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/Draft01.java new file mode 100644 index 0000000000..557adb6129 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/Draft01.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2013 Cisco 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.sal.rest.api; + +public class Draft01 { + public static class MediaTypes { + public static final String API = "application/vnd.yang.api"; + public static final String DATASTORE = "application/vnd.yang.datastore"; + public static final String DATA = "application/vnd.yang.data"; + public static final String EVENT = "application/vnd.yang.event"; + public static final String OPERATION = "application/vnd.yang.operation"; + public static final String PATCH = "application/vnd.yang.patch"; + } +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java index a22ea62397..5d08b3e7b6 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java @@ -7,14 +7,13 @@ */ package org.opendaylight.controller.sal.rest.api; -import static org.opendaylight.controller.sal.restconf.impl.MediaTypes.API; - import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.opendaylight.controller.sal.restconf.impl.StructuredData; @@ -58,42 +57,51 @@ public interface RestconfService extends RestconfServiceLegacy { @GET @Path("/modules") - @Produces({API+JSON,API+XML}) + @Produces({Draft01.MediaTypes.API+JSON,Draft01.MediaTypes.API+XML, + Draft02.MediaTypes.API+JSON,Draft02.MediaTypes.API+XML}) public StructuredData getModules(); @POST @Path("/operations/{identifier}") - @Produces({Draft02.MediaTypes.API+JSON,Draft02.MediaTypes.API+XML,API+JSON,API+XML}) + @Produces({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML, + Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload); @GET @Path("/config/{identifier:.+}") - @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML}) + @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public StructuredData readConfigurationData(@PathParam("identifier") String identifier); - @PUT + @POST @Path("/config/{identifier:.+}") - @Produces({API+JSON,API+XML}) + @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public Response createConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload); - @POST + @PUT @Path("/config/{identifier:.+}") - @Produces({API+JSON,API+XML}) + @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public Response updateConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload); @GET @Path("/operational/{identifier:.+}") - @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML}) + @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public StructuredData readOperationalData(@PathParam("identifier") String identifier); - @PUT + @POST @Path("/operational/{identifier:.+}") - @Produces({API+JSON,API+XML}) + @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public Response createOperationalData(@PathParam("identifier") String identifier, CompositeNode payload); - @POST + @PUT @Path("/operational/{identifier:.+}") - @Produces({API+JSON,API+XML}) + @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public Response updateOperationalData(@PathParam("identifier") String identifier, CompositeNode payload); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfServiceLegacy.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfServiceLegacy.java index 242e7f3150..35da98b1a0 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfServiceLegacy.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfServiceLegacy.java @@ -1,13 +1,12 @@ package org.opendaylight.controller.sal.rest.api; -import static org.opendaylight.controller.sal.restconf.impl.MediaTypes.API; - import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.opendaylight.controller.sal.restconf.impl.StructuredData; @@ -21,25 +20,28 @@ public interface RestconfServiceLegacy { @Deprecated @GET @Path("/datastore") - @Produces({API+JSON,API+XML}) + @Produces({Draft01.MediaTypes.DATASTORE+JSON,Draft01.MediaTypes.DATASTORE+XML}) public StructuredData readAllData(); @Deprecated @GET @Path("/datastore/{identifier:.+}") - @Produces({API+JSON,API+XML}) + @Produces({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public StructuredData readData(@PathParam("identifier") String identifier); @Deprecated - @PUT + @POST @Path("/datastore/{identifier:.+}") - @Produces({API+JSON,API+XML}) + @Produces({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public Response createConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload); @Deprecated - @POST + @PUT @Path("/datastore/{identifier:.+}") - @Produces({API+JSON,API+XML}) + @Produces({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public Response updateConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java index 5a1b42fd80..351ae6ebbe 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java @@ -3,70 +3,57 @@ package org.opendaylight.controller.sal.rest.impl; import static com.google.common.base.Preconditions.checkNotNull; import java.io.IOException; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import javax.activation.UnsupportedDataTypeException; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.opendaylight.yangtools.yang.data.api.Node; -import org.opendaylight.yangtools.yang.data.api.SimpleNode; -import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; -import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; -import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.TypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition; +import org.opendaylight.controller.sal.restconf.impl.ControllerContext; +import org.opendaylight.yangtools.yang.data.api.*; +import org.opendaylight.yangtools.yang.model.api.*; +import org.opendaylight.yangtools.yang.model.api.type.*; import com.google.common.base.Preconditions; import com.google.gson.stream.JsonWriter; class JsonMapper { - + private final Set foundLeafLists = new HashSet<>(); private final Set foundLists = new HashSet<>(); - + public void write(JsonWriter writer, CompositeNode data, DataNodeContainer schema) throws IOException { Preconditions.checkNotNull(writer); Preconditions.checkNotNull(data); Preconditions.checkNotNull(schema); writer.beginObject(); - + if (schema instanceof ContainerSchemaNode) { writeContainer(writer, data, (ContainerSchemaNode) schema); } else if (schema instanceof ListSchemaNode) { - writeList(writer, data, (ListSchemaNode) schema); + writeList(writer, null, data, (ListSchemaNode) schema); } else { throw new UnsupportedDataTypeException( "Schema can be ContainerSchemaNode or ListSchemaNode. Other types are not supported yet."); } - + writer.endObject(); - + foundLeafLists.clear(); foundLists.clear(); } - private void writeChildrenOfParent(JsonWriter writer, CompositeNode parent, DataNodeContainer parentSchema) throws IOException { + private void writeChildrenOfParent(JsonWriter writer, CompositeNode parent, DataNodeContainer parentSchema) + throws IOException { checkNotNull(parent); checkNotNull(parentSchema); - + for (Node child : parent.getChildren()) { DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchema.getChildNodes()); if (childSchema == null) { throw new UnsupportedDataTypeException("Probably the data node \"" + child.getNodeType().getLocalName() + "\" is not conform to schema"); } - + if (childSchema instanceof ContainerSchemaNode) { Preconditions.checkState(child instanceof CompositeNode, "Data representation of Container should be CompositeNode - " + child.getNodeType()); @@ -76,14 +63,14 @@ class JsonMapper { Preconditions.checkState(child instanceof CompositeNode, "Data representation of List should be CompositeNode - " + child.getNodeType()); foundLists.add((ListSchemaNode) childSchema); - writeList(writer, (CompositeNode) child, (ListSchemaNode) childSchema); + writeList(writer, parent, (CompositeNode) child, (ListSchemaNode) childSchema); } } else if (childSchema instanceof LeafListSchemaNode) { if (!foundLeafLists.contains(childSchema)) { Preconditions.checkState(child instanceof SimpleNode, "Data representation of LeafList should be SimpleNode - " + child.getNodeType()); foundLeafLists.add((LeafListSchemaNode) childSchema); - writeLeafList(writer, (SimpleNode) child, (LeafListSchemaNode) childSchema); + writeLeafList(writer, parent, (SimpleNode) child, (LeafListSchemaNode) childSchema); } } else if (childSchema instanceof LeafSchemaNode) { Preconditions.checkState(child instanceof SimpleNode, @@ -94,7 +81,7 @@ class JsonMapper { + "LeafListSchemaNode, or LeafSchemaNode. Other types are not supported yet."); } } - + for (Node child : parent.getChildren()) { DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchema.getChildNodes()); if (childSchema instanceof LeafListSchemaNode) { @@ -104,7 +91,7 @@ class JsonMapper { } } } - + private DataSchemaNode findFirstSchemaForNode(Node node, Set dataSchemaNode) { for (DataSchemaNode dsn : dataSchemaNode) { if (node.getNodeType().getLocalName().equals(dsn.getQName().getLocalName())) { @@ -113,84 +100,166 @@ class JsonMapper { } return null; } - + private void writeContainer(JsonWriter writer, CompositeNode node, ContainerSchemaNode schema) throws IOException { - writer.name(node.getNodeType().getLocalName()); + writeName(node, schema, writer); writer.beginObject(); writeChildrenOfParent(writer, node, schema); writer.endObject(); } - - private void writeList(JsonWriter writer, CompositeNode node, ListSchemaNode schema) throws IOException { - writer.name(node.getNodeType().getLocalName()); - writer.beginArray(); - - if (node.getParent() != null) { - CompositeNode parent = node.getParent(); - List nodeLists = parent.getCompositesByName(node.getNodeType()); - for (CompositeNode nodeList : nodeLists) { - writer.beginObject(); - writeChildrenOfParent(writer, nodeList, schema); - writer.endObject(); - } - } else { + + private void writeList(JsonWriter writer, CompositeNode nodeParent, CompositeNode node, ListSchemaNode schema) + throws IOException { + writeName(node, schema, writer); + writer.beginArray(); + + if (nodeParent != null) { + List nodeLists = nodeParent.getCompositesByName(node.getNodeType()); + for (CompositeNode nodeList : nodeLists) { writer.beginObject(); - writeChildrenOfParent(writer, node, schema); + writeChildrenOfParent(writer, nodeList, schema); writer.endObject(); } - - writer.endArray(); - } - - private void writeLeafList(JsonWriter writer, SimpleNode node, LeafListSchemaNode schema) throws IOException { - writer.name(node.getNodeType().getLocalName()); - writer.beginArray(); - - CompositeNode parent = node.getParent(); - List> nodeLeafLists = parent.getSimpleNodesByName(node.getNodeType()); - for (SimpleNode nodeLeafList : nodeLeafLists) { - writeValueOfNodeByType(writer, nodeLeafList, schema.getType()); - } - - writer.endArray(); + } else { + writer.beginObject(); + writeChildrenOfParent(writer, node, schema); + writer.endObject(); + } + + writer.endArray(); + } + + private void writeLeafList(JsonWriter writer, CompositeNode nodeParent, SimpleNode node, + LeafListSchemaNode schema) throws IOException { + writeName(node, schema, writer); + writer.beginArray(); + + List> nodeLeafLists = nodeParent.getSimpleNodesByName(node.getNodeType()); + for (SimpleNode nodeLeafList : nodeLeafLists) { + writeValueOfNodeByType(writer, nodeLeafList, schema.getType()); + } + + writer.endArray(); } - + private void writeLeaf(JsonWriter writer, SimpleNode node, LeafSchemaNode schema) throws IOException { - writer.name(node.getNodeType().getLocalName()); + writeName(node, schema, writer); writeValueOfNodeByType(writer, node, schema.getType()); } - - private void writeValueOfNodeByType(JsonWriter writer, SimpleNode node, TypeDefinition type) throws IOException { - if (!(node.getValue() instanceof String)) { - throw new IllegalStateException("Value in SimpleNode should be type String"); - } - - String value = (String) node.getValue(); - // TODO check Leafref, InstanceIdentifierTypeDefinition, IdentityrefTypeDefinition, UnionTypeDefinition - if (type.getBaseType() != null) { - writeValueOfNodeByType(writer, node, type.getBaseType()); - } else if (type instanceof InstanceIdentifierTypeDefinition) { - writer.value(((InstanceIdentifierTypeDefinition) type).getPathStatement().toString()); - } else if (type instanceof DecimalTypeDefinition - || type instanceof IntegerTypeDefinition - || type instanceof UnsignedIntegerTypeDefinition) { + + private void writeValueOfNodeByType(JsonWriter writer, SimpleNode node, TypeDefinition type) + throws IOException { + + String value = String.valueOf(node.getValue()); + // TODO check Leafref, InstanceIdentifierTypeDefinition, + // IdentityrefTypeDefinition, UnionTypeDefinition + TypeDefinition baseType = resolveBaseTypeFrom(type); + if (baseType instanceof InstanceIdentifierTypeDefinition) { + writer.value(((InstanceIdentifierTypeDefinition) baseType).getPathStatement().toString()); + } else if (baseType instanceof UnionTypeDefinition) { + processTypeIsUnionType(writer, (UnionTypeDefinition) baseType, value); + } else if (baseType instanceof DecimalTypeDefinition || baseType instanceof IntegerTypeDefinition + || baseType instanceof UnsignedIntegerTypeDefinition) { + writer.value(new NumberForJsonWriter(value)); + } else if (baseType instanceof BooleanTypeDefinition) { + writer.value(Boolean.parseBoolean(value)); + } else if (baseType instanceof EmptyTypeDefinition) { + writeEmptyDataTypeToJson(writer); + } else { + writer.value(value.equals("null") ? "" : value); + } + } + + private void processTypeIsUnionType(JsonWriter writer, UnionTypeDefinition unionType, String value) + throws IOException { + if (value == null) { + writeEmptyDataTypeToJson(writer); + } else if ((isNumber(value)) + && containsType(unionType, UnsignedIntegerTypeDefinition.class, IntegerTypeDefinition.class, + DecimalTypeDefinition.class)) { writer.value(new NumberForJsonWriter(value)); - } else if (type instanceof BooleanTypeDefinition) { + } else if (isBoolean(value) && containsType(unionType, BooleanTypeDefinition.class)) { writer.value(Boolean.parseBoolean(value)); - } else if (type instanceof EmptyTypeDefinition) { - writer.beginArray(); - writer.nullValue(); - writer.endArray(); } else { - writer.value(value != null ? value : ""); + writer.value(value); } } - + + private boolean isBoolean(String value) { + if (value.equals("true") || value.equals("false")) { + return true; + } + return false; + } + + private void writeEmptyDataTypeToJson(JsonWriter writer) throws IOException { + writer.beginArray(); + writer.nullValue(); + writer.endArray(); + } + + private boolean isNumber(String value) { + try { + Double.valueOf(value); + } catch (NumberFormatException e) { + return false; + } + return true; + } + + private boolean containsType(UnionTypeDefinition unionType, Class... searchedTypes) { + List> allUnionSubtypes = resolveAllUnionSubtypesFrom(unionType); + + for (TypeDefinition unionSubtype : allUnionSubtypes) { + for (Class searchedType : searchedTypes) { + if (searchedType.isInstance(unionSubtype)) { + return true; + } + } + } + return false; + } + + private List> resolveAllUnionSubtypesFrom(UnionTypeDefinition inputType) { + List> result = new ArrayList<>(); + for (TypeDefinition subtype : inputType.getTypes()) { + TypeDefinition resolvedSubtype = subtype; + + resolvedSubtype = resolveBaseTypeFrom(subtype); + + if (resolvedSubtype instanceof UnionTypeDefinition) { + List> subtypesFromRecursion = resolveAllUnionSubtypesFrom((UnionTypeDefinition) resolvedSubtype); + result.addAll(subtypesFromRecursion); + } else { + result.add(resolvedSubtype); + } + } + + return result; + } + + private TypeDefinition resolveBaseTypeFrom(TypeDefinition type) { + return type.getBaseType() != null ? resolveBaseTypeFrom(type.getBaseType()) : type; + } + + private void writeName(Node node, DataSchemaNode schema, JsonWriter writer) throws IOException { + String nameForOutput = node.getNodeType().getLocalName(); + if (schema.isAugmenting()) { + ControllerContext contContext = ControllerContext.getInstance(); + CharSequence moduleName; + moduleName = contContext.toRestconfIdentifier(schema.getQName()); + if (moduleName != null) { + nameForOutput = moduleName.toString(); + } + } + writer.name(nameForOutput); + } + private static final class NumberForJsonWriter extends Number { - + private static final long serialVersionUID = -3147729419814417666L; private final String value; - + public NumberForJsonWriter(String value) { this.value = value; } @@ -219,7 +288,7 @@ class JsonMapper { public String toString() { return value; } - + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java index dea4a73cd1..2b1abaa987 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java @@ -1,7 +1,5 @@ package org.opendaylight.controller.sal.rest.impl; -import static org.opendaylight.controller.sal.restconf.impl.MediaTypes.API; - import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; @@ -15,14 +13,17 @@ import javax.ws.rs.core.Response; import javax.ws.rs.ext.MessageBodyReader; import javax.ws.rs.ext.Provider; +import org.opendaylight.controller.sal.rest.api.Draft01; +import org.opendaylight.controller.sal.rest.api.Draft02; import org.opendaylight.controller.sal.rest.api.RestconfService; import org.opendaylight.yangtools.yang.data.api.CompositeNode; @Provider -@Consumes({API+RestconfService.JSON}) +@Consumes({ Draft01.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.DATA + RestconfService.JSON, + MediaType.APPLICATION_JSON }) public enum JsonToCompositeNodeProvider implements MessageBodyReader { INSTANCE; - + @Override public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { return true; @@ -36,8 +37,8 @@ public enum JsonToCompositeNodeProvider implements MessageBodyReader { INSTANCE; - + @Override public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { return true; diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToXmlProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToXmlProvider.java index 9f41b571da..d0c0077952 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToXmlProvider.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToXmlProvider.java @@ -1,7 +1,5 @@ package org.opendaylight.controller.sal.rest.impl; -import static org.opendaylight.controller.sal.restconf.impl.MediaTypes.API; - import java.io.IOException; import java.io.OutputStream; import java.lang.annotation.Annotation; @@ -21,7 +19,10 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import org.opendaylight.controller.sal.rest.api.Draft01; +import org.opendaylight.controller.sal.rest.api.Draft02; import org.opendaylight.controller.sal.rest.api.RestconfService; +import org.opendaylight.controller.sal.restconf.impl.ResponseException; import org.opendaylight.controller.sal.restconf.impl.StructuredData; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.impl.NodeUtils; @@ -30,10 +31,11 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @Provider -@Produces({API+RestconfService.XML}) +@Produces({ Draft01.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.DATA + RestconfService.XML, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public enum StructuredDataToXmlProvider implements MessageBodyWriter { INSTANCE; - + private final static Logger logger = LoggerFactory.getLogger(StructuredDataToXmlProvider.class); @Override @@ -52,9 +54,9 @@ public enum StructuredDataToXmlProvider implements MessageBodyWriter> processingQueue = new Stack<>(); CompositeNodeWrapper root = null; NodeWrapper element = null; @@ -73,14 +73,14 @@ public class XmlReader { element = processingQueue.pop(); } } - + if (!root.getLocalName().equals(element.getLocalName())) { throw new UnsupportedFormatException("XML should contain only one root element"); } - + return root; } - + private boolean isSimpleNodeEvent(final XMLEvent event) throws XMLStreamException { checkArgument(event != null, "XML Event cannot be NULL!"); if (event.isStartElement()) { @@ -99,7 +99,7 @@ public class XmlReader { } return false; } - + private boolean isCompositeNodeEvent(final XMLEvent event) throws XMLStreamException { checkArgument(event != null, "XML Event cannot be NULL!"); if (event.isStartElement()) { @@ -120,8 +120,9 @@ public class XmlReader { } return false; } - - private SimpleNodeWrapper resolveSimpleNodeFromStartElement(final StartElement startElement) throws XMLStreamException { + + private SimpleNodeWrapper resolveSimpleNodeFromStartElement(final StartElement startElement) + throws XMLStreamException { checkArgument(startElement != null, "Start Element cannot be NULL!"); String data = null; @@ -133,25 +134,29 @@ public class XmlReader { data = innerEvent.asCharacters().getData(); } } else if (innerEvent.isEndElement()) { - data = ""; + if (startElement.getLocation().getCharacterOffset() == innerEvent.getLocation().getCharacterOffset()) { + data = null; + } else { + data = ""; + } } } - + return new SimpleNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement), data); } - + private CompositeNodeWrapper resolveCompositeNodeFromStartElement(final StartElement startElement) { checkArgument(startElement != null, "Start Element cannot be NULL!"); return new CompositeNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement)); } - + private String getLocalNameFrom(StartElement startElement) { return startElement.getName().getLocalPart(); } - + private URI getNamespaceFrom(StartElement startElement) { String namespaceURI = startElement.getName().getNamespaceURI(); return namespaceURI.isEmpty() ? null : URI.create(namespaceURI); } - + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java index 19720107d3..f09c3b4cc1 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java @@ -1,7 +1,5 @@ package org.opendaylight.controller.sal.rest.impl; -import static org.opendaylight.controller.sal.restconf.impl.MediaTypes.API; - import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; @@ -16,11 +14,15 @@ import javax.ws.rs.ext.MessageBodyReader; import javax.ws.rs.ext.Provider; import javax.xml.stream.XMLStreamException; +import org.opendaylight.controller.sal.rest.api.Draft01; +import org.opendaylight.controller.sal.rest.api.Draft02; import org.opendaylight.controller.sal.rest.api.RestconfService; +import org.opendaylight.controller.sal.restconf.impl.ResponseException; import org.opendaylight.yangtools.yang.data.api.CompositeNode; @Provider -@Consumes({ API + RestconfService.XML }) +@Consumes({ Draft01.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.DATA + RestconfService.XML, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public enum XmlToCompositeNodeProvider implements MessageBodyReader { INSTANCE; @@ -37,8 +39,7 @@ public enum XmlToCompositeNodeProvider implements MessageBodyReader { private DataBrokerService dataService; private new() { - if (INSTANCE != null) { + if (INSTANCE !== null) { throw new IllegalStateException("Already instantiated"); } } @@ -32,9 +32,8 @@ class BrokerFacade implements DataReader { } private def void checkPreconditions() { - if (context == null || dataService == null) { - throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE) - .entity(RestconfProvider::NOT_INITALIZED_MSG).build()) + if (context === null || dataService === null) { + throw new ResponseException(Response.Status.SERVICE_UNAVAILABLE, RestconfProvider::NOT_INITALIZED_MSG) } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend index c1ee611e07..065d01e8e9 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend @@ -9,7 +9,6 @@ import java.util.HashMap import java.util.List import java.util.Map import java.util.concurrent.ConcurrentHashMap -import javax.ws.rs.WebApplicationException import javax.ws.rs.core.Response import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener import org.opendaylight.controller.sal.rest.impl.RestconfProvider @@ -46,7 +45,7 @@ class ControllerContext implements SchemaServiceListener { private new() { - if (INSTANCE != null) { + if (INSTANCE !== null) { throw new IllegalStateException("Already instantiated"); } } @@ -56,9 +55,8 @@ class ControllerContext implements SchemaServiceListener { } private def void checkPreconditions() { - if (schemas == null) { - throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE) - .entity(RestconfProvider::NOT_INITALIZED_MSG).build()) + if (schemas === null) { + throw new ResponseException(Response.Status.SERVICE_UNAVAILABLE, RestconfProvider::NOT_INITALIZED_MSG) } } @@ -72,7 +70,7 @@ class ControllerContext implements SchemaServiceListener { pathArgs.remove(0) } val schemaNode = ret.collectPathArguments(pathArgs, restconfInstance.findModule); - if (schemaNode == null) { + if (schemaNode === null) { return null } new InstanceIdWithSchemaNode(ret.toInstance, schemaNode) @@ -92,7 +90,7 @@ class ControllerContext implements SchemaServiceListener { private def getLatestModule(SchemaContext schema, String moduleName) { checkNotNull(schema) - checkArgument(moduleName != null && !moduleName.empty) + checkArgument(moduleName !== null && !moduleName.empty) val modules = schema.modules.filter[m|m.name == moduleName] var latestModule = modules.head for (module : modules) { @@ -134,9 +132,9 @@ class ControllerContext implements SchemaServiceListener { def CharSequence toRestconfIdentifier(QName qname) { checkPreconditions var module = uriToModuleName.get(qname.namespace) - if (module == null) { + if (module === null) { val moduleSchema = schemas.findModuleByNamespaceAndRevision(qname.namespace, qname.revision); - if(moduleSchema == null) throw new IllegalArgumentException() + if(moduleSchema === null) throw new IllegalArgumentException() uriToModuleName.put(qname.namespace, moduleSchema.name) module = moduleSchema.name; } @@ -189,13 +187,16 @@ class ControllerContext implements SchemaServiceListener { } private def toUriString(Object object) { - if(object == null) return ""; + if(object === null) return ""; return URLEncoder.encode(object.toString) } private def DataSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List strings, DataNodeContainer parentNode) { checkNotNull(strings) + if (parentNode === null) { + return null; + } if (strings.empty) { return parentNode as DataSchemaNode; } @@ -203,14 +204,14 @@ class ControllerContext implements SchemaServiceListener { val nodeName = nodeRef.toNodeName(); val targetNode = parentNode.getDataChildByName(nodeName); - if (targetNode == null) { + if (targetNode === null) { val children = parentNode.childNodes for (child : children) { if (child instanceof ChoiceNode) { val choice = child as ChoiceNode for (caze : choice.cases) { val result = builder.collectPathArguments(strings, caze as DataNodeContainer); - if (result != null) + if (result !== null) return result } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/MediaTypes.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/MediaTypes.java deleted file mode 100644 index af18828bfb..0000000000 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/MediaTypes.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2013 Cisco 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.sal.restconf.impl; - -public class MediaTypes { - public static final String API = "application/vnd.yang.api"; - public static final String DATASTORE = "application/vnd.yang.datastore"; - public static final String DATA = "application/vnd.yang.data"; - public static final String EVENT = "application/vnd.yang.event"; - public static final String OPERATION = "application/vnd.yang.operation"; - public static final String PATCH = "application/vnd.yang.patch"; -} diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ResponseException.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ResponseException.java new file mode 100644 index 0000000000..e2edd5dcb2 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ResponseException.java @@ -0,0 +1,15 @@ +package org.opendaylight.controller.sal.restconf.impl; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +public class ResponseException extends WebApplicationException { + + private static final long serialVersionUID = -5320114450593021655L; + + public ResponseException(Status status, String msg) { + super(Response.status(status).type(MediaType.TEXT_PLAIN_TYPE).entity(msg).build()); + } +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend index d9ac53589f..8f6ca1685b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend @@ -7,6 +7,7 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode import org.opendaylight.yangtools.yang.model.api.DataNodeContainer import org.opendaylight.yangtools.yang.model.api.DataSchemaNode import org.opendaylight.controller.md.sal.common.api.TransactionStatus +import javax.ws.rs.WebApplicationException class RestconfImpl implements RestconfService { @@ -19,7 +20,7 @@ class RestconfImpl implements RestconfService { extension ControllerContext controllerContext private new() { - if (INSTANCE != null) { + if (INSTANCE !== null) { throw new IllegalStateException("Already instantiated"); } } @@ -42,13 +43,13 @@ class RestconfImpl implements RestconfService { } override readData(String identifier) { - val instanceIdentifierWithSchemaNode = identifier.toInstanceIdentifier + val instanceIdentifierWithSchemaNode = identifier.resolveInstanceIdentifier val data = broker.readOperationalData(instanceIdentifierWithSchemaNode.getInstanceIdentifier); return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode) } override createConfigurationData(String identifier, CompositeNode payload) { - val identifierWithSchemaNode = identifier.toInstanceIdentifier + val identifierWithSchemaNode = identifier.resolveInstanceIdentifier val value = resolveNodeNamespaceBySchema(payload, identifierWithSchemaNode.schemaNode) val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get(); switch status.result { @@ -58,7 +59,7 @@ class RestconfImpl implements RestconfService { } override updateConfigurationData(String identifier, CompositeNode payload) { - val identifierWithSchemaNode = identifier.toInstanceIdentifier + val identifierWithSchemaNode = identifier.resolveInstanceIdentifier val value = resolveNodeNamespaceBySchema(payload, identifierWithSchemaNode.schemaNode) val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get(); switch status.result { @@ -76,13 +77,13 @@ class RestconfImpl implements RestconfService { } override readConfigurationData(String identifier) { - val instanceIdentifierWithSchemaNode = identifier.toInstanceIdentifier + val instanceIdentifierWithSchemaNode = identifier.resolveInstanceIdentifier val data = broker.readOperationalData(instanceIdentifierWithSchemaNode.getInstanceIdentifier); return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode) } override readOperationalData(String identifier) { - val instanceIdentifierWithSchemaNode = identifier.toInstanceIdentifier + val instanceIdentifierWithSchemaNode = identifier.resolveInstanceIdentifier val data = broker.readOperationalData(instanceIdentifierWithSchemaNode.getInstanceIdentifier); return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode) } @@ -96,7 +97,7 @@ class RestconfImpl implements RestconfService { } override createOperationalData(String identifier, CompositeNode payload) { - val identifierWithSchemaNode = identifier.toInstanceIdentifier + val identifierWithSchemaNode = identifier.resolveInstanceIdentifier val value = resolveNodeNamespaceBySchema(payload, identifierWithSchemaNode.schemaNode) val status = broker.commitOperationalDataPut(identifierWithSchemaNode.instanceIdentifier,value).get(); switch status.result { @@ -106,7 +107,7 @@ class RestconfImpl implements RestconfService { } override updateOperationalData(String identifier, CompositeNode payload) { - val identifierWithSchemaNode = identifier.toInstanceIdentifier + val identifierWithSchemaNode = identifier.resolveInstanceIdentifier val value = resolveNodeNamespaceBySchema(payload, identifierWithSchemaNode.schemaNode) val status = broker.commitOperationalDataPut(identifierWithSchemaNode.instanceIdentifier,value).get(); switch status.result { @@ -115,6 +116,14 @@ class RestconfImpl implements RestconfService { } } + private def InstanceIdWithSchemaNode resolveInstanceIdentifier(String identifier) { + val identifierWithSchemaNode = identifier.toInstanceIdentifier + if (identifierWithSchemaNode === null) { + throw new ResponseException(Response.Status.BAD_REQUEST, "URI has bad format"); + } + return identifierWithSchemaNode + } + private def CompositeNode resolveNodeNamespaceBySchema(CompositeNode node, DataSchemaNode schema) { if (node instanceof CompositeNodeWrapper) { addNamespaceToNodeFromSchemaRecursively(node as CompositeNodeWrapper, schema) @@ -124,7 +133,7 @@ class RestconfImpl implements RestconfService { } private def void addNamespaceToNodeFromSchemaRecursively(NodeWrapper nodeBuilder, DataSchemaNode schema) { - if (nodeBuilder.namespace == null) { + if (nodeBuilder.namespace === null) { nodeBuilder.namespace = schema.QName.namespace } if (nodeBuilder instanceof CompositeNodeWrapper) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java index 12f33d4562..62a9ae0581 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java @@ -1,13 +1,13 @@ package org.opendaylight.controller.sal.restconf.impl; import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.*; public class StructuredData { - + private final CompositeNode data; private final DataSchemaNode schema; - + public StructuredData(CompositeNode data, DataSchemaNode schema) { this.data = data; this.schema = schema; @@ -20,5 +20,4 @@ public class StructuredData { public DataSchemaNode getSchema() { return schema; } - } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNodeTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNodeTest.java index ede225c709..2e8b071519 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNodeTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNodeTest.java @@ -90,7 +90,7 @@ public class FromJsonToCompositeNodeTest { } @Test - public void nullArrayToCompositeNodeWithNullValueTest() { + public void nullArrayToSimpleNodeWithNullValueTest() { CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/array-with-null.json", true); assertNotNull(compositeNode); assertEquals("cont", compositeNode.getNodeType().getLocalName()); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNodeTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNodeTest.java index 6249d2a5b0..ef122dd8d7 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNodeTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNodeTest.java @@ -11,7 +11,7 @@ import javax.ws.rs.WebApplicationException; import org.junit.*; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; -import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.*; import org.opendaylight.yangtools.yang.data.api.*; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.slf4j.*; @@ -41,9 +41,36 @@ public class FromXmlToCompositeNodeTest { String nameSpace = "data:container:yang"; assertEquals(nameSpace, compNode.getNodeType().getNamespace().toString()); + verifyNullAndEmptyStringSingleNode(compNode, nameSpace); verifyCommonPartAOfXml(compNode, "", nameSpace); } + private void verifyNullAndEmptyStringSingleNode(CompositeNode compNode, String nameSpace) { + assertEquals("cont", compNode.getNodeType().getLocalName()); + + SimpleNode lf2 = null; + SimpleNode lf3 = null; + int found = 0; + for (Node child : compNode.getChildren()) { + if (found == 0x3) + break; + if (child instanceof SimpleNode) { + SimpleNode childSimple = (SimpleNode) child; + if (childSimple.getNodeType().getLocalName().equals("lf3")) { + lf3 = childSimple; + found = found | (1 << 0); + } else if (childSimple.getNodeType().getLocalName().equals("lf2")) { + lf2 = childSimple; + found = found | (1 << 1); + } + } + assertEquals(nameSpace, child.getNodeType().getNamespace().toString()); + } + + assertEquals("", lf2.getValue()); + assertEquals(null, lf3.getValue()); + } + @Test public void testXmlDataList() { CompositeNode compNode = compositeContainerFromXml("/xml-to-composite-node/data-list.xml", false); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java index 1d8d7495f9..bc941b997e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java @@ -13,9 +13,7 @@ import java.util.*; import java.util.concurrent.Future; import javax.ws.rs.WebApplicationException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.*; import javax.xml.stream.XMLStreamException; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; @@ -24,8 +22,7 @@ import javax.xml.transform.stream.StreamResult; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.restconf.impl.*; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.*; import org.opendaylight.yangtools.yang.data.api.*; import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder; import org.opendaylight.yangtools.yang.model.api.*; @@ -99,7 +96,7 @@ final class TestUtils { } return (CompositeNode) dataTree; } - + public static Document loadDocumentFrom(InputStream inputStream) { try { DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); @@ -135,6 +132,11 @@ final class TestUtils { } static String convertCompositeNodeDataAndYangToJson(CompositeNode compositeNode, String yangPath, String outputPath) { + return convertCompositeNodeDataAndYangToJson(compositeNode, yangPath, outputPath, null, null); + } + + static String convertCompositeNodeDataAndYangToJson(CompositeNode compositeNode, String yangPath, + String outputPath, String searchedModuleName, String searchedDataSchemaName) { String jsonResult = null; Set modules = null; @@ -145,30 +147,54 @@ final class TestUtils { } assertNotNull("modules can't be null.", modules); + Module module = null; + if (searchedModuleName != null) { + for (Module m : modules) { + if (m.getName().equals(searchedModuleName)) { + module = m; + break; + } + } + } else if (modules.size() == 1) { + module = modules.iterator().next(); + } + assertNotNull("Module is missing", module); + assertNotNull("Composite node can't be null", compositeNode); StructuredDataToJsonProvider structuredDataToJsonProvider = StructuredDataToJsonProvider.INSTANCE; - for (Module module : modules) { - ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream(); - for (DataSchemaNode dataSchemaNode : module.getChildNodes()) { - StructuredData structuredData = new StructuredData(compositeNode, dataSchemaNode); - try { - structuredDataToJsonProvider.writeTo(structuredData, null, null, null, null, null, byteArrayOS); - } catch (WebApplicationException | IOException e) { - e.printStackTrace(); + ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream(); + DataSchemaNode dataSchemaNode = null; + if (searchedDataSchemaName != null) { + for (DataSchemaNode dsn : module.getChildNodes()) { + if (dsn.getQName().getLocalName().equals(searchedDataSchemaName)) { + dataSchemaNode = dsn; } - assertFalse( - "Returning JSON string can't be empty for node " + dataSchemaNode.getQName().getLocalName(), - byteArrayOS.toString().isEmpty()); - } - jsonResult = byteArrayOS.toString(); - try { - outputToFile(byteArrayOS, outputPath); - } catch (IOException e) { - System.out.println("Output file wasn't cloased sucessfuly."); } + } else if (module.getChildNodes().size() == 1) { + dataSchemaNode = module.getChildNodes().iterator().next(); + } + assertNotNull(dataSchemaNode); + // SchemaContextUtil. + + ControllerContext controllerContext = ControllerContext.getInstance(); + controllerContext.setSchemas(loadSchemaContext(modules)); + StructuredData structuredData = new StructuredData(compositeNode, dataSchemaNode); + try { + structuredDataToJsonProvider.writeTo(structuredData, null, null, null, null, null, byteArrayOS); + } catch (WebApplicationException | IOException e) { + e.printStackTrace(); + } + assertFalse("Returning JSON string can't be empty for node " + dataSchemaNode.getQName().getLocalName(), + byteArrayOS.toString().isEmpty()); + jsonResult = byteArrayOS.toString(); + try { + outputToFile(byteArrayOS, outputPath); + } catch (IOException e) { + System.out.println("Output file wasn't cloased sucessfuly."); } + return jsonResult; } @@ -296,7 +322,8 @@ final class TestUtils { RpcResult rpcResult = DummyRpcResult.builder().result(TransactionStatus.COMMITED).build(); Future> future = DummyFuture.builder().rpcResult(rpcResult).build(); when(controllerContext.toInstanceIdentifier(any(String.class))).thenReturn(instIdAndSchema); - when(broker.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(future); + when(broker.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn( + future); restconf.setControllerContext(controllerContext); restconf.setBroker(broker); @@ -320,15 +347,15 @@ final class TestUtils { if (modules.size() < 1) { return null; } - - Module moduleRes = null; + + Module moduleRes = null; if (modules.size() > 1) { if (moduleName == null) { return null; } else { - for (Module module: modules) { + for (Module module : modules) { if (module.getName().equals(moduleName)) { - moduleRes = module; + moduleRes = module; } } if (moduleRes == null) { @@ -338,7 +365,7 @@ final class TestUtils { } else { moduleRes = modules.iterator().next(); } - + if (moduleRes.getChildNodes() == null) { return null; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonBasicDataTypesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonBasicDataTypesTest.java index f88a335f18..69de9f86c1 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonBasicDataTypesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonBasicDataTypesTest.java @@ -18,10 +18,6 @@ public class ToJsonBasicDataTypesTest { @Test public void simpleYangDataTest() { String jsonOutput; - // jsonOutput = - // TestUtils.readJsonFromFile("/yang-to-json-conversion/simple-yang-types/xml/awaited_output.json", - // false); - jsonOutput = TestUtils.convertCompositeNodeDataAndYangToJson( TestUtils.loadCompositeNode("/yang-to-json-conversion/simple-data-types/xml/data.xml"), "/yang-to-json-conversion/simple-data-types", "/yang-to-json-conversion/simple-data-types/xml"); @@ -73,7 +69,7 @@ public class ToJsonBasicDataTypesTest { // boolean lfref1Checked = false; boolean lfemptyChecked = false; boolean lfstr1Checked = false; - + while (jReader.hasNext()) { String keyName = jReader.nextName(); JsonToken peek = null; @@ -148,10 +144,8 @@ public class ToJsonBasicDataTypesTest { jReader.nextNull(); jReader.endArray(); lfemptyChecked = true; - // TODO: test will be implemented when functionality will be - // implemented - } else if (keyName.equals("lflstunion")) { - jReader.skipValue(); + } else if (keyName.startsWith("lfunion")) { + checkLfUnion(jReader, keyName, peek); } else { assertTrue("Key " + keyName + " doesn't exists in yang file.", false); } @@ -180,4 +174,44 @@ public class ToJsonBasicDataTypesTest { jReader.endObject(); } + + private void checkLfUnion(JsonReader jReader, String keyName, JsonToken peek) throws IOException { + if (keyName.equals("lfunion1")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion2")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion3")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextInt(); + } else if (keyName.equals("lfunion4")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek); + jReader.nextBoolean(); + } else if (keyName.equals("lfunion5")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion6")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion7")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion8")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion9")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion10")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion11")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion12")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek); + jReader.nextBoolean(); + } + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonWithAugmentTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonWithAugmentTest.java new file mode 100644 index 0000000000..994916dea5 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonWithAugmentTest.java @@ -0,0 +1,27 @@ +package org.opendaylight.controller.sal.restconf.impl.test; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class ToJsonWithAugmentTest { + + /** + * Test of json output when as input are specified composite node with empty + * data + YANG file + */ + @Test + public void augmentedElementsToJson() { + String jsonOutput = TestUtils.convertCompositeNodeDataAndYangToJson( + TestUtils.loadCompositeNode("/yang-to-json-conversion/augmentation/xml/data.xml"), + "/yang-to-json-conversion/augmentation", "/yang-to-json-conversion/augmentation/xml", "yang", "cont"); + + assertTrue(jsonOutput.contains("\"augment-leaf:lf2\": \"lf2\"")); + assertTrue(jsonOutput.contains("\"augment-container:cont1\": {")); + assertTrue(jsonOutput.contains("\"augment-container:lf11\": \"lf11\"")); + assertTrue(jsonOutput.contains("\"augment-list:lst1\": [")); + assertTrue(jsonOutput.contains("\"augment-list:lf11\": \"lf1_1\"")); + assertTrue(jsonOutput.contains("\"augment-list:lf11\": \"lf1_2\"")); + assertTrue(jsonOutput.contains("\"augment-leaflist:lflst1\": [")); + } +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlProvidersTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlProvidersTest.java index 7b63c5fd94..4336ac8a83 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlProvidersTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlProvidersTest.java @@ -29,12 +29,12 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.sal.rest.api.Draft01; import org.opendaylight.controller.sal.rest.api.RestconfService; import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; -import org.opendaylight.controller.sal.restconf.impl.MediaTypes; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; @@ -49,7 +49,8 @@ public class XmlProvidersTest extends JerseyTest { private static ControllerContext controllerContext; private static BrokerFacade brokerFacade; private static RestconfImpl restconfImpl; - private static final MediaType MEDIA_TYPE = new MediaType("application", "vnd.yang.api+xml"); + private static final MediaType MEDIA_TYPE = new MediaType("application", "vnd.yang.data+xml"); + private static final MediaType MEDIA_TYPE_DRAFT02 = new MediaType("application", "yang.data+xml"); @BeforeClass public static void init() throws FileNotFoundException { @@ -87,11 +88,11 @@ public class XmlProvidersTest extends JerseyTest { public void testBadFormatXmlToCompositeNodeProvider() throws UnsupportedEncodingException, URISyntaxException { String uri = createUri("/operations/", "ietf-interfaces:interfaces/interface/eth0"); - Response response = target(uri).request(MediaTypes.API + RestconfService.XML).post( + Response response = target(uri).request(Draft01.MediaTypes.DATA + RestconfService.XML).post( Entity.entity("", MEDIA_TYPE)); assertEquals(400, response.getStatus()); - response = target(uri).request(MediaTypes.API + RestconfService.XML).post( + response = target(uri).request(Draft01.MediaTypes.DATA + RestconfService.XML).post( Entity.entity("", MEDIA_TYPE)); assertEquals(400, response.getStatus()); } @@ -102,59 +103,69 @@ public class XmlProvidersTest extends JerseyTest { when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(null); - Response response = target(uri).request(MediaTypes.API+RestconfService.XML).get(); + Response response = target(uri).request(Draft01.MediaTypes.DATA+RestconfService.XML).get(); assertEquals(404, response.getStatus()); } + @Test + public void testXmlToCompositeNode400() throws UnsupportedEncodingException, URISyntaxException { + String uri = createUri("/datastore/", "simple-nodes:user/name"); + + when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(null); + + Response response = target(uri).request(Draft01.MediaTypes.DATA+RestconfService.XML).get(); + assertEquals(400, response.getStatus()); + } + @Test public void testRpcResultCommitedToStatusCodes() throws UnsupportedEncodingException { InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml"); String xml = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream)); - Entity entity = Entity.entity(xml, MEDIA_TYPE); + Entity entity = Entity.entity(xml, MEDIA_TYPE_DRAFT02); RpcResult rpcResult = DummyRpcResult.builder().result(TransactionStatus.COMMITED).build(); Future> dummyFuture = DummyFuture.builder().rpcResult(rpcResult).build(); when(brokerFacade.commitOperationalDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); when(brokerFacade.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0"); - Response response = target(uri).request(MEDIA_TYPE).put(entity); - assertEquals(200, response.getStatus()); - response = target(uri).request(MEDIA_TYPE).post(entity); + Response response = target(uri).request(MEDIA_TYPE_DRAFT02).put(entity); assertEquals(204, response.getStatus()); + response = target(uri).request(MEDIA_TYPE_DRAFT02).post(entity); + assertEquals(200, response.getStatus()); uri = createUri("/operational/", "ietf-interfaces:interfaces/interface/eth0"); - response = target(uri).request(MEDIA_TYPE).put(entity); - assertEquals(200, response.getStatus()); - response = target(uri).request(MEDIA_TYPE).post(entity); + response = target(uri).request(MEDIA_TYPE_DRAFT02).put(entity); assertEquals(204, response.getStatus()); + response = target(uri).request(MEDIA_TYPE_DRAFT02).post(entity); + assertEquals(200, response.getStatus()); uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0"); response = target(uri).request(MEDIA_TYPE).put(entity); - assertEquals(200, response.getStatus()); - response = target(uri).request(MEDIA_TYPE).post(entity); assertEquals(204, response.getStatus()); + response = target(uri).request(MEDIA_TYPE).post(entity); + assertEquals(200, response.getStatus()); } @Test public void testRpcResultOtherToStatusCodes() throws UnsupportedEncodingException { InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml"); String xml = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream)); - Entity entity = Entity.entity(xml, MEDIA_TYPE); + Entity entity = Entity.entity(xml, MEDIA_TYPE_DRAFT02); RpcResult rpcResult = DummyRpcResult.builder().result(TransactionStatus.FAILED).build(); Future> dummyFuture = DummyFuture.builder().rpcResult(rpcResult).build(); when(brokerFacade.commitOperationalDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); when(brokerFacade.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0"); - Response response = target(uri).request(MEDIA_TYPE).put(entity); + Response response = target(uri).request(MEDIA_TYPE_DRAFT02).put(entity); assertEquals(500, response.getStatus()); - response = target(uri).request(MEDIA_TYPE).post(entity); + response = target(uri).request(MEDIA_TYPE_DRAFT02).post(entity); assertEquals(500, response.getStatus()); uri = createUri("/operational/", "ietf-interfaces:interfaces/interface/eth0"); - response = target(uri).request(MEDIA_TYPE).put(entity); + response = target(uri).request(MEDIA_TYPE_DRAFT02).put(entity); assertEquals(500, response.getStatus()); - response = target(uri).request(MEDIA_TYPE).post(entity); + response = target(uri).request(MEDIA_TYPE_DRAFT02).post(entity); assertEquals(500, response.getStatus()); uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0"); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container-yang/data-container.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container-yang/data-container.yang index 7c17bf9fdf..b038eb193c 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container-yang/data-container.yang +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container-yang/data-container.yang @@ -2,13 +2,22 @@ module data-container-yang { namespace "data:container:yang"; prefix "dtconyg"; - revision 2013-11-19 { + revision 2013-11-19 { } container cont { leaf lf1 { type string; } + + leaf lf2 { + type string; + } + + leaf lf3 { + type empty; + } + leaf-list lflst1 { type string; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container.xml index 0c60fbcff3..ce97dd1715 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container.xml @@ -1,5 +1,7 @@ str0 + + 121 131 str1 diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-container.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-container.yang new file mode 100644 index 0000000000..7efe4f75e9 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-container.yang @@ -0,0 +1,22 @@ +module augment-container { + namespace "ns:augment:container"; + prefix "augcont"; + + + import yang {prefix yng; revision-date 2013-11-26;} + + + revision "2013-11-26" { + } + + augment "/yng:cont" { + container cont1 { + leaf lf11 { + type string; + } + } + } + + + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-leaf.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-leaf.yang new file mode 100644 index 0000000000..248d3bb8b0 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-leaf.yang @@ -0,0 +1,18 @@ +module augment-leaf { + namespace "ns:augment:leaf"; + prefix "auglf"; + + + import yang {prefix yng; revision-date 2013-11-26;} + + + revision "2013-11-26" { + } + + augment "/yng:cont" { + leaf lf2 { + type string; + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-leaflist.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-leaflist.yang new file mode 100644 index 0000000000..1f4b93702f --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-leaflist.yang @@ -0,0 +1,20 @@ +module augment-leaflist { + namespace "ns:augment:leaflist"; + prefix "auglflst"; + + + import yang {prefix yng; revision-date 2013-11-26;} + + + revision "2013-11-26" { + } + + augment "/yng:cont" { + leaf-list lflst1 { + type string; + } + } + + + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-list.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-list.yang new file mode 100644 index 0000000000..a35a87e90e --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-list.yang @@ -0,0 +1,22 @@ +module augment-list { + namespace "ns:augment:list"; + prefix "auglst"; + + + import yang {prefix yng; revision-date 2013-11-26;} + + + revision "2013-11-26" { + } + + augment "/yng:cont" { + list lst1 { + leaf lf11 { + type string; + } + } + } + + + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/xml/data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/xml/data.xml new file mode 100644 index 0000000000..08cdb34290 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/xml/data.xml @@ -0,0 +1,16 @@ + + lf1 + lf2 + + lf11 + + + lf1_1 + + + lf1_2 + + lflst1_1 + lflst1_2 + lflst1_3 + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/yang.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/yang.yang new file mode 100644 index 0000000000..aeb973704d --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/yang.yang @@ -0,0 +1,17 @@ +module yang { + namespace "ns:yang"; + + prefix "yng"; + revision 2013-11-26 { + } + + container cont { + leaf lf1 { + type string; + } + + } + + + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/simple-data-types.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/simple-data-types.yang index 010d3b1c2b..759b3ecf71 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/simple-data-types.yang +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/simple-data-types.yang @@ -5,6 +5,45 @@ module simple-data-types { revision 2013-11-12 { } + typedef tpdfempty { + type empty; + } + + typedef tpdfbit { + type bits { + bit b1; + bit b2; + bit b3; + } + } + + typedef tpdfun4 { + type boolean; + } + + typedef tpdfun3 { + type union { + type tpdfbit; + type tpdfempty; + } + } + + typedef tpdfun2 { + type union { + type tpdfun3; + type tpdfun4; + } + } + + typedef tpdfun1 { + type union { + type uint8; + type decimal64 { + fraction-digits 2; + } + } + } + container cont { leaf lfnint8Min { type int8; @@ -125,12 +164,87 @@ module simple-data-types { type empty; } - leaf-list lflstunion { + leaf lfunion1 { type union { type uint16; type string; } } + leaf lfunion2 { + type union { + type decimal64 { + fraction-digits 2; + } + type string; + } + } + + leaf lfunion3 { + type union { + type empty; + type string; + } + } + + leaf lfunion4 { + type union { + type boolean; + type string; + } + } + + leaf lfunion5 { + type union { + type uint16; + type string; + } + } + + leaf lfunion6 { + type union { + type uint16; + type empty; + } + } + + leaf lfunion7 { + type tpdfun3; + } + + leaf lfunion8 { + type union { + type uint16; + type string; + } + } + + leaf lfunion9 { + type union { + type uint16; + type boolean; + } + } + + leaf lfunion10 { + type union { + type bits { + bit bt1; + bit bt2; + } + type boolean; + } + } + + leaf lfunion11 { + type union { + type tpdfun1; + type tpdfun2; + } + } + + leaf lfunion12 { + type tpdfun2; + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/xml/data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/xml/data.xml index df00ca917e..0d31e9037a 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/xml/data.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/xml/data.xml @@ -24,8 +24,16 @@ bit3 AAaacdabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%%-#^ - 324 - 33.3 - lfunion - true + 324 + 33.3 + 55 + true + true + false + + + + bt1 + 33 + false \ No newline at end of file diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java index 7cbd2314b6..521de7e394 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java @@ -28,6 +28,7 @@ public class StatisticsManagerActivator extends AbstractBindingAwareProvider { @Override public void onSessionInitiated(ProviderContext session) { + pSession = session; DataProviderService dps = session.getSALService(DataProviderService.class); StatisticsManagerActivator.statsProvider.setDataService(dps); NotificationProviderService nps = session.getSALService(NotificationProviderService.class); diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java index 5218d051fa..d1ab351503 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java @@ -100,8 +100,6 @@ public class StatisticsProvider implements AutoCloseable { public void run() { while(true){ try { - spLogger.info("Statistics requester thread started with timer interval : {}",5000); - statsRequestSender(); Thread.sleep(5000); @@ -111,6 +109,11 @@ public class StatisticsProvider implements AutoCloseable { } } }); + + spLogger.debug("Statistics requester thread started with timer interval : {}",5000); + + statisticsRequesterThread.start(); + spLogger.info("Statistics Provider started."); } @@ -124,6 +127,9 @@ public class StatisticsProvider implements AutoCloseable { //Need to call API to receive all the nodes connected to controller. List targetNodes = getAllConnectedNodes(); + + if(targetNodes == null) + return; for (Node targetNode : targetNodes){ spLogger.info("Send request for stats collection to node : {})",targetNode.getId()); @@ -212,6 +218,9 @@ public class StatisticsProvider implements AutoCloseable { private List getAllConnectedNodes(){ Nodes nodes = (Nodes) dps.readOperationalData(nodesIdentifier); + if(nodes == null) + return null; + spLogger.info("Number of connected nodes : {}",nodes.getNode().size()); return nodes.getNode(); } diff --git a/opendaylight/md-sal/test/sal-rest-connector-it/src/test/java/org/opendaylight/controller/test/restconf/it/ServiceProviderController.java b/opendaylight/md-sal/test/sal-rest-connector-it/src/test/java/org/opendaylight/controller/test/restconf/it/ServiceProviderController.java index 23ba8aaea4..41ae52b3bf 100644 --- a/opendaylight/md-sal/test/sal-rest-connector-it/src/test/java/org/opendaylight/controller/test/restconf/it/ServiceProviderController.java +++ b/opendaylight/md-sal/test/sal-rest-connector-it/src/test/java/org/opendaylight/controller/test/restconf/it/ServiceProviderController.java @@ -21,7 +21,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; import org.opendaylight.controller.sal.connect.netconf.InventoryUtils; -import org.opendaylight.controller.sal.connect.netconf.NetconfDeviceManager; import org.opendaylight.controller.sal.connect.netconf.NetconfInventoryUtils; import org.opendaylight.controller.sal.core.api.data.DataBrokerService; import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance; @@ -61,9 +60,6 @@ public class ServiceProviderController { @Inject DataBrokerService dataBroker; - @Inject - NetconfDeviceManager netconfManager; - @Test public void properInitialized() throws Exception { @@ -72,8 +68,6 @@ public class ServiceProviderController { InstanceIdentifier path = InstanceIdentifier.builder(InventoryUtils.INVENTORY_PATH) .nodeWithKey(InventoryUtils.INVENTORY_NODE, InventoryUtils.INVENTORY_ID, "foo").toInstance(); - netconfManager.netconfNodeAdded(path, new InetSocketAddress("127.0.0.1", 8383)); - InstanceIdentifier mountPointPath = path; diff --git a/opendaylight/md-sal/topology-manager/pom.xml b/opendaylight/md-sal/topology-manager/pom.xml new file mode 100644 index 0000000000..6e50f9ce73 --- /dev/null +++ b/opendaylight/md-sal/topology-manager/pom.xml @@ -0,0 +1,75 @@ + + 4.0.0 + + org.opendaylight.controller + sal-parent + 1.0-SNAPSHOT + + org.opendaylight.controller.md + topology-manager + bundle + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + + + + + com.google.guava + guava + + + org.opendaylight.controller + sal-binding-api + 1.0-SNAPSHOT + + + org.opendaylight.controller + sal-binding-util + 1.0-SNAPSHOT + + + org.opendaylight.controller.model + model-flow-service + 1.0-SNAPSHOT + + + org.opendaylight.controller.model + model-inventory + 1.0-SNAPSHOT + + + org.opendaylight.controller.model + model-topology-view + 1.0-SNAPSHOT + + + org.eclipse.xtend + org.eclipse.xtend.lib + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.opendaylight.controller.md.inventory.manager.InventoryActivator + org.opendaylight.controller.md.inventory.manager + + + + + org.eclipse.xtend + xtend-maven-plugin + + + maven-clean-plugin + + + + diff --git a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableNodeMapping.xtend b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableNodeMapping.xtend new file mode 100644 index 0000000000..46f5d2b406 --- /dev/null +++ b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableNodeMapping.xtend @@ -0,0 +1,45 @@ +package org.opendaylight.md.controller.topology.manager + +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnector +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.node.TerminationPoint +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.node.TerminationPointBuilder +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.node.TerminationPointKey +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.TpId +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.NodeId + +class FlowCapableNodeMapping { + + static def NodeKey getNodeKey(NodeRef ref) { + (ref?.value?.path?.get(1) as IdentifiableItem).key + } + + static def NodeKey getNodeKey(NodeConnectorRef ref) { + (ref?.value?.path?.get(1) as IdentifiableItem).key + } + + static def NodeConnectorKey getNodeConnectorKey(NodeConnectorRef ref) { + (ref?.value?.path?.get(2) as IdentifiableItem).key + } + + static def TerminationPoint toTerminationPoint(NodeConnectorUpdated updated) { + val it = new TerminationPointBuilder + key = new TerminationPointKey(new TpId(updated.id)); + return it.build() + } + + static def NodeId toToplogyNodeId(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId) { + return new NodeId(nodeId); + } + + static def toTerminationPointId(NodeConnectorId id) { + return new TpId(id); + } +} diff --git a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.xtend b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.xtend new file mode 100644 index 0000000000..fb129e4710 --- /dev/null +++ b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.xtend @@ -0,0 +1,132 @@ +package org.opendaylight.md.controller.topology.manager + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryListener +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkDiscovered +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkOverutilized +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkRemoved +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkUtilizationNormal +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated +import org.opendaylight.controller.sal.binding.api.data.DataProviderService +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.Topology +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.node.TerminationPoint +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.TopologyKey +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.NetworkTopology +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.Node + +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.NodeKey +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.NodeId +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.node.TerminationPointKey +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.TpId +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef +import static extension org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.* +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction +import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader +import com.google.common.collect.FluentIterable +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.network.topology.topology.Link + +class FlowCapableTopologyExporter implements // +FlowTopologyDiscoveryListener, // +OpendaylightInventoryListener // +{ + + var TopologyKey topology; + + @Property + var DataProviderService dataService; + + override onNodeRemoved(NodeRemoved notification) { + val invNodeKey = notification.nodeRef.nodeKey + val tpNodeId = invNodeKey.id.toToplogyNodeId() + val tpNodeInstance = notification.nodeRef.toNodeIdentifier() + + val it = dataService.beginTransaction + removeRuntimeData(tpNodeInstance); + removeAffectedLinks(tpNodeId) + commit() + + } + + override onNodeUpdated(NodeUpdated notification) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override onNodeConnectorRemoved(NodeConnectorRemoved notification) { + val tpRef = notification.nodeConnectorRef.toTerminationPointIdentifier(); + val it = dataService.beginTransaction + removeRuntimeData(tpRef); + commit() + + } + + override onNodeConnectorUpdated(NodeConnectorUpdated notification) { + val nodeId = notification.nodeConnectorRef.nodeKey.id.toToplogyNodeId(); + val TerminationPoint point = notification.toTerminationPoint(); + val path = tpPath(nodeId, point.key.tpId); + + val it = dataService.beginTransaction + putRuntimeData(path, point); + commit() + } + + override onLinkDiscovered(LinkDiscovered notification) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override onLinkOverutilized(LinkOverutilized notification) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override onLinkRemoved(LinkRemoved notification) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + + } + + override onLinkUtilizationNormal(LinkUtilizationNormal notification) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + def InstanceIdentifier toNodeIdentifier(NodeRef ref) { + val invNodeKey = ref.nodeKey + + val nodeKey = new NodeKey(invNodeKey.id.toToplogyNodeId); + return InstanceIdentifier.builder.node(NetworkTopology).child(Topology, topology).child(Node, nodeKey). + toInstance; + } + + def InstanceIdentifier toTerminationPointIdentifier(NodeConnectorRef ref) { + val invNodeKey = ref.nodeKey + val invNodeConnectorKey = ref.nodeConnectorKey + return tpPath(invNodeKey.id.toToplogyNodeId(), invNodeConnectorKey.id.toTerminationPointId()) + } + + private def void removeAffectedLinks(DataModificationTransaction transaction, NodeId id) { + val reader = TypeSafeDataReader.forReader(transaction) + val topologyPath = InstanceIdentifier.builder().node(NetworkTopology).child(Topology, topology).toInstance; + val topologyData = reader.readOperationalData(topologyPath); + if (topologyData === null) { + return; + } + val affectedLinkInstances = FluentIterable.from(topologyData.link).filter[ + source.sourceNode == id || destination.destNode == id].transform [ + // + InstanceIdentifier.builder().node(NetworkTopology).child(Topology, topology).child(Link, key).toInstance + // + ] + for(affectedLink : affectedLinkInstances) { + transaction.removeRuntimeData(affectedLink); + } + } + + private def InstanceIdentifier tpPath(NodeId nodeId, TpId tpId) { + val nodeKey = new NodeKey(nodeId); + val tpKey = new TerminationPointKey(tpId) + return InstanceIdentifier.builder.node(NetworkTopology).child(Topology, topology).child(Node, nodeKey). + child(TerminationPoint, tpKey).toInstance; + } +} diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/rpc/Rpcs.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/rpc/Rpcs.java index 556541ab22..ef286ac862 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/rpc/Rpcs.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/rpc/Rpcs.java @@ -24,8 +24,9 @@ public class Rpcs { public ModuleRpcs getRpcMapping(RuntimeRpcElementResolved id) { Map modules = mappedRpcs.get(id.getNamespace()); Preconditions.checkState(modules != null, "No modules found for namespace %s", id.getNamespace()); - ModuleRpcs rpcMapping = modules.get(id.getModuleName()); - Preconditions.checkState(modules != null, "No module %s found for namespace %s", id.getModuleName(), + String moduleName = id.getModuleName(); + ModuleRpcs rpcMapping = modules.get(moduleName); + Preconditions.checkState(rpcMapping != null, "No module %s found for namespace %s", moduleName, id.getNamespace()); return rpcMapping; diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/InstanceRuntime.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/InstanceRuntime.java index 9d348d0985..70b10d0019 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/InstanceRuntime.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/InstanceRuntime.java @@ -12,7 +12,6 @@ import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Sets; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig; -import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -83,15 +82,14 @@ public class InstanceRuntime { })); } - public Element toXml(ObjectName rootOn, Set childRbeOns, Document document) { - return toXml(rootOn, childRbeOns, document, null, null); + public Element toXml(ObjectName rootOn, Set childRbeOns, Document document, Element parentElement, String namespace) { + return toXml(rootOn, childRbeOns, document, null, parentElement, namespace); } public Element toXml(ObjectName rootOn, Set childRbeOns, Document document, String instanceIndex, - String keyName) { - Element xml = document.createElement(keyName == null ? XmlNetconfConstants.DATA_KEY : keyName); + Element parentElement, String namespace) { // TODO namespace - xml = instanceMapping.toXml(rootOn, null, "namespace", document, xml); + Element xml = instanceMapping.toXml(rootOn, null, namespace, document, parentElement); if (instanceIndex != null) { xml.setAttribute(KEY_ATTRIBUTE_KEY, instanceIndex); @@ -106,8 +104,11 @@ public class InstanceRuntime { String runtimeInstanceIndex = objectName.getKeyProperty(childMappingEntry.getKey()); String elementName = jmxToYangChildRbeMapping.get(childMappingEntry.getKey()); - xml.appendChild(childMappingEntry.getValue().toXml(objectName, innerChildRbeOns, document, - runtimeInstanceIndex, elementName)); + + Element innerXml = document.createElement(elementName); + childMappingEntry.getValue().toXml(objectName, innerChildRbeOns, document, + runtimeInstanceIndex, innerXml, namespace); + xml.appendChild(innerXml); } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/ModuleRuntime.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/ModuleRuntime.java index 07da65ed19..4dbfba119f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/ModuleRuntime.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/ModuleRuntime.java @@ -8,7 +8,6 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime; -import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -41,31 +40,30 @@ public class ModuleRuntime { throw new IllegalStateException("Root runtime bean not found among " + runtimeBeanOns); } - public Element toXml(String namespace, Multimap instances, Document document) { - Element root = document.createElement(XmlNetconfConstants.MODULE_KEY); - XmlUtil.addNamespaceAttr(root, namespace); + public Element toXml(String namespace, String instanceName, Collection runtimeBeanOns, Document document) { + Element moduleElement = document.createElement(XmlNetconfConstants.MODULE_KEY); - Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, moduleName); - root.appendChild(nameElement); + final String prefix = getPrefix(namespace); + Element typeElement = XmlUtil.createPrefixedTextElement(document, XmlNetconfConstants.TYPE_KEY, prefix, + moduleName); + XmlUtil.addPrefixedNamespaceAttr(typeElement, prefix, namespace); + moduleElement.appendChild(typeElement); - for (String instanceName : instances.keySet()) { - Element instance = document.createElement(XmlNetconfConstants.INSTANCE_KEY); + Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, instanceName); + moduleElement.appendChild(nameElement); - Element innerNameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, instanceName); - instance.appendChild(innerNameElement); + ObjectName rootName = findRoot(runtimeBeanOns); - Collection runtimeBeanOns = instances.get(instanceName); - ObjectName rootName = findRoot(runtimeBeanOns); + Set childrenRuntimeBeans = Sets.newHashSet(runtimeBeanOns); + childrenRuntimeBeans.remove(rootName); - Set childrenRuntimeBeans = Sets.newHashSet(runtimeBeanOns); - childrenRuntimeBeans.remove(rootName); + instanceRuntime.toXml(rootName, childrenRuntimeBeans, document, moduleElement, namespace); - instance.appendChild(instanceRuntime.toXml(rootName, childrenRuntimeBeans, document)); - - root.appendChild(instance); - } + return moduleElement; + } - return root; + private String getPrefix(String namespace) { + return XmlNetconfConstants.PREFIX; } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java index da281269e6..8af1e0ee90 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java @@ -66,9 +66,12 @@ public class Runtime { if (instanceToRbe == null) continue; - ModuleRuntime moduleRuntime = moduleRuntimes.get(localNamespace).get(moduleName); - Element innerXml = moduleRuntime.toXml(localNamespace, instanceToRbe, document); - modulesElement.appendChild(innerXml); + for (String instanceName : instanceToRbe.keySet()) { + ModuleRuntime moduleRuntime = moduleRuntimes.get(localNamespace).get(moduleName); + Element innerXml = moduleRuntime.toXml(localNamespace, instanceName, instanceToRbe.get(instanceName), document); + modulesElement.appendChild(innerXml); + } + } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java index 838e5d8731..0f0b1227a6 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java @@ -33,11 +33,11 @@ public final class RuntimeRpcElementResolved { private RuntimeRpcElementResolved(String namespace, String moduleName, String instanceName, String runtimeBeanName, Map additionalAttributes) { - this.moduleName = moduleName; - this.instanceName = instanceName; + this.moduleName = Preconditions.checkNotNull(moduleName, "Module name"); + this.instanceName = Preconditions.checkNotNull(instanceName, "Instance name"); this.additionalAttributes = additionalAttributes; - this.namespace = namespace; - this.runtimeBeanName = runtimeBeanName; + this.namespace = Preconditions.checkNotNull(namespace, "Namespace"); + this.runtimeBeanName = Preconditions.checkNotNull(runtimeBeanName, "Runtime bean name"); } public String getModuleName() { @@ -68,12 +68,22 @@ public final class RuntimeRpcElementResolved { return ObjectNameUtil.createRuntimeBeanName(moduleName, instanceName, additionalAttributesJavaNames); } - private static final String xpathPatternBlueprint = "/" + XmlNetconfConstants.DATA_KEY + "/" - + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "\\[" - + XmlNetconfConstants.NAME_KEY + "='(.+)'\\]/" + XmlNetconfConstants.INSTANCE_KEY + "\\[" - + XmlNetconfConstants.NAME_KEY + "='([^']+)'\\](.*)"; + private static final String xpathPatternBlueprint = + "/" + XmlNetconfConstants.MODULES_KEY + + "/" + XmlNetconfConstants.MODULE_KEY + + "\\[" + + + "(?type|name)" + + "='(?[^']+)'" + + "( and |\\]\\[)" + + "(?type|name)" + + "='(?[^']+)'" + + + "\\]" + + "(?.*)"; + private static final Pattern xpathPattern = Pattern.compile(xpathPatternBlueprint); - private static final String additionalPatternBlueprint = "(.+)\\[(.+)='(.+)'\\]"; + private static final String additionalPatternBlueprint = "(?.+)\\[(.+)='(?.+)'\\]"; private static final Pattern additionalPattern = Pattern.compile(additionalPatternBlueprint); public static RuntimeRpcElementResolved fromXpath(String xpath, String elementName, String namespace) { @@ -82,26 +92,65 @@ public final class RuntimeRpcElementResolved { "Node %s with value '%s' not in required form on rpc element %s, required format is %s", RuntimeRpc.CONTEXT_INSTANCE, xpath, elementName, xpathPatternBlueprint); - String moduleName = matcher.group(1); - String instanceName = matcher.group(2); - String additionalString = matcher.group(3); - HashMap additionalAttributes = Maps. newHashMap(); - String runtimeBeanYangName = moduleName; - for (String additionalKeyValue : additionalString.split("/")) { - if (Strings.isNullOrEmpty(additionalKeyValue)) - continue; - matcher = additionalPattern.matcher(additionalKeyValue); - Preconditions - .checkState( - matcher.matches(), - "Attribute %s not in required form on rpc element %s, required format for additional attributes is %s", - additionalKeyValue, elementName, additionalPatternBlueprint); - String name = matcher.group(1); - runtimeBeanYangName = name; - additionalAttributes.put(name, matcher.group(3)); - } + PatternGroupResolver groups = new PatternGroupResolver(matcher.group("key1"), matcher.group("value1"), + matcher.group("key2"), matcher.group("value2"), matcher.group("additional")); + + String moduleName = groups.getModuleName(); + String instanceName = groups.getInstanceName(); + + HashMap additionalAttributes = groups.getAdditionalKeys(elementName, moduleName); - return new RuntimeRpcElementResolved(namespace, moduleName, instanceName, runtimeBeanYangName, + return new RuntimeRpcElementResolved(namespace, moduleName, instanceName, groups.getRuntimeBeanYangName(), additionalAttributes); } + + private static final class PatternGroupResolver { + + private final String key1, key2, value1, value2; + private final String additional; + private String runtimeBeanYangName; + + PatternGroupResolver(String key1, String value1, String key2, String value2, String additional) { + this.key1 = Preconditions.checkNotNull(key1); + this.value1 = Preconditions.checkNotNull(value1); + + this.key2 = Preconditions.checkNotNull(key2); + this.value2 = Preconditions.checkNotNull(value2); + + this.additional = Preconditions.checkNotNull(additional); + } + + String getModuleName() { + return key1.equals(XmlNetconfConstants.TYPE_KEY) ? value1 : value2; + } + + String getInstanceName() { + return key1.equals(XmlNetconfConstants.NAME_KEY) ? value1 : value2; + } + + HashMap getAdditionalKeys(String elementName, String moduleName) { + HashMap additionalAttributes = Maps.newHashMap(); + + runtimeBeanYangName = moduleName; + for (String additionalKeyValue : additional.split("/")) { + if (Strings.isNullOrEmpty(additionalKeyValue)) + continue; + Matcher matcher = additionalPattern.matcher(additionalKeyValue); + Preconditions + .checkState( + matcher.matches(), + "Attribute %s not in required form on rpc element %s, required format for additional attributes is %s", + additionalKeyValue, elementName, additionalPatternBlueprint); + String name = matcher.group("additionalKey"); + runtimeBeanYangName = name; + additionalAttributes.put(name, matcher.group("additionalValue")); + } + return additionalAttributes; + } + + private String getRuntimeBeanYangName() { + Preconditions.checkState(runtimeBeanYangName!=null); + return runtimeBeanYangName; + } + } } diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java index de0ecdbf1e..296b224fff 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java @@ -441,7 +441,9 @@ public class NetconfMappingTest extends AbstractConfigTest { Element response = get(); - assertEquals(2, getElementsSize(response, "instance")); + System.err.println(XmlUtil.toString(response)); + + assertEquals(2, getElementsSize(response, "module")); assertEquals(2, getElementsSize(response, "asdf")); assertEquals(5, getElementsSize(response, "inner-running-data")); assertEquals(5, getElementsSize(response, "deep2")); diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java index 0d68e25f67..25d2ad6abd 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java @@ -41,6 +41,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; import java.util.Collections; +import java.util.HashSet; import java.util.Set; /** @@ -152,9 +153,11 @@ public class ConfigPersisterNotificationHandler implements NotificationListener, Thread.sleep(delay); } - - throw new RuntimeException("Netconf server did not provide required capabilities " + expectedCaps - + " in time, provided capabilities " + currentCapabilities); + Set allNotFound = new HashSet<>(expectedCaps); + allNotFound.removeAll(currentCapabilities); + logger.error("Netconf server did not provide required capabilities. Expected but not found: {}, all expected {}, current {}", + allNotFound, expectedCaps ,currentCapabilities); + throw new RuntimeException("Netconf server did not provide required capabilities. Expected but not found:" + allNotFound); } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java index 54deb91837..11b8dc623c 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java @@ -121,8 +121,7 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter { String messageAsString = XmlUtil.toString(message); try { - netconfOperationExecution = getNetconfOperationWithHighestPriority( - message, session); + netconfOperationExecution = getNetconfOperationWithHighestPriority(message, session); } catch (IllegalArgumentException | IllegalStateException e) { logger.warn("Unable to handle rpc {} on session {}", messageAsString, session, e); @@ -140,8 +139,29 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter { throw new NetconfDocumentedException(errorMessage, e, NetconfDocumentedException.ErrorType.application, tag, NetconfDocumentedException.ErrorSeverity.error, errorInfo); + } catch (RuntimeException e) { + throw handleUnexpectedEx("Unexpected exception during netconf operation sort", e); } + try { + return executeOperationWithHighestPriority(message, netconfOperationExecution, messageAsString); + } catch (RuntimeException e) { + throw handleUnexpectedEx("Unexpected exception during netconf operation execution", e); + } + } + + private NetconfDocumentedException handleUnexpectedEx(String s, Exception e) throws NetconfDocumentedException { + logger.error(s, e); + + Map info = Maps.newHashMap(); + info.put(NetconfDocumentedException.ErrorSeverity.error.toString(), e.toString()); + return new NetconfDocumentedException("Unexpected error", + NetconfDocumentedException.ErrorType.application, + NetconfDocumentedException.ErrorTag.operation_failed, + NetconfDocumentedException.ErrorSeverity.error, info); + } + + private Document executeOperationWithHighestPriority(Document message, NetconfOperationExecution netconfOperationExecution, String messageAsString) throws NetconfDocumentedException { logger.debug("Forwarding netconf message {} to {}", messageAsString, netconfOperationExecution.operationWithHighestPriority); diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java index 5f6e046929..c03254dba2 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java @@ -275,7 +275,7 @@ public class NetconfITTest extends AbstractConfigTest { + " " - + "/data/modules/module[name='impl-netconf']/instance[name='instance']" + + "/modules/module[type='impl-netconf'][name='instance']" + "argument1" + "" + ""; final Document doc = XmlUtil.readXmlToDocument(rpc); final NetconfMessage message = netconfClient.sendMessage(new NetconfMessage(doc)); diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml index b2a2ee30c8..413b78c5d3 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml @@ -1,6 +1,6 @@ - /data/modules/module[name='impl-netconf']/instance[name='instance'] + /modules/module[type='impl-netconf' and name='instance'] testarg1 diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml index 8bc504a56e..cf15000b1a 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml @@ -1,7 +1,7 @@ - /data/modules/module[name='impl-netconf']/instance[name='instance2']/inner-running-data-additional[key='randomString_1003'] + /modules/module[name='instance2'][type='impl-netconf']/inner-running-data-additional[key='randomString_1003'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner.xml index 2356398e64..31f417e879 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner.xml @@ -2,7 +2,7 @@ - /data/modules/module[name='impl-netconf']/instance[name='instance2']/inner-running-data[key='1015']/inner-inner-running-data[key='1017'] + /modules/module[type='impl-netconf'][name='instance2']/inner-running-data[key='1015']/inner-inner-running-data[key='1017'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml index 209c382252..af0835b5df 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml @@ -2,7 +2,7 @@ - /data/modules/module[name='impl-netconf']/instance[name='instance2']/inner-running-data[key='1015']/inner-inner-running-data[key='1017'] + /modules/module[type='impl-netconf'][name='instance2']/inner-running-data[key='1015']/inner-inner-running-data[key='1017'] diff --git a/opendaylight/northbound/containermanager/src/main/java/org/opendaylight/controller/containermanager/northbound/ContainerConfigs.java b/opendaylight/northbound/containermanager/src/main/java/org/opendaylight/controller/containermanager/northbound/ContainerConfigs.java index eecc19f216..582c0766dd 100644 --- a/opendaylight/northbound/containermanager/src/main/java/org/opendaylight/controller/containermanager/northbound/ContainerConfigs.java +++ b/opendaylight/northbound/containermanager/src/main/java/org/opendaylight/controller/containermanager/northbound/ContainerConfigs.java @@ -20,10 +20,10 @@ import javax.xml.bind.annotation.XmlRootElement; import org.opendaylight.controller.containermanager.ContainerConfig; -@XmlRootElement(name = "container-config-list") +@XmlRootElement(name = "containerConfig-list") @XmlAccessorType(XmlAccessType.NONE) public class ContainerConfigs { - @XmlElement(name = "container-config") + @XmlElement(name = "containerConfig") List containerConfig; //To satisfy JAXB diff --git a/opendaylight/northbound/containermanager/src/main/java/org/opendaylight/controller/containermanager/northbound/ContainerManagerNorthbound.java b/opendaylight/northbound/containermanager/src/main/java/org/opendaylight/controller/containermanager/northbound/ContainerManagerNorthbound.java index 518fc4692f..fe38361cca 100644 --- a/opendaylight/northbound/containermanager/src/main/java/org/opendaylight/controller/containermanager/northbound/ContainerManagerNorthbound.java +++ b/opendaylight/northbound/containermanager/src/main/java/org/opendaylight/controller/containermanager/northbound/ContainerManagerNorthbound.java @@ -114,8 +114,8 @@ public class ContainerManagerNorthbound { * http://localhost:8080/controller/nb/v2/containermanager/containers * * Response body in XML: - * <container-config-list> - * <container-config> + * <containerConfig-list> + * <containerConfig> * <container>black</container> * <staticVlan>10</staticVlan> * <nodeConnectors>OF|1@OF|00:00:00:00:00:00:00:01</nodeConnectors> @@ -124,8 +124,8 @@ public class ContainerManagerNorthbound { * <name>tcp</name> * <protocol>TCP</protocol> * </flowSpecs> - * </container-config> - * <container-config> + * </containerConfig> + * <containerConfig> * <container>red</container> * <staticVlan>20</staticVlan> * <nodeConnectors>OF|1@OF|00:00:00:00:00:00:00:01</nodeConnectors> @@ -134,11 +134,11 @@ public class ContainerManagerNorthbound { * <name>udp</name> * <protocol>UDP</protocol> * </flowSpecs> - * </container-config> - * </container-config-list> + * </containerConfig> + * </containerConfig-list> * * Response body in JSON: - * { "container-config" : [ + * { "containerConfig" : [ * { "container" : "black", * "nodeConnectors" : [ * "OF|1@OF|00:00:00:00:00:00:00:01", "OF|23@OF|00:00:00:00:00:00:20:21" @@ -196,16 +196,16 @@ public class ContainerManagerNorthbound { * http://localhost:8080/controller/nb/v2/containermanager/container/blue * * Response body in XML: - * <container-config> + * <containerConfig> * <container>blue</container> * <staticVlan>10</staticVlan> * <nodeConnectors>OF|1@OF|00:00:00:00:00:00:00:01</nodeConnectors> * <nodeConnectors>OF|23@OF|00:00:00:00:00:00:20:21</nodeConnectors> - * </container-config> + * </containerConfig> * * Response body in JSON: * { - * "container-config": [ + * "containerConfig": [ * { * "container": "yellow", * "staticVlan": "10", @@ -259,11 +259,11 @@ public class ContainerManagerNorthbound { * http://localhost:8080/controller/nb/v2/containermanager/container/yellow * * Request body in XML: - * <container-config> + * <containerConfig> * <container>yellow</container> * <staticVlan>10</staticVlan> * <nodeConnectors></nodeConnectors> - * </container-config> + * </containerConfig> * * Request body in JSON: * {