From: Madhu Venugopal Date: Mon, 23 Dec 2013 19:24:23 +0000 (+0000) Subject: Merge "Simplify method isMutualExclusive in Subnet. Remove redundant 'if' statements." X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-1~151 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=9212fed678702583f4a555641208cf1c7b45b829;hp=1257b6b217ae7fb2fca640b5991eac2a0266a93f Merge "Simplify method isMutualExclusive in Subnet. Remove redundant 'if' statements." --- diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigTransactionController.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigTransactionController.java index c257e55dc0..264751318c 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigTransactionController.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigTransactionController.java @@ -16,7 +16,7 @@ import javax.management.ObjectName; /** * Represents functionality provided by configuration transaction. */ -public interface ConfigTransactionController extends LookupRegistry, ServiceReferenceReadableRegistry, ServiceReferenceWritableRegistry { +public interface ConfigTransactionController extends LookupRegistry, ServiceReferenceWritableRegistry { /** * Create new configuration bean. diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/LookupRegistry.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/LookupRegistry.java index 772617e97d..376ecdb52a 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/LookupRegistry.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/LookupRegistry.java @@ -65,8 +65,9 @@ public interface LookupRegistry { */ void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException; + /** - * @return qnames of all ModuleFactory instances in the system + * @return qNames of all ModuleFactory instances in the system */ Set getAvailableModuleFactoryQNames(); diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceReadableRegistry.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceReadableRegistry.java index f84fcd48c9..d7e94e8a76 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceReadableRegistry.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceReadableRegistry.java @@ -16,24 +16,24 @@ public interface ServiceReferenceReadableRegistry { /** * Lookup object name by fully qualified service interface name and service reference name. - * @param serviceInterfaceName service interface name + * @param serviceInterfaceQName service interface name * @param refName service reference name supplied in * {@link org.opendaylight.controller.config.api.ConfigTransactionController#saveServiceReference(String, String, javax.management.ObjectName)} * @throws java.lang.IllegalArgumentException if module not found */ - ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName); + ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName); /** * Get mapping of services to reference names and module object names. */ - Map> getServiceMapping(); + Map> getServiceMapping(); /** * Get current mapping between reference names and module object names for given service interface name. - * @param serviceInterfaceName service interface name + * @param serviceInterfaceQName service interface name * @throws IllegalArgumentException if there is a mismatch between serviceInterfaceName and objectName */ - Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName); + Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName); /** * Find all available service interface names of a module. @@ -50,4 +50,13 @@ public interface ServiceReferenceReadableRegistry { */ String getServiceInterfaceName(String namespace, String localName); + /** + * @return ObjectName with type=Service that was created using + * {@link org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry#saveServiceReference(String, String, + * javax.management.ObjectName)} + */ + ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException; + + void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException; + } diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceWritableRegistry.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceWritableRegistry.java index f3d6d16d6c..fa2aa1f56e 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceWritableRegistry.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceWritableRegistry.java @@ -13,17 +13,18 @@ import javax.management.ObjectName; public interface ServiceReferenceWritableRegistry extends ServiceReferenceReadableRegistry { /** * Create or update reference name to objectName. Reference name is unique per service interface name. + * @return created or updated object name containing service name and reference name * @throws IllegalArgumentException if there is a mismatch between serviceInterfaceName and objectName * @throws InstanceNotFoundException if search did not find exactly one instance */ - void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException; + ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException; /** * Remove service reference. * @return true iif removed * @throws IllegalArgumentException if service interface name is not advertised by any module */ - boolean removeServiceReference(String serviceInterfaceName, String refName); + void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException; /** * Remove all service references. diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java index cc1d89761c..3baa1039e0 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java @@ -25,21 +25,23 @@ import java.util.Set; * is defined as {@link #ON_DOMAIN} and at least one key-value pair. The only * mandatory property is {@link #TYPE_KEY}. All transaction related mbeans have * {@link #TRANSACTION_NAME_KEY} property set. - * */ @ThreadSafe public class ObjectNameUtil { public static final String ON_DOMAIN = ConfigRegistryConstants.ON_DOMAIN; public static final String MODULE_FACTORY_NAME_KEY = "moduleFactoryName"; + public static final String SERVICE_QNAME_KEY = "serviceQName"; public static final String INSTANCE_NAME_KEY = "instanceName"; public static final String TYPE_KEY = ConfigRegistryConstants.TYPE_KEY; public static final String TYPE_CONFIG_REGISTRY = ConfigRegistryConstants.TYPE_CONFIG_REGISTRY; public static final String TYPE_CONFIG_TRANSACTION = "ConfigTransaction"; public static final String TYPE_MODULE = "Module"; + public static final String TYPE_SERVICE_REFERENCE = "ServiceReference"; public static final String TYPE_RUNTIME_BEAN = "RuntimeBean"; - public static final String TRANSACTION_NAME_KEY = "TransactionName"; + public static final String REF_NAME_KEY = "RefName"; + private static final String REPLACED_QUOTATION_MARK = "\\?"; public static ObjectName createON(String on) { try { @@ -57,10 +59,10 @@ public class ObjectNameUtil { return ConfigRegistryConstants.createON(name, key, value); } - public static ObjectName createON(String name, Map attribs) { + public static ObjectName createON(String domain, Map attribs) { Hashtable table = new Hashtable<>(attribs); try { - return new ObjectName(name, table); + return new ObjectName(domain, table); } catch (Exception e) { throw new RuntimeException(e); } @@ -76,21 +78,21 @@ public class ObjectNameUtil { } public static ObjectName createTransactionModuleON(String transactionName, - ModuleIdentifier moduleIdentifier) { + ModuleIdentifier moduleIdentifier) { return createTransactionModuleON(transactionName, moduleIdentifier.getFactoryName(), moduleIdentifier.getInstanceName()); } public static ObjectName createTransactionModuleON(String transactionName, - String moduleName, String instanceName) { - Map onParams = createModuleON(moduleName, instanceName); + String moduleName, String instanceName) { + Map onParams = createModuleMap(moduleName, instanceName); onParams.put(TRANSACTION_NAME_KEY, transactionName); return createON(ON_DOMAIN, onParams); } public static ObjectName createTransactionModuleON(String transactionName, - ObjectName on) { + ObjectName on) { return createTransactionModuleON(transactionName, getFactoryName(on), getInstanceName(on)); } @@ -101,14 +103,73 @@ public class ObjectNameUtil { moduleIdentifier.getInstanceName()); } + public static ObjectName createReadOnlyServiceON(String serviceQName, String refName) { + Map onParams = createServiceMap(serviceQName, refName); + return createON(ON_DOMAIN, onParams); + } + + public static ObjectName createTransactionServiceON(String transactionName, String serviceQName, String refName) { + Map onParams = createServiceON(transactionName, serviceQName, refName); + return createON(ON_DOMAIN, onParams); + } + + public static String getServiceQName(ObjectName objectName) { + checkType(objectName, TYPE_SERVICE_REFERENCE); + String quoted = objectName.getKeyProperty(SERVICE_QNAME_KEY); + String result = unquoteAndUnescape(objectName, quoted); + return result; + } + + // ObjectName supports quotation and ignores tokens like =, but fails to ignore ? sign. + // It must be replaced with another character that hopefully does not collide + // with actual value. + private static String unquoteAndUnescape(ObjectName objectName, String quoted) { + if (quoted == null) { + throw new IllegalArgumentException("Cannot find " + SERVICE_QNAME_KEY + " in " + objectName); + } + if (quoted.startsWith("\"") == false || quoted.endsWith("\"") == false) { + throw new IllegalArgumentException("Quotes not found in " + objectName); + } + String substring = quoted.substring(1); + substring = substring.substring(0, substring.length() - 1); + substring = substring.replace(REPLACED_QUOTATION_MARK, "?"); + return substring; + } + + private static String quoteAndEscapeValue(String serviceQName) { + return "\"" + serviceQName.replace("?", REPLACED_QUOTATION_MARK) + "\""; + } + + public static String getReferenceName(ObjectName objectName) { + checkType(objectName, TYPE_SERVICE_REFERENCE); + return objectName.getKeyProperty(REF_NAME_KEY); + } + + private static Map createServiceON(String transactionName, String serviceQName, + String refName) { + Map result = new HashMap<>(createServiceMap(serviceQName, refName)); + result.put(TRANSACTION_NAME_KEY, transactionName); + return result; + } + + private static Map createServiceMap(String serviceQName, + String refName) { + Map onParams = new HashMap<>(); + onParams.put(TYPE_KEY, TYPE_SERVICE_REFERENCE); + onParams.put(SERVICE_QNAME_KEY, quoteAndEscapeValue(serviceQName)); + onParams.put(REF_NAME_KEY, refName); + return onParams; + } + + public static ObjectName createReadOnlyModuleON(String moduleName, - String instanceName) { - Map onParams = createModuleON(moduleName, instanceName); + String instanceName) { + Map onParams = createModuleMap(moduleName, instanceName); return createON(ON_DOMAIN, onParams); } - private static Map createModuleON(String moduleName, - String instanceName) { + private static Map createModuleMap(String moduleName, + String instanceName) { Map onParams = new HashMap<>(); onParams.put(TYPE_KEY, TYPE_MODULE); onParams.put(MODULE_FACTORY_NAME_KEY, moduleName); @@ -117,10 +178,12 @@ public class ObjectNameUtil { } public static String getFactoryName(ObjectName objectName) { + checkTypeOneOf(objectName, TYPE_MODULE, TYPE_RUNTIME_BEAN); return objectName.getKeyProperty(MODULE_FACTORY_NAME_KEY); } public static String getInstanceName(ObjectName objectName) { + checkTypeOneOf(objectName, TYPE_MODULE, TYPE_RUNTIME_BEAN); return objectName.getKeyProperty(INSTANCE_NAME_KEY); } @@ -132,6 +195,7 @@ public class ObjectNameUtil { * Sanitize on: keep only mandatory attributes of module + metadata. */ public static ObjectName withoutTransactionName(ObjectName inputON) { + checkTypeOneOf(inputON, TYPE_MODULE, TYPE_SERVICE_REFERENCE); if (getTransactionName(inputON) == null) { throw new IllegalArgumentException( "Expected ObjectName with transaction:" + inputON); @@ -140,14 +204,18 @@ public class ObjectNameUtil { throw new IllegalArgumentException("Expected different domain: " + inputON); } - String moduleName = getFactoryName(inputON); - String instanceName = getInstanceName(inputON); - - + Map outputProperties; + if (inputON.getKeyProperty(TYPE_KEY).equals(TYPE_MODULE)) { + String moduleName = getFactoryName(inputON); + String instanceName = getInstanceName(inputON); + outputProperties = new HashMap<>(createModuleMap(moduleName, instanceName)); + } else { + String serviceQName = getServiceQName(inputON); + String refName = getReferenceName(inputON); + outputProperties = new HashMap<>(createServiceMap(serviceQName, refName)); + } Map allProperties = getAdditionalProperties(inputON); - Map outputProperties = new HashMap<>(createModuleON(moduleName, instanceName)); - - for(Entry entry: allProperties.entrySet()) { + for (Entry entry : allProperties.entrySet()) { if (entry.getKey().startsWith("X-")) { outputProperties.put(entry.getKey(), entry.getValue()); } @@ -155,6 +223,13 @@ public class ObjectNameUtil { return createON(ON_DOMAIN, outputProperties); } + public static ObjectName withTransactionName(ObjectName inputON, String transactionName) { + Map additionalProperties = getAdditionalProperties(inputON); + additionalProperties.put(TRANSACTION_NAME_KEY, transactionName); + return createON(inputON.getDomain(), additionalProperties); + + } + private static void assertDoesNotContain( Map additionalProperties, String key) { if (additionalProperties.containsKey(key)) { @@ -165,7 +240,7 @@ public class ObjectNameUtil { } public static ObjectName createRuntimeBeanName(String moduleName, - String instanceName, Map additionalProperties) { + String instanceName, Map additionalProperties) { // check that there is no overwriting of default attributes assertDoesNotContain(additionalProperties, MODULE_FACTORY_NAME_KEY); assertDoesNotContain(additionalProperties, INSTANCE_NAME_KEY); @@ -217,8 +292,18 @@ public class ObjectNameUtil { } } + public static void checkTypeOneOf(ObjectName objectName, String ... types) { + for(String type: types) { + if (type.equals(objectName.getKeyProperty(TYPE_KEY))) { + return; + } + } + throw new IllegalArgumentException("Wrong type, expected one of " + Arrays.asList(types) + + ", got " + objectName); + } + public static ObjectName createModulePattern(String moduleName, - String instanceName) { + String instanceName) { if (moduleName == null) moduleName = "*"; if (instanceName == null) @@ -235,7 +320,7 @@ public class ObjectNameUtil { } public static ObjectName createModulePattern(String ifcName, - String instanceName, String transactionName) { + String instanceName, String transactionName) { return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN + ":type=Module," + ObjectNameUtil.MODULE_FACTORY_NAME_KEY + "=" + ifcName + "," + ObjectNameUtil.INSTANCE_NAME_KEY + "=" @@ -244,7 +329,7 @@ public class ObjectNameUtil { } public static ObjectName createRuntimeBeanPattern(String moduleName, - String instanceName) { + String instanceName) { return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN + ":" + ObjectNameUtil.TYPE_KEY + "=" + ObjectNameUtil.TYPE_RUNTIME_BEAN + "," @@ -255,7 +340,7 @@ public class ObjectNameUtil { } public static ModuleIdentifier fromON(ObjectName objectName, - String expectedType) { + String expectedType) { checkType(objectName, expectedType); String factoryName = getFactoryName(objectName); if (factoryName == null) @@ -268,4 +353,7 @@ public class ObjectNameUtil { return new ModuleIdentifier(factoryName, instanceName); } + public static boolean isServiceReference(ObjectName objectName) { + return TYPE_SERVICE_REFERENCE.equals(objectName.getKeyProperty(TYPE_KEY)); + } } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/CloseableServiceReferenceReadableRegistry.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/CloseableServiceReferenceReadableRegistry.java new file mode 100644 index 0000000000..8c325079d3 --- /dev/null +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/CloseableServiceReferenceReadableRegistry.java @@ -0,0 +1,17 @@ +/* + * 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.config.manager.impl; + +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; + +public interface CloseableServiceReferenceReadableRegistry extends AutoCloseable, ServiceReferenceReadableRegistry { + + + void close(); + +} 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 e3311c747f..19231705d1 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 @@ -10,7 +10,6 @@ package org.opendaylight.controller.config.manager.impl; import org.opendaylight.controller.config.api.ConflictingVersionException; import org.opendaylight.controller.config.api.ModuleIdentifier; import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule; -import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry; import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.jmx.CommitStatus; @@ -104,7 +103,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe private List lastListOfFactories = Collections.emptyList(); @GuardedBy("this") // switched in every 2ndPC - private ServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry(); + private CloseableServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry(); // constructor public ConfigRegistryImpl(ModuleFactoriesResolver resolver, @@ -298,8 +297,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe OsgiRegistration osgiRegistration = null; if (entry.hasOldModule()) { ModuleInternalInfo oldInternalInfo = entry.getOldInternalInfo(); - DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo - .getReadableModule(); + DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo.getReadableModule(); currentConfig.remove(entry.getIdentifier()); // test if old instance == new instance @@ -368,7 +366,9 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe version = configTransactionController.getVersion(); // switch readable Service Reference Registry - this.readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry(configTransactionController.getWritableRegistry(), this); + this.readableSRRegistry.close(); + this.readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry( + configTransactionController.getWritableRegistry(), this, baseJMXRegistrator); return new CommitStatus(newInstances, reusedInstances, recreatedInstances); @@ -525,8 +525,8 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe // service reference functionality: @Override - public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) { - return readableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceName, refName); + public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { + return readableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName); } @Override @@ -535,8 +535,8 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe } @Override - public synchronized Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) { - return readableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceName); + public synchronized Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { + return readableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName); } @Override @@ -549,11 +549,28 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe return readableSRRegistry.getServiceInterfaceName(namespace, localName); } + @Override + public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException { + readableSRRegistry.checkServiceReferenceExists(objectName); + } + + @Override + public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException { + return readableSRRegistry.getServiceReference(serviceInterfaceQName, refName); + } + @Override public Set getAvailableModuleFactoryQNames() { return ModuleQNameUtil.getQNames(resolver.getAllFactories()); } + @Override + public String toString() { + return "ConfigRegistryImpl{" + + "versionCounter=" + versionCounter + + ", version=" + version + + '}'; + } } /** @@ -579,12 +596,12 @@ class ConfigHolder { } private void add(ModuleInternalInfo configInfo) { - ModuleInternalInfo oldValue = currentConfig.put(configInfo.getName(), + ModuleInternalInfo oldValue = currentConfig.put(configInfo.getIdentifier(), configInfo); if (oldValue != null) { throw new IllegalStateException( "Cannot overwrite module with same name:" - + configInfo.getName() + ":" + configInfo); + + configInfo.getIdentifier() + ":" + configInfo); } } 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 17ce078154..e0d1a42661 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 @@ -95,7 +95,7 @@ class ConfigTransactionControllerImpl implements this.currentlyRegisteredFactories = currentlyRegisteredFactories; this.factoriesHolder = new HierarchicalConfigMBeanFactoriesHolder(currentlyRegisteredFactories); this.transactionStatus = new TransactionStatus(); - this.dependencyResolverManager = new DependencyResolverManager(transactionName, transactionStatus); + this.dependencyResolverManager = new DependencyResolverManager(transactionName, transactionStatus, writableSRRegistry); this.transactionsMBeanServer = transactionsMBeanServer; this.configMBeanServer = configMBeanServer; this.blankTransaction = blankTransaction; @@ -165,15 +165,14 @@ class ConfigTransactionControllerImpl implements throws InstanceAlreadyExistsException { transactionStatus.checkNotCommitStarted(); transactionStatus.checkNotAborted(); - ModuleIdentifier moduleIdentifier = oldConfigBeanInfo.getName(); + ModuleIdentifier moduleIdentifier = oldConfigBeanInfo.getIdentifier(); dependencyResolverManager.assertNotExists(moduleIdentifier); ModuleFactory moduleFactory = factoriesHolder .findByModuleName(moduleIdentifier.getFactoryName()); Module module; - DependencyResolver dependencyResolver = dependencyResolverManager - .getOrCreate(moduleIdentifier); + DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(moduleIdentifier); try { BundleContext bc = getModuleFactoryBundleContext(moduleFactory.getImplementationName()); module = moduleFactory.createModule( @@ -412,7 +411,7 @@ class ConfigTransactionControllerImpl implements close(); } - private void close() { + public void close() { //FIXME: should not close object that was retrieved in constructor, a wrapper object should do that perhaps txLookupRegistry.close(); } @@ -523,8 +522,8 @@ class ConfigTransactionControllerImpl implements @Override - public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) { - return writableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceName, refName); + public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { + return writableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName); } @Override @@ -533,8 +532,8 @@ class ConfigTransactionControllerImpl implements } @Override - public synchronized Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) { - return writableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceName); + public synchronized Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { + return writableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName); } @Override @@ -548,13 +547,13 @@ class ConfigTransactionControllerImpl implements } @Override - public synchronized void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException { - writableSRRegistry.saveServiceReference(serviceInterfaceName, refName, objectName); + public synchronized ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException { + return writableSRRegistry.saveServiceReference(serviceInterfaceName, refName, moduleON); } @Override - public synchronized boolean removeServiceReference(String serviceInterfaceName, String refName) { - return writableSRRegistry.removeServiceReference(serviceInterfaceName, refName); + public synchronized void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException { + writableSRRegistry.removeServiceReference(serviceInterfaceName, refName); } @Override @@ -581,4 +580,13 @@ class ConfigTransactionControllerImpl implements return txLookupRegistry.getAvailableModuleFactoryQNames(); } + @Override + public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException { + writableSRRegistry.checkServiceReferenceExists(objectName); + } + + @Override + public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException { + return writableSRRegistry.getServiceReference(serviceInterfaceQName, refName); + } } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionLookupRegistry.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionLookupRegistry.java index 12db6c8f89..a7d426ebdd 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionLookupRegistry.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionLookupRegistry.java @@ -117,6 +117,13 @@ class ConfigTransactionLookupRegistry implements LookupRegistry, Closeable { return ModuleQNameUtil.getQNames(allCurrentFactories); } + + @Override + public String toString() { + return "ConfigTransactionLookupRegistry{" + + "transactionIdentifier=" + transactionIdentifier + + '}'; + } } interface TransactionJMXRegistratorFactory { diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalInfo.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalInfo.java index 14a706dd9b..941aec1096 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalInfo.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalInfo.java @@ -90,11 +90,6 @@ public class ModuleInternalInfo implements Comparable, return osgiRegistration; } - @Deprecated - public ModuleIdentifier getName() { - return name; - } - /** * Get index representing dependency ordering within a transaction. */ @@ -111,7 +106,7 @@ public class ModuleInternalInfo implements Comparable, } public DestroyedModule toDestroyedModule() { - return new DestroyedModule(getName(), + return new DestroyedModule(getIdentifier(), getReadableModule().getInstance(), getModuleJMXRegistrator(), getOsgiRegistration(), getOrderingIdx()); } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java index 7fedcdf71c..0faa32b7dc 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java @@ -13,42 +13,52 @@ import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry; import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator; +import org.opendaylight.controller.config.manager.impl.jmx.ServiceReference; +import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceMXBeanImpl; +import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator; +import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceJMXRegistration; +import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceTransactionRegistratorFactory; +import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceTransactionRegistratorFactoryImpl; import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper; import org.opendaylight.controller.config.spi.ModuleFactory; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.ObjectName; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableRegistry, ServiceReferenceWritableRegistry { +public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceReadableRegistry, ServiceReferenceWritableRegistry { private static final Logger logger = LoggerFactory.getLogger(ServiceReferenceRegistryImpl.class); private final Map factories; private final Map> factoryNamesToQNames; // validator of incoming ObjectNames - throws InstanceNotFoundException if not found either in registry or transaction private final LookupRegistry lookupRegistry; + private final ServiceReferenceRegistrator serviceReferenceRegistrator; // helper method for getting QName of SI from namespace + local name private final Map> namespacesToAnnotations; // all Service Interface qNames for sanity checking private final Set allQNames; // actual reference database - private final Map> refNames; + private final Map refNames = new HashMap<>(); + private final boolean writable; + private final Map> mBeans = new HashMap<>(); /** * Static constructor for config registry. Since only transaction can write to this registry, it will * return blank state. */ - public static ServiceReferenceReadableRegistry createInitialSRLookupRegistry() { + public static CloseableServiceReferenceReadableRegistry createInitialSRLookupRegistry() { // since this is initial state, just throw exception: LookupRegistry lookupRegistry = new LookupRegistry() { @Override @@ -73,36 +83,99 @@ public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableReg @Override public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException { - throw new InstanceNotFoundException("Cannot find " + objectName); + throw new InstanceNotFoundException("Cannot find " + objectName + " - Tried to use mocking registry"); } @Override public Set getAvailableModuleFactoryQNames() { throw new UnsupportedOperationException(); } + + @Override + public String toString() { + return "initial"; + } + }; + ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory = new ServiceReferenceTransactionRegistratorFactory(){ + @Override + public ServiceReferenceRegistrator create() { + return new ServiceReferenceRegistrator() { + @Override + public String getNullableTransactionName() { + throw new UnsupportedOperationException(); + } + + @Override + public ServiceReferenceJMXRegistration registerMBean(ServiceReferenceMXBeanImpl object, ObjectName on) throws InstanceAlreadyExistsException { + throw new UnsupportedOperationException(); + } + + @Override + public void close() { + + } + }; + } }; return new ServiceReferenceRegistryImpl(Collections.emptyMap(), lookupRegistry, - Collections.>emptyMap()); + serviceReferenceRegistratorFactory, false); } /** * Static constructor for transaction controller. Take current state as seen by config registry, allow writing new data. */ public static ServiceReferenceWritableRegistry createSRWritableRegistry(ServiceReferenceReadableRegistry oldReadableRegistry, - LookupRegistry lookupRegistry, Map> currentlyRegisteredFactories) { + ConfigTransactionLookupRegistry txLookupRegistry, + Map> currentlyRegisteredFactories) { + if (txLookupRegistry == null) { + throw new IllegalArgumentException("txLookupRegistry is null"); + } ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldReadableRegistry; Map factories = extractFactoriesMap(currentlyRegisteredFactories); - return new ServiceReferenceRegistryImpl(factories, lookupRegistry, Collections.unmodifiableMap(old.refNames)); + ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory = new ServiceReferenceTransactionRegistratorFactoryImpl( + txLookupRegistry.getTxModuleJMXRegistrator(), txLookupRegistry.getTxModuleJMXRegistrator().getTransactionName()); + ServiceReferenceRegistryImpl newRegistry = new ServiceReferenceRegistryImpl(factories, txLookupRegistry, + serviceReferenceRegistratorFactory, true); + copy(old, newRegistry, txLookupRegistry.getTransactionIdentifier().getName()); + return newRegistry; } /** * Copy back state to config registry after commit. */ - public static ServiceReferenceReadableRegistry createSRReadableRegistry(ServiceReferenceWritableRegistry oldWritableRegistry, LookupRegistry lookupRegistry) { + public static CloseableServiceReferenceReadableRegistry createSRReadableRegistry(ServiceReferenceWritableRegistry oldWritableRegistry, + LookupRegistry lookupRegistry, BaseJMXRegistrator baseJMXRegistrator) { ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldWritableRegistry; + // even if factories do change, nothing in the mapping can change between transactions - return new ServiceReferenceRegistryImpl(old.factories, lookupRegistry, Collections.unmodifiableMap(old.refNames)); + ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory = new ServiceReferenceTransactionRegistratorFactoryImpl(baseJMXRegistrator); + ServiceReferenceRegistryImpl newRegistry = new ServiceReferenceRegistryImpl(old.factories, lookupRegistry, + serviceReferenceRegistratorFactory, false); + copy(old, newRegistry, null); + return newRegistry; + } + + /** + * Fill refNames and mBeans maps from old instance + */ + private static void copy(ServiceReferenceRegistryImpl old, ServiceReferenceRegistryImpl newRegistry, String nullableDstTransactionName) { + for (Entry> refNameEntry : old.mBeans.entrySet()) { + ObjectName currentImplementation; + ObjectName currentImplementationSrc = refNameEntry.getValue().getKey().getCurrentImplementation(); + if (nullableDstTransactionName != null) { + currentImplementation = ObjectNameUtil.withTransactionName(currentImplementationSrc, nullableDstTransactionName); + } else { + currentImplementation = ObjectNameUtil.withoutTransactionName(currentImplementationSrc); + } + try { + boolean skipChecks = true; + newRegistry.saveServiceReference(refNameEntry.getKey(), currentImplementation, skipChecks); + } catch (InstanceNotFoundException e) { + logger.error("Cannot save service reference({}, {})", refNameEntry.getKey(), currentImplementation); + throw new IllegalStateException("Possible code error", e); + } + } } private static Map extractFactoriesMap(Map> currentlyRegisteredFactories) { @@ -114,9 +187,14 @@ public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableReg } private ServiceReferenceRegistryImpl(Map factories, LookupRegistry lookupRegistry, - Map> refNamesToCopy) { + ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory, + boolean writable) { this.factories = factories; + this.writable = writable; this.lookupRegistry = lookupRegistry; + + this.serviceReferenceRegistrator = serviceReferenceRegistratorFactory.create(); + Map> factoryNamesToQNames = new HashMap<>(); Set allAnnotations = new HashSet<>(); Set allQNames = new HashSet<>(); @@ -154,22 +232,12 @@ public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableReg } this.namespacesToAnnotations = Collections.unmodifiableMap(namespacesToAnnotations); // copy refNames - Map> deepCopy = new HashMap<>(); - for (Entry> outerROEntry: refNamesToCopy.entrySet()) { - Map innerWritableMap = new HashMap<>(); - deepCopy.put(outerROEntry.getKey(), innerWritableMap); - for (Entry innerROEntry: outerROEntry.getValue().entrySet()) { - innerWritableMap.put(innerROEntry.getKey(), innerROEntry.getValue()); - } - } - this.refNames = deepCopy; logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames); - logger.trace("refNames:{}", refNames); } @Override - public Set lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException { + public synchronized Set lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException { lookupRegistry.checkConfigBeanExists(objectName); String factoryName = ObjectNameUtil.getFactoryName(objectName); @@ -183,7 +251,7 @@ public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableReg } @Override - public String getServiceInterfaceName(String namespace, String localName) { + public synchronized String getServiceInterfaceName(String namespace, String localName) { Map ofNamespace = namespacesToAnnotations.get(namespace); if (ofNamespace == null) { logger.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations); @@ -197,23 +265,19 @@ public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableReg return sia.value(); } - - // reading: @Override - public Map> getServiceMapping() { + public synchronized Map> getServiceMapping() { Map> result = new HashMap<>(); - for (Entry> outerEntry: refNames.entrySet()) { - String qName = outerEntry.getKey(); - Map innerMap = new HashMap<>(); - result.put(qName, innerMap); - for (Entry innerEntry: outerEntry.getValue().entrySet()) { - ModuleIdentifier moduleIdentifier = innerEntry.getValue(); - ObjectName on; - on = getObjectName(moduleIdentifier); - innerMap.put(innerEntry.getKey(), on); + for (Entry entry: refNames.entrySet()) { + String qName = entry.getKey().getServiceInterfaceName(); + Map innerMap = result.get(qName); + if (innerMap == null) { + innerMap = new HashMap<>(); + result.put(qName, innerMap); } + innerMap.put(entry.getKey().getRefName(), getObjectName(entry.getValue())); } return result; } @@ -230,116 +294,227 @@ public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableReg } @Override - public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) { - Map innerMap = refNames.get(serviceInterfaceName); - if (innerMap == null) { - logger.error("Cannot find qname {} in {}", serviceInterfaceName, refName); - throw new IllegalArgumentException("Cannot find " + serviceInterfaceName); - } - ModuleIdentifier moduleIdentifier = innerMap.get(refName); + public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { + ServiceReference serviceReference = new ServiceReference(serviceInterfaceQName, refName); + ModuleIdentifier moduleIdentifier = refNames.get(serviceReference); if (moduleIdentifier == null) { - logger.error("Cannot find refName {} in {}, using qname {}", refName, innerMap, serviceInterfaceName); - throw new IllegalArgumentException("Cannot find module based on service reference " + refName); + logger.error("Cannot find qname {} and refName {} in {}", serviceInterfaceQName, refName, refName); + throw new IllegalArgumentException("Cannot find " + serviceReference); } return getObjectName(moduleIdentifier); } @Override - public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) { - Map innerMap = refNames.get(serviceInterfaceName); + public synchronized Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { + Map> serviceMapping = getServiceMapping(); + Map innerMap = serviceMapping.get(serviceInterfaceQName); if (innerMap == null) { - logger.error("Cannot find qname {} in {}", serviceInterfaceName, refNames); - throw new IllegalArgumentException("Cannot find " + serviceInterfaceName); + logger.error("Cannot find qname {} in {}", serviceInterfaceQName, refNames); + throw new IllegalArgumentException("Cannot find " + serviceInterfaceQName); } - Map result = new HashMap<>(); - for (Entry entry: innerMap.entrySet()) { - ObjectName on = getObjectName(entry.getValue()); - result.put(entry.getKey(), on); + return innerMap; + } + + @Override + public synchronized ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException { + ServiceReference serviceReference = new ServiceReference(serviceInterfaceQName, refName); + if (mBeans.containsKey(serviceReference) == false) { + throw new InstanceNotFoundException("Cannot find " + serviceReference); + } + return getServiceON(serviceReference); + } + + @Override + public synchronized void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException { + String actualTransactionName = ObjectNameUtil.getTransactionName(objectName); + String expectedTransactionName = serviceReferenceRegistrator.getNullableTransactionName(); + if (writable & actualTransactionName == null || (writable && actualTransactionName.equals(expectedTransactionName) == false)) { + throw new IllegalArgumentException("Mismatched transaction name in " + objectName); + } + String serviceQName = ObjectNameUtil.getServiceQName(objectName); + String referenceName = ObjectNameUtil.getReferenceName(objectName); + ServiceReference serviceReference = new ServiceReference(serviceQName, referenceName); + if (refNames.containsKey(serviceReference) == false) { + logger.warn("Cannot find {} in {}", serviceReference, refNames); + throw new InstanceNotFoundException("Service reference not found:" + objectName); } - return result; } // writing: + private void assertWritable() { + if (writable == false) { + throw new IllegalStateException("Cannot write to readable registry"); + } + } + @Override - public void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException { + public synchronized ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException { + assertWritable(); + ServiceReference serviceReference = new ServiceReference(serviceInterfaceName, refName); + return saveServiceReference(serviceReference, moduleON); + } + + private synchronized ObjectName saveServiceReference(ServiceReference serviceReference, ObjectName moduleON) + throws InstanceNotFoundException{ + return saveServiceReference(serviceReference, moduleON, false); + } + + private synchronized ObjectName saveServiceReference(ServiceReference serviceReference, ObjectName moduleON, + boolean skipChecks) throws InstanceNotFoundException { + // make sure it is found - lookupRegistry.checkConfigBeanExists(objectName); - String factoryName = ObjectNameUtil.getFactoryName(objectName); + if (skipChecks == false) { + lookupRegistry.checkConfigBeanExists(moduleON); + } + String factoryName = ObjectNameUtil.getFactoryName(moduleON); + String instanceName = ObjectNameUtil.getInstanceName(moduleON); + ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName); + // check that service interface name exist - Set serviceInterfaceQNames = factoryNamesToQNames.get(factoryName); + Set serviceInterfaceQNames = factoryNamesToQNames.get(moduleIdentifier.getFactoryName()); if (serviceInterfaceQNames == null) { - logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, objectName); - throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName); + logger.error("Possible error in code: cannot find factoryName {} in {}, {}", moduleIdentifier.getFactoryName(), + factoryNamesToQNames, moduleIdentifier); + throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + moduleIdentifier.getFactoryName()); } // supplied serviceInterfaceName must exist in this collection - if (serviceInterfaceQNames.contains(serviceInterfaceName) == false) { - logger.error("Cannot find qname {} with factory name {}, found {}", serviceInterfaceName, factoryName, serviceInterfaceQNames); - throw new IllegalArgumentException("Cannot find service interface " + serviceInterfaceName + " within factory " + factoryName ); + if (serviceInterfaceQNames.contains(serviceReference.getServiceInterfaceName()) == false) { + logger.error("Cannot find qName {} with factory name {}, found {}", serviceReference.getServiceInterfaceName(), moduleIdentifier.getFactoryName(), serviceInterfaceQNames); + throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceName() + " within factory " + moduleIdentifier.getFactoryName()); } - String instanceName = ObjectNameUtil.getInstanceName(objectName); - ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName); - Map ofQName = refNames.get(serviceInterfaceName); - // might be null - if (ofQName == null) { - ofQName = new HashMap<>(); - refNames.put(serviceInterfaceName, ofQName); + + + // create service reference object name, put to mBeans + ObjectName result = getServiceON(serviceReference); + Entry mxBeanEntry = mBeans.get(serviceReference); + if (mxBeanEntry == null) { + // create dummy mx bean + ServiceReferenceMXBeanImpl dummyMXBean = new ServiceReferenceMXBeanImpl(moduleON); + ServiceReferenceJMXRegistration dummyMXBeanRegistration; + try { + dummyMXBeanRegistration = serviceReferenceRegistrator.registerMBean(dummyMXBean, result); + } catch (InstanceAlreadyExistsException e) { + throw new IllegalStateException("Possible error in code. Cannot register " + result, e); + } + mBeans.put(serviceReference, createMXBeanEntry(dummyMXBean, dummyMXBeanRegistration)); + } else { + // update + mxBeanEntry.getKey().setCurrentImplementation(moduleON); + } + // save to refNames + refNames.put(serviceReference, moduleIdentifier); + return result; + } + + private Entry createMXBeanEntry( + final ServiceReferenceMXBeanImpl mxBean, final ServiceReferenceJMXRegistration registration) { + return new Entry() { + @Override + public ServiceReferenceMXBeanImpl getKey() { + return mxBean; + } + + @Override + public ServiceReferenceJMXRegistration getValue() { + return registration; + } + + @Override + public ServiceReferenceJMXRegistration setValue(ServiceReferenceJMXRegistration value) { + throw new UnsupportedOperationException(); + } + }; + } + + private ObjectName getServiceON(ServiceReference serviceReference) { + if (writable) { + return ObjectNameUtil.createTransactionServiceON(serviceReferenceRegistrator.getNullableTransactionName(), + serviceReference.getServiceInterfaceName(), serviceReference.getRefName()); + } else { + return ObjectNameUtil.createReadOnlyServiceON(serviceReference.getServiceInterfaceName(), serviceReference.getRefName()); } - ofQName.put(refName, moduleIdentifier); } @Override - public boolean removeServiceReference(String serviceInterfaceName, String refName) { - // is the qname known? - if (allQNames.contains(serviceInterfaceName) == false) { - logger.error("Cannot find qname {} in {}", serviceInterfaceName, allQNames); - throw new IllegalArgumentException("Cannot find service interface " + serviceInterfaceName); + public synchronized void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException{ + ServiceReference serviceReference = new ServiceReference(serviceInterfaceName, refName); + removeServiceReference(serviceReference); + } + + private synchronized void removeServiceReference(ServiceReference serviceReference) throws InstanceNotFoundException { + logger.debug("Removing service reference {} from {}", serviceReference, this); + assertWritable(); + // is the qName known? + if (allQNames.contains(serviceReference.getServiceInterfaceName()) == false) { + logger.error("Cannot find qname {} in {}", serviceReference.getServiceInterfaceName(), allQNames); + throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceName()); + } + ModuleIdentifier removed = refNames.remove(serviceReference); + if (removed == null){ + throw new InstanceNotFoundException("Cannot find " + serviceReference.getServiceInterfaceName()); } - Map ofQName = refNames.get(serviceInterfaceName); - if (ofQName == null) { - return false; + Entry entry = mBeans.remove(serviceReference); + if (entry == null) { + throw new IllegalStateException("Possible code error: cannot remove from mBeans: " + serviceReference); } - return ofQName.remove(refName) != null; + entry.getValue().close(); } @Override - public void removeAllServiceReferences() { - refNames.clear(); + public synchronized void removeAllServiceReferences() { + assertWritable(); + for (ServiceReference serviceReference: mBeans.keySet()) { + try { + removeServiceReference(serviceReference); + } catch (InstanceNotFoundException e) { + throw new IllegalStateException("Possible error in code", e); + } + } } @Override - public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException { - lookupRegistry.checkConfigBeanExists(objectName); - String factoryName = ObjectNameUtil.getFactoryName(objectName); + public synchronized boolean removeServiceReferences(ObjectName moduleObjectName) throws InstanceNotFoundException { + assertWritable(); + Set serviceReferencesLinkingTo = findServiceReferencesLinkingTo(moduleObjectName); + for (ServiceReference sr : serviceReferencesLinkingTo) { + removeServiceReference(sr); + } + return serviceReferencesLinkingTo.isEmpty() == false; + } + + private synchronized Set findServiceReferencesLinkingTo(ObjectName moduleObjectName) throws InstanceNotFoundException { + lookupRegistry.checkConfigBeanExists(moduleObjectName); + String factoryName = ObjectNameUtil.getFactoryName(moduleObjectName); // check that service interface name exist Set serviceInterfaceQNames = factoryNamesToQNames.get(factoryName); if (serviceInterfaceQNames == null) { - logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, objectName); + logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, moduleObjectName); throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName); } - String instanceName = ObjectNameUtil.getInstanceName(objectName); + String instanceName = ObjectNameUtil.getInstanceName(moduleObjectName); ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName); - boolean found = false; - for(String qName: serviceInterfaceQNames){ - Map ofQName = refNames.get(qName); - if (ofQName != null) { - for(Iterator> it = ofQName.entrySet ().iterator(); it.hasNext();){ - Entry next = it.next(); - if (next.getValue().equals(moduleIdentifier)) { - found = true; - it.remove(); - } - } + Set result = new HashSet<>(); + for (Entry entry : refNames.entrySet()) { + if (entry.getValue().equals(moduleIdentifier)) { + result.add(entry.getKey()); } } - return found; + return result; } + @Override public String toString() { return "ServiceReferenceRegistryImpl{" + + "lookupRegistry=" + lookupRegistry + "refNames=" + refNames + ", factoryNamesToQNames=" + factoryNamesToQNames + '}'; } + + @Override + public void close() { + serviceReferenceRegistrator.close(); + } } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java index 760fe50e28..925a57b044 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java @@ -11,6 +11,7 @@ import org.opendaylight.controller.config.api.DependencyResolver; import org.opendaylight.controller.config.api.JmxAttribute; import org.opendaylight.controller.config.api.JmxAttributeValidationException; import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.config.manager.impl.TransactionStatus; @@ -37,12 +38,16 @@ final class DependencyResolverImpl implements DependencyResolver, private final TransactionStatus transactionStatus; @GuardedBy("this") private final Set dependencies = new HashSet<>(); + private final ServiceReferenceReadableRegistry readableRegistry; DependencyResolverImpl(ModuleIdentifier currentModule, - TransactionStatus transactionStatus, ModulesHolder modulesHolder) { + TransactionStatus transactionStatus, ModulesHolder modulesHolder, + ServiceReferenceReadableRegistry readableRegistry) { + this.name = currentModule; this.transactionStatus = transactionStatus; this.modulesHolder = modulesHolder; + this.readableRegistry = readableRegistry; } /** @@ -52,7 +57,7 @@ final class DependencyResolverImpl implements DependencyResolver, @Override public void validateDependency( Class expectedServiceInterface, - ObjectName dependentModuleReadOnlyON, JmxAttribute jmxAttribute) { + ObjectName dependentReadOnlyON, JmxAttribute jmxAttribute) { transactionStatus.checkNotCommitted(); if (expectedServiceInterface == null) { @@ -62,22 +67,26 @@ final class DependencyResolverImpl implements DependencyResolver, if (jmxAttribute == null) throw new NullPointerException("Parameter 'jmxAttribute' is null"); - JmxAttributeValidationException.checkNotNull(dependentModuleReadOnlyON, + JmxAttributeValidationException.checkNotNull(dependentReadOnlyON, "is null, " + "expected dependency implementing " + expectedServiceInterface, jmxAttribute); + + // check that objectName belongs to this transaction - this should be // stripped // in DynamicWritableWrapper boolean hasTransaction = ObjectNameUtil - .getTransactionName(dependentModuleReadOnlyON) != null; + .getTransactionName(dependentReadOnlyON) != null; JmxAttributeValidationException.checkCondition( hasTransaction == false, format("ObjectName should not contain " + "transaction name. %s set to %s. ", jmxAttribute, - dependentModuleReadOnlyON), jmxAttribute); + dependentReadOnlyON), jmxAttribute); + + dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON); - ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentModuleReadOnlyON, ObjectNameUtil + ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentReadOnlyON, ObjectNameUtil .TYPE_MODULE); ModuleFactory foundFactory = modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute); @@ -90,7 +99,7 @@ final class DependencyResolverImpl implements DependencyResolver, + "Module name is %s : %s, expected service interface %s, dependent module ON %s , " + "attribute %s", foundFactory.getImplementationName(), foundFactory, - expectedServiceInterface, dependentModuleReadOnlyON, + expectedServiceInterface, dependentReadOnlyON, jmxAttribute); throw new JmxAttributeValidationException(message, jmxAttribute); } @@ -99,24 +108,35 @@ final class DependencyResolverImpl implements DependencyResolver, } } + // transalate from serviceref to module ON + private ObjectName translateServiceRefIfPossible(ObjectName dependentReadOnlyON) { + if (ObjectNameUtil.isServiceReference(dependentReadOnlyON)) { + String serviceQName = ObjectNameUtil.getServiceQName(dependentReadOnlyON); + String refName = ObjectNameUtil.getReferenceName(dependentReadOnlyON); + dependentReadOnlyON = ObjectNameUtil.withoutTransactionName( // strip again of transaction name + readableRegistry.lookupConfigBeanByServiceInterfaceName(serviceQName, refName)); + } + return dependentReadOnlyON; + } + /** * {@inheritDoc} */ //TODO: check for cycles @Override - public T resolveInstance(Class expectedType, ObjectName dependentON, + public T resolveInstance(Class expectedType, ObjectName dependentReadOnlyON, JmxAttribute jmxAttribute) { - if (expectedType == null || dependentON == null || jmxAttribute == null) { + if (expectedType == null || dependentReadOnlyON == null || jmxAttribute == null) { throw new IllegalArgumentException(format( "Null parameters not allowed, got {} {} {}", expectedType, - dependentON, jmxAttribute)); + dependentReadOnlyON, jmxAttribute)); } - + dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON); transactionStatus.checkCommitStarted(); transactionStatus.checkNotCommitted(); ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON( - dependentON, ObjectNameUtil.TYPE_MODULE); + dependentReadOnlyON, ObjectNameUtil.TYPE_MODULE); Module module = modulesHolder.findModule(dependentModuleIdentifier, jmxAttribute); synchronized (this) { diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java index 645aab37ff..afd865c4fc 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java @@ -11,6 +11,7 @@ import org.opendaylight.controller.config.api.DependencyResolver; import org.opendaylight.controller.config.api.DependencyResolverFactory; import org.opendaylight.controller.config.api.JmxAttribute; import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.manager.impl.CommitInfo; import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo; import org.opendaylight.controller.config.manager.impl.TransactionStatus; @@ -35,11 +36,13 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR private final Map moduleIdentifiersToDependencyResolverMap = new HashMap<>(); private final ModulesHolder modulesHolder; private final TransactionStatus transactionStatus; + private final ServiceReferenceReadableRegistry readableRegistry; public DependencyResolverManager(String transactionName, - TransactionStatus transactionStatus) { + TransactionStatus transactionStatus, ServiceReferenceReadableRegistry readableRegistry) { this.modulesHolder = new ModulesHolder(transactionName); this.transactionStatus = transactionStatus; + this.readableRegistry = readableRegistry; } @Override @@ -48,14 +51,11 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR } public synchronized DependencyResolverImpl getOrCreate(ModuleIdentifier name) { - DependencyResolverImpl dependencyResolver = moduleIdentifiersToDependencyResolverMap - .get(name); + DependencyResolverImpl dependencyResolver = moduleIdentifiersToDependencyResolverMap.get(name); if (dependencyResolver == null) { transactionStatus.checkNotCommitted(); - dependencyResolver = new DependencyResolverImpl(name, - transactionStatus, modulesHolder); - moduleIdentifiersToDependencyResolverMap.put(name, - dependencyResolver); + dependencyResolver = new DependencyResolverImpl(name, transactionStatus, modulesHolder, readableRegistry); + moduleIdentifiersToDependencyResolverMap.put(name, dependencyResolver); } return dependencyResolver; } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java index ba2c1089c2..6f0d1b2682 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java @@ -7,16 +7,14 @@ */ package org.opendaylight.controller.config.manager.impl.dynamicmbean; -import static java.lang.String.format; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.annotations.Description; +import org.opendaylight.controller.config.api.annotations.RequireInterface; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper; +import org.opendaylight.controller.config.spi.Module; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.management.Attribute; import javax.management.AttributeList; @@ -40,15 +38,17 @@ import javax.management.Notification; import javax.management.NotificationListener; import javax.management.ObjectName; import javax.management.ReflectionException; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; -import org.opendaylight.controller.config.api.ModuleIdentifier; -import org.opendaylight.controller.config.api.annotations.Description; -import org.opendaylight.controller.config.api.annotations.RequireInterface; -import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; -import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper; -import org.opendaylight.controller.config.spi.Module; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static java.lang.String.format; /** * Contains common code for readable/rw dynamic mbean wrappers. Routes all @@ -246,6 +246,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { } catch (InstanceNotFoundException e) { new MBeanException(e); } + if (obj instanceof ObjectName) { AttributeHolder attributeHolder = attributeHolderMap .get(attributeName); @@ -254,8 +255,42 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { } return obj; } + + + if(isDependencyListAttr(attributeName, obj)) { + obj = fixDependencyListAttribute(obj); + } + return obj; + } + + private Object fixDependencyListAttribute(Object attribute) { + if(attribute.getClass().isArray() == false) + throw new IllegalArgumentException("Unexpected attribute type, should be an array, but was " + attribute.getClass()); + + for (int i = 0; i < Array.getLength(attribute); i++) { + + Object on = Array.get(attribute, i); + if(on instanceof ObjectName == false) + throw new IllegalArgumentException("Unexpected attribute type, should be an ObjectName, but was " + on.getClass()); + on = fixObjectName((ObjectName) on); + + Array.set(attribute, i, on); + } + + return attribute; + } + + private boolean isDependencyListAttr(String attributeName, Object attribute) { + if (attributeHolderMap.containsKey(attributeName) == false) + return false; + + AttributeHolder attributeHolder = attributeHolderMap.get(attributeName); + boolean isDepList = true; + isDepList &= attributeHolder.getRequireInterfaceOrNull() != null; + isDepList &= attribute instanceof ObjectName[]; + return isDepList; } protected ObjectName fixObjectName(ObjectName on) { diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java index 109ab10ac2..9dd6a2269e 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java @@ -7,18 +7,17 @@ */ package org.opendaylight.controller.config.manager.impl.dynamicmbean; -import java.lang.reflect.Method; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import org.opendaylight.controller.config.api.annotations.Description; +import org.opendaylight.controller.config.api.annotations.RequireInterface; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.management.MBeanAttributeInfo; import javax.management.ObjectName; - -import org.opendaylight.controller.config.api.annotations.Description; -import org.opendaylight.controller.config.api.annotations.RequireInterface; +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.List; +import java.util.Set; @Immutable class AttributeHolder { @@ -32,6 +31,14 @@ class AttributeHolder { private final RequireInterface requireInterfaceAnnotation; private final String attributeType; + public static final Set> PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER = new HashSet<>(); + + static { + PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.add(ObjectName.class); + PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.add(ObjectName[].class); + PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.add(List.class); + } + public AttributeHolder(String name, Object object, String returnType, boolean writable, @Nullable RequireInterface requireInterfaceAnnotation, @@ -114,12 +121,12 @@ class AttributeHolder { static RequireInterface findRequireInterfaceAnnotation(final Method setter, Set> inspectedInterfaces) { - // only allow setX(ObjectName y) or setX(ObjectName[] y) to continue - if (setter.getParameterTypes().length != 1 - || (setter.getParameterTypes()[0].equals(ObjectName.class) == false && setter - .getParameterTypes()[0].equals(ObjectName[].class) == false)) { + // only allow setX(ObjectName y) or setX(ObjectName[] y) or setX(List y) to continue + + if (setter.getParameterTypes().length > 1) + return null; + if(PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.contains(setter.getParameterTypes()[0]) == false) return null; - } List foundRequireInterfaces = AnnotationsHelper .findMethodAnnotationInSuperClassesAndIfcs(setter, RequireInterface.class, inspectedInterfaces); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java index a1cd6b0133..2ab04e53e3 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java @@ -7,7 +7,13 @@ */ package org.opendaylight.controller.config.manager.impl.dynamicmbean; -import java.lang.reflect.Method; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.ValidationException; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.config.manager.impl.TransactionIdentifier; +import org.opendaylight.controller.config.spi.Module; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.concurrent.ThreadSafe; import javax.management.Attribute; @@ -20,14 +26,7 @@ import javax.management.MBeanOperationInfo; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.ReflectionException; - -import org.opendaylight.controller.config.api.ModuleIdentifier; -import org.opendaylight.controller.config.api.ValidationException; -import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; -import org.opendaylight.controller.config.manager.impl.TransactionIdentifier; -import org.opendaylight.controller.config.spi.Module; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.lang.reflect.Method; /** * Wraps {@link org.opendaylight.controller.config.spi.Module} instance in a @@ -92,16 +91,11 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper { try { if (attribute.getValue() instanceof ObjectName) { - AttributeHolder attributeHolder = attributeHolderMap - .get(attribute.getName()); - if (attributeHolder.getRequireInterfaceOrNull() != null) { - attribute = new Attribute(attribute.getName(), - fixObjectName((ObjectName) attribute.getValue())); - } else { - attribute = new Attribute(attribute.getName(), - attribute.getValue()); - } + attribute = fixDependencyAttribute(attribute); + } else if(attribute.getValue() instanceof ObjectName[]) { + attribute = fixDependencyListAttribute(attribute); } + internalServer.setAttribute(objectNameInternal, attribute); } catch (InstanceNotFoundException e) { throw new MBeanException(e); @@ -109,6 +103,39 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper { } + private Attribute fixDependencyListAttribute(Attribute attribute) { + AttributeHolder attributeHolder = attributeHolderMap + .get(attribute.getName()); + if (attributeHolder.getRequireInterfaceOrNull() != null) { + attribute = new Attribute(attribute.getName(), + fixObjectNames((ObjectName[]) attribute.getValue())); + } + return attribute; + } + + private Attribute fixDependencyAttribute(Attribute attribute) { + AttributeHolder attributeHolder = attributeHolderMap + .get(attribute.getName()); + if (attributeHolder.getRequireInterfaceOrNull() != null) { + attribute = new Attribute(attribute.getName(), + fixObjectName((ObjectName) attribute.getValue())); + } else { + attribute = new Attribute(attribute.getName(), + attribute.getValue()); + } + return attribute; + } + + private ObjectName[] fixObjectNames(ObjectName[] dependencies) { + int i = 0; + + for (ObjectName dependencyOn : dependencies) { + dependencies[i++] = fixObjectName(dependencyOn); + } + + return dependencies; + } + @Override public AttributeList setAttributes(AttributeList attributes) { AttributeList result = new AttributeList(); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/BaseJMXRegistrator.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/BaseJMXRegistrator.java index 09bc1f818f..d09fc75d73 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/BaseJMXRegistrator.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/BaseJMXRegistrator.java @@ -14,7 +14,7 @@ import javax.management.ObjectName; import javax.management.QueryExp; import java.util.Set; -public class BaseJMXRegistrator implements AutoCloseable { +public class BaseJMXRegistrator implements AutoCloseable, NestableJMXRegistrator { private final InternalJMXRegistrator internalJMXRegistrator; @@ -50,6 +50,11 @@ public class BaseJMXRegistrator implements AutoCloseable { return internalJMXRegistrator.getRegisteredObjectNames(); } + @Override + public InternalJMXRegistrator createChild() { + return internalJMXRegistrator.createChild(); + } + @Override public void close() { internalJMXRegistrator.close(); diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/KeyStoreHandler.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/NestableJMXRegistrator.java similarity index 62% rename from opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/KeyStoreHandler.java rename to opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/NestableJMXRegistrator.java index 59a911b207..ff78e0257b 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/KeyStoreHandler.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/NestableJMXRegistrator.java @@ -5,10 +5,9 @@ * 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.netconf.ssh.authentication; +package org.opendaylight.controller.config.manager.impl.jmx; -import ch.ethz.ssh2.signature.RSAPrivateKey; +public interface NestableJMXRegistrator { -public interface KeyStoreHandler { - public RSAPrivateKey getPrivateKey(); + InternalJMXRegistrator createChild(); } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReference.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReference.java new file mode 100644 index 0000000000..849f75234f --- /dev/null +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReference.java @@ -0,0 +1,45 @@ +/* + * 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.config.manager.impl.jmx; + +public class ServiceReference { + private final String serviceInterfaceName, refName; + + public ServiceReference(String serviceInterfaceName, String refName) { + this.serviceInterfaceName = serviceInterfaceName; + this.refName = refName; + } + + public String getServiceInterfaceName() { + return serviceInterfaceName; + } + + public String getRefName() { + return refName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ServiceReference that = (ServiceReference) o; + + if (!refName.equals(that.refName)) return false; + if (!serviceInterfaceName.equals(that.serviceInterfaceName)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = serviceInterfaceName.hashCode(); + result = 31 * result + refName.hashCode(); + return result; + } +} diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReferenceMXBean.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReferenceMXBean.java new file mode 100644 index 0000000000..759541dc26 --- /dev/null +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReferenceMXBean.java @@ -0,0 +1,16 @@ +/* + * 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.config.manager.impl.jmx; + +import javax.management.ObjectName; + +public interface ServiceReferenceMXBean { + + ObjectName getCurrentImplementation(); + +} diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReferenceMXBeanImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReferenceMXBeanImpl.java new file mode 100644 index 0000000000..dedeeed789 --- /dev/null +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReferenceMXBeanImpl.java @@ -0,0 +1,27 @@ +/* + * 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.config.manager.impl.jmx; + +import javax.management.ObjectName; + +public class ServiceReferenceMXBeanImpl implements ServiceReferenceMXBean { + private ObjectName currentImplementation; + + public ServiceReferenceMXBeanImpl(ObjectName currentImplementation) { + this.currentImplementation = currentImplementation; + } + + @Override + public ObjectName getCurrentImplementation() { + return currentImplementation; + } + + public void setCurrentImplementation(ObjectName currentImplementation) { + this.currentImplementation = currentImplementation; + } +} diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReferenceRegistrator.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReferenceRegistrator.java new file mode 100644 index 0000000000..160ee1888a --- /dev/null +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReferenceRegistrator.java @@ -0,0 +1,103 @@ +/* + * 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.config.manager.impl.jmx; + +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.config.manager.impl.jmx.InternalJMXRegistrator.InternalJMXRegistration; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.ObjectName; + +public interface ServiceReferenceRegistrator extends AutoCloseable { + + public String getNullableTransactionName(); + + ServiceReferenceJMXRegistration registerMBean(ServiceReferenceMXBeanImpl object, + ObjectName on) throws InstanceAlreadyExistsException; + + @Override + void close(); + + public static class ServiceReferenceJMXRegistration implements AutoCloseable { + private final InternalJMXRegistration registration; + + ServiceReferenceJMXRegistration(InternalJMXRegistration registration) { + this.registration = registration; + } + + @Override + public void close() { + registration.close(); + } + } + + public static interface ServiceReferenceTransactionRegistratorFactory { + public ServiceReferenceRegistrator create(); + } + + public static class ServiceReferenceRegistratorImpl implements ServiceReferenceRegistrator { + private final InternalJMXRegistrator currentJMXRegistrator; + private final String nullableTransactionName; + + public ServiceReferenceRegistratorImpl(NestableJMXRegistrator parentRegistrator, String nullableTransactionName){ + currentJMXRegistrator = parentRegistrator.createChild(); + this.nullableTransactionName = nullableTransactionName; + } + + public String getNullableTransactionName() { + return nullableTransactionName; + } + + + public ServiceReferenceJMXRegistration registerMBean(ServiceReferenceMXBeanImpl object, + ObjectName on) throws InstanceAlreadyExistsException { + String actualTransactionName = ObjectNameUtil.getTransactionName(on); + boolean broken = false; + broken |= (nullableTransactionName == null) != (actualTransactionName == null); + broken |= (nullableTransactionName != null) && nullableTransactionName.equals(actualTransactionName) == false; + if (broken) { + throw new IllegalArgumentException("Transaction name mismatch between expected " + + nullableTransactionName + ", got " + actualTransactionName + " in " + on); + } + if (ObjectNameUtil.isServiceReference(on) == false) { + throw new IllegalArgumentException("Invalid type of " + on); + } + return new ServiceReferenceJMXRegistration(currentJMXRegistrator.registerMBean(object, on)); + } + + + @Override + public void close() { + currentJMXRegistrator.close(); + } + public static interface ServiceReferenceTransactionRegistratorFactory { + public ServiceReferenceRegistrator create(); + } + } + + + public static class ServiceReferenceTransactionRegistratorFactoryImpl implements ServiceReferenceTransactionRegistratorFactory { + private final NestableJMXRegistrator parentRegistrator; + private final String nullableTransactionName; + + public ServiceReferenceTransactionRegistratorFactoryImpl(TransactionModuleJMXRegistrator parentRegistrator, + String nullableTransactionName) { + this.parentRegistrator = parentRegistrator; + this.nullableTransactionName = nullableTransactionName; + } + + public ServiceReferenceTransactionRegistratorFactoryImpl(BaseJMXRegistrator baseJMXRegistrator) { + this.parentRegistrator = baseJMXRegistrator; + this.nullableTransactionName = null; + } + + public ServiceReferenceRegistrator create() { + return new ServiceReferenceRegistratorImpl(parentRegistrator, nullableTransactionName); + } + } +} diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/TransactionModuleJMXRegistrator.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/TransactionModuleJMXRegistrator.java index 546adb0d89..238fd2447e 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/TransactionModuleJMXRegistrator.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/TransactionModuleJMXRegistrator.java @@ -17,14 +17,14 @@ import javax.management.QueryExp; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.config.manager.impl.jmx.InternalJMXRegistrator.InternalJMXRegistration; -public class TransactionModuleJMXRegistrator implements Closeable { - private final InternalJMXRegistrator childJMXRegistrator; +public class TransactionModuleJMXRegistrator implements Closeable, NestableJMXRegistrator { + private final InternalJMXRegistrator currentJMXRegistrator; private final String transactionName; public TransactionModuleJMXRegistrator( InternalJMXRegistrator internalJMXRegistrator, String transactionName) { - this.childJMXRegistrator = internalJMXRegistrator.createChild(); + this.currentJMXRegistrator = internalJMXRegistrator.createChild(); this.transactionName = transactionName; } @@ -44,21 +44,29 @@ public class TransactionModuleJMXRegistrator implements Closeable { public TransactionModuleJMXRegistration registerMBean(Object object, ObjectName on) throws InstanceAlreadyExistsException { - if (!transactionName.equals(ObjectNameUtil.getTransactionName(on))) - throw new IllegalArgumentException( - "Transaction name mismatch between expected " + if (transactionName.equals(ObjectNameUtil.getTransactionName(on)) == false) { + throw new IllegalArgumentException("Transaction name mismatch between expected " + transactionName + " " + "and " + on); - ObjectNameUtil.checkType(on, ObjectNameUtil.TYPE_MODULE); + } + ObjectNameUtil.checkTypeOneOf(on, ObjectNameUtil.TYPE_MODULE); return new TransactionModuleJMXRegistration( - childJMXRegistrator.registerMBean(object, on)); + currentJMXRegistrator.registerMBean(object, on)); } public Set queryNames(ObjectName name, QueryExp query) { - return childJMXRegistrator.queryNames(name, query); + return currentJMXRegistrator.queryNames(name, query); } @Override public void close() { - childJMXRegistrator.close(); + currentJMXRegistrator.close(); + } + + public String getTransactionName() { + return transactionName; + } + + public InternalJMXRegistrator createChild() { + return currentJMXRegistrator.createChild(); } } 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 a7e3fa6c6f..81b0921660 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,13 +7,20 @@ */ package org.opendaylight.controller.config.manager.impl; +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import junit.framework.Assert; import org.junit.After; import org.mockito.Matchers; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.opendaylight.controller.config.api.jmx.CommitStatus; import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver; import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator; import org.opendaylight.controller.config.manager.impl.jmx.ConfigRegistryJMXRegistrator; import org.opendaylight.controller.config.manager.impl.jmx.InternalJMXRegistrator; +import org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool.TestingScheduledThreadPoolImpl; +import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.controller.config.util.ConfigRegistryJMXClient; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; @@ -24,14 +31,20 @@ import javax.management.InstanceAlreadyExistsException; import javax.management.MBeanServer; import javax.management.ObjectName; import java.io.Closeable; +import java.io.InputStream; import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.Dictionary; +import java.util.List; +import java.util.Map; import java.util.Set; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; /** @@ -53,6 +66,10 @@ public abstract class AbstractConfigTest extends protected BundleContext mockedContext = mock(BundleContext.class); protected ServiceRegistration mockedServiceRegistration; + protected Map getBundleContextServiceRegistrationHandlers() { + return Maps.newHashMap(); + } + // this method should be called in @Before protected void initConfigTransactionManagerImpl( ModuleFactoriesResolver resolver) { @@ -61,17 +78,14 @@ public abstract class AbstractConfigTest extends configRegistryJMXRegistrator = new ConfigRegistryJMXRegistrator( platformMBeanServer); - this.mockedServiceRegistration = mock(ServiceRegistration.class); - doNothing().when(mockedServiceRegistration).unregister(); - doReturn(mockedServiceRegistration).when(mockedContext).registerService( - Matchers.any(String[].class), any(Closeable.class), - any(Dictionary.class)); + initBundleContext(); internalJmxRegistrator = new InternalJMXRegistrator(platformMBeanServer); baseJmxRegistrator = new BaseJMXRegistrator(internalJmxRegistrator); configRegistry = new ConfigRegistryImpl(resolver, platformMBeanServer, baseJmxRegistrator); + try { configRegistryJMXRegistrator.registerToJMX(configRegistry); } catch (InstanceAlreadyExistsException e) { @@ -80,10 +94,41 @@ public abstract class AbstractConfigTest extends configRegistryClient = new ConfigRegistryJMXClient(platformMBeanServer); } + private void initBundleContext() { + this.mockedServiceRegistration = mock(ServiceRegistration.class); + doNothing().when(mockedServiceRegistration).unregister(); + + RegisterServiceAnswer answer = new RegisterServiceAnswer(); + + doAnswer(answer).when(mockedContext).registerService(Matchers.any(String[].class), + any(Closeable.class), Matchers.>any()); + doAnswer(answer).when(mockedContext).registerService(Matchers.>any(), any(Closeable.class), + Matchers.>any()); + } + + + public Collection getFilesAsInputStreams(List paths) { + final Collection resources = new ArrayList<>(); + List failedToFind = new ArrayList<>(); + for (String path : paths) { + InputStream resourceAsStream = getClass().getResourceAsStream(path); + if (resourceAsStream == null) { + failedToFind.add(path); + } else { + resources.add(resourceAsStream); + } + } + Assert.assertEquals("Some files were not found", Collections.emptyList(), failedToFind); + + return resources; + } + @After public final void cleanUpConfigTransactionManagerImpl() { configRegistryJMXRegistrator.close(); configRegistry.close(); + TestingFixedThreadPool.cleanUp(); + TestingScheduledThreadPoolImpl.cleanUp(); } /** @@ -111,10 +156,10 @@ public abstract class AbstractConfigTest extends protected void assertStatus(CommitStatus status, int expectedNewInstances, int expectedRecreatedInstances, int expectedReusedInstances) { - assertEquals(expectedNewInstances, status.getNewInstances().size()); - assertEquals(expectedRecreatedInstances, status.getRecreatedInstances() + assertEquals("New instances mismatch in " + status, expectedNewInstances, status.getNewInstances().size()); + assertEquals("Recreated instances mismatch in " + status, expectedRecreatedInstances, status.getRecreatedInstances() .size()); - assertEquals(expectedReusedInstances, status.getReusedInstances() + assertEquals("Reused instances mismatch in " + status, expectedReusedInstances, status.getReusedInstances() .size()); } @@ -150,4 +195,35 @@ public abstract class AbstractConfigTest extends Class configBeanClass, String implementationName) { return new ClassBasedModuleFactory(implementationName, configBeanClass); } + + + public static interface BundleContextServiceRegistrationHandler { + + void handleServiceRegistration(Object serviceInstance); + + } + + private class RegisterServiceAnswer implements Answer { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + + Preconditions.checkArgument(args.length == 3); + + Preconditions.checkArgument(args[0] instanceof Class); + Class serviceType = (Class) args[0]; + Object serviceInstance = args[1]; + + BundleContextServiceRegistrationHandler serviceRegistrationHandler = getBundleContextServiceRegistrationHandlers() + .get(serviceType); + + Preconditions.checkArgument(serviceType.isAssignableFrom(serviceInstance.getClass())); + + if (serviceRegistrationHandler != null) { + serviceRegistrationHandler.handleServiceRegistration(serviceType.cast(serviceInstance)); + } + + return mockedServiceRegistration; + } + } } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImplTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImplTest.java new file mode 100644 index 0000000000..6d0b340cd3 --- /dev/null +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImplTest.java @@ -0,0 +1,116 @@ +/* + * 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.config.manager.impl; + +import com.google.common.collect.ImmutableMap; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; +import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceMXBean; +import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPModuleFactory; +import org.opendaylight.controller.config.manager.testingservices.parallelapsp.test.AbstractParallelAPSPTest; +import org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool.TestingScheduledThreadPoolModuleFactory; +import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingThreadPoolServiceInterface; +import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory; +import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; + +import javax.management.Attribute; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.JMX; +import javax.management.MBeanException; +import javax.management.ObjectName; +import javax.management.ReflectionException; + +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.opendaylight.controller.config.api.jmx.ObjectNameUtil.withoutTransactionName; + +public class ServiceReferenceRegistryImplTest extends AbstractParallelAPSPTest { + + + @Before + public void setUp() { + super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver( + new TestingFixedThreadPoolModuleFactory(), + new TestingParallelAPSPModuleFactory(), + new TestingScheduledThreadPoolModuleFactory())); + } + + @Override + protected String getThreadPoolImplementationName() { + return TestingFixedThreadPoolModuleFactory.NAME; + } + + @Test + public void test() throws Exception { + ConfigTransactionJMXClient transaction1 = configRegistryClient.createTransaction(); + // create fixed1 + int fixedNrOfThreads = 20, scheduledNrOfThreads = 30; + + ObjectName fixedTPTransactionON = transaction1.createModule(getThreadPoolImplementationName(), fixed1); + platformMBeanServer.setAttribute(fixedTPTransactionON, new Attribute("ThreadCount", fixedNrOfThreads)); + + ObjectName scheduledTPTransactionON = transaction1.createModule( + TestingScheduledThreadPoolModuleFactory.NAME, "scheduled1"); + platformMBeanServer.setAttribute(scheduledTPTransactionON, new Attribute("ThreadCount", + scheduledNrOfThreads)); + + String refName = "ref"; + ObjectName serviceReference = transaction1.saveServiceReference(TestingThreadPoolServiceInterface.QNAME, refName, + fixedTPTransactionON); + // create apsp-parallel + createParallelAPSP(transaction1, serviceReference); + transaction1.commit(); + // check fixed1 is used + ServiceReferenceMXBean serviceReferenceMXBean = JMX.newMXBeanProxy(platformMBeanServer, + withoutTransactionName(serviceReference), ServiceReferenceMXBean.class); + assertEquals(withoutTransactionName(fixedTPTransactionON), serviceReferenceMXBean.getCurrentImplementation()); + checkApspThreadCount(fixedNrOfThreads); + + // switch reference to scheduled + ConfigTransactionJMXClient transaction2 = configRegistryClient.createTransaction(); + transaction2.saveServiceReference(TestingThreadPoolServiceInterface.QNAME, refName, + ObjectNameUtil.withTransactionName(scheduledTPTransactionON, transaction2.getTransactionName())); + transaction2.commit(); + // check scheduled is used + checkApspThreadCount(scheduledNrOfThreads); + // check that dummy MXBean points to scheduled + assertEquals(withoutTransactionName(scheduledTPTransactionON), serviceReferenceMXBean.getCurrentImplementation()); + + // empty transaction + configRegistryClient.createTransaction().commit(); + + // get service mapping + Map> serviceMapping = configRegistryClient.getServiceMapping(); + Map> expectedMapping = ImmutableMap.of(TestingThreadPoolServiceInterface.QNAME, + (Map)ImmutableMap.of(refName, withoutTransactionName(scheduledTPTransactionON))); + assertEquals(expectedMapping, serviceMapping); + + // destroy all + ConfigTransactionJMXClient transaction4 = configRegistryClient.createTransaction(); + Set objectNames = transaction4.lookupConfigBeans(); + for(ObjectName on: objectNames) { + transaction4.destroyModule(on); + } + transaction4.commit(); + + serviceMapping = configRegistryClient.getServiceMapping(); + assertTrue(serviceMapping.isEmpty()); + } + + private void checkApspThreadCount(int fixedNrOfThreads) throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException { + ObjectName apspON = ObjectNameUtil.createReadOnlyModuleON(TestingParallelAPSPModuleFactory.NAME, apsp1); + assertEquals(fixedNrOfThreads, platformMBeanServer.getAttribute(apspON, "MaxNumberOfThreads")); + } +} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManagerTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManagerTest.java index 65b010532b..31e70bd84e 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManagerTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManagerTest.java @@ -20,6 +20,7 @@ import org.junit.Before; import org.junit.Test; import org.opendaylight.controller.config.api.JmxAttribute; import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo; import org.opendaylight.controller.config.manager.impl.TransactionStatus; @@ -40,7 +41,8 @@ public class DependencyResolverManagerTest { @Before public void setUp() { transactionStatus = mock(TransactionStatus.class); - tested = new DependencyResolverManager("txName", transactionStatus); + ServiceReferenceReadableRegistry mockedRegistry = mock(ServiceReferenceReadableRegistry.class); + tested = new DependencyResolverManager("txName", transactionStatus, mockedRegistry); doNothing().when(transactionStatus).checkCommitStarted(); doNothing().when(transactionStatus).checkNotCommitted(); } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/ObjectNameUtilTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/ObjectNameUtilTest.java index 03380392e8..fe322895ab 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/ObjectNameUtilTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/ObjectNameUtilTest.java @@ -7,16 +7,19 @@ */ package org.opendaylight.controller.config.manager.impl.util; -import java.util.Set; - -import javax.management.ObjectName; - +import com.google.common.base.Throwables; +import com.google.common.collect.Sets; import org.junit.After; import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.config.manager.impl.AbstractLockedPlatformMBeanServerTest; -import com.google.common.base.Throwables; -import com.google.common.collect.Sets; +import javax.management.ObjectName; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; public class ObjectNameUtilTest extends AbstractLockedPlatformMBeanServerTest { private Set unregisterONs; @@ -37,7 +40,26 @@ public class ObjectNameUtilTest extends AbstractLockedPlatformMBeanServerTest { } } if (lastException != null) { - Throwables.propagate(lastException); + throw Throwables.propagate(lastException); } } + + @Test + public void testQuotation() throws Exception { + String serviceQName = "(namespace?revision=r)qname"; + String refName = "refName"; + String transaction = "transaction"; + ObjectName serviceReferenceON = ObjectNameUtil.createTransactionServiceON(transaction, serviceQName, refName); + assertFalse(serviceReferenceON.isPattern()); + assertEquals(serviceQName, ObjectNameUtil.getServiceQName(serviceReferenceON)); + assertEquals(refName, ObjectNameUtil.getReferenceName(serviceReferenceON)); + assertEquals(transaction, ObjectNameUtil.getTransactionName(serviceReferenceON)); + + serviceReferenceON = ObjectNameUtil.createReadOnlyServiceON(serviceQName, refName); + assertFalse(serviceReferenceON.isPattern()); + assertEquals(serviceQName, ObjectNameUtil.getServiceQName(serviceReferenceON)); + assertEquals(refName, ObjectNameUtil.getReferenceName(serviceReferenceON)); + assertEquals(null, ObjectNameUtil.getTransactionName(serviceReferenceON)); + + } } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModule.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModule.java index 3c55f4dcc0..f4ba5ef887 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModule.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModule.java @@ -114,8 +114,7 @@ public class TestingParallelAPSPModule implements Module, if (oldInstance != null) { // changing thread pool is not supported - boolean reuse = threadPoolInstance.equals(oldInstance - .getThreadPool()); + boolean reuse = threadPoolInstance == oldInstance.getThreadPool(); if (reuse) { logger.debug("Reusing old instance"); instance = oldInstance; diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/AbstractParallelAPSPTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/AbstractParallelAPSPTest.java index 3d9d5245ef..f979a45dd1 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/AbstractParallelAPSPTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/AbstractParallelAPSPTest.java @@ -16,11 +16,11 @@ import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; import javax.management.InstanceAlreadyExistsException; import javax.management.ObjectName; -abstract class AbstractParallelAPSPTest extends AbstractConfigTest { +public abstract class AbstractParallelAPSPTest extends AbstractConfigTest { protected final String fixed1 = "fixed1"; protected final String apsp1 = "apsp-parallel"; - abstract String getThreadPoolImplementationName(); + protected abstract String getThreadPoolImplementationName(); protected ObjectName createParallelAPSP( ConfigTransactionJMXClient transaction, ObjectName threadPoolON) @@ -36,6 +36,7 @@ abstract class AbstractParallelAPSPTest extends AbstractConfigTest { protected ObjectName createFixed1(ConfigTransactionJMXClient transaction, int numberOfThreads) throws InstanceAlreadyExistsException { + ObjectName name = transaction.createModule( getThreadPoolImplementationName(), fixed1); diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/DependentWiringTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/DependentWiringTest.java index f9a11301e1..978d375cd2 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/DependentWiringTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/DependentWiringTest.java @@ -48,7 +48,7 @@ public class DependentWiringTest extends AbstractParallelAPSPTest { } @Override - String getThreadPoolImplementationName() { + protected String getThreadPoolImplementationName() { return TestingFixedThreadPoolModuleFactory.NAME; } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/MockedDependenciesTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/MockedDependenciesTest.java index e385136abf..642f526efd 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/MockedDependenciesTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/MockedDependenciesTest.java @@ -111,7 +111,7 @@ public class MockedDependenciesTest extends AbstractParallelAPSPTest { } @Override - String getThreadPoolImplementationName() { + protected String getThreadPoolImplementationName() { return threadPoolImplementationName; } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/scheduledthreadpool/TestingScheduledThreadPoolConfigBeanMXBean.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/scheduledthreadpool/TestingScheduledThreadPoolConfigBeanMXBean.java index df86232906..6ccb2418f0 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/scheduledthreadpool/TestingScheduledThreadPoolConfigBeanMXBean.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/scheduledthreadpool/TestingScheduledThreadPoolConfigBeanMXBean.java @@ -15,4 +15,7 @@ public interface TestingScheduledThreadPoolConfigBeanMXBean extends public boolean isRecreate(); public void setRecreate(boolean recreate); + + public void setThreadCount(int threadCount); + } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/scheduledthreadpool/TestingScheduledThreadPoolModule.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/scheduledthreadpool/TestingScheduledThreadPoolModule.java index 77d1f8bbdf..2b9760cfc4 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/scheduledthreadpool/TestingScheduledThreadPoolModule.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/scheduledthreadpool/TestingScheduledThreadPoolModule.java @@ -36,7 +36,7 @@ public class TestingScheduledThreadPoolModule implements Module, @Nullable private final TestingScheduledThreadPoolImpl oldInstance; - private final int threadCount = 10; + private int threadCount = 10; private TestingScheduledThreadPoolImpl instance; private RootRuntimeBeanRegistrator runtimeBeanRegistrator; private boolean recreate; @@ -68,6 +68,11 @@ public class TestingScheduledThreadPoolModule implements Module, return threadCount; } + @Override + public void setThreadCount(int threadCount) { + this.threadCount = threadCount; + } + @Override public Closeable getInstance() { assertNotNull(runtimeBeanRegistrator); diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/TestingThreadPoolServiceInterface.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/TestingThreadPoolServiceInterface.java index 91a4cff415..0a886e5fb0 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/TestingThreadPoolServiceInterface.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/TestingThreadPoolServiceInterface.java @@ -11,8 +11,9 @@ import org.opendaylight.controller.config.api.annotations.AbstractServiceInterfa import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingThreadPoolIfc; -@ServiceInterfaceAnnotation(value = "testing-threadpool", osgiRegistrationType = TestingThreadPoolIfc.class, - namespace = "ns", revision = "foo", localName = "bar") +@ServiceInterfaceAnnotation(value = TestingThreadPoolServiceInterface.QNAME, osgiRegistrationType = TestingThreadPoolIfc.class, + namespace = "ns", revision = "foo", localName = "testing-threadpool") public interface TestingThreadPoolServiceInterface extends AbstractServiceInterface { + public static final String QNAME = "(ns?revision=foo)testing-threadpool"; } diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java index 8badb75f05..549ff9ffcf 100644 --- a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java +++ b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java @@ -148,8 +148,8 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient { } @Override - public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) { - return configRegistryMXBeanProxy.lookupConfigBeanByServiceInterfaceName(serviceInterfaceName, refName); + public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { + return configRegistryMXBeanProxy.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName); } @Override @@ -158,8 +158,8 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient { } @Override - public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) { - return configRegistryMXBeanProxy.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceName); + public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { + return configRegistryMXBeanProxy.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName); } @Override @@ -201,4 +201,15 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient { public Set getAvailableModuleFactoryQNames() { return configRegistryMXBeanProxy.getAvailableModuleFactoryQNames(); } + + @Override + public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException { + return configRegistryMXBeanProxy.getServiceReference(serviceInterfaceQName, refName); + } + + @Override + public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException { + configRegistryMXBeanProxy.checkServiceReferenceExists(objectName); + } + } diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java index 0db1e5b822..e683d915ba 100644 --- a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java +++ b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java @@ -164,13 +164,13 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { } @Override - public void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException { - configTransactionControllerMXBeanProxy.saveServiceReference(serviceInterfaceName,refName,objectName); + public ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException { + return configTransactionControllerMXBeanProxy.saveServiceReference(serviceInterfaceName,refName, moduleON); } @Override - public boolean removeServiceReference(String serviceInterfaceName, String refName) { - return configTransactionControllerMXBeanProxy.removeServiceReference(serviceInterfaceName, refName); + public void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException{ + configTransactionControllerMXBeanProxy.removeServiceReference(serviceInterfaceName, refName); } @Override @@ -179,8 +179,8 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { } @Override - public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) { - return configTransactionControllerMXBeanProxy.lookupConfigBeanByServiceInterfaceName(serviceInterfaceName, refName); + public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { + return configTransactionControllerMXBeanProxy.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName); } @Override @@ -189,8 +189,8 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { } @Override - public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) { - return configTransactionControllerMXBeanProxy.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceName); + public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { + return configTransactionControllerMXBeanProxy.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName); } @Override @@ -208,6 +208,16 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { return configTransactionControllerMXBeanProxy.removeServiceReferences(objectName); } + @Override + public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException { + return configTransactionControllerMXBeanProxy.getServiceReference(serviceInterfaceQName, refName); + } + + @Override + public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException { + configTransactionControllerMXBeanProxy.checkServiceReferenceExists(objectName); + } + @Override public void validateBean(ObjectName configBeanON) throws ValidationException { diff --git a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigRegistry.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigRegistry.java index 65341714df..e0d4c85943 100644 --- a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigRegistry.java +++ b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigRegistry.java @@ -150,7 +150,7 @@ public class TestingConfigRegistry implements ConfigRegistryMXBean { } @Override - public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) { + public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { throw new UnsupportedOperationException(); } @@ -160,7 +160,7 @@ public class TestingConfigRegistry implements ConfigRegistryMXBean { } @Override - public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) { + public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { throw new UnsupportedOperationException(); } @@ -178,4 +178,14 @@ public class TestingConfigRegistry implements ConfigRegistryMXBean { public Set getAvailableModuleFactoryQNames() { throw new UnsupportedOperationException(); } + + @Override + public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException { + throw new UnsupportedOperationException(); + } + + @Override + public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException { + throw new UnsupportedOperationException(); + } } diff --git a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java index 44eb73af79..4d16f51ae5 100644 --- a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java +++ b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java @@ -117,12 +117,12 @@ public class TestingConfigTransactionController implements } @Override - public void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException { + public ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException { throw new UnsupportedOperationException(); } @Override - public boolean removeServiceReference(String serviceInterfaceName, String refName) { + public void removeServiceReference(String serviceInterfaceName, String refName) { throw new UnsupportedOperationException(); } @@ -132,7 +132,7 @@ public class TestingConfigTransactionController implements } @Override - public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) { + public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { throw new UnsupportedOperationException(); } @@ -142,7 +142,7 @@ public class TestingConfigTransactionController implements } @Override - public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) { + public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { throw new UnsupportedOperationException(); } @@ -165,4 +165,14 @@ public class TestingConfigTransactionController implements public Set getAvailableModuleFactoryQNames() { throw new UnsupportedOperationException(); } + + @Override + public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException { + throw new UnsupportedOperationException(); + } + + @Override + public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException { + throw new UnsupportedOperationException(); + } } diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java index 28e0256c05..49a20bd462 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java @@ -26,6 +26,7 @@ import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIf import org.opendaylight.controller.config.yangjmxgenerator.attribute.Dependency; import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute; import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute; +import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute; import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute; import org.opendaylight.controller.config.yangjmxgenerator.attribute.TypedAttribute; import org.opendaylight.controller.config.yangjmxgenerator.attribute.VoidAttribute; @@ -623,6 +624,7 @@ public class TemplateFactory { } boolean isDependency = false; + boolean isListOfDependencies = false; Dependency dependency = null; Annotation overrideAnnotation = new Annotation("Override", Collections. emptyList()); @@ -635,12 +637,15 @@ public class TemplateFactory { .getDependency(); annotations.add(Annotation .createRequireIfcAnnotation(dependency.getSie())); + if (attributeIfc instanceof ListDependenciesAttribute) { + isListOfDependencies = true; + } } String varName = BindingGeneratorUtil .parseToValidParamName(attrEntry.getKey()); moduleFields.add(new ModuleField(type, varName, attributeIfc - .getUpperCaseCammelCase(), nullableDefaultWrapped, isDependency, dependency)); + .getUpperCaseCammelCase(), nullableDefaultWrapped, isDependency, dependency, isListOfDependencies)); String getterName = "get" + attributeIfc.getUpperCaseCammelCase(); @@ -657,10 +662,16 @@ public class TemplateFactory { .createDescriptionAnnotation(attributeIfc.getNullableDescription())); } + String setterBody = "this." + varName + " = " + varName + ";"; + if (isListOfDependencies) { + String nullCheck = String.format("if (%s == null) throw new IllegalArgumentException(\"Null not supported\");%n", + varName); + setterBody = nullCheck + setterBody; + } MethodDefinition setter = new MethodDefinition("void", setterName, Lists.newArrayList(new Field(type, varName)), - annotations, "this." + varName + " = " + varName + ";"); + annotations, setterBody); setter.setJavadoc(attributeIfc.getNullableDescription()); methods.add(getter); diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/ModuleField.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/ModuleField.java index 5624e169da..aff7af2811 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/ModuleField.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/ModuleField.java @@ -17,12 +17,12 @@ import java.util.List; public class ModuleField extends Field { private final String nullableDefault, attributeName; - private final boolean dependent; + private final boolean dependent, isListOfDependencies; private final Dependency dependency; - public ModuleField(List modifiers, String type, String name, + private ModuleField(List modifiers, String type, String name, String attributeName, String nullableDefault, boolean isDependency, - Dependency dependency) { + Dependency dependency, boolean isListOfDependencies) { super(modifiers, type, name); this.dependent = isDependency; this.dependency = dependency; @@ -32,12 +32,13 @@ public class ModuleField extends Field { nullableDefault = "new " + ArrayList.class.getName() + generics + "()"; } this.nullableDefault = nullableDefault; + this.isListOfDependencies = isListOfDependencies; } public ModuleField(String type, String name, String attributeName, - String nullableDefault, boolean isDependency, Dependency dependency) { + String nullableDefault, boolean isDependency, Dependency dependency, boolean isListOfDependencies) { this(Collections. emptyList(), type, name, attributeName, - nullableDefault, isDependency, dependency); + nullableDefault, isDependency, dependency, isListOfDependencies); } public Dependency getDependency() { @@ -52,6 +53,10 @@ public class ModuleField extends Field { return dependent; } + public boolean isListOfDependencies() { + return isListOfDependencies; + } + public String getAttributeName() { return attributeName; } diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/module_abs_template_new.ftl b/opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/module_abs_template_new.ftl index f7197d1582..7192ac661f 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/module_abs_template_new.ftl +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/module_abs_template_new.ftl @@ -149,13 +149,19 @@ package ${packageName}; throw new IllegalArgumentException("Parameter 'other' is null"); } <#list moduleFields as field> - <#if field.dependent==true> - if (${field.name}Dependency == null) { - if (other.${field.name}Dependency != null) - return false; - } else if (!${field.name}Dependency.equals(other.${field.name}Dependency)) { + <#if field.dependent==true && field.listOfDependencies == false> + if (${field.name}Dependency != other.${field.name}Dependency) { // reference to dependency must be same + return false; + } + <#elseif field.listOfDependencies> + if (${field.name}Dependency.equals(other.${field.name}Dependency) == false) { return false; } + for (int idx = 0; idx < ${field.name}Dependency.size(); idx++) { + if (${field.name}Dependency.get(idx) != other.${field.name}Dependency.get(idx)) { + return false; + } + } <#else> if (${field.name} == null) { if (other.${field.name} != null) { diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorFileNamesValidationTest.java b/opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorFileNamesValidationTest.java index b49b17e3a0..e33f1cddc4 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorFileNamesValidationTest.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorFileNamesValidationTest.java @@ -42,7 +42,7 @@ public class JMXGeneratorFileNamesValidationTest extends JMXGeneratorTest { } catch (RuntimeException e) { final Throwable cause = e.getCause(); assertNotNull(cause); - assertTrue(cause instanceof IllegalStateException); + assertTrue(cause.toString() + " is unexpected", cause instanceof IllegalStateException); assertThat(cause.getMessage(), containsString("Name conflict in generated files")); assertThat(cause.getMessage(), containsString("DtoA.java")); diff --git a/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/MbeParser.java b/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/MbeParser.java index 211da6bfef..2be6c81ee7 100644 --- a/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/MbeParser.java +++ b/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/MbeParser.java @@ -9,7 +9,6 @@ package org.opendaylight.controller.config.yang.store.impl; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import org.apache.commons.io.IOUtils; import org.opendaylight.controller.config.yang.store.api.YangStoreException; import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry; @@ -22,13 +21,10 @@ 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 java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -37,26 +33,11 @@ public class MbeParser { public YangStoreSnapshotImpl parseYangFiles( Collection allInput) throws YangStoreException { - YangParserImpl parser = new YangParserImpl(); + YangParserImpl parser = YangParserWrapper.getYangParserInstance(); - List bufferedInputStreams = new ArrayList<>(); - for (InputStream is : allInput) { - String content; - try { - content = IOUtils.toString(is); - } catch (IOException e) { - throw new YangStoreException("Can not get yang as String from " - + is, e); - } - InputStream buf = new ByteArrayInputStream(content.getBytes()); - bufferedInputStreams.add(buf); - } - - Map allYangModules = parser - .parseYangModelsFromStreamsMapped(bufferedInputStreams); + Map allYangModules = YangParserWrapper.parseYangFiles(parser, allInput); - SchemaContext resolveSchemaContext = parser.resolveSchemaContext(Sets - .newHashSet(allYangModules.values())); + SchemaContext resolveSchemaContext = YangParserWrapper.getSchemaContextFromModules(parser, allYangModules); // JMX generator @@ -115,7 +96,7 @@ public class MbeParser { public Map parseYangFilesToString( Collection allYangs) { - YangParserImpl parser = new YangParserImpl(); + YangParserImpl parser = YangParserWrapper.getYangParserInstance(); Map allYangModules = parser .parseYangModelsFromStreamsMapped(Lists.newArrayList(allYangs)); diff --git a/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/YangParserWrapper.java b/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/YangParserWrapper.java new file mode 100644 index 0000000000..7c428181aa --- /dev/null +++ b/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/YangParserWrapper.java @@ -0,0 +1,68 @@ +/* + * 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.config.yang.store.impl; + +import com.google.common.collect.Sets; +import org.apache.commons.io.IOUtils; +import org.opendaylight.controller.config.yang.store.api.YangStoreException; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser; +import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public class YangParserWrapper { + + /** + * throw IllegalStateException if it is unable to parse yang files + */ + public static SchemaContext parseYangFiles(Collection yangFilesAsInputStreams) { + YangParserImpl parser = getYangParserInstance(); + Map mappedYangModules = null; + try { + mappedYangModules = parseYangFiles(parser, yangFilesAsInputStreams); + } catch (YangStoreException e) { + throw new IllegalStateException("Unable to parse yang files", e); + } + return getSchemaContextFromModules(parser, mappedYangModules); + } + + static YangParserImpl getYangParserInstance() { + return new YangParserImpl(); + } + + static SchemaContext getSchemaContextFromModules(YangModelParser parser, Map allYangModules) { + return parser.resolveSchemaContext(Sets + .newHashSet(allYangModules.values())); + } + + static Map parseYangFiles(YangModelParser parser, Collection allInput) throws YangStoreException { + List bufferedInputStreams = new ArrayList<>(); + for (InputStream is : allInput) { + String content; + try { + content = IOUtils.toString(is); + } catch (IOException e) { + throw new YangStoreException("Can not get yang as String from " + + is, e); + } + InputStream buf = new ByteArrayInputStream(content.getBytes()); + bufferedInputStreams.add(buf); + } + + return parser + .parseYangModelsFromStreamsMapped(bufferedInputStreams); + } +} diff --git a/opendaylight/config/yang-test/pom.xml b/opendaylight/config/yang-test/pom.xml index 149348df4b..b1f7013abe 100644 --- a/opendaylight/config/yang-test/pom.xml +++ b/opendaylight/config/yang-test/pom.xml @@ -30,8 +30,34 @@ slf4j-api - org.opendaylight.yangtools.model - ietf-inet-types + org.opendaylight.yangtools.model + ietf-inet-types + + + org.opendaylight.bgpcep + mockito-configuration + test + + + ${project.groupId} + config-manager + test + + + ${project.groupId} + config-manager + test-jar + test + + + org.opendaylight.controller + config-util + test + + + junit + junit + test diff --git a/opendaylight/config/yang-test/src/test/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModuleTest.java b/opendaylight/config/yang-test/src/test/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModuleTest.java new file mode 100644 index 0000000000..50e1d4bb6a --- /dev/null +++ b/opendaylight/config/yang-test/src/test/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModuleTest.java @@ -0,0 +1,89 @@ +package org.opendaylight.controller.config.yang.test.impl; + +import com.google.common.collect.Lists; +import junit.framework.Assert; +import org.junit.Before; +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.api.jmx.ObjectNameUtil; +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.InstanceAlreadyExistsException; +import javax.management.ObjectName; +import java.util.ArrayList; +import java.util.List; + +public class NetconfTestImplModuleTest extends AbstractConfigTest { + + public static final String TESTING_DEP_PREFIX = "testing-dep"; + private NetconfTestImplModuleFactory factory; + private final String instanceName = "n1"; + + @Before + public void setUp() { + + factory = new NetconfTestImplModuleFactory(); + super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(factory, + new DepTestImplModuleFactory())); + } + + @Test + public void testDependencyList() throws InstanceAlreadyExistsException, ValidationException, + ConflictingVersionException { + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + + ObjectName on = createInstance(transaction, instanceName, 4); + transaction.validateConfig(); + CommitStatus status = transaction.commit(); + + assertBeanCount(1, factory.getImplementationName()); + assertBeanCount(4 + 1, DepTestImplModuleFactory.NAME); + assertStatus(status, 1 + 4 + 1, 0, 0); + + transaction = configRegistryClient.createTransaction(); + + NetconfTestImplModuleMXBean proxy = transaction.newMXBeanProxy(ObjectNameUtil.withoutTransactionName(on), + NetconfTestImplModuleMXBean.class); + proxy.getComplexList(); + List testingDeps = proxy.getTestingDeps(); + ObjectName testingDep = proxy.getTestingDep(); + + Assert.assertEquals(TESTING_DEP_PREFIX, ObjectNameUtil.getInstanceName(testingDep)); + assertTestingDeps(testingDeps, 4); + + transaction.abortConfig(); + } + + private void assertTestingDeps(List testingDeps, int i) { + Assert.assertEquals(i, testingDeps.size()); + + int c = 1; + for (ObjectName testingDep : testingDeps) { + Assert.assertEquals(TESTING_DEP_PREFIX + Integer.toString(c++), ObjectNameUtil.getInstanceName(testingDep)); + } + } + + + private ObjectName createInstance(ConfigTransactionJMXClient transaction, String instanceName, int depsCount) + throws InstanceAlreadyExistsException { + ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), instanceName); + NetconfTestImplModuleMXBean mxBean = transaction.newMXBeanProxy(nameCreated, NetconfTestImplModuleMXBean.class); + + ObjectName dep = transaction.createModule(DepTestImplModuleFactory.NAME, TESTING_DEP_PREFIX); + mxBean.setTestingDep(dep); + + ArrayList testingDeps = Lists.newArrayList(); + for (int i = 0; i < depsCount; i++) { + dep = transaction.createModule(DepTestImplModuleFactory.NAME, TESTING_DEP_PREFIX + Integer.toString(i + 1)); + testingDeps.add(dep); + } + mxBean.setTestingDeps(testingDeps); + + return nameCreated; + } + +} diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index e519a04a57..b0f7ad89a4 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -285,6 +285,11 @@ ietf-netconf-monitoring ${netconf.version} + + ${project.groupId} + ietf-netconf-monitoring-extension + ${netconf.version} + org.opendaylight.controller config-persister-impl @@ -459,7 +464,7 @@ org.opendaylight.controller - zeromq-routingtable.implementation + remoterpc-routingtable.implementation 0.4.1-SNAPSHOT diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml b/opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml index 2815422274..84d1c913c4 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml @@ -61,7 +61,7 @@ - + diff --git a/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java b/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java index 45fb11a83e..3d6a0292ef 100644 --- a/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java +++ b/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java @@ -2930,8 +2930,16 @@ public class ForwardingRulesManager implements } if (target != null) { // Update Configuration database - target.toggleInstallation(); - target.setStatus(StatusCode.SUCCESS.toString()); + if (target.getHardTimeout() != null || target.getIdleTimeout() != null) { + /* + * No need for checking if actual values: these strings were + * validated at configuration creation. Also, after a switch + * down scenario, no use to reinstall a timed flow. Mark it as + * "do not install". User can manually toggle it. + */ + target.toggleInstallation(); + } + target.setStatus(StatusCode.GONE.toString()); staticFlows.put(key, target); } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend index b460edff74..95acbcdb13 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend @@ -8,7 +8,6 @@ import static org.opendaylight.controller.sal.compatibility.NodeMapping.* import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey import org.apache.felix.dm.Component import java.util.Arrays -import org.opendaylight.yangtools.yang.binding.NotificationListener import java.util.Dictionary import java.util.Hashtable import org.opendaylight.controller.sal.utils.GlobalConstants @@ -30,6 +29,9 @@ import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService import org.opendaylight.controller.sal.discovery.IDiscoveryService import org.opendaylight.controller.sal.topology.IPluginOutTopologyService import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryService +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService +import org.opendaylight.controller.sal.binding.api.data.DataProviderService class ComponentActivator extends ComponentActivatorAbstractBase implements BindingAwareConsumer { @@ -44,9 +46,16 @@ class ComponentActivator extends ComponentActivatorAbstractBase implements Bindi @Property DataPacketAdapter dataPacket = new DataPacketAdapter; + @Property + org.opendaylight.controller.sal.utils.INodeFactory nodeFactory = new MDSalNodeFactory + + @Property + org.opendaylight.controller.sal.utils.INodeConnectorFactory nodeConnectorFactory = new MDSalNodeConnectorFactory + + override protected init() { - Node.NodeIDType.registerIDType(MD_SAL_TYPE, NodeKey); - NodeConnector.NodeConnectorIDType.registerIDType(MD_SAL_TYPE, NodeConnectorKey, MD_SAL_TYPE); + Node.NodeIDType.registerIDType(MD_SAL_TYPE, String); + NodeConnector.NodeConnectorIDType.registerIDType(MD_SAL_TYPE, String, MD_SAL_TYPE); } override start(BundleContext context) { @@ -71,25 +80,38 @@ class ComponentActivator extends ComponentActivatorAbstractBase implements Bindi // Inventory Service inventory.dataService = session.getSALService(DataBrokerService); inventory.flowStatisticsService = session.getRpcService(OpendaylightFlowStatisticsService); + inventory.flowTableStatisticsService = session.getRpcService(OpendaylightFlowTableStatisticsService); + inventory.nodeConnectorStatisticsService = session.getRpcService(OpendaylightPortStatisticsService); inventory.topologyDiscovery = session.getRpcService(FlowTopologyDiscoveryService); + inventory.dataProviderService = session.getSALService(DataProviderService) subscribe.registerNotificationListener(dataPacket) } override protected getGlobalImplementations() { - return Arrays.asList(this, flow, inventory, dataPacket) + return Arrays.asList(this, flow, inventory, dataPacket, nodeFactory, nodeConnectorFactory) } override protected configureGlobalInstance(Component c, Object imp) { configure(imp, c); } + private def dispatch configure(MDSalNodeFactory imp, Component it) { + setInterface(org.opendaylight.controller.sal.utils.INodeFactory.name, properties); + } + + private def dispatch configure(MDSalNodeConnectorFactory imp, Component it) { + setInterface(org.opendaylight.controller.sal.utils.INodeConnectorFactory.name, properties); + } + private def dispatch configure(ComponentActivator imp, Component it) { add( createServiceDependency().setService(BindingAwareBroker) // .setCallbacks("setBroker", "setBroker") // .setRequired(true)) + + } private def dispatch configure(DataPacketAdapter imp, Component it) { @@ -114,7 +136,7 @@ class ComponentActivator extends ComponentActivatorAbstractBase implements Bindi add( createServiceDependency() // .setService(IPluginOutReadService) // - .setCallbacks("setReadPublisher", "setReadPublisher") // + .setCallbacks("setReadPublisher", "unsetReadPublisher") // .setRequired(false)) add( createServiceDependency() // @@ -137,6 +159,7 @@ class ComponentActivator extends ComponentActivatorAbstractBase implements Bindi private def Dictionary properties() { val props = new Hashtable(); props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString, MD_SAL_TYPE) + props.put("protocolName", MD_SAL_TYPE); return props; } } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/DataPacketAdapter.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/DataPacketAdapter.xtend index ce6af6469e..f1c19b127f 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/DataPacketAdapter.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/DataPacketAdapter.xtend @@ -15,8 +15,9 @@ class DataPacketAdapter implements PacketProcessingListener { dataPacketPublisher.receiveDataPacket(inPacket); } - public static def RawPacket toRawPacket(PacketReceived received) { + public static def RawPacket toRawPacket(PacketReceived received) { val ret = new RawPacket(received.payload); + ret.setIncomingNodeConnector(NodeMapping.toADNodeConnector(received.ingress)) return ret; } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java index ad6009c827..4e6e49eac7 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java @@ -1,5 +1,9 @@ package org.opendaylight.controller.sal.compatibility; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.CRUDP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.ETHERNET_ARP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.TCP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.UDP; import static org.opendaylight.controller.sal.match.MatchType.DL_DST; import static org.opendaylight.controller.sal.match.MatchType.DL_SRC; import static org.opendaylight.controller.sal.match.MatchType.DL_TYPE; @@ -8,11 +12,6 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; - -import org.opendaylight.controller.sal.core.NodeConnector; - - - import org.opendaylight.controller.sal.match.Match; import org.opendaylight.controller.sal.match.MatchField; import org.opendaylight.controller.sal.match.MatchType; @@ -22,14 +21,11 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types. import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetNodeConnectorStatisticsInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetNodeConnectorStatisticsInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.Address; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv4Builder; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv6Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType; import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanPcp; @@ -53,9 +49,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; + import com.google.common.net.InetAddresses; -import static org.opendaylight.controller.sal.compatibility.NodeMapping.*; -import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.*; public class FromSalConversionsUtils { @@ -63,19 +58,7 @@ public class FromSalConversionsUtils { } - public static GetNodeConnectorStatisticsInput nodeConnectorStatistics( - NodeConnector connector) { - GetNodeConnectorStatisticsInputBuilder target = new GetNodeConnectorStatisticsInputBuilder(); - - NodeRef nodeRef = toNodeRef(connector.getNode()); - target.setNode(nodeRef); - - NodeConnectorRef nodeConnectorRef = toNodeConnectorRef(connector); - target.setNodeConnector(nodeConnectorRef); - - return target.build(); - } - + @SuppressWarnings("unused") private static Address addressFromAction(InetAddress inetAddress) { String strInetAddresss = InetAddresses.toAddrString(inetAddress); if (inetAddress instanceof Inet4Address) { @@ -196,7 +179,7 @@ public class FromSalConversionsUtils { MatchField vlan = sourceMatch.getField(MatchType.DL_VLAN); if (vlan != null && vlan.getValue() != null) { VlanIdBuilder vlanIDBuilder = new VlanIdBuilder(); - vlanIDBuilder.setVlanId(new VlanId((int) (NetUtils + vlanIDBuilder.setVlanId(new VlanId((NetUtils .getUnsignedShort((short) vlan.getValue())))); vlanMatchBuild.setVlanId(vlanIDBuilder.build()); } @@ -270,7 +253,7 @@ public class FromSalConversionsUtils { InetAddress inetDestAddress = null; MatchField netDest = sourceMatch.getField(MatchType.NW_DST); - if (netSource != null && netSource.getValue() != null) { + if (netDest != null && netDest.getValue() != null) { inetDestAddress = (InetAddress) (netDest.getValue()); } @@ -371,5 +354,76 @@ public class FromSalConversionsUtils { .setIpv6Destination(new Ipv6Prefix(inetDstAddressString)); return layer6MatchBuild.build(); } + + public static boolean flowEquals(Flow statsFlow, Flow storedFlow) { + if (statsFlow.getClass() != storedFlow.getClass()) { + return false; + } + if (statsFlow.getBufferId()== null) { + if (storedFlow.getBufferId() != null) { + return false; + } + } else if(!statsFlow.getBufferId().equals(storedFlow.getBufferId())) { + return false; + } + if (statsFlow.getContainerName()== null) { + if (storedFlow.getContainerName()!= null) { + return false; + } + } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) { + return false; + } + if (statsFlow.getCookie()== null) { + if (storedFlow.getCookie()!= null) { + return false; + } + } else if(!statsFlow.getCookie().equals(storedFlow.getCookie())) { + return false; + } + if (statsFlow.getMatch()== null) { + if (storedFlow.getMatch() != null) { + return false; + } + } else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) { + return false; + } + if (statsFlow.getCookie()== null) { + if (storedFlow.getCookie()!= null) { + return false; + } + } else if(!statsFlow.getCookie().equals(storedFlow.getCookie())) { + return false; + } + if (statsFlow.getHardTimeout() == null) { + if (storedFlow.getHardTimeout() != null) { + return false; + } + } else if(!statsFlow.getHardTimeout().equals(storedFlow.getHardTimeout() )) { + return false; + } + if (statsFlow.getIdleTimeout()== null) { + if (storedFlow.getIdleTimeout() != null) { + return false; + } + } else if(!statsFlow.getIdleTimeout().equals(storedFlow.getIdleTimeout())) { + return false; + } + if (statsFlow.getPriority() == null) { + if (storedFlow.getPriority() != null) { + return false; + } + } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) { + return false; + } + if (statsFlow.getTableId() == null) { + if (storedFlow.getTableId() != null) { + return false; + } + } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) { + return false; + } + return true; + } + } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend index 8ac6f1b050..31ae745d73 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend @@ -9,7 +9,6 @@ import org.opendaylight.controller.sal.binding.api.data.DataBrokerService import static extension org.opendaylight.controller.sal.common.util.Arguments.* import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.* -import static org.opendaylight.controller.sal.compatibility.MDFlowMapping.* import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef @@ -19,9 +18,7 @@ import org.opendaylight.controller.sal.reader.NodeConnectorStatistics import org.opendaylight.controller.sal.reader.FlowOnNode import org.opendaylight.controller.sal.reader.NodeDescription import org.slf4j.LoggerFactory -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsInputBuilder import java.util.ArrayList -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllNodeConnectorStatisticsInputBuilder import org.opendaylight.controller.sal.inventory.IPluginInInventoryService import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService @@ -45,17 +42,64 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkUtilizationNormal import org.opendaylight.controller.sal.topology.TopoEdgeUpdate import org.opendaylight.controller.sal.discovery.IDiscoveryService - -class InventoryAndReadAdapter implements IPluginInTopologyService, IPluginInReadService, IPluginInInventoryService, OpendaylightInventoryListener, FlowTopologyDiscoveryListener { +import org.opendaylight.controller.sal.reader.IPluginOutReadService +import java.util.List +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate +import org.opendaylight.controller.sal.reader.NodeTableStatistics +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey +import org.opendaylight.controller.sal.binding.api.data.DataProviderService +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatistics +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetNodeConnectorStatisticsInputBuilder +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder + +class InventoryAndReadAdapter implements IPluginInTopologyService, + IPluginInReadService, + IPluginInInventoryService, + OpendaylightInventoryListener, + FlowTopologyDiscoveryListener, + OpendaylightFlowStatisticsListener, + OpendaylightFlowTableStatisticsListener, + OpendaylightPortStatisticsListener { private static val LOG = LoggerFactory.getLogger(InventoryAndReadAdapter); + private static val OPENFLOWV10_TABLE_ID = new Integer(0).shortValue; @Property DataBrokerService dataService; + @Property + DataProviderService dataProviderService; + @Property OpendaylightFlowStatisticsService flowStatisticsService; + @Property + OpendaylightPortStatisticsService nodeConnectorStatisticsService; + + @Property + OpendaylightFlowTableStatisticsService flowTableStatisticsService; + @Property IPluginOutInventoryService inventoryPublisher; @@ -67,6 +111,22 @@ class InventoryAndReadAdapter implements IPluginInTopologyService, IPluginInRead @Property FlowTopologyDiscoveryService topologyDiscovery; + + @Property + List statisticsPublisher = new ArrayList(); + + def setReadPublisher(IPluginOutReadService listener) { + statisticsPublisher.add(listener); + } + + def unsetReadPublisher (IPluginOutReadService listener) { + if( listener != null) + statisticsPublisher.remove(listener); + } + + protected def startChange() { + return dataProviderService.beginTransaction; + } override getTransmitRate(NodeConnector connector) { val nodeConnector = readFlowCapableNodeConnector(connector.toNodeConnectorRef); @@ -74,82 +134,206 @@ class InventoryAndReadAdapter implements IPluginInTopologyService, IPluginInRead } override readAllFlow(Node node, boolean cached) { - val input = new GetAllFlowStatisticsInputBuilder; - input.setNode(node.toNodeRef); - val result = flowStatisticsService.getAllFlowStatistics(input.build) - val statistics = result.get.result; val output = new ArrayList(); - for (stat : statistics.flowStatistics) { - // FIXME: Create FlowOnNode - } + val tableRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) + .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance(); + + val it = this.startChange(); + + val table= it.readConfigurationData(tableRef) as Table; + + if(table != null){ + LOG.info("Number of flows installed in table 0 of node {} : {}",node,table.flow.size); + + for(flow : table.flow){ + + val adsalFlow = ToSalConversionsUtils.toFlow(flow); + val statsFromDataStore = flow.getAugmentation(FlowStatisticsData) as FlowStatisticsData; + + if(statsFromDataStore != null){ + val it = new FlowOnNode(adsalFlow); + byteCount = statsFromDataStore.flowStatistics.byteCount.value.longValue; + packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue; + durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue; + durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue; + + output.add(it); + } + } + } + + //TODO (main): Shell we send request to the switch? It will make async request to the switch. + // Once plugin receive response, it will let adaptor know through onFlowStatisticsUpdate() + // If we assume that md-sal statistics manager will always be running, then its not required + // But if not, then sending request will collect the latest data for adaptor atleast. + val input = new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder; + input.setNode(node.toNodeRef); + flowStatisticsService.getAllFlowsStatisticsFromAllFlowTables(input.build) + return output; } override readAllNodeConnector(Node node, boolean cached) { - val input = new GetAllNodeConnectorStatisticsInputBuilder(); + + val ret = new ArrayList(); + val nodeRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) + .toInstance(); + + val provider = this.startChange(); + + val dsNode= provider.readConfigurationData(nodeRef) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; + + if(dsNode != null){ + + for (dsNodeConnector : dsNode.nodeConnector){ + val nodeConnectorRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector, dsNodeConnector.key) + .toInstance(); + + val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; + + if(nodeConnectorFromDS != null){ + val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics; + + ret.add(toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,dsNode.id,dsNodeConnector.id)); + } + } + } + + //TODO: Refer TODO (main) + val input = new GetAllNodeConnectorsStatisticsInputBuilder(); input.setNode(node.toNodeRef); - val result = flowStatisticsService.getAllNodeConnectorStatistics(input.build()); - val statistics = result.get.result.nodeConnectorStatistics; - val ret = new ArrayList(); - for (stat : statistics) { - ret.add(stat.toNodeConnectorStatistics()) - } + nodeConnectorStatisticsService.getAllNodeConnectorsStatistics(input.build()); return ret; } override readAllNodeTable(Node node, boolean cached) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") + val ret = new ArrayList(); + + val dsFlowCapableNode= readFlowCapableNode(node.toNodeRef) + + if(dsFlowCapableNode != null){ + + for (table : dsFlowCapableNode.table){ + + val tableStats = table.getAugmentation(FlowTableStatisticsData) as FlowTableStatisticsData; + + if(tableStats != null){ + ret.add(toNodeTableStatistics(tableStats.flowTableStatistics,table.id,node)); + } + } + } + + //TODO: Refer TODO (main) + val input = new GetFlowTablesStatisticsInputBuilder(); + input.setNode(node.toNodeRef); + flowTableStatisticsService.getFlowTablesStatistics(input.build); + return ret; } override readDescription(Node node, boolean cached) { - val capableNode = readFlowCapableNode(node.toNodeRef) - - val it = new NodeDescription() - manufacturer = capableNode.manufacturer - serialNumber = capableNode.serialNumber - software = capableNode.software - description = capableNode.description - - return it; - } - - override readFlow(Node node, Flow flow, boolean cached) { - val input = flowStatisticsInput(node, flow); - val output = flowStatisticsService.getFlowStatistics(input); - - try { - val statistics = output.get().getResult(); - if (statistics != null) { - val it = new FlowOnNode(flow); - byteCount = statistics.byteCount.value.longValue - durationNanoseconds = statistics.duration.getNanosecond().getValue().intValue(); - durationSeconds = statistics.duration.getSecond().getValue().intValue(); - packetCount = statistics.getPacketCount().getValue().longValue(); - return it; - } - } catch (Exception e) { - LOG.error("Read flow not processed", e); - } - return null; + return toNodeDescription(node.toNodeRef); + } + + override readFlow(Node node, Flow targetFlow, boolean cached) { + var FlowOnNode ret= null; + + val tableRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) + .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance(); + + val it = this.startChange(); + + val table= it.readConfigurationData(tableRef) as Table; + + if(table != null){ + LOG.info("Number of flows installed in table 0 of node {} : {}",node,table.flow.size); + + for(mdsalFlow : table.flow){ + if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))){ + val statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData) as FlowStatisticsData; + + if(statsFromDataStore != null){ + LOG.debug("Found matching flow in the data store flow table "); + val it = new FlowOnNode(targetFlow); + byteCount = statsFromDataStore.flowStatistics.byteCount.value.longValue; + packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue; + durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue; + durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue; + + ret = it; + } + } + } + } + + //TODO: Refer TODO (main) + val input = new GetFlowStatisticsFromFlowTableInputBuilder; + input.setNode(node.toNodeRef); + input.fieldsFrom(MDFlowMapping.toMDSalflow(targetFlow)); + flowStatisticsService.getFlowStatisticsFromFlowTable(input.build) + + return ret; + } override readNodeConnector(NodeConnector connector, boolean cached) { + var NodeConnectorStatistics nodeConnectorStatistics = null; + + val nodeConnectorRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(connector.node)) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector, InventoryMapping.toNodeConnectorKey(connector)) + .toInstance(); + val provider = this.startChange(); + + val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; + + if(nodeConnectorFromDS != null){ + val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics; + if(nodeConnectorStatsFromDs != null) { + nodeConnectorStatistics = toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics, + InventoryMapping.toNodeKey(connector.node).id, + InventoryMapping.toNodeConnectorKey(connector).id); + } + } + + //TODO: Refer TODO (main) + val input = new GetNodeConnectorStatisticsInputBuilder(); + input.setNode(connector.node.toNodeRef); + input.setNodeConnectorId(InventoryMapping.toNodeConnectorKey(connector).id); + nodeConnectorStatisticsService.getNodeConnectorStatistics(input.build()); + return nodeConnectorStatistics; + } - val getNodeConnectorStatisticsInput = FromSalConversionsUtils.nodeConnectorStatistics(connector); - val future = flowStatisticsService.getNodeConnectorStatistics(getNodeConnectorStatisticsInput); - try { - val rpcResult = future.get(); - val output = rpcResult.getResult(); - - if (output != null) { - return output.toNodeConnectorStatistics; - } - } catch (Exception e) { - LOG.error("Read node connector not processed", e); - } - - return null; + override readNodeTable(NodeTable nodeTable, boolean cached) { + var NodeTableStatistics nodeStats = null + + val tableRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(nodeTable.node)) + .augmentation(FlowCapableNode).child(Table, new TableKey(nodeTable.ID as Short)).toInstance(); + + val it = this.startChange(); + + val table= it.readConfigurationData(tableRef) as Table; + + if(table != null){ + val tableStats = table.getAugmentation(FlowTableStatisticsData) as FlowTableStatisticsData; + + if(tableStats != null){ + nodeStats = toNodeTableStatistics(tableStats.flowTableStatistics,table.id,nodeTable.node); + } + } + + //TODO: Refer TODO (main) + val input = new GetFlowTablesStatisticsInputBuilder(); + input.setNode(nodeTable.node.toNodeRef); + flowTableStatisticsService.getFlowTablesStatistics(input.build); + + return nodeStats; } override onNodeConnectorRemoved(NodeConnectorRemoved update) { @@ -157,17 +341,45 @@ class InventoryAndReadAdapter implements IPluginInTopologyService, IPluginInRead } override onNodeRemoved(NodeRemoved notification) { - // NOOP + val properties = Collections.emptySet(); + + inventoryPublisher.updateNode(notification.nodeRef.toADNode, UpdateType.REMOVED, properties); } override onNodeConnectorUpdated(NodeConnectorUpdated update) { - val properties = Collections.emptySet(); - inventoryPublisher.updateNodeConnector(update.nodeConnectorRef.toADNodeConnector, UpdateType.CHANGED, properties); + val properties = new java.util.HashSet(); + + + val org.opendaylight.yangtools.yang.binding.InstanceIdentifier identifier = update.nodeConnectorRef.value as org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + var updateType = UpdateType.CHANGED; + if ( this._dataService.readOperationalData(identifier) == null ){ + updateType = UpdateType.ADDED; + } + + var nodeConnector = update.nodeConnectorRef.toADNodeConnector + + + properties.add(new org.opendaylight.controller.sal.core.Name(nodeConnector.ID.toString())); + + inventoryPublisher.updateNodeConnector(nodeConnector , updateType , properties); } override onNodeUpdated(NodeUpdated notification) { val properties = Collections.emptySet(); - inventoryPublisher.updateNode(notification.nodeRef.toADNode, UpdateType.CHANGED, properties); + val org.opendaylight.yangtools.yang.binding.InstanceIdentifier identifier = notification.nodeRef.value as org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + + var updateType = UpdateType.CHANGED; + if ( this._dataService.readOperationalData(identifier) == null ){ + updateType = UpdateType.ADDED; + } + inventoryPublisher.updateNode(notification.nodeRef.toADNode, updateType, properties); + + //Notify the listeners of IPluginOutReadService + + for (statsPublisher : statisticsPublisher){ + val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; + statsPublisher.descriptionStatisticsUpdated(nodeRef.toADNode,toNodeDescription(notification.nodeRef)); + } } override getNodeProps() { @@ -182,10 +394,6 @@ class InventoryAndReadAdapter implements IPluginInTopologyService, IPluginInRead return null; } - override readNodeTable(NodeTable table, boolean cached) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - private def FlowCapableNode readFlowCapableNode(NodeRef ref) { val dataObject = dataService.readOperationalData(ref.value as InstanceIdentifier); val node = dataObject.checkInstanceOf( @@ -200,26 +408,61 @@ class InventoryAndReadAdapter implements IPluginInTopologyService, IPluginInRead return node.getAugmentation(FlowCapableNodeConnector); } - private static def toNodeConnectorStatistics( - org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics output) { - val it = new NodeConnectorStatistics - - collisionCount = output.getCollisionCount().longValue(); - receiveCRCErrorCount = output.getReceiveCrcError().longValue(); - receiveFrameErrorCount = output.getReceiveFrameError().longValue(); - receiveOverRunErrorCount = output.getReceiveOverRunError().longValue(); + private def toNodeConnectorStatistics( + org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics nodeConnectorStatistics, NodeId nodeId, NodeConnectorId nodeConnectorId) { + + val it = new NodeConnectorStatistics(); + + receivePacketCount = nodeConnectorStatistics.packets.received.longValue; + transmitPacketCount = nodeConnectorStatistics.packets.transmitted.longValue; + + receiveByteCount = nodeConnectorStatistics.bytes.received.longValue; + transmitByteCount = nodeConnectorStatistics.bytes.transmitted.longValue; + + receiveDropCount = nodeConnectorStatistics.receiveDrops.longValue; + transmitDropCount = nodeConnectorStatistics.transmitDrops.longValue; + + receiveErrorCount = nodeConnectorStatistics.receiveErrors.longValue; + transmitErrorCount = nodeConnectorStatistics.transmitErrors.longValue; + + receiveFrameErrorCount = nodeConnectorStatistics.receiveFrameError.longValue; + receiveOverRunErrorCount = nodeConnectorStatistics.receiveOverRunError.longValue; + receiveCRCErrorCount = nodeConnectorStatistics.receiveCrcError.longValue; + collisionCount = nodeConnectorStatistics.collisionCount.longValue; + + val nodeConnectorRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(nodeId)) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector,new NodeConnectorKey(nodeConnectorId)).toInstance; + + nodeConnector = NodeMapping.toADNodeConnector(new NodeConnectorRef(nodeConnectorRef)); + + return it; + } - receiveDropCount = output.getReceiveDrops().longValue(); - receiveErrorCount = output.getReceiveErrors().longValue(); - receivePacketCount = output.getPackets().getReceived().longValue(); - receiveByteCount = output.getBytes().getReceived().longValue(); + private def toNodeTableStatistics( + org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics tableStats, + Short tableId,Node node){ + var it = new NodeTableStatistics(); + + activeCount = tableStats.activeFlows.value.intValue; + lookupCount = tableStats.packetsLookedUp.value.intValue; + matchedCount = tableStats.packetsMatched.value.intValue; + name = tableId.toString; + nodeTable = new NodeTable(NodeMapping.MD_SAL_TYPE,tableId,node); + return it; + } + + private def toNodeDescription(NodeRef nodeRef){ + val capableNode = readFlowCapableNode(nodeRef); - transmitDropCount = output.getTransmitDrops().longValue(); - transmitErrorCount = output.getTransmitErrors().longValue(); - transmitPacketCount = output.getPackets().getTransmitted().longValue(); - transmitByteCount = output.getBytes().getTransmitted().longValue(); + val it = new NodeDescription() + manufacturer = capableNode.manufacturer + serialNumber = capableNode.serialNumber + software = capableNode.software + description = capableNode.description + return it; - } + } override sollicitRefresh() { topologyDiscovery.solicitRefresh @@ -248,5 +491,78 @@ class InventoryAndReadAdapter implements IPluginInTopologyService, IPluginInRead def Edge toADEdge(Link link) { new Edge(link.source.toADNodeConnector,link.destination.toADNodeConnector) } - + + /* + * OpendaylightFlowStatisticsListener interface implementation + */ + override onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) { + + val adsalFlowsStatistics = new ArrayList(); + + for(flowStats : notification.flowAndStatisticsMapList){ + if(flowStats.tableId == 0) + adsalFlowsStatistics.add(toFlowOnNode(flowStats)); + } + + for (statsPublisher : statisticsPublisher){ + val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; + statsPublisher.nodeFlowStatisticsUpdated(nodeRef.toADNode,adsalFlowsStatistics); + } + + } + /* + * OpendaylightFlowTableStatisticsListener interface implementation + */ + override onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) { + var adsalFlowTableStatistics = new ArrayList(); + + for(stats : notification.flowTableAndStatisticsMap){ + if (stats.tableId.value == 0){ + val it = new NodeTableStatistics(); + activeCount = stats.activeFlows.value.intValue; + lookupCount = stats.packetsLookedUp.value.longValue; + matchedCount = stats.packetsMatched.value.longValue; + + adsalFlowTableStatistics.add(it); + } + } + for (statsPublisher : statisticsPublisher){ + val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; + statsPublisher.nodeTableStatisticsUpdated(nodeRef.toADNode,adsalFlowTableStatistics); + } + } + + /* + * OpendaylightPortStatisticsUpdate interface implementation + */ + override onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) { + + val adsalPortStatistics = new ArrayList(); + + for(nodeConnectorStatistics : notification.nodeConnectorStatisticsAndPortNumberMap){ + adsalPortStatistics.add(toNodeConnectorStatistics(nodeConnectorStatistics,notification.id,nodeConnectorStatistics.nodeConnectorId)); + } + + for (statsPublisher : statisticsPublisher){ + val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; + statsPublisher.nodeConnectorStatisticsUpdated(nodeRef.toADNode,adsalPortStatistics); + } + + } + + private static def toFlowOnNode (FlowAndStatisticsMapList flowAndStatsMap){ + + val it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap)); + + byteCount = flowAndStatsMap.byteCount.value.longValue; + packetCount = flowAndStatsMap.packetCount.value.longValue; + durationSeconds = flowAndStatsMap.duration.second.value.intValue; + durationNanoseconds = flowAndStatsMap.duration.nanosecond.value.intValue; + + return it; + } } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDFlowMapping.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDFlowMapping.xtend index 6cf728cde9..2f458c41dd 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDFlowMapping.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDFlowMapping.xtend @@ -5,7 +5,6 @@ import java.math.BigInteger import java.net.Inet4Address import java.net.Inet6Address import java.util.ArrayList -import java.util.List import org.opendaylight.controller.sal.action.Controller import org.opendaylight.controller.sal.action.Drop import org.opendaylight.controller.sal.action.Flood @@ -40,7 +39,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddF import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAddedBuilder import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInputBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsInputBuilder import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.VlanCfi import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.Address import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv4Builder @@ -67,7 +65,6 @@ 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.hw.path.action._case.HwPathActionBuilder import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.loopback.action._case.LoopbackActionBuilder import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.vlan.action._case.PopVlanActionBuilder import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.push.vlan.action._case.PushVlanActionBuilder import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.dst.action._case.SetDlDstActionBuilder import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.src.action._case.SetDlSrcActionBuilder @@ -106,6 +103,8 @@ 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.SwPathActionCaseBuilder import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder public class MDFlowMapping { @@ -142,13 +141,6 @@ public class MDFlowMapping { return it.build; } - public static def flowStatisticsInput(Node sourceNode, Flow sourceFlow) { - val source = flowAdded(sourceFlow); - val it = new GetFlowStatisticsInputBuilder(source as org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow); - node = sourceNode.toNodeRef(); - return it.build(); - } - public static def removeFlowInput(Node sourceNode, Flow sourceFlow) { val source = flowAdded(sourceFlow); val it = new RemoveFlowInputBuilder(source as org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow); @@ -355,7 +347,7 @@ public class MDFlowMapping { } public static def Uri toUri(NodeConnector connector) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") + return new NodeConnectorId(connector.ID as String); } public static def MacAddress toMacAddress(byte[] bytes) { @@ -367,4 +359,25 @@ public class MDFlowMapping { } return new MacAddress(sb.toString()); } + + public static def toMDSalflow(Flow sourceFlow) { + if (sourceFlow == null) + throw new IllegalArgumentException(); + val it = new FlowBuilder(); + + hardTimeout = sourceFlow.hardTimeout as int + idleTimeout = sourceFlow.idleTimeout as int + cookie = BigInteger.valueOf(sourceFlow.id) + priority = sourceFlow.priority as int + + val sourceActions = sourceFlow.actions; + val targetActions = new ArrayList(); + for (sourceAction : sourceActions) { + targetActions.add(sourceAction.toAction()); + } + instructions = targetActions.toApplyInstruction(); + match = sourceFlow.match.toMatch(); + return it.build(); + } + } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDSalNodeConnectorFactory.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDSalNodeConnectorFactory.java new file mode 100644 index 0000000000..5b4b16a39a --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDSalNodeConnectorFactory.java @@ -0,0 +1,23 @@ +package org.opendaylight.controller.sal.compatibility; + +import org.opendaylight.controller.sal.core.ConstructionException; +import org.opendaylight.controller.sal.core.Node; +import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.utils.INodeConnectorFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MDSalNodeConnectorFactory implements INodeConnectorFactory{ + private Logger logger = LoggerFactory.getLogger(MDSalNodeConnectorFactory.class); + + @Override + public NodeConnector fromStringNoNode(String type, String id, Node node) { + try { + return new NodeConnector(type, id, node); + } catch (ConstructionException e) { + logger.error("Could not construct NodeConnector", e); + } + return null; + + } +} diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDSalNodeFactory.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDSalNodeFactory.java new file mode 100644 index 0000000000..e36ebd7245 --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/MDSalNodeFactory.java @@ -0,0 +1,22 @@ +package org.opendaylight.controller.sal.compatibility; + +import org.opendaylight.controller.sal.core.ConstructionException; +import org.opendaylight.controller.sal.core.Node; +import org.opendaylight.controller.sal.utils.INodeFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MDSalNodeFactory implements INodeFactory{ + private Logger logger = LoggerFactory.getLogger(MDSalNodeFactory.class); + + @Override + public Node fromString(String type, String id) { + + try { + return new Node(type, id); + } catch (ConstructionException e) { + logger.error("Could not construct Node", e); + } + return null; + } +} diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.xtend index 4c9a9e6658..6bfee578ab 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.xtend @@ -10,17 +10,19 @@ import static extension org.opendaylight.controller.sal.common.util.Arguments.*; 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.opendaylight.inventory.rev130819.NodeConnectorId import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey import org.opendaylight.controller.sal.core.ConstructionException import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId + public class NodeMapping { public static val MD_SAL_TYPE = "MD_SAL"; private static val NODE_CLASS = org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; - private static val NODECONNECTOR_CLASS = org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node. - NodeConnector; + private static val NODECONNECTOR_CLASS = org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; private new() { throw new UnsupportedOperationException("Utility class. Instantiation is not allowed."); @@ -33,7 +35,7 @@ public class NodeMapping { val arg = node.getPath().get(1); val item = arg.checkInstanceOf(IdentifiableItem); val nodeKey = item.getKey().checkInstanceOf(NodeKey); - return new Node(MD_SAL_TYPE, nodeKey); + return new Node(MD_SAL_TYPE, nodeKey.getId().getValue().toString()); } public static def toADNodeConnector(NodeConnectorRef source) throws ConstructionException { @@ -44,20 +46,22 @@ public class NodeMapping { val arg = path.getPath().get(2); val item = arg.checkInstanceOf(IdentifiableItem); val connectorKey = item.getKey().checkInstanceOf(NodeConnectorKey); - return new NodeConnector(MD_SAL_TYPE, connectorKey, node); + return new NodeConnector(MD_SAL_TYPE, connectorKey.getId().getValue().toString(), node); } - + public static def toNodeRef(Node node) { checkArgument(MD_SAL_TYPE.equals(node.getType())); - val nodeKey = node.ID.checkInstanceOf(NodeKey); + var nodeId = node.ID.checkInstanceOf(String) + val nodeKey = new NodeKey(new NodeId(nodeId)); val nodePath = InstanceIdentifier.builder().node(Nodes).child(NODE_CLASS, nodeKey).toInstance(); return new NodeRef(nodePath); } - + public static def toNodeConnectorRef(NodeConnector nodeConnector) { val node = nodeConnector.node.toNodeRef(); val nodePath = node.getValue() as InstanceIdentifier - val connectorKey = nodeConnector.ID.checkInstanceOf(NodeConnectorKey); + var nodeConnectorId = nodeConnector.ID.checkInstanceOf(String) + val connectorKey = new NodeConnectorKey(new NodeConnectorId(nodeConnectorId)); val path = InstanceIdentifier.builder(nodePath).child(NODECONNECTOR_CLASS, connectorKey).toInstance(); return new NodeConnectorRef(path); } @@ -65,5 +69,5 @@ public class NodeMapping { public static def toADNode(NodeRef node) throws ConstructionException { return toADNode(node.getValue()); } - + } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java index a8349be1b4..37bb277858 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java @@ -1,6 +1,25 @@ package org.opendaylight.controller.sal.compatibility; -import com.google.common.net.InetAddresses; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.CRUDP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.ETHERNET_ARP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.TCP; +import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.UDP; +import static org.opendaylight.controller.sal.match.MatchType.DL_DST; +import static org.opendaylight.controller.sal.match.MatchType.DL_SRC; +import static org.opendaylight.controller.sal.match.MatchType.DL_TYPE; +import static org.opendaylight.controller.sal.match.MatchType.DL_VLAN; +import static org.opendaylight.controller.sal.match.MatchType.DL_VLAN_PR; +import static org.opendaylight.controller.sal.match.MatchType.NW_DST; +import static org.opendaylight.controller.sal.match.MatchType.NW_PROTO; +import static org.opendaylight.controller.sal.match.MatchType.NW_SRC; +import static org.opendaylight.controller.sal.match.MatchType.NW_TOS; +import static org.opendaylight.controller.sal.match.MatchType.TP_DST; +import static org.opendaylight.controller.sal.match.MatchType.TP_SRC; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.opendaylight.controller.sal.action.Controller; import org.opendaylight.controller.sal.action.Drop; @@ -33,7 +52,6 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types. import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.ActionList; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.VlanCfi; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.ControllerActionCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionCase; @@ -88,26 +106,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanId; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.ETHERNET_ARP; -import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.CRUDP; -import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.TCP; -import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.UDP; -import static org.opendaylight.controller.sal.match.MatchType.DL_DST; -import static org.opendaylight.controller.sal.match.MatchType.DL_SRC; -import static org.opendaylight.controller.sal.match.MatchType.DL_TYPE; -import static org.opendaylight.controller.sal.match.MatchType.DL_VLAN; -import static org.opendaylight.controller.sal.match.MatchType.DL_VLAN_PR; -import static org.opendaylight.controller.sal.match.MatchType.NW_DST; -import static org.opendaylight.controller.sal.match.MatchType.NW_PROTO; -import static org.opendaylight.controller.sal.match.MatchType.NW_SRC; -import static org.opendaylight.controller.sal.match.MatchType.NW_TOS; -import static org.opendaylight.controller.sal.match.MatchType.TP_DST; -import static org.opendaylight.controller.sal.match.MatchType.TP_SRC; +import com.google.common.net.InetAddresses; public class ToSalConversionsUtils { @@ -484,11 +483,11 @@ public class ToSalConversionsUtils { private static void fillFromArp(Match target, ArpMatch source) { Ipv4Prefix sourceAddress = source.getArpSourceTransportAddress(); if (sourceAddress != null) { - target.setField(NW_SRC, (InetAddress) inetAddressFrom(sourceAddress), null); + target.setField(NW_SRC, inetAddressFrom(sourceAddress), null); } Ipv4Prefix destAddress = source.getArpTargetTransportAddress(); if (destAddress != null) { - target.setField(NW_DST, (InetAddress) inetAddressFrom(destAddress), null); + target.setField(NW_DST, inetAddressFrom(destAddress), null); } ArpSourceHardwareAddress sourceHwAddress = source.getArpSourceHardwareAddress(); if (sourceHwAddress != null) { @@ -506,22 +505,22 @@ public class ToSalConversionsUtils { private static void fillFromIpv6(Match target, Ipv6Match source) { Ipv6Prefix sourceAddress = source.getIpv6Source(); if (sourceAddress != null) { - target.setField(NW_SRC, (InetAddress) inetAddressFrom(sourceAddress), null); + target.setField(NW_SRC, inetAddressFrom(sourceAddress), null); } Ipv6Prefix destAddress = source.getIpv6Destination(); if (destAddress != null) { - target.setField(NW_DST, (InetAddress) inetAddressFrom(destAddress), null); + target.setField(NW_DST, inetAddressFrom(destAddress), null); } } private static void fillFromIpv4(Match target, Ipv4Match source) { Ipv4Prefix sourceAddress = source.getIpv4Source(); if (sourceAddress != null) { - target.setField(NW_SRC, (InetAddress) inetAddressFrom(sourceAddress), null); + target.setField(NW_SRC, inetAddressFrom(sourceAddress), null); } Ipv4Prefix destAddress = source.getIpv4Destination(); if (destAddress != null) { - target.setField(NW_DST, (InetAddress) inetAddressFrom(destAddress), null); + target.setField(NW_DST, inetAddressFrom(destAddress), null); } } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java index 09585d6273..149544b6c4 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java @@ -8,6 +8,8 @@ import java.util.concurrent.Future; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.controller.sal.common.util.Futures; import org.opendaylight.controller.sal.common.util.Rpcs; +import org.opendaylight.controller.sal.compatibility.FromSalConversionsUtils; +import org.opendaylight.controller.sal.compatibility.InventoryMapping; import org.opendaylight.controller.sal.compatibility.NodeMapping; import org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils; import org.opendaylight.controller.sal.core.ConstructionException; @@ -19,87 +21,78 @@ import org.opendaylight.controller.sal.reader.IReadServiceListener; import org.opendaylight.controller.sal.reader.NodeConnectorStatistics; import org.opendaylight.controller.sal.reader.NodeDescription; import org.opendaylight.controller.sal.reader.NodeTableStatistics; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter32; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter64; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdateBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForGivenMatchOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsFromFlowTableInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsFromFlowTableOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsFromFlowTableOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllNodeConnectorStatisticsInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllNodeConnectorStatisticsOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllNodeConnectorStatisticsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsOutputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowTableStatisticsInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowTableStatisticsOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowTableStatisticsOutputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetNodeConnectorStatisticsInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetNodeConnectorStatisticsOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetNodeConnectorStatisticsOutputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.NodeConnectorStatisticsUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.get.all.flow.statistics.output.FlowStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.get.all.flow.statistics.output.FlowStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.get.all.node.connector.statistics.output.NodeConnectorStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.statistics.Duration; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.statistics.DurationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMapBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.duration.DurationBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.Bytes; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.BytesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.Packets; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.PacketsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMapBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, IReadServiceListener { +public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, IReadServiceListener{ private static final Logger LOG = LoggerFactory.getLogger(FlowStatisticsAdapter.class); private IReadService readDelegate; private NotificationProviderService notifier; @Override - public Future> getAllFlowStatistics(GetAllFlowStatisticsInput input) { - GetAllFlowStatisticsOutput rpcResultType = null; - boolean rpcResultBool = false; - - try { - Node adNode = NodeMapping.toADNode(input.getNode()); - List flowsOnNode = readDelegate.readAllFlows(adNode); - List flowsStatistics = toOdFlowsStatistics(flowsOnNode); - GetAllFlowStatisticsOutputBuilder builder = new GetAllFlowStatisticsOutputBuilder(); - rpcResultType = builder.setFlowStatistics(flowsStatistics).build(); - rpcResultBool = true; - } catch (ConstructionException e) { - LOG.error(e.getMessage()); - } + public Future> getAggregateFlowStatisticsFromFlowTableForAllFlows( + GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput input) { + //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and + // generating aggregate flow statistics out of those individual flow stats. + return null; + } - return Futures.immediateFuture(Rpcs.getRpcResult(rpcResultBool, rpcResultType, null)); + @Override + public Future> getAggregateFlowStatisticsFromFlowTableForGivenMatch( + GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput input) { + //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and + // generating aggregate flow statistics out of those individual flow stats. + return null; } @Override - public Future> getAllNodeConnectorStatistics( - GetAllNodeConnectorStatisticsInput input) { - GetAllNodeConnectorStatisticsOutput rpcResultType = null; + public Future> getAllFlowStatisticsFromFlowTable( + GetAllFlowStatisticsFromFlowTableInput input) { + GetAllFlowStatisticsFromFlowTableOutput rpcResultType = null; boolean rpcResultBool = false; try { Node adNode = NodeMapping.toADNode(input.getNode()); - List nodesConnectorStatistics = readDelegate.readNodeConnectors(adNode); - List odNodesConnectorStatistics; - odNodesConnectorStatistics = toOdNodesConnectorStatistics(nodesConnectorStatistics); - GetAllNodeConnectorStatisticsOutputBuilder builder = new GetAllNodeConnectorStatisticsOutputBuilder(); - rpcResultType = builder.setNodeConnectorStatistics(odNodesConnectorStatistics).build(); + List flowsOnNode = readDelegate.readAllFlows(adNode); + List flowsStatistics = toOdFlowsStatistics(flowsOnNode); + GetAllFlowStatisticsFromFlowTableOutputBuilder builder = new GetAllFlowStatisticsFromFlowTableOutputBuilder(); + builder.setTransactionId(new TransactionId(new BigInteger("0"))); + rpcResultType = builder.setFlowAndStatisticsMapList(flowsStatistics).build(); + rpcResultBool = true; } catch (ConstructionException e) { LOG.error(e.getMessage()); @@ -108,17 +101,24 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, return Futures.immediateFuture(Rpcs.getRpcResult(rpcResultBool, rpcResultType, null)); } + /** + * Essentially this API will return the same result as getAllFlowStatisticsFromFlowTable + */ @Override - public Future> getFlowStatistics(GetFlowStatisticsInput input) { - GetFlowStatisticsOutput rpcResultType = null; + public Future> getAllFlowsStatisticsFromAllFlowTables( + GetAllFlowsStatisticsFromAllFlowTablesInput input) { + + GetAllFlowsStatisticsFromAllFlowTablesOutput rpcResultType = null; boolean rpcResultBool = false; try { - Node node = NodeMapping.toADNode(input.getNode()); - Flow flow = ToSalConversionsUtils.toFlow(input); - FlowOnNode readFlow = readDelegate.readFlow(node, flow); - FlowStatistics flowOnNodeToFlowStatistics = toOdFlowStatistics(readFlow); - rpcResultType = new GetFlowStatisticsOutputBuilder(flowOnNodeToFlowStatistics).build(); + Node adNode = NodeMapping.toADNode(input.getNode()); + List flowsOnNode = readDelegate.readAllFlows(adNode); + List flowsStatistics = toOdFlowsStatistics(flowsOnNode); + GetAllFlowsStatisticsFromAllFlowTablesOutputBuilder builder = new GetAllFlowsStatisticsFromAllFlowTablesOutputBuilder(); + builder.setTransactionId(new TransactionId(new BigInteger("0"))); + rpcResultType = builder.setFlowAndStatisticsMapList(flowsStatistics).build(); + rpcResultBool = true; } catch (ConstructionException e) { LOG.error(e.getMessage()); @@ -128,38 +128,18 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, } @Override - public Future> getFlowTableStatistics(GetFlowTableStatisticsInput input) { - GetFlowTableStatisticsOutput rpcResultType = null; + public Future> getFlowStatisticsFromFlowTable( + GetFlowStatisticsFromFlowTableInput input) { + GetFlowStatisticsFromFlowTableOutput rpcResultType = null; boolean rpcResultBool = false; try { Node node = NodeMapping.toADNode(input.getNode()); - List nodesTable = readDelegate.readNodeTable(node); - NodeTableStatistics nodeTable = null; - if (!nodesTable.isEmpty()) { - nodeTable = nodesTable.get(0); - rpcResultType = toOdTableStatistics(nodeTable); - rpcResultBool = true; - } - } catch (ConstructionException e) { - LOG.error(e.getMessage()); - } - - return Futures.immediateFuture(Rpcs.getRpcResult(rpcResultBool, rpcResultType, null)); - } - - @Override - public Future> getNodeConnectorStatistics( - GetNodeConnectorStatisticsInput input) { - GetNodeConnectorStatisticsOutput rpcResultType = null; - boolean rpcResultBool = false; - - NodeConnectorRef nodeConnector = input.getNodeConnector(); - try { - NodeConnectorStatistics nodeConnectorStats = readDelegate.readNodeConnector(NodeMapping - .toADNodeConnector(nodeConnector)); - org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.get.all.node.connector.statistics.output.NodeConnectorStatistics odNodeConnectorStatistics = toOdNodeConnectorStatistics(nodeConnectorStats); - rpcResultType = new GetNodeConnectorStatisticsOutputBuilder(odNodeConnectorStatistics).build(); + Flow flow = ToSalConversionsUtils.toFlow(input); + FlowOnNode readFlow = readDelegate.readFlow(node, flow); + List flowOnNodeToFlowStatistics = new ArrayList(); + flowOnNodeToFlowStatistics.add(toOdFlowStatistics(readFlow)); + rpcResultType = new GetFlowStatisticsFromFlowTableOutputBuilder().setFlowAndStatisticsMapList(flowOnNodeToFlowStatistics).build(); rpcResultBool = true; } catch (ConstructionException e) { LOG.error(e.getMessage()); @@ -169,59 +149,74 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, } @Override - public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) { - - // TODO which *StatisticsUpdated interface should be used? - + public void nodeFlowStatisticsUpdated(Node node, List flowStatsList) { + List flowStatistics = toOdFlowsStatistics(flowStatsList); + FlowsStatisticsUpdateBuilder flowsStatisticsUpdateBuilder = new FlowsStatisticsUpdateBuilder(); + flowsStatisticsUpdateBuilder.setFlowAndStatisticsMapList(flowStatistics); + flowsStatisticsUpdateBuilder.setMoreReplies(false); + flowsStatisticsUpdateBuilder.setTransactionId(null); + flowsStatisticsUpdateBuilder.setId(InventoryMapping.toNodeKey(node).getId()); + notifier.publish(flowsStatisticsUpdateBuilder.build()); } @Override public void nodeConnectorStatisticsUpdated(Node node, List ncStatsList) { - for (NodeConnectorStatistics ndConStats : ncStatsList) { - org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.get.all.node.connector.statistics.output.NodeConnectorStatistics odNodeConnectorStatistics; - odNodeConnectorStatistics = toOdNodeConnectorStatistics(ndConStats); - NodeConnectorStatisticsUpdatedBuilder statisticsBuilder = new NodeConnectorStatisticsUpdatedBuilder( - odNodeConnectorStatistics); - notifier.publish(statisticsBuilder.build()); - } - } - - @Override - public void nodeFlowStatisticsUpdated(Node node, List flowStatsList) { - for (FlowOnNode flowOnNode : flowStatsList) { - FlowStatistics flowStatistics = toOdFlowStatistics(flowOnNode); - FlowStatisticsUpdatedBuilder statisticsBuilder = new FlowStatisticsUpdatedBuilder(flowStatistics); - notifier.publish(statisticsBuilder.build()); - } + NodeConnectorStatisticsUpdateBuilder nodeConnectorStatisticsUpdateBuilder = new NodeConnectorStatisticsUpdateBuilder(); + List nodeConnectorStatistics = toOdNodeConnectorStatistics(ncStatsList); + + nodeConnectorStatisticsUpdateBuilder.setNodeConnectorStatisticsAndPortNumberMap(nodeConnectorStatistics); + nodeConnectorStatisticsUpdateBuilder.setMoreReplies(false); + nodeConnectorStatisticsUpdateBuilder.setTransactionId(null); + nodeConnectorStatisticsUpdateBuilder.setId(InventoryMapping.toNodeKey(node).getId()); + notifier.publish(nodeConnectorStatisticsUpdateBuilder.build()); } @Override public void nodeTableStatisticsUpdated(Node node, List tableStatsList) { - // TODO : Not implemented by AD-SAL. + + FlowTableStatisticsUpdateBuilder flowTableStatisticsUpdateBuilder = new FlowTableStatisticsUpdateBuilder(); + + List flowTableStatistics = toOdFlowTableStatistics(tableStatsList); + flowTableStatisticsUpdateBuilder.setFlowTableAndStatisticsMap(flowTableStatistics); + flowTableStatisticsUpdateBuilder.setMoreReplies(false); + flowTableStatisticsUpdateBuilder.setTransactionId(null); + flowTableStatisticsUpdateBuilder.setId(InventoryMapping.toNodeKey(node).getId()); + notifier.publish(flowTableStatisticsUpdateBuilder.build()); +} + + @Override + public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) { + // TODO which *StatisticsUpdated interface should be used? + } - private List toOdFlowsStatistics(List flowsOnNode) { - List flowsStatistics = new ArrayList<>(); + private List toOdFlowsStatistics(List flowsOnNode) { + List flowsStatistics = new ArrayList<>(); for (FlowOnNode flowOnNode : flowsOnNode) { flowsStatistics.add(toOdFlowStatistics(flowOnNode)); } return flowsStatistics; } - private FlowStatistics toOdFlowStatistics(FlowOnNode flowOnNode) { - FlowStatisticsBuilder builder = new FlowStatisticsBuilder(); + private FlowAndStatisticsMapList toOdFlowStatistics(FlowOnNode flowOnNode) { + FlowAndStatisticsMapListBuilder builder = new FlowAndStatisticsMapListBuilder(); builder.setByteCount(toCounter64(flowOnNode.getByteCount())); builder.setPacketCount(toCounter64(flowOnNode.getPacketCount())); builder.setDuration(extractDuration(flowOnNode)); - + builder.setMatch(FromSalConversionsUtils.toMatch(flowOnNode.getFlow().getMatch())); + builder.setPriority((int)flowOnNode.getFlow().getPriority()); + builder.setHardTimeout((int)flowOnNode.getFlow().getHardTimeout()); + builder.setIdleTimeout((int)flowOnNode.getFlow().getIdleTimeout()); + //TODO: actions to instruction conversion + builder.setInstructions(null); return builder.build(); } - private Duration extractDuration(FlowOnNode flowOnNode) { + private org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.duration.Duration extractDuration(FlowOnNode flowOnNode) { DurationBuilder builder = new DurationBuilder(); - builder.setNanosecond(toCounter64(flowOnNode.getDurationNanoseconds())); - builder.setSecond(toCounter64(flowOnNode.getDurationSeconds())); + builder.setNanosecond(new Counter32((long)flowOnNode.getDurationNanoseconds())); + builder.setSecond(new Counter32((long)flowOnNode.getDurationSeconds())); return builder.build(); } @@ -231,38 +226,43 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, return new Counter64(byteCountBigInt); } - private Counter64 toCounter64(int num) { - String byteCountStr = String.valueOf(num); - BigInteger byteCountBigInt = new BigInteger(byteCountStr); - return new Counter64(byteCountBigInt); - } - - private List toOdNodesConnectorStatistics( - List nodesConnectorStatistics) { - List odNodesConnectorStatistics = new ArrayList<>(); - for (NodeConnectorStatistics nodeConnectorStatistics : nodesConnectorStatistics) { - odNodesConnectorStatistics.add(toOdNodeConnectorStatistics(nodeConnectorStatistics)); + private List toOdFlowTableStatistics(List tableStatsList) { + + List flowTableStatsMap = new ArrayList(); + for (NodeTableStatistics nodeTableStatistics : tableStatsList) { + FlowTableAndStatisticsMapBuilder flowTableAndStatisticsMapBuilder = new FlowTableAndStatisticsMapBuilder(); + flowTableAndStatisticsMapBuilder.setActiveFlows(new Counter32((long) nodeTableStatistics.getActiveCount())); + flowTableAndStatisticsMapBuilder.setPacketsLookedUp(toCounter64(nodeTableStatistics.getLookupCount())); + flowTableAndStatisticsMapBuilder.setPacketsMatched(toCounter64(nodeTableStatistics.getMatchedCount())); + flowTableAndStatisticsMapBuilder.setActiveFlows(new Counter32((long) nodeTableStatistics.getActiveCount())); + flowTableAndStatisticsMapBuilder.setTableId(new TableId((short)nodeTableStatistics.getNodeTable().getID())); + flowTableStatsMap.add(flowTableAndStatisticsMapBuilder.build()); } - return odNodesConnectorStatistics; + + return flowTableStatsMap; } - private org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.get.all.node.connector.statistics.output.NodeConnectorStatistics toOdNodeConnectorStatistics( - NodeConnectorStatistics ndConStats) { - NodeConnectorStatisticsBuilder builder = new NodeConnectorStatisticsBuilder(); - - builder.setBytes(extractBytes(ndConStats)); - builder.setCollisionCount(toBI(ndConStats.getCollisionCount())); - builder.setDuration(null); - builder.setPackets(extractPackets(ndConStats)); - builder.setReceiveCrcError(toBI(ndConStats.getReceiveCRCErrorCount())); - builder.setReceiveDrops(toBI(ndConStats.getReceiveDropCount())); - builder.setReceiveErrors(toBI(ndConStats.getReceiveErrorCount())); - builder.setReceiveFrameError(toBI(ndConStats.getReceiveFrameErrorCount())); - builder.setReceiveOverRunError(toBI(ndConStats.getReceiveOverRunErrorCount())); - builder.setTransmitDrops(toBI(ndConStats.getTransmitDropCount())); - builder.setTransmitErrors(toBI(ndConStats.getTransmitErrorCount())); - - return builder.build(); + private List toOdNodeConnectorStatistics( + List ncStatsList) { + List nodeConnectorStatisticsList = new ArrayList(); + for(NodeConnectorStatistics ofNodeConnectorStatistics : ncStatsList){ + NodeConnectorStatisticsAndPortNumberMapBuilder nodeConnectorStatisticsAndPortNumberMapBuilder = new NodeConnectorStatisticsAndPortNumberMapBuilder(); + + nodeConnectorStatisticsAndPortNumberMapBuilder.setBytes(extractBytes(ofNodeConnectorStatistics)); + nodeConnectorStatisticsAndPortNumberMapBuilder.setCollisionCount(toBI(ofNodeConnectorStatistics.getCollisionCount())); + nodeConnectorStatisticsAndPortNumberMapBuilder.setDuration(null); + nodeConnectorStatisticsAndPortNumberMapBuilder.setPackets(extractPackets(ofNodeConnectorStatistics)); + nodeConnectorStatisticsAndPortNumberMapBuilder.setReceiveCrcError(toBI(ofNodeConnectorStatistics.getReceiveCRCErrorCount())); + nodeConnectorStatisticsAndPortNumberMapBuilder.setReceiveDrops(toBI(ofNodeConnectorStatistics.getReceiveDropCount())); + nodeConnectorStatisticsAndPortNumberMapBuilder.setReceiveErrors(toBI(ofNodeConnectorStatistics.getReceiveErrorCount())); + nodeConnectorStatisticsAndPortNumberMapBuilder.setReceiveFrameError(toBI(ofNodeConnectorStatistics.getReceiveFrameErrorCount())); + nodeConnectorStatisticsAndPortNumberMapBuilder.setReceiveOverRunError(toBI(ofNodeConnectorStatistics.getReceiveOverRunErrorCount())); + nodeConnectorStatisticsAndPortNumberMapBuilder.setTransmitDrops(toBI(ofNodeConnectorStatistics.getTransmitDropCount())); + nodeConnectorStatisticsAndPortNumberMapBuilder.setTransmitErrors(toBI(ofNodeConnectorStatistics.getTransmitErrorCount())); + nodeConnectorStatisticsList.add(nodeConnectorStatisticsAndPortNumberMapBuilder.build()); + } + + return nodeConnectorStatisticsList; } private BigInteger toBI(long num) { @@ -292,49 +292,4 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, return builder.build(); } - private GetFlowTableStatisticsOutput toOdTableStatistics(NodeTableStatistics nodeTable) { - GetFlowTableStatisticsOutputBuilder builder = new GetFlowTableStatisticsOutputBuilder(); - - builder.setActive(toCounter64(nodeTable.getActiveCount())); - builder.setLookup(toCounter64(nodeTable.getLookupCount())); - builder.setMatched(toCounter64(nodeTable.getMatchedCount())); - - return builder.build(); - } - - @Override - public Future> getAggregateFlowStatisticsFromFlowTableForAllFlows( - GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput input) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Future> getAggregateFlowStatisticsFromFlowTableForGivenMatch( - GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput input) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Future> getAllFlowStatisticsFromFlowTable( - GetAllFlowStatisticsFromFlowTableInput input) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Future> getAllFlowsStatisticsFromAllFlowTables( - GetAllFlowsStatisticsFromAllFlowTablesInput input) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Future> getFlowStatisticsFromFlowTable( - GetFlowStatisticsFromFlowTableInput input) { - // TODO Auto-generated method stub - return null; - } - } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransaction.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransaction.xtend index 5203d3c1a8..6fcadea8bf 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransaction.xtend +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransaction.xtend @@ -15,6 +15,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.N import org.opendaylight.yangtools.yang.binding.DataObject import org.opendaylight.yangtools.yang.binding.InstanceIdentifier import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef class FlowTransaction extends AbstractTransaction { @@ -32,6 +33,7 @@ class FlowTransaction extends AbstractTransaction { val tableInstanceId = instanceId.firstIdentifierOf(Table); val nodeInstanceId = instanceId.firstIdentifierOf(Node); val builder = new RemoveFlowInputBuilder(flow); + builder.setFlowRef(new FlowRef(instanceId)); builder.setNode(new NodeRef(nodeInstanceId)); builder.setFlowTable(new FlowTableRef(tableInstanceId)); _salFlowService.removeFlow(builder.build()); @@ -45,6 +47,7 @@ class FlowTransaction extends AbstractTransaction { val nodeInstanceId = instanceId.firstIdentifierOf(Node); val builder = new UpdateFlowInputBuilder(); builder.setNode(new NodeRef(nodeInstanceId)); + builder.setFlowRef(new FlowRef(instanceId)); val ufb = new UpdatedFlowBuilder(updatedFlow); builder.setUpdatedFlow((ufb.build())); val ofb = new OriginalFlowBuilder(originalFlow); @@ -61,6 +64,7 @@ class FlowTransaction extends AbstractTransaction { val nodeInstanceId = instanceId.firstIdentifierOf(Node); val builder = new AddFlowInputBuilder(flow); builder.setNode(new NodeRef(nodeInstanceId)); + builder.setFlowRef(new FlowRef(instanceId)); builder.setFlowTable(new FlowTableRef(tableInstanceId)); _salFlowService.addFlow(builder.build()); } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransaction.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransaction.xtend index 54382ea056..d68ffa09fa 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransaction.xtend +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransaction.xtend @@ -2,26 +2,18 @@ package org.opendaylight.controller.frm.group import org.opendaylight.controller.frm.AbstractTransaction import org.opendaylight.controller.md.sal.common.api.data.DataModification -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInputBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node import org.opendaylight.yangtools.yang.binding.DataObject import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder class GroupTransaction extends AbstractTransaction { @@ -39,6 +31,7 @@ class GroupTransaction extends AbstractTransaction { val nodeInstanceId = instanceId.firstIdentifierOf(Node); val builder = new RemoveGroupInputBuilder(group); builder.setNode(new NodeRef(nodeInstanceId)); + builder.setGroupRef(new GroupRef(instanceId)); _groupService.removeGroup(builder.build()); } } @@ -50,6 +43,7 @@ class GroupTransaction extends AbstractTransaction { val nodeInstanceId = instanceId.firstIdentifierOf(Node); val builder = new UpdateGroupInputBuilder(); builder.setNode(new NodeRef(nodeInstanceId)); + builder.setGroupRef(new GroupRef(instanceId)); val ufb = new UpdatedGroupBuilder(updatedGroup); builder.setUpdatedGroup((ufb.build())); val ofb = new OriginalGroupBuilder(originalGroup); @@ -65,6 +59,7 @@ class GroupTransaction extends AbstractTransaction { val nodeInstanceId = instanceId.firstIdentifierOf(Node); val builder = new AddGroupInputBuilder(group); builder.setNode(new NodeRef(nodeInstanceId)); + builder.setGroupRef(new GroupRef(instanceId)); _groupService.addGroup(builder.build()); } } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransaction.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransaction.xtend index 3ed1f40735..d64f2518a8 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransaction.xtend +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransaction.xtend @@ -13,6 +13,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.met import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter import org.opendaylight.yangtools.yang.binding.DataObject import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef class MeterTransaction extends AbstractTransaction { @@ -30,6 +31,7 @@ class MeterTransaction extends AbstractTransaction { val nodeInstanceId = instanceId.firstIdentifierOf(Node); val builder = new RemoveMeterInputBuilder(meter); builder.setNode(new NodeRef(nodeInstanceId)); + builder.setMeterRef(new MeterRef(instanceId)); _salMeterService.removeMeter(builder.build()); } } @@ -41,6 +43,7 @@ class MeterTransaction extends AbstractTransaction { val nodeInstanceId = instanceId.firstIdentifierOf(Node); val builder = new UpdateMeterInputBuilder(); builder.setNode(new NodeRef(nodeInstanceId)); + builder.setMeterRef(new MeterRef(instanceId)); val ufb = new UpdatedMeterBuilder(updatedMeter); builder.setUpdatedMeter((ufb.build())); val ofb = new OriginalMeterBuilder(originalMeter); @@ -56,6 +59,7 @@ class MeterTransaction extends AbstractTransaction { val nodeInstanceId = instanceId.firstIdentifierOf(Node); val builder = new AddMeterInputBuilder(meter); builder.setNode(new NodeRef(nodeInstanceId)); + builder.setMeterRef(new MeterRef(instanceId)); _salMeterService.addMeter(builder.build()); } } diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/group-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/group-types.yang index 8c874e2fe8..4442fbb335 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/group-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/group-types.yang @@ -84,6 +84,10 @@ module opendaylight-group-types { description "Check chaining for loops and delete"; } + typedef group-ref { + type instance-identifier; + } + grouping group { leaf group-type { @@ -102,10 +106,6 @@ module opendaylight-group-types { type string; } - leaf install { - type boolean; - } - leaf barrier { type boolean; } diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/meter-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/meter-types.yang index b380af2212..d84b2f0851 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/meter-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/meter-types.yang @@ -112,6 +112,10 @@ module opendaylight-meter-types { } } + typedef meter-ref { + type instance-identifier; + } + grouping meter { leaf flags { @@ -120,11 +124,12 @@ module opendaylight-meter-types { leaf meter-id { type meter-id; - } + } - leaf install { + leaf barrier { type boolean; } + leaf meter-name { type string; } diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-flow-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-flow-types.yang index 2bcd405223..a0beb2a84c 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-flow-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-flow-types.yang @@ -12,6 +12,10 @@ module opendaylight-flow-types { description "Initial revision of flow service"; } + typedef flow-ref { + type instance-identifier; + } + typedef output-port-values { type enumeration { enum MAX { diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/port-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/port-types.yang index f0b7e97a15..bc05894da8 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/port-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/port-types.yang @@ -4,6 +4,7 @@ module opendaylight-port-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-queue-types {prefix queue-types; revision-date "2013-09-25";} revision "2013-09-25" { description "Initial revision of Port Inventory model"; @@ -86,6 +87,13 @@ module opendaylight-port-types { uses flow-capable-port; } + grouping queues { + list queue { + key "queue-id"; + uses queue-types:queue-packet; + } + } + grouping flow-capable-port { uses common-port; @@ -126,6 +134,8 @@ module opendaylight-port-types { units "kbps"; description "Max port bit rate in kbps"; } + + uses queues; } grouping port-mod { 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 index 57a92378c0..06f832e114 100644 --- 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 @@ -9,6 +9,11 @@ module opendaylight-queue-types { description "Initial revision of Queue Inventory model"; } + typedef queue-id { + type yang:counter32; + description "id for the specific queue."; + } + typedef queue-properties { type enumeration { enum min_rate; @@ -37,8 +42,6 @@ module opendaylight-queue-types { } } - - grouping queue-prop-max-rate { @@ -54,7 +57,7 @@ module opendaylight-queue-types { leaf queue-id { - type uint32; + type queue-id; description "id for the specific queue."; } diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-service.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-service.yang index 07678f57e1..d6a31c30de 100644 --- a/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-service.yang +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-service.yang @@ -51,6 +51,9 @@ module sal-flow { rpc add-flow { input { + leaf flow-ref { + type types:flow-ref; + } uses node-flow; uses tr:transaction-aware; } @@ -61,6 +64,9 @@ module sal-flow { rpc remove-flow { input { + leaf flow-ref { + type types:flow-ref; + } uses node-flow; uses tr:transaction-aware; } @@ -71,6 +77,9 @@ module sal-flow { rpc update-flow { input { + leaf flow-ref { + type types:flow-ref; + } uses flow-update; uses tr:transaction-aware; } @@ -80,15 +89,28 @@ module sal-flow { } notification flow-added { + leaf flow-ref { + type types:flow-ref; + } uses node-flow; + uses tr:transaction-aware; } notification flow-updated { + leaf flow-ref { + type types:flow-ref; + } uses node-flow; + uses tr:transaction-aware; + } notification flow-removed { + leaf flow-ref { + type types:flow-ref; + } uses node-flow; + uses tr:transaction-aware; } notification switch-flow-removed { 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 9106bca8a4..6cc1537ebc 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 @@ -31,6 +31,9 @@ module sal-group { rpc add-group { input { + leaf group-ref { + type group-type:group-ref; + } uses node-group; uses tr:transaction-aware; } @@ -41,6 +44,9 @@ module sal-group { rpc remove-group { input { + leaf group-ref { + type group-type:group-ref; + } uses node-group; uses tr:transaction-aware; } @@ -51,6 +57,9 @@ module sal-group { rpc update-group { input { + leaf group-ref { + type group-type:group-ref; + } uses group-update; uses tr:transaction-aware; } @@ -60,14 +69,26 @@ module sal-group { } notification group-added { + leaf group-ref { + type group-type:group-ref; + } uses node-group; + uses tr:transaction-aware; } notification group-updated { + leaf group-ref { + type group-type:group-ref; + } uses node-group; + uses tr:transaction-aware; } notification group-removed { + leaf group-ref { + type group-type:group-ref; + } uses node-group; + uses tr:transaction-aware; } } \ No newline at end of file diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/meter-service.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/meter-service.yang index c187181e5e..6205fed529 100644 --- a/opendaylight/md-sal/model/model-flow-service/src/main/yang/meter-service.yang +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/meter-service.yang @@ -31,6 +31,9 @@ module sal-meter { rpc add-meter { input { + leaf meter-ref { + type meter-type:meter-ref; + } uses node-meter; uses tr:transaction-aware; } @@ -41,6 +44,10 @@ module sal-meter { rpc remove-meter { input { + leaf meter-ref { + type meter-type:meter-ref; + } + uses node-meter; uses tr:transaction-aware; } @@ -51,6 +58,10 @@ module sal-meter { rpc update-meter { input { + leaf meter-ref { + type meter-type:meter-ref; + } + uses meter-update; uses tr:transaction-aware; } @@ -60,14 +71,26 @@ module sal-meter { } notification meter-added { + leaf meter-ref { + type meter-type:meter-ref; + } uses node-meter; + uses tr:transaction-aware; } notification meter-updated { + leaf meter-ref { + type meter-type:meter-ref; + } uses node-meter; + uses tr:transaction-aware; } notification meter-removed { + leaf meter-ref { + type meter-type:meter-ref; + } uses node-meter; + uses tr:transaction-aware; } } \ No newline at end of file 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 d49675ad39..6795e6fd67 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 @@ -43,9 +43,14 @@ module sal-port { output { uses port-type:flow-capable-port; } - } + } + + notification port-updated { + uses port-update; + uses tr:transaction-aware; + } notification port-removed { - uses node-port; + uses node-port; } } \ No newline at end of file diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-statistics.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-statistics.yang index 3bd37bcf33..7bbcca3a12 100644 --- a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-statistics.yang +++ b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-statistics.yang @@ -115,7 +115,7 @@ module opendaylight-flow-statistics { } } - // RPC calls to fetch flow statistics + // RPC calls to fetch aggregate flow statistics rpc get-aggregate-flow-statistics-from-flow-table-for-all-flows { description "Fetch aggregate statistics for all the flows present in the specific flow table of the switch"; input { @@ -150,76 +150,4 @@ module opendaylight-flow-statistics { uses stat-types:aggregate-flow-statistics; uses tr:transaction-aware; } - - //Keeping flow statistics RPC call for backward compatibility for sal-compatibility layer --START - rpc get-flow-statistics { - input { - uses inv:node-context-ref; - uses flow-types:flow; - } - output { - uses flow-types:flow-statistics; - } - } - - rpc get-all-flow-statistics { - input { - uses inv:node-context-ref; - } - output { - list flow-statistics { - uses flow-types:flow-statistics; - } - } - } - - notification flow-statistics-updated { - uses flow-types:flow-statistics; - } - - //Keeping flow statistics RPC call for backward compatibility for sal-compatibility layer --END - - //RPC call to fetch node connector statistics - rpc get-node-connector-statistics { - input { - uses inv:node-context-ref; - leaf node-connector { - type inv:node-connector-ref; - } - } - output { - uses stat-types:node-connector-statistics; - } - } - - rpc get-all-node-connector-statistics { - input { - uses inv:node-context-ref; - } - output { - list node-connector-statistics { - uses stat-types:node-connector-statistics; - } - } - } - - rpc get-flow-table-statistics { - input { - uses inv:node-context-ref; - } - output { - uses flow-types:flow-table-statistics; - } - } - - notification flow-table-statistics-updated { - leaf flow-table { - type flow:flow-table-ref; - } - uses flow-types:flow-table-statistics; - } - - notification node-connector-statistics-updated { - uses stat-types:node-connector-statistics; - } } diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/group-statistics.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/group-statistics.yang index ebc6ead25e..5640858d51 100644 --- a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/group-statistics.yang +++ b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/group-statistics.yang @@ -18,11 +18,11 @@ module opendaylight-group-statistics { grouping group-statistics { container group-statistics { //config "false"; - uses group-types:group-statistics-reply; + uses group-types:group-statistics; } } - augment "/inv:nodes/inv:node" { + augment "/inv:nodes/inv:node/group-types:group" { ext:augment-identifier "node-group-statistics"; uses group-statistics; } @@ -30,11 +30,11 @@ module opendaylight-group-statistics { grouping group-desc { container group-desc { //config "false"; - uses group-types:group-desc-stats-reply; + uses group-types:group; } } - augment "/inv:nodes/inv:node" { + augment "/inv:nodes/inv:node/group-types:group" { ext:augment-identifier "node-group-desc-stats"; uses group-desc; } diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/meter-statistics.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/meter-statistics.yang index e3b2a3fc64..b2cf78b61d 100644 --- a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/meter-statistics.yang +++ b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/meter-statistics.yang @@ -4,6 +4,7 @@ module opendaylight-meter-statistics { import yang-ext {prefix ext; revision-date "2013-07-09";} import opendaylight-inventory {prefix inv;revision-date "2013-08-19";} + import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";} import opendaylight-meter-types {prefix meter-types;revision-date "2013-09-18";} import flow-capable-transaction {prefix tr;} @@ -15,19 +16,19 @@ module opendaylight-meter-statistics { description "Initial revision of meter statistics service"; } - augment "/inv:nodes/inv:node" { + augment "/inv:nodes/inv:node/flow-node:meter" { ext:augment-identifier "node-meter-statistics"; container meter-statistics { //config "false"; - uses meter-types:meter-statistics-reply; + uses meter-types:meter-statistics; } } - augment "/inv:nodes/inv:node" { + augment "/inv:nodes/inv:node/flow-node:meter" { ext:augment-identifier "node-meter-config-stats"; container meter-config-stats { //config "false"; - uses meter-types:meter-config-stats-reply; + uses meter-types:meter; } } diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/port-statistics.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/port-statistics.yang index 0cb6a60cfe..787a4e6aa0 100644 --- a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/port-statistics.yang +++ b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/port-statistics.yang @@ -30,19 +30,19 @@ module opendaylight-port-statistics { } // RPC calls - rpc get-all-ports-statistics { - description "Get statistics for all the ports from the node"; + rpc get-all-node-connectors-statistics { + description "Get statistics for all node connectors from the node"; input { uses inv:node-context-ref; } output { - uses stat-types:node-connector-statistics; + uses node-connector-statistics-and-port-number-map; uses tr:transaction-aware; } } - rpc get-port-statistics { - description "Get statistics for given port from the node"; + rpc get-node-connector-statistics { + description "Get statistics for given node connector from the node"; input { uses inv:node-context-ref; leaf node-connector-id { @@ -55,9 +55,9 @@ module opendaylight-port-statistics { } } - //Notification for port statistics update + //Notification for node connector statistics update grouping node-connector-statistics-and-port-number-map { - description "List of flow and statistics map"; + description "List of map - node connectors and their statistics"; list node-connector-statistics-and-port-number-map { key "node-connector-id"; leaf node-connector-id { @@ -67,7 +67,7 @@ module opendaylight-port-statistics { } } - notification port-statistics-update { + notification node-connector-statistics-update { leaf moreReplies { type boolean; } diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/queue-statistics.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/queue-statistics.yang new file mode 100644 index 0000000000..7665ef75c7 --- /dev/null +++ b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/queue-statistics.yang @@ -0,0 +1,101 @@ +module opendaylight-queue-statistics { + namespace "urn:opendaylight:queue:statistics"; + prefix queuestat; + + import flow-capable-transaction {prefix tr;} + import yang-ext {prefix ext; revision-date "2013-07-09";} + import ietf-yang-types {prefix yang; revision-date "2010-09-24";} + import opendaylight-inventory {prefix inv;revision-date "2013-08-19";} + import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";} + import opendaylight-queue-types {prefix queue-types;revision-date "2013-09-25";} + import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";} + + contact + "Anilkumar Vishnoi + Email: avishnoi@in.ibm.com"; + + revision "2013-12-16" { + description "Initial revision of queue statistics model"; + } + + //Augment queue statistics data to the flow-capable-node-connector + augment "/inv:nodes/inv:node/inv:node-connector/flow-node:queue" { + ext:augment-identifier "flow-capable-node-connector-queue-statistics-data"; + uses flow-capable-node-connector-queue-statistics; + } + + grouping flow-capable-node-connector-queue-statistics { + container flow-capable-node-connector-queue-statistics { + //config "false"; + uses stat-types:generic-queue-statistics; + } + } + + //RPC calls to fetch queue statistics + grouping queue-id-and-statistics-map { + list queue-id-and-statistics-map { + key "queue-id node-connector-id"; + leaf queue-id { + type queue-types:queue-id; + } + leaf node-connector-id { + type inv:node-connector-id; + } + + uses stat-types:generic-queue-statistics; + } + } + + rpc get-all-queues-statistics-from-all-ports { + description "Get statistics for all the queues attached to all the ports from the node"; + input { + uses inv:node-context-ref; + } + output { + uses queue-id-and-statistics-map; + uses tr:transaction-aware; + } + } + + rpc get-all-queues-statistics-from-given-port { + description "Get statistics for all queues for given port of the node"; + input { + uses inv:node-context-ref; + leaf node-connector-id { + type inv:node-connector-id; + } + } + output { + uses queue-id-and-statistics-map; + uses tr:transaction-aware; + } + } + + rpc get-queue-statistics-from-given-port { + description "Get statistics for given queues from given port of the node"; + input { + uses inv:node-context-ref; + leaf node-connector-id { + type inv:node-connector-id; + } + leaf queue-id { + type queue-types:queue-id; + } + } + output { + uses queue-id-and-statistics-map; + uses tr:transaction-aware; + } + } + + //Notification for port statistics update + + notification queue-statistics-update { + leaf moreReplies { + type boolean; + } + uses inv:node; + uses queue-id-and-statistics-map; + uses tr:transaction-aware; + } +} diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/statistics-types.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/statistics-types.yang index 6d5bec1280..7bde486e91 100644 --- a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/statistics-types.yang +++ b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/statistics-types.yang @@ -7,7 +7,18 @@ module opendaylight-statistics-types { revision "2013-09-25" { description "Initial revision of flow service"; - } + } + + grouping duration { + container duration { + leaf second { + type yang:counter32; + } + leaf nanosecond { + type yang:counter32; + } + } + } grouping node-connector-statistics { container packets { @@ -50,15 +61,7 @@ module opendaylight-statistics-types { leaf collision-count { type uint64; } - - container duration { - leaf second { - type yang:counter32; - } - leaf nanosecond { - type yang:counter32; - } - } + uses duration; } grouping generic-statistics { @@ -70,16 +73,8 @@ module opendaylight-statistics-types { leaf byte-count { type yang:counter64; } - - container duration { - leaf second { - type yang:counter64; - } - leaf nanosecond { - type yang:counter64; - } - } - } + uses duration; + } grouping generic-table-statistics { description "Generic grouping holding generic statistics related to switch table"; @@ -108,4 +103,20 @@ module opendaylight-statistics-types { } } + grouping generic-queue-statistics { + description "Generic statistics of switch port attached queues."; + leaf transmitted-bytes { + type yang:counter64; + } + + leaf transmitted-packets { + type yang:counter64; + } + + leaf transmission-errors { + type yang:counter64; + } + uses duration; + } + } \ No newline at end of file diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index 6f1b2c0c10..0d6523bc0b 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -43,7 +43,7 @@ sal-rest-connector sal-netconf-connector - zeromq-routingtable/implementation + remoterpc-routingtable/implementation sal-remoterpc-connector/implementation clustered-data-store/implementation @@ -428,6 +428,26 @@ org.apache.felix maven-bundle-plugin + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/config + ${project.build.directory}/generated-sources/sal + + + + + org.apache.maven.plugins maven-jar-plugin diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/pom.xml b/opendaylight/md-sal/remoterpc-routingtable/implementation/pom.xml similarity index 98% rename from opendaylight/md-sal/zeromq-routingtable/implementation/pom.xml rename to opendaylight/md-sal/remoterpc-routingtable/implementation/pom.xml index 2926786849..a788baf4c0 100644 --- a/opendaylight/md-sal/zeromq-routingtable/implementation/pom.xml +++ b/opendaylight/md-sal/remoterpc-routingtable/implementation/pom.xml @@ -15,7 +15,7 @@ HEAD - zeromq-routingtable.implementation + remoterpc-routingtable.implementation 0.4.1-SNAPSHOT bundle diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RouteChangeListener.java b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RouteChangeListener.java similarity index 100% rename from opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RouteChangeListener.java rename to opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RouteChangeListener.java diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java similarity index 100% rename from opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java rename to opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTableException.java b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTableException.java similarity index 100% rename from opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTableException.java rename to opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTableException.java diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/SystemException.java b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/SystemException.java similarity index 100% rename from opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/SystemException.java rename to opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/SystemException.java diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java similarity index 100% rename from opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java rename to opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java similarity index 95% rename from opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java rename to opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java index 4e1dfb0058..59292a174e 100644 --- a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java +++ b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java @@ -30,6 +30,7 @@ import javax.transaction.RollbackException; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentMap; @@ -254,6 +255,23 @@ public class RoutingTableImpl implements RoutingTable, ICacheUpdateA return this.routingTableCache; } + /** + * This is used from integration test NP rest API to check out the result of the + * cache population + * For testing purpose only-- use it wisely + * @return + */ + public String dumpRoutingTableCache(){ + Set> cacheEntrySet = this.routingTableCache.entrySet(); + StringBuilder sb = new StringBuilder(); + for(Map.Entry entry:cacheEntrySet){ + sb.append("Key:").append(entry.getKey()).append("---->Value:") + .append((entry.getValue() != null)?entry.getValue():"null") + .append("\n"); + } + return sb.toString(); + } + /** * Invoked when a new entry is available in the cache, the key is only * provided, the value will come as an entryUpdate invocation diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java similarity index 100% rename from opendaylight/md-sal/zeromq-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java rename to opendaylight/md-sal/remoterpc-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java diff --git a/opendaylight/md-sal/zeromq-routingtable/integrationtest/pom.xml b/opendaylight/md-sal/remoterpc-routingtable/integrationtest/pom.xml similarity index 98% rename from opendaylight/md-sal/zeromq-routingtable/integrationtest/pom.xml rename to opendaylight/md-sal/remoterpc-routingtable/integrationtest/pom.xml index 308d5a9316..bdc4569f31 100644 --- a/opendaylight/md-sal/zeromq-routingtable/integrationtest/pom.xml +++ b/opendaylight/md-sal/remoterpc-routingtable/integrationtest/pom.xml @@ -14,13 +14,13 @@ HEAD - zeromq-routingtable.integrationtest + remoterpc-routingtable.integrationtest 0.4.1-SNAPSHOT org.opendaylight.controller - zeromq-routingtable.implementation + remoterpc-routingtable.implementation 0.4.1-SNAPSHOT diff --git a/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java b/opendaylight/md-sal/remoterpc-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java similarity index 99% rename from opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java rename to opendaylight/md-sal/remoterpc-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java index a7929e82fc..0cf505c8cf 100644 --- a/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java +++ b/opendaylight/md-sal/remoterpc-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java @@ -120,7 +120,7 @@ public class .versionAsInProject(), mavenBundle(ODL, "sal-connector-api") .versionAsInProject(), - mavenBundle(ODL, "zeromq-routingtable.implementation") + mavenBundle(ODL, "remoterpc-routingtable.implementation") .versionAsInProject(), mavenBundle("org.jboss.spec.javax.transaction", diff --git a/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/resources/logback.xml b/opendaylight/md-sal/remoterpc-routingtable/integrationtest/src/test/resources/logback.xml similarity index 100% rename from opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/resources/logback.xml rename to opendaylight/md-sal/remoterpc-routingtable/integrationtest/src/test/resources/logback.xml diff --git a/opendaylight/md-sal/remoterpc-routingtable/integrationtest/test-nb/pom.xml b/opendaylight/md-sal/remoterpc-routingtable/integrationtest/test-nb/pom.xml new file mode 100644 index 0000000000..35b2a4b250 --- /dev/null +++ b/opendaylight/md-sal/remoterpc-routingtable/integrationtest/test-nb/pom.xml @@ -0,0 +1,92 @@ + + + 4.0.0 + + sal-remoterpc-connector-test-parent + org.opendaylight.controller.tests + 1.0-SNAPSHOT + + + remoterpc-routingtable-nb-it + bundle + + + + + org.apache.felix + maven-bundle-plugin + ${bundle.plugin.version} + true + + + + org.opendaylight.controller.tests.zmqroutingtable.rest + + + com.sun.jersey.spi.container.servlet, + org.codehaus.jackson.annotate, + javax.ws.rs, + javax.ws.rs.core, + javax.xml.bind, + javax.xml.bind.annotation, + org.slf4j, + org.apache.catalina.filters, + org.codehaus.jackson.jaxrs, + org.opendaylight.controller.sal.utils, + org.opendaylight.yangtools.yang.common, + org.opendaylight.controller.sal.connector.api, + org.opendaylight.controller.sal.connector.remoterpc.api, + org.opendaylight.controller.sal.connector.remoterpc.impl, + org.osgi.framework, + com.google.common.base, + org.opendaylight.yangtools.yang.data.api, + !org.codehaus.enunciate.jaxrs + + + /controller/nb/v2/zmqnbrt + ,${classes;ANNOTATION;javax.ws.rs.Path} + + ${project.basedir}/src/main/resources/META-INF + + + + + + + org.opendaylight.controller + containermanager + 0.5.1-SNAPSHOT + + + org.opendaylight.controller + commons.northbound + 0.4.1-SNAPSHOT + + + org.opendaylight.controller + sal + 0.5.1-SNAPSHOT + + + + org.osgi + org.osgi.core + 5.0.0 + + + junit + junit + + + org.opendaylight.controller + remoterpc-routingtable.implementation + 0.4.1-SNAPSHOT + + + com.google.guava + guava + + + + diff --git a/opendaylight/md-sal/remoterpc-routingtable/integrationtest/test-nb/src/main/java/org/opendaylight/controller/tests/zmqroutingtable/rest/RouteIdentifierImpl.java b/opendaylight/md-sal/remoterpc-routingtable/integrationtest/test-nb/src/main/java/org/opendaylight/controller/tests/zmqroutingtable/rest/RouteIdentifierImpl.java new file mode 100644 index 0000000000..6b7ee26f14 --- /dev/null +++ b/opendaylight/md-sal/remoterpc-routingtable/integrationtest/test-nb/src/main/java/org/opendaylight/controller/tests/zmqroutingtable/rest/RouteIdentifierImpl.java @@ -0,0 +1,69 @@ +package org.opendaylight.controller.tests.zmqroutingtable.rest; + +import org.opendaylight.controller.sal.connector.api.RpcRouter; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +import java.io.Serializable; +import java.net.URI; + +/** + * @author: syedbahm + * Date: 12/10/13 + */ +public class RouteIdentifierImpl implements RpcRouter.RouteIdentifier, Serializable { + + private final URI namespace; + private final QName QNAME; + private final QName instance; + + public RouteIdentifierImpl() { + namespace = URI.create("http://cisco.com/example"); + QNAME = new QName(namespace, "global"); + instance = new QName(URI.create("127.0.0.1"), "local"); + } + + public RouteIdentifierImpl(String url,String instanceIP){ + namespace = URI.create(url); + QNAME = new QName(namespace,"global"); + instance = new QName(URI.create(instanceIP), "local"); + } + + + @Override + public QName getContext() { + return QNAME; + } + + @Override + public QName getType() { + return QNAME; + } + + @Override + public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier getRoute() { + return InstanceIdentifier.of(instance); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + RouteIdentifierImpl that = (RouteIdentifierImpl) o; + + if (!QNAME.equals(that.QNAME)) return false; + if (!instance.equals(that.instance)) return false; + if (!namespace.equals(that.namespace)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = namespace.hashCode(); + result = 31 * result + QNAME.hashCode(); + result = 31 * result + instance.hashCode(); + return result; + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/remoterpc-routingtable/integrationtest/test-nb/src/main/java/org/opendaylight/controller/tests/zmqroutingtable/rest/Router.java b/opendaylight/md-sal/remoterpc-routingtable/integrationtest/test-nb/src/main/java/org/opendaylight/controller/tests/zmqroutingtable/rest/Router.java new file mode 100644 index 0000000000..c426927d52 --- /dev/null +++ b/opendaylight/md-sal/remoterpc-routingtable/integrationtest/test-nb/src/main/java/org/opendaylight/controller/tests/zmqroutingtable/rest/Router.java @@ -0,0 +1,157 @@ +package org.opendaylight.controller.tests.zmqroutingtable.rest; + +import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable; +import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException; +import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException; +import org.opendaylight.controller.sal.connector.remoterpc.impl.RoutingTableImpl; +import org.opendaylight.yangtools.yang.common.QName; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleReference; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import java.io.Serializable; +import java.net.URI; + +@Path("router") +public class Router implements Serializable { + private Logger _logger = LoggerFactory.getLogger(Router.class); + private final URI namespace = URI.create("http://cisco.com/example"); + private final QName QNAME = new QName(namespace, "heartbeat"); + + + @GET + @Path("/hello") + @Produces(MediaType.TEXT_PLAIN) + public String hello() { + return "Hello"; + } + + + + + @GET + @Path("/rtadd") + @Produces(MediaType.TEXT_PLAIN) + public String addToRoutingTable(@QueryParam("nsp") String namespace,@QueryParam("inst") String instance,@QueryParam("port") String port) { + _logger.info("Invoking adding an entry in routing table"); + + BundleContext ctx = getBundleContext(); + ServiceReference routingTableServiceReference = ctx.getServiceReference(RoutingTable.class); + if (routingTableServiceReference == null) { + _logger.debug("Could not get routing table impl reference"); + return "Could not get routingtable referen "; + } + RoutingTableImpl routingTable = (RoutingTableImpl) ctx.getService(routingTableServiceReference); + if (routingTable == null) { + _logger.info("Could not get routing table service"); + return "Could not get routing table service"; + } + + + RouteIdentifierImpl rii = new RouteIdentifierImpl(namespace,instance); + try { + routingTable.addGlobalRoute(rii, instance+":"+ port); + } catch (RoutingTableException e) { + _logger.error("error in adding routing identifier" + e.getMessage()); + + } catch (SystemException e) { + _logger.error("error in adding routing identifier" + e.getMessage()); + } + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("Result of adding route:").append("\n") + .append(routingTable.dumpRoutingTableCache()); + return stringBuilder.toString(); + } + + @GET + @Path("/rtdelete") + @Produces(MediaType.TEXT_PLAIN) + public String invokeDeleteRoutingTable(@QueryParam("nsp") String namespace,@QueryParam("inst") String instance) { + _logger.info("Invoking delete an entry in routing table"); + + BundleContext ctx = getBundleContext(); + ServiceReference routingTableServiceReference = ctx.getServiceReference(RoutingTable.class); + if (routingTableServiceReference == null) { + _logger.debug("Could not get routing table impl reference"); + return "Could not get routingtable referen "; + } + RoutingTableImpl routingTable = (RoutingTableImpl) ctx.getService(routingTableServiceReference); + if (routingTable == null) { + _logger.info("Could not get routing table service"); + return "Could not get routing table service"; + } + + + RouteIdentifierImpl rii = new RouteIdentifierImpl(namespace,instance); + try { + routingTable.removeGlobalRoute(rii); + } catch (RoutingTableException e) { + _logger.error("error in adding routing identifier" + e.getMessage()); + + } catch (SystemException e) { + _logger.error("error in adding routing identifier" + e.getMessage()); + } + + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("Result of deleting route:").append("\n") + .append(routingTable.dumpRoutingTableCache()); + + return stringBuilder.toString(); + } + + @GET + @Path("/routingtable") + @Produces(MediaType.TEXT_PLAIN) + public String invokeGetRoutingTable() { + _logger.info("Invoking getting of routing table"); + + BundleContext ctx = getBundleContext(); + ServiceReference routingTableServiceReference = ctx.getServiceReference(RoutingTable.class); + if (routingTableServiceReference == null) { + _logger.debug("Could not get routing table impl reference"); + return "Could not get routingtable referen "; + } + RoutingTableImpl routingTable = (RoutingTableImpl) ctx.getService(routingTableServiceReference); + if (routingTable == null) { + _logger.info("Could not get routing table service"); + return "Could not get routing table service"; + } + + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("Result of getting routetable:").append("\n") + .append(routingTable.dumpRoutingTableCache()); + + return stringBuilder.toString(); + } + + + + private BundleContext getBundleContext() { + ClassLoader tlcl = Thread.currentThread().getContextClassLoader(); + Bundle bundle = null; + + if (tlcl instanceof BundleReference) { + bundle = ((BundleReference) tlcl).getBundle(); + } else { + _logger.info("Unable to determine the bundle context based on " + + "thread context classloader."); + bundle = FrameworkUtil.getBundle(this.getClass()); + } + return (bundle == null ? null : bundle.getBundleContext()); + } + + + +} diff --git a/opendaylight/md-sal/remoterpc-routingtable/integrationtest/test-nb/src/main/resources/WEB-INF/web.xml b/opendaylight/md-sal/remoterpc-routingtable/integrationtest/test-nb/src/main/resources/WEB-INF/web.xml new file mode 100644 index 0000000000..2a0f3f3651 --- /dev/null +++ b/opendaylight/md-sal/remoterpc-routingtable/integrationtest/test-nb/src/main/resources/WEB-INF/web.xml @@ -0,0 +1,58 @@ + + + + JAXRSZmqRT + com.sun.jersey.spi.container.servlet.ServletContainer + + javax.ws.rs.Application + org.opendaylight.controller.northbound.commons.NorthboundApplication + + 1 + + + + JAXRSZmqRT + /* + + + + + + + NB api + /* + POST + GET + PUT + PATCH + DELETE + HEAD + + + System-Admin + Network-Admin + Network-Operator + Container-User + + + + + System-Admin + + + Network-Admin + + + Network-Operator + + + Container-User + + + + BASIC + opendaylight + + diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcAvailabilityListener.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcAvailabilityListener.java new file mode 100644 index 0000000000..e25b93918a --- /dev/null +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcAvailabilityListener.java @@ -0,0 +1,5 @@ +package org.opendaylight.controller.sal.binding.api; + +public interface RpcAvailabilityListener { + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModule.java index 48c33ad0fc..c46b0dd6b4 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModule.java @@ -36,7 +36,7 @@ public final class BindingBrokerImplModule extends org.opendaylight.controller.c @Override public java.lang.AutoCloseable createInstance() { - BindingAwareBrokerImpl broker = new BindingAwareBrokerImpl(getBundleContext()); + BindingAwareBrokerImpl broker = new BindingAwareBrokerImpl(getIdentifier().getInstanceName(),getBundleContext()); broker.setDataBroker(getDataBrokerDependency()); broker.setNotifyBroker(getNotificationServiceDependency()); broker.start(); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java index 74b6ad8a23..01dc6b8c0c 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java @@ -16,7 +16,7 @@ import java.util.concurrent.ScheduledExecutorService; import org.opendaylight.controller.config.yang.md.sal.binding.statistics.DataBrokerRuntimeMXBeanImpl; import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter; import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl; -import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.data.DataProviderService; @@ -63,7 +63,7 @@ public final class DataBrokerImplModule extends BindingIndependentMappingService mappingService = getMappingServiceDependency(); if (domBroker != null && mappingService != null) { - BindingIndependentDataServiceConnector runtimeMapping = new BindingIndependentDataServiceConnector(); + BindingIndependentConnector runtimeMapping = new BindingIndependentConnector(); runtimeMapping.setMappingService(mappingService); runtimeMapping.setBaDataService(dataBindingBroker); domBroker.registerProvider(runtimeMapping, getBundleContext()); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java index 1bf15c182f..99b7ed8acf 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java @@ -11,6 +11,7 @@ package org.opendaylight.controller.config.yang.md.sal.binding.impl; import javassist.ClassPool; +import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl; import org.osgi.framework.BundleContext; @@ -50,8 +51,7 @@ public final class RuntimeMappingModule extends @Override public java.lang.AutoCloseable createInstance() { RuntimeGeneratedMappingServiceImpl service = new RuntimeGeneratedMappingServiceImpl(); - ClassPool pool = new ClassPool(); // Should be default singleton - service.setPool(pool); + service.setPool(SingletonHolder.CLASS_POOL); service.start(getBundleContext()); return service; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java index 6672d953a2..7789a06fe8 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java @@ -86,7 +86,7 @@ public interface RuntimeCodeGenerator { * @return Instance of RpcService of provided serviceType which implements * also {@link RpcRouter} and {@link DelegateProxy} */ - RpcRouter getRouterFor(Class serviceType) throws IllegalArgumentException; + RpcRouter getRouterFor(Class serviceType,String name) throws IllegalArgumentException; NotificationInvokerFactory getInvokerFactory(); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend index f0f92da18e..dff0d215b2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend @@ -76,7 +76,6 @@ class RuntimeCodeHelper { if (field == null) throw new UnsupportedOperationException( "Unable to set routing table. Table field does not exists"); field.set(target,routingTable); - } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java new file mode 100644 index 0000000000..8b2db8b13c --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java @@ -0,0 +1,168 @@ +package org.opendaylight.controller.sal.binding.codegen.impl; + +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; +import org.opendaylight.controller.sal.binding.spi.RpcRouter; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*; + +import java.util.Map; +import java.util.Set; +import java.util.HashMap; + +import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable; +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.RpcImplementation; +import org.opendaylight.controller.md.sal.common.api.routing.MutableRoutingTable; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.util.ListenerRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +public class RpcRouterCodegenInstance implements // + RpcRouter, RouteChangeListener, InstanceIdentifier> { + + private static final Logger LOG = LoggerFactory.getLogger(RpcRouterCodegenInstance.class); + + private T defaultService; + + private final Class serviceType; + + private final T invocationProxy; + + private final Set> contexts; + + private final ListenerRegistry, InstanceIdentifier>> listeners; + + private final Map, RpcRoutingTableImpl> routingTables; + + private final String name; + + @SuppressWarnings("unchecked") + public RpcRouterCodegenInstance(String name,Class type, T routerImpl, Set> contexts, + Set> inputs) { + this.name = name; + this.listeners = ListenerRegistry.create(); + this.serviceType = type; + this.invocationProxy = routerImpl; + this.contexts = ImmutableSet.copyOf(contexts); + Map, RpcRoutingTableImpl> mutableRoutingTables = new HashMap<>(); + for (Class ctx : contexts) { + RpcRoutingTableImpl table = new RpcRoutingTableImpl<>(name,ctx,type); + + @SuppressWarnings("rawtypes") + Map invokerView = table.getRoutes(); + + setRoutingTable((RpcService) invocationProxy, ctx, invokerView); + mutableRoutingTables.put(ctx, table); + table.registerRouteChangeListener(this); + } + this.routingTables = ImmutableMap.copyOf(mutableRoutingTables); + } + + @Override + public Class getServiceType() { + return serviceType; + } + + @Override + public T getInvocationProxy() { + return invocationProxy; + } + + @Override + @SuppressWarnings("unchecked") + public RpcRoutingTable getRoutingTable(Class routeContext) { + return (RpcRoutingTable) routingTables.get(routeContext); + } + + @Override + public T getDefaultService() { + return defaultService; + } + + @Override + public Set> getContexts() { + return contexts; + } + + @Override + public , InstanceIdentifier>> ListenerRegistration registerRouteChangeListener( + L listener) { + return listeners.registerWithType(listener); + } + + @Override + public void onRouteChange(RouteChange, InstanceIdentifier> change) { + for (ListenerRegistration, InstanceIdentifier>> listener : listeners) { + try { + listener.getInstance().onRouteChange(change); + } catch (Exception e) { + LOG.error("Error occured during invoker listener {}", listener.getInstance(), e); + } + } + } + + @Override + public T getService(Class context, InstanceIdentifier path) { + return routingTables.get(context).getRoute(path); + } + + @Override + public RoutedRpcRegistration addRoutedRpcImplementation(T service) { + return new RoutedRpcRegistrationImpl(service); + } + + @Override + public RpcRegistration registerDefaultService(T service) { + // TODO Auto-generated method stub + return null; + } + + private class RoutedRpcRegistrationImpl extends AbstractObjectRegistration implements RoutedRpcRegistration { + + public RoutedRpcRegistrationImpl(T instance) { + super(instance); + } + + @Override + public Class getServiceType() { + return serviceType; + } + + @Override + public void registerPath(Class context, InstanceIdentifier path) { + routingTables.get(context).updateRoute(path, getInstance()); + } + + @Override + public void unregisterPath(Class context, InstanceIdentifier path) { + routingTables.get(context).removeRoute(path, getInstance()); + + } + + @Override + public void registerInstance(Class context, InstanceIdentifier instance) { + registerPath(context, instance); + } + + @Override + public void unregisterInstance(Class context, InstanceIdentifier instance) { + unregisterPath(context, instance); + } + + @Override + protected void removeRegistration() { + + } + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend deleted file mode 100644 index b6dcde19ee..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend +++ /dev/null @@ -1,64 +0,0 @@ -package org.opendaylight.controller.sal.binding.codegen.impl - -import org.opendaylight.yangtools.yang.binding.RpcService -import org.opendaylight.controller.sal.binding.spi.RpcRouter -import org.opendaylight.yangtools.yang.binding.BaseIdentity -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.* -import java.util.Set -import java.util.HashMap -import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable -import org.opendaylight.yangtools.yang.binding.DataContainer -import org.opendaylight.yangtools.yang.binding.RpcImplementation - -class RpcRouterCodegenInstance implements RpcRouter { - - @Property - val T invocationProxy - - @Property - val RpcImplementation invokerDelegate; - - @Property - val Class serviceType - - @Property - val Set> contexts - - @Property - val Set> supportedInputs; - - val routingTables = new HashMap, RpcRoutingTableImpl>; - - @Property - var T defaultService - - new(Class type, T routerImpl, Set> contexts, - Set> inputs) { - _serviceType = type - _invocationProxy = routerImpl - _invokerDelegate = routerImpl as RpcImplementation - _contexts = contexts - _supportedInputs = inputs; - - for (ctx : contexts) { - val table = XtendHelper.createRoutingTable(ctx) - invocationProxy.setRoutingTable(ctx, table.routes); - routingTables.put(ctx, table); - } - } - - override getRoutingTable(Class table) { - routingTables.get(table) as RpcRoutingTable - } - - override getService(Class context, InstanceIdentifier path) { - val table = getRoutingTable(context); - return table.getRoute(path); - } - - override invoke(Class type, T input) { - return invokerDelegate.invoke(type, input); - } - -} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java new file mode 100644 index 0000000000..808358fb35 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java @@ -0,0 +1,148 @@ +package org.opendaylight.controller.sal.binding.codegen.impl; + +import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Mutable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class RpcRoutingTableImpl // +implements // + Mutable, // + RpcRoutingTable, // + RouteChangePublisher, InstanceIdentifier> { + + private static final Logger LOGGER = LoggerFactory.getLogger(RpcRoutingTableImpl.class); + private final String routerName; + private final Class serviceType; + + private final Class contextType; + private final ConcurrentMap, S> routes; + private final Map, S> unmodifiableRoutes; + + private RouteChangeListener, InstanceIdentifier> listener; + private S defaultRoute; + + public RpcRoutingTableImpl(String routerName,Class contextType, Class serviceType) { + super(); + this.routerName = routerName; + this.serviceType = serviceType; + this.contextType = contextType; + this.routes = new ConcurrentHashMap<>(); + this.unmodifiableRoutes = Collections.unmodifiableMap(routes); + } + + @Override + public void setDefaultRoute(S target) { + defaultRoute = target; + } + + @Override + public S getDefaultRoute() { + return defaultRoute; + } + + @Override + public , InstanceIdentifier>> ListenerRegistration registerRouteChangeListener( + L listener) { + return (ListenerRegistration) new SingletonListenerRegistration(listener); + } + + @Override + public Class getIdentifier() { + return contextType; + } + + @Override + @SuppressWarnings("unchecked") + public void updateRoute(InstanceIdentifier path, S service) { + S previous = this.routes.put(path, service); + + LOGGER.debug("Route {} updated to {} in routing table {}",path,service,this); + @SuppressWarnings("rawtypes") + RouteChangeListener listenerCapture = listener; + if (previous == null && listenerCapture != null) { + listenerCapture.onRouteChange(RoutingUtils.announcementChange(contextType, path)); + } + } + + + @Override + @SuppressWarnings("unchecked") + public void removeRoute(InstanceIdentifier path) { + S previous = this.routes.remove(path); + LOGGER.debug("Route {} to {} removed in routing table {}",path,previous,this); + @SuppressWarnings("rawtypes") + RouteChangeListener listenerCapture = listener; + if (previous != null && listenerCapture != null) { + listenerCapture.onRouteChange(RoutingUtils.removalChange(contextType, path)); + } + } + + public void removeRoute(InstanceIdentifier path, S service) { + @SuppressWarnings("rawtypes") + RouteChangeListener listenerCapture = listener; + if (routes.remove(path, service) && listenerCapture != null) { + LOGGER.debug("Route {} to {} removed in routing table {}",path,service,this); + listenerCapture.onRouteChange(RoutingUtils.removalChange(contextType, path)); + } + } + + @Override + public S getRoute(InstanceIdentifier nodeInstance) { + S route = routes.get(nodeInstance); + if (route != null) { + return route; + } + return getDefaultRoute(); + } + + @Override + public Map, S> getRoutes() { + return unmodifiableRoutes; + } + + protected void removeAllReferences(S service) { + + } + + + + @Override + public String toString() { + return "RpcRoutingTableImpl [router=" + routerName + ", service=" + serviceType.getSimpleName() + ", context=" + + contextType.getSimpleName() + "]"; + } + + + + private class SingletonListenerRegistration, InstanceIdentifier>> extends + AbstractObjectRegistration + implements ListenerRegistration { + + public SingletonListenerRegistration(L instance) { + super(instance); + listener = instance; + } + + @Override + protected void removeRegistration() { + listener = null; + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend deleted file mode 100644 index 116a8177f9..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend +++ /dev/null @@ -1,49 +0,0 @@ -package org.opendaylight.controller.sal.binding.codegen.impl - -import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable -import org.opendaylight.yangtools.yang.binding.BaseIdentity -import org.opendaylight.yangtools.yang.binding.RpcService -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import java.util.Map -import org.opendaylight.yangtools.yang.binding.DataObject -import java.util.HashMap - -class RpcRoutingTableImpl implements RpcRoutingTable{ - - @Property - val Class identifier; - - @Property - var S defaultRoute; - - @Property - val Map,S> routes; - - new(Class ident, Map,S> route) { - _identifier = ident - _routes = route - } - - new(Class ident) { - _identifier = ident - _routes = new HashMap - } - - - override getRoute(InstanceIdentifier nodeInstance) { - val ret = routes.get(nodeInstance); - if(ret !== null) { - return ret; - } - return defaultRoute; - } - - override removeRoute(InstanceIdentifier path) { - routes.remove(path); - } - - @SuppressWarnings("rawtypes") - override updateRoute(InstanceIdentifier path, S service) { - routes.put(path as InstanceIdentifier,service); - } -} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend index 90fcbd99aa..d9e0983cfa 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend @@ -27,7 +27,7 @@ import org.opendaylight.yangtools.yang.binding.Notification import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.* import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.* import java.util.HashSet -import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.* +import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.* import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker import java.util.Set @@ -37,6 +37,8 @@ import org.opendaylight.yangtools.yang.binding.annotations.QName import org.opendaylight.yangtools.yang.binding.DataContainer import org.opendaylight.yangtools.yang.binding.RpcImplementation import org.opendaylight.controller.sal.binding.codegen.util.JavassistUtils +import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils +import javassist.LoaderClassPath class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory { @@ -45,40 +47,70 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co val extension JavassistUtils utils; val Map, RuntimeGeneratedInvokerPrototype> invokerClasses; - public new(ClassPool pool) { + + new(ClassPool pool) { classPool = pool; utils = new JavassistUtils(pool); invokerClasses = new WeakHashMap(); BROKER_NOTIFICATION_LISTENER = org.opendaylight.controller.sal.binding.api.NotificationListener.asCtClass; + pool.appendClassPath(new LoaderClassPath(RpcService.classLoader)); } override getDirectProxyFor(Class iface) { - val supertype = iface.asCtClass - val targetCls = createClass(iface.directProxyName, supertype) [ - field(DELEGATE_FIELD, iface); - implementMethodsFrom(supertype) [ - body = ''' - { - if(«DELEGATE_FIELD» == null) { + val T instance = withClassLoaderAndLock(iface.classLoader,lock) [| + val proxyName = iface.directProxyName; + val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(proxyName) + if(potentialClass != null) { + return potentialClass.newInstance as T; + } + val supertype = iface.asCtClass + val createdCls = createClass(iface.directProxyName, supertype) [ + field(DELEGATE_FIELD, iface); + implementsType(RpcImplementation.asCtClass) + implementMethodsFrom(supertype) [ + body = ''' + { + if(«DELEGATE_FIELD» == null) { + throw new java.lang.IllegalStateException("No default provider is available"); + } + return ($r) «DELEGATE_FIELD».«it.name»($$); + } + ''' + ] + implementMethodsFrom(RpcImplementation.asCtClass) [ + body = ''' + { throw new java.lang.IllegalStateException("No provider is processing supplied message"); + return ($r) null; } - return ($r) «DELEGATE_FIELD».«it.name»($$); - } - ''' + ''' + ] ] + return createdCls.toClass(iface.classLoader).newInstance as T ] - return targetCls.toClass(iface.classLoader).newInstance as T + return instance; } - override getRouterFor(Class iface) { - val instance = >withClassLoaderAndLock(iface.classLoader,lock) [ | + override getRouterFor(Class iface,String routerInstanceName) { + val metadata = withClassLoader(iface.classLoader) [| + val supertype = iface.asCtClass + return supertype.rpcMetadata; + ] + + val instance = withClassLoaderAndLock(iface.classLoader,lock) [ | val supertype = iface.asCtClass - val metadata = supertype.rpcMetadata; + val routerName = iface.routerName; + val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(routerName) + if(potentialClass != null) { + return potentialClass.newInstance as T; + } + val targetCls = createClass(iface.routerName, supertype) [ - addInterface(RpcImplementation.asCtClass) + field(DELEGATE_FIELD, iface) //field(REMOTE_INVOKER_FIELD,iface); + implementsType(RpcImplementation.asCtClass) for (ctx : metadata.contexts) { field(ctx.routingTableField, Map) @@ -95,7 +127,7 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co instance = «DELEGATE_FIELD»; } if(instance == null) { - throw new java.lang.IllegalStateException("No provider is processing supplied message"); + throw new java.lang.IllegalStateException("No routable provider is processing routed message for " + String.valueOf(identifier)); } return ($r) instance.«it.name»($$); }''' @@ -105,35 +137,18 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co } ] implementMethodsFrom(RpcImplementation.asCtClass) [ - switch (name) { - case "getSupportedInputs": - body = ''' - { - throw new java.lang.UnsupportedOperationException("Not implemented yet"); - return ($r) null; - }''' - case "invoke": { - val tmpBody = ''' - { - «FOR input : metadata.supportedInputs SEPARATOR " else "» - «val rpcMetadata = metadata.rpcInputs.get(input)» - if(«input.name».class.equals($1)) { - return ($r) this.«rpcMetadata.methodName»((«input.name») $2); - } - «ENDFOR» - throw new java.lang.IllegalArgumentException("Not supported message type"); - return ($r) null; - } - ''' - body = tmpBody - } + body = ''' + { + throw new java.lang.IllegalStateException("No provider is processing supplied message"); + return ($r) null; } + ''' ] ] - val instance = targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T - return new RpcRouterCodegenInstance(iface, instance, metadata.contexts,metadata.supportedInputs); + return targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T + ]; - return instance; + return new RpcRouterCodegenInstance(routerInstanceName,iface, instance, metadata.contexts,metadata.supportedInputs); } private def RpcServiceMetadata getRpcMetadata(CtClass iface) { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java new file mode 100644 index 0000000000..266293fb6d --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java @@ -0,0 +1,14 @@ +package org.opendaylight.controller.sal.binding.codegen.impl; + +import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator; +import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory; + +import javassist.ClassPool; + +public class SingletonHolder { + + public static final ClassPool CLASS_POOL = new ClassPool(); + public static final org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator RPC_GENERATOR_IMPL = new org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator(CLASS_POOL); + public static final RuntimeCodeGenerator RPC_GENERATOR = RPC_GENERATOR_IMPL; + public static final NotificationInvokerFactory INVOKER_FACTORY = RPC_GENERATOR_IMPL.getInvokerFactory(); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/XtendHelper.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/XtendHelper.java index 8309651446..ca1b6344e6 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/XtendHelper.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/XtendHelper.java @@ -1,12 +1,16 @@ package org.opendaylight.controller.sal.binding.codegen.impl; +import java.util.List; + import org.opendaylight.yangtools.yang.binding.BaseIdentity; import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; public class XtendHelper { - public static RpcRoutingTableImpl createRoutingTable( - Class cls) { - return new RpcRoutingTableImpl<>(cls); + @SuppressWarnings({"rawtypes","unchecked"}) + public static Iterable getTypes(UnionTypeDefinition definition) { + return (Iterable) (List) definition.getTypes(); } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java index 4b672f1140..cabb1bc4e2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java @@ -175,7 +175,7 @@ public class LazyGeneratedCodecRegistry implements // }); return ret; } catch (Exception e) { - LOG.error("Could not find augmentable for {}", augmentation, e); + LOG.debug("Could not find augmentable for {} using {}", augmentation, augmentation.getClassLoader(), e); return null; } } @@ -233,7 +233,7 @@ public class LazyGeneratedCodecRegistry implements // if (typeToClass.containsKey(typeRef)) { return; } - LOG.info("Binding Class {} encountered.", cls); + LOG.trace("Binding Class {} encountered.", cls); WeakReference weakRef = new WeakReference<>(cls); typeToClass.put(typeRef, weakRef); if (Augmentation.class.isAssignableFrom(cls)) { @@ -250,7 +250,7 @@ public class LazyGeneratedCodecRegistry implements // if (typeToClass.containsKey(typeRef)) { return; } - LOG.info("Binding Class {} encountered.", cls); + LOG.trace("Binding Class {} encountered.", cls); WeakReference weakRef = new WeakReference<>((Class) cls); typeToClass.put(typeRef, weakRef); } 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 853e62aa38..1b3acf7674 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 @@ -43,6 +43,11 @@ import java.util.ArrayList import org.opendaylight.yangtools.yang.data.api.Node import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl +import org.opendaylight.yangtools.yang.binding.RpcService +import java.util.Set +import org.opendaylight.yangtools.yang.common.QName +import com.google.common.collect.FluentIterable +import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable { @@ -65,6 +70,9 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer @Property val ConcurrentMap typeToSchemaNode = new ConcurrentHashMap(); + + @Property + val ConcurrentMap> serviceTypeToRpc = new ConcurrentHashMap(); val promisedTypeDefinitions = HashMultimap.>create; @@ -85,10 +93,17 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer registry.onModuleContextAdded(schemaContext, entry.key, entry.value); binding.pathToType.putAll(entry.value.childNodes) - //val module = entry.key; + val module = entry.key; val context = entry.value; updateBindingFor(context.childNodes, schemaContext); updateBindingFor(context.cases, schemaContext); + val namespace = BindingGeneratorUtil.moduleNamespaceToPackageName(module); + + if(!module.rpcs.empty) { + val rpcs = FluentIterable.from(module.rpcs).transform[QName].toSet + val serviceClass = new ReferencedTypeImpl(namespace,BindingGeneratorUtil.parseToClassName(module.name)+"Service"); + serviceTypeToRpc.put(serviceClass,rpcs); + } val typedefs = context.typedefs; for (typedef : typedefs.entrySet) { @@ -186,15 +201,7 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer } override dataObjectFromDataDom(InstanceIdentifier path, CompositeNode node) { - 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; - ] + dataObjectFromDataDom(path.targetType,node) as DataObject; } override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) { @@ -243,6 +250,10 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable()); } } + + override getRpcQNamesFor(Class service) { + return serviceTypeToRpc.get(new ReferencedTypeImpl(service.package.name,service.simpleName)); + } private def getSchemaWithRetry(Type type) { val typeDef = typeToSchemaNode.get(type); @@ -274,5 +285,16 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer override close() throws Exception { listenerRegistration?.unregister(); } + + override dataObjectFromDataDom(Class container, CompositeNode domData) { + return tryDeserialization[ | + if (domData == null) { + return null; + } + val transformer = registry.getCodecForDataObject(container); + val ret = transformer.deserialize(domData)?.value as DataObject; + return ret; + ] + } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend index 4271ef9c1a..5bc2d70c6a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend @@ -56,6 +56,14 @@ import javassist.CannotCompileException import java.util.concurrent.locks.Lock import java.util.concurrent.Callable import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils +import org.opendaylight.yangtools.yang.model.api.TypeDefinition +import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition +import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition +import java.util.HashSet +import java.util.Collections +import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit +import java.util.Set +import org.opendaylight.controller.sal.binding.codegen.impl.XtendHelper class TransformerGenerator { @@ -137,9 +145,13 @@ class TransformerGenerator { if (typeSpecBuilder == null) { typeSpecBuilder = pathToType.get(node.path); } + var schemaNode = typeToSchemaNode.get(ref); + if(schemaNode === null) { + schemaNode = node; + } checkState(typeSpecBuilder !== null, "Could not find TypeDefinition for %s, $s", inputType.name, node); val typeSpec = typeSpecBuilder.toInstance(); - val newret = generateTransformerFor(inputType, typeSpec, node); + val newret = generateTransformerFor(inputType, typeSpec, schemaNode); listener.onClassProcessed(inputType); return newret as Class, Object>>; ] @@ -243,19 +255,24 @@ class TransformerGenerator { transformerFor(cls, node); } - private def Class getValueSerializer(GeneratedTransferObject type) { + private def Class valueSerializer(GeneratedTransferObject type, TypeDefinition typeDefinition) { val cls = loadClassWithTCCL(type.resolvedName); val transformer = cls.generatedClass; if (transformer !== null) { return transformer; } + var baseType = typeDefinition; + while (baseType.baseType != null) { + baseType = baseType.baseType; + } + val finalType = baseType; return withClassLoaderAndLock(cls.classLoader, lock) [ | - val valueTransformer = generateValueTransformer(cls, type); + val valueTransformer = generateValueTransformer(cls, type, finalType); return valueTransformer; ] } - private def Class getValueSerializer(Enumeration type) { + private def Class valueSerializer(Enumeration type, TypeDefinition typeDefinition) { val cls = loadClassWithTCCL(type.resolvedName); val transformer = cls.generatedClass; if (transformer !== null) { @@ -340,7 +357,7 @@ class TransformerGenerator { ] ] val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) - log.info("DOM Codec for {} was generated {}", inputType, ret) + log.debug("DOM Codec for {} was generated {}", inputType, ret) return ret as Class, ?>>; } catch (Exception e) { processException(inputType, e); @@ -391,7 +408,7 @@ class TransformerGenerator { method(Object, "deserialize", Object) [ bodyChecked = ''' { - //System.out.println("«type.name»#deserialize: " +$1); + ////System.out.println("«type.name»#deserialize: " +$1); java.util.Map.Entry _input = (java.util.Map.Entry) $1; return fromDomStatic((«QName.name»)_input.getKey(),_input.getValue()); } @@ -401,7 +418,7 @@ class TransformerGenerator { val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class> listener?.onDataContainerCodecCreated(inputType, ret); - log.info("DOM Codec for {} was generated {}", inputType, ret) + log.debug("DOM Codec for {} was generated {}", inputType, ret) return ret; } catch (Exception e) { processException(inputType, e); @@ -450,7 +467,7 @@ class TransformerGenerator { val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class, Object>> listener?.onDataContainerCodecCreated(inputType, ret); - log.info("DOM Codec for {} was generated {}", inputType, ret) + log.debug("DOM Codec for {} was generated {}", inputType, ret) return ret; } catch (Exception e) { processException(inputType, e); @@ -475,14 +492,14 @@ class TransformerGenerator { modifiers = PUBLIC + FINAL + STATIC bodyChecked = ''' { - //System.out.println("Qname " + $1); - //System.out.println("Value " + $2); + ////System.out.println("Qname " + $1); + ////System.out.println("Value " + $2); «QName.name» _resultName = «QName.name».create(QNAME,QNAME.getLocalName()); java.util.List _childNodes = new java.util.ArrayList(); «type.resolvedName» value = («type.resolvedName») $2; «FOR child : node.childNodes» «var signature = properties.getFor(child)» - //System.out.println("«signature.key»" + value.«signature.key»()); + ////System.out.println("«signature.key»" + value.«signature.key»()); «serializeProperty(child, signature.value, signature.key)» «ENDFOR» return ($r) _childNodes; @@ -511,7 +528,7 @@ class TransformerGenerator { return null; } java.util.Map _compositeNode = (java.util.Map) $2; - //System.out.println(_localQName + " " + _compositeNode); + System.out.println(_localQName + " " + _compositeNode); «type.builderName» _builder = new «type.builderName»(); boolean _is_empty = true; «FOR child : node.childNodes» @@ -571,7 +588,7 @@ class TransformerGenerator { } java.util.Map.Entry _input = new «SimpleEntry.name»($1,_baValue); Object _ret = _codec.serialize(_input); - //System.out.println("«typeSpec.name»#toDomStatic: " + _ret); + ////System.out.println("«typeSpec.name»#toDomStatic: " + _ret); return («List.name») _ret; } ''' @@ -603,7 +620,7 @@ class TransformerGenerator { val rawRet = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) val ret = rawRet as Class, Object>>; listener?.onChoiceCodecCreated(inputType, ret, node); - log.info("DOM Codec for {} was generated {}", inputType, ret) + log.debug("DOM Codec for {} was generated {}", inputType, ret) return ret; } catch (Exception e) { processException(inputType, e); @@ -659,6 +676,7 @@ class TransformerGenerator { return null; } java.util.Map _compositeNode = (java.util.Map) $2; + System.out.println(_localQName + " " + _compositeNode); «type.builderName» _builder = new «type.builderName»(); «deserializeKey(type, node)» «deserializeDataNodeContainerBody(type, node)» @@ -674,6 +692,7 @@ class TransformerGenerator { return null; } java.util.Map _compositeNode = (java.util.Map) $2; + System.out.println(_localQName + " " + _compositeNode); «type.builderName» _builder = new «type.builderName»(); «deserializeDataNodeContainerBody(type, node)» «deserializeAugmentations» @@ -689,7 +708,7 @@ class TransformerGenerator { return null; } java.util.Map _compositeNode = (java.util.Map) $2; - //System.out.println(_localQName + " " + _compositeNode); + System.out.println(_localQName + " " + _compositeNode); «type.builderName» _builder = new «type.builderName»(); «deserializeDataNodeContainerBody(type, node)» «deserializeAugmentations» @@ -722,7 +741,7 @@ class TransformerGenerator { «Iterator.name» _entries = _augmentation.entrySet().iterator(); while(_entries.hasNext()) { java.util.Map.Entry _entry = (java.util.Map.Entry) _entries.next(); - //System.out.println("Aug. key:" + _entry.getKey()); + ////System.out.println("Aug. key:" + _entry.getKey()); Class _type = (Class) _entry.getKey(); «Augmentation.resolvedName» _value = («Augmentation.name») _entry.getValue(); if(_value != null) { @@ -736,7 +755,7 @@ class TransformerGenerator { String propertyName) ''' java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName. localName»")); - //System.out.println("«propertyName»#deCode"+_dom_«propertyName»); + ////System.out.println("«propertyName»#deCode"+_dom_«propertyName»); java.util.List «propertyName» = new java.util.ArrayList(); if(_dom_«propertyName» != null) { java.util.List _serialized = new java.util.ArrayList(); @@ -745,15 +764,15 @@ class TransformerGenerator { while(_hasNext) { Object _listItem = _iterator.next(); _is_empty = false; - //System.out.println(" item" + _listItem); + ////System.out.println(" item" + _listItem); Object _value = «type.actualTypeArguments.get(0).serializer(schema).resolvedName».fromDomStatic(_localQName,_listItem); - //System.out.println(" value" + _value); + ////System.out.println(" value" + _value); «propertyName».add(_value); _hasNext = _iterator.hasNext(); } } - //System.out.println(" list" + «propertyName»); + ////System.out.println(" list" + «propertyName»); ''' private def dispatch CharSequence deserializeProperty(LeafListSchemaNode schema, ParameterizedType type, @@ -770,7 +789,7 @@ class TransformerGenerator { Object _listItem = _iterator.next(); if(_listItem instanceof java.util.Map.Entry) { Object _innerValue = ((java.util.Map.Entry) _listItem).getValue(); - Object _value = «deserializeValue(type.actualTypeArguments.get(0), "_innerValue")»; + Object _value = «deserializeValue(type.actualTypeArguments.get(0), "_innerValue", schema.type)»; «propertyName».add(_value); } _hasNext = _iterator.hasNext(); @@ -786,7 +805,7 @@ class TransformerGenerator { _is_empty = false; java.util.Map.Entry _dom_«propertyName» = (java.util.Map.Entry) _dom_«propertyName»_list.get(0); Object _inner_value = _dom_«propertyName».getValue(); - «propertyName» = «deserializeValue(type, "_inner_value")»; + «propertyName» = «deserializeValue(type, "_inner_value", schema.type)»; } ''' @@ -809,16 +828,17 @@ class TransformerGenerator { } ''' - private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter) ''' - («type.resolvedName») «type.valueSerializer.resolvedName».fromDomValue(«domParameter») + private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter, + TypeDefinition typeDefinition) ''' + («type.resolvedName») «type.valueSerializer(typeDefinition).resolvedName».fromDomValue(«domParameter») ''' - private def dispatch String deserializeValue(Enumeration type, String domParameter) ''' - («type.resolvedName») «type.valueSerializer.resolvedName».fromDomValue(«domParameter») + private def dispatch String deserializeValue(Enumeration type, String domParameter, TypeDefinition typeDefinition) ''' + («type.resolvedName») «type.valueSerializer(typeDefinition).resolvedName».fromDomValue(«domParameter») ''' private def dispatch Class, Object>> generateValueTransformer( - Class inputType, GeneratedTransferObject typeSpec) { + Class inputType, GeneratedTransferObject typeSpec, TypeDefinition typeDef) { try { val returnType = typeSpec.valueReturnType; @@ -827,11 +847,6 @@ class TransformerGenerator { val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) return ret as Class, Object>>; } - if (returnType.name == 'char[]') { - val ctCls = createUnionImplementation(inputType, typeSpec); - val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) - return ret as Class, Object>>; - } val ctCls = createClass(typeSpec.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); @@ -846,16 +861,16 @@ class TransformerGenerator { val ctSpec = typeSpec.asCtClass; bodyChecked = ''' { - //System.out.println("«inputType.simpleName»#toDomValue: "+$1); + ////System.out.println("«inputType.simpleName»#toDomValue: "+$1); if($1 == null) { return null; } «typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1; - //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue); + ////System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue); «returnType.resolvedName» _value = _encapsulatedValue.getValue(); - //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value); - Object _domValue = «serializeValue(returnType, "_value")»; + ////System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value); + Object _domValue = «serializeValue(returnType, "_value", null)»; return _domValue; } ''' @@ -871,12 +886,12 @@ class TransformerGenerator { modifiers = PUBLIC + FINAL + STATIC bodyChecked = ''' { - //System.out.println("«inputType.simpleName»#fromDomValue: "+$1); + ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1); if($1 == null) { return null; } - «returnType.resolvedName» _simpleValue = «deserializeValue(returnType, "$1")»; + «returnType.resolvedName» _simpleValue = «deserializeValue(returnType, "$1", null)»; «typeSpec.resolvedName» _value = new «typeSpec.resolvedName»(_simpleValue); return _value; } @@ -891,7 +906,7 @@ class TransformerGenerator { ] val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) - log.info("DOM Codec for {} was generated {}", inputType, ret) + log.debug("DOM Codec for {} was generated {}", inputType, ret) return ret as Class, Object>>; } catch (Exception e) { log.error("Cannot compile DOM Codec for {}", inputType, e); @@ -899,74 +914,182 @@ class TransformerGenerator { exception.addSuppressed(e); throw exception; } - } - def createUnionImplementation(Class inputType, GeneratedTransferObject typeSpec) { - return createClass(typeSpec.codecClassName) [ - val properties = typeSpec.allProperties; - //staticField(Map,"AUGMENTATION_SERIALIZERS"); - if (inputType.isYangBindingAvailable) { - implementsType(BINDING_CODEC) - staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) - staticField(it, IDENTITYREF_CODEC, BindingCodec) - implementsType(BindingDeserializer.asCtClass) - } - method(Object, "toDomValue", Object) [ - modifiers = PUBLIC + FINAL + STATIC - val ctSpec = inputType.asCtClass; - bodyChecked = ''' - { - //System.out.println("«inputType.simpleName»#toDomValue: "+$1); - - if($1 == null) { + private def dispatch Class, Object>> generateValueTransformer( + Class inputType, GeneratedTransferObject typeSpec, UnionTypeDefinition typeDef) { + try { + val ctCls = createClass(typeSpec.codecClassName) [ + val properties = typeSpec.allProperties; + val getterToTypeDefinition = XtendHelper.getTypes(typeDef).toMap[type | type.QName.getterName]; + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + if (inputType.isYangBindingAvailable) { + implementsType(BINDING_CODEC) + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) + implementsType(BindingDeserializer.asCtClass) + } + method(Object, "toDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + val ctSpec = inputType.asCtClass; + + bodyChecked = ''' + { + ////System.out.println("«inputType.simpleName»#toDomValue: "+$1); + + if($1 == null) { + return null; + } + «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1; + «FOR property : properties.entrySet» + «IF property.key != "getValue"» + «property.value.resolvedName» «property.key» = («property.value.resolvedName») _value.«property. + key»(); + if(«property.key» != null) { + return «serializeValue(property.value, property.key, getterToTypeDefinition.get(property.key))»; + } + «ENDIF» + «ENDFOR» + return null; } - «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1; - «FOR property : properties.entrySet» - «IF property.key != "getValue"» - «property.value.resolvedName» «property.key» = («property.value.resolvedName») _value.«property.key»(); - if(«property.key» != null) { - return «serializeValue(property.value, property.key)»; - } - «ENDIF» - «ENDFOR» - - return null; - } - ''' - ] - method(Object, "serialize", Object) [ - bodyChecked = ''' - { - return toDomValue($1); - } - ''' - ] - method(Object, "fromDomValue", Object) [ - modifiers = PUBLIC + FINAL + STATIC - bodyChecked = ''' - { - //System.out.println("«inputType.simpleName»#fromDomValue: "+$1); - - if($1 == null) { - return null; + ''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + { + return toDomValue($1); } - if($1 instanceof String) { - String _simpleValue = (String) $1; - return new «typeSpec.resolvedName»(_simpleValue.toCharArray()); + ''' + ] + method(Object, "fromDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = ''' + { + ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1); + + if($1 == null) { + return null; + } + if($1 instanceof String) { + String _simpleValue = (String) $1; + return new «typeSpec.resolvedName»(_simpleValue.toCharArray()); + } + return null; } - return null; + ''' + ] + method(Object, "deserialize", Object) [ + bodyChecked = '''{ + return fromDomValue($1); } - ''' + ''' + ] ] - method(Object, "deserialize", Object) [ - bodyChecked = '''{ + + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + log.debug("DOM Codec for {} was generated {}", inputType, ret) + return ret as Class, Object>>; + } catch (Exception e) { + log.error("Cannot compile DOM Codec for {}", inputType, e); + val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType); + exception.addSuppressed(e); + throw exception; + } + } + + + private def dispatch Class, Object>> generateValueTransformer( + Class inputType, GeneratedTransferObject typeSpec, BitsTypeDefinition typeDef) { + try { + val ctCls = createClass(typeSpec.codecClassName) [ + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + if (inputType.isYangBindingAvailable) { + implementsType(BINDING_CODEC) + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) + implementsType(BindingDeserializer.asCtClass) + } + method(Object, "toDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + val ctSpec = typeSpec.asCtClass; + bodyChecked = ''' + { + ////System.out.println("«inputType.simpleName»#toDomValue: "+$1); + + if($1 == null) { + return null; + } + «typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1; + «HashSet.resolvedName» _value = new «HashSet.resolvedName»(); + //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue); + + «FOR bit : typeDef.bits» + «val getter = bit.getterName()» + if(Boolean.TRUE.equals(_encapsulatedValue.«getter»())) { + _value.add("«bit.name»"); + } + «ENDFOR» + «Set.resolvedName» _domValue = «Collections.resolvedName».unmodifiableSet(_value); + //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_domValue); + + return _domValue; + } + ''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + { + return toDomValue($1); + } + ''' + ] + method(Object, "fromDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + val sortedBits = typeDef.bits.sort[o1, o2|o1.propertyName.compareTo(o2.propertyName)] + bodyChecked = ''' + { + //System.out.println("«inputType.simpleName»#fromDomValue: "+$1); + + if($1 == null) { + return null; + } + «Set.resolvedName» _domValue = («Set.resolvedName») $1; + «FOR bit : sortedBits» + Boolean «bit.propertyName» = Boolean.valueOf(_domValue.contains("«bit.name»")); + «ENDFOR» + + return new «inputType.resolvedName»(«FOR bit : sortedBits SEPARATOR ","»«bit.propertyName»«ENDFOR»); + } + ''' + ] + method(Object, "deserialize", Object) [ + bodyChecked = '''{ return fromDomValue($1); } ''' + ] ] - ] + + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + log.debug("DOM Codec for {} was generated {}", inputType, ret) + return ret as Class, Object>>; + } catch (Exception e) { + log.error("Cannot compile DOM Codec for {}", inputType, e); + val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType); + exception.addSuppressed(e); + throw exception; + } + } + + def String getPropertyName(Bit bit) { + '''_«BindingGeneratorUtil.parseToValidParamName(bit.name)»''' + } + + def String getterName(Bit bit) { + + val paramName = BindingGeneratorUtil.parseToValidParamName(bit.name); + return '''is«paramName.toFirstUpper»'''; } def boolean isYangBindingAvailable(Class class1) { @@ -1030,7 +1153,7 @@ class TransformerGenerator { return null; } - private def dispatch Class generateValueTransformer(Class inputType, Enumeration typeSpec) { + private def Class generateValueTransformer(Class inputType, Enumeration typeSpec) { try { val typeRef = new ReferencedTypeImpl(typeSpec.packageName, typeSpec.name); val schema = typeToSchemaNode.get(typeRef) as ExtendedType; @@ -1086,7 +1209,7 @@ class TransformerGenerator { ] val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) - log.info("DOM Codec for {} was generated {}", inputType, ret) + log.debug("DOM Codec for {} was generated {}", inputType, ret) return ret; } catch (CodeGenerationException e) { throw new CodeGenerationException("Cannot compile Transformator for " + inputType, e); @@ -1116,7 +1239,7 @@ class TransformerGenerator { } - private def dispatch String deserializeValue(Type type, String domParameter) { + private def dispatch String deserializeValue(Type type, String domParameter, TypeDefinition typeDef) { if (INSTANCE_IDENTIFIER.equals(type)) { return '''(«InstanceIdentifier.name») «INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)''' } else if (CLASS_TYPE.equals(type)) { @@ -1214,7 +1337,7 @@ class TransformerGenerator { «FOR child : node.childNodes» «val signature = properties.getFor(child)» «IF signature !== null» - //System.out.println("«type.name»#«signature.key»" + value.«signature.key»()); + ////System.out.println("«type.name»#«signature.key»" + value.«signature.key»()); «serializeProperty(child, signature.value, signature.key)» «ENDIF» «ENDFOR» @@ -1256,7 +1379,7 @@ class TransformerGenerator { private def dispatch CharSequence serializeProperty(ListSchemaNode schema, ParameterizedType type, String propertyName) ''' «type.resolvedName» «propertyName» = value.«propertyName»(); - //System.out.println("«propertyName»:" + «propertyName»); + ////System.out.println("«propertyName»:" + «propertyName»); if(«propertyName» != null) { java.util.Iterator _iterator = «propertyName».iterator(); boolean _hasNext = _iterator.hasNext(); @@ -1274,7 +1397,7 @@ class TransformerGenerator { if(«propertyName» != null) { «QName.name» _qname = «QName.name».create(_resultName,"«schema.QName.localName»"); - Object _propValue = «serializeValue(type, propertyName)»; + Object _propValue = «serializeValue(type, propertyName, schema.type)»; if(_propValue != null) { Object _domValue = java.util.Collections.singletonMap(_qname,_propValue); _childNodes.add(_domValue); @@ -1282,12 +1405,15 @@ class TransformerGenerator { } ''' - private def dispatch serializeValue(GeneratedTransferObject type, String parameter) '''«type.valueSerializer. - resolvedName».toDomValue(«parameter»)''' + private def dispatch serializeValue(GeneratedTransferObject type, String parameter, TypeDefinition typeDefinition) { + '''«type.valueSerializer(typeDefinition).resolvedName».toDomValue(«parameter»)''' + } - private def dispatch serializeValue(Enumeration type, String parameter) '''«type.valueSerializer.resolvedName».toDomValue(«parameter»)''' + private def dispatch serializeValue(Enumeration type, String parameter, TypeDefinition typeDefinition) { + '''«type.valueSerializer(typeDefinition).resolvedName».toDomValue(«parameter»)''' + } - private def dispatch serializeValue(Type signature, String property) { + private def dispatch serializeValue(Type signature, String property, TypeDefinition typeDefinition) { if (INSTANCE_IDENTIFIER == signature) { return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)''' } else if (CLASS_TYPE.equals(signature)) { @@ -1308,7 +1434,7 @@ class TransformerGenerator { boolean _hasNext = _iterator.hasNext(); while(_hasNext) { Object _listItem = _iterator.next(); - Object _propValue = «serializeValue(type.actualTypeArguments.get(0), "_listItem")»; + Object _propValue = «serializeValue(type.actualTypeArguments.get(0), "_listItem", schema.type)»; Object _domValue = java.util.Collections.singletonMap(_qname,_propValue); _childNodes.add(_domValue); _hasNext = _iterator.hasNext(); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend index 9381a5a070..b4bf3f5a83 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend @@ -9,69 +9,22 @@ package org.opendaylight.controller.sal.binding.impl import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer import org.opendaylight.controller.sal.binding.api.BindingAwareProvider -import org.opendaylight.yangtools.yang.binding.RpcService -import javassist.ClassPool import org.osgi.framework.BundleContext -import java.util.Map -import java.util.HashMap -import javassist.LoaderClassPath import org.opendaylight.controller.sal.binding.api.BindingAwareBroker -import java.util.Hashtable -import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.* - import org.opendaylight.controller.sal.binding.api.NotificationProviderService -import org.osgi.framework.ServiceRegistration -import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.* -import static extension org.opendaylight.controller.sal.binding.impl.osgi.PropertiesUtils.* -import org.opendaylight.controller.sal.binding.api.NotificationService import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext - -import org.slf4j.LoggerFactory -import org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration -import org.opendaylight.controller.sal.binding.api.data.DataProviderService -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService -import org.opendaylight.controller.sal.binding.spi.RpcRouter -import java.util.concurrent.ConcurrentHashMap -import static com.google.common.base.Preconditions.* -import org.opendaylight.yangtools.concepts.AbstractObjectRegistration -import org.opendaylight.yangtools.yang.binding.BaseIdentity -import com.google.common.collect.Multimap -import com.google.common.collect.HashMultimap -import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.* -import java.util.concurrent.Executors -import java.util.Collections import org.opendaylight.yangtools.yang.binding.DataObject -import java.util.concurrent.locks.ReentrantLock -import java.util.concurrent.Callable -import java.util.WeakHashMap -import javax.annotation.concurrent.GuardedBy -import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener +import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier +import org.opendaylight.controller.sal.binding.api.data.DataProviderService +import org.slf4j.LoggerFactory -class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry, AutoCloseable { +class BindingAwareBrokerImpl extends RpcProviderRegistryImpl implements BindingAwareBroker, AutoCloseable { private static val log = LoggerFactory.getLogger(BindingAwareBrokerImpl) private InstanceIdentifier root = InstanceIdentifier.builder().toInstance(); - private static val clsPool = ClassPool.getDefault() - public static var RuntimeCodeGenerator generator; - - /** - * Map of all Managed Direct Proxies - * - */ - private val Map, RpcProxyContext> managedProxies = new ConcurrentHashMap(); - - /** - * - * Map of all available Rpc Routers - * - * - */ - private val Map, RpcRouter> rpcRouters = new WeakHashMap(); - @Property private var NotificationProviderService notifyBroker @@ -81,43 +34,16 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry, @Property var BundleContext brokerBundleContext - ServiceRegistration notifyProviderRegistration - - ServiceRegistration notifyConsumerRegistration - - ServiceRegistration dataProviderRegistration - - ServiceRegistration dataConsumerRegistration - - private val proxyGenerationLock = new ReentrantLock; - - private val routerGenerationLock = new ReentrantLock; - - public new(BundleContext bundleContext) { + public new(String name,BundleContext bundleContext) { + super(name); _brokerBundleContext = bundleContext; } def start() { log.info("Starting MD-SAL: Binding Aware Broker"); - initGenerator(); - - val executor = Executors.newCachedThreadPool; - - // Initialization of notificationBroker - log.info("Starting MD-SAL: Binding Aware Notification Broker"); - - log.info("Starting MD-SAL: Binding Aware Data Broker"); - - log.info("Starting MD-SAL: Binding Aware Data Broker"); - log.info("MD-SAL: Binding Aware Broker Started"); } - def initGenerator() { - // YANG Binding Class Loader - clsPool.appendClassPath(new LoaderClassPath(RpcService.classLoader)); - generator = new RuntimeCodeGenerator(clsPool); - } override registerConsumer(BindingAwareConsumer consumer, BundleContext bundleCtx) { val ctx = consumer.createContext(bundleCtx) @@ -140,246 +66,11 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry, new OsgiProviderContext(providerCtx, this) } - /** - * Returns a Managed Direct Proxy for supplied class - * - * Managed direct proxy is a generated proxy class conforming to the supplied interface - * which delegates all calls to the backing delegate. - * - * Proxy does not do any validation, null pointer checks or modifies data in any way, it - * is only use to avoid exposing direct references to backing implementation of service. - * - * If proxy class does not exist for supplied service class it will be generated automatically. - */ - private def getManagedDirectProxy(Class service) { - var RpcProxyContext existing = null - - if ((existing = managedProxies.get(service)) != null) { - return existing.proxy - } - return withLock(proxyGenerationLock) [ | - val maybeProxy = managedProxies.get(service); - if (maybeProxy !== null) { - return maybeProxy.proxy; - } - - - val proxyInstance = generator.getDirectProxyFor(service) - val rpcProxyCtx = new RpcProxyContext(proxyInstance.class) - val properties = new Hashtable() - rpcProxyCtx.proxy = proxyInstance as RpcService - properties.salServiceType = SAL_SERVICE_TYPE_CONSUMER_PROXY - rpcProxyCtx.registration = brokerBundleContext.registerService(service, rpcProxyCtx.proxy as T, properties) - managedProxies.put(service, rpcProxyCtx) - return rpcProxyCtx.proxy - ] - } - - private static def T withLock(ReentrantLock lock, Callable method) { - try { - lock.lock(); - val ret = method.call; - return ret; - } finally { - lock.unlock(); - } - } - - /** - * Registers RPC Implementation - * - */ - override addRpcImplementation(Class type, T service) { - checkNotNull(type, "Service type should not be null") - checkNotNull(service, "Service type should not be null") - - val proxy = getManagedDirectProxy(type) - checkState(proxy.delegate === null, "The Service for type %s is already registered", type) - - proxy.delegate = service; - return new RpcServiceRegistrationImpl(type, service, this); - } - - override RoutedRpcRegistration addRoutedRpcImplementation(Class type, T service) { - checkNotNull(type, "Service type should not be null") - checkNotNull(service, "Service type should not be null") - - val router = resolveRpcRouter(type); - checkState(router !== null) - return new RoutedRpcRegistrationImpl(service, router, this) + override >> registerRouteChangeListener(L listener) { + super.registerRouteChangeListener(listener) } - override getRpcService(Class service) { - checkNotNull(service, "Service should not be null"); - return getManagedDirectProxy(service) as T; - } - - private def RpcRouter resolveRpcRouter(Class type) { - - val router = rpcRouters.get(type); - if (router !== null) { - return router as RpcRouter; - } - - // We created Router - return withLock(routerGenerationLock) [ | - val maybeRouter = rpcRouters.get(type); - if (maybeRouter !== null) { - return maybeRouter as RpcRouter; - } - - val newRouter = generator.getRouterFor(type); - checkState(newRouter !== null); - rpcRouters.put(type, newRouter); - // We create / update Direct Proxy for router - val proxy = getManagedDirectProxy(type); - proxy.delegate = newRouter.invocationProxy - return newRouter; - ] - - } - - protected def void registerPath(RoutedRpcRegistrationImpl registration, - Class context, InstanceIdentifier path) { - - val router = registration.router; - val paths = registration.registeredPaths; - - val routingTable = router.getRoutingTable(context) - checkState(routingTable != null); - - // Updating internal structure of registration - routingTable.updateRoute(path, registration.instance) - - // Update routing table / send announce to message bus - val success = paths.put(context, path); - } - - protected def void unregisterPath(RoutedRpcRegistrationImpl registration, - Class context, InstanceIdentifier path) { - - val router = registration.router; - val paths = registration.registeredPaths; - - val routingTable = router.getRoutingTable(context) - checkState(routingTable != null); - - // Updating internal structure of registration - val target = routingTable.getRoute(path) - checkState(target === registration.instance) - routingTable.removeRoute(path) - checkState(paths.remove(context, path)); - } - - protected def void unregisterRoutedRpcService(RoutedRpcRegistrationImpl registration) { - - val router = registration.router; - val paths = registration.registeredPaths; - - for (ctxMap : registration.registeredPaths.entries) { - val context = ctxMap.key - val routingTable = router.getRoutingTable(context) - val path = ctxMap.value - routingTable.removeRoute(path) - } - } - - protected def void unregisterRpcService(RpcServiceRegistrationImpl registration) { - - val type = registration.serviceType; - - val proxy = managedProxies.get(type); - if (proxy.proxy.delegate === registration.instance) { - proxy.proxy.delegate = null; - } - } - - def createDelegate(Class type) { - getManagedDirectProxy(type); - } - - def getRpcRouters() { - return Collections.unmodifiableMap(rpcRouters); - } - - override close() { - dataConsumerRegistration.unregister() - dataProviderRegistration.unregister() - notifyConsumerRegistration.unregister() - notifyProviderRegistration.unregister() - } - -} - -class RoutedRpcRegistrationImpl extends AbstractObjectRegistration implements RoutedRpcRegistration { - - @Property - private val BindingAwareBrokerImpl broker; - - @Property - private val RpcRouter router; - - @Property - private val Multimap, InstanceIdentifier> registeredPaths = HashMultimap.create(); - - private var closed = false; - - new(T instance, RpcRouter backingRouter, BindingAwareBrokerImpl broker) { - super(instance) - _router = backingRouter; - _broker = broker; - } - - override protected removeRegistration() { - closed = true - broker.unregisterRoutedRpcService(this) - } - - override registerInstance(Class context, InstanceIdentifier instance) { - registerPath(context, instance); - } - - override unregisterInstance(Class context, InstanceIdentifier instance) { - unregisterPath(context, instance); - } - - override registerPath(Class context, InstanceIdentifier path) { - checkClosed() - broker.registerPath(this, context, path); - } - - override unregisterPath(Class context, InstanceIdentifier path) { - checkClosed() - broker.unregisterPath(this, context, path); - } - - override getServiceType() { - return router.serviceType; - } - - private def checkClosed() { - if (closed) - throw new IllegalStateException("Registration was closed."); - } - -} - -class RpcServiceRegistrationImpl extends AbstractObjectRegistration implements RpcRegistration { - - private var BindingAwareBrokerImpl broker; - - @Property - val Class serviceType; - - public new(Class type, T service, BindingAwareBrokerImpl broker) { - super(service); - this._serviceType = type; - this.broker = broker; - } - - override protected removeRegistration() { - broker.unregisterRpcService(this); - broker = null; + override close() throws Exception { + } - -} +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend index e8b3850b77..b10c06f0c5 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend @@ -20,8 +20,8 @@ import org.opendaylight.yangtools.concepts.AbstractObjectRegistration import org.opendaylight.yangtools.concepts.ListenerRegistration import org.opendaylight.yangtools.concepts.Registration import org.opendaylight.yangtools.yang.binding.Notification -import org.slf4j.LoggerFactory - +import org.slf4j.LoggerFactory import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder + class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable { val Multimap, NotificationListener> listeners; @@ -29,6 +29,11 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab @Property var ExecutorService executor; + new() { + listeners = HashMultimap.create() + } + + @Deprecated new(ExecutorService executor) { listeners = HashMultimap.create() this.executor = executor; @@ -100,7 +105,7 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab override registerNotificationListener( org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - val invoker = BindingAwareBrokerImpl.generator.invokerFactory.invokerFor(listener); + val invoker = SingletonHolder.INVOKER_FACTORY.invokerFor(listener); for (notifyType : invoker.supportedNotifications) { listeners.put(notifyType, invoker.invocationProxy) } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend index bc53108675..644c50b86a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend @@ -45,8 +45,7 @@ class OsgiConsumerContext implements ConsumerContext { val ref = services.iterator().next() as ServiceReference; return bundleContext.getService(ref) as T; } else { - broker.createDelegate(module); - return getRpcService(module); + return broker.getRpcService(module); } } catch (InvalidSyntaxException e) { log.error("Created filter was invalid:", e.message, e) diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java new file mode 100644 index 0000000000..6a17007d22 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java @@ -0,0 +1,209 @@ +package org.opendaylight.controller.sal.binding.impl; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.HashMap; +import java.util.Set; +import java.util.WeakHashMap; + +import javax.swing.tree.ExpandVetoException; + +import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher; +import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; +import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator; +import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper; +import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; +import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier; +import org.opendaylight.controller.sal.binding.spi.RpcRouter; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.util.ListenerRegistry; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static com.google.common.base.Preconditions.*; + +public class RpcProviderRegistryImpl implements // + RpcProviderRegistry, // + RouteChangePublisher> { + + private RuntimeCodeGenerator rpcFactory = SingletonHolder.RPC_GENERATOR_IMPL; + + private final Map, RpcService> publicProxies = new WeakHashMap<>(); + private final Map, RpcRouter> rpcRouters = new WeakHashMap<>(); + private final ListenerRegistry>> routeChangeListeners = ListenerRegistry + .create(); + + private final static Logger LOG = LoggerFactory.getLogger(RpcProviderRegistryImpl.class); + + private final String name; + + public String getName() { + return name; + } + + public RpcProviderRegistryImpl(String name) { + super(); + this.name = name; + } + + @Override + public final RoutedRpcRegistration addRoutedRpcImplementation(Class type, + T implementation) throws IllegalStateException { + return getRpcRouter(type).addRoutedRpcImplementation(implementation); + } + + @Override + public final RpcRegistration addRpcImplementation(Class type, T implementation) + throws IllegalStateException { + @SuppressWarnings("unchecked") + RpcRouter potentialRouter = (RpcRouter) rpcRouters.get(type); + if (potentialRouter != null) { + checkState(potentialRouter.getDefaultService() == null, + "Default service for routed RPC already registered."); + return potentialRouter.registerDefaultService(implementation); + } + T publicProxy = getRpcService(type); + RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy); + checkState(currentDelegate == null, "Rpc service is already registered"); + LOG.debug("Registering {} as global implementation of {} in {}",implementation,type.getSimpleName(),this); + RuntimeCodeHelper.setDelegate(publicProxy, implementation); + return new RpcProxyRegistration(type, implementation, this); + } + + @SuppressWarnings("unchecked") + @Override + public final T getRpcService(Class type) { + + @SuppressWarnings("unchecked") + T potentialProxy = (T) publicProxies.get(type); + if (potentialProxy != null) { + return potentialProxy; + } + synchronized(this) { + /** + * Potential proxy could be instantiated by other thread while we were + * waiting for the lock. + */ + + potentialProxy = (T) publicProxies.get(type); + if (potentialProxy != null) { + return (T) potentialProxy; + } + T proxy = rpcFactory.getDirectProxyFor(type); + LOG.debug("Created {} as public proxy for {} in {}",proxy,type.getSimpleName(),this); + publicProxies.put(type, proxy); + return proxy; + } + } + + private RpcRouter getRpcRouter(Class type) { + RpcRouter potentialRouter = rpcRouters.get(type); + if (potentialRouter != null) { + return (RpcRouter) potentialRouter; + } + synchronized(this) { + /** + * Potential Router could be instantiated by other thread while we were + * waiting for the lock. + */ + potentialRouter = rpcRouters.get(type); + if (potentialRouter != null) { + return (RpcRouter) potentialRouter; + } + RpcRouter router = rpcFactory.getRouterFor(type,name); + router.registerRouteChangeListener(new RouteChangeForwarder(type)); + LOG.debug("Registering router {} as global implementation of {} in {}",router,type.getSimpleName(),this); + RuntimeCodeHelper.setDelegate(getRpcService(type), router.getInvocationProxy()); + rpcRouters.put(type, router); + return router; + } + } + + @Override + public >> ListenerRegistration registerRouteChangeListener( + L listener) { + return (ListenerRegistration) routeChangeListeners.register(listener); + } + + public RuntimeCodeGenerator getRpcFactory() { + return rpcFactory; + } + + public void setRpcFactory(RuntimeCodeGenerator rpcFactory) { + this.rpcFactory = rpcFactory; + } + + private class RouteChangeForwarder implements + RouteChangeListener, InstanceIdentifier> { + + private final Class type; + + public RouteChangeForwarder(Class type) { + this.type = type; + } + + @Override + public void onRouteChange(RouteChange, InstanceIdentifier> change) { + Map>> announcements = new HashMap<>(); + for (Entry, Set>> entry : change.getAnnouncements() + .entrySet()) { + RpcContextIdentifier key = RpcContextIdentifier.contextFor(type, entry.getKey()); + announcements.put(key, entry.getValue()); + } + Map>> removals = new HashMap<>(); + for (Entry, Set>> entry : change.getRemovals() + .entrySet()) { + RpcContextIdentifier key = RpcContextIdentifier.contextFor(type, entry.getKey()); + removals.put(key, entry.getValue()); + } + RouteChange> toPublish = RoutingUtils + .> change(announcements, removals); + for (ListenerRegistration>> listener : routeChangeListeners) { + try { + listener.getInstance().onRouteChange(toPublish); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + public static class RpcProxyRegistration extends AbstractObjectRegistration implements + RpcRegistration { + + private final Class serviceType; + private RpcProviderRegistryImpl registry; + + public RpcProxyRegistration(Class type, T service, RpcProviderRegistryImpl registry) { + super(service); + serviceType = type; + } + + @Override + public Class getServiceType() { + return serviceType; + } + + @Override + protected void removeRegistration() { + if (registry != null) { + T publicProxy = registry.getRpcService(serviceType); + RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy); + if (currentDelegate == getInstance()) { + RuntimeCodeHelper.setDelegate(publicProxy, null); + } + registry = null; + } + } + } +} 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/BindingIndependentConnector.java similarity index 58% rename from opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java rename to opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java index 9eff29f8cc..daa3914cf7 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/BindingIndependentConnector.java @@ -1,42 +1,78 @@ package org.opendaylight.controller.sal.binding.impl.connect.dom; +import java.lang.ref.WeakReference; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; + import org.opendaylight.controller.md.sal.common.api.RegistrationListener; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration; import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider; +import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl; +import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier; +import org.opendaylight.controller.sal.binding.spi.RpcRouter; import org.opendaylight.controller.sal.common.util.Rpcs; import org.opendaylight.controller.sal.core.api.Provider; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; +import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils; import org.opendaylight.yangtools.yang.binding.Augmentable; import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.BindingMapping; +import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcInput; +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.yangtools.yang.binding.util.BindingReflections; +import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BindingIndependentDataServiceConnector implements // +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableSet; + +import static com.google.common.base.Preconditions.*; +import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.*; + +public class BindingIndependentConnector implements // RuntimeDataProvider, // - Provider, AutoCloseable { + Provider, // + AutoCloseable { - private final Logger LOG = LoggerFactory.getLogger(BindingIndependentDataServiceConnector.class); + private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class); private static final InstanceIdentifier ROOT = InstanceIdentifier.builder().toInstance(); @@ -59,26 +95,41 @@ public class BindingIndependentDataServiceConnector implements // private Registration> biCommitHandlerRegistration; + private RpcProvisionRegistry biRpcRegistry; + private RpcProviderRegistryImpl baRpcRegistry; + + private ListenerRegistration domToBindingRpcManager; + // private ListenerRegistration + // bindingToDomRpcManager; + + private Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() { + + @Override + public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier input) { + return mappingService.toDataDom(input); + } + + }; + @Override public DataObject readOperationalData(InstanceIdentifier path) { try { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path); - - + CompositeNode result = biDataService.readOperationalData(biPath); Class targetType = path.getTargetType(); - - if(Augmentation.class.isAssignableFrom(targetType)) { + + if (Augmentation.class.isAssignableFrom(targetType)) { path = mappingService.fromDataDom(biPath); Class> augmentType = (Class>) targetType; DataObject parentTo = mappingService.dataObjectFromDataDom(path, result); - if(parentTo instanceof Augmentable) { + if (parentTo instanceof Augmentable) { return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType); } - + } return mappingService.dataObjectFromDataDom(path, result); - + } catch (DeserializationException e) { throw new IllegalStateException(e); } @@ -183,11 +234,24 @@ public class BindingIndependentDataServiceConnector implements // this.baDataService = baDataService; } + public RpcProviderRegistry getRpcRegistry() { + return baRpcRegistry; + } + + public void setRpcRegistry(RpcProviderRegistryImpl rpcRegistry) { + this.baRpcRegistry = rpcRegistry; + } + public void start() { baDataService.registerDataReader(ROOT, this); baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler); biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler); baDataService.registerCommitHandlerListener(domToBindingCommitHandler); + + if (baRpcRegistry != null && biRpcRegistry != null) { + domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager()); + + } } public void setMappingService(BindingIndependentMappingService mappingService) { @@ -205,6 +269,14 @@ public class BindingIndependentDataServiceConnector implements // start(); } + public void onRpcRouterCreated(Class serviceType, RpcRouter router) { + + } + + public void setDomRpcRegistry(RpcProvisionRegistry registry) { + biRpcRegistry = registry; + } + @Override public void close() throws Exception { if (baCommitHandlerRegistration != null) { @@ -358,4 +430,204 @@ public class BindingIndependentDataServiceConnector implements // return forwardedTransaction; } } + + private class DomToBindingRpcForwardingManager implements + RouteChangeListener> { + + private final Map, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>(); + + @Override + public void onRouteChange(RouteChange> change) { + for (Entry>> entry : change.getAnnouncements().entrySet()) { + bindingRoutesAdded(entry); + } + } + + private void bindingRoutesAdded(Entry>> entry) { + Class context = entry.getKey().getRoutingContext(); + Class service = entry.getKey().getRpcService(); + if (context != null) { + getRpcForwarder(service, context).registerPaths(context, service, entry.getValue()); + } + } + + private DomToBindingRpcForwarder getRpcForwarder(Class service, + Class context) { + DomToBindingRpcForwarder potential = forwarders.get(service); + if (potential != null) { + return potential; + } + if (context == null) { + potential = new DomToBindingRpcForwarder(service); + } else { + potential = new DomToBindingRpcForwarder(service, context); + } + forwarders.put(service, potential); + return potential; + } + + } + + private class DomToBindingRpcForwarder implements RpcImplementation { + + private final Set supportedRpcs; + private final WeakReference> rpcServiceType; + private Set registrations; + + public DomToBindingRpcForwarder(Class service) { + this.rpcServiceType = new WeakReference>(service); + this.supportedRpcs = mappingService.getRpcQNamesFor(service); + for (QName rpc : supportedRpcs) { + biRpcRegistry.addRpcImplementation(rpc, this); + } + registrations = ImmutableSet.of(); + } + + public DomToBindingRpcForwarder(Class service, Class context) { + this.rpcServiceType = new WeakReference>(service); + this.supportedRpcs = mappingService.getRpcQNamesFor(service); + registrations = new HashSet<>(); + for (QName rpc : supportedRpcs) { + registrations.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this)); + } + registrations = ImmutableSet.copyOf(registrations); + } + + public void registerPaths(Class context, Class service, + Set> set) { + QName ctx = BindingReflections.findQName(context); + for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform( + toDOMInstanceIdentifier)) { + for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) { + reg.registerPath(ctx, path); + } + } + } + + public void removePaths(Class context, Class service, + Set> set) { + QName ctx = BindingReflections.findQName(context); + for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform( + toDOMInstanceIdentifier)) { + for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) { + reg.unregisterPath(ctx, path); + } + } + } + + @Override + public Set getSupportedRpcs() { + return supportedRpcs; + } + + @Override + public RpcResult invokeRpc(QName rpc, CompositeNode domInput) { + checkArgument(rpc != null); + checkArgument(domInput != null); + + Class rpcType = rpcServiceType.get(); + checkState(rpcType != null); + RpcService rpcService = baRpcRegistry.getRpcService(rpcType); + checkState(rpcService != null); + CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input")); + try { + return resolveInvocationStrategy(rpc, rpcType).invokeOn(rpcService, domUnwrappedInput); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc, + final Class rpcType) throws Exception { + return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable() { + @Override + public RpcInvocationStrategy call() throws Exception { + String methodName = BindingMapping.getMethodName(rpc); + Method targetMethod = null; + for (Method possibleMethod : rpcType.getMethods()) { + if (possibleMethod.getName().equals(methodName) + && BindingReflections.isRpcMethod(possibleMethod)) { + targetMethod = possibleMethod; + break; + } + } + checkState(targetMethod != null, "Rpc method not found"); + Optional> outputClass = BindingReflections.resolveRpcOutputClass(targetMethod); + Optional> inputClass = BindingReflections + .resolveRpcInputClass(targetMethod); + + RpcInvocationStrategy strategy = null; + if (outputClass.isPresent()) { + if (inputClass.isPresent()) { + strategy = new DefaultInvocationStrategy(targetMethod, outputClass.get(), inputClass.get()); + } else { + strategy = new NoInputNoOutputInvocationStrategy(targetMethod); + } + } else { + strategy = null; + } + return strategy; + } + + }); + } + } + + private abstract class RpcInvocationStrategy { + + protected final Method targetMethod; + + public RpcInvocationStrategy(Method targetMethod) { + this.targetMethod = targetMethod; + } + + public abstract RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) + throws Exception; + + public RpcResult invokeOn(RpcService rpcService, CompositeNode domInput) throws Exception { + return uncheckedInvoke(rpcService, domInput); + } + } + + private class DefaultInvocationStrategy extends RpcInvocationStrategy { + + @SuppressWarnings("rawtypes") + private WeakReference inputClass; + + @SuppressWarnings("rawtypes") + private WeakReference outputClass; + + public DefaultInvocationStrategy(Method targetMethod, Class outputClass, + Class inputClass) { + super(targetMethod); + this.outputClass = new WeakReference(outputClass); + this.inputClass = new WeakReference(inputClass); + } + + @Override + public RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception { + DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput); + Future> result = (Future>) targetMethod.invoke(rpcService, bindingInput); + if (result == null) { + return Rpcs.getRpcResult(false); + } + RpcResult bindingResult = result.get(); + return Rpcs.getRpcResult(true); + } + + } + + private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy { + + public NoInputNoOutputInvocationStrategy(Method targetMethod) { + super(targetMethod); + } + + public RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception { + Future> result = (Future>) targetMethod.invoke(rpcService); + RpcResult bindingResult = result.get(); + return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors()); + } + + } } 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 b1983fe224..e16ae48ef4 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 @@ -1,10 +1,13 @@ package org.opendaylight.controller.sal.binding.impl.connect.dom; import java.util.Map.Entry; +import java.util.Set; -import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; public interface BindingIndependentMappingService { @@ -19,5 +22,9 @@ public interface BindingIndependentMappingService { DataObject dataObjectFromDataDom(InstanceIdentifier path, CompositeNode result) throws DeserializationException; InstanceIdentifier fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) throws DeserializationException; + + Set getRpcQNamesFor(Class service); + + DataContainer dataObjectFromDataDom(Class inputClass, CompositeNode domInput); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RoutingContext.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RoutingContext.java new file mode 100644 index 0000000000..49e056b100 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RoutingContext.java @@ -0,0 +1,5 @@ +package org.opendaylight.controller.sal.binding.spi; + +public class RoutingContext { + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcContextIdentifier.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcContextIdentifier.java new file mode 100644 index 0000000000..33569eb077 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcContextIdentifier.java @@ -0,0 +1,65 @@ +package org.opendaylight.controller.sal.binding.spi; + +import org.opendaylight.yangtools.concepts.Immutable; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.RpcService; + +public final class RpcContextIdentifier implements Immutable{ + + public final Class rpcService; + public final Class routingContext; + + private RpcContextIdentifier(Class rpcService, Class routingContext) { + super(); + this.rpcService = rpcService; + this.routingContext = routingContext; + } + + public Class getRpcService() { + return rpcService; + } + + public Class getRoutingContext() { + return routingContext; + } + + public static final RpcContextIdentifier contextForGlobalRpc(Class serviceType) { + return new RpcContextIdentifier(serviceType, null); + } + + public static final RpcContextIdentifier contextFor(Class serviceType,Class routingContext) { + return new RpcContextIdentifier(serviceType, routingContext); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((routingContext == null) ? 0 : routingContext.hashCode()); + result = prime * result + ((rpcService == null) ? 0 : rpcService.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RpcContextIdentifier other = (RpcContextIdentifier) obj; + if (routingContext == null) { + if (other.routingContext != null) + return false; + } else if (!routingContext.equals(other.routingContext)) + return false; + if (rpcService == null) { + if (other.rpcService != null) + return false; + } else if (!rpcService.equals(other.rpcService)) + return false; + return true; + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRouter.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRouter.java index 7db90b62fd..621d048dfd 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRouter.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRouter.java @@ -9,6 +9,9 @@ package org.opendaylight.controller.sal.binding.spi; import java.util.Set; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; import org.opendaylight.yangtools.yang.binding.BaseIdentity; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.RpcImplementation; @@ -26,7 +29,8 @@ import org.opendaylight.yangtools.yang.binding.RpcService; * Type of RpcService for which router provides routing information * and route selection. */ -public interface RpcRouter extends RpcImplementation{ +public interface RpcRouter extends // + RouteChangePublisher, InstanceIdentifier> { /** * Returns a type of RpcService which is served by this instance of router. @@ -72,12 +76,11 @@ public interface RpcRouter extends RpcImplementation{ * @return default instance responsible for processing RPCs. */ T getDefaultService(); - - /** - * - */ - void setDefaultService(T service); Set> getContexts(); + + RoutedRpcRegistration addRoutedRpcImplementation(T service); + + RpcRegistration registerDefaultService(T service); } 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 a7a70c2839..633506fec6 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 @@ -12,7 +12,7 @@ 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; -import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService; import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory; import org.opendaylight.controller.sal.binding.test.util.BindingTestContext; diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java index 1a97bd693a..6f0db4cd8d 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java @@ -61,13 +61,10 @@ public class RuntimeCodeGeneratorTest { @Test public void testGenerateRouter() throws Exception { - RpcRouter product = codeGenerator.getRouterFor(FooService.class); + RpcRouter product = codeGenerator.getRouterFor(FooService.class,"test"); assertNotNull(product); assertNotNull(product.getInvocationProxy()); - assertNotNull(product.getSupportedInputs()); - assertTrue(product.getSupportedInputs().contains(SimpleInput.class)); - assertTrue(product.getSupportedInputs().contains(InheritedContextInput.class)); assertEquals("2 fields should be generated.", 2, product.getInvocationProxy().getClass().getFields().length); verifyRouting(product); diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/MultipleAugmentationPuts.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/MultipleAugmentationPuts.java index 6d1a699145..5abc8fe0f7 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/MultipleAugmentationPuts.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/MultipleAugmentationPuts.java @@ -1,5 +1,9 @@ package org.opendaylight.controller.sal.binding.test.bugfix; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; @@ -9,24 +13,23 @@ import java.util.Map; import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; -import org.opendaylight.controller.sal.binding.test.AugmentationVerifier; import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; +import org.opendaylight.controller.sal.binding.test.AugmentationVerifier; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter32; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter64; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.Duration; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.DurationBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStatsBuilder; @@ -38,10 +41,6 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import com.google.common.collect.FluentIterable; - -import static org.junit.Assert.*; - public class MultipleAugmentationPuts extends AbstractDataServiceTest implements DataChangeListener { private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); @@ -86,35 +85,35 @@ public class MultipleAugmentationPuts extends AbstractDataServiceTest implements verifyNode(nodes, flowCapableNode).assertHasAugmentation(FlowCapableNode.class); ; assertBindingIndependentVersion(NODE_INSTANCE_ID_BI); - Node meterStatsNode = createTestNode(NodeMeterStatistics.class, nodeMeterStatistics()); - commitNodeAndVerifyTransaction(meterStatsNode); - - assertNotNull(receivedChangeEvent); - verifyNode((Nodes) receivedChangeEvent.getUpdatedOperationalSubtree(), meterStatsNode); - - assertBindingIndependentVersion(NODE_INSTANCE_ID_BI); - - Node mergedNode = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); - - AugmentationVerifier.from(mergedNode) // - .assertHasAugmentation(FlowCapableNode.class) // - .assertHasAugmentation(NodeMeterStatistics.class); - - assertBindingIndependentVersion(NODE_INSTANCE_ID_BI); - - Node meterStatsNodeWithDuration = createTestNode(NodeMeterStatistics.class, nodeMeterStatistics(5, true)); - commitNodeAndVerifyTransaction(meterStatsNodeWithDuration); - - - Node nodeWithUpdatedList = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); - AugmentationVerifier.from(nodeWithUpdatedList) // - .assertHasAugmentation(FlowCapableNode.class) // - .assertHasAugmentation(NodeMeterStatistics.class); - - List meterStats = nodeWithUpdatedList.getAugmentation(NodeMeterStatistics.class).getMeterStatistics().getMeterStats(); - assertNotNull(meterStats); - assertFalse(meterStats.isEmpty()); - assertBindingIndependentVersion(NODE_INSTANCE_ID_BI); +// Node meterStatsNode = createTestNode(NodeMeterStatistics.class, nodeMeterStatistics()); +// commitNodeAndVerifyTransaction(meterStatsNode); +// +// assertNotNull(receivedChangeEvent); +// verifyNode((Nodes) receivedChangeEvent.getUpdatedOperationalSubtree(), meterStatsNode); +// +// assertBindingIndependentVersion(NODE_INSTANCE_ID_BI); +// +// Node mergedNode = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); +// +// AugmentationVerifier.from(mergedNode) // +// .assertHasAugmentation(FlowCapableNode.class) // +// .assertHasAugmentation(NodeMeterStatistics.class); +// +// assertBindingIndependentVersion(NODE_INSTANCE_ID_BI); +// +// Node meterStatsNodeWithDuration = createTestNode(NodeMeterStatistics.class, nodeMeterStatistics(5, true)); +// commitNodeAndVerifyTransaction(meterStatsNodeWithDuration); +// +// +// Node nodeWithUpdatedList = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); +// AugmentationVerifier.from(nodeWithUpdatedList) // +// .assertHasAugmentation(FlowCapableNode.class) // +// .assertHasAugmentation(NodeMeterStatistics.class); +// +// List meterStats = nodeWithUpdatedList.getAugmentation(NodeMeterStatistics.class).getMeterStatistics().getMeterStats(); +// assertNotNull(meterStats); +// assertFalse(meterStats.isEmpty()); +// assertBindingIndependentVersion(NODE_INSTANCE_ID_BI); testNodeRemove(); } @@ -186,7 +185,7 @@ public class MultipleAugmentationPuts extends AbstractDataServiceTest implements stats.add(statistic.build()); } - meterStats.setMeterStats(stats); + // meterStats.setMeterStats(stats); nmsb.setMeterStatistics(meterStats.build()); return nmsb.build(); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java index 4e611c5fe2..d4d27a14ec 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java @@ -7,15 +7,22 @@ import java.util.Set; import javassist.ClassPool; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl; +import org.opendaylight.controller.sal.binding.impl.BindingAwareBrokerImpl; import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl; -import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector; +import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService; import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.controller.sal.core.api.data.DataStore; +import org.opendaylight.controller.sal.dom.broker.BrokerImpl; 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.RpcRouterImpl; 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; @@ -31,7 +38,7 @@ import com.google.common.util.concurrent.MoreExecutors; import static com.google.common.base.Preconditions.*; -public class BindingTestContext { +public class BindingTestContext implements AutoCloseable { public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier TREE_ROOT = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier @@ -40,10 +47,15 @@ public class BindingTestContext { private static final Logger LOG = LoggerFactory.getLogger(BindingTestContext.class); private RuntimeGeneratedMappingServiceImpl mappingServiceImpl; + + + private BindingAwareBrokerImpl baBrokerImpl; private DataBrokerImpl baDataImpl; + private NotificationBrokerImpl baNotifyImpl; + private BindingIndependentConnector baConnectDataServiceImpl; + private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl; - - private BindingIndependentDataServiceConnector connectorServiceImpl; + private BrokerImpl biBrokerImpl; private HashMapDataStore rawDataStore; private SchemaAwareDataStoreAdapter schemaAwareDataStore; private DataStoreStatsWrapper dataStoreStats; @@ -56,6 +68,7 @@ public class BindingTestContext { private final ClassPool classPool; private final boolean startWithSchema; + protected BindingTestContext(ListeningExecutorService executor, ClassPool classPool, boolean startWithSchema) { this.executor = executor; @@ -93,15 +106,29 @@ public class BindingTestContext { baDataImpl.setExecutor(executor); } + public void startBindingBroker() { + checkState(executor != null,"Executor needs to be set"); + checkState(baDataImpl != null,"Binding Data Broker must be started"); + checkState(baNotifyImpl != null, "Notification Service must be started"); + baBrokerImpl = new BindingAwareBrokerImpl("test",null); + + baBrokerImpl.setDataBroker(baDataImpl); + baBrokerImpl.setNotifyBroker(baNotifyImpl); + + baBrokerImpl.start(); + } + public void startBindingToDomDataConnector() { checkState(baDataImpl != null,"Binding Data Broker needs to be started"); checkState(biDataImpl != null,"DOM Data Broker needs to be started."); checkState(mappingServiceImpl != null,"DOM Mapping Service needs to be started."); - connectorServiceImpl = new BindingIndependentDataServiceConnector(); - connectorServiceImpl.setBaDataService(baDataImpl); - connectorServiceImpl.setBiDataService(biDataImpl); - connectorServiceImpl.setMappingService(mappingServiceImpl); - connectorServiceImpl.start(); + baConnectDataServiceImpl = new BindingIndependentConnector(); + baConnectDataServiceImpl.setRpcRegistry(baBrokerImpl); + baConnectDataServiceImpl.setDomRpcRegistry(getDomRpcRegistry()); + baConnectDataServiceImpl.setBaDataService(baDataImpl); + baConnectDataServiceImpl.setBiDataService(biDataImpl); + baConnectDataServiceImpl.setMappingService(mappingServiceImpl); + baConnectDataServiceImpl.start(); } public void startBindingToDomMappingService() { @@ -149,8 +176,11 @@ public class BindingTestContext { public void start() { startBindingDataBroker(); + startBindingNotificationBroker(); + startBindingBroker(); startDomDataBroker(); startDomDataStore(); + startDomBroker(); startBindingToDomMappingService(); startBindingToDomDataConnector(); if(startWithSchema) { @@ -158,6 +188,19 @@ public class BindingTestContext { } } + private void startDomBroker() { + checkState(executor != null); + biBrokerImpl = new BrokerImpl(); + biBrokerImpl.setExecutor(executor); + biBrokerImpl.setRouter(new RpcRouterImpl("test")); + } + + public void startBindingNotificationBroker() { + checkState(executor != null); + baNotifyImpl = new NotificationBrokerImpl(executor); + + } + public void loadYangSchemaFromClasspath() { String[] files = getAllYangFilesOnClasspath(); updateYangSchema(files); @@ -196,4 +239,24 @@ public class BindingTestContext { dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(), dataStoreStats.getRequestCommitAverageTime()); } + + public RpcProviderRegistry getBindingRpcRegistry() { + return baBrokerImpl; + } + + public RpcProvisionRegistry getDomRpcRegistry() { + if(biBrokerImpl == null) { + return null; + } + return biBrokerImpl.getRouter(); + } + + public RpcImplementation getDomRpcInvoker() { + return biBrokerImpl.getRouter(); + } + + @Override + public void close() throws Exception { + + } } diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/FlagsSerializationTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/FlagsSerializationTest.java new file mode 100644 index 0000000000..1304f0d52a --- /dev/null +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/FlagsSerializationTest.java @@ -0,0 +1,210 @@ +package org.opendaylight.controller.sal.binding.test.bugfix; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + + + + + + + + + + + + + + + + + + + +import org.junit.Test; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsActionCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.mpls.action._case.PopMplsActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +import static org.junit.Assert.*; + +public class FlagsSerializationTest extends AbstractDataServiceTest { + + private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); + private static final QName FLOW_ID_QNAME = QName.create(Flow.QNAME, "id"); + private static final QName FLOW_NODE_QNAME = QName.create(Flow.QNAME, "node"); + private static final long FLOW_ID = 1234; + private static final short TABLE_ID = (short)0; + private static final String NODE_ID = "node:1"; + + private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID)); + private static final FlowKey FLOW_KEY = new FlowKey(new FlowId(FLOW_ID)); + private static final TableKey TABLE_KEY = new TableKey(TABLE_ID); + + private static final Map NODE_KEY_BI = Collections. singletonMap(NODE_ID_QNAME, + NODE_ID); + + private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) // + .child(Node.class, NODE_KEY).toInstance(); + + private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = // + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // + .node(Nodes.QNAME) // + .nodeWithKey(Node.QNAME, NODE_KEY_BI) // + .toInstance(); + private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA); + + + +// private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier FLOW_INSTANCE_ID_BI = // +// org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // +// +// .node(Flows.QNAME) // +// .nodeWithKey(Flow.QNAME, FLOW_KEY_BI) // +// .toInstance(); + private static final InstanceIdentifier FLOW_INSTANCE_ID_BA = // + InstanceIdentifier.builder(NODE_INSTANCE_ID_BA) // + .augmentation(FlowCapableNode.class) + .child(Table.class,TABLE_KEY) + .child(Flow.class, FLOW_KEY) // + .toInstance(); + private static final QName FLOW_FLAGS_QNAME = QName.create(Flow.QNAME, "flags"); + + @Test + public void testIndirectGeneration() throws Exception { + + FlowModFlags checkOverlapFlags = new FlowModFlags(true,false,false,false,false); + ImmutableSet domCheckOverlapFlags = ImmutableSet.of("CHECK_OVERLAP"); + testFlags(checkOverlapFlags,domCheckOverlapFlags); + + + + FlowModFlags allFalseFlags = new FlowModFlags(false,false,false,false,false); + ImmutableSet domAllFalseFlags = ImmutableSet.of(); + testFlags(allFalseFlags,domAllFalseFlags); + + FlowModFlags allTrueFlags = new FlowModFlags(true,true,true,true,true); + ImmutableSet domAllTrueFlags = ImmutableSet.of("CHECK_OVERLAP","NO_BYT_COUNTS", "NO_PKT_COUNTS", "RESET_COUNTS", "SEND_FLOW_REM"); + testFlags(allTrueFlags,domAllTrueFlags); + + FlowModFlags nullFlags = null; + ImmutableSet domNullFlags = null; + testFlags(null,null); + + + + } + + private void testFlags(FlowModFlags flagsToTest, ImmutableSet domFlags) throws Exception { + Flow flow = createFlow(flagsToTest); + assertNotNull(flow); + + CompositeNode domFlow = biDataService.readConfigurationData(mappingService.toDataDom(FLOW_INSTANCE_ID_BA)); + + assertNotNull(domFlow); + org.opendaylight.yangtools.yang.data.api.Node readedFlags = domFlow.getFirstSimpleByName(FLOW_FLAGS_QNAME); + + if(domFlags != null) { + assertNotNull(readedFlags); + assertEquals(domFlags,readedFlags.getValue()); + } else { + assertNull(readedFlags); + } + assertEquals(flagsToTest, flow.getFlags()); + + DataModificationTransaction transaction = baDataService.beginTransaction(); + transaction.removeConfigurationData(FLOW_INSTANCE_ID_BA); + RpcResult result = transaction.commit().get(); + assertEquals(TransactionStatus.COMMITED, result.getResult()); + + } + + private Flow createFlow(FlowModFlags flagsToTest) throws Exception { + + DataModificationTransaction modification = baDataService.beginTransaction(); + + FlowBuilder flow = new FlowBuilder(); + MatchBuilder match = new MatchBuilder(); + VlanMatchBuilder vlanBuilder = new VlanMatchBuilder(); + VlanIdBuilder vlanIdBuilder = new VlanIdBuilder(); + VlanId vlanId = new VlanId(10); + vlanBuilder.setVlanId(vlanIdBuilder.setVlanId(vlanId).build()); + match.setVlanMatch(vlanBuilder.build()); + + flow.setKey(FLOW_KEY); + flow.setMatch(match.build()); + + flow.setFlags(flagsToTest); + + InstructionsBuilder instructions = new InstructionsBuilder(); + InstructionBuilder instruction = new InstructionBuilder(); + + instruction.setOrder(10); + ApplyActionsBuilder applyActions = new ApplyActionsBuilder(); + List actionList = new ArrayList<>(); + PopMplsActionBuilder popMplsAction = new PopMplsActionBuilder(); + popMplsAction.setEthernetType(34); + actionList.add(new ActionBuilder().setAction(new PopMplsActionCaseBuilder().setPopMplsAction(popMplsAction.build()).build()).setOrder(10).build()); + + applyActions.setAction(actionList ); + + instruction.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(applyActions.build()).build()); + + + List instructionList = Collections.singletonList(instruction.build()); + instructions.setInstruction(instructionList ); + + flow.setInstructions(instructions.build()); + modification.putConfigurationData(FLOW_INSTANCE_ID_BA, flow.build()); + RpcResult ret = modification.commit().get(); + assertNotNull(ret); + assertEquals(TransactionStatus.COMMITED, ret.getResult()); + return (Flow) baDataService.readConfigurationData(FLOW_INSTANCE_ID_BA); + } +} diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java new file mode 100644 index 0000000000..92a0a3a98d --- /dev/null +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java @@ -0,0 +1,159 @@ +package org.opendaylight.controller.sal.binding.test.connect.dom; + +import java.math.BigInteger; +import java.util.Collections; +import java.util.concurrent.Future; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory; +import org.opendaylight.controller.sal.binding.test.util.BindingTestContext; +import org.opendaylight.controller.sal.common.util.Rpcs; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlowRemoved; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeContext; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; + +import static junit.framework.Assert.*; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.MoreExecutors; + +public class CrossBrokerRpcTest { + + protected RpcProviderRegistry baRpcRegistry; + protected RpcProvisionRegistry biRpcRegistry; + private BindingTestContext testContext; + private RpcImplementation biRpcInvoker; + private MessageCapturingFlowService flowService; + + public static final NodeId NODE_A = new NodeId("a"); + public static final NodeId NODE_B = new NodeId("b"); + public static final NodeId NODE_C = new NodeId("c"); + public static final NodeId NODE_D = new NodeId("d"); + + public static final InstanceIdentifier BA_NODE_A_ID = createBANodeIdentifier(NODE_A); + public static final InstanceIdentifier BA_NODE_B_ID = createBANodeIdentifier(NODE_B); + public static final InstanceIdentifier BA_NODE_C_ID = createBANodeIdentifier(NODE_C); + public static final InstanceIdentifier BA_NODE_D_ID = createBANodeIdentifier(NODE_D); + + public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_A_ID = createBINodeIdentifier(NODE_A); + public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_B_ID = createBINodeIdentifier(NODE_B); + public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_C_ID = createBINodeIdentifier(NODE_C); + public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_D_ID = createBINodeIdentifier(NODE_D); + + private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); + private static final QName ADD_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "add-flow"); + private static final QName REMOVE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "remove-flow"); + private static final QName UPDATE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "update-flow"); + + @Before + public void setup() { + BindingBrokerTestFactory testFactory = new BindingBrokerTestFactory(); + testFactory.setExecutor(MoreExecutors.sameThreadExecutor()); + testFactory.setStartWithParsedSchema(true); + testContext = testFactory.getTestContext(); + + testContext.start(); + baRpcRegistry = testContext.getBindingRpcRegistry(); + biRpcRegistry = testContext.getDomRpcRegistry(); + biRpcInvoker = testContext.getDomRpcInvoker(); + assertNotNull(baRpcRegistry); + assertNotNull(biRpcRegistry); + + flowService = MessageCapturingFlowService.create(baRpcRegistry); + + } + + @Test + public void bindingRoutedRpcProvider_DomInvokerTest() { + + flowService// + .registerPath(NodeContext.class, BA_NODE_A_ID) // + .registerPath(NodeContext.class, BA_NODE_B_ID) // + .setAddFlowResult(addFlowResult(true, 10)); + + SalFlowService baFlowInvoker = baRpcRegistry.getRpcService(SalFlowService.class); + assertNotSame(flowService, baFlowInvoker); + + AddFlowInput addFlowA = addFlow(BA_NODE_A_ID) // + .setPriority(100).setBarrier(true).build(); + + CompositeNode addFlowDom = toDomRpc(ADD_FLOW_QNAME, addFlowA); + assertNotNull(addFlowDom); + RpcResult domResult = biRpcInvoker.invokeRpc(ADD_FLOW_QNAME, addFlowDom); + assertNotNull(domResult); + assertTrue("DOM result is successful.", domResult.isSuccessful()); + assertTrue("Bidning Add Flow RPC was captured.", flowService.getReceivedAddFlows().containsKey(BA_NODE_A_ID)); + assertEquals(addFlowA, flowService.getReceivedAddFlows().get(BA_NODE_A_ID).iterator().next()); + } + + public void bindingRpcInvoker_DomRoutedProviderTest() { + + } + + private CompositeNode toDomRpcInput(DataObject addFlowA) { + return testContext.getBindingToDomMappingService().toDataDom(addFlowA); + } + + @After + public void teardown() throws Exception { + testContext.close(); + } + + private static InstanceIdentifier createBANodeIdentifier(NodeId node) { + return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(node)).toInstance(); + } + + private static org.opendaylight.yangtools.yang.data.api.InstanceIdentifier createBINodeIdentifier(NodeId node) { + return org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder().node(Nodes.QNAME) + .nodeWithKey(Node.QNAME, NODE_ID_QNAME, node.getValue()).toInstance(); + } + + private Future> addFlowResult(boolean success, long xid) { + AddFlowOutput output = new AddFlowOutputBuilder() // + .setTransactionId(new TransactionId(BigInteger.valueOf(xid))).build(); + RpcResult result = Rpcs.getRpcResult(success, output, ImmutableList. of()); + return Futures.immediateFuture(result); + } + + private static AddFlowInputBuilder addFlow(InstanceIdentifier nodeId) { + AddFlowInputBuilder builder = new AddFlowInputBuilder(); + builder.setNode(new NodeRef(nodeId)); + return builder; + } + + private CompositeNode toDomRpc(QName rpcName, AddFlowInput addFlowA) { + return new CompositeNodeTOImpl(rpcName, null, + Collections.> singletonList(toDomRpcInput(addFlowA))); + } +} diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java new file mode 100644 index 0000000000..74f07818d5 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java @@ -0,0 +1,122 @@ +package org.opendaylight.controller.sal.binding.test.connect.dom; + +import static junit.framework.Assert.assertNotNull; + +import java.util.concurrent.Future; + +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +public class MessageCapturingFlowService implements SalFlowService, AutoCloseable { + + private Future> addFlowResult; + private Future> removeFlowResult; + private Future> updateFlowResult; + + private final Multimap, AddFlowInput> receivedAddFlows = HashMultimap.create(); + private final Multimap, RemoveFlowInput> receivedRemoveFlows = HashMultimap.create(); + private final Multimap, UpdateFlowInput> receivedUpdateFlows = HashMultimap.create(); + private RoutedRpcRegistration registration; + + @Override + public Future> addFlow(AddFlowInput arg0) { + receivedAddFlows.put(arg0.getNode().getValue(), arg0); + return addFlowResult; + } + + @Override + public Future> removeFlow(RemoveFlowInput arg0) { + receivedRemoveFlows.put(arg0.getNode().getValue(), arg0); + return removeFlowResult; + } + + @Override + public Future> updateFlow(UpdateFlowInput arg0) { + receivedUpdateFlows.put(arg0.getNode().getValue(), arg0); + return updateFlowResult; + } + + public Future> getAddFlowResult() { + return addFlowResult; + } + + public MessageCapturingFlowService setAddFlowResult(Future> addFlowResult) { + this.addFlowResult = addFlowResult; + return this; + } + + public Future> getRemoveFlowResult() { + return removeFlowResult; + } + + public MessageCapturingFlowService setRemoveFlowResult(Future> removeFlowResult) { + this.removeFlowResult = removeFlowResult; + return this; + } + + public Future> getUpdateFlowResult() { + return updateFlowResult; + } + + public MessageCapturingFlowService setUpdateFlowResult(Future> updateFlowResult) { + this.updateFlowResult = updateFlowResult; + return this; + } + + public Multimap, AddFlowInput> getReceivedAddFlows() { + return receivedAddFlows; + } + + public Multimap, RemoveFlowInput> getReceivedRemoveFlows() { + return receivedRemoveFlows; + } + + public Multimap, UpdateFlowInput> getReceivedUpdateFlows() { + return receivedUpdateFlows; + } + + public MessageCapturingFlowService registerTo(RpcProviderRegistry registry) { + registration = registry.addRoutedRpcImplementation(SalFlowService.class, this); + assertNotNull(registration); + return this; + } + + public void close() throws Exception { + registration.close(); + } + + public MessageCapturingFlowService registerPath(Class context, InstanceIdentifier path) { + registration.registerPath(context, path); + return this; + } + + public MessageCapturingFlowService unregisterPath(Class context, InstanceIdentifier path) { + registration.unregisterPath(context, path); + return this; + } + + public static MessageCapturingFlowService create() { + return new MessageCapturingFlowService(); + } + + public static MessageCapturingFlowService create(RpcProviderRegistry registry) { + MessageCapturingFlowService ret = new MessageCapturingFlowService(); + ret.registerTo(registry); + return ret; + } + + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java b/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java index 15616215d3..112b57cd33 100644 --- a/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java +++ b/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java @@ -54,6 +54,7 @@ public class TestHelper { mavenBundle(CONTROLLER, "config-persister-api").versionAsInProject(), // mavenBundle(CONTROLLER, "netconf-api").versionAsInProject(), // mavenBundle(CONTROLLER, "ietf-netconf-monitoring").versionAsInProject(), // + mavenBundle(CONTROLLER, "ietf-netconf-monitoring-extension").versionAsInProject(), // mavenBundle(CONTROLLER, "netconf-monitoring").versionAsInProject(), // mavenBundle(CONTROLLER, "netconf-client").versionAsInProject(), // diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java index 89851c9393..bee29a1ad1 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java @@ -4,5 +4,5 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration; public interface RouteChangePublisher { - ListenerRegistration> registerRouteChangeListener(RouteChangeListener listener); + > ListenerRegistration registerRouteChangeListener(L listener); } diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java new file mode 100644 index 0000000000..60d0cdf766 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java @@ -0,0 +1,92 @@ +package org.opendaylight.controller.md.sal.common.impl.routing; + +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +public class RoutingUtils { + + public static RouteChange removalChange(C context,P path) { + final ImmutableMap> announcements = ImmutableMap.>of(); + final ImmutableMap> removals = ImmutableMap.>of(context, ImmutableSet.of(path)); + return new RouteChangeImpl(announcements, removals); + } + + public static RouteChange announcementChange(C context,P path) { + final ImmutableMap> announcements = ImmutableMap.>of(context, ImmutableSet.of(path)); + final ImmutableMap> removals = ImmutableMap.>of(); + return new RouteChangeImpl(announcements, removals); + } + + + public static RouteChange change(Map> announcements, + Map> removals) { + final ImmutableMap> immutableAnnouncements = ImmutableMap.>copyOf(announcements); + final ImmutableMap> immutableRemovals = ImmutableMap.>copyOf(removals); + return new RouteChangeImpl(immutableAnnouncements, immutableRemovals); + } + + + private static class RouteChangeImpl implements RouteChange { + private final Map> removal; + private final Map> announcement; + + public RouteChangeImpl(ImmutableMap> removal, ImmutableMap> announcement) { + super(); + this.removal = removal; + this.announcement = announcement; + } + + @Override + public Map> getAnnouncements() { + return announcement; + } + + @Override + public Map> getRemovals() { + return removal; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((announcement == null) ? 0 : announcement.hashCode()); + result = prime * result + ((removal == null) ? 0 : removal.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + RouteChangeImpl other = (RouteChangeImpl) obj; + if (announcement == null) { + if (other.announcement != null) + return false; + } else if (!announcement.equals(other.announcement)) + return false; + if (removal == null) { + if (other.removal != null) { + return false; + } + } else if (!removal.equals(other.removal)) + return false; + return true; + } + } + + + +} diff --git a/opendaylight/md-sal/sal-common-util/pom.xml b/opendaylight/md-sal/sal-common-util/pom.xml index 7e8069a9b3..ff15e72ba6 100644 --- a/opendaylight/md-sal/sal-common-util/pom.xml +++ b/opendaylight/md-sal/sal-common-util/pom.xml @@ -23,6 +23,10 @@ concepts 0.1.1-SNAPSHOT + + com.google.guava + guava + bundle diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java index 54e1a065f4..356ec8ff7c 100644 --- a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java +++ b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java @@ -11,17 +11,31 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; + +import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; +import com.google.common.collect.ImmutableList; + public class Rpcs { + + public static RpcResult getRpcResult(boolean successful) { + RpcResult ret = new RpcResultTO(successful, null, ImmutableList.of()); + return ret; + } + public static RpcResult getRpcResult(boolean successful, T result, Collection errors) { RpcResult ret = new RpcResultTO(successful, result, errors); return ret; } - private static class RpcResultTO implements RpcResult, Serializable { + public static RpcResult getRpcResult(boolean successful, Collection errors) { + return new RpcResultTO(successful, null, errors); + } + + private static class RpcResultTO implements RpcResult, Serializable, Immutable { private final Collection errors; private final T result; @@ -31,8 +45,7 @@ public class Rpcs { Collection errors) { this.successful = successful; this.result = result; - this.errors = Collections.unmodifiableList(new ArrayList( - errors)); + this.errors = ImmutableList.copyOf(errors); } @Override diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend index 7ef594bad9..8f179987b9 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend @@ -29,8 +29,10 @@ import org.slf4j.LoggerFactory import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter import org.opendaylight.yangtools.concepts.ListenerRegistration import org.opendaylight.controller.sal.core.api.RpcRegistrationListener +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry +import org.opendaylight.controller.sal.core.api.RpcImplementation -public class BrokerImpl implements Broker, AutoCloseable { +public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable { private static val log = LoggerFactory.getLogger(BrokerImpl); // Broker Generic Context @@ -115,4 +117,12 @@ public class BrokerImpl implements Broker, AutoCloseable { deactivator?.close(); } + override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException { + router.addRpcImplementation(rpcType,implementation); + } + + override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { + router.addRoutedRpcImplementation(rpcType,implementation); + } + } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend index d8680ce3b4..5ee19a0e8f 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend @@ -15,6 +15,8 @@ import org.opendaylight.yangtools.concepts.AbstractObjectRegistration import org.opendaylight.controller.sal.core.api.RpcRegistrationListener import org.slf4j.LoggerFactory import org.opendaylight.yangtools.concepts.util.ListenerRegistry +import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier class RpcRouterImpl implements RpcRouter, Identifiable { @@ -35,6 +37,20 @@ class RpcRouterImpl implements RpcRouter, Identifiable { } override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { + checkNotNull(rpcType, "Rpc Type should not be null"); + checkNotNull(implementation, "Implementation should not be null."); + val reg = new RoutedRpcRegistrationImpl(rpcType, implementation, this); + implementations.put(rpcType, reg) + + for (listener : rpcRegistrationListeners.listeners) { + try { + listener.instance.onRpcImplementationAdded(rpcType); + } catch (Exception e) { + log.error("Unhandled exception during invoking listener", e); + } + } + + return reg; } override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException { @@ -102,5 +118,23 @@ class RpcRegistrationImpl extends AbstractObjectRegistration override protected removeRegistration() { router.remove(this); } +} +class RoutedRpcRegistrationImpl extends RpcRegistrationImpl implements RoutedRpcRegistration { + + + new(QName type, RpcImplementation instance, RpcRouterImpl router) { + super(type,instance,router) + } + override protected removeRegistration() { + router.remove(this); + } + override registerPath(QName context, InstanceIdentifier path) { + // + + } + + override unregisterPath(QName context, InstanceIdentifier path) { + // + } } 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 index 4f4fadcc44..75e96491b6 100644 --- 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 @@ -151,19 +151,20 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator original) { // NOOP for now NormalizedDataModification normalized = new NormalizedDataModification(original); - for (Entry entry : original.getUpdatedConfigurationData().entrySet()) { + for (Entry entry : original.getUpdatedConfigurationData().entrySet()) { normalized.putConfigurationData(entry.getKey(), entry.getValue()); } - for (Entry entry : original.getUpdatedOperationalData().entrySet()) { + for (Entry entry : original.getUpdatedOperationalData().entrySet()) { normalized.putOperationalData(entry.getKey(), entry.getValue()); } for (InstanceIdentifier entry : original.getRemovedConfigurationData()) { normalized.removeConfigurationData(entry); } - for(InstanceIdentifier entry : original.getRemovedOperationalData()) { + for (InstanceIdentifier entry : original.getRemovedOperationalData()) { normalized.removeOperationalData(entry); } return normalized; @@ -284,7 +285,7 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator { private Object identifier; @@ -295,12 +296,12 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator> commit() { throw new UnsupportedOperationException("Commit should not be invoked on this"); } - + @Override - protected CompositeNode mergeConfigurationData(InstanceIdentifier path,CompositeNode stored, CompositeNode modified) { - return mergeData(path,stored, modified,true); + protected CompositeNode mergeConfigurationData(InstanceIdentifier path, CompositeNode stored, + CompositeNode modified) { + return mergeData(path, stored, modified, true); } - + @Override - protected CompositeNode mergeOperationalData(InstanceIdentifier path,CompositeNode stored, CompositeNode modified) { + protected CompositeNode mergeOperationalData(InstanceIdentifier path, CompositeNode stored, + CompositeNode modified) { // TODO Auto-generated method stub - return mergeData(path,stored,modified,false); + return mergeData(path, stored, modified, false); } - } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/implementation/pom.xml index b8e0938a5f..c973498e85 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/pom.xml +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/pom.xml @@ -37,7 +37,7 @@ org.opendaylight.controller - zeromq-routingtable.implementation + remoterpc-routingtable.implementation 0.4.1-SNAPSHOT diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml index dd7e36cfb4..dc2fdbf9a0 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml +++ b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml @@ -97,7 +97,7 @@ org.opendaylight.controller - zeromq-routingtable.implementation + remoterpc-routingtable.implementation 0.4.1-SNAPSHOT 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 a42c468c2a..fb7872f8bc 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,15 +3,38 @@ package org.opendaylight.controller.sal.rest.impl; import static com.google.common.base.Preconditions.checkNotNull; import java.io.IOException; -import java.util.*; +import java.net.URI; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import javax.activation.UnsupportedDataTypeException; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue; +import org.opendaylight.controller.sal.restconf.impl.RestCodec; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.*; -import org.opendaylight.yangtools.yang.model.api.*; -import org.opendaylight.yangtools.yang.model.api.type.*; +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.ChoiceCaseNode; +import org.opendaylight.yangtools.yang.model.api.ChoiceNode; +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.IdentityrefTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; import com.google.gson.stream.JsonWriter; @@ -20,6 +43,7 @@ class JsonMapper { private final Set foundLeafLists = new HashSet<>(); private final Set foundLists = new HashSet<>(); + private final Logger logger = LoggerFactory.getLogger(JsonMapper.class); public void write(JsonWriter writer, CompositeNode data, DataNodeContainer schema) throws IOException { Preconditions.checkNotNull(writer); @@ -158,117 +182,42 @@ class JsonMapper { private void writeValueOfNodeByType(JsonWriter writer, SimpleNode node, TypeDefinition type, DataSchemaNode schema) throws IOException { - String value = String.valueOf(node.getValue()); - TypeDefinition baseType = resolveBaseTypeFrom(type); + TypeDefinition baseType = RestUtil.resolveBaseTypeFrom(type); - // TODO check InstanceIdentifierTypeDefinition, - // IdentityrefTypeDefinition + // TODO check InstanceIdentifierTypeDefinition if (baseType instanceof IdentityrefTypeDefinition) { if (node.getValue() instanceof QName) { - QName qName = (QName) node.getValue(); - - ControllerContext contContext = ControllerContext.getInstance(); - String moduleName = contContext.findModuleByNamespace(qName.getNamespace()); - - writer.value(moduleName + ":" + qName.getLocalName()); - } - - } else if (baseType instanceof LeafrefTypeDefinition) { - ControllerContext contContext = ControllerContext.getInstance(); - LeafSchemaNode lfSchemaNode = contContext.resolveTypeFromLeafref((LeafrefTypeDefinition) baseType, schema); - if (lfSchemaNode != null) { - writeValueOfNodeByType(writer, node, lfSchemaNode.getType(), lfSchemaNode); + IdentityValuesDTO valueDTO = (IdentityValuesDTO) RestCodec.from(baseType).serialize(node.getValue()); + IdentityValue valueFromDTO = valueDTO.getValuesWithNamespaces().get(0); + String moduleName = ControllerContext.getInstance().findModuleByNamespace(URI.create(valueFromDTO.getNamespace())); + writer.value(moduleName + ":" + valueFromDTO.getValue()); } else { - writer.value(value); + logger.debug("Value of " + baseType.getQName().getNamespace() + ":" + + baseType.getQName().getLocalName() + " is not instance of " + QName.class + " but is " + node.getValue().getClass()); + writer.value(String.valueOf(node.getValue())); } - } else 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)); + writer.value(new NumberForJsonWriter((String) RestCodec.from(baseType).serialize(node.getValue()))); } else if (baseType instanceof BooleanTypeDefinition) { - writer.value(Boolean.parseBoolean(value)); + writer.value(Boolean.parseBoolean((String) RestCodec.from(baseType).serialize(node.getValue()))); } else if (baseType instanceof EmptyTypeDefinition) { writeEmptyDataTypeToJson(writer); } else { + String value = String.valueOf(RestCodec.from(baseType).serialize(node.getValue())); + if (value == null) { + value = String.valueOf(node.getValue()); + } 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 (isBoolean(value) && containsType(unionType, BooleanTypeDefinition.class)) { - writer.value(Boolean.parseBoolean(value)); - } else { - 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()) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java index 83e2d20d0e..f4c5034776 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java @@ -9,6 +9,7 @@ import java.util.Set; import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; import com.google.common.collect.Lists; import com.google.gson.JsonElement; @@ -52,8 +53,8 @@ class JsonReader { } private CompositeNodeWrapper createStructureWithRoot(String rootObjectName, JsonObject rootObject) { - CompositeNodeWrapper firstNode = new CompositeNodeWrapper(getNamespaceFrom(rootObjectName), - getLocalNameFrom(rootObjectName)); + CompositeNodeWrapper firstNode = new CompositeNodeWrapper(getNamespaceFor(rootObjectName), + getLocalNameFor(rootObjectName)); for (Entry childOfFirstNode : rootObject.entrySet()) { addChildToParent(childOfFirstNode.getKey(), childOfFirstNode.getValue(), firstNode); } @@ -62,15 +63,15 @@ class JsonReader { private void addChildToParent(String childName, JsonElement childType, CompositeNodeWrapper parent) { if (childType.isJsonObject()) { - CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFrom(childName), - getLocalNameFrom(childName)); + CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFor(childName), + getLocalNameFor(childName)); parent.addValue(child); for (Entry childOfChild : childType.getAsJsonObject().entrySet()) { addChildToParent(childOfChild.getKey(), childOfChild.getValue(), child); } } else if (childType.isJsonArray()) { if (childType.getAsJsonArray().size() == 1 && childType.getAsJsonArray().get(0).isJsonNull()) { - parent.addValue(new EmptyNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName))); + parent.addValue(new EmptyNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName))); } else { for (JsonElement childOfChildType : childType.getAsJsonArray()) { @@ -80,24 +81,36 @@ class JsonReader { } else if (childType.isJsonPrimitive()) { JsonPrimitive childPrimitive = childType.getAsJsonPrimitive(); String value = childPrimitive.getAsString(); - parent.addValue(new SimpleNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName), value)); + parent.addValue(new SimpleNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName), + resolveValueOfElement(value))); } } - private URI getNamespaceFrom(String jsonElementName) { - int indexOfDelimeter = jsonElementName.lastIndexOf(':'); - if (indexOfDelimeter == -1) { + private URI getNamespaceFor(String jsonElementName) { + String[] moduleNameAndLocalName = jsonElementName.split(":"); + if (moduleNameAndLocalName.length != 2) { // it is not "moduleName:localName" return null; } - return URI.create(jsonElementName.substring(0, indexOfDelimeter)); + return URI.create(moduleNameAndLocalName[0]); } - private String getLocalNameFrom(String jsonElementName) { - int indexOfDelimeter = jsonElementName.lastIndexOf(':'); - if (indexOfDelimeter == -1) { + private String getLocalNameFor(String jsonElementName) { + String[] moduleNameAndLocalName = jsonElementName.split(":"); + if (moduleNameAndLocalName.length != 2) { // it is not "moduleName:localName" return jsonElementName; } - return jsonElementName.substring(indexOfDelimeter + 1, jsonElementName.length()); + return moduleNameAndLocalName[1]; + } + + /** + * @param value + * value of json element + * @return if value is "moduleName:localName" then {@link IdentityValuesDTO} else + * the same string as parameter "value" + */ + private Object resolveValueOfElement(String value) { + URI namespace = getNamespaceFor(value); + return namespace == null ? value : new IdentityValuesDTO(namespace.toString(), getLocalNameFor(value), null); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java new file mode 100644 index 0000000000..6e70b9bddf --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java @@ -0,0 +1,15 @@ +package org.opendaylight.controller.sal.rest.impl; + +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; + +public final class RestUtil { + + public final static TypeDefinition resolveBaseTypeFrom(TypeDefinition type) { + TypeDefinition superType = type; + while (superType.getBaseType() != null) { + superType = superType.getBaseType(); + } + return superType; + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java index 53b401e4a2..242f18d240 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java @@ -20,7 +20,7 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; public class RestconfProvider implements BundleActivator, Provider, ServiceTrackerCustomizer { - public final static String NOT_INITALIZED_MSG = "Restcof is not initialized yet. Please try again later"; + public final static String NOT_INITALIZED_MSG = "Restconf is not initialized yet. Please try again later"; private ListenerRegistration listenerRegistration; private ServiceTracker brokerServiceTrancker; diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlMapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlMapper.java index 4a077e663f..a3d658e7bf 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlMapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlMapper.java @@ -7,6 +7,9 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue; +import org.opendaylight.controller.sal.restconf.impl.RestCodec; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.Node; @@ -61,9 +64,9 @@ public class XmlMapper { Element itemEl = doc.createElementNS(dataType.getNamespace().toString(), dataType.getLocalName()); if (data instanceof SimpleNode) { if (schema instanceof LeafListSchemaNode) { - writeValueOfNodeByType(itemEl, (SimpleNode) data, ((LeafListSchemaNode) schema).getType()); + writeValueOfNodeByType(itemEl, (SimpleNode) data, ((LeafListSchemaNode) schema).getType(), (DataSchemaNode) schema); } else if (schema instanceof LeafSchemaNode) { - writeValueOfNodeByType(itemEl, (SimpleNode) data, ((LeafSchemaNode) schema).getType()); + writeValueOfNodeByType(itemEl, (SimpleNode) data, ((LeafSchemaNode) schema).getType(), (DataSchemaNode) schema); } else { Object value = data.getValue(); if (value != null) { @@ -88,18 +91,32 @@ public class XmlMapper { return itemEl; } - private void writeValueOfNodeByType(Element element, SimpleNode node, TypeDefinition type) { + private void writeValueOfNodeByType(Element element, SimpleNode node, TypeDefinition type, DataSchemaNode schema) { - TypeDefinition baseType = resolveBaseTypeFrom(type); + TypeDefinition baseType = RestUtil.resolveBaseTypeFrom(type); - if (baseType instanceof IdentityrefTypeDefinition && node.getValue() instanceof QName) { - QName value = (QName) node.getValue(); - element.setAttribute("xmlns:x", value.getNamespace().toString()); - element.setTextContent("x:" + value.getLocalName()); + if (baseType instanceof IdentityrefTypeDefinition) { + if (node.getValue() instanceof QName) { + IdentityValuesDTO valueDTO = (IdentityValuesDTO) RestCodec.from(type).serialize(node.getValue()); + IdentityValue value = valueDTO.getValuesWithNamespaces().get(0); + String prefix = "x"; + if (value.getPrefix() != null && !value.getPrefix().isEmpty()) { + prefix = value.getPrefix(); + } + element.setAttribute("xmlns:" + prefix, value.getNamespace()); + element.setTextContent(prefix + ":" + value.getValue()); + } else { + logger.debug("Value of " + baseType.getQName().getNamespace() + ":" + + baseType.getQName().getLocalName() + " is not instance of " + QName.class + " but is " + node.getValue().getClass()); + element.setTextContent(String.valueOf(node.getValue())); + } } else { - Object value = node.getValue(); - if (value != null) { - element.setTextContent(String.valueOf(value)); + if (node.getValue() != null) { + String value = String.valueOf(RestCodec.from(baseType).serialize(node.getValue())); + if (value.equals("null")) { + value = String.valueOf(node.getValue()); + } + element.setTextContent(value); } } } @@ -122,8 +139,4 @@ public class XmlMapper { return null; } - private TypeDefinition resolveBaseTypeFrom(TypeDefinition type) { - return type.getBaseType() != null ? resolveBaseTypeFrom(type.getBaseType()) : type; - } - } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java index a53281492f..014e839f26 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java @@ -14,6 +14,7 @@ import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.NodeWrapper; import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; @@ -123,11 +124,24 @@ public class XmlReader { return false; } + private CompositeNodeWrapper resolveCompositeNodeFromStartElement(final StartElement startElement) { + checkArgument(startElement != null, "Start Element cannot be NULL!"); + return new CompositeNodeWrapper(getNamespaceFor(startElement), getLocalNameFor(startElement)); + } + private NodeWrapper> resolveSimpleNodeFromStartElement(final StartElement startElement) throws XMLStreamException { checkArgument(startElement != null, "Start Element cannot be NULL!"); - String data = null; + String data = getValueOf(startElement); + if (data == null) { + return new EmptyNodeWrapper(getNamespaceFor(startElement), getLocalNameFor(startElement)); + } + return new SimpleNodeWrapper(getNamespaceFor(startElement), getLocalNameFor(startElement), + resolveValueOfElement(data, startElement)); + } + private String getValueOf(StartElement startElement) throws XMLStreamException { + String data = null; if (eventReader.hasNext()) { final XMLEvent innerEvent = eventReader.peek(); if (innerEvent.isCharacters()) { @@ -143,24 +157,36 @@ public class XmlReader { } } } - if(data == null) { - return new EmptyNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement)); - } - return new SimpleNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement), data); + return 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) { + private String getLocalNameFor(StartElement startElement) { return startElement.getName().getLocalPart(); } - private URI getNamespaceFrom(StartElement startElement) { + private URI getNamespaceFor(StartElement startElement) { String namespaceURI = startElement.getName().getNamespaceURI(); return namespaceURI.isEmpty() ? null : URI.create(namespaceURI); } + /** + * @param value + * value of startElement + * @param startElement + * element containing value + * @return if value is "prefix:value" then {@link IdentityValuesDTO} else the same + * string as parameter "value" + */ + private Object resolveValueOfElement(String value, StartElement startElement) { + String[] namespaceAndValue = value.split(":"); + if (namespaceAndValue.length != 2) { // it is not "prefix:value" + return value; + } + String namespace = startElement.getNamespaceContext().getNamespaceURI(namespaceAndValue[0]); + if (namespace != null && !namespace.isEmpty()) { + return new IdentityValuesDTO(namespace, namespaceAndValue[1], namespaceAndValue[0]); + } + return value; + } + } 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 930aa663bb..eec2d452a1 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 @@ -1,6 +1,7 @@ package org.opendaylight.controller.sal.restconf.impl import com.google.common.collect.BiMap +import com.google.common.collect.FluentIterable import com.google.common.collect.HashBiMap import java.net.URI import java.net.URLDecoder @@ -11,6 +12,7 @@ import java.util.Map import java.util.concurrent.ConcurrentHashMap import javax.ws.rs.core.Response import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener +import org.opendaylight.controller.sal.rest.impl.RestUtil import org.opendaylight.controller.sal.rest.impl.RestconfProvider import org.opendaylight.yangtools.yang.common.QName import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier @@ -18,6 +20,7 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdent import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument +import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode import org.opendaylight.yangtools.yang.model.api.ChoiceNode import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode @@ -27,15 +30,10 @@ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode import org.opendaylight.yangtools.yang.model.api.ListSchemaNode import org.opendaylight.yangtools.yang.model.api.RpcDefinition import org.opendaylight.yangtools.yang.model.api.SchemaContext -import org.opendaylight.yangtools.yang.model.api.SchemaNode -import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition -import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil - -import static com.google.common.base.Preconditions.* -import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition import org.slf4j.LoggerFactory -import com.google.common.collect.FluentIterable + +import static com.google.common.base.Preconditions.* class ControllerContext implements SchemaServiceListener { val static LOG = LoggerFactory.getLogger(ControllerContext) @@ -96,7 +94,7 @@ class ControllerContext implements SchemaServiceListener { return getLatestModule(startModule) } - private def getLatestModule(String moduleName) { + def getLatestModule(String moduleName) { checkPreconditions checkArgument(moduleName !== null && !moduleName.empty) val modules = schemas.modules.filter[m|m.name == moduleName] @@ -142,20 +140,37 @@ class ControllerContext implements SchemaServiceListener { var module = uriToModuleName.get(namespace) if (module === null) { val moduleSchemas = schemas.findModuleByNamespace(namespace); - if(moduleSchemas === null) throw new IllegalArgumentException() + if(moduleSchemas === null) return null var latestModule = moduleSchemas.head for (m : moduleSchemas) { if (m.revision.after(latestModule.revision)) { latestModule = m } } - if(latestModule === null) throw new IllegalArgumentException() + if(latestModule === null) return null uriToModuleName.put(namespace, latestModule.name) module = latestModule.name; } return module } + def findNamespaceByModule(String module) { + var namespace = moduleNameToUri.get(module) + if (namespace === null) { + val moduleSchemas = schemas.modules.filter[it|it.name.equals(module)] + var latestModule = moduleSchemas.head + for (m : moduleSchemas) { + if (m.revision.after(latestModule.revision)) { + latestModule = m + } + } + if(latestModule === null) return null + namespace = latestModule.namespace + uriToModuleName.put(namespace, latestModule.name) + } + return namespace + } + def CharSequence toRestconfIdentifier(QName qname) { checkPreconditions var module = uriToModuleName.get(qname.namespace) @@ -295,11 +310,8 @@ class ControllerContext implements SchemaServiceListener { val typedef = (node as LeafSchemaNode).type; var decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded) - if(decoded == null) { - var baseType = typedef - while (baseType.baseType != null) { - baseType = baseType.baseType; - } + if(decoded === null) { + var baseType = RestUtil.resolveBaseTypeFrom(typedef) if(baseType instanceof IdentityrefTypeDefinition) { decoded = toQName(urlDecoded) } @@ -349,35 +361,4 @@ class ControllerContext implements SchemaServiceListener { } } - /** - * Resolve target type from leafref type. - * - * According to RFC 6020 referenced element has to be leaf (chapter 9.9). - * Therefore if other element is referenced then null value is returned. - * - * Currently only cases without path-predicate are supported. - * - * @param leafRef - * @param schemaNode - * data schema node which contains reference - * @return type if leaf is referenced and it is possible to find referenced - * node in schema context. In other cases null value is returned - */ - def LeafSchemaNode resolveTypeFromLeafref(LeafrefTypeDefinition leafRef, DataSchemaNode schemaNode) { - val xPath = leafRef.getPathStatement(); - val module = SchemaContextUtil.findParentModule(schemas, schemaNode); - - var SchemaNode foundSchemaNode - if (xPath.isAbsolute()) { - foundSchemaNode = SchemaContextUtil.findDataSchemaNode(schemas, module, xPath); - } else { - foundSchemaNode = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemas, module, schemaNode, xPath); - } - - if (foundSchemaNode instanceof LeafSchemaNode) { - return foundSchemaNode as LeafSchemaNode; - } - - return null; - } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/IdentityValuesDTO.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/IdentityValuesDTO.java new file mode 100644 index 0000000000..6924fb620f --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/IdentityValuesDTO.java @@ -0,0 +1,60 @@ +package org.opendaylight.controller.sal.restconf.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class IdentityValuesDTO { + + private final List elementData = new ArrayList<>(); + + public IdentityValuesDTO(String namespace, String value, String prefix) { + elementData.add(new IdentityValue(namespace, value, prefix)); + } + + public void add(String namespace, String value, String prefix) { + elementData.add(new IdentityValue(namespace, value, prefix)); + } + + public List getValuesWithNamespaces() { + return Collections.unmodifiableList(elementData); + } + + public static final class IdentityValue { + + private String namespace; + private String value; + private String prefix; + + public IdentityValue(String namespace, String value, String prefix) { + this.namespace = namespace; + this.value = value; + this.prefix = prefix; + } + + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + } +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java new file mode 100644 index 0000000000..450ba02b56 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java @@ -0,0 +1,123 @@ +package org.opendaylight.controller.sal.restconf.impl; + +import java.net.URI; + +import org.opendaylight.controller.sal.rest.impl.RestUtil; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue; +import org.opendaylight.yangtools.concepts.Codec; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.codec.IdentityrefCodec; +import org.opendaylight.yangtools.yang.data.api.codec.LeafrefCodec; +import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RestCodec { + + private RestCodec() { + } + + public static final Codec from(TypeDefinition typeDefinition) { + return new ObjectCodec(typeDefinition); + } + + @SuppressWarnings("rawtypes") + public static final class ObjectCodec implements Codec { + + private final Logger logger = LoggerFactory.getLogger(RestCodec.class); + + public static final Codec IDENTITYREF_DEFAULT_CODEC = new IdentityrefCodecImpl(); + public static final Codec LEAFREF_DEFAULT_CODEC = new LeafrefCodecImpl(); + + private TypeDefinition type; + + private ObjectCodec(TypeDefinition typeDefinition) { + type = RestUtil.resolveBaseTypeFrom(typeDefinition); + } + + @SuppressWarnings("unchecked") + @Override + public Object deserialize(Object input) { + try { + if (type instanceof IdentityrefTypeDefinition) { + return IDENTITYREF_DEFAULT_CODEC.deserialize(input); + } else if (type instanceof LeafrefTypeDefinition) { + return LEAFREF_DEFAULT_CODEC.deserialize(input); + } else { + TypeDefinitionAwareCodec> typeAwarecodec = TypeDefinitionAwareCodec.from(type); + if (typeAwarecodec != null) { + return typeAwarecodec.deserialize(String.valueOf(input)); + } else { + logger.debug("Codec for type \"" + type.getQName().getLocalName() + "\" is not implemented yet."); + return null; + } + } + } catch (ClassCastException e) { // TODO remove this catch when everyone use codecs + logger.error("ClassCastException was thrown when codec is invoked with parameter " + String.valueOf(input), e); + return input; + } + } + + @SuppressWarnings("unchecked") + @Override + public Object serialize(Object input) { + try { + if (type instanceof IdentityrefTypeDefinition) { + return IDENTITYREF_DEFAULT_CODEC.serialize(input); + } else if (type instanceof LeafrefTypeDefinition) { + return LEAFREF_DEFAULT_CODEC.serialize(input); + } else { + TypeDefinitionAwareCodec> typeAwarecodec = TypeDefinitionAwareCodec.from(type); + if (typeAwarecodec != null) { + return typeAwarecodec.serialize(input); + } else { + logger.debug("Codec for type \"" + type.getQName().getLocalName() + "\" is not implemented yet."); + return null; + } + } + } catch (ClassCastException e) { // TODO remove this catch when everyone use codecs + logger.error("ClassCastException was thrown when codec is invoked with parameter " + String.valueOf(input), e); + return input; + } + } + + } + + public static class IdentityrefCodecImpl implements IdentityrefCodec { + + @Override + public IdentityValuesDTO serialize(QName data) { + return new IdentityValuesDTO(data.getNamespace().toString(), data.getLocalName(), data.getPrefix()); + } + + @Override + public QName deserialize(IdentityValuesDTO data) { + IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0); + String namespace = valueWithNamespace.getNamespace(); + URI validNamespace = ControllerContext.getInstance().findNamespaceByModule(namespace); + if (validNamespace == null) { + validNamespace = URI.create(namespace); + } + return QName.create(validNamespace, null, valueWithNamespace.getValue()); + } + + } + + public static class LeafrefCodecImpl implements LeafrefCodec { + + @Override + public String serialize(Object data) { + return String.valueOf(data); + } + + @Override + public Object deserialize(String data) { + return data; + } + + } + +} 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 94a7756da6..4645a411c1 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 @@ -6,18 +6,20 @@ import java.util.Set import javax.ws.rs.core.Response import org.opendaylight.controller.md.sal.common.api.TransactionStatus import org.opendaylight.controller.sal.rest.api.RestconfService +import org.opendaylight.yangtools.yang.common.QName import org.opendaylight.yangtools.yang.data.api.CompositeNode import org.opendaylight.yangtools.yang.data.api.Node import org.opendaylight.yangtools.yang.data.impl.NodeFactory import org.opendaylight.yangtools.yang.model.api.ChoiceNode +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.data.impl.codec.TypeDefinitionAwareCodec -import org.opendaylight.yangtools.yang.model.api.TypeDefinition -import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode -import org.opendaylight.yangtools.yang.common.QName -import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode +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.IdentityrefTypeDefinition + import static javax.ws.rs.core.Response.Status.* class RestconfImpl implements RestconfService { @@ -148,7 +150,7 @@ class RestconfImpl implements RestconfService { } val moduleName = controllerContext.findModuleByNamespace(validQName.namespace); if (nodeBuilder.namespace === null || nodeBuilder.namespace == validQName.namespace || - nodeBuilder.namespace.path == moduleName) { + nodeBuilder.namespace.toString == moduleName) { nodeBuilder.qname = validQName } else { throw new ResponseException(BAD_REQUEST, @@ -164,12 +166,34 @@ class RestconfImpl implements RestconfService { findFirstSchemaByLocalName(child.localName, (schema as DataNodeContainer).childNodes), currentAugment) } + if(schema instanceof ListSchemaNode) { + val listKeys = (schema as ListSchemaNode).keyDefinition + for (listKey : listKeys) { + var foundKey = false + for (child : children) { + if (child.unwrap.nodeType.localName == listKey.localName) { + foundKey = true; + } + } + if (!foundKey) { + throw new ResponseException(BAD_REQUEST, + "Missing key \"" + listKey.localName + "\" of list \"" + schema.QName.localName + "\"") + } + } + } } else if (nodeBuilder instanceof SimpleNodeWrapper) { val simpleNode = (nodeBuilder as SimpleNodeWrapper) - val stringValue = simpleNode.value as String; - - val objectValue = TypeDefinitionAwareCodec.from(schema.typeDefinition)?.deserialize(stringValue); - simpleNode.setValue(objectValue) + val value = simpleNode.value + var inputValue = value; + + if (schema.typeDefinition instanceof IdentityrefTypeDefinition) { + if (value instanceof String) { + inputValue = new IdentityValuesDTO(validQName.namespace.toString, value as String, null) + } // else value is instance of ValuesDTO + } + + val outputValue = RestCodec.from(schema.typeDefinition)?.deserialize(inputValue); + simpleNode.setValue(outputValue) } else if (nodeBuilder instanceof EmptyNodeWrapper) { val emptyNodeBuilder = nodeBuilder as EmptyNodeWrapper if (schema instanceof LeafSchemaNode) { @@ -183,11 +207,19 @@ class RestconfImpl implements RestconfService { } private def dispatch TypeDefinition typeDefinition(LeafSchemaNode node) { - node.type + var baseType = node.type + while (baseType.baseType !== null) { + baseType = baseType.baseType; + } + baseType } private def dispatch TypeDefinition typeDefinition(LeafListSchemaNode node) { - node.type + var TypeDefinition baseType = node.type + while (baseType.baseType !== null) { + baseType = baseType.baseType; + } + baseType } private def DataSchemaNode findFirstSchemaByLocalName(String localName, Set schemas) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/SimpleNodeWrapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/SimpleNodeWrapper.java index 9f3c6e51e9..97f8102127 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/SimpleNodeWrapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/SimpleNodeWrapper.java @@ -13,7 +13,7 @@ import com.google.common.base.Preconditions; public final class SimpleNodeWrapper implements NodeWrapper>, SimpleNode { - private SimpleNode simpleNode; + private SimpleNode simpleNode; private String localName; private Object value; @@ -25,7 +25,7 @@ public final class SimpleNodeWrapper implements NodeWrapper>, Simp this.value = value; } - public SimpleNodeWrapper(URI namespace, String localName, String value) { + public SimpleNodeWrapper(URI namespace, String localName, Object value) { this(localName, value); this.namespace = namespace; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonBasicDataTypesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonBasicDataTypesTest.java new file mode 100644 index 0000000000..73d0c82521 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonBasicDataTypesTest.java @@ -0,0 +1,349 @@ +package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.io.StringReader; +import java.math.BigDecimal; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; + +import javax.ws.rs.WebApplicationException; +import javax.xml.bind.DatatypeConverter; + +import org.junit.Test; +import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.*; +import org.opendaylight.yangtools.yang.data.impl.NodeFactory; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; + +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; + +public class ToJsonBasicDataTypesTest { + + @Test + public void simpleYangDataTest() { + String jsonOutput = ""; + CompositeNode compositeNode = TestUtils.loadCompositeNode("/cnsn-to-json/simple-data-types/xml/data.xml"); + + Set modules = TestUtils.resolveModules("/cnsn-to-json/simple-data-types"); + assertEquals(1, modules.size()); + Module module = TestUtils.resolveModule(null, modules); + assertNotNull(module); + DataSchemaNode dataSchemaNode = TestUtils.resolveDataSchemaNode(module, null); + assertNotNull(dataSchemaNode); + + TestUtils.normalizeCompositeNode(compositeNode, modules, dataSchemaNode, "simple-data-types:cont"); + + try { + jsonOutput = TestUtils.writeCompNodeWithSchemaContextToJson(compositeNode, modules, dataSchemaNode); + } catch (WebApplicationException | IOException e) { + assertTrue(false); // shouldn't get here + } + + System.out.println(jsonOutput); + verifyJsonOutput(jsonOutput); + } + + private CompositeNode prepareData() { + MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont"), null, null, + ModifyAction.CREATE, null); + + List> childNodes = new ArrayList<>(); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint8Min"), cont, (byte) -128, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint8Max"), cont, (byte) 127, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint16Min"), cont, (short) -32768, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint16Max"), cont, (short) 32767, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint32Min"), cont, + (int) -2147483648, ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint32Max"), cont, (int) 2147483647, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint64Min"), cont, new Long( + "-9223372036854775807"), ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint64Max"), cont, new Long( + "9223372036854775807"), ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnuint8Max"), cont, (short) 255, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnuint16Max"), cont, (int) 65535, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnuint32Max"), cont, new Long( + "4294967295"), ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfstr"), cont, "lfstr", + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfstr1"), cont, "", + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfbool1"), cont, Boolean.TRUE, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfbool2"), cont, Boolean.FALSE, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfdecimal1"), cont, new BigDecimal( + "43.32"), ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfdecimal2"), cont, new BigDecimal( + "-0.43"), ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfdecimal3"), cont, new BigDecimal( + "43"), ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfdecimal4"), cont, new BigDecimal( + "43E3"), ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfdecimal6"), cont, new BigDecimal( + "33.12345"), ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfenum"), cont, "enum3", + ModifyAction.CREATE, null)); + + HashSet bits = new HashSet(); + bits.add("bit3"); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfbits"), cont, bits, + ModifyAction.CREATE, null)); + + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfbinary"), cont, DatatypeConverter + .parseBase64Binary("AAaacdabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"), + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfempty"), cont, null, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion1"), cont, (int) 324, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion2"), cont, new BigDecimal( + "33.3"), ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion3"), cont, "55", + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion4"), cont, Boolean.TRUE, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion5"), cont, "true", + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion6"), cont, "false", + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion7"), cont, null, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion8"), cont, "", + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion9"), cont, "", + ModifyAction.CREATE, null)); + + HashSet bits2 = new HashSet(); + bits2.add("bt1"); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion10"), cont, bits2, + ModifyAction.CREATE, null)); + + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion11"), cont, (short) 33, + ModifyAction.CREATE, null)); + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion12"), cont, Boolean.FALSE, + ModifyAction.CREATE, null)); + try { + childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("identityref1"), cont, new QName( + new URI("simple:data:types"), "iden"), ModifyAction.CREATE, null)); + } catch (URISyntaxException e) { + } + + cont.getChildren().addAll(childNodes); + + cont.init(); + + return cont; + } + + private void verifyJsonOutput(String jsonOutput) { + StringReader strReader = new StringReader(jsonOutput); + JsonReader jReader = new JsonReader(strReader); + + String exception = null; + try { + jsonReadCont(jReader); + } catch (IOException e) { + exception = e.getMessage(); + } + + assertNull("Error during reading Json output: " + exception, exception); + } + + private void jsonReadCont(JsonReader jReader) throws IOException { + jReader.beginObject(); + assertNotNull("cont1 is missing.", jReader.hasNext()); + + // Cont dataFromJson = new Cont(jReader.nextName()); + jReader.nextName(); + jsonReadContElements(jReader); + + assertFalse("cont shouldn't have other element.", jReader.hasNext()); + jReader.endObject(); + // return dataFromJson; + } + + private void jsonReadContElements(JsonReader jReader) throws IOException { + jReader.beginObject(); + List loadedLfs = new ArrayList<>(); + boolean exceptForDecimal5Raised = false; + boolean enumChecked = false; + boolean bitsChecked = false; + boolean lfdecimal6Checked = false; + boolean lfdecimal4Checked = false; + boolean lfdecimal3Checked = false; + boolean lfdecimal2Checked = false; + boolean lfdecimal1Checked = false; + boolean lfbool1Checked = false; + boolean lfbool2Checked = false; + boolean lfstrChecked = false; + boolean lfbinaryChecked = false; + // boolean lfref1Checked = false; + boolean lfemptyChecked = false; + boolean lfstr1Checked = false; + boolean lfidentityrefChecked = false; + + while (jReader.hasNext()) { + String keyName = jReader.nextName(); + JsonToken peek = null; + try { + peek = jReader.peek(); + } catch (IOException e) { + if (keyName.equals("lfdecimal5")) { + exceptForDecimal5Raised = true; + } else { + assertTrue("Key " + keyName + " has incorrect value for specifed type", false); + } + } + + if (keyName.startsWith("lfnint") || keyName.startsWith("lfnuint")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); + try { + jReader.nextLong(); + } catch (NumberFormatException e) { + assertTrue("Key " + keyName + " has incorrect value - " + e.getMessage(), false); + } + loadedLfs.add(keyName.substring(3)); + } else if (keyName.equals("identityref1")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("simple-data-types:iden", jReader.nextString()); + lfidentityrefChecked = true; + } else if (keyName.equals("lfstr")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("lfstr", jReader.nextString()); + lfstrChecked = true; + } else if (keyName.equals("lfstr1")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("", jReader.nextString()); + lfstr1Checked = true; + } else if (keyName.equals("lfbool1")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek); + assertEquals(true, jReader.nextBoolean()); + lfbool1Checked = true; + } else if (keyName.equals("lfbool2")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek); + assertEquals(false, jReader.nextBoolean()); + lfbool2Checked = true; + } else if (keyName.equals("lfbool3")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek); + assertEquals(false, jReader.nextBoolean()); + } else if (keyName.equals("lfdecimal1")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); + assertEquals(new Double(43.32), (Double) jReader.nextDouble()); + lfdecimal1Checked = true; + } else if (keyName.equals("lfdecimal2")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); + assertEquals(new Double(-0.43), (Double) jReader.nextDouble()); + lfdecimal2Checked = true; + } else if (keyName.equals("lfdecimal3")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); + assertEquals(new Double(43), (Double) jReader.nextDouble()); + lfdecimal3Checked = true; + } else if (keyName.equals("lfdecimal4")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); + assertEquals(new Double(43E3), (Double) jReader.nextDouble()); + lfdecimal4Checked = true; + } else if (keyName.equals("lfdecimal6")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); + assertEquals(new Double(33.12345), (Double) jReader.nextDouble()); + lfdecimal6Checked = true; + } else if (keyName.equals("lfenum")) { + assertEquals("enum3", jReader.nextString()); + enumChecked = true; + } else if (keyName.equals("lfbits")) { + assertEquals("bit3 bit2", jReader.nextString()); + bitsChecked = true; + } else if (keyName.equals("lfbinary")) { + assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", jReader.nextString()); + lfbinaryChecked = true; + } else if (keyName.equals("lfempty")) { + jReader.beginArray(); + jReader.nextNull(); + jReader.endArray(); + lfemptyChecked = true; + } else if (keyName.startsWith("lfunion")) { + checkLfUnion(jReader, keyName, peek); + } else { + assertTrue("Key " + keyName + " doesn't exists in yang file.", false); + } + + } + Collections.sort(loadedLfs); + String expectedLfsStr = "[int16Max, int16Min, int32Max, int32Min, int64Max, int64Min, int8Max, int8Min, uint16Max, uint32Max, uint8Max]"; + String actualLfsStr = loadedLfs.toString(); + assertEquals("Some leaves are missing", expectedLfsStr, actualLfsStr); + assertTrue("Enum wasn't checked", enumChecked); + assertTrue("Bits wasn't checked", bitsChecked); + assertTrue("Decimal1 wasn't checked", lfdecimal1Checked); + assertTrue("Decimal2 wasn't checked", lfdecimal2Checked); + assertTrue("Decimal3 wasn't checked", lfdecimal3Checked); + assertTrue("Decimal4 wasn't checked", lfdecimal4Checked); + assertTrue("Decimal5 wasn't checked", lfdecimal6Checked); + assertTrue("lfbool1 wasn't checked", lfbool1Checked); + assertTrue("lfbool2 wasn't checked", lfbool2Checked); + assertTrue("lfstr wasn't checked", lfstrChecked); + assertTrue("lfstr1 wasn't checked", lfstr1Checked); + assertTrue("lfbinary wasn't checked", lfbinaryChecked); + assertTrue("lfempty wasn't checked", lfemptyChecked); + assertTrue("lfidentityref wasn't checked", lfidentityrefChecked); + jReader.endObject(); + } + + private void checkLfUnion(JsonReader jReader, String keyName, JsonToken peek) throws IOException { + if (keyName.equals("lfunion1")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("324", jReader.nextString()); + } else if (keyName.equals("lfunion2")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("33.3", jReader.nextString()); + } else if (keyName.equals("lfunion3")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("55", jReader.nextString()); + } else if (keyName.equals("lfunion4")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("true", jReader.nextString()); + } else if (keyName.equals("lfunion5")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("true", jReader.nextString()); + } else if (keyName.equals("lfunion6")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("false", jReader.nextString()); + } else if (keyName.equals("lfunion7")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("", jReader.nextString()); + } else if (keyName.equals("lfunion8")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("", jReader.nextString()); + } else if (keyName.equals("lfunion9")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("", jReader.nextString()); + } else if (keyName.equals("lfunion10")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("bt1", jReader.nextString()); + } else if (keyName.equals("lfunion11")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("33", jReader.nextString()); + } else if (keyName.equals("lfunion12")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("false", jReader.nextString()); + } else if (keyName.equals("lfunion13")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("44", jReader.nextString()); + } else if (keyName.equals("lfunion14")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + assertEquals("21", jReader.nextString()); + } + } +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonBasicYangTypesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonBasicYangTypesTest.java similarity index 87% rename from opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonBasicYangTypesTest.java rename to opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonBasicYangTypesTest.java index e7a185a01d..b01d4104b2 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonBasicYangTypesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonBasicYangTypesTest.java @@ -1,20 +1,20 @@ -package org.opendaylight.controller.sal.restconf.impl.test; +package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; -import java.io.*; -import java.util.*; +import java.io.IOException; +import java.io.StringReader; +import java.util.Map; +import java.util.Set; import org.junit.Test; +import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.structures.*; import org.opendaylight.yangtools.yang.data.api.*; import org.opendaylight.yangtools.yang.data.impl.NodeFactory; -import com.google.gson.stream.*; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; public class ToJsonBasicYangTypesTest { @@ -25,7 +25,7 @@ public class ToJsonBasicYangTypesTest { @Test public void compositeNodeAndYangWithJsonReaderEmptyDataTest() { String jsonOutput = TestUtils.convertCompositeNodeDataAndYangToJson(prepareCompositeNodeWithEmpties(), - "/yang-to-json-conversion/simple-yang-types", "/yang-to-json-conversion/simple-yang-types/xml"); + "/cnsn-to-json/simple-yang-types", "/cnsn-to-json/simple-yang-types/xml", "simple-yang-types", "cont1"); verifyJsonOutputForEmpty(jsonOutput); } @@ -36,8 +36,8 @@ public class ToJsonBasicYangTypesTest { @Test public void xmlAndYangTypesWithJsonReaderTest() { String jsonOutput = TestUtils.convertCompositeNodeDataAndYangToJson( - TestUtils.loadCompositeNode("/yang-to-json-conversion/simple-yang-types/xml/data.xml"), - "/yang-to-json-conversion/simple-yang-types", "/yang-to-json-conversion/simple-yang-types/xml"); + TestUtils.loadCompositeNode("/cnsn-to-json/simple-yang-types/xml/data.xml"), + "/cnsn-to-json/simple-yang-types", "/cnsn-to-json/simple-yang-types/xml", "simple-yang-types", "cont1"); verifyJsonOutput(jsonOutput); } @@ -204,10 +204,12 @@ public class ToJsonBasicYangTypesTest { return lstItem; } - private String nextValue(JsonReader jReader) throws IOException { + private Object nextValue(JsonReader jReader) throws IOException { if (jReader.peek().equals(JsonToken.NULL)) { jReader.nextNull(); return null; + } else if (jReader.peek().equals(JsonToken.NUMBER)) { + return jReader.nextInt(); } else { return jReader.nextString(); } @@ -289,11 +291,11 @@ public class ToJsonBasicYangTypesTest { LstItem lst11_2 = null; LstItem lst11_3 = null; for (LstItem lstItem : lstItems) { - if (lstItem.getLfs().get("lf111").getValue().equals("1")) { + if (lstItem.getLfs().get("lf111").getValue().equals(1)) { lst11_1 = lstItem; - } else if (lstItem.getLfs().get("lf111").getValue().equals("2")) { + } else if (lstItem.getLfs().get("lf111").getValue().equals(2)) { lst11_2 = lstItem; - } else if (lstItem.getLfs().get("lf111").getValue().equals("3")) { + } else if (lstItem.getLfs().get("lf111").getValue().equals(3)) { lst11_3 = lstItem; } } @@ -307,8 +309,11 @@ public class ToJsonBasicYangTypesTest { assertEquals(1, lst11_1.getLfs().size()); assertEquals(1, lst11_1.getConts().size()); assertEquals(1, lst11_1.getLsts().size()); - assertEquals(lst11_1.getLsts().get("lst111"), new Lst("lst111").addLstItem(new LstItem().addLf("lf1111", "35")) - .addLstItem(new LstItem().addLf("lf1111", "34")).addLstItem(new LstItem()).addLstItem(new LstItem())); + assertEquals( + lst11_1.getLsts().get("lst111"), + new Lst("lst111").addLstItem(new LstItem().addLf("lf1111", (int) 35)) + .addLstItem(new LstItem().addLf("lf1111", (int) 34)).addLstItem(new LstItem()) + .addLstItem(new LstItem())); assertEquals(lst11_1.getConts().get("cont111"), new Cont("cont111")); // : lst11_1 @@ -327,9 +332,10 @@ public class ToJsonBasicYangTypesTest { assertEquals(1, lst11_2_cont111.getLsts().size()); assertTrue(lst11_2_cont111.getConts().isEmpty()); - assertEquals(new LfLst("lflst1111").addLf("1024").addLf("4096"), lst11_2_cont111.getLfLsts().get("lflst1111")); + assertEquals(new LfLst("lflst1111").addLf((int) 1024).addLf((int) 4096), + lst11_2_cont111.getLfLsts().get("lflst1111")); assertEquals( - new Lst("lst1111").addLstItem(new LstItem().addLf("lf1111B", "4")).addLstItem( + new Lst("lst1111").addLstItem(new LstItem().addLf("lf1111B", (int) 4)).addLstItem( new LstItem().addLf("lf1111A", "lf1111A str12")), lst11_2_cont111.getLsts().get("lst1111")); // :-cont111 assertEquals(lst11_2.getLsts().get("lst112"), new Lst("lst112").addLstItem(new LstItem())); @@ -369,9 +375,9 @@ public class ToJsonBasicYangTypesTest { assertNotNull(lflst12); assertEquals(3, lflst11.getLfs().size()); - assertTrue(lflst11.getLfs().contains(new Lf("55"))); - assertTrue(lflst11.getLfs().contains(new Lf("56"))); - assertTrue(lflst11.getLfs().contains(new Lf("57"))); + assertTrue(lflst11.getLfs().contains(new Lf(55))); + assertTrue(lflst11.getLfs().contains(new Lf(56))); + assertTrue(lflst11.getLfs().contains(new Lf(57))); assertEquals(3, lflst12.getLfs().size()); assertTrue(lflst12.getLfs().contains(new Lf("lflst12 str1"))); @@ -387,9 +393,9 @@ public class ToJsonBasicYangTypesTest { LstItem lst11_2 = null; for (LstItem lstItem : lst11.getLstItems()) { Lf lf = lstItem.getLfs().get("lf111"); - if (lf != null && lf.getValue().equals("140")) { + if (lf != null && lf.getValue().equals(140)) { lst11_1 = lstItem; - } else if (lf != null && lf.getValue().equals("141")) { + } else if (lf != null && lf.getValue().equals(141)) { lst11_2 = lstItem; } } @@ -414,15 +420,15 @@ public class ToJsonBasicYangTypesTest { // cont111 check assertEquals(new Lf("lf1111", "lf1111 str2"), lst11_2_cont.getLfs().get("lf1111")); - assertEquals(new LfLst("lflst1111").addLf(new Lf("2049")).addLf(new Lf("1025")).addLf(new Lf("4097")), - lst11_2_cont.getLfLsts().get("lflst1111")); + assertEquals(new LfLst("lflst1111").addLf(new Lf(2049)).addLf(new Lf(1025)).addLf(new Lf(4097)), lst11_2_cont + .getLfLsts().get("lflst1111")); assertNotNull(lst11_2_cont.getLsts().get("lst1111")); checkLst1111(lst11_2_cont.getLsts().get("lst1111").getLstItems(), new Lf("lf1111A", "lf1111A str21"), new Lf( - "lf1111B", "5"), new Lf("lf1111A", "lf1111A str22"), new Lf("lf1111B", "8")); + "lf1111B", 5), new Lf("lf1111A", "lf1111A str22"), new Lf("lf1111B", 8)); - checkLst11x(lst11_2.getLsts().get("lst111"), new LstItem().addLf(new Lf("lf1111", "55")), - new LstItem().addLf(new Lf("lf1111", "56"))); + checkLst11x(lst11_2.getLsts().get("lst111"), new LstItem().addLf(new Lf("lf1111", 55)), + new LstItem().addLf(new Lf("lf1111", 56))); checkLst11x(lst11_2.getLsts().get("lst112"), new LstItem().addLf(new Lf("lf1121", "lf1121 str22")), new LstItem().addLf(new Lf("lf1121", "lf1121 str21"))); } @@ -444,14 +450,14 @@ public class ToJsonBasicYangTypesTest { // cont111 check assertEquals(new Lf("lf1111", "lf1111 str"), lst11_1_cont.getLfs().get("lf1111")); - assertEquals(new LfLst("lflst1111").addLf(new Lf("2048")).addLf(new Lf("1024")).addLf(new Lf("4096")), - lst11_1_cont.getLfLsts().get("lflst1111")); + assertEquals(new LfLst("lflst1111").addLf(new Lf(2048)).addLf(new Lf(1024)).addLf(new Lf(4096)), lst11_1_cont + .getLfLsts().get("lflst1111")); assertNotNull(lst11_1_cont.getLsts().get("lst1111")); checkLst1111(lst11_1_cont.getLsts().get("lst1111").getLstItems(), new Lf("lf1111A", "lf1111A str11"), new Lf( - "lf1111B", "4"), new Lf("lf1111A", "lf1111A str12"), new Lf("lf1111B", "7")); + "lf1111B", 4), new Lf("lf1111A", "lf1111A str12"), new Lf("lf1111B", 7)); - checkLst11x(lst11_1.getLsts().get("lst111"), new LstItem().addLf(new Lf("lf1111", "65"))); + checkLst11x(lst11_1.getLsts().get("lst111"), new LstItem().addLf(new Lf("lf1111", 65))); checkLst11x(lst11_1.getLsts().get("lst112"), new LstItem().addLf(new Lf("lf1121", "lf1121 str11"))); } @@ -491,8 +497,8 @@ public class ToJsonBasicYangTypesTest { null, ModifyAction.CREATE, null); cont1.getChildren().add(lst11_1); - MutableSimpleNode lf111_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_1, "1", - ModifyAction.CREATE, null); + MutableSimpleNode lf111_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_1, + (short) 1, ModifyAction.CREATE, null); lst11_1.getChildren().add(lf111_1); // lst111_1_1 @@ -500,7 +506,7 @@ public class ToJsonBasicYangTypesTest { lst11_1, null, ModifyAction.CREATE, null); lst11_1.getChildren().add(lst111_1_1); MutableSimpleNode lf1111_1_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111"), - lst111_1_1, "34", ModifyAction.CREATE, null); + lst111_1_1, (int) 34, ModifyAction.CREATE, null); lst111_1_1.getChildren().add(lf1111_1_1); lst111_1_1.init(); // :lst111_1_1 @@ -510,7 +516,7 @@ public class ToJsonBasicYangTypesTest { lst11_1, null, ModifyAction.CREATE, null); lst11_1.getChildren().add(lst111_1_2); MutableSimpleNode lf1111_1_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111"), - lst111_1_2, "35", ModifyAction.CREATE, null); + lst111_1_2, (int) 35, ModifyAction.CREATE, null); lst111_1_2.getChildren().add(lf1111_1_2); lst111_1_2.init(); // :lst111_1_2 @@ -541,8 +547,8 @@ public class ToJsonBasicYangTypesTest { null, ModifyAction.CREATE, null); cont1.getChildren().add(lst11_2); - MutableSimpleNode lf111_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_2, "2", - ModifyAction.CREATE, null); + MutableSimpleNode lf111_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_2, + (short) 2, ModifyAction.CREATE, null); lst11_2.getChildren().add(lf111_2); // cont111_2 @@ -551,10 +557,10 @@ public class ToJsonBasicYangTypesTest { lst11_2.getChildren().add(cont111_2); MutableSimpleNode lflst1111_2_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lflst1111"), - cont111_2, "1024", ModifyAction.CREATE, null); + cont111_2, (int) 1024, ModifyAction.CREATE, null); cont111_2.getChildren().add(lflst1111_2_2); MutableSimpleNode lflst1111_2_3 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lflst1111"), - cont111_2, "4096", ModifyAction.CREATE, null); + cont111_2, (int) 4096, ModifyAction.CREATE, null); cont111_2.getChildren().add(lflst1111_2_3); // lst1111_2 @@ -562,16 +568,16 @@ public class ToJsonBasicYangTypesTest { cont111_2, null, ModifyAction.CREATE, null); cont111_2.getChildren().add(lst1111_2_1); MutableSimpleNode lf1111B_2_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111B"), - lst1111_2_1, "4", ModifyAction.CREATE, null); + lst1111_2_1, (short) 4, ModifyAction.CREATE, null); lst1111_2_1.getChildren().add(lf1111B_2_1); lst1111_2_1.init(); MutableCompositeNode lst1111_2_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst1111"), cont111_2, null, ModifyAction.CREATE, null); cont111_2.getChildren().add(lst1111_2_2); - MutableSimpleNode lf1111B_2_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111A"), + MutableSimpleNode lf1111A_2_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111A"), lst1111_2_2, "lf1111A str12", ModifyAction.CREATE, null); - lst1111_2_2.getChildren().add(lf1111B_2_2); + lst1111_2_2.getChildren().add(lf1111A_2_2); lst1111_2_2.init(); // :lst1111_2 @@ -591,8 +597,8 @@ public class ToJsonBasicYangTypesTest { null, ModifyAction.CREATE, null); cont1.getChildren().add(lst11_3); - MutableSimpleNode lf111_3 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_3, "3", - ModifyAction.CREATE, null); + MutableSimpleNode lf111_3 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_3, + (short) 3, ModifyAction.CREATE, null); lst11_3.getChildren().add(lf111_3); // cont111_3 diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonChoiceCaseTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonChoiceCaseTest.java new file mode 100644 index 0000000000..b745411bf4 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonChoiceCaseTest.java @@ -0,0 +1,123 @@ +package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import javax.ws.rs.WebApplicationException; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; +import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; + +public class ToJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader { + + @BeforeClass + public static void initialization() { + dataLoad("/cnsn-to-json/choice"); + } + + /** + * Test when some data are in one case node and other in another. This isn't + * correct. Next Json validator should return error because nodes has to be + * from one case below concrete choice. + * + */ + @Test + public void nodeSchemasOnVariousChoiceCasePathTest() { + testWrapper("/cnsn-to-json/choice/xml/data_various_path_err.xml", "choice-case-test:cont"); + } + + /** + * Test when some data are in one case node and other in another. + * Additionally data are loadef from various choices. This isn't correct. + * Next Json validator should return error because nodes has to be from one + * case below concrete choice. + * + */ + @Test + public void nodeSchemasOnVariousChoiceCasePathAndMultipleChoicesTest() { + testWrapper("/cnsn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml", + "choice-case-test:cont"); + } + + /** + * Test when second level data are red first, then first and at the end + * third level. Level represents pass through couple choice-case + */ + + @Test + public void nodeSchemasWithRandomOrderAccordingLevel() { + testWrapper("/cnsn-to-json/choice/xml/data_random_level.xml", "choice-case-test:cont"); + } + + /** + * Test when element from no first case is used + */ + @Test + public void nodeSchemasNotInFirstCase() { + testWrapper("/cnsn-to-json/choice/xml/data_no_first_case.xml", "choice-case-test:cont"); + } + + /** + * Test when element in case is list + */ + @Test + public void nodeSchemaAsList() { + testWrapper("/cnsn-to-json/choice/xml/data_list.xml", "choice-case-test:cont"); + } + + /** + * Test when element in case is container + */ + @Test + public void nodeSchemaAsContainer() { + testWrapper("/cnsn-to-json/choice/xml/data_container.xml", "choice-case-test:cont"); + } + + /** + * Test when element in case is leaflist + */ + @Test + public void nodeSchemaAsLeafList() { + testWrapper("/cnsn-to-json/choice/xml/data_leaflist.xml", "choice-case-test:cont"); + } + + /** + * + */ + @Test + public void nodeSchemasInMultipleChoicesTest() { + testWrapper("/cnsn-to-json/choice/xml/data_more_choices_same_level.xml", "choice-case-test:cont"); + } + + /** + * Test whether is possible to find data schema for node which is specified + * as dirrect subnode of choice (case without CASE key word) + */ + @Test + public void nodeSchemasInCaseNotDefinedWithCaseKeyword() { + testWrapper("/cnsn-to-json/choice/xml/data_case_defined_without_case.xml", "choice-case-test:cont"); + } + + /** + * Test of multiple use of choices + */ + @Test + public void nodeSchemasInThreeChoicesAtSameLevel() { + testWrapper("/cnsn-to-json/choice/xml/data_three_choices_same_level.xml", "choice-case-test:cont"); + } + + private void testWrapper(String xmlPath, String pathToSchemaNode) { + CompositeNode compNode = TestUtils.loadCompositeNode(xmlPath); + TestUtils.normalizeCompositeNode(compNode, modules, dataSchemaNode, pathToSchemaNode); + try { + TestUtils.writeCompNodeWithSchemaContextToJson(compNode, modules, dataSchemaNode); + } catch (WebApplicationException | IOException e) { + // shouldn't end here + assertTrue(false); + } + } +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonIdentityrefTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonIdentityrefTest.java similarity index 61% rename from opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonIdentityrefTest.java rename to opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonIdentityrefTest.java index ce1b4afaba..6d30559ccd 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonIdentityrefTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonIdentityrefTest.java @@ -1,14 +1,18 @@ -package org.opendaylight.controller.sal.restconf.impl.test; +package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; -import java.util.regex.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.ws.rs.WebApplicationException; -import org.junit.*; +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; +import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; import org.opendaylight.yangtools.yang.data.api.*; import org.opendaylight.yangtools.yang.data.impl.NodeFactory; @@ -16,15 +20,14 @@ public class ToJsonIdentityrefTest extends YangAndXmlAndDataSchemaLoader { @BeforeClass public static void initialization() { - dataLoad("/yang-to-json-conversion/identityref", 2, "identityref-module", "cont"); + dataLoad("/cnsn-to-json/identityref", 2, "identityref-module", "cont"); } @Test public void identityrefToJsonTest() { String json = null; try { - json = TestUtils - .writeCompNodeWithSchemaContextToJson(prepareCompositeNode(), null, modules, dataSchemaNode); + json = TestUtils.writeCompNodeWithSchemaContextToJson(prepareCompositeNode(), modules, dataSchemaNode); } catch (WebApplicationException | IOException e) { // shouldn't end here assertTrue(false); @@ -40,9 +43,14 @@ public class ToJsonIdentityrefTest extends YangAndXmlAndDataSchemaLoader { private CompositeNode prepareCompositeNode() { MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont"), null, null, ModifyAction.CREATE, null); - MutableSimpleNode lf1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1"), cont, + MutableCompositeNode cont1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont1"), cont, null, + ModifyAction.CREATE, null); + cont.getChildren().add(cont1); + + MutableSimpleNode lf1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1"), cont1, TestUtils.buildQName("name_test", "identityref:module", "2013-12-2"), ModifyAction.CREATE, null); - cont.getChildren().add(lf1); + cont1.getChildren().add(lf1); + cont1.init(); cont.init(); return cont; diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonLeafrefType.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonLeafrefType.java similarity index 75% rename from opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonLeafrefType.java rename to opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonLeafrefType.java index b4b8b4b3e3..1ac81a332f 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonLeafrefType.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonLeafrefType.java @@ -1,4 +1,4 @@ -package org.opendaylight.controller.sal.restconf.impl.test; +package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -9,21 +9,30 @@ import java.util.regex.Matcher; import javax.ws.rs.WebApplicationException; import org.junit.*; +import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; +import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; + +/** + * + * All tests are commented now because leafref isn't supported now + * + */ public class ToJsonLeafrefType extends YangAndXmlAndDataSchemaLoader { @BeforeClass public static void initialization() { - dataLoad("/yang-to-json-conversion/leafref", 2, "main-module", "cont"); + dataLoad("/cnsn-to-json/leafref", 2, "main-module", "cont"); } + @Ignore @Test public void leafrefAbsolutePathToExistingLeafTest() { String json = null; try { - json = TestUtils.writeCompNodeWithSchemaContextToJson(TestUtils - .loadCompositeNode("/yang-to-json-conversion/leafref/xml/data_absolut_ref_to_existing_leaf.xml"), - "/yang-to-json-conversion/leafref/xml", modules, dataSchemaNode); + json = TestUtils.writeCompNodeWithSchemaContextToJson( + TestUtils.loadCompositeNode("/cnsn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml"), + modules, dataSchemaNode); } catch (WebApplicationException | IOException e) { // shouldn't end here assertTrue(false); @@ -35,13 +44,14 @@ public class ToJsonLeafrefType extends YangAndXmlAndDataSchemaLoader { assertTrue(mtch.matches()); } + @Ignore @Test public void leafrefRelativePathToExistingLeafTest() { String json = null; try { - json = TestUtils.writeCompNodeWithSchemaContextToJson(TestUtils - .loadCompositeNode("/yang-to-json-conversion/leafref/xml/data_relativ_ref_to_existing_leaf.xml"), - "/yang-to-json-conversion/leafref/xml", modules, dataSchemaNode); + json = TestUtils.writeCompNodeWithSchemaContextToJson( + TestUtils.loadCompositeNode("/cnsn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml"), + modules, dataSchemaNode); } catch (WebApplicationException | IOException e) { // shouldn't end here assertTrue(false); @@ -57,13 +67,14 @@ public class ToJsonLeafrefType extends YangAndXmlAndDataSchemaLoader { * Tests case when reference to not existing element is present. In this * case value from single node is printed as string. */ + @Ignore @Test public void leafrefToNonExistingLeafTest() { String json = null; try { - json = TestUtils.writeCompNodeWithSchemaContextToJson(TestUtils - .loadCompositeNode("/yang-to-json-conversion/leafref/xml/data_ref_to_non_existing_leaf.xml"), - "/yang-to-json-conversion/leafref/xml", modules, dataSchemaNode); + json = TestUtils.writeCompNodeWithSchemaContextToJson( + TestUtils.loadCompositeNode("/cnsn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml"), + modules, dataSchemaNode); } catch (WebApplicationException | IOException e) { // shouldn't end here assertTrue(false); @@ -79,13 +90,14 @@ public class ToJsonLeafrefType extends YangAndXmlAndDataSchemaLoader { * Tests case when non leaf element is referenced. In this case value from * single node is printed as string. */ + @Ignore @Test public void leafrefToNotLeafTest() { String json = null; try { json = TestUtils.writeCompNodeWithSchemaContextToJson( - TestUtils.loadCompositeNode("/yang-to-json-conversion/leafref/xml/data_ref_to_not_leaf.xml"), - "/yang-to-json-conversion/leafref/xml", modules, dataSchemaNode); + TestUtils.loadCompositeNode("/cnsn-to-json/leafref/xml/data_ref_to_not_leaf.xml"), modules, + dataSchemaNode); } catch (WebApplicationException | IOException e) { // shouldn't end here assertTrue(false); @@ -101,6 +113,7 @@ public class ToJsonLeafrefType extends YangAndXmlAndDataSchemaLoader { /** * Tests case when leaflist element is refers to leaf. */ + @Ignore @Test public void leafrefFromLeafListToLeafTest() { String json = null; @@ -108,8 +121,8 @@ public class ToJsonLeafrefType extends YangAndXmlAndDataSchemaLoader { json = TestUtils .writeCompNodeWithSchemaContextToJson( TestUtils - .loadCompositeNode("/yang-to-json-conversion/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml"), - "/yang-to-json-conversion/leafref/xml", modules, dataSchemaNode); + .loadCompositeNode("/cnsn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml"), + modules, dataSchemaNode); } catch (WebApplicationException | IOException e) { // shouldn't end here assertTrue(false); @@ -126,13 +139,14 @@ public class ToJsonLeafrefType extends YangAndXmlAndDataSchemaLoader { /** * Tests case when leaflist element is refers to leaf. */ + @Ignore @Test public void leafrefFromLeafrefToLeafrefTest() { String json = null; try { - json = TestUtils.writeCompNodeWithSchemaContextToJson(TestUtils - .loadCompositeNode("/yang-to-json-conversion/leafref/xml/data_from_leafref_to_leafref.xml"), - "/yang-to-json-conversion/leafref/xml", modules, dataSchemaNode); + json = TestUtils.writeCompNodeWithSchemaContextToJson( + TestUtils.loadCompositeNode("/cnsn-to-json/leafref/xml/data_from_leafref_to_leafref.xml"), modules, + dataSchemaNode); } catch (WebApplicationException | IOException e) { // shouldn't end here assertTrue(false); 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/cnsn/to/json/test/ToJsonWithAugmentTest.java similarity index 66% rename from opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonWithAugmentTest.java rename to opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/ToJsonWithAugmentTest.java index 994916dea5..73bd178ff3 100644 --- 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/cnsn/to/json/test/ToJsonWithAugmentTest.java @@ -1,8 +1,10 @@ -package org.opendaylight.controller.sal.restconf.impl.test; +package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test; import static org.junit.Assert.assertTrue; import org.junit.Test; +import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; public class ToJsonWithAugmentTest { @@ -12,9 +14,10 @@ public class ToJsonWithAugmentTest { */ @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"); + + CompositeNode compositeNode = TestUtils.loadCompositeNode("/cnsn-to-json/augmentation/xml/data.xml"); + String jsonOutput = TestUtils.convertCompositeNodeDataAndYangToJson(compositeNode, + "/cnsn-to-json/augmentation", "/cnsn-to-json/augmentation/xml", "yang", "cont"); assertTrue(jsonOutput.contains("\"augment-leaf:lf2\": \"lf2\"")); assertTrue(jsonOutput.contains("\"augment-container:cont1\": {")); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java new file mode 100644 index 0000000000..d04337865a --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java @@ -0,0 +1,247 @@ +package org.opendaylight.controller.sal.restconf.impl.cnsn.to.xml.test; + +import static org.junit.Assert.*; + +import java.io.StringWriter; +import java.util.Set; + +import javax.activation.UnsupportedDataTypeException; +import javax.xml.transform.*; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.controller.sal.rest.impl.XmlMapper; +import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; +import org.opendaylight.yangtools.yang.data.api.*; +import org.opendaylight.yangtools.yang.data.impl.NodeFactory; +import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; +import org.opendaylight.yangtools.yang.model.api.*; +import org.w3c.dom.Document; + +/** + * + * CnSn = Composite node and Simple node data structure Class contains test of + * serializing simple nodes data values according data types from YANG schema to + * XML file + * + */ +public class CnSnToXmlTest { + + private static Set modules; + private static DataSchemaNode dataSchemaNode; + + @BeforeClass + public static void initialization() { + modules = TestUtils.resolveModules("/cnsn-to-xml/yang"); + assertEquals(2, modules.size()); + Module module = TestUtils.resolveModule("basic-module", modules); + assertNotNull(module); + dataSchemaNode = TestUtils.resolveDataSchemaNode(module, "cont"); + assertNotNull(dataSchemaNode); + + } + + @Test + public void snAsYangIdentityrefToXMLTest() { + serializeToXml(prepareIdentityrefData(), "x:iden"); + } + + @Test + public void snAsYangStringToXmlTest() { + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.STRING_DEFAULT_CODEC.deserialize("lfStr value"), + "lfStr"), "lfStr value"); + } + + @Test + public void snAsYangInt8ToXmlTest() { + String elName = "lfInt8"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.INT8_DEFAULT_CODEC.deserialize("14"), elName), "<" + + elName + ">14"); + } + + @Test + public void snAsYangInt16ToXmlTest() { + String elName = "lfInt16"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.INT16_DEFAULT_CODEC.deserialize("3000"), elName), + "<" + elName + ">3000"); + } + + @Test + public void snAsYangInt32ToXmlTest() { + String elName = "lfInt32"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.INT32_DEFAULT_CODEC.deserialize("201234"), elName), + "<" + elName + ">201234"); + } + + @Test + public void snAsYangInt64ToXmlTest() { + String elName = "lfInt64"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.INT64_DEFAULT_CODEC.deserialize("5123456789"), + elName), "<" + elName + ">5123456789"); + } + + @Test + public void snAsYangUint8ToXmlTest() { + String elName = "lfUint8"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.UINT8_DEFAULT_CODEC.deserialize("200"), elName), + "<" + elName + ">200"); + } + + @Test + public void snAsYangUint16ToXmlTest() { + String elName = "lfUint16"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.UINT16_DEFAULT_CODEC.deserialize("4000"), elName), + "<" + elName + ">4000"); + } + + @Test + public void snAsYangUint32ToXmlTest() { + String elName = "lfUint32"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.UINT32_DEFAULT_CODEC.deserialize("4123456789"), + elName), "<" + elName + ">4123456789"); + } + + @Test + public void snAsYangUint64ToXmlTest() { + String elName = "lfUint64"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.UINT64_DEFAULT_CODEC.deserialize("5123456789"), + elName), "<" + elName + ">5123456789"); + } + + @Test + public void snAsYangBinaryToXmlTest() { + String elName = "lfBinary"; + serializeToXml( + prepareCnStructForYangData( + TypeDefinitionAwareCodec.BINARY_DEFAULT_CODEC + .deserialize("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567"), + elName), "<" + elName + ">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567"); + } + + @Test + public void snAsYangBitsToXmlTest() { + String elName = "lfBits"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.BITS_DEFAULT_CODEC.deserialize("one two"), elName), + "<" + elName + ">one two", "<" + elName + ">two one"); + } + + @Test + public void snAsYangEnumerationToXmlTest() { + String elName = "lfEnumeration"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.ENUMERATION_DEFAULT_CODEC.deserialize("enum2"), + elName), "<" + elName + ">enum2"); + } + + @Test + public void snAsYangEmptyToXmlTest() { + String elName = "lfEmpty"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.EMPTY_DEFAULT_CODEC.deserialize(null), elName), "<" + + elName + "/>"); + } + + @Test + public void snAsYangBooleanToXmlTest() { + String elName = "lfBoolean"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.BOOLEAN_DEFAULT_CODEC.deserialize("str"), elName), + "<" + elName + ">false"); + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.BOOLEAN_DEFAULT_CODEC.deserialize("true"), elName), + "<" + elName + ">true"); + } + + @Test + public void snAsYangUnionToXmlTest() { + String elName = "lfUnion"; + String int8 = "15"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.UNION_DEFAULT_CODEC.deserialize(int8), elName), "<" + + elName + ">15"); + + String bits = "first second"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.UNION_DEFAULT_CODEC.deserialize(bits), elName), "<" + + elName + ">first second"); + + String bool = "str"; + serializeToXml( + prepareCnStructForYangData(TypeDefinitionAwareCodec.UNION_DEFAULT_CODEC.deserialize(bool), elName), "<" + + elName + ">str"); + } + + private void serializeToXml(CompositeNode compositeNode, String... xmlRepresentation) + throws TransformerFactoryConfigurationError { + XmlMapper xmlMapper = new XmlMapper(); + String xmlString = null; + if (dataSchemaNode instanceof DataNodeContainer) { + try { + Document doc = xmlMapper.write(compositeNode, (DataNodeContainer) dataSchemaNode); + DOMSource domSource = new DOMSource(doc); + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + transformer.transform(domSource, result); + xmlString = writer.toString(); + } catch (UnsupportedDataTypeException | TransformerException e) { + } + } + assertNotNull(xmlMapper); + boolean containSearchedStr = false; + String strRepresentation = ""; + for (String searchedStr : xmlRepresentation) { + if (xmlString.contains(searchedStr)) { + containSearchedStr = true; + break; + } + strRepresentation = strRepresentation + "[" + searchedStr + "]"; + } + assertTrue("At least one of specified strings " + strRepresentation + " wasn't found.", containSearchedStr); + + } + + private CompositeNode prepareIdentityrefData() { + MutableCompositeNode cont = NodeFactory.createMutableCompositeNode( + TestUtils.buildQName("cont", "basic:module", "2013-12-2"), null, null, ModifyAction.CREATE, null); + MutableCompositeNode cont1 = NodeFactory.createMutableCompositeNode( + TestUtils.buildQName("cont1", "basic:module", "2013-12-2"), cont, null, ModifyAction.CREATE, null); + cont.getChildren().add(cont1); + + MutableSimpleNode lf11 = NodeFactory.createMutableSimpleNode( + TestUtils.buildQName("lf11", "basic:module", "2013-12-2"), cont1, + TestUtils.buildQName("iden", "referenced:module", "2013-12-2"), ModifyAction.CREATE, null); + cont1.getChildren().add(lf11); + cont1.init(); + cont.init(); + + return cont; + } + + private CompositeNode prepareCnStructForYangData(Object data, String leafName) { + MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont"), null, null, + ModifyAction.CREATE, null); + + MutableSimpleNode lf1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName(leafName), cont, data, + ModifyAction.CREATE, null); + cont.getChildren().add(lf1); + cont.init(); + + return cont; + } + +} 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/json/to/cnsn/test/JsonToCnSnTest.java similarity index 73% rename from opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNodeTest.java rename to opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java index f55e92f9c9..b02ea9a3a2 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/json/to/cnsn/test/JsonToCnSnTest.java @@ -1,43 +1,41 @@ -package org.opendaylight.controller.sal.restconf.impl.test; +package org.opendaylight.controller.sal.restconf.impl.json.to.cnsn.test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.net.URISyntaxException; import java.util.List; +import java.util.Set; import javax.ws.rs.WebApplicationException; import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; -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.controller.sal.restconf.impl.test.TestUtils; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.*; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.JsonSyntaxException; -public class FromJsonToCompositeNodeTest { +public class JsonToCnSnTest { - private static final Logger LOG = LoggerFactory.getLogger(FromJsonToCompositeNodeTest.class); + private static final Logger LOG = LoggerFactory.getLogger(JsonToCnSnTest.class); @Test public void simpleListTest() { - simpleTest("/json-to-composite-node/simple-list.json", "/json-to-composite-node/simple-list-yang", "lst", - "simple:list:yang1", "simple-list-yang1"); + simpleTest("/json-to-cnsn/simple-list.json", "/json-to-cnsn/simple-list-yang", "lst", "simple:list:yang1", + "simple-list-yang1"); } @Test public void simpleContainerTest() { - simpleTest("/json-to-composite-node/simple-container.json", "/json-to-composite-node/simple-container-yang", - "cont", "simple:container:yang", "simple-container-yang"); + simpleTest("/json-to-cnsn/simple-container.json", "/json-to-cnsn/simple-container-yang", "cont", + "simple:container:yang", "simple-container-yang"); } /** @@ -45,8 +43,7 @@ public class FromJsonToCompositeNodeTest { */ @Test public void multipleItemsInLeafList() { - CompositeNode compositeNode = compositeContainerFromJson( - "/json-to-composite-node/multiple-leaflist-items.json", true); + CompositeNode compositeNode = compositeContainerFromJson("/json-to-cnsn/multiple-leaflist-items.json", true); assertNotNull(compositeNode); assertEquals(3, compositeNode.getChildren().size()); @@ -79,8 +76,7 @@ public class FromJsonToCompositeNodeTest { */ @Test public void multipleItemsInListTest() { - CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/multiple-items-in-list.json", - true); + CompositeNode compositeNode = compositeContainerFromJson("/json-to-cnsn/multiple-items-in-list.json", true); assertNotNull(compositeNode); assertEquals("lst", compositeNode.getNodeType().getLocalName()); @@ -90,7 +86,7 @@ public class FromJsonToCompositeNodeTest { @Test public void nullArrayToSimpleNodeWithNullValueTest() { - CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/array-with-null.json", true); + CompositeNode compositeNode = compositeContainerFromJson("/json-to-cnsn/array-with-null.json", true); assertNotNull(compositeNode); assertEquals("cont", compositeNode.getNodeType().getLocalName()); @@ -107,7 +103,7 @@ public class FromJsonToCompositeNodeTest { public void incorrectTopLevelElementsTest() { Throwable cause1 = null; try { - compositeContainerFromJson("/json-to-composite-node/wrong-top-level1.json", true); + compositeContainerFromJson("/json-to-cnsn/wrong-top-level1.json", true); } catch (WebApplicationException e) { cause1 = e; } @@ -121,7 +117,7 @@ public class FromJsonToCompositeNodeTest { Throwable cause2 = null; try { - compositeContainerFromJson("/json-to-composite-node/wrong-top-level2.json", true); + compositeContainerFromJson("/json-to-cnsn/wrong-top-level2.json", true); } catch (WebApplicationException e) { cause2 = e; } @@ -130,7 +126,7 @@ public class FromJsonToCompositeNodeTest { Throwable cause3 = null; try { - compositeContainerFromJson("/json-to-composite-node/wrong-top-level3.json", true); + compositeContainerFromJson("/json-to-cnsn/wrong-top-level3.json", true); } catch (WebApplicationException e) { cause3 = e; } @@ -149,7 +145,7 @@ public class FromJsonToCompositeNodeTest { */ @Test public void emptyDataReadTest() { - CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/empty-data.json", true); + CompositeNode compositeNode = compositeContainerFromJson("/json-to-cnsn/empty-data.json", true); assertNotNull(compositeNode); @@ -162,7 +158,7 @@ public class FromJsonToCompositeNodeTest { String reason = null; try { - compositeContainerFromJson("/json-to-composite-node/empty-data1.json", true); + compositeContainerFromJson("/json-to-cnsn/empty-data1.json", true); } catch (JsonSyntaxException e) { reason = e.getMessage(); } @@ -180,16 +176,14 @@ public class FromJsonToCompositeNodeTest { @Test public void notSupplyNamespaceIfAlreadySupplied() { - CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/simple-list.json"); + CompositeNode compositeNode = compositeContainerFromJson("/json-to-cnsn/simple-list.json"); assertNotNull(compositeNode); DataSchemaNode dataSchemaNode1 = null; DataSchemaNode dataSchemaNode2 = null; try { - dataSchemaNode1 = TestUtils.obtainSchemaFromYang("/json-to-composite-node/simple-list-yang", - "simple-list-yang1"); - dataSchemaNode2 = TestUtils.obtainSchemaFromYang("/json-to-composite-node/simple-list-yang", - "simple-list-yang2"); + dataSchemaNode1 = TestUtils.obtainSchemaFromYang("/json-to-cnsn/simple-list-yang", "simple-list-yang1"); + dataSchemaNode2 = TestUtils.obtainSchemaFromYang("/json-to-cnsn/simple-list-yang", "simple-list-yang2"); } catch (FileNotFoundException e) { LOG.error(e.getMessage()); assertTrue(false); @@ -214,6 +208,64 @@ public class FromJsonToCompositeNodeTest { } + @Test + public void jsonIdentityrefToCompositeNode() { + CompositeNode compositeNode = compositeContainerFromJson("/json-to-cnsn/identityref/json/data.json"); + assertNotNull(compositeNode); + + Set modules = TestUtils.resolveModules("/json-to-cnsn/identityref"); + assertEquals(2, modules.size()); + Module module = TestUtils.resolveModule("identityref-module", modules); + assertNotNull(module); + DataSchemaNode dataSchemaNode = TestUtils.resolveDataSchemaNode(module, null); + assertNotNull(dataSchemaNode); + + TestUtils.normalizeCompositeNode(compositeNode, modules, dataSchemaNode, "identityref-module:cont"); + + assertEquals("cont", compositeNode.getNodeType().getLocalName()); + + List> childs = compositeNode.getChildren(); + assertEquals(1, childs.size()); + Node nd = childs.iterator().next(); + assertTrue(nd instanceof CompositeNode); + assertEquals("cont1", nd.getNodeType().getLocalName()); + + childs = ((CompositeNode) nd).getChildren(); + assertEquals(4, childs.size()); + SimpleNode lf11 = null; + SimpleNode lf12 = null; + SimpleNode lf13 = null; + SimpleNode lf14 = null; + for (Node child : childs) { + assertTrue(child instanceof SimpleNode); + if (child.getNodeType().getLocalName().equals("lf11")) { + lf11 = (SimpleNode) child; + } else if (child.getNodeType().getLocalName().equals("lf12")) { + lf12 = (SimpleNode) child; + } else if (child.getNodeType().getLocalName().equals("lf13")) { + lf13 = (SimpleNode) child; + } else if (child.getNodeType().getLocalName().equals("lf14")) { + lf14 = (SimpleNode) child; + } + } + + assertTrue(lf11.getValue() instanceof QName); + assertEquals("iden", ((QName) lf11.getValue()).getLocalName()); + assertEquals("identity:module", ((QName) lf11.getValue()).getNamespace().toString()); + + assertTrue(lf12.getValue() instanceof QName); + assertEquals("iden_local", ((QName) lf12.getValue()).getLocalName()); + assertEquals("identityref:module", ((QName) lf12.getValue()).getNamespace().toString()); + + assertTrue(lf13.getValue() instanceof QName); + assertEquals("iden_local", ((QName) lf13.getValue()).getLocalName()); + assertEquals("identityref:module", ((QName) lf13.getValue()).getNamespace().toString()); + + assertTrue(lf14.getValue() instanceof QName); + assertEquals("iden_local", ((QName) lf14.getValue()).getLocalName()); + assertEquals("identity:module", ((QName) lf14.getValue()).getNamespace().toString()); + } + private void simpleTest(String jsonPath, String yangPath, String topLevelElementName, String namespace, String moduleName) { CompositeNode compositeNode = compositeContainerFromJson(jsonPath); @@ -325,7 +377,7 @@ public class FromJsonToCompositeNodeTest { throws WebApplicationException { JsonToCompositeNodeProvider jsonToCompositeNodeProvider = JsonToCompositeNodeProvider.INSTANCE; - InputStream jsonStream = FromJsonToCompositeNodeTest.class.getResourceAsStream(jsonPath); + InputStream jsonStream = JsonToCnSnTest.class.getResourceAsStream(jsonPath); try { CompositeNode compositeNode = jsonToCompositeNodeProvider .readFrom(null, null, null, null, null, jsonStream); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ReadConfAndOperDataTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ReadConfAndOperDataTest.java new file mode 100644 index 0000000000..cac77eb368 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ReadConfAndOperDataTest.java @@ -0,0 +1,118 @@ +package org.opendaylight.controller.sal.restconf.impl.test; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.FileNotFoundException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URLEncoder; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.LogRecord; + +import javax.ws.rs.core.Application; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.TestProperties; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +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.RestconfImpl; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +import com.google.common.base.Charsets; + +public class ReadConfAndOperDataTest extends JerseyTest { + + private static ControllerContext controllerContext; + private static BrokerFacade brokerFacade; + private static RestconfImpl restconfImpl; + private static final MediaType MEDIA_TYPE_DRAFT02 = new MediaType("application", "yang.data+xml"); + + @BeforeClass + public static void init() throws FileNotFoundException { + Set allModules = TestUtils.loadModules(RestconfImplTest.class.getResource("/full-versions/yangs") + .getPath()); + SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules); + controllerContext = ControllerContext.getInstance(); + controllerContext.setSchemas(schemaContext); + brokerFacade = mock(BrokerFacade.class); + restconfImpl = RestconfImpl.getInstance(); + restconfImpl.setBroker(brokerFacade); + restconfImpl.setControllerContext(controllerContext); + } + + @Before + public void logs() { + List loggedRecords = getLoggedRecords(); + for (LogRecord l : loggedRecords) { + System.out.println(l.getMessage()); + } + } + + @Test + public void testReadConfigurationData() throws UnsupportedEncodingException, FileNotFoundException { + + String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0"); + + CompositeNode loadedCompositeNode = TestUtils.loadCompositeNodeWithXmlTreeBuilder("/parts/ietf-interfaces_interfaces.xml"); + when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode); + + Response response = target(uri).request(MEDIA_TYPE_DRAFT02).get(); + assertEquals(200, response.getStatus()); + + uri = createUri("/config/", "ietf-interfaces:interfaces/interface/example"); + when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(null); + + response = target(uri).request(MEDIA_TYPE_DRAFT02).get(); + assertEquals(404, response.getStatus()); + } + + @Test + public void testReadOperationalData() throws UnsupportedEncodingException, FileNotFoundException { + String uri = createUri("/operational/", "ietf-interfaces:interfaces/interface/eth0"); + + CompositeNode loadedCompositeNode = TestUtils.loadCompositeNodeWithXmlTreeBuilder("/parts/ietf-interfaces_interfaces.xml"); + when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode); + + Response response = target(uri).request(MEDIA_TYPE_DRAFT02).get(); + assertEquals(200, response.getStatus()); + + uri = createUri("/config/", "ietf-interfaces:interfaces/interface/example"); + when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(null); + + response = target(uri).request(MEDIA_TYPE_DRAFT02).get(); + assertEquals(404, response.getStatus()); + } + + private String createUri(String prefix, String encodedPart) throws UnsupportedEncodingException { + return URI.create(prefix + URLEncoder.encode(encodedPart, Charsets.US_ASCII.name()).toString()).toASCIIString(); + } + + @Override + protected Application configure() { + enable(TestProperties.LOG_TRAFFIC); + enable(TestProperties.DUMP_ENTITY); + enable(TestProperties.RECORD_LOG_LEVEL); + set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue()); + + ResourceConfig resourceConfig = new ResourceConfig(); + resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE, + XmlToCompositeNodeProvider.INSTANCE); + return resourceConfig; + } +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java index c36de6e4ea..41cc0ddb51 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java @@ -1,7 +1,9 @@ package org.opendaylight.controller.sal.restconf.impl.test; -import static org.mockito.Mockito.*; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.io.FileNotFoundException; import java.io.InputStream; @@ -9,9 +11,7 @@ import java.util.Set; import org.junit.BeforeClass; import org.junit.Test; -import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; -import org.opendaylight.controller.sal.restconf.impl.ControllerContext; -import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; +import org.opendaylight.controller.sal.restconf.impl.*; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.Module; @@ -23,7 +23,8 @@ public class RestconfImplTest { @BeforeClass public static void init() throws FileNotFoundException { - Set allModules = TestUtils.loadModules(RestconfImplTest.class.getResource("/full-versions/yangs").getPath()); + Set allModules = TestUtils.loadModules(RestconfImplTest.class.getResource("/full-versions/yangs") + .getPath()); SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules); ControllerContext controllerContext = ControllerContext.getInstance(); controllerContext.setSchemas(schemaContext); @@ -33,7 +34,7 @@ public class RestconfImplTest { @Test public void testExample() throws FileNotFoundException { InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml"); - CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream); + CompositeNode loadedCompositeNode = TestUtils.loadCompositeNodeWithXmlTreeBuilder(xmlStream); BrokerFacade brokerFacade = mock(BrokerFacade.class); when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode); assertEquals(loadedCompositeNode, brokerFacade.readOperationalData(null)); 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 20dfb31dab..366d99dbcb 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 @@ -1,13 +1,13 @@ package org.opendaylight.controller.sal.restconf.impl.test; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.*; -import java.net.*; +import java.net.URI; +import java.net.URISyntaxException; import java.sql.Date; import java.util.*; import java.util.concurrent.Future; @@ -20,21 +20,23 @@ import javax.xml.transform.dom.DOMSource; 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.rest.impl.*; import org.opendaylight.controller.sal.restconf.impl.*; -import org.opendaylight.yangtools.yang.common.*; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.*; import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder; import org.opendaylight.yangtools.yang.model.api.*; import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser; import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; -import org.slf4j.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.SAXException; import com.google.common.base.Preconditions; -final class TestUtils { +public final class TestUtils { private static final Logger logger = LoggerFactory.getLogger(TestUtils.class); @@ -75,27 +77,7 @@ final class TestUtils { return result; } - public static CompositeNode loadCompositeNode(InputStream xmlInputStream) throws FileNotFoundException { - if (xmlInputStream == null) { - throw new IllegalArgumentException(); - } - Node dataTree; - try { - dataTree = XmlTreeBuilder.buildDataTree(xmlInputStream); - } catch (XMLStreamException e) { - logger.error("Error during building data tree from XML", e); - return null; - } - if (dataTree == null) { - logger.error("data tree is null"); - return null; - } - if (dataTree instanceof SimpleNode) { - logger.error("RPC XML was resolved as SimpleNode"); - return null; - } - return (CompositeNode) dataTree; - } + public static Document loadDocumentFrom(InputStream inputStream) { try { @@ -131,18 +113,17 @@ 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, + public static String convertCompositeNodeDataAndYangToJson(CompositeNode compositeNode, String yangPath, String outputPath, String searchedModuleName, String searchedDataSchemaName) { Set modules = resolveModules(yangPath); Module module = resolveModule(searchedModuleName, modules); DataSchemaNode dataSchemaNode = resolveDataSchemaNode(module, searchedDataSchemaName); + normalizeCompositeNode(compositeNode, modules, dataSchemaNode, searchedModuleName + ":" + + searchedDataSchemaName); + try { - return writeCompNodeWithSchemaContextToJson(compositeNode, outputPath, modules, dataSchemaNode); + return writeCompNodeWithSchemaContextToJson(compositeNode, modules, dataSchemaNode); } catch (WebApplicationException | IOException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -151,7 +132,16 @@ final class TestUtils { } - static Module resolveModule(String searchedModuleName, Set modules) { + public static void normalizeCompositeNode(CompositeNode compositeNode, Set modules, + DataSchemaNode dataSchemaNode, String schemaNodePath) { + RestconfImpl restconf = RestconfImpl.getInstance(); + ControllerContext.getInstance().setSchemas(TestUtils.loadSchemaContext(modules)); + + TestUtils.prepareMockForRestconfBeforeNormalization(modules, dataSchemaNode, restconf); + restconf.createConfigurationData(schemaNodePath, compositeNode); + } + + public static Module resolveModule(String searchedModuleName, Set modules) { assertNotNull("modules can't be null.", modules); Module module = null; if (searchedModuleName != null) { @@ -167,11 +157,11 @@ final class TestUtils { return module; } - static Set resolveModules(String yangPath) { + public static Set resolveModules(String yangPath) { Set modules = null; try { - modules = TestUtils.loadModules(ToJsonBasicDataTypesTest.class.getResource(yangPath).getPath()); + modules = TestUtils.loadModules(TestUtils.class.getResource(yangPath).getPath()); } catch (FileNotFoundException e) { e.printStackTrace(); } @@ -179,7 +169,7 @@ final class TestUtils { return modules; } - static DataSchemaNode resolveDataSchemaNode(Module module, String searchedDataSchemaName) { + public static DataSchemaNode resolveDataSchemaNode(Module module, String searchedDataSchemaName) { assertNotNull("Module is missing", module); DataSchemaNode dataSchemaNode = null; @@ -195,39 +185,33 @@ final class TestUtils { return dataSchemaNode; } - static String writeCompNodeWithSchemaContextToJson(CompositeNode compositeNode, String outputPath, - Set modules, DataSchemaNode dataSchemaNode) throws IOException, WebApplicationException { + public static String writeCompNodeWithSchemaContextToJson(CompositeNode compositeNode, Set modules, + DataSchemaNode dataSchemaNode) throws IOException, WebApplicationException { String jsonResult; assertNotNull(dataSchemaNode); assertNotNull("Composite node can't be null", compositeNode); ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream(); - ControllerContext contContext = ControllerContext.getInstance(); - contContext.setSchemas(loadSchemaContext(modules)); + ControllerContext.getInstance().setSchemas(loadSchemaContext(modules)); StructuredDataToJsonProvider structuredDataToJsonProvider = StructuredDataToJsonProvider.INSTANCE; structuredDataToJsonProvider.writeTo(new StructuredData(compositeNode, dataSchemaNode), null, null, null, null, null, byteArrayOS); jsonResult = byteArrayOS.toString(); - if (outputPath != null) { - try { - outputToFile(byteArrayOS, outputPath); - } catch (IOException e) { - System.out.println("Output file wasn't cloased sucessfuly."); - } - } return jsonResult; } - static CompositeNode loadCompositeNode(String xmlDataPath) { - InputStream xmlStream = ToJsonBasicDataTypesTest.class.getResourceAsStream(xmlDataPath); + public static CompositeNode loadCompositeNode(String xmlDataPath) { + InputStream xmlStream = TestUtils.class.getResourceAsStream(xmlDataPath); CompositeNode compositeNode = null; try { - compositeNode = TestUtils.loadCompositeNode(xmlStream); - } catch (FileNotFoundException e) { + XmlReader xmlReader = new XmlReader(); + compositeNode = xmlReader.read(xmlStream); + + } catch (UnsupportedFormatException | XMLStreamException e) { e.printStackTrace(); } return compositeNode; @@ -236,7 +220,7 @@ final class TestUtils { static void outputToFile(ByteArrayOutputStream outputStream, String outputDir) throws IOException { FileOutputStream fileOS = null; try { - String path = ToJsonBasicDataTypesTest.class.getResource(outputDir).getPath(); + String path = TestUtils.class.getResource(outputDir).getPath(); File outFile = new File(path + "/data.json"); fileOS = new FileOutputStream(outFile); try { @@ -285,7 +269,7 @@ final class TestUtils { } private static FileReader getFileReader(String path) { - String fullPath = ToJsonBasicDataTypesTest.class.getResource(path).getPath(); + String fullPath = TestUtils.class.getResource(path).getPath(); assertNotNull("Path to file can't be null.", fullPath); File file = new File(fullPath); assertNotNull("File can't be null", file); @@ -317,7 +301,7 @@ final class TestUtils { return strBuilder.toString(); } - static QName buildQName(String name, String uri, String date) { + public static QName buildQName(String name, String uri, String date) { try { URI u = new URI(uri); Date dt = null; @@ -330,11 +314,11 @@ final class TestUtils { } } - static QName buildQName(String name) { + public static QName buildQName(String name) { return buildQName(name, "", null); } - static void supplementNamespace(DataSchemaNode dataSchemaNode, CompositeNode compositeNode) { + public static void supplementNamespace(DataSchemaNode dataSchemaNode, CompositeNode compositeNode) { RestconfImpl restconf = RestconfImpl.getInstance(); InstanceIdWithSchemaNode instIdAndSchema = new InstanceIdWithSchemaNode(mock(InstanceIdentifier.class), @@ -358,13 +342,14 @@ final class TestUtils { restconf.createConfigurationData("something", compositeNode); } - static DataSchemaNode obtainSchemaFromYang(String yangFolder) throws FileNotFoundException { + public static DataSchemaNode obtainSchemaFromYang(String yangFolder) throws FileNotFoundException { return obtainSchemaFromYang(yangFolder, null); } - static DataSchemaNode obtainSchemaFromYang(String yangFolder, String moduleName) throws FileNotFoundException { + public static DataSchemaNode obtainSchemaFromYang(String yangFolder, String moduleName) + throws FileNotFoundException { Set modules = null; - modules = TestUtils.loadModules(ToJsonBasicDataTypesTest.class.getResource(yangFolder).getPath()); + modules = TestUtils.loadModules(TestUtils.class.getResource(yangFolder).getPath()); if (modules == null) { return null; @@ -403,7 +388,7 @@ final class TestUtils { } - static void addDummyNamespaceToAllNodes(NodeWrapper wrappedNode) throws URISyntaxException { + public static void addDummyNamespaceToAllNodes(NodeWrapper wrappedNode) throws URISyntaxException { wrappedNode.setNamespace(new URI("")); if (wrappedNode instanceof CompositeNodeWrapper) { for (NodeWrapper childNodeWrapper : ((CompositeNodeWrapper) wrappedNode).getValues()) { @@ -412,4 +397,56 @@ final class TestUtils { } } + public static void prepareMockForRestconfBeforeNormalization(Set modules, DataSchemaNode dataSchemaNode, + RestconfImpl restconf) { + ControllerContext instance = ControllerContext.getInstance(); + instance.setSchemas(TestUtils.loadSchemaContext(modules)); + restconf.setControllerContext(ControllerContext.getInstance()); + + BrokerFacade mockedBrokerFacade = mock(BrokerFacade.class); + when(mockedBrokerFacade.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))) + .thenReturn( + new DummyFuture.Builder().rpcResult( + new DummyRpcResult.Builder().result(TransactionStatus.COMMITED) + .build()).build()); + restconf.setBroker(mockedBrokerFacade); + } + + static CompositeNode loadCompositeNodeWithXmlTreeBuilder(String xmlDataPath) { + InputStream xmlStream = TestUtils.class.getResourceAsStream(xmlDataPath); + CompositeNode compositeNode = null; + try { + compositeNode = TestUtils.loadCompositeNodeWithXmlTreeBuilder(xmlStream); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + return compositeNode; + + + + } + + + public static CompositeNode loadCompositeNodeWithXmlTreeBuilder(InputStream xmlInputStream) throws FileNotFoundException { + if (xmlInputStream == null) { + throw new IllegalArgumentException(); + } + Node dataTree; + try { + dataTree = XmlTreeBuilder.buildDataTree(xmlInputStream); + } catch (XMLStreamException e) { + logger.error("Error during building data tree from XML", e); + return null; + } + if (dataTree == null) { + logger.error("data tree is null"); + return null; + } + if (dataTree instanceof SimpleNode) { + logger.error("RPC XML was resolved as SimpleNode"); + return null; + } + return (CompositeNode) dataTree; + } + } 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 deleted file mode 100644 index 69de9f86c1..0000000000 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonBasicDataTypesTest.java +++ /dev/null @@ -1,217 +0,0 @@ -package org.opendaylight.controller.sal.restconf.impl.test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.io.*; -import java.util.*; - -import org.junit.Test; - -import com.google.gson.stream.*; - -public class ToJsonBasicDataTypesTest { - - @Test - public void simpleYangDataTest() { - String jsonOutput; - 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"); - verifyJsonOutput(jsonOutput); - } - - private void verifyJsonOutput(String jsonOutput) { - StringReader strReader = new StringReader(jsonOutput); - JsonReader jReader = new JsonReader(strReader); - - String exception = null; - try { - jsonReadCont(jReader); - } catch (IOException e) { - exception = e.getMessage(); - } - - assertNull("Error during reading Json output: " + exception, exception); - } - - private void jsonReadCont(JsonReader jReader) throws IOException { - jReader.beginObject(); - assertNotNull("cont1 is missing.", jReader.hasNext()); - - // Cont dataFromJson = new Cont(jReader.nextName()); - jReader.nextName(); - jsonReadContElements(jReader); - - assertFalse("cont shouldn't have other element.", jReader.hasNext()); - jReader.endObject(); - // return dataFromJson; - } - - private void jsonReadContElements(JsonReader jReader) throws IOException { - jReader.beginObject(); - List loadedLfs = new ArrayList<>(); - boolean exceptForDecimal5Raised = false; - boolean enumChecked = false; - boolean bitsChecked = false; - boolean lfdecimal6Checked = false; - boolean lfdecimal4Checked = false; - boolean lfdecimal3Checked = false; - boolean lfdecimal2Checked = false; - boolean lfdecimal1Checked = false; - boolean lfbool1Checked = false; - boolean lfbool2Checked = false; - boolean lfstrChecked = false; - boolean lfbinaryChecked = false; - // boolean lfref1Checked = false; - boolean lfemptyChecked = false; - boolean lfstr1Checked = false; - - while (jReader.hasNext()) { - String keyName = jReader.nextName(); - JsonToken peek = null; - try { - peek = jReader.peek(); - } catch (IOException e) { - if (keyName.equals("lfdecimal5")) { - exceptForDecimal5Raised = true; - } else { - assertTrue("Key " + keyName + " has incorrect value for specifed type", false); - } - } - - if (keyName.startsWith("lfnint") || keyName.startsWith("lfnuint")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); - try { - jReader.nextLong(); - } catch (NumberFormatException e) { - assertTrue("Key " + keyName + " has incorrect value - " + e.getMessage(), false); - } - loadedLfs.add(keyName.substring(3)); - } else if (keyName.equals("lfstr")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("lfstr", jReader.nextString()); - lfstrChecked = true; - } else if (keyName.equals("lfstr1")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("", jReader.nextString()); - lfstr1Checked = true; - } else if (keyName.equals("lfbool1")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek); - assertEquals(true, jReader.nextBoolean()); - lfbool1Checked = true; - } else if (keyName.equals("lfbool2")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek); - assertEquals(false, jReader.nextBoolean()); - lfbool2Checked = true; - } else if (keyName.equals("lfbool3")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek); - assertEquals(false, jReader.nextBoolean()); - } else if (keyName.equals("lfdecimal1")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); - assertEquals(new Double(43.32), (Double) jReader.nextDouble()); - lfdecimal1Checked = true; - } else if (keyName.equals("lfdecimal2")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); - assertEquals(new Double(-0.43), (Double) jReader.nextDouble()); - lfdecimal2Checked = true; - } else if (keyName.equals("lfdecimal3")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); - assertEquals(new Double(43), (Double) jReader.nextDouble()); - lfdecimal3Checked = true; - } else if (keyName.equals("lfdecimal4")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); - assertEquals(new Double(43E3), (Double) jReader.nextDouble()); - lfdecimal4Checked = true; - } else if (keyName.equals("lfdecimal6")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); - assertEquals(new Double(33.12345), (Double) jReader.nextDouble()); - lfdecimal6Checked = true; - } else if (keyName.equals("lfenum")) { - assertEquals("enum3", jReader.nextString()); - enumChecked = true; - } else if (keyName.equals("lfbits")) { - assertEquals("bit3", jReader.nextString()); - bitsChecked = true; - } else if (keyName.equals("lfbinary")) { - assertEquals("AAaacdabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%%-#^", jReader.nextString()); - lfbinaryChecked = true; - } else if (keyName.equals("lfempty")) { - jReader.beginArray(); - jReader.nextNull(); - jReader.endArray(); - lfemptyChecked = true; - } else if (keyName.startsWith("lfunion")) { - checkLfUnion(jReader, keyName, peek); - } else { - assertTrue("Key " + keyName + " doesn't exists in yang file.", false); - } - - } - Collections.sort(loadedLfs); - String expectedLfsStr = "[int16Max, int16Min, int32Max, int32Min, int64Max, int64Min, int8Max, int8Min, uint16Max, uint32Max, uint8Max]"; - String actualLfsStr = loadedLfs.toString(); - assertEquals("Some leaves are missing", expectedLfsStr, actualLfsStr); - // assertTrue("For lfdecimal5 wasn't catch error",exceptForDecimal5Raised); - assertTrue("Enum wasn't checked", enumChecked); - assertTrue("Bits wasn't checked", bitsChecked); - assertTrue("Decimal1 wasn't checked", lfdecimal1Checked); - assertTrue("Decimal2 wasn't checked", lfdecimal2Checked); - assertTrue("Decimal3 wasn't checked", lfdecimal3Checked); - assertTrue("Decimal4 wasn't checked", lfdecimal4Checked); - assertTrue("Decimal5 wasn't checked", lfdecimal6Checked); - assertTrue("lfbool1 wasn't checked", lfbool1Checked); - assertTrue("lfbool2 wasn't checked", lfbool2Checked); - assertTrue("lfstr wasn't checked", lfstrChecked); - assertTrue("lfstr1 wasn't checked", lfstr1Checked); - assertTrue("lfbinary wasn't checked", lfbinaryChecked); - assertTrue("lfempty wasn't checked", lfemptyChecked); - // assertTrue("lfref1 wasn't checked", lfref1Checked); - - 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/ToJsonChoiceCaseTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonChoiceCaseTest.java deleted file mode 100644 index c5682cb5cc..0000000000 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonChoiceCaseTest.java +++ /dev/null @@ -1,181 +0,0 @@ -package org.opendaylight.controller.sal.restconf.impl.test; - -import static org.junit.Assert.assertTrue; - -import java.io.IOException; - -import javax.ws.rs.WebApplicationException; - -import org.junit.*; - -public class ToJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader { - - @BeforeClass - public static void initialization() { - dataLoad("/yang-to-json-conversion/choice"); - } - - /** - * Test when some data are in one case node and other in another. This isn't - * correct. Next Json validator should return error because nodes has to be - * from one case below concrete choice. - * - */ - @Test - public void nodeSchemasOnVariousChoiceCasePathTest() { - try { - TestUtils.writeCompNodeWithSchemaContextToJson( - TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_various_path_err.xml"), - "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode); - } catch (WebApplicationException | IOException e) { - // shouldn't end here - assertTrue(false); - } - } - - /** - * Test when some data are in one case node and other in another. - * Additionally data are loadef from various choices. This isn't correct. - * Next Json validator should return error because nodes has to be from one - * case below concrete choice. - * - */ - @Test - public void nodeSchemasOnVariousChoiceCasePathAndMultipleChoicesTest() { - try { - TestUtils - .writeCompNodeWithSchemaContextToJson( - TestUtils - .loadCompositeNode("/yang-to-json-conversion/choice/xml/data_more_choices_same_level_various_paths_err.xml"), - "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode); - } catch (WebApplicationException | IOException e) { - // shouldn't end here - assertTrue(false); - } - } - - /** - * Test when second level data are red first, then first and at the end - * third level. Level represents pass through couple choice-case - */ - - @Test - public void nodeSchemasWithRandomOrderAccordingLevel() { - try { - TestUtils.writeCompNodeWithSchemaContextToJson( - TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_random_level.xml"), - "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode); - - } catch (WebApplicationException | IOException e) { - // shouldn't end here - assertTrue(false); - } - } - - /** - * Test when element from no first case is used - */ - @Test - public void nodeSchemasNotInFirstCase() { - try { - TestUtils.writeCompNodeWithSchemaContextToJson( - TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_no_first_case.xml"), - "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode); - } catch (WebApplicationException | IOException e) { - // shouldn't end here - assertTrue(false); - } - } - - /** - * Test when element in case is list - */ - @Test - public void nodeSchemaAsList() { - try { - TestUtils.writeCompNodeWithSchemaContextToJson( - TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_list.xml"), - "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode); - } catch (WebApplicationException | IOException e) { - // shouldn't end here - assertTrue(false); - } - } - - /** - * Test when element in case is container - */ - @Test - public void nodeSchemaAsContainer() { - try { - TestUtils.writeCompNodeWithSchemaContextToJson( - TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_container.xml"), - "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode); - } catch (WebApplicationException | IOException e) { - // shouldn't end here - assertTrue(false); - } - } - - /** - * Test when element in case is leaflist - */ - @Test - public void nodeSchemaAsLeafList() { - try { - TestUtils.writeCompNodeWithSchemaContextToJson( - TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_leaflist.xml"), - "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode); - } catch (WebApplicationException | IOException e) { - // shouldn't end here - assertTrue(false); - } - } - - /** - * - */ - @Test - public void nodeSchemasInMultipleChoicesTest() { - try { - TestUtils - .writeCompNodeWithSchemaContextToJson(TestUtils - .loadCompositeNode("/yang-to-json-conversion/choice/xml/data_more_choices_same_level.xml"), - "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode); - } catch (WebApplicationException | IOException e) { - // shouldn't end here - assertTrue(false); - } - } - - /** - * Test whether is possible to find data schema for node which is specified - * as dirrect subnode of choice (case without CASE key word) - */ - @Test - public void nodeSchemasInCaseNotDefinedWithCaseKeyword() { - try { - TestUtils.writeCompNodeWithSchemaContextToJson(TestUtils - .loadCompositeNode("/yang-to-json-conversion/choice/xml/data_case_defined_without_case.xml"), - "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode); - } catch (WebApplicationException | IOException e) { - // shouldn't end here - assertTrue(false); - } - } - - /** - * Test of multiple use of choices - */ - @Test - public void nodeSchemasInThreeChoicesAtSameLevel() { - try { - TestUtils.writeCompNodeWithSchemaContextToJson(TestUtils - .loadCompositeNode("/yang-to-json-conversion/choice/xml/data_three_choices_same_level.xml"), - "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode); - } catch (WebApplicationException | IOException e) { - // shouldn't end here - assertTrue(false); - } - } -} 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 ec7dba67b9..4cea120d4d 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 @@ -11,8 +11,7 @@ import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.LogRecord; @@ -33,12 +32,10 @@ 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.RestconfImpl; +import org.opendaylight.controller.sal.restconf.impl.*; import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.*; +import org.opendaylight.yangtools.yang.data.impl.NodeFactory; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -77,14 +74,31 @@ public class XmlProvidersTest extends JerseyTest { public void testStructuredDataToXmlProvider() throws FileNotFoundException, UnsupportedEncodingException { String uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0"); - InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml"); - CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream); + CompositeNode loadedCompositeNode = prepareCompositeNodeWithIetfInterfacesInterfacesData(); when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode); Response response = target(uri).request(MEDIA_TYPE).get(); assertEquals(200, response.getStatus()); } + private CompositeNode prepareCompositeNodeWithIetfInterfacesInterfacesData() { + CompositeNode intface; + try { + intface = new CompositeNodeWrapper(new URI("interface"), "interface"); + List> childs = new ArrayList<>(); + + childs.add(new SimpleNodeWrapper(new URI("name"), "name", "eth0")); + childs.add(new SimpleNodeWrapper(new URI("type"), "type", "ethernetCsmacd")); + childs.add(new SimpleNodeWrapper(new URI("enabled"), "enabled", Boolean.FALSE)); + childs.add(new SimpleNodeWrapper(new URI("description"), "description", "some interface")); + intface.setValue(childs); + return intface; + } catch (URISyntaxException e) { + } + + return null; + } + @Test public void testBadFormatXmlToCompositeNodeProvider() throws UnsupportedEncodingException, URISyntaxException { String uri = createUri("/operations/", "ietf-interfaces:interfaces/interface/eth0"); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/Lf.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/Lf.java index a1e06c3cab..afd40d1c2b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/Lf.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/Lf.java @@ -1,21 +1,20 @@ package org.opendaylight.controller.sal.restconf.impl.test.structures; public class Lf extends YangElement { - private String value; + private Object value; private int numOfEqualItems = 0; - - public Lf(String name, String value) { + public Lf(String name, Object value) { super(name); this.value = value; } - public Lf(String value) { + public Lf(Object value) { super(""); this.value = value; } - public String getValue() { + public Object getValue() { return value; } @@ -43,11 +42,10 @@ public class Lf extends YangElement { } return true; } - + public void incNumOfEqualItems() { this.numOfEqualItems++; } - @Override public int hashCode() { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/LfLst.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/LfLst.java index 87fed95f6f..dda590944a 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/LfLst.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/LfLst.java @@ -1,6 +1,7 @@ package org.opendaylight.controller.sal.restconf.impl.test.structures; -import java.util.*; +import java.util.HashSet; +import java.util.Set; public class LfLst extends YangElement { Set lfs; @@ -10,11 +11,10 @@ public class LfLst extends YangElement { lfs = new HashSet<>(); } - public LfLst addLf(String value) { + public LfLst addLf(Object value) { return addLf(new Lf(value)); } - public LfLst addLf(Lf lf) { while (this.lfs.contains(lf)) { lf.incNumOfEqualItems(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/LstItem.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/LstItem.java index 9eb58b5344..10582de083 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/LstItem.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/LstItem.java @@ -1,6 +1,7 @@ package org.opendaylight.controller.sal.restconf.impl.test.structures; -import java.util.*; +import java.util.HashMap; +import java.util.Map; public class LstItem { String lstName; @@ -42,7 +43,7 @@ public class LstItem { return this; } - public LstItem addLf(String name, String value) { + public LstItem addLf(String name, Object value) { lfs.put(name, new Lf(name, value)); return this; } 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/xml/to/cnsn/test/XmlToCnSnTest.java similarity index 65% rename from opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNodeTest.java rename to opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java index a72bd60d30..50ab0857b7 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/xml/to/cnsn/test/XmlToCnSnTest.java @@ -1,23 +1,27 @@ -package org.opendaylight.controller.sal.restconf.impl.test; +package org.opendaylight.controller.sal.restconf.impl.xml.to.cnsn.test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.io.*; import java.net.URISyntaxException; +import java.util.List; +import java.util.Set; import javax.ws.rs.WebApplicationException; -import org.junit.*; +import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; -import org.opendaylight.controller.sal.restconf.impl.*; +import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; +import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.*; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.slf4j.*; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -public class FromXmlToCompositeNodeTest { - private static final Logger LOG = LoggerFactory.getLogger(FromXmlToCompositeNodeTest.class); +public class XmlToCnSnTest { + private static final Logger LOG = LoggerFactory.getLogger(XmlToCnSnTest.class); /** * top level element represents container. second level element is list with @@ -25,11 +29,11 @@ public class FromXmlToCompositeNodeTest { */ @Test public void testXmlDataContainer() { - CompositeNode compNode = compositeContainerFromXml("/xml-to-composite-node/data-container.xml", false); + CompositeNode compNode = compositeNodeFromXml("/xml-to-cnsn/data-container.xml", false); assertNotNull(compNode); DataSchemaNode dataSchemaNode = null; try { - dataSchemaNode = TestUtils.obtainSchemaFromYang("/xml-to-composite-node/data-container-yang"); + dataSchemaNode = TestUtils.obtainSchemaFromYang("/xml-to-cnsn/data-container-yang"); } catch (FileNotFoundException e) { LOG.error(e.getMessage()); assertTrue(false); @@ -73,13 +77,12 @@ public class FromXmlToCompositeNodeTest { @Test public void testXmlDataList() { - CompositeNode compNode = compositeContainerFromXml("/xml-to-composite-node/data-list.xml", false); + CompositeNode compNode = compositeNodeFromXml("/xml-to-cnsn/data-list.xml", false); assertNotNull(compNode); DataSchemaNode dataSchemaNode = null; try { - dataSchemaNode = TestUtils.obtainSchemaFromYang("/xml-to-composite-node/data-list-yang", - "data-container-yang"); + dataSchemaNode = TestUtils.obtainSchemaFromYang("/xml-to-cnsn/data-list-yang", "data-container-yang"); } catch (FileNotFoundException e) { LOG.error(e.getMessage()); } @@ -145,7 +148,7 @@ public class FromXmlToCompositeNodeTest { @Test public void testXmlEmptyData() { - CompositeNode compNode = compositeContainerFromXml("/xml-to-composite-node/empty-data.xml", true); + CompositeNode compNode = compositeNodeFromXml("/xml-to-cnsn/empty-data.xml", true); assertEquals("cont", compNode.getNodeType().getLocalName()); SimpleNode lf1 = null; SimpleNode lflst1_1 = null; @@ -189,6 +192,72 @@ public class FromXmlToCompositeNodeTest { } + /** + * Test case like this x:identity + */ + @Test + public void testIdentityrefNmspcInElement() { + testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-nmspc-in-element.xml", "/xml-to-cnsn/identityref", + "identityref-module", "cont", 2, "iden", "identity:module"); + } + + /** + * + * Test case like identity + */ + + @Test + public void testIdentityrefDefaultNmspcInElement() { + testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-default-nmspc-in-element.xml", + "/xml-to-cnsn/identityref/yang-augments", "general-module", "cont", 3, "iden", "identityref:module"); + } + + /** + * + * Test case like identity + */ + @Test + public void testIdentityrefDefaultNmspcInParrentElement() { + testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-default-nmspc-in-parrent-element.xml", + "/xml-to-cnsn/identityref", "identityref-module", "cont", 2, "iden", "identityref:module"); + } + + /** + * + * Test case like + * x:identity + */ + @Test + public void testIdentityrefNmspcInParrentElement() { + testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml", + "/xml-to-cnsn/identityref", "identityref-module", "cont", 2, "iden", "z:namespace"); + + } + + /** + * + * Test case like (without namespace in xml) x:identity + * + */ + @Test + public void testIdentityrefNoNmspcValueWithPrefix() { + testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-no-nmspc-value-with-prefix.xml", + "/xml-to-cnsn/identityref", "identityref-module", "cont", 2, "x:iden", "identityref:module"); + } + + /** + * + * Test case like (without namespace in xml) identity + * + */ + @Test + public void testIdentityrefNoNmspcValueWithoutPrefix() { + testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-no-nmspc-value-without-prefix.xml", + "/xml-to-cnsn/identityref", "identityref-module", "cont", 2, "iden", "identityref:module"); + } + private void verifyCommonPartAOfXml(CompositeNode compNode, String suf, String nameSpace) { SimpleNode lf1suf = null; SimpleNode lflst1suf_1 = null; @@ -254,10 +323,10 @@ public class FromXmlToCompositeNodeTest { assertEquals((short) 100, cont1_lf11.getValue()); } - private CompositeNode compositeContainerFromXml(String xmlPath, boolean dummyNamespaces) { + private CompositeNode compositeNodeFromXml(String xmlPath, boolean dummyNamespaces) { XmlToCompositeNodeProvider xmlToCompositeNodeProvider = XmlToCompositeNodeProvider.INSTANCE; try { - InputStream xmlStream = FromXmlToCompositeNodeTest.class.getResourceAsStream(xmlPath); + InputStream xmlStream = XmlToCnSnTest.class.getResourceAsStream(xmlPath); CompositeNode compositeNode = xmlToCompositeNodeProvider.readFrom(null, null, null, null, null, xmlStream); if (dummyNamespaces) { try { @@ -277,4 +346,47 @@ public class FromXmlToCompositeNodeTest { return null; } + private void testIdentityrefToCnSn(String xmlPath, String yangPath, String moduleName, String schemaName, + int moduleCount, String resultLocalName, String resultNamespace) { + CompositeNode compositeNode = compositeNodeFromXml(xmlPath, false); + assertNotNull(compositeNode); + + Set modules = TestUtils.resolveModules(yangPath); + assertEquals(moduleCount, modules.size()); + Module module = TestUtils.resolveModule(moduleName, modules); + assertNotNull(module); + DataSchemaNode dataSchemaNode = TestUtils.resolveDataSchemaNode(module, null); + assertNotNull(dataSchemaNode); + + TestUtils.normalizeCompositeNode(compositeNode, modules, dataSchemaNode, moduleName + ":" + schemaName); + + SimpleNode lf11 = getLf11(compositeNode); + assertTrue(lf11.getValue() instanceof QName); + QName qName = (QName) lf11.getValue(); + assertEquals(resultLocalName, qName.getLocalName()); + assertEquals(resultNamespace, qName.getNamespace().toString()); + + } + + private SimpleNode getLf11(CompositeNode compositeNode) { + assertEquals("cont", compositeNode.getNodeType().getLocalName()); + + List> childs = compositeNode.getChildren(); + assertEquals(1, childs.size()); + Node nd = childs.iterator().next(); + assertTrue(nd instanceof CompositeNode); + assertEquals("cont1", nd.getNodeType().getLocalName()); + + childs = ((CompositeNode) nd).getChildren(); + SimpleNode lf11 = null; + for (Node child : childs) { + assertTrue(child instanceof SimpleNode); + if (child.getNodeType().getLocalName().equals("lf11")) { + lf11 = (SimpleNode) child; + } + } + assertNotNull(lf11); + return lf11; + } + } 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/cnsn-to-json/augmentation/augment-container.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-container.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/augmentation/augment-container.yang 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/cnsn-to-json/augmentation/augment-leaf.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-leaf.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/augmentation/augment-leaf.yang 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/cnsn-to-json/augmentation/augment-leaflist.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-leaflist.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/augmentation/augment-leaflist.yang 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/cnsn-to-json/augmentation/augment-list.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/augment-list.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/augmentation/augment-list.yang 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/cnsn-to-json/augmentation/xml/data.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/xml/data.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/augmentation/xml/data.xml 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/cnsn-to-json/augmentation/yang.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/augmentation/yang.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/augmentation/yang.yang diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/choice.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/choice.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/choice.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/choice.yang diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_case_defined_without_case.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_case_defined_without_case.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_case_defined_without_case.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_case_defined_without_case.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_container.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_container.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_container.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_container.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_leaflist.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_leaflist.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_leaflist.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_leaflist.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_list.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_list.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_list.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_list.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_more_choices_same_level.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_more_choices_same_level.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_more_choices_same_level.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_more_choices_same_level.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_more_choices_same_level_various_paths_err.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_more_choices_same_level_various_paths_err.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_no_first_case.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_no_first_case.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_no_first_case.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_no_first_case.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_random_level.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_random_level.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_random_level.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_random_level.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_three_choices_same_level.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_three_choices_same_level.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_three_choices_same_level.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_three_choices_same_level.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_various_path_err.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_various_path_err.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_various_path_err.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_various_path_err.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/identityref/identity-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/identityref/identity-module.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/identityref/identity-module.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/identityref/identity-module.yang diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/identityref/identityref-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/identityref/identityref-module.yang new file mode 100644 index 0000000000..20f91b2bdd --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/identityref/identityref-module.yang @@ -0,0 +1,21 @@ +module identityref-module { + namespace "identityref:module"; + + prefix "iderefmod"; + + import identity-module {prefix idemo; revision-date 2013-12-2;} + + revision 2013-12-2 { + } + + container cont { + container cont1 { + leaf lf1 { + type identityref { + base "idemo:iden"; + } + } + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/cont-augment-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/cont-augment-module.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/cont-augment-module.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/cont-augment-module.yang diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/main-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/main-module.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/main-module.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/main-module.yang diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/xml/data_absolut_ref_to_existing_leaf.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/xml/data_absolut_ref_to_existing_leaf.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/xml/data_from_leafref_to_leafref.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_from_leafref_to_leafref.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/xml/data_from_leafref_to_leafref.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_from_leafref_to_leafref.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/xml/data_ref_to_non_existing_leaf.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/xml/data_ref_to_non_existing_leaf.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/xml/data_ref_to_not_leaf.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_ref_to_not_leaf.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/xml/data_ref_to_not_leaf.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_ref_to_not_leaf.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/xml/data_relativ_ref_to_existing_leaf.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/leafref/xml/data_relativ_ref_to_existing_leaf.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml 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/cnsn-to-json/simple-data-types/simple-data-types.yang similarity index 90% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/simple-data-types.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-data-types/simple-data-types.yang index 759b3ecf71..9bdea81579 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/cnsn-to-json/simple-data-types/simple-data-types.yang @@ -5,6 +5,9 @@ module simple-data-types { revision 2013-11-12 { } + identity iden { + } + typedef tpdfempty { type empty; } @@ -245,6 +248,26 @@ module simple-data-types { leaf lfunion12 { type tpdfun2; } + + leaf lfunion13 { + type tpdfbit; + } + + leaf lfunion14 { + type union { + type enumeration { + enum zero; + enum one; + } + type uint16; + } + } + + leaf identityref1 { + type identityref { + base iden; + } + } } 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/cnsn-to-json/simple-data-types/xml/data.xml similarity index 80% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/xml/data.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-data-types/xml/data.xml index 0d31e9037a..56872a337d 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/cnsn-to-json/simple-data-types/xml/data.xml @@ -21,9 +21,9 @@ 43E3 33.12345 enum3 - bit3 - AAaacdabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%%-#^ - + bit3 bit2 + ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz + 324 33.3 55 @@ -36,4 +36,8 @@ bt1 33 false + 44 + 21 + + x:iden \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/simple-yang-types.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/simple-yang-types.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/simple-yang-types.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/simple-yang-types.yang diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/awaited_output_data.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/awaited_output_data.json similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/awaited_output_data.json rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/awaited_output_data.json diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/awaited_output_empty_data.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/awaited_output_empty_data.json similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/awaited_output_empty_data.json rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/awaited_output_empty_data.json diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/data.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/data.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/data.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/empty_data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/empty_data.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-yang-types/xml/empty_data.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/empty_data.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/instance_identifier/aug-referenced-elements-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/instance_identifier/aug-referenced-elements-module.yang new file mode 100644 index 0000000000..1b861f5765 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/instance_identifier/aug-referenced-elements-module.yang @@ -0,0 +1,18 @@ +module aug-referenced-elements-module { + namespace "aug:referenced:elements:module"; + + prefix "augrefelmo"; + + import referenced-elements-module {prefix refelmo; revision-date 2013-12-3;} + + revision 2013-12-3 { + } + + augment "/refelmo:cont" { + leaf lf2 { + type boolean; + } + } + + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/instance_identifier/eferenced-elements-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/instance_identifier/eferenced-elements-module.yang new file mode 100644 index 0000000000..fd6e0fb27a --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/instance_identifier/eferenced-elements-module.yang @@ -0,0 +1,20 @@ +module referenced-elements-module { + namespace "referenced:elements:module"; + + prefix "refelmo"; + + revision 2013-12-3 { + } + + container cont { + leaf lf1 { + type string; + } + } + leaf-list lflst1 { + type uint32; + } + + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/instance_identifier/rinstance-identifier-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/instance_identifier/rinstance-identifier-module.yang new file mode 100644 index 0000000000..61ce8228b7 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/instance_identifier/rinstance-identifier-module.yang @@ -0,0 +1,16 @@ +module instance-identifier-module { + namespace "instance:identifier:module"; + + prefix "inidmod"; + + revision 2013-12-3 { + } + + container cont { + leaf lf1 { + type instance-identifier { + } + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/yang/basic-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/yang/basic-module.yang new file mode 100644 index 0000000000..7023c94f2f --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/yang/basic-module.yang @@ -0,0 +1,96 @@ +module basic-module { + namespace "basic:module"; + + prefix "basmod"; + + import referenced-module {prefix refmo; revision-date 2013-12-2;} + + revision 2013-12-2 { + } + + container cont { + container cont1 { + leaf lf11 { + type identityref { + base "refmo:iden"; + } + } + } + leaf lfStr { + type string; + } + leaf lfInt8 { + type int8; + } + + leaf lfInt16 { + type int16; + } + + leaf lfInt32 { + type int32; + } + + leaf lfInt64 { + type int64; + } + + leaf lfUint8 { + type uint8; + } + + leaf lfUint16 { + type uint16; + } + + leaf lfUint32 { + type uint32; + } + + leaf lfUint64 { + type uint64; + } + + leaf lfBinary { + type binary; + } + + leaf lfBits { + type bits { + bit one; + bit two; + bit three; + } + } + + leaf lfEnumeration { + type enumeration { + enum enum1; + enum enum2; + enum enum3; + } + } + + leaf lfEmpty { + type empty; + } + + leaf lfBoolean { + type boolean; + } + + leaf lfUnion { + type union { + type int8; + type string; + type bits { + bit first; + bit second; + } + type boolean; + } + } + + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/yang/referenced-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/yang/referenced-module.yang new file mode 100644 index 0000000000..9821b1e169 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/yang/referenced-module.yang @@ -0,0 +1,10 @@ +module referenced-module { + namespace "referenced:module"; + + prefix "refmod"; + revision 2013-12-2 { + } + + identity iden { + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/array-with-null.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/array-with-null.json similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/array-with-null.json rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/array-with-null.json diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/empty-data.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/empty-data.json similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/empty-data.json rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/empty-data.json diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/empty-data1.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/empty-data1.json similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/empty-data1.json rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/empty-data1.json diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/identityref/identity-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/identityref/identity-module.yang new file mode 100644 index 0000000000..30890bf9c3 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/identityref/identity-module.yang @@ -0,0 +1,10 @@ +module identity-module { + namespace "identity:module"; + + prefix "idemod"; + revision 2013-12-2 { + } + + identity iden { + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/identityref/identityref-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/identityref/identityref-module.yang new file mode 100644 index 0000000000..b90b533ce5 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/identityref/identityref-module.yang @@ -0,0 +1,39 @@ +module identityref-module { + namespace "identityref:module"; + + prefix "iderefmod"; + + import identity-module {prefix idemo; revision-date 2013-12-2;} + + revision 2013-12-2 { + } + + identity iden_local { + } + + container cont { + container cont1 { + leaf lf11 { + type identityref { + base "idemo:iden"; + } + } + leaf lf12 { + type identityref { + base "iden_local"; + } + } + leaf lf13 { + type identityref { + base "iden_local"; + } + } + leaf lf14 { + type identityref { + base "iden_local"; + } + } + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/identityref/json/data.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/identityref/json/data.json new file mode 100644 index 0000000000..320ee05eff --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/identityref/json/data.json @@ -0,0 +1,10 @@ +{ + "cont":{ + "cont1":{ + "lf11":"identity-module:iden", + "lf12":"iden_local", + "identityref-module:lf13":"iden_local", + "identityref-module:lf14":"identity-module:iden_local" + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/multiple-items-in-list.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/multiple-items-in-list.json similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/multiple-items-in-list.json rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/multiple-items-in-list.json diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/multiple-leaflist-items.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/multiple-leaflist-items.json similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/multiple-leaflist-items.json rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/multiple-leaflist-items.json diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container-yang/simple-container.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/simple-container-yang/simple-container.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container-yang/simple-container.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/simple-container-yang/simple-container.yang diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/simple-container.json similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container.json rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/simple-container.json diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list1.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/simple-list-yang/simple-list1.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list1.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/simple-list-yang/simple-list1.yang diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list2.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/simple-list-yang/simple-list2.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list2.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/simple-list-yang/simple-list2.yang diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/simple-list.json similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list.json rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/simple-list.json diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level1.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/wrong-top-level1.json similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level1.json rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/wrong-top-level1.json diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level2.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/wrong-top-level2.json similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level2.json rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/wrong-top-level2.json diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level3.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/wrong-top-level3.json similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/wrong-top-level3.json rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/wrong-top-level3.json 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-cnsn/data-container-yang/data-container.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container-yang/data-container.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-container-yang/data-container.yang 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-cnsn/data-container.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-container.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list-yang/data-container.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-list-yang/data-container.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list-yang/data-container.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-list-yang/data-container.yang diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list-yang/data-list.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-list-yang/data-list.yang similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list-yang/data-list.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-list-yang/data-list.yang diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-list.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-list.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-list.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-nmspc-in-attributes.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-nmspc-in-attributes.xml new file mode 100644 index 0000000000..848c02047f --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-nmspc-in-attributes.xml @@ -0,0 +1,5 @@ + + + c:iden + + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/empty-data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/empty-data.xml similarity index 100% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/empty-data.xml rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/empty-data.xml diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/identity-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/identity-module.yang new file mode 100644 index 0000000000..30890bf9c3 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/identity-module.yang @@ -0,0 +1,10 @@ +module identity-module { + namespace "identity:module"; + + prefix "idemod"; + revision 2013-12-2 { + } + + identity iden { + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/identityref-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/identityref-module.yang new file mode 100644 index 0000000000..a43d43990d --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/identityref-module.yang @@ -0,0 +1,21 @@ +module identityref-module { + namespace "identityref:module"; + + prefix "iderefmod"; + + import identity-module {prefix idemo; revision-date 2013-12-2;} + + revision 2013-12-2 { + } + + container cont { + container cont1 { + leaf lf11 { + type identityref { + base "idemo:iden"; + } + } + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-element.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-element.xml new file mode 100644 index 0000000000..aae2af36d1 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-element.xml @@ -0,0 +1,5 @@ + + + iden + + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-parrent-element.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-parrent-element.xml new file mode 100644 index 0000000000..621d2bc84c --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-parrent-element.xml @@ -0,0 +1,5 @@ + + + iden + + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-element.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-element.xml new file mode 100644 index 0000000000..76de72d9f4 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-element.xml @@ -0,0 +1,5 @@ + + + c:iden + + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml new file mode 100644 index 0000000000..497c35f2fc --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml @@ -0,0 +1,5 @@ + + + z:iden + + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-with-prefix.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-with-prefix.xml new file mode 100644 index 0000000000..925442fee1 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-with-prefix.xml @@ -0,0 +1,5 @@ + + + x:iden + + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-without-prefix.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-without-prefix.xml new file mode 100644 index 0000000000..5a86eb02a8 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-without-prefix.xml @@ -0,0 +1,5 @@ + + + iden + + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/yang-augments/general-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/yang-augments/general-module.yang new file mode 100644 index 0000000000..f1a1ea6260 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/yang-augments/general-module.yang @@ -0,0 +1,14 @@ +module general-module { + namespace "general:module"; + + prefix "genmod"; + revision 2013-12-12 { + } + + container cont { + container cont1 { + } + } + + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/yang-augments/identity-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/yang-augments/identity-module.yang new file mode 100644 index 0000000000..30890bf9c3 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/yang-augments/identity-module.yang @@ -0,0 +1,10 @@ +module identity-module { + namespace "identity:module"; + + prefix "idemod"; + revision 2013-12-2 { + } + + identity iden { + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/identityref/identityref-module.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/yang-augments/identityref-module.yang similarity index 69% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/identityref/identityref-module.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/yang-augments/identityref-module.yang index 273f5d77ee..719ac12226 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/identityref/identityref-module.yang +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/yang-augments/identityref-module.yang @@ -4,12 +4,13 @@ module identityref-module { prefix "iderefmod"; import identity-module {prefix idemo; revision-date 2013-12-2;} + import general-module {prefix gmo; revision-date 2013-12-12;} revision 2013-12-2 { } - container cont { - leaf lf1 { + augment "/gmo:cont/gmo:cont1" { + leaf lf11 { type identityref { base "idemo:iden"; } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java index 11cce72ef1..998d5d8faa 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java @@ -21,6 +21,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103. */ public class MultipartMessageManager { + /* + * Map for tx id and type of request, to keep track of all the request sent + * by Statistics Manager. Statistics Manager won't entertain any multipart + * response for which it didn't send the request. + */ + + private static Map txIdToRequestTypeMap = new ConcurrentHashMap(); + /* + * Map to keep track of the request tx id for flow table statistics request. + * Because flow table statistics multi part response do not contains the table id. + */ private static Map txIdTotableIdMap = new ConcurrentHashMap(); public MultipartMessageManager(){} @@ -34,4 +45,23 @@ public class MultipartMessageManager { public void setTxIdAndTableIdMapEntry(TransactionId id,Short tableId){ txIdTotableIdMap.put(id, tableId); } + + public void addTxIdToRequestTypeEntry (TransactionId id,StatsRequestType type){ + txIdToRequestTypeMap.put(id, type); + } + public StatsRequestType removeTxId(TransactionId id){ + return txIdToRequestTypeMap.remove(id); + } + + public enum StatsRequestType{ + ALL_FLOW, + AGGR_FLOW, + ALL_PORT, + ALL_FLOW_TABLE, + ALL_QUEUE_STATS, + ALL_GROUP, + ALL_METER, + GROUP_DESC, + METER_CONFIG + } } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatistics.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatistics.java index a659a40886..e84b437b53 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatistics.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatistics.java @@ -14,6 +14,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeatures; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats; @@ -22,6 +23,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeatures; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericQueueStatistics; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericTableStatistics; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics; @@ -54,6 +56,9 @@ public class NodeStatistics { private final Map flowTableAndStatisticsMap = new HashMap(); + private final Map> NodeConnectorAndQueuesStatsMap = + new HashMap>(); + public NodeStatistics(){ } @@ -128,4 +133,8 @@ public class NodeStatistics { public Map getNodeConnectorStats() { return nodeConnectorStats; } + + public Map> getNodeConnectorAndQueuesStatsMap() { + return NodeConnectorAndQueuesStatsMap; + } } 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 521de7e394..738c2cb9a8 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 @@ -5,12 +5,7 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -/* - * TODO: Handle multipart messages with following flag true - * OFPMPF_REPLY_MORE = 1 << 0 - * Better accumulate all the messages and update local cache - * and configurational data store - */ + package org.opendaylight.controller.md.statistics.manager; import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider; 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 b7b4082118..19cf0ed386 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 @@ -15,6 +15,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.eclipse.xtext.xbase.lib.Exceptions; +import org.opendaylight.controller.md.statistics.manager.MultipartMessageManager.StatsRequestType; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; @@ -43,9 +44,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111. import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllPortsStatisticsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllPortsStatisticsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService; import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.NotificationListener; @@ -71,6 +75,8 @@ public class StatisticsProvider implements AutoCloseable { private OpendaylightFlowTableStatisticsService flowTableStatsService; + private OpendaylightQueueStatisticsService queueStatsService; + private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager(); private Thread statisticsRequesterThread; @@ -129,6 +135,9 @@ public class StatisticsProvider implements AutoCloseable { flowTableStatsService = StatisticsManagerActivator.getProviderContext(). getRpcService(OpendaylightFlowTableStatisticsService.class); + queueStatsService = StatisticsManagerActivator.getProviderContext(). + getRpcService(OpendaylightQueueStatisticsService.class); + statisticsRequesterThread = new Thread( new Runnable(){ @Override @@ -177,9 +186,11 @@ public class StatisticsProvider implements AutoCloseable { sendAllFlowsStatsFromAllTablesRequest(targetNodeRef); - sendAllPortStatisticsRequest(targetNodeRef); + sendAllNodeConnectorsStatisticsRequest(targetNodeRef); sendAllFlowTablesStatisticsRequest(targetNodeRef); + + sendAllQueueStatsFromAllNodeConnector (targetNodeRef); }catch(Exception e){ spLogger.error("Exception occured while sending statistics requests : {}",e); @@ -191,13 +202,9 @@ public class StatisticsProvider implements AutoCloseable { try{ sendAllGroupStatisticsRequest(targetNodeRef); - Thread.sleep(1000); sendAllMeterStatisticsRequest(targetNodeRef); - Thread.sleep(1000); sendGroupDescriptionRequest(targetNodeRef); - Thread.sleep(1000); sendMeterConfigStatisticsRequest(targetNodeRef); - Thread.sleep(1000); }catch(Exception e){ spLogger.error("Exception occured while sending statistics requests : {}", e); } @@ -205,27 +212,32 @@ public class StatisticsProvider implements AutoCloseable { } } - private void sendAllFlowTablesStatisticsRequest(NodeRef targetNodeRef) { + private void sendAllFlowTablesStatisticsRequest(NodeRef targetNodeRef) throws InterruptedException, ExecutionException { final GetFlowTablesStatisticsInputBuilder input = new GetFlowTablesStatisticsInputBuilder(); input.setNode(targetNodeRef); - @SuppressWarnings("unused") Future> response = flowTableStatsService.getFlowTablesStatistics(input.build()); + + this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId() + , StatsRequestType.ALL_FLOW_TABLE); + } - private void sendAllFlowsStatsFromAllTablesRequest(NodeRef targetNode){ + private void sendAllFlowsStatsFromAllTablesRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input = new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder(); input.setNode(targetNode); - @SuppressWarnings("unused") Future> response = flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build()); + this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId() + , StatsRequestType.ALL_FLOW); + } private void sendAggregateFlowsStatsFromAllTablesRequest(NodeKey targetNodeKey) throws InterruptedException, ExecutionException{ @@ -245,6 +257,8 @@ public class StatisticsProvider implements AutoCloseable { flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build()); multipartMessageManager.setTxIdAndTableIdMapEntry(response.get().getResult().getTransactionId(), id); + this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId() + , StatsRequestType.AGGR_FLOW); } } @@ -261,63 +275,90 @@ public class StatisticsProvider implements AutoCloseable { // flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build());` // // multipartMessageManager.setTxIdAndTableIdMapEntry(response.get().getResult().getTransactionId(), (short)1); + } - private void sendAllPortStatisticsRequest(NodeRef targetNode){ + private void sendAllNodeConnectorsStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ - final GetAllPortsStatisticsInputBuilder input = new GetAllPortsStatisticsInputBuilder(); + final GetAllNodeConnectorsStatisticsInputBuilder input = new GetAllNodeConnectorsStatisticsInputBuilder(); input.setNode(targetNode); - @SuppressWarnings("unused") - Future> response = - portStatsService.getAllPortsStatistics(input.build()); + Future> response = + portStatsService.getAllNodeConnectorsStatistics(input.build()); + this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId() + , StatsRequestType.ALL_PORT); + } - private void sendAllGroupStatisticsRequest(NodeRef targetNode){ + private void sendAllGroupStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder(); input.setNode(targetNode); - @SuppressWarnings("unused") Future> response = groupStatsService.getAllGroupStatistics(input.build()); + + this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId() + , StatsRequestType.ALL_GROUP); + } - private void sendGroupDescriptionRequest(NodeRef targetNode){ + private void sendGroupDescriptionRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ final GetGroupDescriptionInputBuilder input = new GetGroupDescriptionInputBuilder(); input.setNode(targetNode); - @SuppressWarnings("unused") Future> response = groupStatsService.getGroupDescription(input.build()); + + this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId() + , StatsRequestType.GROUP_DESC); + } - private void sendAllMeterStatisticsRequest(NodeRef targetNode){ + private void sendAllMeterStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ GetAllMeterStatisticsInputBuilder input = new GetAllMeterStatisticsInputBuilder(); input.setNode(targetNode); - @SuppressWarnings("unused") Future> response = meterStatsService.getAllMeterStatistics(input.build()); + + this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId() + , StatsRequestType.ALL_METER);; + } - private void sendMeterConfigStatisticsRequest(NodeRef targetNode){ + private void sendMeterConfigStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ GetAllMeterConfigStatisticsInputBuilder input = new GetAllMeterConfigStatisticsInputBuilder(); input.setNode(targetNode); - @SuppressWarnings("unused") Future> response = meterStatsService.getAllMeterConfigStatistics(input.build()); + this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId() + , StatsRequestType.METER_CONFIG);; + } + private void sendAllQueueStatsFromAllNodeConnector(NodeRef targetNode) throws InterruptedException, ExecutionException { + GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder(); + + input.setNode(targetNode); + + Future> response = + queueStatsService.getAllQueuesStatisticsFromAllPorts(input.build()); + + this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId() + , StatsRequestType.ALL_QUEUE_STATS);; + + } + public ConcurrentMap getStatisticsCache() { return statisticsCache; } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java index a4a7e1e661..5c21fd6e10 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java @@ -13,7 +13,11 @@ import java.util.concurrent.ConcurrentMap; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; @@ -25,10 +29,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.A import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowTableStatisticsUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.NodeConnectorStatisticsUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList; @@ -40,6 +41,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev13 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated; @@ -53,6 +58,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111. import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; @@ -72,26 +82,44 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111. import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterConfigStatsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericQueueStatistics; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData; import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate; import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.PortStatisticsUpdate; import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Class implement statistics manager related listener interface and augment all the + * received statistics data to data stores. + * TODO: Need to add error message listener and clean-up the associated tx id + * if it exists in the tx-id cache. + * @author vishnoianil + * + */ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsListener, OpendaylightMeterStatisticsListener, OpendaylightFlowStatisticsListener, OpendaylightPortStatisticsListener, - OpendaylightFlowTableStatisticsListener{ + OpendaylightFlowTableStatisticsListener, + OpendaylightQueueStatisticsListener{ public final static Logger sucLogger = LoggerFactory.getLogger(StatisticsUpdateCommiter.class); @@ -110,7 +138,10 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList @Override public void onMeterConfigStatsUpdated(MeterConfigStatsUpdated notification) { - + //Check if response is for the request statistics-manager sent. + if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null) + return; + //Add statistics to local cache ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); if(!cache.containsKey(notification.getId())){ @@ -119,29 +150,40 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList cache.get(notification.getId()).setMeterConfigStats(notification.getMeterConfigStats()); //Publish data to configuration data store - DataModificationTransaction it = this.statisticsManager.startChange(); NodeKey key = new NodeKey(notification.getId()); - NodeRef ref = getNodeRef(key); - - final NodeBuilder nodeData = new NodeBuilder(); - nodeData.setKey(key); - NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder(); - MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder(); - stats.setMeterConfigStats(notification.getMeterConfigStats()); - meterConfig.setMeterConfigStats(stats.build()); - - //Update augmented data - nodeData.addAugmentation(NodeMeterConfigStats.class, meterConfig.build()); + List eterConfigStatsList = notification.getMeterConfigStats(); - InstanceIdentifier refValue = ref.getValue(); - it.putOperationalData(refValue, nodeData.build()); - it.commit(); + for(MeterConfigStats meterConfigStats : eterConfigStatsList){ + DataModificationTransaction it = this.statisticsManager.startChange(); + MeterBuilder meterBuilder = new MeterBuilder(); + MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId()); + meterBuilder.setKey(meterKey); + + InstanceIdentifier meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key) + .augmentation(FlowCapableNode.class) + .child(Meter.class,meterKey).toInstance(); + + NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder(); + MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder(); + stats.fieldsFrom(meterConfigStats); + meterConfig.setMeterConfigStats(stats.build()); + + //Update augmented data + meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build()); + it.putOperationalData(meterRef, meterBuilder.build()); + it.commit(); + } } @Override public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) { + + //Check if response is for the request statistics-manager sent. + if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null) + return; + //Add statistics to local cache ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); if(!cache.containsKey(notification.getId())){ @@ -149,30 +191,41 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList } cache.get(notification.getId()).setMeterStatistics(notification.getMeterStats()); - //Publish data to configuration data store - DataModificationTransaction it = this.statisticsManager.startChange(); NodeKey key = new NodeKey(notification.getId()); - NodeRef ref = getNodeRef(key); - - final NodeBuilder nodeData = new NodeBuilder(); - nodeData.setKey(key); - NodeMeterStatisticsBuilder meterStats= new NodeMeterStatisticsBuilder(); - MeterStatisticsBuilder stats = new MeterStatisticsBuilder(); - stats.setMeterStats(notification.getMeterStats()); - meterStats.setMeterStatistics(stats.build()); + List meterStatsList = notification.getMeterStats(); - //Update augmented data - nodeData.addAugmentation(NodeMeterStatistics.class, meterStats.build()); - - InstanceIdentifier refValue = ref.getValue(); - it.putOperationalData(refValue, nodeData.build()); - it.commit(); + for(MeterStats meterStats : meterStatsList){ + //Publish data to configuration data store + DataModificationTransaction it = this.statisticsManager.startChange(); + MeterBuilder meterBuilder = new MeterBuilder(); + MeterKey meterKey = new MeterKey(meterStats.getMeterId()); + meterBuilder.setKey(meterKey); + + InstanceIdentifier meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key) + .augmentation(FlowCapableNode.class) + .child(Meter.class,meterKey).toInstance(); + + NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder(); + MeterStatisticsBuilder stats = new MeterStatisticsBuilder(); + stats.fieldsFrom(meterStats); + meterStatsBuilder.setMeterStatistics(stats.build()); + + //Update augmented data + meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build()); + it.putOperationalData(meterRef, meterBuilder.build()); + it.commit(); + } } @Override public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) { + + //Check if response is for the request statistics-manager sent. + if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null) + return; + //Add statistics to local cache ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); if(!cache.containsKey(notification.getId())){ @@ -181,30 +234,40 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList cache.get(notification.getId()).setGroupDescStats(notification.getGroupDescStats()); //Publish data to configuration data store - DataModificationTransaction it = this.statisticsManager.startChange(); NodeKey key = new NodeKey(notification.getId()); - NodeRef ref = getNodeRef(key); - - final NodeBuilder nodeData = new NodeBuilder(); - nodeData.setKey(key); - - NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder(); - GroupDescBuilder stats = new GroupDescBuilder(); - stats.setGroupDescStats(notification.getGroupDescStats()); - groupDesc.setGroupDesc(stats.build()); - - //Update augmented data - nodeData.addAugmentation(NodeGroupDescStats.class, groupDesc.build()); + List groupDescStatsList = notification.getGroupDescStats(); - InstanceIdentifier refValue = ref.getValue(); - it.putOperationalData(refValue, nodeData.build()); - it.commit(); + for(GroupDescStats groupDescStats : groupDescStatsList){ + DataModificationTransaction it = this.statisticsManager.startChange(); + + GroupBuilder groupBuilder = new GroupBuilder(); + GroupKey groupKey = new GroupKey(groupDescStats.getGroupId()); + groupBuilder.setKey(groupKey); + + InstanceIdentifier groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key) + .augmentation(FlowCapableNode.class) + .child(Group.class,groupKey).toInstance(); + + NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder(); + GroupDescBuilder stats = new GroupDescBuilder(); + stats.fieldsFrom(groupDescStats); + groupDesc.setGroupDesc(stats.build()); + + //Update augmented data + groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build()); + it.putOperationalData(groupRef, groupBuilder.build()); + it.commit(); + } } @Override public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) { + //Check if response is for the request statistics-manager sent. + if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null) + return; + //Add statistics to local cache ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); if(!cache.containsKey(notification.getId())){ @@ -213,33 +276,30 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList cache.get(notification.getId()).setGroupStatistics(notification.getGroupStats()); //Publish data to configuration data store - - DataModificationTransaction it = this.statisticsManager.startChange(); NodeKey key = new NodeKey(notification.getId()); - NodeRef ref = getNodeRef(key); - - final NodeBuilder nodeData = new NodeBuilder(); - nodeData.setKey(key); - - NodeGroupStatisticsBuilder groupStats = new NodeGroupStatisticsBuilder(); - GroupStatisticsBuilder stats = new GroupStatisticsBuilder(); - stats.setGroupStats(notification.getGroupStats()); - groupStats.setGroupStatistics(stats.build()); - - //Update augmented data - nodeData.addAugmentation(NodeGroupStatistics.class, groupStats.build()); + List groupStatsList = notification.getGroupStats(); - InstanceIdentifier refValue = ref.getValue(); - it.putOperationalData(refValue, nodeData.build()); - it.commit(); - -// for (GroupStats groupstat : notification.getGroupStats()) { -// -// GroupStatsKey groupKey = groupstat.getKey(); -// InstanceIdentifier id = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).augmentation(NodeGroupStatistics.class).child(GroupStatistics.class).child(GroupStats.class,groupKey).toInstance(); -// it.putOperationalData(id, groupstat); -// it.commit(); -// } + for(GroupStats groupStats : groupStatsList){ + DataModificationTransaction it = this.statisticsManager.startChange(); + + GroupBuilder groupBuilder = new GroupBuilder(); + GroupKey groupKey = new GroupKey(groupStats.getGroupId()); + groupBuilder.setKey(groupKey); + + InstanceIdentifier groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key) + .augmentation(FlowCapableNode.class) + .child(Group.class,groupKey).toInstance(); + + NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder(); + GroupStatisticsBuilder stats = new GroupStatisticsBuilder(); + stats.fieldsFrom(groupStats); + groupStatisticsBuilder.setGroupStatistics(stats.build()); + + //Update augmented data + groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build()); + it.putOperationalData(groupRef, groupBuilder.build()); + it.commit(); + } } @Override @@ -315,8 +375,13 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList @Override public void onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) { + + //Check if response is for the request statistics-manager sent. + if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null) + return; + NodeKey key = new NodeKey(notification.getId()); - sucLogger.info("Received flow stats update : {}",notification.toString()); + sucLogger.debug("Received flow stats update : {}",notification.toString()); for(FlowAndStatisticsMapList map: notification.getFlowAndStatisticsMapList()){ short tableId = map.getTableId(); @@ -395,8 +460,8 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList flowStatisticsData.setFlowStatistics(flowStatistics.build()); - sucLogger.info("Flow : {}",flowRule.toString()); - sucLogger.info("Statistics to augment : {}",flowStatistics.build().toString()); + sucLogger.debug("Flow : {}",flowRule.toString()); + sucLogger.debug("Statistics to augment : {}",flowStatistics.build().toString()); InstanceIdentifier tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); @@ -437,7 +502,7 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList .child(Flow.class,newFlowKey).toInstance(); flowBuilder.setKey(newFlowKey); flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - sucLogger.debug("Flow was no present in data store, augmenting statistics as an unaccounted flow"); + sucLogger.info("Flow was no present in data store, augmenting statistics as an unaccounted flow"); it.putOperationalData(flowRef, flowBuilder.build()); it.commit(); } @@ -446,6 +511,10 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList @Override public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) { + //Check if response is for the request statistics-manager sent. + if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null) + return; + NodeKey key = new NodeKey(notification.getId()); sucLogger.debug("Received aggregate flow statistics update : {}",notification.toString()); @@ -482,9 +551,13 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList } @Override - public void onPortStatisticsUpdate(PortStatisticsUpdate notification) { + public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) { + //Check if response is for the request statistics-manager sent. + if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null) + return; + NodeKey key = new NodeKey(notification.getId()); - sucLogger.info("Received port stats update : {}",notification.toString()); + sucLogger.debug("Received port stats update : {}",notification.toString()); //Add statistics to local cache ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); @@ -537,6 +610,10 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList @Override public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) { + //Check if response is for the request statistics-manager sent. + if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null) + return; + NodeKey key = new NodeKey(notification.getId()); sucLogger.debug("Received flow table statistics update : {}",notification.toString()); @@ -574,24 +651,63 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList } @Override - public void onFlowStatisticsUpdated(FlowStatisticsUpdated notification) { - // TODO Auto-generated method stub - //TODO: Depricated, will clean it up once sal-compatibility is fixed. - //Sal-Compatibility code usage this notification event. + public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) { - } + //Check if response is for the request statistics-manager sent. + if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null) + return; - @Override - public void onFlowTableStatisticsUpdated(FlowTableStatisticsUpdated notification) { - // TODO Auto-generated method stub - //TODO: Need to implement it yet + NodeKey key = new NodeKey(notification.getId()); + sucLogger.debug("Received queue stats update : {}",notification.toString()); - } + //Add statistics to local cache + ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); + if(!cache.containsKey(notification.getId())){ + cache.put(notification.getId(), new NodeStatistics()); + } + + List queuesStats = notification.getQueueIdAndStatisticsMap(); + for(QueueIdAndStatisticsMap swQueueStats : queuesStats){ + + if(!cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap().containsKey(swQueueStats.getNodeConnectorId())){ + cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap().put(swQueueStats.getNodeConnectorId(), new HashMap()); + } + + FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder(); + + FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder(); + + queueStatisticsBuilder.fieldsFrom(swQueueStats); + + queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build()); + + cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap() + .get(swQueueStats.getNodeConnectorId()) + .put(swQueueStats.getQueueId(), queueStatisticsBuilder.build()); + + + DataModificationTransaction it = this.statisticsManager.startChange(); - @Override - public void onNodeConnectorStatisticsUpdated(NodeConnectorStatisticsUpdated notification) { - // TODO Auto-generated method stub - //TODO: Need to implement it yet + InstanceIdentifier queueRef + = InstanceIdentifier.builder(Nodes.class) + .child(Node.class, key) + .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId())) + .augmentation(FlowCapableNodeConnector.class) + .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance(); + + QueueBuilder queueBuilder = new QueueBuilder(); + queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, queueStatisticsDataBuilder.build()); + queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId())); + + sucLogger.info("Augmenting queue statistics {} of queue {} to port {}" + ,queueStatisticsDataBuilder.build().toString(), + swQueueStats.getQueueId(), + swQueueStats.getNodeConnectorId()); + + it.putOperationalData(queueRef, queueBuilder.build()); + it.commit(); + + } } @@ -669,4 +785,5 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList } return true; } + } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImpl.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImpl.java index ed8f02bf56..7cd43bd79a 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImpl.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImpl.java @@ -8,12 +8,16 @@ package org.opendaylight.controller.netconf.confignetconfconnector.osgi; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; +import com.google.common.base.Preconditions; import com.google.common.collect.Sets; +import org.opendaylight.controller.config.api.LookupRegistry; import org.opendaylight.controller.config.util.ConfigRegistryJMXClient; import org.opendaylight.controller.config.yang.store.api.YangStoreException; import org.opendaylight.controller.config.yang.store.api.YangStoreService; import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot; +import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry; import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider; import org.opendaylight.controller.netconf.confignetconfconnector.util.Util; import org.opendaylight.controller.netconf.mapping.api.Capability; @@ -42,12 +46,38 @@ public class NetconfOperationServiceImpl implements NetconfOperationService { String netconfSessionIdForReporting) throws YangStoreException { yangStoreSnapshot = yangStoreService.getYangStoreSnapshot(); + checkConsistencyBetweenYangStoreAndConfig(jmxClient, yangStoreSnapshot); + transactionProvider = new TransactionProvider(jmxClient, netconfSessionIdForReporting); operationProvider = new NetconfOperationProvider(yangStoreSnapshot, jmxClient, transactionProvider, netconfSessionIdForReporting); capabilities = setupCapabilities(yangStoreSnapshot); } + + @VisibleForTesting + static void checkConsistencyBetweenYangStoreAndConfig(LookupRegistry jmxClient, YangStoreSnapshot yangStoreSnapshot) { + Set missingModulesFromConfig = Sets.newHashSet(); + + Set modulesSeenByConfig = jmxClient.getAvailableModuleFactoryQNames(); + Map> moduleMXBeanEntryMap = yangStoreSnapshot.getModuleMXBeanEntryMap(); + + for (Map moduleNameToMBE : moduleMXBeanEntryMap.values()) { + for (ModuleMXBeanEntry moduleMXBeanEntry : moduleNameToMBE.values()) { + String moduleSeenByYangStore = moduleMXBeanEntry.getYangModuleQName().toString(); + if(modulesSeenByConfig.contains(moduleSeenByYangStore) == false) + missingModulesFromConfig.add(moduleSeenByYangStore); + } + } + + Preconditions + .checkState( + missingModulesFromConfig.isEmpty(), + "There are inconsistencies between configuration subsystem and yangstore in terms of discovered yang modules, yang modules missing from config subsystem but present in yangstore: %s, %sAll modules present in config: %s", + missingModulesFromConfig, System.lineSeparator(), modulesSeenByConfig); + + } + @Override public void close() { yangStoreSnapshot.close(); diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImplTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImplTest.java new file mode 100644 index 0000000000..53e14ba5fb --- /dev/null +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImplTest.java @@ -0,0 +1,124 @@ +/* + * 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.netconf.confignetconfconnector.osgi; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.junit.Assert; +import org.junit.Test; +import org.junit.matchers.JUnitMatchers; +import org.opendaylight.controller.config.api.LookupRegistry; +import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot; +import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry; +import org.opendaylight.yangtools.yang.common.QName; + +import java.net.URI; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +public class NetconfOperationServiceImplTest { + + private static final Date date1970_01_01; + + static { + try { + date1970_01_01 = new SimpleDateFormat("yyyy-MM-dd").parse("1970-01-01"); + } catch (ParseException e) { + throw new IllegalStateException(e); + } + } + + @Test + public void testCheckConsistencyBetweenYangStoreAndConfig_ok() throws Exception { + NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig( + mockJmxClient("qname1", "qname2"), + mockYangStoreSnapshot("qname2", "qname1")); + } + + @Test + public void testCheckConsistencyBetweenYangStoreAndConfig_ok2() throws Exception { + NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig( + mockJmxClient("qname1", "qname2", "qname4", "qname5"), + mockYangStoreSnapshot("qname2", "qname1")); + } + + @Test + public void testCheckConsistencyBetweenYangStoreAndConfig_ok3() throws Exception { + NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig( + mockJmxClient(), + mockYangStoreSnapshot()); + } + + @Test + public void testCheckConsistencyBetweenYangStoreAndConfig_yangStoreMore() throws Exception { + try { + NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(mockJmxClient("qname1"), + mockYangStoreSnapshot("qname2", "qname1")); + fail("An exception of type " + IllegalArgumentException.class + " was expected"); + } catch (IllegalStateException e) { + String message = e.getMessage(); + Assert.assertThat( + message, + JUnitMatchers + .containsString("missing from config subsystem but present in yangstore: [(namespace?revision=1970-01-01)qname2]")); + Assert.assertThat( + message, + JUnitMatchers + .containsString("All modules present in config: [(namespace?revision=1970-01-01)qname1]")); + } + } + + private YangStoreSnapshot mockYangStoreSnapshot(String... qnames) { + YangStoreSnapshot mock = mock(YangStoreSnapshot.class); + + Map> map = Maps.newHashMap(); + + Map innerMap = Maps.newHashMap(); + + int i = 1; + for (String qname : qnames) { + innerMap.put(Integer.toString(i++), mockMBeanEntry(qname)); + } + + map.put("1", innerMap); + + doReturn(map).when(mock).getModuleMXBeanEntryMap(); + + return mock; + } + + private ModuleMXBeanEntry mockMBeanEntry(String qname) { + ModuleMXBeanEntry mock = mock(ModuleMXBeanEntry.class); + QName q = getQName(qname); + doReturn(q).when(mock).getYangModuleQName(); + return mock; + } + + private QName getQName(String qname) { + return new QName(URI.create("namespace"), date1970_01_01, qname); + } + + private LookupRegistry mockJmxClient(String... visibleQNames) { + LookupRegistry mock = mock(LookupRegistry.class); + Set qnames = Sets.newHashSet(); + for (String visibleQName : visibleQNames) { + QName q = getQName(visibleQName); + qnames.add(q.toString()); + } + doReturn(qnames).when(mock).getAvailableModuleFactoryQNames(); + return mock; + } +} diff --git a/opendaylight/netconf/config-persister-impl/pom.xml b/opendaylight/netconf/config-persister-impl/pom.xml index 7fc2b584b8..20bd386063 100644 --- a/opendaylight/netconf/config-persister-impl/pom.xml +++ b/opendaylight/netconf/config-persister-impl/pom.xml @@ -90,6 +90,7 @@ org.opendaylight.controller.netconf.client, org.opendaylight.controller.netconf.util.osgi, org.opendaylight.controller.netconf.util.xml, + org.opendaylight.controller.netconf.util.messages, io.netty.channel, io.netty.channel.nio, io.netty.util.concurrent, diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java index 89c2703285..0b623baaa4 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java @@ -8,14 +8,24 @@ package org.opendaylight.controller.netconf.persist.impl; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; import io.netty.channel.EventLoopGroup; + +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.annotation.concurrent.Immutable; + import org.opendaylight.controller.config.api.ConflictingVersionException; import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.client.NetconfClient; import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; +import org.opendaylight.controller.netconf.util.messages.NetconfMessageAdditionalHeader; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -25,14 +35,8 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; -import javax.annotation.concurrent.Immutable; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetSocketAddress; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; @Immutable public class ConfigPusher { @@ -127,10 +131,14 @@ public class ConfigPusher { long deadline = pollingStart + timeout; + String additionalHeader = NetconfMessageAdditionalHeader.toString("unknown", address.getAddress().getHostAddress(), + Integer.toString(address.getPort()), "tcp", Optional.of("persister")); + Set latestCapabilities = new HashSet<>(); while (System.currentTimeMillis() < deadline) { attempt++; - NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup); + NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, + nettyThreadgroup, additionalHeader); NetconfClient netconfClient; try { netconfClient = new NetconfClient(this.toString(), address, delay, netconfClientDispatcher); diff --git a/opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml b/opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml new file mode 100644 index 0000000000..aebaaebc1a --- /dev/null +++ b/opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml @@ -0,0 +1,101 @@ + + + netconf-subsystem + org.opendaylight.controller + 0.2.3-SNAPSHOT + + 4.0.0 + ietf-netconf-monitoring-extension + ${project.artifactId} + bundle + + + + org.opendaylight.controller + ietf-netconf-monitoring + + + com.google.guava + guava + + + org.slf4j + slf4j-api + + + + + + + + org.opendaylight.yangtools + yang-maven-plugin + ${yangtools.version} + + + + generate-sources + + + src/main/yang + + + + org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl + + + target/generated-sources/monitoring + + + + true + + + + + + org.opendaylight.yangtools + maven-sal-api-gen-plugin + ${yangtools.binding.version} + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.7 + + + generate-sources + + add-source + + + + target/generated-sources/sal + + + + + + + + org.apache.felix + maven-bundle-plugin + + + + com.google.common.collect, + org.opendaylight.yangtools.yang.binding, + org.opendaylight.yangtools.yang.common, + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004, + + + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210, + + + + + + + \ No newline at end of file diff --git a/opendaylight/netconf/ietf-netconf-monitoring-extension/src/main/yang/ietf-netconf-monitoring-extension.yang b/opendaylight/netconf/ietf-netconf-monitoring-extension/src/main/yang/ietf-netconf-monitoring-extension.yang new file mode 100644 index 0000000000..e8f2ec324b --- /dev/null +++ b/opendaylight/netconf/ietf-netconf-monitoring-extension/src/main/yang/ietf-netconf-monitoring-extension.yang @@ -0,0 +1,31 @@ +module ietf-netconf-monitoring-extension { + + yang-version 1; + + namespace + "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring-extension"; + + prefix ncme; + + import ietf-netconf-monitoring { + prefix ncm; + } + + revision "2013-12-10" { + description "Initial revision."; + + } + + identity netconf-tcp { + base ncm:transport; + description + "NETCONF over TCP."; + } + + augment "/ncm:netconf-state/ncm:sessions/ncm:session" { + leaf session-identifier { + type string; + } + } + +} \ No newline at end of file diff --git a/opendaylight/netconf/netconf-api/pom.xml b/opendaylight/netconf/netconf-api/pom.xml index 0fce4748a4..856bd77c20 100644 --- a/opendaylight/netconf/netconf-api/pom.xml +++ b/opendaylight/netconf/netconf-api/pom.xml @@ -30,6 +30,11 @@ ${project.groupId} ietf-netconf-monitoring + + ${project.groupId} + ietf-netconf-monitoring-extension + ${project.version} + org.opendaylight.bgpcep diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java index a0fddd79f2..7877843ccb 100644 --- a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java @@ -8,9 +8,10 @@ package org.opendaylight.controller.netconf.api; -import com.google.common.base.Optional; import org.w3c.dom.Document; +import com.google.common.base.Optional; + /** * NetconfMessage represents a wrapper around org.w3c.dom.Document. Needed for * implementing ProtocolMessage interface. diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java index 6ac57a88c9..fc6f87db5d 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java @@ -13,8 +13,10 @@ import io.netty.channel.socket.SocketChannel; import io.netty.util.HashedWheelTimer; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; + import java.io.Closeable; import java.net.InetSocketAddress; + import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.api.NetconfTerminationReason; @@ -26,6 +28,8 @@ import org.opendaylight.protocol.framework.SessionListenerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Optional; + public class NetconfClientDispatcher extends AbstractDispatcher implements Closeable { private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class); @@ -36,7 +40,13 @@ public class NetconfClientDispatcher extends AbstractDispatcherabsent()); + } + + public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, String additionalHeader) { + super(bossGroup, workerGroup); + timer = new HashedWheelTimer(); + this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader)); } public Future createClient(InetSocketAddress address, diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java index db0b953bdd..abfbdd526c 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java @@ -8,10 +8,13 @@ package org.opendaylight.controller.netconf.client; -import com.google.common.base.Preconditions; import io.netty.channel.Channel; import io.netty.util.Timer; import io.netty.util.concurrent.Promise; + +import java.io.IOException; +import java.io.InputStream; + import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.api.NetconfSessionPreferences; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -20,15 +23,18 @@ import org.opendaylight.protocol.framework.SessionNegotiator; import org.opendaylight.protocol.framework.SessionNegotiatorFactory; import org.xml.sax.SAXException; -import java.io.IOException; -import java.io.InputStream; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory { private final Timer timer; - public NetconfClientSessionNegotiatorFactory(Timer timer) { + private final Optional additionalHeader; + + public NetconfClientSessionNegotiatorFactory(Timer timer, Optional additionalHeader) { this.timer = timer; + this.additionalHeader = additionalHeader; } private static NetconfMessage loadHelloMessageTemplate() { @@ -45,7 +51,11 @@ public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorF public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel, Promise promise) { // Hello message needs to be recreated every time - NetconfSessionPreferences proposal = new NetconfSessionPreferences(loadHelloMessageTemplate()); + NetconfMessage helloMessage = loadHelloMessageTemplate(); + if(this.additionalHeader.isPresent()) { + helloMessage = new NetconfMessage(helloMessage.getDocument(), additionalHeader.get()); + } + NetconfSessionPreferences proposal = new NetconfSessionPreferences(helloMessage); return new NetconfClientSessionNegotiator(proposal, promise, channel, timer, sessionListenerFactory.getSessionListener()); } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java index 4de6cc35c0..ee07b3949d 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java @@ -14,8 +14,10 @@ import io.netty.channel.socket.SocketChannel; import io.netty.util.HashedWheelTimer; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; + import java.io.IOException; import java.net.InetSocketAddress; + import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.api.NetconfTerminationReason; @@ -31,6 +33,8 @@ import org.opendaylight.protocol.framework.ReconnectStrategy; import org.opendaylight.protocol.framework.SessionListener; import org.opendaylight.protocol.framework.SessionListenerFactory; +import com.google.common.base.Optional; + public class NetconfSshClientDispatcher extends NetconfClientDispatcher { private AuthenticationHandler authHandler; @@ -42,7 +46,15 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher { super(bossGroup, workerGroup); this.authHandler = authHandler; this.timer = new HashedWheelTimer(); - this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer); + this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.absent()); + } + + public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup, + EventLoopGroup workerGroup, String additionalHeader) { + super(bossGroup, workerGroup, additionalHeader); + this.authHandler = authHandler; + this.timer = new HashedWheelTimer(); + this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader)); } public Future createClient(InetSocketAddress address, diff --git a/opendaylight/netconf/netconf-impl/pom.xml b/opendaylight/netconf/netconf-impl/pom.xml index e073aaca8d..b056f9be87 100644 --- a/opendaylight/netconf/netconf-impl/pom.xml +++ b/opendaylight/netconf/netconf-impl/pom.xml @@ -23,6 +23,11 @@ ${project.groupId} ietf-netconf-monitoring + + ${project.groupId} + ietf-netconf-monitoring-extension + ${project.version} + ${project.groupId} netconf-util @@ -150,6 +155,8 @@ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas, + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210, + org.opendaylight.yangtools.yang.binding, diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java index b692179429..4cc05b7b42 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java @@ -8,13 +8,21 @@ package org.opendaylight.controller.netconf.impl; -import com.google.common.base.Preconditions; import io.netty.channel.Channel; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession; import org.opendaylight.protocol.framework.SessionListener; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.NetconfTcp; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1Builder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Transport; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session; @@ -25,10 +33,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types. import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import com.google.common.base.Preconditions; public class NetconfServerSession extends NetconfSession implements NetconfManagementSession { @@ -91,14 +96,18 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag builder.setOutNotifications(new ZeroBasedCounter32(0L)); builder.setKey(new SessionKey(getSessionId())); + + Session1Builder builder1 = new Session1Builder(); + builder1.setSessionIdentifier(header.getSessionType()); + builder.addAugmentation(Session1.class, builder1.build()); + return builder.build(); } private Class getTransportForString(String transport) { switch(transport) { case "ssh" : return NetconfSsh.class; - // TODO what about tcp - case "tcp" : return NetconfSsh.class; + case "tcp" : return NetconfTcp.class; default: throw new IllegalArgumentException("Unknown transport type " + transport); } } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java index 01ac018b3e..8ba4cdc052 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java @@ -8,28 +8,27 @@ package org.opendaylight.controller.netconf.impl; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; import io.netty.channel.Channel; import io.netty.util.Timer; import io.netty.util.concurrent.Promise; + +import java.net.InetSocketAddress; + import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences; +import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil; import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator; import org.opendaylight.protocol.framework.SessionListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import com.google.common.base.Optional; public class NetconfServerSessionNegotiator extends AbstractNetconfSessionNegotiator { static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionNegotiator.class); - private static final AdditionalHeader DEFAULT_HEADER = new AdditionalHeader(); - protected NetconfServerSessionNegotiator(NetconfServerSessionPreferences sessionPreferences, Promise promise, Channel channel, Timer timer, SessionListener sessionListener) { super(sessionPreferences, promise, channel, timer, sessionListener); @@ -41,36 +40,28 @@ public class NetconfServerSessionNegotiator extends AdditionalHeader parsedHeader; if (additionalHeader.isPresent()) { - parsedHeader = new AdditionalHeader(additionalHeader.get()); + parsedHeader = AdditionalHeaderUtil.fromString(additionalHeader.get()); } else { - parsedHeader = DEFAULT_HEADER; + parsedHeader = new AdditionalHeader("unknown", ((InetSocketAddress)channel.localAddress()).getHostString(), + "tcp", "client"); } logger.debug("Additional header from hello parsed as {} from {}", parsedHeader, additionalHeader); return new NetconfServerSession(sessionListener, channel, sessionPreferences.getSessionId(), parsedHeader); } - static class AdditionalHeader { + public static class AdditionalHeader { - private static final Pattern pattern = Pattern - .compile("\\[(?[^;]+);(?
[0-9\\.]+)[:/](?[0-9]+);(?[a-z]+)[^\\]]+\\]"); private final String username; private final String address; private final String transport; + private final String sessionIdentifier; - public AdditionalHeader(String addHeaderAsString) { - addHeaderAsString = addHeaderAsString.trim(); - Matcher matcher = pattern.matcher(addHeaderAsString); - Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s", - addHeaderAsString, pattern); - this.username = matcher.group("username"); - this.address = matcher.group("address"); - this.transport = matcher.group("transport"); - } - - private AdditionalHeader() { - this.username = this.address = "unknown"; - this.transport = "ssh"; + public AdditionalHeader(String userName, String hostAddress, String transport, String sessionIdentifier) { + this.address = hostAddress; + this.username = userName; + this.transport = transport; + this.sessionIdentifier = sessionIdentifier; } String getUsername() { @@ -85,6 +76,10 @@ public class NetconfServerSessionNegotiator extends return transport; } + String getSessionType() { + return sessionIdentifier; + } + @Override public String toString() { final StringBuffer sb = new StringBuffer("AdditionalHeader{"); @@ -95,4 +90,5 @@ public class NetconfServerSessionNegotiator extends return sb.toString(); } } + } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java new file mode 100644 index 0000000000..5c630dd343 --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java @@ -0,0 +1,41 @@ +/* + * 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.netconf.impl.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiator.AdditionalHeader; + +import com.google.common.base.Preconditions; + +public class AdditionalHeaderUtil { + + private static final Pattern pattern = Pattern + .compile("\\[(?[^;]+);(?
[0-9\\.]+)[:/](?[0-9]+);(?[a-z]+)[^\\]]+\\]"); + private static final Pattern customHeaderPattern = Pattern + .compile("\\[(?[^;]+);(?
[0-9\\.]+)[:/](?[0-9]+);(?[a-z]+);(?[a-z]+)[^\\]]+\\]"); + + public static AdditionalHeader fromString(String additionalHeader) { + additionalHeader = additionalHeader.trim(); + Matcher matcher = pattern.matcher(additionalHeader); + Matcher matcher2 = customHeaderPattern.matcher(additionalHeader); + Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s", + additionalHeader, pattern); + String username = matcher.group("username"); + String address = matcher.group("address"); + String transport = matcher.group("transport"); + String sessionIdentifier = "client"; + if (matcher2.matches()) { + sessionIdentifier = matcher2.group("sessionIdentifier"); + } + return new AdditionalHeader(username, address, transport, sessionIdentifier); + } + +} diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java index 2f8fac23f5..97d9a98b57 100644 --- a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java @@ -8,14 +8,16 @@ package org.opendaylight.controller.netconf.impl; import junit.framework.Assert; + import org.junit.Test; +import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil; public class AdditionalHeaderParserTest { @Test public void testParsing() throws Exception { String s = "[netconf;10.12.0.102:48528;ssh;;;;;;]"; - NetconfServerSessionNegotiator.AdditionalHeader header = new NetconfServerSessionNegotiator.AdditionalHeader(s); + NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s); Assert.assertEquals("netconf", header.getUsername()); Assert.assertEquals("10.12.0.102", header.getAddress()); Assert.assertEquals("ssh", header.getTransport()); @@ -24,7 +26,7 @@ public class AdditionalHeaderParserTest { @Test public void testParsing2() throws Exception { String s = "[tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]"; - NetconfServerSessionNegotiator.AdditionalHeader header = new NetconfServerSessionNegotiator.AdditionalHeader(s); + NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s); Assert.assertEquals("tomas", header.getUsername()); Assert.assertEquals("10.0.0.0", header.getAddress()); Assert.assertEquals("tcp", header.getTransport()); @@ -33,6 +35,6 @@ public class AdditionalHeaderParserTest { @Test(expected = IllegalArgumentException.class) public void testParsingNoUsername() throws Exception { String s = "[10.12.0.102:48528;ssh;;;;;;]"; - new NetconfServerSessionNegotiator.AdditionalHeader(s); + AdditionalHeaderUtil.fromString(s); } } diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java index ce5233c494..8d3476f4b8 100644 --- a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java @@ -8,12 +8,31 @@ package org.opendaylight.controller.netconf.impl; -import com.google.common.base.Optional; -import com.google.common.collect.Sets; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.junit.Assert.fail; +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 io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.util.HashedWheelTimer; + +import java.io.DataOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.management.ManagementFactory; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import javax.management.ObjectName; + import org.apache.commons.io.IOUtils; import org.junit.After; import org.junit.AfterClass; @@ -44,31 +63,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; -import javax.management.ObjectName; -import java.io.DataOutputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.management.ManagementFactory; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import static com.google.common.base.Preconditions.checkNotNull; -import static org.junit.Assert.fail; -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 com.google.common.base.Optional; +import com.google.common.collect.Sets; public class ConcurrentClientsTest { private static final int CONCURRENCY = 16; private static EventLoopGroup nettyGroup = new NioEventLoopGroup(); - public static final NetconfClientDispatcher NETCONF_CLIENT_DISPATCHER = new NetconfClientDispatcher( nettyGroup, nettyGroup); + public static final NetconfClientDispatcher NETCONF_CLIENT_DISPATCHER = + new NetconfClientDispatcher( nettyGroup, nettyGroup); @Mock private YangStoreService yangStoreService; diff --git a/opendaylight/netconf/netconf-it/pom.xml b/opendaylight/netconf/netconf-it/pom.xml index f2de91ef46..31248137e8 100644 --- a/opendaylight/netconf/netconf-it/pom.xml +++ b/opendaylight/netconf/netconf-it/pom.xml @@ -91,6 +91,12 @@ netconf-ssh test + + ${project.groupId} + netconf-ssh + test + test-jar + ${project.groupId} netconf-util 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 c61dab7f64..4818b5f0a3 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 @@ -8,18 +8,14 @@ package org.opendaylight.controller.netconf.it; -import static java.util.Collections.emptyList; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertTrue; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; +import ch.ethz.ssh2.Connection; +import ch.ethz.ssh2.Session; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.util.HashedWheelTimer; - import java.io.IOException; import java.io.InputStream; import java.lang.management.ManagementFactory; @@ -31,12 +27,9 @@ import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; - import javax.management.ObjectName; import javax.xml.parsers.ParserConfigurationException; - import junit.framework.Assert; - import org.junit.After; import org.junit.Before; import org.junit.Ignore; @@ -51,6 +44,7 @@ import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactor import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory; import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean; import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory; +import org.opendaylight.controller.netconf.StubUserManager; import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.client.NetconfClient; import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; @@ -68,6 +62,7 @@ import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFact import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService; import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; import org.opendaylight.controller.netconf.util.test.XmlFileLoader; import org.opendaylight.controller.netconf.util.xml.ExiParameters; import org.opendaylight.controller.netconf.util.xml.XmlElement; @@ -79,12 +74,13 @@ import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.xml.sax.SAXException; - -import ch.ethz.ssh2.Connection; -import ch.ethz.ssh2.Session; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; +import static java.util.Collections.emptyList; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; public class NetconfITTest extends AbstractConfigTest { @@ -435,7 +431,9 @@ public class NetconfITTest extends AbstractConfigTest { private void startSSHServer() throws Exception{ logger.info("Creating SSH server"); - Thread sshServerThread = new Thread(NetconfSSHServer.start(10830,tcpAddress)); + StubUserManager um = new StubUserManager(USERNAME,PASSWORD); + AuthProvider ap = new AuthProvider(um); + Thread sshServerThread = new Thread(NetconfSSHServer.start(10830,tcpAddress,ap)); sshServerThread.setDaemon(true); sshServerThread.start(); logger.info("SSH server on"); diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfMonitoringITTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfMonitoringITTest.java index 244e4ba4a9..3a7b7de7a0 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfMonitoringITTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfMonitoringITTest.java @@ -7,14 +7,27 @@ */ package org.opendaylight.controller.netconf.it; -import com.google.common.base.Charsets; -import com.google.common.base.Optional; -import com.google.common.collect.Sets; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.util.HashedWheelTimer; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + import junit.framework.Assert; + import org.junit.Before; import org.junit.Test; import org.junit.matchers.JUnitMatchers; @@ -48,20 +61,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import static org.mockito.Matchers.anyLong; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; +import com.google.common.base.Charsets; +import com.google.common.base.Optional; +import com.google.common.collect.Sets; public class NetconfMonitoringITTest extends AbstractConfigTest { diff --git a/opendaylight/netconf/netconf-monitoring/pom.xml b/opendaylight/netconf/netconf-monitoring/pom.xml index 31e427191c..8e1e599c71 100644 --- a/opendaylight/netconf/netconf-monitoring/pom.xml +++ b/opendaylight/netconf/netconf-monitoring/pom.xml @@ -79,10 +79,13 @@ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924, org.osgi.util.tracker, + org.opendaylight.yangtools.yang.common, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas, + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210, + org.opendaylight.yangtools.yang.binding, diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java index 25fb5d44dc..55aee72fda 100644 --- a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java +++ b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java @@ -7,13 +7,13 @@ */ package org.opendaylight.controller.netconf.monitoring.xml.model; -import com.google.common.base.Preconditions; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session; - import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlTransient; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session; +import org.opendaylight.yangtools.yang.common.QName; + final class MonitoringSession { @XmlTransient @@ -67,8 +67,17 @@ final class MonitoringSession { @XmlElement(name = "transport") public String getTransport() { - Preconditions.checkState(managementSession.getTransport() == NetconfSsh.class); - return "netconf-ssh"; + try { + QName qName = (QName) managementSession.getTransport().getField("QNAME").get(null); + return qName.getLocalName(); + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + throw new IllegalArgumentException("Unknown transport type " + managementSession.getTransport(), e); + } + } + + @XmlElement(name= "session-identifier") + public String getSessionType() { + return managementSession.getAugmentation(Session1.class).getSessionIdentifier(); } @XmlElement(name = "username") diff --git a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java index cb6e59f83f..1e3f343624 100644 --- a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java +++ b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java @@ -7,13 +7,18 @@ */ package org.opendaylight.controller.netconf.monitoring.xml; -import com.google.common.collect.Lists; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +import java.util.Date; + import org.junit.Test; import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService; import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder; @@ -25,10 +30,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types. import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.ZeroBasedCounter32; import org.w3c.dom.Element; -import java.util.Date; - -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; +import com.google.common.collect.Lists; public class JaxBSerializerTest { @@ -54,6 +56,8 @@ public class JaxBSerializerTest { private Session getMockSession() { Session mocked = mock(Session.class); + Session1 mockedSession1 = mock(Session1.class); + doReturn("client").when(mockedSession1).getSessionIdentifier(); doReturn(1L).when(mocked).getSessionId(); doReturn(new DateAndTime(new Date().toString())).when(mocked).getLoginTime(); doReturn(new Host(new DomainName("address/port"))).when(mocked).getSourceHost(); @@ -63,6 +67,7 @@ public class JaxBSerializerTest { doReturn(new ZeroBasedCounter32(0L)).when(mocked).getOutRpcErrors(); doReturn(NetconfSsh.class).when(mocked).getTransport(); doReturn("username").when(mocked).getUsername(); + doReturn(mockedSession1).when(mocked).getAugmentation(Session1.class); return mocked; } } diff --git a/opendaylight/netconf/netconf-ssh/pom.xml b/opendaylight/netconf/netconf-ssh/pom.xml index f60b4b02f5..5dde0448bd 100644 --- a/opendaylight/netconf/netconf-ssh/pom.xml +++ b/opendaylight/netconf/netconf-ssh/pom.xml @@ -33,10 +33,28 @@ commons-io commons-io + + org.opendaylight.controller + usermanager + 0.4.1-SNAPSHOT + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + package + + test-jar + + + + org.apache.felix maven-bundle-plugin @@ -55,9 +73,13 @@ org.apache.commons.io, org.opendaylight.controller.netconf.util, org.opendaylight.controller.netconf.util.osgi, + org.opendaylight.controller.usermanager, + org.opendaylight.controller.sal.authorization, + org.opendaylight.controller.sal.utils, org.opendaylight.protocol.framework, org.osgi.framework, - org.slf4j + org.osgi.util.tracker, + org.slf4j, diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java index b91824866a..3b513790bd 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java @@ -10,9 +10,14 @@ package org.opendaylight.controller.netconf.osgi; import com.google.common.base.Optional; import java.net.InetSocketAddress; import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; +import org.opendaylight.controller.usermanager.IUserManager; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,18 +36,57 @@ public class NetconfSSHActivator implements BundleActivator{ private NetconfSSHServer server; private static final Logger logger = LoggerFactory.getLogger(NetconfSSHActivator.class); private static final String EXCEPTION_MESSAGE = "Netconf ssh bridge is not available."; + private IUserManager iUserManager; + private BundleContext context = null; + + ServiceTrackerCustomizer customizer = new ServiceTrackerCustomizer(){ + @Override + public IUserManager addingService(ServiceReference reference) { + logger.info("Service IUserManager added, let there be SSH bridge."); + iUserManager = context.getService(reference); + try { + onUserManagerFound(iUserManager); + } catch (Exception e) { + logger.trace("Can't start SSH server due to {}",e); + } + return iUserManager; + } + @Override + public void modifiedService(ServiceReference reference, IUserManager service) { + logger.info("Replacing modified service IUserManager in netconf SSH."); + server.addUserManagerService(service); + } + @Override + public void removedService(ServiceReference reference, IUserManager service) { + logger.info("Removing service IUserManager from netconf SSH. " + + "SSH won't authenticate users until IUserManeger service will be started."); + removeUserManagerService(); + } + }; + @Override public void start(BundleContext context) throws Exception { + this.context = context; + listenForManagerService(); + } + @Override + public void stop(BundleContext context) throws Exception { + if (server != null){ + server.stop(); + logger.trace("Netconf SSH bridge is down ..."); + } + } + private void startSSHServer() throws Exception { logger.trace("Starting netconf SSH bridge."); - - Optional sshSocketAddressOptional = NetconfConfigUtil.extractSSHNetconfAddress(context,EXCEPTION_MESSAGE); + Optional sshSocketAddressOptional = NetconfConfigUtil.extractSSHNetconfAddress(context, EXCEPTION_MESSAGE); InetSocketAddress tcpSocketAddress = NetconfConfigUtil.extractTCPNetconfAddress(context, EXCEPTION_MESSAGE, true); if (sshSocketAddressOptional.isPresent()){ - server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress); + AuthProvider authProvider = new AuthProvider(iUserManager); + this.server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress,authProvider); Thread serverThread = new Thread(server,"netconf SSH server thread"); serverThread.setDaemon(true); serverThread.start(); @@ -52,13 +96,18 @@ public class NetconfSSHActivator implements BundleActivator{ throw new Exception("No valid connection configuration for SSH bridge found."); } } - - @Override - public void stop(BundleContext context) throws Exception { - if (server != null){ - logger.trace("Netconf SSH bridge going down ..."); - server.stop(); - logger.trace("Netconf SSH bridge is down ..."); + private void onUserManagerFound(IUserManager userManager) throws Exception{ + if (server!=null && server.isUp()){ + server.addUserManagerService(userManager); + } else { + startSSHServer(); } } + private void removeUserManagerService(){ + this.server.removeUserManagerService(); + } + private void listenForManagerService(){ + ServiceTracker listenerTracker = new ServiceTracker<>(context, IUserManager.class,customizer); + listenerTracker.open(); + } } diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java index 72135cc7dc..45807a8333 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java @@ -12,20 +12,23 @@ import java.net.InetSocketAddress; import java.net.ServerSocket; import java.util.concurrent.atomic.AtomicLong; import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; import org.opendaylight.controller.netconf.ssh.threads.SocketThread; +import org.opendaylight.controller.usermanager.IUserManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @ThreadSafe public class NetconfSSHServer implements Runnable { - private static boolean acceptMore = true; private ServerSocket ss = null; private static final Logger logger = LoggerFactory.getLogger(NetconfSSHServer.class); private static final AtomicLong sesssionId = new AtomicLong(); private final InetSocketAddress clientAddress; + private final AuthProvider authProvider; + private boolean up = false; - private NetconfSSHServer(int serverPort,InetSocketAddress clientAddress) throws Exception{ + private NetconfSSHServer(int serverPort,InetSocketAddress clientAddress, AuthProvider authProvider) throws Exception{ logger.trace("Creating SSH server socket on port {}",serverPort); this.ss = new ServerSocket(serverPort); @@ -34,27 +37,37 @@ public class NetconfSSHServer implements Runnable { } logger.trace("Server socket created."); this.clientAddress = clientAddress; - + this.authProvider = authProvider; + this.up = true; } - - public static NetconfSSHServer start(int serverPort, InetSocketAddress clientAddress) throws Exception { - return new NetconfSSHServer(serverPort, clientAddress); + public static NetconfSSHServer start(int serverPort, InetSocketAddress clientAddress,AuthProvider authProvider) throws Exception { + return new NetconfSSHServer(serverPort, clientAddress,authProvider); } public void stop() throws Exception { - acceptMore = false; + up = false; logger.trace("Closing SSH server socket."); ss.close(); logger.trace("SSH server socket closed."); } + public void removeUserManagerService(){ + this.authProvider.removeUserManagerService(); + } + + public void addUserManagerService(IUserManager userManagerService){ + this.authProvider.addUserManagerService(userManagerService); + } + public boolean isUp(){ + return this.up; + } @Override public void run() { - while (acceptMore) { + while (up) { logger.trace("Starting new socket thread."); try { - SocketThread.start(ss.accept(), clientAddress, sesssionId.incrementAndGet()); + SocketThread.start(ss.accept(), clientAddress, sesssionId.incrementAndGet(),authProvider); } catch (IOException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java new file mode 100644 index 0000000000..a73dfdfd49 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java @@ -0,0 +1,76 @@ +/* + * 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.netconf.ssh.authentication; + +import ch.ethz.ssh2.signature.RSAPrivateKey; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.io.IOUtils; +import org.opendaylight.controller.sal.authorization.AuthResultEnum; +import org.opendaylight.controller.sal.authorization.UserLevel; +import org.opendaylight.controller.usermanager.IUserManager; +import org.opendaylight.controller.usermanager.UserConfig; + +public class AuthProvider implements AuthProviderInterface { + + private static RSAPrivateKey hostkey = null; + private static IUserManager um; + private static final String DEAFULT_USER = "netconf"; + private static final String DEAFULT_PASSWORD = "netconf"; + + + public AuthProvider(IUserManager ium) throws Exception { + + this.um = ium; + + if (this.um == null){ + throw new Exception("No usermanager service available."); + } + + List roles = new ArrayList(1); + roles.add(UserLevel.SYSTEMADMIN.toString()); + this.um.addLocalUser(new UserConfig(DEAFULT_USER, DEAFULT_PASSWORD, roles)); + } + @Override + public boolean authenticated(String username, String password) throws Exception { + if (this.um == null){ + throw new Exception("No usermanager service available."); + } + AuthResultEnum authResult = this.um.authenticate(username,password); + if (authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC)){ + return true; + } + return false; + } + + @Override + public char[] getPEMAsCharArray() { + + InputStream is = getClass().getResourceAsStream("/RSA.pk"); + try { + return IOUtils.toCharArray(is); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public void removeUserManagerService() { + this.um = null; + } + + @Override + public void addUserManagerService(IUserManager userManagerService) { + this.um = userManagerService; + } + + +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProviderInterface.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProviderInterface.java new file mode 100644 index 0000000000..71f1cc350f --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProviderInterface.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.netconf.ssh.authentication; + +import org.opendaylight.controller.usermanager.IUserManager; + +public interface AuthProviderInterface { + + public boolean authenticated(String username, String password) throws Exception; + public char[] getPEMAsCharArray(); + public void removeUserManagerService(); + public void addUserManagerService(IUserManager userManagerService); +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/RSAKey.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/RSAKey.java deleted file mode 100644 index b420b33a7b..0000000000 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/RSAKey.java +++ /dev/null @@ -1,36 +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.netconf.ssh.authentication; - -import ch.ethz.ssh2.signature.RSAPrivateKey; - -import java.math.BigInteger; - -public class RSAKey implements KeyStoreHandler { - - private static RSAPrivateKey hostkey = null; - private static String user = "netconf"; - private static String password = "netconf"; - static { - - BigInteger p = new BigInteger("2967886344240998436887630478678331145236162666668503940430852241825039192450179076148979094256007292741704260675085192441025058193581327559331546948442042987131728039318861235625879376246169858586459472691398815098207618446039"); //.BigInteger.probablePrime(N / 2, rnd); - BigInteger q = new BigInteger("4311534819291430017572425052029278681302539382618633848168923130451247487970187151403375389974616614405320169278870943605377518341666894603659873284783174749122655429409273983428000534304828056597676444751611433784228298909767"); //BigInteger.probablePrime(N / 2, rnd); - BigInteger phi = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE)); - - BigInteger n = p.multiply(q); - BigInteger e = new BigInteger("65537"); - BigInteger d = e.modInverse(phi); - - hostkey = new RSAPrivateKey(d, e, n); - } - - @Override - public RSAPrivateKey getPrivateKey() { - return hostkey; - } -} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java index 15d99a44ee..e5da03b4cf 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java @@ -13,7 +13,7 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.controller.netconf.ssh.authentication.RSAKey; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,27 +30,38 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser private long sessionId; private String currentUser; private final String remoteAddressWithPort; + private final AuthProvider authProvider; - public static void start(Socket socket, InetSocketAddress clientAddress, long sessionId) throws IOException{ - Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket,clientAddress,sessionId)); + public static void start(Socket socket, + InetSocketAddress clientAddress, + long sessionId, + AuthProvider authProvider) throws IOException{ + Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket,clientAddress,sessionId,authProvider)); netconf_ssh_socket_thread.setDaemon(true); netconf_ssh_socket_thread.start(); } - private SocketThread(Socket socket, InetSocketAddress clientAddress, long sessionId) throws IOException { + private SocketThread(Socket socket, + InetSocketAddress clientAddress, + long sessionId, + AuthProvider authProvider) throws IOException { this.socket = socket; this.clientAddress = clientAddress; this.sessionId = sessionId; this.remoteAddressWithPort = socket.getRemoteSocketAddress().toString().replaceFirst("/",""); + this.authProvider = authProvider; } @Override public void run() { conn = new ServerConnection(socket); - RSAKey keyStore = new RSAKey(); - conn.setRsaHostKey(keyStore.getPrivateKey()); + try { + conn.setPEMHostKey(authProvider.getPEMAsCharArray(),"netconf"); + } catch (IOException e) { + e.printStackTrace(); + } conn.setAuthenticationCallback(this); conn.setServerConnectionCallback(this); try { @@ -90,7 +101,7 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser netconf_ssh_output.start(); } catch (Throwable t){ - logger.error(t.getMessage(),t); + logger.error("SSH bridge couldn't create echo socket",t.getMessage(),t); try { if (netconf_ssh_input!=null){ @@ -166,13 +177,16 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password) { - if (USER.equals(username) && PASSWORD.equals(password)){ - currentUser = username; - logger.trace("user {}@{} authenticated",currentUser,remoteAddressWithPort); - return AuthenticationResult.SUCCESS; - } - + try { + if (authProvider.authenticated(username,password)){ + currentUser = username; + logger.trace("user {}@{} authenticated",currentUser,remoteAddressWithPort); + return AuthenticationResult.SUCCESS; + } + } catch (Exception e){ + logger.info("Authentication failed due to :" + e.getLocalizedMessage()); + } return AuthenticationResult.FAILURE; } diff --git a/opendaylight/netconf/netconf-ssh/src/main/resources/RSA.pk b/opendaylight/netconf/netconf-ssh/src/main/resources/RSA.pk new file mode 100644 index 0000000000..c0266c7bd2 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/resources/RSA.pk @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAuC9hbEacpewvylI0mwFwjy3Wou2hpr/ncN9BBiFDSaG5yW2k +3Oy+SCAcFCL+ZKWb6cc6Ch4gUeCwyEHRojZguuhliKtak9YQf6qbvpPLe00842Lx +iqNAGurMpzizCDsGFq8ChaAkBZQI3TvcHuPoSUWSMJ+K8xHpRyUdVr6g2yEjezKJ +sTXBtWaeCCh6YUafFujuDJk7fvYcPW7Je5KRBBStIKvxcMW0zB+7eq04deTHwGbJ +gGjKWilQ72hsDDP3Hbp5CJMAYg1r4GlCmFx3KyHRGztgWgNgaD7nNpKCkTLjtmA6 +b4x7TA+jrzZ6Af2z5TMrI4dv5w1SrxHaZ+ziLQIDAQABAoIBAHTndeGgq/rQf8De +Do+4CTaHtK0zQSAyu/azbXUzlZ7drKuCEVs8VMY4wzmwwGEnkF+A2YDkgEUX5X0l +8aYQ97KKoS9u+43MGCrAIhyDeGrpqlT1TzRcy+qJz53v6gq2U/X/3QztiQ+VV078 +mIluxNgE9XYxPaNsYfGLSCTv1+9c8y/hjGVX2kwFK+u4ut0ZZETggNa8UxfaHVDS +fIJQX9Gm3J3GSUV30fDGMBIUW6ESLc2L8b7u8Mp9TRP39ZeQSuEUjBe8MYKv0Rel +oEpjZvcnniMTpFbLpndBYn7/AoIiEBvtCN8faVTuRRcvvLcsRm09IctzKQYnMh6M +6PLKV+ECgYEA8HFRYaKHUzxpzE/fyon82GQbzqFFY0/bbWrfWICMfNbIgshJUie6 +FmH5iUFMfeqaT7v557HFM0GB9FeIeSbvd88YmiBAcRopZ3DfMkDH+DT73yJ+/TKG +2nrQtdhyuTIs4bwHqeS2BBJYs7PK9R2rratF3l34Tf7mjlvyOgygHdUCgYEAxBo2 +8hEBlAVNcNb1hTYUxe1w1B6675/mFlmw98Xmj9dRYfICXNhahs8tX3/lsBEd+vBu +fI0oyHaff8m5bPgGzD1ZMybfeROujNrgxaKVk7Ef0FDRRCop4bm18OroFlFAt9l8 +wMp++ToACbdvQvL/mjWMPYlIxhB/YxHswICZZvkCgYAexxKYwdo6sGAGlC7cWT9x +X5cjowcjyEQZRHXkeUgCbufpvcOM7aLnXJE5nY8yCwbHsBM0MlBA2GDPKylAANjk +aDEJAZneIHAuWodngl1Wi0m2bU7+ECqs6s2uiU9eH2sZVh1RBQK7kLGkBx6ys6KX +L3ZZGYRAT6GplWFzRsx0JQKBgCeVlxPD5QqpC1nEumi6YvUVGdpnnZpzL3HBhxxs +wT612wKnZFyze4qM1X7ahVXGDsQxtkvD/sCAWW/lG13orw6ZL6FIroF1PJ3ILOkY +CZN3hJF7TtKwpCWhZB2OfWzL2AGEkE8mUP0j/Q/5DCd6f6f0OSvOw3bfq6cm3iB5 +lP2ZAoGAXsRN5TZTX4AQ2xTlrDQ8A5XgcvyWQpJOmEXMTyHV7VaJVzmNWFVAvndK +5UIq8ALDwB2t7vjmMUW6euvIwqtXiop7G79UOb3e3NhzeyWFGQyBLqCRznGaXQTT +dlFy73xhukZMhFnj006bjKCYvOPnwuGl3+0fuWil5Rq3jOuY5c8= +-----END RSA PRIVATE KEY----- diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/SSHServerTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/SSHServerTest.java similarity index 53% rename from opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/SSHServerTest.java rename to opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/SSHServerTest.java index 54bc7bc4b6..62396ed87a 100644 --- a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/SSHServerTest.java +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/SSHServerTest.java @@ -5,15 +5,14 @@ * 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.netconf.ssh; +package org.opendaylight.controller.netconf; import ch.ethz.ssh2.Connection; -import ch.ethz.ssh2.Session; -import java.io.IOException; import java.net.InetSocketAddress; import junit.framework.Assert; -import org.apache.commons.io.IOUtils; import org.junit.Test; +import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,36 +25,37 @@ public class SSHServerTest { private static final int PORT = 1830; private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 8383); private static final Logger logger = LoggerFactory.getLogger(SSHServerTest.class); + private Thread sshServerThread; + + + -// @Before public void startSSHServer() throws Exception{ - logger.info("Creating SSH server"); - NetconfSSHServer server = NetconfSSHServer.start(PORT,tcpAddress); - Thread sshServerThread = new Thread(server); - sshServerThread.setDaemon(true); - sshServerThread.start(); - logger.info("SSH server on"); + logger.info("Creating SSH server"); + StubUserManager um = new StubUserManager(USER,PASSWORD); + AuthProvider ap = new AuthProvider(um); + NetconfSSHServer server = NetconfSSHServer.start(PORT,tcpAddress,ap); + sshServerThread = new Thread(server); + sshServerThread.setDaemon(true); + sshServerThread.start(); + logger.info("SSH server on"); } @Test public void connect(){ - Connection conn = new Connection(HOST,PORT); - Assert.assertNotNull(conn); try { + this.startSSHServer(); + Connection conn = new Connection(HOST,PORT); + Assert.assertNotNull(conn); logger.info("connecting to SSH server"); conn.connect(); logger.info("authenticating ..."); boolean isAuthenticated = conn.authenticateWithPassword(USER,PASSWORD); Assert.assertTrue(isAuthenticated); - logger.info("opening session"); - Session sess = conn.openSession(); - logger.info("subsystem netconf"); - sess.startSubSystem("netconf"); - sess.getStdin().write("urn:ietf:params:netconf:base:1.1]]>]]>".getBytes()); - IOUtils.copy(sess.getStdout(), System.out); - } catch (IOException e) { - e.printStackTrace(); + } catch (Exception e) { + logger.error("Error while starting SSH server.", e); } + } } diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/StubUserManager.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/StubUserManager.java new file mode 100644 index 0000000000..4a3a650ecd --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/StubUserManager.java @@ -0,0 +1,184 @@ +/* + * 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.netconf; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.opendaylight.controller.sal.authorization.AuthResultEnum; +import org.opendaylight.controller.sal.authorization.UserLevel; +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; +import org.opendaylight.controller.usermanager.AuthorizationConfig; +import org.opendaylight.controller.usermanager.ISessionManager; +import org.opendaylight.controller.usermanager.IUserManager; +import org.opendaylight.controller.usermanager.ServerConfig; +import org.opendaylight.controller.usermanager.UserConfig; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.web.context.SecurityContextRepository; + +public class StubUserManager implements IUserManager{ + + + private static String user; + private static String password; + + public StubUserManager(String user, String password){ + this.user = user; + this.password = password; + } + @Override + public List getUserRoles(String userName) { + return null; + } + + @Override + public AuthResultEnum authenticate(String username, String password) { + if (this.user.equals(username) && this.password.equals(password)){ + return AuthResultEnum.AUTH_ACCEPT_LOC; + } + return AuthResultEnum.AUTH_REJECT_LOC; + } + + @Override + public Status addAAAServer(ServerConfig configObject) { + return null; + } + + @Override + public Status removeAAAServer(ServerConfig configObject) { + return null; + } + + @Override + public Status addLocalUser(UserConfig configObject) { + return new Status(StatusCode.SUCCESS); + } + + @Override + public Status modifyLocalUser(UserConfig configObject) { + return null; + } + + @Override + public Status removeLocalUser(UserConfig configObject) { + return null; + } + + @Override + public Status removeLocalUser(String userName) { + return null; + } + + @Override + public Status addAuthInfo(AuthorizationConfig AAAconf) { + return null; + } + + @Override + public Status removeAuthInfo(AuthorizationConfig AAAconf) { + return null; + } + + @Override + public List getAuthorizationList() { + return null; + } + + @Override + public Set getAAAProviderNames() { + return null; + } + + @Override + public Status changeLocalUserPassword(String user, String curPassword, String newPassword) { + return null; + } + + @Override + public List getAAAServerList() { + return null; + } + + @Override + public List getLocalUserList() { + return null; + } + + @Override + public Status saveLocalUserList() { + return null; + } + + @Override + public Status saveAAAServerList() { + return null; + } + + @Override + public Status saveAuthorizationList() { + return null; + } + + @Override + public void userLogout(String username) { + + } + + @Override + public void userTimedOut(String username) { + + } + + @Override + public Map> getUserLoggedIn() { + return null; + } + + @Override + public String getAccessDate(String user) { + return null; + } + + @Override + public UserLevel getUserLevel(String userName) { + return null; + } + + @Override + public List getUserLevels(String userName) { + return null; + } + + @Override + public SecurityContextRepository getSecurityContextRepo() { + return null; + } + + @Override + public ISessionManager getSessionManager() { + return null; + } + + @Override + public boolean isRoleInUse(String role) { + return false; + } + + @Override + public String getPassword(String username) { + return null; + } + + @Override + public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { + return null; + } + +} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java index 95d2feb65c..4fee930eff 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java @@ -10,8 +10,9 @@ package org.opendaylight.controller.netconf.util; import com.google.common.base.Optional; import com.google.common.base.Preconditions; - import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; import io.netty.handler.ssl.SslHandler; import io.netty.util.Timeout; import io.netty.util.Timer; @@ -19,9 +20,8 @@ import io.netty.util.TimerTask; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.concurrent.Promise; - -import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.api.NetconfMessage; +import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.api.NetconfSessionPreferences; import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory; import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator; @@ -44,11 +44,14 @@ public abstract class AbstractNetconfSessionNegotiator

sslHandler = getSslHandler(channel); if (sslHandler.isPresent()) { Future future = sslHandler.get().handshakeFuture(); @@ -94,10 +97,25 @@ public abstract class AbstractNetconfSessionNegotiator

+ * It has pattern "[username; host-address:port; transport; session-identifier;]" + * username - name of account on a remote + * host-address - client's IP address + * port - port number + * transport - tcp, ssh + * session-identifier - persister, client + * Session-identifier is optional, others mandatory. + * + */ +public class NetconfMessageAdditionalHeader { + + private static final String SC = ";"; + + public static String toString(String userName, String hostAddress, String port, String transport, + Optional sessionIdentifier) { + Preconditions.checkNotNull(userName); + Preconditions.checkNotNull(hostAddress); + Preconditions.checkNotNull(port); + Preconditions.checkNotNull(transport); + String identifier = sessionIdentifier.isPresent() ? sessionIdentifier.get() : ""; + return "[" + userName + SC + hostAddress + ":" + port + SC + transport + SC + identifier + SC + "]" + + System.lineSeparator(); + } +} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java index 891d40cf74..526708ab58 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java @@ -8,9 +8,12 @@ package org.opendaylight.controller.netconf.util.messages; -import com.google.common.base.Charsets; -import com.google.common.base.Optional; -import com.google.common.collect.Lists; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.List; + import org.opendaylight.controller.netconf.api.NetconfDeserializerException; import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -24,11 +27,9 @@ import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.xml.sax.SAXException; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.List; +import com.google.common.base.Charsets; +import com.google.common.base.Optional; +import com.google.common.collect.Lists; /** * NetconfMessageFactory for (de)serializing DOM documents. @@ -114,7 +115,14 @@ public final class NetconfMessageFactory implements ProtocolMessageFactory../../third-party/com.siemens.ct.exi netconf-monitoring ietf-netconf-monitoring + ietf-netconf-monitoring-extension @@ -147,6 +148,12 @@ netconf-ssh ${netconf.version} + + ${project.groupId} + netconf-ssh + ${netconf.version} + test-jar + ${project.groupId} netconf-mapping-api diff --git a/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/NorthboundApplication.java b/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/NorthboundApplication.java index e97a562620..e164abaf95 100644 --- a/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/NorthboundApplication.java +++ b/opendaylight/northbound/commons/src/main/java/org/opendaylight/controller/northbound/commons/NorthboundApplication.java @@ -46,9 +46,12 @@ public class NorthboundApplication extends Application { public NorthboundApplication() { _singletons = new HashSet(); _singletons.add(new ContextResolver() { - JAXBContext jaxbContext = newJAXBContext(); + JAXBContext jaxbContext; @Override - public JAXBContext getContext(Class type) { + public synchronized JAXBContext getContext(Class type) { + if (jaxbContext == null) { + jaxbContext = newJAXBContext(); + } return jaxbContext; } diff --git a/opendaylight/northbound/subnets/src/main/resources/WEB-INF/web.xml b/opendaylight/northbound/subnets/src/main/resources/WEB-INF/web.xml index 2300b8da40..7e0d465256 100644 --- a/opendaylight/northbound/subnets/src/main/resources/WEB-INF/web.xml +++ b/opendaylight/northbound/subnets/src/main/resources/WEB-INF/web.xml @@ -25,7 +25,7 @@ cors.allowed.methods - GET,POST,HEAD,OPTIONS,PUT + GET,POST,HEAD,OPTIONS,PUT,DELETE cors.allowed.headers diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServiceShim.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServiceShim.java index bb5681b2df..4e4e867fec 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServiceShim.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServiceShim.java @@ -298,18 +298,18 @@ public class TopologyServiceShim implements IDiscoveryListener, // Compare bandwidth usage Long switchId = (Long) connector.getNode().getID(); Short port = (Short) connector.getID(); - float rate = statsMgr.getTransmitRate(switchId, port); - if (rate > bwThresholdFactor * bw) { - if (!connectorsOverUtilized.contains(connector)) { - connectorsOverUtilized.add(connector); - this.bwUtilNotifyQ.add(new UtilizationUpdate(connector, - UpdateType.ADDED)); - } - } else { - if (connectorsOverUtilized.contains(connector)) { - connectorsOverUtilized.remove(connector); - this.bwUtilNotifyQ.add(new UtilizationUpdate(connector, - UpdateType.REMOVED)); + if (statsMgr != null) { + float rate = statsMgr.getTransmitRate(switchId, port); + if (rate > bwThresholdFactor * bw) { + if (!connectorsOverUtilized.contains(connector)) { + connectorsOverUtilized.add(connector); + this.bwUtilNotifyQ.add(new UtilizationUpdate(connector, UpdateType.ADDED)); + } + } else { + if (connectorsOverUtilized.contains(connector)) { + connectorsOverUtilized.remove(connector); + this.bwUtilNotifyQ.add(new UtilizationUpdate(connector, UpdateType.REMOVED)); + } } } } diff --git a/opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/Subnet.java b/opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/Subnet.java index 0a00cda9af..56df8e26bd 100644 --- a/opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/Subnet.java +++ b/opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/Subnet.java @@ -161,15 +161,11 @@ public class Subnet implements Cloneable, Serializable { } InetAddress thisPrefix = getPrefixForAddress(this.networkAddress); InetAddress otherPrefix = getPrefixForAddress(ip); - if ((thisPrefix == null) || (otherPrefix == null)) { - return false; - } - if (thisPrefix.equals(otherPrefix)) { - return true; - } - else { - return false; + boolean isSubnetOf = true; + if (((thisPrefix == null) || (otherPrefix == null)) || (!thisPrefix.equals(otherPrefix)) ) { + isSubnetOf = false; } + return isSubnetOf; } public short getVlan() { @@ -244,10 +240,7 @@ public class Subnet implements Cloneable, Serializable { if (p == null) { return false; } - if (this.isFlatLayer2()) { - return true; - } - return this.nodeConnectors.contains(p); + return isFlatLayer2() || nodeConnectors.contains(p); } public boolean isMutualExclusive(Subnet otherSubnet) { diff --git a/opendaylight/switchmanager/api/src/test/java/org/opendaylight/controller/switchmanager/SubnetTest.java b/opendaylight/switchmanager/api/src/test/java/org/opendaylight/controller/switchmanager/SubnetTest.java index 41a1f1ab06..8b6a149917 100644 --- a/opendaylight/switchmanager/api/src/test/java/org/opendaylight/controller/switchmanager/SubnetTest.java +++ b/opendaylight/switchmanager/api/src/test/java/org/opendaylight/controller/switchmanager/SubnetTest.java @@ -8,8 +8,13 @@ package org.opendaylight.controller.switchmanager; +import static org.junit.Assert.fail; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import java.net.Inet6Address; import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.HashSet; import java.util.Set; @@ -26,19 +31,19 @@ public class SubnetTest { public void testSubnet() throws Exception { InetAddress ipaddr = InetAddress.getByName("100.0.0.1"); Subnet subnet = new Subnet(ipaddr, (short) 24, (short) 5); - Assert.assertTrue(subnet.equals(subnet)); - Assert.assertFalse(subnet.equals(null)); - Assert.assertFalse(subnet.equals(ipaddr)); + assertTrue(subnet.equals(subnet)); + assertFalse(subnet.equals(null)); + assertFalse(subnet.equals(ipaddr)); Subnet subnet2 = new Subnet(ipaddr, (short) 24, (short) 5); Inet6Address ipv6 = (Inet6Address) Inet6Address .getByName("1111::2222:3333:4444:5555:6666"); Subnet subnet3 = new Subnet(ipv6, (short) 24, (short) 5); - Assert.assertTrue(subnet.equals(subnet2)); - Assert.assertFalse(subnet.isMutualExclusive(subnet2)); - Assert.assertTrue(subnet.isMutualExclusive(subnet3)); + assertTrue(subnet.equals(subnet2)); + assertFalse(subnet.isMutualExclusive(subnet2)); + assertTrue(subnet.isMutualExclusive(subnet3)); InetAddress subnetAddr = InetAddress.getByName("200.0.0.100"); - Assert.assertTrue(subnet.isFlatLayer2() == true); + assertTrue(subnet.isFlatLayer2() == true); Set ncSet = new HashSet(); Node node = NodeCreator.createOFNode(((long) 10)); @@ -53,10 +58,10 @@ public class SubnetTest { ncSet.add(nc1); ncSet.add(nc2); - Assert.assertTrue(subnet.hasNodeConnector(nc0)); - Assert.assertFalse(subnet.hasNodeConnector(null)); + assertTrue(subnet.hasNodeConnector(nc0)); + assertFalse(subnet.hasNodeConnector(null)); subnet.addNodeConnectors(ncSet); - Assert.assertTrue(subnet.hasNodeConnector(nc0)); + assertTrue(subnet.hasNodeConnector(nc0)); Set resultncSet = subnet.getNodeConnectors(); Assert.assertEquals(resultncSet, ncSet); @@ -69,24 +74,61 @@ public class SubnetTest { Set ncSet2 = new HashSet(); ncSet2.add(nc0); subnet.deleteNodeConnectors(ncSet2); - Assert.assertFalse(subnet.getNodeConnectors().contains(nc0)); - Assert.assertFalse(subnet.hasNodeConnector(nc0)); - Assert.assertTrue(subnet.getNodeConnectors().contains(nc1)); - Assert.assertTrue(subnet.getNodeConnectors().contains(nc2)); + assertFalse(subnet.getNodeConnectors().contains(nc0)); + assertFalse(subnet.hasNodeConnector(nc0)); + assertTrue(subnet.getNodeConnectors().contains(nc1)); + assertTrue(subnet.getNodeConnectors().contains(nc2)); subnet.deleteNodeConnectors(ncSet2); subnet.setNetworkAddress(subnetAddr); - Assert.assertTrue(subnet.isMutualExclusive(subnet2)); - Assert.assertTrue(subnet.getNetworkAddress().equals(subnetAddr)); + assertTrue(subnet.isMutualExclusive(subnet2)); + assertTrue(subnet.getNetworkAddress().equals(subnetAddr)); subnet.setSubnetMaskLength((short) 16); - Assert.assertTrue(subnet.getSubnetMaskLength() == 16); + assertTrue(subnet.getSubnetMaskLength() == 16); subnet.setVlan((short) 100); - Assert.assertTrue(subnet.getVlan() == 100); + assertTrue(subnet.getVlan() == 100); + + assertTrue(subnet.isFlatLayer2() == false); + } + + @Test + public void checkIsSubnetOfComparisonMatch() { + String host = "10.0.0.1"; + InetAddress ipAddrForSubnetComparison = null; + try { + ipAddrForSubnetComparison = InetAddress.getByName(host); + } catch (UnknownHostException e) { + fail("Failed to create InetAddress object for" + host); + } + SubnetConfig subnetConf = new SubnetConfig("subnet", "10.0.0.254/24",null); + Subnet subnet = new Subnet(subnetConf); + assertTrue(subnet.isSubnetOf(ipAddrForSubnetComparison)); + } - Assert.assertTrue(subnet.isFlatLayer2() == false); + @Test + public void checkIsSubnetOfComparisonNoMatch() { + String host = "100.0.0.1"; + InetAddress ipAddrForSubnetComparison = null; + try { + ipAddrForSubnetComparison = InetAddress.getByName(host); + } catch (UnknownHostException e) { + fail("Failed to create InetAddress object for" + host); + } + SubnetConfig subnetConf = new SubnetConfig("subnet", "10.0.0.254/24",null); + Subnet subnet = new Subnet(subnetConf); + assertFalse(subnet.isSubnetOf(ipAddrForSubnetComparison)); + } + + @Test + public void checkIsSubnetOfComparisonIpEmpty() { + SubnetConfig subnetConf = new SubnetConfig("subnet", "10.0.0.254/24",null); + Subnet subnet = new Subnet(subnetConf); + assertFalse(subnet.isSubnetOf(null)); } + + } diff --git a/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java b/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java index 41c783618d..b5d0a48c28 100644 --- a/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java +++ b/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java @@ -319,7 +319,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa @Override public SubnetConfig getSubnetConfig(String subnet) { // if there are no subnets, return the default subnet - if(subnetsConfigList.size() == 0 && subnet == DEFAULT_SUBNET_NAME){ + if(subnetsConfigList.isEmpty() && subnet.equalsIgnoreCase(DEFAULT_SUBNET_NAME)){ return DEFAULT_SUBNETCONFIG; }else{ return subnetsConfigList.get(subnet); @@ -428,11 +428,11 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa } private Status semanticCheck(SubnetConfig conf) { - Subnet newSubnet = new Subnet(conf); Set IPs = subnets.keySet(); if (IPs == null) { return new Status(StatusCode.SUCCESS); } + Subnet newSubnet = new Subnet(conf); for (InetAddress i : IPs) { Subnet existingSubnet = subnets.get(i); if ((existingSubnet != null) && !existingSubnet.isMutualExclusive(newSubnet)) { @@ -462,7 +462,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa return status; } } else { - if (conf.getName().equals(DEFAULT_SUBNET_NAME)) { + if (conf.getName().equalsIgnoreCase(DEFAULT_SUBNET_NAME)) { return new Status(StatusCode.NOTALLOWED, "The specified subnet gateway cannot be removed"); } } @@ -506,7 +506,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa @Override public Status removeSubnet(String name) { - if (name.equals(DEFAULT_SUBNET_NAME)) { + if (name.equalsIgnoreCase(DEFAULT_SUBNET_NAME)) { return new Status(StatusCode.NOTALLOWED, "The specified subnet gateway cannot be removed"); } SubnetConfig conf = subnetsConfigList.get(name); @@ -691,12 +691,9 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa return DEFAULT_SUBNET; } - Subnet sub; - Set indices = subnets.keySet(); - for (InetAddress i : indices) { - sub = subnets.get(i); - if (sub.isSubnetOf(networkAddress)) { - return sub; + for(Map.Entry subnetEntry : subnets.entrySet()) { + if(subnetEntry.getValue().isSubnetOf(networkAddress)) { + return subnetEntry.getValue(); } } return null; diff --git a/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java b/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java index 0c14dea38a..83532a1012 100644 --- a/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java +++ b/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java @@ -9,10 +9,11 @@ package org.opendaylight.controller.usermanager; import java.io.Serializable; -import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.regex.Matcher; @@ -24,6 +25,7 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import org.opendaylight.controller.sal.authorization.AuthResultEnum; +import org.opendaylight.controller.sal.packet.BitBufferHelper; import org.opendaylight.controller.sal.utils.HexEncode; import org.opendaylight.controller.sal.utils.Status; import org.opendaylight.controller.sal.utils.StatusCode; @@ -46,6 +48,7 @@ public class UserConfig implements Serializable { protected static final String PASSWORD_REGEX = "(?=.*[^a-zA-Z0-9])(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,256}$"; private static final Pattern INVALID_USERNAME_CHARACTERS = Pattern.compile("([/\\s\\.\\?#%;\\\\]+)"); private static MessageDigest oneWayFunction; + private static SecureRandom randomGenerator; static { try { @@ -54,6 +57,7 @@ public class UserConfig implements Serializable { log.error(String.format("Implementation of %s digest algorithm not found: %s", DIGEST_ALGORITHM, e.getMessage())); } + UserConfig.randomGenerator = new SecureRandom(BitBufferHelper.toByteArray(System.currentTimeMillis())); } /** @@ -81,6 +85,8 @@ public class UserConfig implements Serializable { @XmlElement private String password; + private byte[] salt; + public UserConfig() { @@ -102,11 +108,19 @@ public class UserConfig implements Serializable { /* * Password validation to be done on clear text password. If fails, mark * the password with a well known label, so that object validation can - * report the proper error. Only if password is a valid one, hash it. + * report the proper error. Only if password is a valid one, generate + * salt, concatenate it with clear text password and hash the + * resulting string. Hash result is going to be our stored password. */ - this.password = (validatePassword(password).isSuccess()) ? hash(password) : BAD_PASSWORD; + if (validateClearTextPassword(password).isSuccess()) { + this.salt = BitBufferHelper.toByteArray(randomGenerator.nextLong()); + this.password = hash(salt, password); + } else { + this.salt = null; + this.password = BAD_PASSWORD; + } - this.roles = (roles == null) ? new ArrayList() : new ArrayList(roles); + this.roles = (roles == null) ? Collections.emptyList() : new ArrayList(roles); } public String getUser() { @@ -176,6 +190,7 @@ public class UserConfig implements Serializable { public Status validate() { Status validCheck = validateUsername(); if (validCheck.isSuccess()) { + // Password validation was run at object construction time validCheck = (!password.equals(BAD_PASSWORD)) ? new Status(StatusCode.SUCCESS) : new Status( StatusCode.BADREQUEST, "Password should be 8 to 256 characters long, contain both upper and lower case letters, " @@ -203,7 +218,7 @@ public class UserConfig implements Serializable { return new Status(StatusCode.SUCCESS); } - private Status validatePassword(String password) { + private Status validateClearTextPassword(String password) { if (password == null || password.isEmpty()) { return new Status(StatusCode.BADREQUEST, "Password cannot be empty"); } @@ -227,14 +242,14 @@ public class UserConfig implements Serializable { // To make any changes to a user configured profile, current password // must always be provided - if (!this.password.equals(hash(currentPassword))) { + if (!this.password.equals(hash(this.salt, currentPassword))) { return new Status(StatusCode.BADREQUEST, "Current password is incorrect"); } // Create a new object with the proposed modifications UserConfig proposed = new UserConfig(); proposed.user = this.user; - proposed.password = (newPassword == null)? this.password : hash(newPassword); + proposed.password = (newPassword == null)? this.password : hash(this.salt, newPassword); proposed.roles = (newRoles == null)? this.roles : newRoles; // Validate it @@ -251,9 +266,9 @@ public class UserConfig implements Serializable { return status; } - public AuthResponse authenticate(String clearTextPass) { + public AuthResponse authenticate(String clearTextPassword) { AuthResponse locResponse = new AuthResponse(); - if (password.equals(hash(clearTextPass))) { + if (password.equals(hash(this.salt, clearTextPassword))) { locResponse.setStatus(AuthResultEnum.AUTH_ACCEPT_LOC); locResponse.addData(getRolesString()); } else { @@ -275,12 +290,32 @@ public class UserConfig implements Serializable { return buffer.toString(); } - public static String hash(String message) { + private static byte[] concatenate(byte[] salt, String password) { + byte[] messageArray = password.getBytes(); + byte[] concatenation = new byte[salt.length + password.length()]; + System.arraycopy(salt, 0, concatenation, 0, salt.length); + System.arraycopy(messageArray, 0, concatenation, salt.length, messageArray.length); + return concatenation; + } + + private static String hash(byte[] salt, String message) { if (message == null) { + log.warn("Password hash requested but empty or no password provided"); return message; } + if (salt == null || salt.length == 0) { + log.warn("Password hash requested but empty or no salt provided"); + return message; + } + + // Concatenate salt and password + byte[] messageArray = message.getBytes(); + byte[] concatenation = new byte[salt.length + message.length()]; + System.arraycopy(salt, 0, concatenation, 0, salt.length); + System.arraycopy(messageArray, 0, concatenation, salt.length, messageArray.length); + UserConfig.oneWayFunction.reset(); - return HexEncode.bytesToHexString(UserConfig.oneWayFunction.digest(message.getBytes(Charset.defaultCharset()))); + return HexEncode.bytesToHexString(UserConfig.oneWayFunction.digest(concatenate(salt, message))); } /** @@ -299,7 +334,8 @@ public class UserConfig implements Serializable { public static UserConfig getUncheckedUserConfig(String userName, String password, List roles) { UserConfig config = new UserConfig(); config.user = userName; - config.password = hash(password); + config.salt = BitBufferHelper.toByteArray(randomGenerator.nextLong()); + config.password = hash(config.salt, password); config.roles = roles; return config; } diff --git a/opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthorizationUserConfigTest.java b/opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthorizationUserConfigTest.java index d225e5c760..8fc7f07df1 100644 --- a/opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthorizationUserConfigTest.java +++ b/opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthorizationUserConfigTest.java @@ -7,7 +7,6 @@ */ package org.opendaylight.controller.usermanager; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -71,12 +70,12 @@ public class AuthorizationUserConfigTest { .isSuccess()); // New Password = null, No change in password - assertTrue(userConfig.getPassword().equals(UserConfig.hash("ciscocisco"))); + assertTrue(userConfig.authenticate("ciscocisco").getStatus().equals(AuthResultEnum.AUTH_ACCEPT_LOC)); // Password changed successfully, no change in user role assertTrue(userConfig.update("ciscocisco", "cisco123", roles) .isSuccess()); - assertTrue(userConfig.getPassword().equals(UserConfig.hash("cisco123"))); + assertTrue(userConfig.authenticate("cisco123").getStatus().equals(AuthResultEnum.AUTH_ACCEPT_LOC)); assertTrue(userConfig.getRoles().get(0).equals( UserLevel.NETWORKOPERATOR.toString())); @@ -85,14 +84,14 @@ public class AuthorizationUserConfigTest { roles.add(UserLevel.SYSTEMADMIN.toString()); assertTrue(userConfig.update("cisco123", "cisco123", roles) .isSuccess()); - assertTrue(userConfig.getPassword().equals(UserConfig.hash("cisco123"))); + assertTrue(userConfig.authenticate("cisco123").getStatus().equals(AuthResultEnum.AUTH_ACCEPT_LOC)); assertTrue(userConfig.getRoles().get(0) .equals(UserLevel.SYSTEMADMIN.toString())); // Password and role changed successfully assertTrue(userConfig.update("cisco123", "ciscocisco", roles) .isSuccess()); - assertTrue(userConfig.getPassword().equals(UserConfig.hash("ciscocisco"))); + assertTrue(userConfig.authenticate("ciscocisco").getStatus().equals(AuthResultEnum.AUTH_ACCEPT_LOC)); assertTrue(userConfig.getRoles().get(0) .equals(UserLevel.SYSTEMADMIN.toString())); @@ -104,14 +103,6 @@ public class AuthorizationUserConfigTest { assertTrue(authresp.getStatus().equals(AuthResultEnum.AUTH_ACCEPT_LOC)); authresp = userConfig.authenticate("wrongPassword"); assertTrue(authresp.getStatus().equals(AuthResultEnum.AUTH_REJECT_LOC)); - - // test equals() - roles.clear(); - roles.add(UserLevel.NETWORKOPERATOR.toString()); - userConfig = new UserConfig("uname", "ciscocisco", roles); - assertEquals(userConfig, userConfig); - UserConfig userConfig2 = new UserConfig("uname", "ciscocisco", roles); - assertEquals(userConfig, userConfig2); } @Test diff --git a/opendaylight/usermanager/implementation/pom.xml b/opendaylight/usermanager/implementation/pom.xml index 4eedf7eda9..dcdc2f6d50 100644 --- a/opendaylight/usermanager/implementation/pom.xml +++ b/opendaylight/usermanager/implementation/pom.xml @@ -51,10 +51,10 @@ org.opendaylight.controller.usermanager - + --> org.opendaylight.controller.usermanager.internal.Activator diff --git a/opendaylight/web/flows/src/main/resources/js/page.js b/opendaylight/web/flows/src/main/resources/js/page.js index 094562fac0..6b4cfa0025 100644 --- a/opendaylight/web/flows/src/main/resources/js/page.js +++ b/opendaylight/web/flows/src/main/resources/js/page.js @@ -390,8 +390,8 @@ one.f.flows = { $tr = $(tr); $span = $("td span", $tr); var flowstatus = $span.data("flowstatus"); - if($span.data("installinhw") != null) { - var installInHw = $span.data("installinhw").toString(); + if($span.data("installInHw") != null) { + var installInHw = $span.data("installInHw").toString(); if(installInHw == "true" && flowstatus == "Success") { $tr.addClass("success"); } else {