From: Jason Ye Date: Fri, 20 Dec 2013 22:03:47 +0000 (+0000) Subject: Merge "On openflow plugin restart, NPE in tx poller" X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-1~160 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=1ff9939abc7a4072b07df6b79516fe344b1b42e3;hp=ea064d50e2f3e960573e05ed1abe6f65cfa9a431;p=controller.git Merge "On openflow plugin restart, NPE in tx poller" --- diff --git a/opendaylight/commons/integrationtest/pom.xml b/opendaylight/commons/integrationtest/pom.xml index 5e101ebd28..fe5aa473a6 100644 --- a/opendaylight/commons/integrationtest/pom.xml +++ b/opendaylight/commons/integrationtest/pom.xml @@ -59,11 +59,6 @@ junit - - org.ops4j.pax.exam - pax-exam-container-native - test - org.ops4j.pax.exam pax-exam-junit4 diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index dd73815b34..5183165752 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -994,7 +994,7 @@ true ${project.basedir} **\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat - **\/target\/,**\/bin\/ + **\/target\/,**\/bin\/,**\/target-ide\/ diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigRegistry.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigRegistry.java index 5f23c90bbe..d81c48a602 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigRegistry.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigRegistry.java @@ -19,7 +19,7 @@ import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConsta * Provides functionality for working with configuration registry - mainly * creating and committing config transactions. */ -public interface ConfigRegistry extends LookupRegistry { +public interface ConfigRegistry extends LookupRegistry, ServiceReferenceReadableRegistry { /** * Only well-known ObjectName in configuration system, under which @@ -62,8 +62,13 @@ public interface ConfigRegistry extends LookupRegistry { */ boolean isHealthy(); + /** + * @return module factory names available in the system + */ Set getAvailableModuleNames(); + + /** * Find all runtime beans * 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 7e8ee64daa..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 { +public interface ConfigTransactionController extends LookupRegistry, ServiceReferenceWritableRegistry { /** * Create new configuration bean. @@ -64,6 +64,9 @@ public interface ConfigTransactionController extends LookupRegistry { */ String getTransactionName(); + /** + * @return all known module factory names as reported by {@link org.opendaylight.controller.config.spi.ModuleFactory#getImplementationName()} + */ Set getAvailableModuleNames(); } 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 7a3c4bf82d..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 @@ -7,10 +7,9 @@ */ package org.opendaylight.controller.config.api; -import java.util.Set; - import javax.management.InstanceNotFoundException; import javax.management.ObjectName; +import java.util.Set; public interface LookupRegistry { @@ -58,4 +57,18 @@ public interface LookupRegistry { ObjectName lookupConfigBean(String moduleName, String instanceName) throws InstanceNotFoundException; + /** + * Check that object name corresponds with existing module. + * + * @throws InstanceNotFoundException + * if search did not find exactly one instance + */ + void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException; + + + /** + * @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 new file mode 100644 index 0000000000..d7e94e8a76 --- /dev/null +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceReadableRegistry.java @@ -0,0 +1,62 @@ +/* + * 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.api; + +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import java.util.Map; +import java.util.Set; + +public interface ServiceReferenceReadableRegistry { + + /** + * Lookup object name by fully qualified service interface name and service reference 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 serviceInterfaceQName, String refName); + + /** + * Get mapping of services to reference names and module object names. + */ + Map> getServiceMapping(); + + /** + * Get current mapping between reference names and module object names for given service interface name. + * @param serviceInterfaceQName service interface name + * @throws IllegalArgumentException if there is a mismatch between serviceInterfaceName and objectName + */ + Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName); + + /** + * Find all available service interface names of a module. + * @param objectName module object name + * @throws InstanceNotFoundException if search did not find exactly one instance + */ + Set lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException; + + /** + * @param namespace service interface namespace + * @param localName service interface local name + * @return fully qualified name needed by all other service reference mapping methods. + * @throws java.lang.IllegalArgumentException if namespace or localName is not found + */ + 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 new file mode 100644 index 0000000000..fa2aa1f56e --- /dev/null +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ServiceReferenceWritableRegistry.java @@ -0,0 +1,39 @@ +/* + * 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.api; + +import javax.management.InstanceNotFoundException; +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 + */ + 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 + */ + void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException; + + /** + * Remove all service references. + */ + void removeAllServiceReferences(); + + /** + * Remove all service references attached to given module. + * @return true iif at least one reference was removed + */ + boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException; +} diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/annotations/ServiceInterfaceAnnotation.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/annotations/ServiceInterfaceAnnotation.java index a81d992d81..e66de46520 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/annotations/ServiceInterfaceAnnotation.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/annotations/ServiceInterfaceAnnotation.java @@ -23,8 +23,9 @@ import java.lang.annotation.Target; public @interface ServiceInterfaceAnnotation { /** - * Specifies human readable name of this service. Each service name should - * be globally unique. Should not contain spaces. + * Fully qualified name of a service that must be globally unique. + * When generating service interfaces from yang, this will be QName of + * identity extending service-type. */ String value(); @@ -34,4 +35,19 @@ public @interface ServiceInterfaceAnnotation { * is called. */ Class osgiRegistrationType(); + + /** + * Get namespace of {@link #value()} + */ + String namespace(); + + /** + * Get revision of {@link #value()} + */ + String revision(); + + /** + * Get local name of {@link #value()} + */ + String localName(); } 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 8111690c72..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 @@ -7,6 +7,11 @@ */ package org.opendaylight.controller.config.api.jmx; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants; + +import javax.annotation.concurrent.ThreadSafe; +import javax.management.ObjectName; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -15,32 +20,28 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import javax.annotation.concurrent.ThreadSafe; -import javax.management.ObjectName; - -import org.opendaylight.controller.config.api.ModuleIdentifier; -import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants; - /** * Provides ObjectName creation. Each created ObjectName consists of domain that * 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 { @@ -58,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); } @@ -77,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)); } @@ -102,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); @@ -118,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); } @@ -129,18 +191,43 @@ public class ObjectNameUtil { return objectName.getKeyProperty(TRANSACTION_NAME_KEY); } - public static ObjectName withoutTransactionName(ObjectName on) { - if (getTransactionName(on) == null) { + /** + * 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:" + on); + "Expected ObjectName with transaction:" + inputON); } - if (ON_DOMAIN.equals(on.getDomain()) == false) { + if (ON_DOMAIN.equals(inputON.getDomain()) == false) { throw new IllegalArgumentException("Expected different domain: " - + on); + + 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)); } - String moduleName = getFactoryName(on); - String instanceName = getInstanceName(on); - return createReadOnlyModuleON(moduleName, instanceName); + Map allProperties = getAdditionalProperties(inputON); + for (Entry entry : allProperties.entrySet()) { + if (entry.getKey().startsWith("X-")) { + outputProperties.put(entry.getKey(), entry.getValue()); + } + } + 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( @@ -153,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); @@ -205,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) @@ -223,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 + "=" @@ -232,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 + "," @@ -243,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) @@ -256,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-api/src/main/java/org/opendaylight/controller/config/spi/ModuleFactory.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/ModuleFactory.java index 7b8f7c164e..c86b381493 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/ModuleFactory.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/ModuleFactory.java @@ -97,6 +97,8 @@ public interface ModuleFactory { boolean isModuleImplementingServiceInterface( Class serviceInterface); + Set> getImplementedServiceIntefaces(); + /** * Called when ModuleFactory is registered to config manager. * Useful for populating the registry with pre-existing state. Since 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 1b695a9bda..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,6 +10,7 @@ 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.ServiceReferenceWritableRegistry; import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.jmx.CommitStatus; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; @@ -23,6 +24,7 @@ import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistr import org.opendaylight.controller.config.manager.impl.osgi.BeanToOsgiServiceManager; import org.opendaylight.controller.config.manager.impl.osgi.BeanToOsgiServiceManager.OsgiRegistration; import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil; +import org.opendaylight.controller.config.manager.impl.util.ModuleQNameUtil; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.controller.config.spi.ModuleFactory; import org.osgi.framework.BundleContext; @@ -59,9 +61,6 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe private final ModuleFactoriesResolver resolver; private final MBeanServer configMBeanServer; - @GuardedBy("this") - private final BundleContext bundleContext; - @GuardedBy("this") private long version = 0; @GuardedBy("this") @@ -99,23 +98,26 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe // internal jmx server shared by all transactions private final MBeanServer transactionsMBeanServer; + // Used for finding new factory instances for default module functionality @GuardedBy("this") private List lastListOfFactories = Collections.emptyList(); + @GuardedBy("this") // switched in every 2ndPC + private CloseableServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry(); + // constructor public ConfigRegistryImpl(ModuleFactoriesResolver resolver, - BundleContext bundleContext, MBeanServer configMBeanServer) { - this(resolver, bundleContext, configMBeanServer, + MBeanServer configMBeanServer) { + this(resolver, configMBeanServer, new BaseJMXRegistrator(configMBeanServer)); } // constructor public ConfigRegistryImpl(ModuleFactoriesResolver resolver, - BundleContext bundleContext, MBeanServer configMBeanServer, + MBeanServer configMBeanServer, BaseJMXRegistrator baseJMXRegistrator) { this.resolver = resolver; this.beanToOsgiServiceManager = new BeanToOsgiServiceManager(); - this.bundleContext = bundleContext; this.configMBeanServer = configMBeanServer; this.baseJMXRegistrator = baseJMXRegistrator; this.registryMBeanServer = MBeanServerFactory @@ -142,21 +144,32 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe private synchronized ConfigTransactionControllerInternal beginConfigInternal(boolean blankTransaction) { versionCounter++; - String transactionName = "ConfigTransaction-" + version + "-" + versionCounter; - TransactionJMXRegistrator transactionRegistrator = baseJMXRegistrator - .createTransactionJMXRegistrator(transactionName); - Map> allCurrentFactories = Collections.unmodifiableMap(resolver.getAllFactories()); + final String transactionName = "ConfigTransaction-" + version + "-" + versionCounter; + + TransactionJMXRegistratorFactory factory = new TransactionJMXRegistratorFactory() { + @Override + public TransactionJMXRegistrator create() { + return baseJMXRegistrator.createTransactionJMXRegistrator(transactionName); + } + }; + + Map> allCurrentFactories = Collections.unmodifiableMap( + resolver.getAllFactories()); + ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier( + transactionName), factory, allCurrentFactories); + ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry( + readableSRRegistry, txLookupRegistry, allCurrentFactories); + ConfigTransactionControllerInternal transactionController = new ConfigTransactionControllerImpl( - transactionName, transactionRegistrator, version, - versionCounter, allCurrentFactories, transactionsMBeanServer, configMBeanServer, blankTransaction); + txLookupRegistry, version, + versionCounter, allCurrentFactories, transactionsMBeanServer, + configMBeanServer, blankTransaction, writableRegistry); try { - transactionRegistrator.registerMBean(transactionController, transactionController.getControllerObjectName()); + txLookupRegistry.registerMBean(transactionController, transactionController.getControllerObjectName()); } catch (InstanceAlreadyExistsException e) { throw new IllegalStateException(e); } - transactionController.copyExistingModulesAndProcessFactoryDiff(currentConfig.getEntries(), lastListOfFactories); - transactionsHolder.add(transactionName, transactionController); return transactionController; } @@ -284,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 @@ -352,6 +364,12 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe // update version version = configTransactionController.getVersion(); + + // switch readable Service Reference Registry + this.readableSRRegistry.close(); + this.readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry( + configTransactionController.getWritableRegistry(), this, baseJMXRegistrator); + return new CommitStatus(newInstances, reusedInstances, recreatedInstances); } @@ -493,6 +511,66 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe return baseJMXRegistrator.queryNames(namePattern, null); } + @Override + public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException { + ObjectNameUtil.checkDomain(objectName); + ObjectNameUtil.checkType(objectName, ObjectNameUtil.TYPE_MODULE); + String transactionName = ObjectNameUtil.getTransactionName(objectName); + if (transactionName != null) { + throw new IllegalArgumentException("Transaction attribute not supported in registry, wrong ObjectName: " + objectName); + } + // make sure exactly one match is found: + LookupBeansUtil.lookupConfigBean(this, ObjectNameUtil.getFactoryName(objectName), ObjectNameUtil.getInstanceName(objectName)); + } + + // service reference functionality: + @Override + public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { + return readableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName); + } + + @Override + public synchronized Map> getServiceMapping() { + return readableSRRegistry.getServiceMapping(); + } + + @Override + public synchronized Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { + return readableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName); + } + + @Override + public synchronized Set lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException { + return readableSRRegistry.lookupServiceInterfaceNames(objectName); + } + + @Override + public synchronized String getServiceInterfaceName(String namespace, String localName) { + 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 + + '}'; + } } /** @@ -518,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); } } @@ -550,6 +628,8 @@ class ConfigHolder { Collections.sort(result); return result; } + + } /** 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 3e53a7a217..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 @@ -9,6 +9,7 @@ package org.opendaylight.controller.config.manager.impl; import org.opendaylight.controller.config.api.DependencyResolver; import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry; import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.config.manager.impl.dependencyresolver.DependencyResolverManager; @@ -16,10 +17,8 @@ import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicWrita import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean; import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean.ReadOnlyAtomicBooleanImpl; import org.opendaylight.controller.config.manager.impl.factoriesresolver.HierarchicalConfigMBeanFactoriesHolder; -import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator; import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator; import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration; -import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.controller.config.spi.ModuleFactory; import org.opendaylight.yangtools.concepts.Identifiable; @@ -34,20 +33,20 @@ import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; import javax.management.ObjectName; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.ArrayList; -import java.util.Collection; import java.util.concurrent.atomic.AtomicBoolean; import static java.lang.String.format; /** * This is a JMX bean representing current transaction. It contains - * {@link #transactionIdentifier}, unique version and parent version for + * transaction identifier, unique version and parent version for * optimistic locking. */ class ConfigTransactionControllerImpl implements @@ -56,10 +55,9 @@ class ConfigTransactionControllerImpl implements Identifiable{ private static final Logger logger = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class); - private final TransactionIdentifier transactionIdentifier; + private final ConfigTransactionLookupRegistry txLookupRegistry; private final ObjectName controllerON; - private final TransactionJMXRegistrator transactionRegistrator; - private final TransactionModuleJMXRegistrator txModuleJMXRegistrator; + private final long parentVersion, currentVersion; private final HierarchicalConfigMBeanFactoriesHolder factoriesHolder; private final DependencyResolverManager dependencyResolverManager; @@ -80,28 +78,28 @@ class ConfigTransactionControllerImpl implements private final boolean blankTransaction; - public ConfigTransactionControllerImpl(String transactionName, - TransactionJMXRegistrator transactionRegistrator, + @GuardedBy("this") + private final ServiceReferenceWritableRegistry writableSRRegistry; + + public ConfigTransactionControllerImpl(ConfigTransactionLookupRegistry txLookupRegistry, long parentVersion, long currentVersion, Map> currentlyRegisteredFactories, MBeanServer transactionsMBeanServer, MBeanServer configMBeanServer, - boolean blankTransaction) { - - this.transactionIdentifier = new TransactionIdentifier(transactionName); - this.controllerON = ObjectNameUtil - .createTransactionControllerON(transactionName); - this.transactionRegistrator = transactionRegistrator; - txModuleJMXRegistrator = transactionRegistrator - .createTransactionModuleJMXRegistrator(); + boolean blankTransaction, ServiceReferenceWritableRegistry writableSRRegistry) { + + this.txLookupRegistry = txLookupRegistry; + String transactionName = txLookupRegistry.getTransactionIdentifier().getName(); + this.controllerON = ObjectNameUtil.createTransactionControllerON(transactionName); this.parentVersion = parentVersion; this.currentVersion = currentVersion; 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; + this.writableSRRegistry = writableSRRegistry; } @Override @@ -167,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( @@ -225,14 +222,14 @@ class ConfigTransactionControllerImpl implements + moduleIdentifier + ", got " + dependencyResolver.getIdentifier()); } DynamicMBean writableDynamicWrapper = new DynamicWritableWrapper( - module, moduleIdentifier, transactionIdentifier, + module, moduleIdentifier, getTransactionIdentifier(), readOnlyAtomicBoolean, transactionsMBeanServer, configMBeanServer); ObjectName writableON = ObjectNameUtil.createTransactionModuleON( - transactionIdentifier.getName(), moduleIdentifier); + getTransactionIdentifier().getName(), moduleIdentifier); // put wrapper to jmx - TransactionModuleJMXRegistration transactionModuleJMXRegistration = txModuleJMXRegistrator + TransactionModuleJMXRegistration transactionModuleJMXRegistration = getTxModuleJMXRegistrator() .registerMBean(writableDynamicWrapper, writableON); ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo( moduleIdentifier, module, moduleFactory, @@ -243,18 +240,21 @@ class ConfigTransactionControllerImpl implements } @Override - public synchronized void destroyModule(ObjectName objectName) - throws InstanceNotFoundException { + public synchronized void destroyModule(ObjectName objectName) throws InstanceNotFoundException { + checkTransactionName(objectName); + ObjectNameUtil.checkDomain(objectName); + ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(objectName, + ObjectNameUtil.TYPE_MODULE); + destroyModule(moduleIdentifier); + } + + private void checkTransactionName(ObjectName objectName) { String foundTransactionName = ObjectNameUtil .getTransactionName(objectName); - if (transactionIdentifier.getName().equals(foundTransactionName) == false) { + if (getTransactionIdentifier().getName().equals(foundTransactionName) == false) { throw new IllegalArgumentException("Wrong transaction name " + objectName); } - ObjectNameUtil.checkDomain(objectName); - ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(objectName, - ObjectNameUtil.TYPE_MODULE); - destroyModule(moduleIdentifier); } private synchronized void destroyModule(ModuleIdentifier moduleIdentifier) { @@ -268,6 +268,15 @@ class ConfigTransactionControllerImpl implements logger.warn("Warning: removing default bean. This will be forbidden in next version of config-subsystem"); } } + // first remove refNames, it checks for objectname existence + try { + writableSRRegistry.removeServiceReferences( + ObjectNameUtil.createTransactionModuleON(getTransactionName(),moduleIdentifier)); + } catch (InstanceNotFoundException e) { + logger.error("Possible code error: cannot find {} in {}", moduleIdentifier, writableSRRegistry); + throw new IllegalStateException("Possible code error: cannot find " + moduleIdentifier, e); + } + ModuleInternalTransactionalInfo removedTInfo = dependencyResolverManager.destroyModule(moduleIdentifier); // remove from jmx removedTInfo.getTransactionModuleJMXRegistration().close(); @@ -297,7 +306,7 @@ class ConfigTransactionControllerImpl implements private void validate_noLocks() throws ValidationException { transactionStatus.checkNotAborted(); - logger.info("Validating transaction {}", transactionIdentifier); + logger.info("Validating transaction {}", getTransactionIdentifier()); // call validate() List collectedExceptions = new ArrayList<>(); for (Entry entry : dependencyResolverManager @@ -317,7 +326,7 @@ class ConfigTransactionControllerImpl implements throw ValidationException .createFromCollectedValidationExceptions(collectedExceptions); } - logger.info("Validated transaction {}", transactionIdentifier); + logger.info("Validated transaction {}", getTransactionIdentifier()); } /** @@ -359,7 +368,7 @@ class ConfigTransactionControllerImpl implements + "to obtain a lock"); } - logger.info("Committing transaction {}", transactionIdentifier); + logger.info("Committing transaction {}", getTransactionIdentifier()); // call getInstance() for (Entry entry : dependencyResolverManager @@ -368,21 +377,21 @@ class ConfigTransactionControllerImpl implements ModuleIdentifier name = entry.getKey(); try { logger.debug("About to commit {} in transaction {}", - name, transactionIdentifier); + name, getTransactionIdentifier()); module.getInstance(); } catch (Exception e) { logger.error("Commit failed on {} in transaction {}", name, - transactionIdentifier, e); + getTransactionIdentifier(), e); internalAbort(); throw new RuntimeException( format("Error - getInstance() failed for %s in transaction %s", - name, transactionIdentifier), e); + name, getTransactionIdentifier()), e); } } // count dependency order - logger.info("Committed configuration {}", transactionIdentifier); + logger.info("Committed configuration {}", getTransactionIdentifier()); transactionStatus.setCommitted(); // unregister this and all modules from jmx close(); @@ -402,8 +411,9 @@ class ConfigTransactionControllerImpl implements close(); } - private void close() { - transactionRegistrator.close(); + public void close() { + //FIXME: should not close object that was retrieved in constructor, a wrapper object should do that perhaps + txLookupRegistry.close(); } @Override @@ -413,7 +423,7 @@ class ConfigTransactionControllerImpl implements @Override public String getTransactionName() { - return transactionIdentifier.getName(); + return getTransactionIdentifier().getName(); } /** @@ -421,7 +431,7 @@ class ConfigTransactionControllerImpl implements */ @Override public Set lookupConfigBeans() { - return lookupConfigBeans("*", "*"); + return txLookupRegistry.lookupConfigBeans(); } /** @@ -429,7 +439,7 @@ class ConfigTransactionControllerImpl implements */ @Override public Set lookupConfigBeans(String moduleName) { - return lookupConfigBeans(moduleName, "*"); + return txLookupRegistry.lookupConfigBeans(moduleName); } /** @@ -438,20 +448,29 @@ class ConfigTransactionControllerImpl implements @Override public ObjectName lookupConfigBean(String moduleName, String instanceName) throws InstanceNotFoundException { - return LookupBeansUtil.lookupConfigBean(this, moduleName, instanceName); + return txLookupRegistry.lookupConfigBean(moduleName, instanceName); } /** * {@inheritDoc} */ @Override - public Set lookupConfigBeans(String moduleName, - String instanceName) { - ObjectName namePattern = ObjectNameUtil.createModulePattern(moduleName, - instanceName, transactionIdentifier.getName()); - return txModuleJMXRegistrator.queryNames(namePattern, null); + public Set lookupConfigBeans(String moduleName, String instanceName) { + return txLookupRegistry.lookupConfigBeans(moduleName, instanceName); } + /** + * {@inheritDoc} + */ + @Override + public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException { + txLookupRegistry.checkConfigBeanExists(objectName); + } + // -- + + /** + * {@inheritDoc} + */ @Override public Set getAvailableModuleNames() { return factoriesHolder.getModuleNames(); @@ -473,11 +492,11 @@ class ConfigTransactionControllerImpl implements // @VisibleForTesting TransactionModuleJMXRegistrator getTxModuleJMXRegistrator() { - return txModuleJMXRegistrator; + return txLookupRegistry.getTxModuleJMXRegistrator(); } public TransactionIdentifier getName() { - return transactionIdentifier; + return getTransactionIdentifier(); } @Override @@ -487,7 +506,7 @@ class ConfigTransactionControllerImpl implements @Override public TransactionIdentifier getIdentifier() { - return transactionIdentifier; + return getTransactionIdentifier(); } @Override @@ -498,4 +517,76 @@ class ConfigTransactionControllerImpl implements } return factoryBundleContextEntry.getValue(); } + + // service reference functionality: + + + @Override + public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { + return writableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName); + } + + @Override + public synchronized Map> getServiceMapping() { + return writableSRRegistry.getServiceMapping(); + } + + @Override + public synchronized Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { + return writableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName); + } + + @Override + public synchronized Set lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException { + return writableSRRegistry.lookupServiceInterfaceNames(objectName); + } + + @Override + public synchronized String getServiceInterfaceName(String namespace, String localName) { + return writableSRRegistry.getServiceInterfaceName(namespace, localName); + } + + @Override + public synchronized ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException { + return writableSRRegistry.saveServiceReference(serviceInterfaceName, refName, moduleON); + } + + @Override + public synchronized void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException { + writableSRRegistry.removeServiceReference(serviceInterfaceName, refName); + } + + @Override + public synchronized void removeAllServiceReferences() { + writableSRRegistry.removeAllServiceReferences(); + } + + @Override + public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException { + return writableSRRegistry.removeServiceReferences(objectName); + } + + @Override + public ServiceReferenceWritableRegistry getWritableRegistry() { + return writableSRRegistry; + } + + public TransactionIdentifier getTransactionIdentifier() { + return txLookupRegistry.getTransactionIdentifier(); + } + + @Override + public Set getAvailableModuleFactoryQNames() { + 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/ConfigTransactionControllerInternal.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java index 4dc877c62b..82bae44a01 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java @@ -13,6 +13,7 @@ import java.util.List; import javax.management.ObjectName; import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry; import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.spi.ModuleFactory; import org.osgi.framework.BundleContext; @@ -71,4 +72,7 @@ interface ConfigTransactionControllerInternal extends List getCurrentlyRegisteredFactories(); BundleContext getModuleFactoryBundleContext(String factoryName); + + ServiceReferenceWritableRegistry getWritableRegistry(); + } 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 new file mode 100644 index 0000000000..a7d426ebdd --- /dev/null +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionLookupRegistry.java @@ -0,0 +1,131 @@ +/* + * 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.LookupRegistry; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator; +import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator; +import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil; +import org.opendaylight.controller.config.manager.impl.util.ModuleQNameUtil; +import org.opendaylight.controller.config.spi.ModuleFactory; +import org.osgi.framework.BundleContext; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import java.io.Closeable; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * Responsible for creating TransactionJMXRegistrator, registering transaction and all its beans, + * lookup of beans, closing of TransactionJMXRegistrator. + */ +class ConfigTransactionLookupRegistry implements LookupRegistry, Closeable { + private final TransactionJMXRegistrator transactionJMXRegistrator; + private final TransactionIdentifier transactionIdentifier; + private final TransactionModuleJMXRegistrator txModuleJMXRegistrator; + private final Map> allCurrentFactories; + + ConfigTransactionLookupRegistry(TransactionIdentifier transactionIdentifier, + TransactionJMXRegistratorFactory factory, Map> allCurrentFactories) { + this.transactionIdentifier = transactionIdentifier; + this.transactionJMXRegistrator = factory.create(); + this.txModuleJMXRegistrator = transactionJMXRegistrator.createTransactionModuleJMXRegistrator(); + this.allCurrentFactories = allCurrentFactories; + } + + private void checkTransactionName(ObjectName objectName) { + String foundTransactionName = ObjectNameUtil + .getTransactionName(objectName); + if (transactionIdentifier.getName().equals(foundTransactionName) == false) { + throw new IllegalArgumentException("Wrong transaction name " + + objectName); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Set lookupConfigBeans() { + return lookupConfigBeans("*", "*"); + } + + /** + * {@inheritDoc} + */ + @Override + public Set lookupConfigBeans(String moduleName) { + return lookupConfigBeans(moduleName, "*"); + } + + /** + * {@inheritDoc} + */ + @Override + public ObjectName lookupConfigBean(String moduleName, String instanceName) + throws InstanceNotFoundException { + return LookupBeansUtil.lookupConfigBean(this, moduleName, instanceName); + } + + /** + * {@inheritDoc} + */ + @Override + public Set lookupConfigBeans(String moduleName, + String instanceName) { + ObjectName namePattern = ObjectNameUtil.createModulePattern(moduleName, + instanceName, transactionIdentifier.getName()); + return txModuleJMXRegistrator.queryNames(namePattern, null); + } + + @Override + public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException { + ObjectNameUtil.checkDomain(objectName); + ObjectNameUtil.checkType(objectName, ObjectNameUtil.TYPE_MODULE); + checkTransactionName(objectName); + // make sure exactly one match is found: + LookupBeansUtil.lookupConfigBean(this, ObjectNameUtil.getFactoryName(objectName), ObjectNameUtil.getInstanceName(objectName)); + } + + TransactionIdentifier getTransactionIdentifier() { + return transactionIdentifier; + } + + TransactionModuleJMXRegistrator getTxModuleJMXRegistrator() { + return txModuleJMXRegistrator; + } + + public void close() { + transactionJMXRegistrator.close(); + } + + public void registerMBean(ConfigTransactionControllerInternal transactionController, ObjectName controllerObjectName) throws InstanceAlreadyExistsException { + transactionJMXRegistrator.registerMBean(transactionController, controllerObjectName); + } + + @Override + public Set getAvailableModuleFactoryQNames() { + return ModuleQNameUtil.getQNames(allCurrentFactories); + } + + + @Override + public String toString() { + return "ConfigTransactionLookupRegistry{" + + "transactionIdentifier=" + transactionIdentifier + + '}'; + } +} + +interface TransactionJMXRegistratorFactory { + TransactionJMXRegistrator create(); +} 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 new file mode 100644 index 0000000000..0faa32b7dc --- /dev/null +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java @@ -0,0 +1,520 @@ +/* + * 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.LookupRegistry; +import org.opendaylight.controller.config.api.ModuleIdentifier; +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.Map; +import java.util.Map.Entry; +import java.util.Set; + +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 = 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 CloseableServiceReferenceReadableRegistry createInitialSRLookupRegistry() { + // since this is initial state, just throw exception: + LookupRegistry lookupRegistry = new LookupRegistry() { + @Override + public Set lookupConfigBeans() { + throw new UnsupportedOperationException(); + } + + @Override + public Set lookupConfigBeans(String moduleName) { + throw new UnsupportedOperationException(); + } + + @Override + public Set lookupConfigBeans(String moduleName, String instanceName) { + throw new UnsupportedOperationException(); + } + + @Override + public ObjectName lookupConfigBean(String moduleName, String instanceName) throws InstanceNotFoundException { + throw new UnsupportedOperationException(); + } + + @Override + public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException { + 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, + 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, + ConfigTransactionLookupRegistry txLookupRegistry, + Map> currentlyRegisteredFactories) { + + if (txLookupRegistry == null) { + throw new IllegalArgumentException("txLookupRegistry is null"); + } + ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldReadableRegistry; + Map factories = extractFactoriesMap(currentlyRegisteredFactories); + 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 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 + 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) { + Map result = new HashMap<>(); + for (Entry> entry : currentlyRegisteredFactories.entrySet()) { + result.put(entry.getKey(), entry.getValue().getKey()); + } + return result; + } + + private ServiceReferenceRegistryImpl(Map factories, LookupRegistry lookupRegistry, + 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<>(); + for (Entry entry : factories.entrySet()) { + if (entry.getKey().equals(entry.getValue().getImplementationName()) == false) { + logger.error("Possible error in code: Mismatch between supplied and actual name of {}", entry); + throw new IllegalArgumentException("Possible error in code: Mismatch between supplied and actual name of " + entry); + } + Set siAnnotations = InterfacesHelper.getServiceInterfaceAnnotations(entry.getValue()); + Set qNames = new HashSet<>(); + for (ServiceInterfaceAnnotation sia: siAnnotations) { + qNames.add(sia.value()); + } + allAnnotations.addAll(siAnnotations); + allQNames.addAll(qNames); + factoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames)); + } + this.factoryNamesToQNames = Collections.unmodifiableMap(factoryNamesToQNames); + this.allQNames = Collections.unmodifiableSet(allQNames); + // fill namespacesToAnnotations + Map> namespacesToAnnotations = + new HashMap<>(); + for (ServiceInterfaceAnnotation sia : allAnnotations) { + Map ofNamespace = namespacesToAnnotations.get(sia.namespace()); + if (ofNamespace == null) { + ofNamespace = new HashMap<>(); + namespacesToAnnotations.put(sia.namespace(), ofNamespace); + } + if (ofNamespace.containsKey(sia.localName())) { + logger.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}", + sia.namespace(), sia.localName(), namespacesToAnnotations); + throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName()); + } + ofNamespace.put(sia.localName(), sia); + } + this.namespacesToAnnotations = Collections.unmodifiableMap(namespacesToAnnotations); + // copy refNames + logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames); + } + + + @Override + public synchronized Set lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException { + lookupRegistry.checkConfigBeanExists(objectName); + + String factoryName = ObjectNameUtil.getFactoryName(objectName); + Set serviceInterfaceAnnotations = factoryNamesToQNames.get(factoryName); + if (serviceInterfaceAnnotations == null) { + logger.error("Possible error in code: cannot find factory annotations of '{}' extracted from ON {} in {}", + factoryName, objectName, factoryNamesToQNames); + throw new IllegalArgumentException("Cannot find factory with name " + factoryName); + } + return serviceInterfaceAnnotations; + } + + @Override + public synchronized String getServiceInterfaceName(String namespace, String localName) { + Map ofNamespace = namespacesToAnnotations.get(namespace); + if (ofNamespace == null) { + logger.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations); + throw new IllegalArgumentException("Cannot find namespace " + namespace); + } + ServiceInterfaceAnnotation sia = ofNamespace.get(localName); + if (sia == null) { + logger.error("Cannot find local name {} in namespace {}, found only {}", localName, namespace, ofNamespace); + throw new IllegalArgumentException("Cannot find local name " + localName + " in namespace " + namespace); + } + return sia.value(); + } + + // reading: + + @Override + public synchronized Map> getServiceMapping() { + Map> result = new HashMap<>(); + 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; + } + + private ObjectName getObjectName(ModuleIdentifier moduleIdentifier) { + ObjectName on; + try { + on = lookupRegistry.lookupConfigBean(moduleIdentifier.getFactoryName(), moduleIdentifier.getInstanceName()); + } catch (InstanceNotFoundException e) { + logger.error("Cannot find instance {}", moduleIdentifier); + throw new IllegalStateException("Cannot find instance " + moduleIdentifier, e); + } + return on; + } + + @Override + 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 qname {} and refName {} in {}", serviceInterfaceQName, refName, refName); + throw new IllegalArgumentException("Cannot find " + serviceReference); + } + return getObjectName(moduleIdentifier); + } + + @Override + public synchronized Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { + Map> serviceMapping = getServiceMapping(); + Map innerMap = serviceMapping.get(serviceInterfaceQName); + if (innerMap == null) { + logger.error("Cannot find qname {} in {}", serviceInterfaceQName, refNames); + throw new IllegalArgumentException("Cannot find " + serviceInterfaceQName); + } + 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); + } + } + + // writing: + + private void assertWritable() { + if (writable == false) { + throw new IllegalStateException("Cannot write to readable registry"); + } + } + + @Override + 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 + 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(moduleIdentifier.getFactoryName()); + if (serviceInterfaceQNames == null) { + 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(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()); + } + + + // 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()); + } + } + + @Override + 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()); + } + Entry entry = mBeans.remove(serviceReference); + if (entry == null) { + throw new IllegalStateException("Possible code error: cannot remove from mBeans: " + serviceReference); + } + entry.getValue().close(); + } + + @Override + 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 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, moduleObjectName); + throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName); + } + String instanceName = ObjectNameUtil.getInstanceName(moduleObjectName); + ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName); + Set result = new HashSet<>(); + for (Entry entry : refNames.entrySet()) { + if (entry.getValue().equals(moduleIdentifier)) { + result.add(entry.getKey()); + } + } + 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 065a0f843f..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,21 +38,26 @@ 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; } /** * {@inheritDoc} */ + //TODO: check for cycles @Override public void validateDependency( Class expectedServiceInterface, - ObjectName dependentModuleReadOnlyON, JmxAttribute jmxAttribute) { + ObjectName dependentReadOnlyON, JmxAttribute jmxAttribute) { transactionStatus.checkNotCommitted(); if (expectedServiceInterface == null) { @@ -61,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); @@ -89,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); } @@ -98,23 +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/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java index f82a7295aa..16f7cf024a 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java @@ -13,6 +13,7 @@ import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map.Entry; import java.util.Set; import java.util.List; import java.util.Map; @@ -76,4 +77,7 @@ public class HierarchicalConfigMBeanFactoriesHolder { return moduleFactories; } + public Map> getModuleNamesToConfigBeanFactories() { + return moduleNamesToConfigBeanFactories; + } } 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/TransactionJMXRegistrator.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/TransactionJMXRegistrator.java index 523cbc5b01..b371c3f170 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/TransactionJMXRegistrator.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/TransactionJMXRegistrator.java @@ -65,7 +65,7 @@ public class TransactionJMXRegistrator implements Closeable { } @Override - public void close() { + public void close() { // closes also all child TransactionModuleJMXRegistrator instances childJMXRegistrator.close(); } } 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/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java index ab81143170..1ee6cca7e2 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java @@ -36,8 +36,7 @@ public class ConfigManagerActivator implements BundleActivator { new BundleContextBackedModuleFactoriesResolver(context); MBeanServer configMBeanServer = ManagementFactory.getPlatformMBeanServer(); configRegistry = new ConfigRegistryImpl( - bundleContextBackedModuleFactoriesResolver, context, - configMBeanServer); + bundleContextBackedModuleFactoriesResolver, configMBeanServer); // register config registry to OSGi configRegistryServiceRegistration = context.registerService(ConfigRegistryImpl.class, configRegistry, null); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelper.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelper.java index 76cb64cf93..033f7222fc 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelper.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelper.java @@ -7,17 +7,18 @@ */ package org.opendaylight.controller.config.manager.impl.util; +import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; +import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; +import org.opendaylight.controller.config.spi.Module; +import org.opendaylight.controller.config.spi.ModuleFactory; + +import javax.management.JMX; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; -import javax.management.JMX; - -import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; -import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; -import org.opendaylight.controller.config.spi.Module; - public class InterfacesHelper { public static Set> getAllInterfaces(Class clazz) { @@ -32,16 +33,25 @@ public class InterfacesHelper { // get parent class clazz = clazz.getSuperclass(); } + return getAllSuperInterfaces(toBeInspected); + + } + + private static Set> getAllSuperInterfaces(Set> ifcs) { + ifcs = new HashSet<>(ifcs); // create copy to modify // each interface can extend other interfaces - Set> inspected = new HashSet<>(); - while (toBeInspected.size() > 0) { - Iterator> iterator = toBeInspected.iterator(); + Set> result = new HashSet<>(); + while (ifcs.size() > 0) { + Iterator> iterator = ifcs.iterator(); Class ifc = iterator.next(); iterator.remove(); - toBeInspected.addAll(Arrays.asList(ifc.getInterfaces())); - inspected.add(ifc); + if (ifc.isInterface() == false) { + throw new IllegalArgumentException(ifc + " should be an interface"); + } + ifcs.addAll(Arrays.asList(ifc.getInterfaces())); + result.add(ifc); } - return inspected; + return result; } /** @@ -80,6 +90,18 @@ public class InterfacesHelper { return result; } + public static Set> getAllAbstractServiceClasses(Class configBeanClass) { + + Set> foundGeneratedSIClasses = new HashSet<>(); + for (Class clazz : getAllInterfaces(configBeanClass)) { + if (AbstractServiceInterface.class.isAssignableFrom(clazz) && AbstractServiceInterface.class.equals(clazz) == false) { + foundGeneratedSIClasses.add((Class) clazz); + } + } + return getAllAbstractServiceInterfaceClasses(foundGeneratedSIClasses); + } + + /** * Get OSGi registration types under which config bean instance should be * registered. This is specified in @@ -98,4 +120,37 @@ public class InterfacesHelper { return result; } + + public static Set getServiceInterfaceAnnotations(ModuleFactory factory) { + Set> implementedServiceIntefaces = Collections.unmodifiableSet(factory.getImplementedServiceIntefaces()); + return getServiceInterfaceAnnotations(implementedServiceIntefaces); + } + + private static Set getServiceInterfaceAnnotations(Set> implementedServiceIntefaces) { + Set> inspected = getAllAbstractServiceInterfaceClasses(implementedServiceIntefaces); + Set result = new HashSet<>(); + // SIs can form hierarchies, inspect superclass until it does not extend AbstractSI + for (Class clazz : inspected) { + ServiceInterfaceAnnotation annotation = clazz.getAnnotation(ServiceInterfaceAnnotation.class); + if (annotation != null) { + result.add(annotation); + } + } + return result; + } + + static Set> getAllAbstractServiceInterfaceClasses( + Set> directlyImplementedAbstractSIs) { + + Set> allInterfaces = getAllSuperInterfaces((Set) directlyImplementedAbstractSIs); + Set> result = new HashSet<>(); + for(Class ifc: allInterfaces){ + if (AbstractServiceInterface.class.isAssignableFrom(ifc) && + ifc.equals(AbstractServiceInterface.class) == false) { + result.add((Class) ifc); + } + + } + return result; + } } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java new file mode 100644 index 0000000000..e84337756e --- /dev/null +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java @@ -0,0 +1,42 @@ +/* + * 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.util; + +import org.opendaylight.controller.config.spi.ModuleFactory; +import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName; +import org.osgi.framework.BundleContext; + +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +public class ModuleQNameUtil { + + public static Set getQNames(Map> resolved) { + Set result = new HashSet<>(); + for (Entry entry : resolved.values()) { + Class inspected = entry.getKey().getClass(); + if (inspected.isInterface()) { + throw new IllegalArgumentException("Unexpected interface " + inspected); + } + ModuleQName annotation = null; + while(annotation == null && inspected != null) { + annotation = inspected.getAnnotation(ModuleQName.class); + inspected = inspected.getSuperclass(); + } + if (annotation != null) { + // FIXME + String qName = "(" + annotation.namespace() + "?revision=" + annotation.revision() + ")" + annotation.name(); + result.add(qName); + } + } + return result; + } + +} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/ConfigRegistryImplTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/ConfigRegistryImplTest.java index ccb67d371e..e6b07bab64 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/ConfigRegistryImplTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/ConfigRegistryImplTest.java @@ -40,7 +40,7 @@ public class ConfigRegistryImplTest extends factory, factory); configRegistry = new ConfigRegistryImpl(resolver, - context, ManagementFactory.getPlatformMBeanServer()); + ManagementFactory.getPlatformMBeanServer()); configRegistry.beginConfig(); fail(); 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 5ed56bd2bf..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, mockedContext, + 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/AbstractConfigWithJolokiaTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigWithJolokiaTest.java deleted file mode 100644 index de26220848..0000000000 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigWithJolokiaTest.java +++ /dev/null @@ -1,38 +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.config.manager.impl; - -import org.junit.After; -import org.junit.Before; -import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver; -import org.opendaylight.controller.config.util.JolokiaHelper; -import org.opendaylight.controller.config.util.jolokia.ConfigRegistryJolokiaClient; - -public class AbstractConfigWithJolokiaTest extends AbstractConfigTest { - protected String jolokiaURL; - protected ConfigRegistryJolokiaClient configRegistryJolokiaClient; - - @Before - public void initJolokia() { - jolokiaURL = JolokiaHelper.startTestingJolokia(); - } - - // this method should be called in @Before - @Override - protected void initConfigTransactionManagerImpl( - ModuleFactoriesResolver resolver) { - super.initConfigTransactionManagerImpl(resolver); - configRegistryJolokiaClient = new ConfigRegistryJolokiaClient( - jolokiaURL); - } - - @After - public void cleanUpJolokia() { - JolokiaHelper.stopJolokia(); - } -} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ClassBasedModuleFactory.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ClassBasedModuleFactory.java index d23b5ca128..672f150914 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ClassBasedModuleFactory.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ClassBasedModuleFactory.java @@ -13,6 +13,7 @@ import org.opendaylight.controller.config.api.DependencyResolverFactory; import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; import org.opendaylight.controller.config.api.ModuleIdentifier; import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; +import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.controller.config.spi.ModuleFactory; import org.osgi.framework.BundleContext; @@ -107,4 +108,9 @@ public class ClassBasedModuleFactory implements ModuleFactory { public Set getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext bundleContext) { return new HashSet(); } + + @Override + public Set> getImplementedServiceIntefaces() { + return InterfacesHelper.getAllAbstractServiceClasses(configBeanClass); + } } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImplLookupTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImplLookupTest.java index 6dddc62f67..a522356a27 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImplLookupTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImplLookupTest.java @@ -66,7 +66,7 @@ public class ConfigRegistryImplLookupTest extends @Before public void setUp() throws Exception { - configRegistryImpl = new ConfigRegistryImpl(null, null, + configRegistryImpl = new ConfigRegistryImpl(null, ManagementFactory.getPlatformMBeanServer()); Field field = configRegistryImpl.getClass().getDeclaredField( "baseJMXRegistrator"); diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImplTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImplTest.java index 22a959060c..50f5742149 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImplTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImplTest.java @@ -11,6 +11,7 @@ import com.google.common.collect.Sets; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry; 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.TransactionJMXRegistrator; @@ -61,13 +62,22 @@ public class ConfigTransactionControllerImplTest extends ManagementFactory.getPlatformMBeanServer()); transactionsMBeanServer = MBeanServerFactory.createMBeanServer(); Map> currentlyRegisteredFactories = new HashMap<>(); - TransactionJMXRegistrator jmxRegistrator123 = baseJMXRegistrator - .createTransactionJMXRegistrator(transactionName123); + + ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier(transactionName123), new TransactionJMXRegistratorFactory() { + @Override + public TransactionJMXRegistrator create() { + return baseJMXRegistrator.createTransactionJMXRegistrator(transactionName123); + } + }, currentlyRegisteredFactories); + + ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry( + ServiceReferenceRegistryImpl.createInitialSRLookupRegistry(), txLookupRegistry, currentlyRegisteredFactories); + testedTxController = new ConfigTransactionControllerImpl( - transactionName123, jmxRegistrator123, 1, 1, + txLookupRegistry, 1, 1, currentlyRegisteredFactories, transactionsMBeanServer, - ManagementFactory.getPlatformMBeanServer(), false); + ManagementFactory.getPlatformMBeanServer(), false, writableRegistry); TransactionModuleJMXRegistrator transactionModuleJMXRegistrator123 = testedTxController .getTxModuleJMXRegistrator(); transactionModuleJMXRegistrator123.registerMBean( diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionManagerImplTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionManagerImplTest.java index eaaee5eb5b..bbb3784b33 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionManagerImplTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionManagerImplTest.java @@ -7,23 +7,19 @@ */ package org.opendaylight.controller.config.manager.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; - -import javax.management.InstanceAlreadyExistsException; - import org.junit.Before; import org.junit.Test; -import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; -import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants; import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; -import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient; + +import javax.management.InstanceAlreadyExistsException; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; public class ConfigTransactionManagerImplTest extends - AbstractConfigWithJolokiaTest { + AbstractConfigTest { @Before public void setUp() { @@ -55,23 +51,4 @@ public class ConfigTransactionManagerImplTest extends transaction.commit(); } - @Test - public void testRemoteCallsUsingJolokia() throws Exception { - - ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient - .createTransaction(); - - assertEquals("ConfigTransaction-0-1", - ObjectNameUtil.getTransactionName(transactionClient - .getTransactionON())); - - assertEquals( - ConfigRegistryConstants.ON_DOMAIN - + ":TransactionName=ConfigTransaction-0-1,type=ConfigTransaction", - transactionClient.getTransactionON().getCanonicalName()); - - // commit - transactionClient.commit(); - - } } 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/dynamicmbean/AnnotationsTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsTest.java index cf6ed18c6c..75b0414711 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsTest.java @@ -97,7 +97,8 @@ public class AnnotationsTest { static final String SIMPLE = "simple"; static final String SUBCLASS2 = "subclass2"; - @ServiceInterfaceAnnotation(value = SIMPLE, osgiRegistrationType = Executor.class) + @ServiceInterfaceAnnotation(value = SIMPLE, osgiRegistrationType = Executor.class, + namespace = "ns", revision = "rev", localName = SIMPLE) static interface SimpleSI extends AbstractServiceInterface { } @@ -161,7 +162,9 @@ public class AnnotationsTest { } - @ServiceInterfaceAnnotation(value = SUBCLASS2, osgiRegistrationType = ExecutorService.class) + @ServiceInterfaceAnnotation(value = SUBCLASS2, osgiRegistrationType = ExecutorService.class, + namespace = "ns", revision = "rev", localName = SUBCLASS2) + static interface SubSI2 extends SubSI { } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java index 9a5452aa6c..22ea528030 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java @@ -9,11 +9,15 @@ package org.opendaylight.controller.config.manager.impl.util; import static org.junit.Assert.assertEquals; +import java.util.HashSet; import java.util.Set; import javax.management.MXBean; import org.junit.Test; +import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; +import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingScheduledThreadPoolServiceInterface; +import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingThreadPoolServiceInterface; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.yangtools.concepts.Identifiable; @@ -60,4 +64,17 @@ public class InterfacesHelperTest { assertEquals(expected, InterfacesHelper.getMXInterfaces(SubClass.class)); } + @Test + public void testGetAllAbstractServiceInterfaceClasses(){ + Class clazz = TestingScheduledThreadPoolServiceInterface.class; + Set> input = new HashSet<>(); + input.add(clazz); + Set> result = InterfacesHelper.getAllAbstractServiceInterfaceClasses(input); + + Set> expected = Sets.newHashSet((Class) TestingScheduledThreadPoolServiceInterface.class, + TestingThreadPoolServiceInterface.class + ); + assertEquals(expected, result); + } + } 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/TestingParallelAPSPConfigMXBean.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPConfigMXBean.java index 4fd2f5f1b5..9674a110ce 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPConfigMXBean.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPConfigMXBean.java @@ -11,7 +11,8 @@ import javax.management.ObjectName; import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; -@ServiceInterfaceAnnotation(value = TestingParallelAPSPConfigMXBean.NAME, osgiRegistrationType = TestingAPSP.class) +@ServiceInterfaceAnnotation(value = TestingParallelAPSPConfigMXBean.NAME, osgiRegistrationType = TestingAPSP.class, +namespace = "namespace", revision = "rev", localName = TestingParallelAPSPConfigMXBean.NAME) public interface TestingParallelAPSPConfigMXBean { static final String NAME = "apsp"; 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/TestingParallelAPSPModuleFactory.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModuleFactory.java index 3adf11484e..50a58792e1 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModuleFactory.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModuleFactory.java @@ -18,6 +18,7 @@ import org.osgi.framework.BundleContext; import javax.annotation.concurrent.ThreadSafe; import javax.management.ObjectName; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -69,4 +70,9 @@ public class TestingParallelAPSPModuleFactory implements ModuleFactory { public Set getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext context) { return new HashSet(); } + + @Override + public Set> getImplementedServiceIntefaces() { + return Collections.emptySet(); + } } 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 7deb1efb55..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 @@ -7,20 +7,20 @@ */ package org.opendaylight.controller.config.manager.testingservices.parallelapsp.test; -import javax.management.InstanceAlreadyExistsException; -import javax.management.ObjectName; - -import org.opendaylight.controller.config.manager.impl.AbstractConfigWithJolokiaTest; +import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPConfigMXBean; import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPModuleFactory; import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; -abstract class AbstractParallelAPSPTest extends AbstractConfigWithJolokiaTest { +import javax.management.InstanceAlreadyExistsException; +import javax.management.ObjectName; + +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 AbstractConfigWithJolokiaTest { 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 5b1a6f6e81..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 @@ -7,17 +7,6 @@ */ package org.opendaylight.controller.config.manager.testingservices.parallelapsp.test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.junit.internal.matchers.StringContains.containsString; - -import java.util.Map; - -import javax.management.ObjectName; - -import org.json.simple.JSONObject; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -32,7 +21,15 @@ import org.opendaylight.controller.config.manager.testingservices.threadpool.Tes import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean; import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; -import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient; + +import javax.management.ObjectName; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.internal.matchers.StringContains.containsString; public class DependentWiringTest extends AbstractParallelAPSPTest { private final String fixed1 = "fixed1"; @@ -51,7 +48,7 @@ public class DependentWiringTest extends AbstractParallelAPSPTest { } @Override - String getThreadPoolImplementationName() { + protected String getThreadPoolImplementationName() { return TestingFixedThreadPoolModuleFactory.NAME; } @@ -135,44 +132,4 @@ public class DependentWiringTest extends AbstractParallelAPSPTest { parallelAPSPRuntimeProxy.getMaxNumberOfThreads()); } - - @Test - public void testUsingJolokia() throws Exception { - - ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient - .createTransaction(); - // fixed1 - ObjectName fixed1ON = transactionClient.createModule( - getThreadPoolImplementationName(), fixed1); - transactionClient.setAttribute(fixed1ON, "ThreadCount", - TestingParallelAPSPImpl.MINIMAL_NUMBER_OF_THREADS); - - // apsp-parallel with syntetic attrib - String threadPoolString = "ThreadPool"; - ObjectName apsp1ON = transactionClient.createModule( - TestingParallelAPSPModuleFactory.NAME, apsp1); - transactionClient.setAttribute(apsp1ON, threadPoolString, fixed1ON); - // check - assertEquals(ObjectNameUtil.withoutTransactionName(fixed1ON), - transactionClient.getAttributeON(apsp1ON, threadPoolString)); - transactionClient.setAttribute(apsp1ON, "SomeParam", "ahoj"); - - // commit - transactionClient.commit(); - // check thread pool - assertEquals(1, TestingFixedThreadPool.allExecutors.size()); - // check platform MBeanServer - ObjectName apspReadOnlyON = ObjectNameUtil - .withoutTransactionName(apsp1ON); - JSONObject threadPoolONJson = (JSONObject) configRegistryJolokiaClient - .getAttribute(apspReadOnlyON, threadPoolString); - ObjectName fixed1ReadOnlyON = ObjectNameUtil - .withoutTransactionName(fixed1ON); - assertEquals(fixed1ReadOnlyON, ObjectNameUtil.createON(threadPoolONJson - .get("objectName").toString())); - assertEquals(fixed1ReadOnlyON, - configRegistryJolokiaClient.getAttributeON(apspReadOnlyON, - threadPoolString)); - - } } 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/scheduledthreadpool/TestingScheduledThreadPoolModuleFactory.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/scheduledthreadpool/TestingScheduledThreadPoolModuleFactory.java index 2e1047849e..e5306a4fa6 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/scheduledthreadpool/TestingScheduledThreadPoolModuleFactory.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/scheduledthreadpool/TestingScheduledThreadPoolModuleFactory.java @@ -7,6 +7,7 @@ */ package org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool; +import com.google.common.collect.Sets; import org.opendaylight.controller.config.api.DependencyResolver; import org.opendaylight.controller.config.api.DependencyResolverFactory; import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; @@ -18,16 +19,16 @@ import org.opendaylight.controller.config.spi.Module; import org.opendaylight.controller.config.spi.ModuleFactory; import org.osgi.framework.BundleContext; -import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; -import java.util.List; import java.util.Set; public class TestingScheduledThreadPoolModuleFactory implements ModuleFactory { public static final String NAME = "scheduled"; - private static List> ifc = Arrays - .asList(TestingScheduledThreadPoolServiceInterface.class, TestingThreadPoolServiceInterface.class); + private static Set> ifc = Collections.unmodifiableSet(Sets.newHashSet( + (Class) TestingScheduledThreadPoolServiceInterface.class, + TestingThreadPoolServiceInterface.class)); @Override public boolean isModuleImplementingServiceInterface( @@ -70,4 +71,11 @@ public class TestingScheduledThreadPoolModuleFactory implements ModuleFactory { public Set getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext bundleContext) { return new HashSet(); } + + @Override + public Set> getImplementedServiceIntefaces() { + return ifc; + } + + } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/ModifiableThreadPoolServiceInterface.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/ModifiableThreadPoolServiceInterface.java index ab1b6bd218..5c30d1e977 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/ModifiableThreadPoolServiceInterface.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/ModifiableThreadPoolServiceInterface.java @@ -10,7 +10,8 @@ package org.opendaylight.controller.config.manager.testingservices.seviceinterfa import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingModifiableThreadPoolIfc; -@ServiceInterfaceAnnotation(value = "modifiable-threadpool", osgiRegistrationType = TestingModifiableThreadPoolIfc.class) +@ServiceInterfaceAnnotation(value = "fqn:modifiable-threadpool", osgiRegistrationType = TestingModifiableThreadPoolIfc.class, + namespace = "foo", revision = "bar", localName = "modifiable-threadpool") public interface ModifiableThreadPoolServiceInterface extends TestingThreadPoolServiceInterface { } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/TestingScheduledThreadPoolServiceInterface.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/TestingScheduledThreadPoolServiceInterface.java index e4e388c610..5ddc1892e3 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/TestingScheduledThreadPoolServiceInterface.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/seviceinterface/TestingScheduledThreadPoolServiceInterface.java @@ -10,7 +10,8 @@ package org.opendaylight.controller.config.manager.testingservices.seviceinterfa import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; import org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool.TestingScheduledThreadPoolIfc; -@ServiceInterfaceAnnotation(value = "threadpool-scheduled", osgiRegistrationType = TestingScheduledThreadPoolIfc.class) +@ServiceInterfaceAnnotation(value = "threadpool-scheduled", osgiRegistrationType = TestingScheduledThreadPoolIfc.class, + namespace = "ns", revision = "rev", localName = "threadpool-scheduled") public interface TestingScheduledThreadPoolServiceInterface extends TestingThreadPoolServiceInterface { } 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 fd5ab1780d..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,7 +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) +@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-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java new file mode 100644 index 0000000000..0286400d7b --- /dev/null +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java @@ -0,0 +1,14 @@ +/* + * 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.testingservices.threadpool; + +import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName; + +@ModuleQName(namespace = "namespace", revision = "revision", name = "name") +public abstract class AbstractTestingFixedThreadPoolModuleFactory { +} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/TestingFixedThreadPoolModuleFactory.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/TestingFixedThreadPoolModuleFactory.java index cf05e44530..bec2868557 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/TestingFixedThreadPoolModuleFactory.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/TestingFixedThreadPoolModuleFactory.java @@ -7,6 +7,7 @@ */ package org.opendaylight.controller.config.manager.testingservices.threadpool; +import com.google.common.collect.Sets; import org.opendaylight.controller.config.api.DependencyResolver; import org.opendaylight.controller.config.api.DependencyResolverFactory; import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; @@ -18,15 +19,16 @@ import org.opendaylight.controller.config.spi.Module; import org.opendaylight.controller.config.spi.ModuleFactory; import org.osgi.framework.BundleContext; -import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; -import java.util.List; import java.util.Set; -public class TestingFixedThreadPoolModuleFactory implements ModuleFactory { +public class TestingFixedThreadPoolModuleFactory extends AbstractTestingFixedThreadPoolModuleFactory implements ModuleFactory { public static final String NAME = "fixed"; - private static List> ifc = Arrays - .asList(ModifiableThreadPoolServiceInterface.class, TestingThreadPoolServiceInterface.class); + + private static Set> ifc = Collections.unmodifiableSet(Sets.newHashSet( + (Class) ModifiableThreadPoolServiceInterface.class, + TestingThreadPoolServiceInterface.class)); @Override public String getImplementationName() { @@ -71,4 +73,9 @@ public class TestingFixedThreadPoolModuleFactory implements ModuleFactory { public Set getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext bundleContext) { return new HashSet(); } + + @Override + public Set> getImplementedServiceIntefaces() { + return ifc; + } } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java index c2f2558a5d..441de36db0 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java @@ -7,28 +7,7 @@ */ package org.opendaylight.controller.config.manager.testingservices.threadpool.test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.junit.matchers.JUnitMatchers.containsString; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ThreadPoolExecutor; - -import javax.management.DynamicMBean; -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.MBeanException; -import javax.management.ObjectName; -import javax.management.ReflectionException; -import javax.management.RuntimeMBeanException; - +import com.google.common.collect.Sets; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -37,14 +16,33 @@ import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace; import org.opendaylight.controller.config.api.jmx.CommitStatus; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; -import org.opendaylight.controller.config.manager.impl.AbstractConfigWithJolokiaTest; +import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool; import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean; import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; -import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient; + +import javax.management.DynamicMBean; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.RuntimeMBeanException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ThreadPoolExecutor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * Tests basic functionality of configuration registry: @@ -58,7 +56,7 @@ import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaC * Only one bean is being configured - {@link TestingThreadPoolIfc} which has no * dependencies. */ -public class SimpleConfigurationTest extends AbstractConfigWithJolokiaTest { +public class SimpleConfigurationTest extends AbstractConfigTest { private final int numberOfThreads = 5; private final int numberOfThreads2 = 10; private static final String fixed1 = "fixed1"; @@ -134,12 +132,6 @@ public class SimpleConfigurationTest extends AbstractConfigWithJolokiaTest { testValidation(transaction); } - @Test - public void testValidationUsingJolokiaClient() throws Exception { - ConfigTransactionClient transaction = configRegistryJolokiaClient - .createTransaction(); - testValidation(transaction); - } private void testValidation(ConfigTransactionClient transaction) throws InstanceAlreadyExistsException, ReflectionException, @@ -393,68 +385,12 @@ public class SimpleConfigurationTest extends AbstractConfigWithJolokiaTest { } } - @Test - public void testOptimisticLock_ConfigTransactionJolokiaClient() - throws Exception { - ConfigTransactionJolokiaClient transaction1 = configRegistryJolokiaClient - .createTransaction(); - ConfigTransactionJolokiaClient transaction2 = configRegistryJolokiaClient - .createTransaction(); - transaction2.assertVersion(0, 2); - transaction2.commit(); - try { - transaction1.commit(); - fail(); - } catch (ConflictingVersionException e) { - assertEquals( - "Optimistic lock failed. Expected parent version 2, was 0", - e.getMessage()); - } - } @Test - public void testOptimisticLock_ConfigRegistryJolokiaClient() - throws Exception { - ConfigTransactionJolokiaClient transaction1 = configRegistryJolokiaClient - .createTransaction(); - ConfigTransactionJolokiaClient transaction2 = configRegistryJolokiaClient - .createTransaction(); - transaction2.assertVersion(0, 2); - transaction2.commit(); - try { - configRegistryJolokiaClient.commitConfig(transaction1 - .getObjectName()); - fail(); - } catch (ConflictingVersionException e) { - assertEquals( - "Optimistic lock failed. Expected parent version 2, was 0", - e.getMessage()); - } - } - - @Test - public void testUsingJolokia() throws Exception { - ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient - .createTransaction(); - - ObjectName name = transactionClient.createModule( - TestingFixedThreadPoolModuleFactory.NAME, fixed1); - - try { - transactionClient.validateConfig(); - fail(); - } catch (ValidationException e) { - assertThat( - e.getMessage(), - containsString("Parameter 'threadCount' must be greater than 0")); - } - - transactionClient.setAttribute(name, "ThreadCount", numberOfThreads); - // commit - CommitStatus commitStatus = transactionClient.commit(); - CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil - .withoutTransactionName(name)), emptyONs, emptyONs); - assertEquals(expected, commitStatus); + public void testQNames() { + Set availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames(); + String expected = "(namespace?revision=revision)name"; + assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames); } } diff --git a/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java b/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java index 39595edb0b..a123eb981e 100644 --- a/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java +++ b/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java @@ -139,7 +139,7 @@ class MyLineProcessor implements com.google.common.io.LineProcessor { } private void checkFileConsistency(){ - checkState(inCapabilities, "File {} is missing delimiters in this order: {}", fileNameForReporting, + checkState(inCapabilities, "File %s is missing delimiters in this order: %s", fileNameForReporting, Arrays.asList(DirectoryPersister.MODULES_START, DirectoryPersister.SERVICES_START, DirectoryPersister.CAPABILITIES_START)); diff --git a/opendaylight/config/config-persister-directory-xml-adapter/pom.xml b/opendaylight/config/config-persister-directory-xml-adapter/pom.xml new file mode 100644 index 0000000000..b2ea632834 --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/pom.xml @@ -0,0 +1,115 @@ + + + 4.0.0 + + config-subsystem + org.opendaylight.controller + 0.2.3-SNAPSHOT + .. + + config-persister-directory-xml-adapter + ${project.artifactId} + bundle + + + + + ${project.groupId} + config-persister-api + + + org.apache.commons + commons-lang3 + + + com.google.guava + guava + + + org.opendaylight.controller + config-persister-file-xml-adapter + ${config.version} + + + + org.eclipse.persistence + org.eclipse.persistence.moxy + + + org.eclipse.persistence + org.eclipse.persistence.core + + + + org.slf4j + slf4j-api + + + commons-io + commons-io + + + + + org.opendaylight.bgpcep + mockito-configuration + test + + + + + + + + + org.codehaus.groovy.maven + gmaven-plugin + + + generate-sources + + execute + + + + System.setProperty("osgiversion", "${project.version}".replace('-', '.')) + + + + + + + org.apache.felix + maven-bundle-plugin + + + ${project.groupId}.config-persister-impl;bundle-version=${osgiversion} + + org.opendaylight.controller.config.persister.storage.adapter + + + com.google.common.base, + com.google.common.io, + org.apache.commons.io, + org.opendaylight.controller.config.persist.api, + org.slf4j, + com.google.common.collect, + javax.xml.bind, + javax.xml.bind.annotation, + javax.xml.transform, + javax.xml.transform.stream, + org.eclipse.persistence.jaxb, + org.apache.commons.lang3 + + + org.opendaylight.controller.config.persist.storage.file.xml.model, + + + + + + + + diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java new file mode 100644 index 0000000000..f6f6de9fd5 --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java @@ -0,0 +1,108 @@ +/* + * 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.persist.storage.directory.xml; + +import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; +import org.opendaylight.controller.config.persist.api.Persister; +import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.SortedSet; + +import static com.google.common.base.Preconditions.checkArgument; + +public class XmlDirectoryPersister implements Persister { + private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryPersister.class); + + private final File storage; + + public XmlDirectoryPersister(File storage) { + checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage); + this.storage = storage; + } + + @Override + public void persistConfig(ConfigSnapshotHolder holder) throws IOException { + throw new UnsupportedOperationException("This adapter is read only. Please set readonly=true on " + getClass()); + } + + @Override + public List loadLastConfigs() throws IOException { + File[] filesArray = storage.listFiles(); + if (filesArray == null || filesArray.length == 0) { + return Collections.emptyList(); + } + List sortedFiles = new ArrayList<>(Arrays.asList(filesArray)); + Collections.sort(sortedFiles); + // combine all found files + logger.debug("Reading files in following order: {}", sortedFiles); + + List result = new ArrayList<>(); + for (File file : sortedFiles) { + logger.trace("Adding file '{}' to combined result", file); + ConfigSnapshotHolder h = fromXmlSnapshot(file); + result.add(h); + } + return result; + } + + private ConfigSnapshotHolder fromXmlSnapshot(File file) { + try { + JAXBContext jaxbContext = JAXBContext.newInstance(ConfigSnapshot.class); + Unmarshaller um = jaxbContext.createUnmarshaller(); + + return asHolder((ConfigSnapshot) um.unmarshal(file)); + } catch (JAXBException e) { + logger.warn("Unable to restore configuration snapshot from {}", file, e); + throw new IllegalStateException("Unable to restore configuration snapshot from " + file, e); + } + } + + private ConfigSnapshotHolder asHolder(final ConfigSnapshot unmarshalled) { + return new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + return unmarshalled.getConfigSnapshot(); + } + + @Override + public SortedSet getCapabilities() { + return unmarshalled.getCapabilities(); + } + + @Override + public String toString() { + return unmarshalled.toString(); + } + }; + } + + + @Override + public void close() { + + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("XmlDirectoryPersister{"); + sb.append("storage=").append(storage); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java new file mode 100644 index 0000000000..ab6fb1577c --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java @@ -0,0 +1,39 @@ +/* + * 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.persist.storage.directory.xml; + +import com.google.common.base.Preconditions; +import org.opendaylight.controller.config.persist.api.Persister; +import org.opendaylight.controller.config.persist.api.PropertiesProvider; +import org.opendaylight.controller.config.persist.api.StorageAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +/** + * StorageAdapter that retrieves initial configuration from a directory. If multiple files are present, snapshot and + * required capabilities will be merged together. Writing to this persister is not supported. + */ +public class XmlDirectoryStorageAdapter implements StorageAdapter { + private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryStorageAdapter.class); + + public static final String DIRECTORY_STORAGE_PROP = "directoryStorage"; + + + @Override + public Persister instantiate(PropertiesProvider propertiesProvider) { + String fileStorageProperty = propertiesProvider.getProperty(DIRECTORY_STORAGE_PROP); + Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(DIRECTORY_STORAGE_PROP)); + File storage = new File(fileStorageProperty); + logger.debug("Using {}", storage); + return new XmlDirectoryPersister(storage); + } + +} diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java b/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java new file mode 100644 index 0000000000..73061f81de --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java @@ -0,0 +1,88 @@ +/* + * 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.persist.storage.directory.xml; + +import org.junit.Test; +import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; + +import java.io.File; +import java.util.Collections; +import java.util.List; +import java.util.SortedSet; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class DirectoryStorageAdapterTest { + XmlDirectoryPersister tested; + + @Test + public void testEmptyDirectory() throws Exception { + File folder = new File("target/emptyFolder"); + folder.mkdir(); + tested = new XmlDirectoryPersister((folder)); + assertEquals(Collections.emptyList(), tested.loadLastConfigs()); + + try { + tested.persistConfig(new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + throw new RuntimeException(); + } + + @Override + public SortedSet getCapabilities() { + throw new RuntimeException(); + } + }); + fail(); + } catch (UnsupportedOperationException e) { + + } + } + + private File getFolder(String folderName) { + File result = new File(("src/test/resources/" + + folderName).replace("/", File.separator)); + assertTrue(result + " is not a directory", result.isDirectory()); + return result; + } + + @Test + public void testOneFile() throws Exception { + File folder = getFolder("oneFile"); + tested = new XmlDirectoryPersister((folder)); + List results = tested.loadLastConfigs(); + assertEquals(1, results.size()); + ConfigSnapshotHolder result = results.get(0); + assertResult(result, "1", "cap1&rev", "cap2", "capa a"); + } + + private void assertResult(ConfigSnapshotHolder result, String s, String... caps) { + assertEquals(s, result.getConfigSnapshot().replaceAll("\\s", "")); + int i = 0; + for (String capFromSnapshot : result.getCapabilities()) { + assertEquals(capFromSnapshot, caps[i++]); + } + } + + @Test + public void testTwoFiles() throws Exception { + File folder = getFolder("twoFiles"); + tested = new XmlDirectoryPersister((folder)); + List results = tested.loadLastConfigs(); + assertEquals(2, results.size()); + + assertResult(results.get(0), "1", "cap1-a", "cap2-a", "capa a-a"); + assertResult(results.get(1), "2", "cap1-b", "cap2-b", "capa a-b"); + + } + +} diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/oneFile/controller.config.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/oneFile/controller.config.xml new file mode 100644 index 0000000000..aa8b14c9c4 --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/oneFile/controller.config.xml @@ -0,0 +1,10 @@ + + + cap1&rev + cap2 + capa a + + + 1 + + \ No newline at end of file diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config1.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config1.xml new file mode 100644 index 0000000000..28f112e4fa --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config1.xml @@ -0,0 +1,10 @@ + + + cap1-a + cap2-a + capa a-a + + + 1 + + \ No newline at end of file diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml new file mode 100644 index 0000000000..8fed29d182 --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml @@ -0,0 +1,10 @@ + + + cap1-b + cap2-b + capa a-b + + + 2 + + \ No newline at end of file diff --git a/opendaylight/config/config-persister-file-xml-adapter/pom.xml b/opendaylight/config/config-persister-file-xml-adapter/pom.xml new file mode 100644 index 0000000000..abbec382b7 --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + + config-subsystem + org.opendaylight.controller + 0.2.3-SNAPSHOT + .. + + config-persister-file-xml-adapter + ${project.artifactId} + bundle + + + + + ${project.groupId} + config-persister-api + + + org.apache.commons + commons-lang3 + + + com.google.guava + guava + + + org.slf4j + slf4j-api + + + + org.eclipse.persistence + org.eclipse.persistence.moxy + + + org.eclipse.persistence + org.eclipse.persistence.core + + + + + org.opendaylight.bgpcep + mockito-configuration + test + + + + + + + + org.codehaus.groovy.maven + gmaven-plugin + + + generate-sources + + execute + + + + System.setProperty("osgiversion", "${project.version}".replace('-', '.')) + + + + + + + org.apache.felix + maven-bundle-plugin + + + ${project.groupId}.config-persister-impl;bundle-version=${osgiversion} + + org.opendaylight.controller.config.persister.storage.adapter + + + + + + + + diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java new file mode 100644 index 0000000000..e75c62b81d --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java @@ -0,0 +1,149 @@ +/* + * 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.persist.storage.file.xml; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; +import org.opendaylight.controller.config.persist.api.Persister; +import org.opendaylight.controller.config.persist.api.PropertiesProvider; +import org.opendaylight.controller.config.persist.api.StorageAdapter; +import org.opendaylight.controller.config.persist.storage.file.xml.model.Config; +import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.SortedSet; + +/** + * StorageAdapter that stores configuration in an xml file. + */ +public class XmlFileStorageAdapter implements StorageAdapter, Persister { + private static final Logger logger = LoggerFactory.getLogger(XmlFileStorageAdapter.class); + + public static final String FILE_STORAGE_PROP = "fileStorage"; + public static final String NUMBER_OF_BACKUPS = "numberOfBackups"; + + private static Integer numberOfStoredBackups; + private File storage; + + @Override + public Persister instantiate(PropertiesProvider propertiesProvider) { + File storage = extractStorageFileFromProperties(propertiesProvider); + logger.debug("Using file {}", storage.getAbsolutePath()); + // Create file if it does not exist + File parentFile = storage.getAbsoluteFile().getParentFile(); + if (parentFile.exists() == false) { + logger.debug("Creating parent folders {}", parentFile); + parentFile.mkdirs(); + } + if (storage.exists() == false) { + logger.debug("Storage file does not exist, creating empty file"); + try { + boolean result = storage.createNewFile(); + if (result == false) + throw new RuntimeException("Unable to create storage file " + storage); + } catch (IOException e) { + throw new RuntimeException("Unable to create storage file " + storage, e); + } + } + if (numberOfStoredBackups == 0) { + throw new RuntimeException(NUMBER_OF_BACKUPS + + " property should be either set to positive value, or ommited. Can not be set to 0."); + } + setFileStorage(storage); + return this; + } + + @VisibleForTesting + public void setFileStorage(File storage) { + this.storage = storage; + } + + @VisibleForTesting + public void setNumberOfBackups(Integer numberOfBackups) { + numberOfStoredBackups = numberOfBackups; + } + + private static File extractStorageFileFromProperties(PropertiesProvider propertiesProvider) { + String fileStorageProperty = propertiesProvider.getProperty(FILE_STORAGE_PROP); + Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(FILE_STORAGE_PROP)); + File result = new File(fileStorageProperty); + String numberOfBackupsAsString = propertiesProvider.getProperty(NUMBER_OF_BACKUPS); + if (numberOfBackupsAsString != null) { + numberOfStoredBackups = Integer.valueOf(numberOfBackupsAsString); + } else { + numberOfStoredBackups = Integer.MAX_VALUE; + } + logger.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups); + return result; + } + + @Override + public void persistConfig(ConfigSnapshotHolder holder) throws IOException { + Preconditions.checkNotNull(storage, "Storage file is null"); + + Config cfg = Config.fromXml(storage); + cfg.addConfigSnapshot(ConfigSnapshot.fromConfigSnapshot(holder), numberOfStoredBackups); + cfg.toXml(storage); + } + + @Override + public List loadLastConfigs() throws IOException { + Preconditions.checkNotNull(storage, "Storage file is null"); + + if (!storage.exists()) { + return Collections.emptyList(); + } + + Optional lastSnapshot = Config.fromXml(storage).getLastSnapshot(); + + if (lastSnapshot.isPresent()) + return Lists.newArrayList(toConfigSnapshot(lastSnapshot.get())); + else + return Collections.emptyList(); + } + + + public ConfigSnapshotHolder toConfigSnapshot(final ConfigSnapshot configSnapshot) { + return new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + return configSnapshot.getConfigSnapshot(); + } + + @Override + public SortedSet getCapabilities() { + return configSnapshot.getCapabilities(); + } + + @Override + public String toString() { + return configSnapshot.toString(); + } + }; + } + + @Override + public void close() { + + } + + @Override + public String toString() { + return "XmlFileStorageAdapter [storage=" + storage + "]"; + } + +} diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java new file mode 100644 index 0000000000..d384df6989 --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java @@ -0,0 +1,47 @@ +/* + * 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.persist.storage.file.xml.model; + +import javax.xml.bind.ValidationEventHandler; +import javax.xml.bind.annotation.DomHandler; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import java.io.StringReader; +import java.io.StringWriter; + +class CapabilityHandler implements DomHandler { + + private static final String START_TAG = ""; + private static final String END_TAG = ""; + + private StringWriter xmlWriter = new StringWriter(); + + public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) { + xmlWriter.getBuffer().setLength(0); + return new StreamResult(xmlWriter); + } + + public String getElement(StreamResult rt) { + String xml = rt.getWriter().toString(); + int beginIndex = xml.indexOf(START_TAG) + START_TAG.length(); + int endIndex = xml.indexOf(END_TAG); + return xml.substring(beginIndex, endIndex); + } + + public Source marshal(String n, ValidationEventHandler errorHandler) { + try { + String xml = START_TAG + n.trim() + END_TAG; + StringReader xmlReader = new StringReader(xml); + return new StreamSource(xmlReader); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/Config.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/Config.java new file mode 100644 index 0000000000..fb84651ca1 --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/Config.java @@ -0,0 +1,109 @@ +/* + * 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.persist.storage.file.xml.model; + +import com.google.common.base.Charsets; +import com.google.common.base.Optional; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.io.Files; +import org.apache.commons.lang3.StringUtils; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.File; +import java.io.IOException; +import java.util.List; + +@XmlRootElement(name = "persisted-snapshots") +public final class Config { + + private List snapshots; + + Config(List snapshots) { + this.snapshots = snapshots; + } + + public Config() { + this.snapshots = Lists.newArrayList(); + } + + @XmlElement(name = "snapshot") + @XmlElementWrapper(name = "snapshots") + public List getSnapshots() { + return snapshots; + } + + public void setSnapshots(List snapshots) { + this.snapshots = snapshots; + } + + public void toXml(File to) { + try { + + // TODO Moxy has to be used instead of default jaxb impl due to a bug + // default implementation has a bug that prevents from serializing xml in a string + JAXBContext jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(new Class[]{Config.class}, null); + + Marshaller marshaller = jaxbContext.createMarshaller(); + + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + + marshaller.marshal(this, to); + } catch (JAXBException e) { + throw new PersistException("Unable to persist configuration", e); + } + } + + public static Config fromXml(File from) { + if(isEmpty(from)) + return new Config(); + + try { + JAXBContext jaxbContext = JAXBContext.newInstance(Config.class); + Unmarshaller um = jaxbContext.createUnmarshaller(); + + return (Config) um.unmarshal(from); + } catch (JAXBException e) { + throw new PersistException("Unable to restore configuration", e); + } + } + + private static boolean isEmpty(File from) { + return from.length() == 0 || isBlank(from); + } + + private static boolean isBlank(File from) { + try { + return StringUtils.isBlank(Files.toString(from, Charsets.UTF_8)); + } catch (IOException e) { + throw new IllegalStateException("Unexpected error reading file" + from, e); + } + } + + public Optional getLastSnapshot() { + ConfigSnapshot last = Iterables.getLast(snapshots, null); + return last == null ? Optional.absent() : Optional.of(last); + } + + public void addConfigSnapshot(ConfigSnapshot snap, int numberOfStoredBackups) { + if(shouldReplaceLast(numberOfStoredBackups) && snapshots.isEmpty() == false) { + snapshots.remove(0); + } + snapshots.add(snap); + } + + private boolean shouldReplaceLast(int numberOfStoredBackups) { + return numberOfStoredBackups == snapshots.size(); + } +} diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java new file mode 100644 index 0000000000..41976000ba --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java @@ -0,0 +1,63 @@ +/* + * 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.persist.storage.file.xml.model; + +import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; + +import javax.xml.bind.annotation.XmlAnyElement; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.SortedSet; + +@XmlRootElement(name = "snapshot") +public class ConfigSnapshot { + + private String configSnapshot; + private SortedSet capabilities; + + ConfigSnapshot(String configXml, SortedSet capabilities) { + this.configSnapshot = configXml; + this.capabilities = capabilities; + } + + public ConfigSnapshot() { + } + + public static ConfigSnapshot fromConfigSnapshot(ConfigSnapshotHolder cfg) { + return new ConfigSnapshot(cfg.getConfigSnapshot(), cfg.getCapabilities()); + } + + @XmlAnyElement(SnapshotHandler.class) + public String getConfigSnapshot() { + return configSnapshot; + } + + public void setConfigSnapshot(String configSnapshot) { + this.configSnapshot = configSnapshot; + } + + @XmlElement(name = "capability") + @XmlElementWrapper(name = "required-capabilities") + public SortedSet getCapabilities() { + return capabilities; + } + + public void setCapabilities(SortedSet capabilities) { + this.capabilities = capabilities; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("ConfigSnapshot{"); + sb.append("configSnapshot='").append(configSnapshot).append('\''); + sb.append(", capabilities=").append(capabilities); + sb.append('}'); + return sb.toString(); + } +} diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java new file mode 100644 index 0000000000..29d623274c --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java @@ -0,0 +1,15 @@ +/* + * 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.persist.storage.file.xml.model; + +final class PersistException extends RuntimeException { + + public PersistException(String s, Exception e) { + super(s, e); + } +} diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/SnapshotHandler.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/SnapshotHandler.java new file mode 100644 index 0000000000..dd39410409 --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/SnapshotHandler.java @@ -0,0 +1,47 @@ +/* + * 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.persist.storage.file.xml.model; + +import javax.xml.bind.ValidationEventHandler; +import javax.xml.bind.annotation.DomHandler; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import java.io.StringReader; +import java.io.StringWriter; + +class SnapshotHandler implements DomHandler { + + private static final String START_TAG = ""; + private static final String END_TAG = ""; + + private StringWriter xmlWriter = new StringWriter(); + + public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) { + xmlWriter.getBuffer().setLength(0); + return new StreamResult(xmlWriter); + } + + public String getElement(StreamResult rt) { + String xml = rt.getWriter().toString(); + int beginIndex = xml.indexOf(START_TAG) + START_TAG.length(); + int endIndex = xml.indexOf(END_TAG); + return xml.substring(beginIndex, endIndex); + } + + public Source marshal(String n, ValidationEventHandler errorHandler) { + try { + String xml = START_TAG + n.trim() + END_TAG; + StringReader xmlReader = new StringReader(xml); + return new StreamSource(xmlReader); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/xml/FileStorageAdapterTest.java b/opendaylight/config/config-persister-file-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/xml/FileStorageAdapterTest.java new file mode 100644 index 0000000000..d6bbeb31da --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/xml/FileStorageAdapterTest.java @@ -0,0 +1,188 @@ +/* + * 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.persist.storage.file.xml; + +import com.google.common.base.Charsets; +import junit.framework.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; + +import java.io.File; +import java.nio.file.Files; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import static junit.framework.Assert.assertFalse; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +public class FileStorageAdapterTest { + + private static int i; + private File file; + + @Before + public void setUp() throws Exception { + file = Files.createTempFile("testFilePersist", ".txt").toFile(); + if (!file.exists()) + return; + com.google.common.io.Files.write("", file, Charsets.UTF_8); + i = 1; + } + + @Test + public void testFileAdapter() throws Exception { + XmlFileStorageAdapter storage = new XmlFileStorageAdapter(); + storage.setFileStorage(file); + storage.setNumberOfBackups(Integer.MAX_VALUE); + final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + return createConfig(); + } + + @Override + public SortedSet getCapabilities() { + return createCaps(); + } + }; + storage.persistConfig(holder); + + storage.persistConfig(holder); + + assertEquals(27, com.google.common.io.Files.readLines(file, Charsets.UTF_8).size()); + List lastConf = storage.loadLastConfigs(); + assertEquals(1, lastConf.size()); + ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0); + assertEquals("2", + configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", "")); + assertEquals(createCaps(), configSnapshotHolder.getCapabilities()); + + storage = new XmlFileStorageAdapter(); + storage.setFileStorage(file); + storage.setNumberOfBackups(Integer.MAX_VALUE); + + List last = storage.loadLastConfigs(); + Assert.assertEquals(createCaps(), last.get(0).getCapabilities()); + } + + private SortedSet createCaps() { + SortedSet caps = new TreeSet<>(); + + caps.add("cap1" + i); + caps.add("cap2" + i); + caps.add("urn:opendaylight:params:xml:ns:yang:controller:netty?module=netty&revision=2013-11-19" + i); + caps.add("capaaaa as dasfasdf s2" + i); + return caps; + } + + @Test + public void testFileAdapterOneBackup() throws Exception { + XmlFileStorageAdapter storage = new XmlFileStorageAdapter(); + storage.setFileStorage(file); + storage.setNumberOfBackups(1); + final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + return createConfig(); + } + + @Override + public SortedSet getCapabilities() { + return createCaps(); + } + }; + storage.persistConfig(holder); + + storage.persistConfig(holder); + + assertEquals(16, com.google.common.io.Files.readLines(file, Charsets.UTF_8).size()); + + List lastConf = storage.loadLastConfigs(); + assertEquals(1, lastConf.size()); + ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0); + assertEquals("2", + configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", "")); + } + + @Test + public void testFileAdapterOnlyTwoBackups() throws Exception { + XmlFileStorageAdapter storage = new XmlFileStorageAdapter(); + storage.setFileStorage(file); + storage.setNumberOfBackups(2); + final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + return createConfig(); + } + + @Override + public SortedSet getCapabilities() { + return createCaps(); + } + }; + storage.persistConfig(holder); + + storage.persistConfig(holder); + storage.persistConfig(holder); + + List readLines = com.google.common.io.Files.readLines(file, Charsets.UTF_8); + assertEquals(27, readLines.size()); + + List lastConf = storage.loadLastConfigs(); + assertEquals(1, lastConf.size()); + ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0); + assertEquals("3", + configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", "")); + assertFalse(readLines.contains(holder.getConfigSnapshot())); + } + + @Test + public void testNoLastConfig() throws Exception { + File file = Files.createTempFile("testFilePersist", ".txt").toFile(); + if (!file.exists()) + return; + XmlFileStorageAdapter storage = new XmlFileStorageAdapter(); + storage.setFileStorage(file); + + List elementOptional = storage.loadLastConfigs(); + assertThat(elementOptional.size(), is(0)); + } + + @Test(expected = NullPointerException.class) + public void testNoProperties() throws Exception { + XmlFileStorageAdapter storage = new XmlFileStorageAdapter(); + storage.loadLastConfigs(); + } + + @Test(expected = NullPointerException.class) + public void testNoProperties2() throws Exception { + XmlFileStorageAdapter storage = new XmlFileStorageAdapter(); + storage.persistConfig(new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + return Mockito.mock(String.class); + } + + @Override + public SortedSet getCapabilities() { + return new TreeSet<>(); + } + } ); + } + + static String createConfig() { + return "" + i++ + ""; + } + +} diff --git a/opendaylight/config/config-util/pom.xml b/opendaylight/config/config-util/pom.xml index 206184ccce..23603ae626 100644 --- a/opendaylight/config/config-util/pom.xml +++ b/opendaylight/config/config-util/pom.xml @@ -17,16 +17,6 @@ ${project.groupId} config-api - - org.jolokia - jolokia-client-java - - - org.jolokia - jolokia-jvm - agent - - com.google.guava 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 3a1efaeaaf..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 @@ -7,9 +7,11 @@ */ package org.opendaylight.controller.config.util; -import java.util.Arrays; -import java.util.List; -import java.util.Set; +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.ConfigRegistryMXBean; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; @@ -20,15 +22,13 @@ import javax.management.MBeanServer; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.ReflectionException; - -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.ConfigRegistryMXBean; -import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; public class ConfigRegistryJMXClient implements ConfigRegistryClient { - private final ConfigRegistryMXBean configRegistryProxy; + private final ConfigRegistryMXBean configRegistryMXBeanProxy; private final ObjectName configRegistryON; private final MBeanServer configMBeanServer; @@ -40,7 +40,7 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient { if (!(searchResult.size() == 1)) { throw new IllegalStateException("Config registry not found"); } - configRegistryProxy = JMX.newMXBeanProxy(configMBeanServer, configRegistryON, ConfigRegistryMXBean.class, + configRegistryMXBeanProxy = JMX.newMXBeanProxy(configMBeanServer, configRegistryON, ConfigRegistryMXBean.class, false); } @@ -61,7 +61,7 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient { @Override public ConfigTransactionJMXClient getConfigTransactionClient( ObjectName objectName) { - return new ConfigTransactionJMXClient(configRegistryProxy, objectName, + return new ConfigTransactionJMXClient(configRegistryMXBeanProxy, objectName, configMBeanServer); } @@ -75,18 +75,18 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient { @Override public ObjectName beginConfig() { - return configRegistryProxy.beginConfig(); + return configRegistryMXBeanProxy.beginConfig(); } @Override public CommitStatus commitConfig(ObjectName transactionControllerON) throws ConflictingVersionException, ValidationException { - return configRegistryProxy.commitConfig(transactionControllerON); + return configRegistryMXBeanProxy.commitConfig(transactionControllerON); } @Override public List getOpenConfigs() { - return configRegistryProxy.getOpenConfigs(); + return configRegistryMXBeanProxy.getOpenConfigs(); } @Override @@ -101,45 +101,75 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient { @Override public Set getAvailableModuleNames() { - return configRegistryProxy.getAvailableModuleNames(); + return configRegistryMXBeanProxy.getAvailableModuleNames(); } @Override public boolean isHealthy() { - return configRegistryProxy.isHealthy(); + return configRegistryMXBeanProxy.isHealthy(); } @Override public Set lookupConfigBeans() { - return configRegistryProxy.lookupConfigBeans(); + return configRegistryMXBeanProxy.lookupConfigBeans(); } @Override public Set lookupConfigBeans(String moduleName) { - return configRegistryProxy.lookupConfigBeans(moduleName); + return configRegistryMXBeanProxy.lookupConfigBeans(moduleName); } @Override public Set lookupConfigBeans(String moduleName, String instanceName) { - return configRegistryProxy.lookupConfigBeans(moduleName, instanceName); + return configRegistryMXBeanProxy.lookupConfigBeans(moduleName, instanceName); } @Override public ObjectName lookupConfigBean(String moduleName, String instanceName) throws InstanceNotFoundException { - return configRegistryProxy.lookupConfigBean(moduleName, instanceName); + return configRegistryMXBeanProxy.lookupConfigBean(moduleName, instanceName); } @Override public Set lookupRuntimeBeans() { - return configRegistryProxy.lookupRuntimeBeans(); + return configRegistryMXBeanProxy.lookupRuntimeBeans(); } @Override public Set lookupRuntimeBeans(String ifcName, String instanceName) { - return configRegistryProxy.lookupRuntimeBeans(ifcName, instanceName); + return configRegistryMXBeanProxy.lookupRuntimeBeans(ifcName, instanceName); + } + + @Override + public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException { + configRegistryMXBeanProxy.checkConfigBeanExists(objectName); + } + + @Override + public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { + return configRegistryMXBeanProxy.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName); + } + + @Override + public Map> getServiceMapping() { + return configRegistryMXBeanProxy.getServiceMapping(); + } + + @Override + public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { + return configRegistryMXBeanProxy.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName); + } + + @Override + public Set lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException { + return configRegistryMXBeanProxy.lookupServiceInterfaceNames(objectName); + } + + @Override + public String getServiceInterfaceName(String namespace, String localName) { + return configRegistryMXBeanProxy.getServiceInterfaceName(namespace, localName); } @Override @@ -167,4 +197,19 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient { } } + @Override + 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 548c0e9ea4..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 @@ -7,6 +7,7 @@ */ package org.opendaylight.controller.config.util; +import java.util.Map; import java.util.Set; import javax.management.Attribute; @@ -26,19 +27,19 @@ import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXB import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; public class ConfigTransactionJMXClient implements ConfigTransactionClient { - private final ConfigRegistryMXBean configTransactionManagerProxy; + private final ConfigRegistryMXBean configRegistryMXBeanProxy; private final ObjectName configTransactionControllerON; - private final ConfigTransactionControllerMXBean configControllerProxy; + private final ConfigTransactionControllerMXBean configTransactionControllerMXBeanProxy; private final MBeanServer configMBeanServer; public ConfigTransactionJMXClient( - ConfigRegistryMXBean configTransactionManagerProxy, + ConfigRegistryMXBean configRegistryMXBeanProxy, ObjectName configTransactionControllerON, MBeanServer configMBeanServer) { this.configMBeanServer = configMBeanServer; - this.configTransactionManagerProxy = configTransactionManagerProxy; + this.configRegistryMXBeanProxy = configRegistryMXBeanProxy; this.configTransactionControllerON = configTransactionControllerON; - this.configControllerProxy = JMX.newMXBeanProxy(configMBeanServer, + this.configTransactionControllerMXBeanProxy = JMX.newMXBeanProxy(configMBeanServer, configTransactionControllerON, ConfigTransactionControllerMXBean.class); } @@ -54,7 +55,7 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { @Override public CommitStatus commit() throws ConflictingVersionException, ValidationException { - return configTransactionManagerProxy + return configRegistryMXBeanProxy .commitConfig(configTransactionControllerON); } @@ -73,13 +74,13 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { @Override public ObjectName createModule(String moduleName, String instanceName) throws InstanceAlreadyExistsException { - return configControllerProxy.createModule(moduleName, instanceName); + return configTransactionControllerMXBeanProxy.createModule(moduleName, instanceName); } @Override public void destroyModule(ObjectName objectName) throws InstanceNotFoundException { - configControllerProxy.destroyModule(objectName); + configTransactionControllerMXBeanProxy.destroyModule(objectName); } @Override @@ -91,12 +92,12 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { @Override public void abortConfig() { - configControllerProxy.abortConfig(); + configTransactionControllerMXBeanProxy.abortConfig(); } @Override public void validateConfig() throws ValidationException { - configControllerProxy.validateConfig(); + configTransactionControllerMXBeanProxy.validateConfig(); } @Override @@ -121,12 +122,12 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { @Override public String getTransactionName() { - return configControllerProxy.getTransactionName(); + return configTransactionControllerMXBeanProxy.getTransactionName(); } @Override public Set getAvailableModuleNames() { - return configControllerProxy.getAvailableModuleNames(); + return configTransactionControllerMXBeanProxy.getAvailableModuleNames(); } @Override @@ -136,27 +137,87 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { @Override public Set lookupConfigBeans() { - return configControllerProxy.lookupConfigBeans(); + return configTransactionControllerMXBeanProxy.lookupConfigBeans(); } @Override public Set lookupConfigBeans(String moduleName) { - return configControllerProxy.lookupConfigBeans(moduleName); + return configTransactionControllerMXBeanProxy.lookupConfigBeans(moduleName); } @Override public ObjectName lookupConfigBean(String moduleName, String instanceName) throws InstanceNotFoundException { - return configControllerProxy.lookupConfigBean(moduleName, instanceName); + return configTransactionControllerMXBeanProxy.lookupConfigBean(moduleName, instanceName); } @Override public Set lookupConfigBeans(String moduleName, String instanceName) { - return configControllerProxy + return configTransactionControllerMXBeanProxy .lookupConfigBeans(moduleName, instanceName); } + @Override + public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException { + configTransactionControllerMXBeanProxy.checkConfigBeanExists(objectName); + } + + @Override + public ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException { + return configTransactionControllerMXBeanProxy.saveServiceReference(serviceInterfaceName,refName, moduleON); + } + + @Override + public void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException{ + configTransactionControllerMXBeanProxy.removeServiceReference(serviceInterfaceName, refName); + } + + @Override + public void removeAllServiceReferences() { + configTransactionControllerMXBeanProxy.removeAllServiceReferences(); + } + + @Override + public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { + return configTransactionControllerMXBeanProxy.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName); + } + + @Override + public Map> getServiceMapping() { + return configTransactionControllerMXBeanProxy.getServiceMapping(); + } + + @Override + public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { + return configTransactionControllerMXBeanProxy.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName); + } + + @Override + public Set lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException { + return configTransactionControllerMXBeanProxy.lookupServiceInterfaceNames(objectName); + } + + @Override + public String getServiceInterfaceName(String namespace, String localName) { + return configTransactionControllerMXBeanProxy.getServiceInterfaceName(namespace, localName); + } + + @Override + public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException { + 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 { @@ -182,4 +243,9 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { + attrName + " for " + on, e); } } + + @Override + public Set getAvailableModuleFactoryQNames() { + return configTransactionControllerMXBeanProxy.getAvailableModuleFactoryQNames(); + } } diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ConfigRegistryJolokiaClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ConfigRegistryJolokiaClient.java deleted file mode 100644 index f29f0e03ac..0000000000 --- a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ConfigRegistryJolokiaClient.java +++ /dev/null @@ -1,139 +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.config.util.jolokia; - -import java.util.List; -import java.util.Set; - -import javax.management.ObjectName; - -import org.jolokia.client.request.J4pExecRequest; -import org.jolokia.client.request.J4pReadRequest; -import org.jolokia.client.request.J4pResponse; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -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.ConfigRegistryMXBean; -import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; -import org.opendaylight.controller.config.util.ConfigRegistryClient; - -public class ConfigRegistryJolokiaClient extends ListableJolokiaClient - implements ConfigRegistryClient { - - public ConfigRegistryJolokiaClient(String url) { - super(url, ConfigRegistryMXBean.OBJECT_NAME); - } - - @Override - public ConfigTransactionJolokiaClient createTransaction() { - // create transaction - J4pExecRequest execReq = new J4pExecRequest(objectName, "beginConfig"); - J4pResponse resp = execute(execReq); - ObjectName transactionControllerON = extractObjectName(resp); - return getConfigTransactionClient(transactionControllerON); - } - - @Override - public ConfigTransactionJolokiaClient getConfigTransactionClient( - String transactionName) { - ObjectName objectName = ObjectNameUtil - .createTransactionControllerON(transactionName); - return getConfigTransactionClient(objectName); - } - - @Override - public ConfigTransactionJolokiaClient getConfigTransactionClient( - ObjectName objectName) { - return new ConfigTransactionJolokiaClient(url, objectName, this); - } - - @Override - public CommitStatus commitConfig(ObjectName transactionControllerON) - throws ConflictingVersionException, ValidationException { - J4pExecRequest execReq = new J4pExecRequest(objectName, "commitConfig", - transactionControllerON); - JSONObject jsonObject; - jsonObject = execute(execReq).getValue(); - JSONArray newInstancesArray = (JSONArray) jsonObject - .get("newInstances"); - List newInstances = jsonArrayToObjectNames(newInstancesArray); - JSONArray reusedInstancesArray = (JSONArray) jsonObject - .get("reusedInstances"); - List reusedInstances = jsonArrayToObjectNames(reusedInstancesArray); - JSONArray recreatedInstancesArray = (JSONArray) jsonObject - .get("recreatedInstances"); - List recreatedInstances = jsonArrayToObjectNames(recreatedInstancesArray); - return new CommitStatus(newInstances, reusedInstances, - recreatedInstances); - } - - public Object getAttribute(ObjectName configBeanTransactionON, String key) { - J4pReadRequest req = new J4pReadRequest(configBeanTransactionON, key); - return execute(req).getValue(); - } - - public ObjectName getAttributeON(ObjectName configBeanTransactionON, - String key) { - JSONObject jsonAttrib = (JSONObject) getAttribute( - configBeanTransactionON, key); - return extractObjectName(jsonAttrib); - } - - // proxy around ConfigTransactionManagerMXBean - - @Override - public ObjectName beginConfig() { - ConfigTransactionJolokiaClient result = createTransaction(); - return result.getTransactionON(); - } - - @Override - public List getOpenConfigs() { - J4pReadRequest req = new J4pReadRequest(objectName, "OpenConfigs"); - JSONArray jsonArray = execute(req).getValue(); - return jsonArrayToObjectNames(jsonArray); - } - - @Override - public long getVersion() { - J4pReadRequest req = new J4pReadRequest(objectName, "Version"); - return (Long) execute(req).getValue(); - } - - @Override - public boolean isHealthy() { - J4pReadRequest req = new J4pReadRequest(objectName, "Healthy"); - return (Boolean) execute(req).getValue(); - } - - @Override - public Set lookupRuntimeBeans() { - return lookupSomething("lookupRuntimeBeans()", new Object[0]); - } - - @Override - public Set lookupRuntimeBeans(String moduleName, - String instanceName) { - return lookupSomething( - "lookupRuntimeBeans(java.lang.String,java.lang.String)", - new Object[] { moduleName, instanceName }); - } - - @Override - public Object invokeMethod(ObjectName on, String name, Object[] params, - String[] signature) { - throw new UnsupportedOperationException(); - } - - @Override - public Object getAttributeCurrentValue(ObjectName on, String attributeName) { - throw new UnsupportedOperationException(); - } -} diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ConfigTransactionJolokiaClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ConfigTransactionJolokiaClient.java deleted file mode 100644 index f4824cd794..0000000000 --- a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ConfigTransactionJolokiaClient.java +++ /dev/null @@ -1,165 +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.config.util.jolokia; - -import java.util.Map; - -import javax.management.Attribute; -import javax.management.AttributeNotFoundException; -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.ObjectName; - -import org.jolokia.client.request.J4pExecRequest; -import org.jolokia.client.request.J4pReadRequest; -import org.jolokia.client.request.J4pWriteRequest; -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.util.AttributeEntry; -import org.opendaylight.controller.config.util.ConfigTransactionClient; - -public class ConfigTransactionJolokiaClient extends ListableJolokiaClient - implements ConfigTransactionClient { - - private final ConfigRegistryJolokiaClient configRegistryJolokiaClient; - - public ConfigTransactionJolokiaClient(String url, - ObjectName transactionControllerON, - ConfigRegistryJolokiaClient configRegistryJolokiaClient) { - super(url, transactionControllerON); - this.configRegistryJolokiaClient = configRegistryJolokiaClient; - } - - public ObjectName getTransactionON() { - return objectName; - } - - @Override - public CommitStatus commit() throws ConflictingVersionException, - ValidationException { - return configRegistryJolokiaClient.commitConfig(objectName); - } - - @Override - public ObjectName createModule(String moduleName, String instanceName) - throws InstanceAlreadyExistsException { - J4pExecRequest execReq = new J4pExecRequest(objectName, "createModule", - moduleName, instanceName); - try { - return extractObjectName(execute(execReq)); - } catch (RuntimeException e) { - if (e.getMessage() != null - && e.getMessage().startsWith( - InstanceAlreadyExistsException.class.getName())) - throw new InstanceAlreadyExistsException(); - throw e; - } - } - - @Override - public void destroyModule(ObjectName configBeanON) { - J4pExecRequest execReq = new J4pExecRequest(objectName, - "destroyModule(javax.management.ObjectName)", configBeanON); - execute(execReq); - } - - @Override - public void destroyConfigBean(String moduleName, String instanceName) - throws InstanceNotFoundException { - destroyModule(ObjectNameUtil.createTransactionModuleON( - getTransactionName(), moduleName, instanceName)); - } - - @Override - public void abortConfig() { - J4pExecRequest execReq = new J4pExecRequest(objectName, "abortConfig"); - execute(execReq); - } - - @Override - public void validateConfig() throws ValidationException { - J4pExecRequest execReq = new J4pExecRequest(objectName, - "validateConfig"); - execute(execReq); - } - - @Override - public long getParentVersion() { - J4pReadRequest req = new J4pReadRequest(objectName, "ParentVersion"); - return (Long) execute(req).getValue(); - } - - @Override - public long getVersion() { - J4pReadRequest req = new J4pReadRequest(objectName, "Version"); - return (Long) execute(req).getValue(); - } - - public void setAttribute(ObjectName configBeanTransactionON, String key, - Object value) { - J4pWriteRequest req = new J4pWriteRequest(configBeanTransactionON, key, - value); - try { - execute(req); - } catch (RuntimeException e) { - if (e.getMessage() != null - && e.getMessage().startsWith( - AttributeNotFoundException.class.getName())) { - // try to fix wrong case - Map allAttributes = getAttributes(configBeanTransactionON); - for (AttributeEntry attrib : allAttributes.values()) { - if (attrib.getKey().equalsIgnoreCase(key)) { - req = new J4pWriteRequest(configBeanTransactionON, - attrib.getKey(), value); - execute(req); - return; - } - } - } - throw e; - } - } - - public Object getAttribute(ObjectName objectName, String key) { - return configRegistryJolokiaClient.getAttribute(objectName, key); - } - - public ObjectName getAttributeON(ObjectName objectName, String key) { - return configRegistryJolokiaClient.getAttributeON(objectName, key); - } - - @Override - public String getTransactionName() { - return ObjectNameUtil.getTransactionName(objectName); - } - - @Override - public void validateBean(ObjectName rwON) throws ValidationException { - J4pExecRequest req = new J4pExecRequest(rwON, "validate", new Object[0]); - execute(req); - } - - @Override - public void assertVersion(int expectedParentVersion, - int expectedCurrentVersion) { - if (expectedParentVersion != getParentVersion()) { - throw new IllegalStateException(); - } - if (expectedCurrentVersion != getVersion()) { - throw new IllegalStateException(); - } - } - - @Override - public void setAttribute(ObjectName on, String jmxName, Attribute attribute) { - throw new UnsupportedOperationException(); - } - -} diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ListableJolokiaClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ListableJolokiaClient.java deleted file mode 100644 index 6277f6a0e6..0000000000 --- a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/jolokia/ListableJolokiaClient.java +++ /dev/null @@ -1,275 +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.config.util.jolokia; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.regex.Pattern; - -import javax.management.InstanceNotFoundException; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; - -import org.jolokia.client.J4pClient; -import org.jolokia.client.exception.J4pException; -import org.jolokia.client.exception.J4pRemoteException; -import org.jolokia.client.request.J4pExecRequest; -import org.jolokia.client.request.J4pListRequest; -import org.jolokia.client.request.J4pQueryParameter; -import org.jolokia.client.request.J4pReadRequest; -import org.jolokia.client.request.J4pRequest; -import org.jolokia.client.request.J4pResponse; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.opendaylight.controller.config.api.ConflictingVersionException; -import org.opendaylight.controller.config.api.ValidationException; -import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace; -import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; -import org.opendaylight.controller.config.util.AttributeEntry; - -abstract class ListableJolokiaClient { - protected final J4pClient j4pClient; - protected final String url; - protected final ObjectName objectName; - - public ListableJolokiaClient(String url, ObjectName objectName) { - if (url == null) { - throw new NullPointerException("Parameter 'url' is null"); - } - if (!url.endsWith("/")) { - throw new IllegalArgumentException( - "Parameter 'url' must end with '/'"); - } - - this.url = url; - this.j4pClient = new J4pClient(url); - this.objectName = objectName; - } - - public ObjectName getObjectName() { - return objectName; - } - - protected , T extends J4pRequest> R execute( - T pRequest) { - try { - Map pProcessingOptions = new HashMap(); - pProcessingOptions - .put(J4pQueryParameter.INCLUDE_STACKTRACE, "true"); - pProcessingOptions.put(J4pQueryParameter.SERIALIZE_EXCEPTION, - "true"); - return j4pClient.execute(pRequest, "POST", pProcessingOptions); - } catch (J4pRemoteException e) { - tryToConvertException(e.getRemoteStackTrace(), e.getErrorValue()); - throw new RuntimeException(e.getRemoteStackTrace(), e); - } catch (J4pException e) { - throw new RuntimeException(e); - } - } - - protected void tryToConvertException(String remoteStackTrace, - JSONObject errorValue) { - String conflictPrefix = ConflictingVersionException.class.getName() - + ": "; - if (remoteStackTrace.startsWith(conflictPrefix)) { - remoteStackTrace = remoteStackTrace.substring(conflictPrefix - .length()); - Pattern p = Pattern.compile("\r?\n"); - remoteStackTrace = Arrays.asList(p.split(remoteStackTrace)) - .iterator().next(); - throw new ConflictingVersionException(remoteStackTrace); - } - String validationExceptionPrefix = ValidationException.class.getName(); - if (remoteStackTrace.startsWith(validationExceptionPrefix)) { - throw createValidationExceptionFromJSONObject(errorValue); - } - } - - static ValidationException createValidationExceptionFromJSONObject( - JSONObject errorValue) { - String fValsKey = "failedValidations"; - JSONObject failedVals = (JSONObject) errorValue.get(fValsKey); - - checkArgument( - !failedVals.isEmpty(), - fValsKey + " was not present in received JSON: " - + errorValue.toJSONString()); - Map> failedValsMap = new HashMap>(); - - for (Object key : failedVals.keySet()) { - checkArgument(key instanceof String, "Unexpected key " + key - + ", expected instance of String"); - Map innerMap = new HashMap(); - for (Object innerKey : ((JSONObject) failedVals.get(key)).keySet()) { - checkArgument(innerKey instanceof String, "Unexpected key " - + innerKey + ", expected instance of String"); - JSONObject exWithStackTraceVal = (JSONObject) (((JSONObject) failedVals - .get(key)).get(innerKey)); - Object mess = exWithStackTraceVal.get("message"); - Object stack = exWithStackTraceVal.get("trace"); - checkArgument(mess != null && stack != null, - "\"Message\" and \"trace\" elements expected in received json: " - + errorValue.toJSONString()); - innerMap.put(innerKey.toString(), - new ExceptionMessageWithStackTrace((String) mess, - (String) stack)); - } - failedValsMap.put((String) key, innerMap); - } - return new ValidationException(failedValsMap); - } - - private static void checkArgument(boolean b, String string) { - if (b == false) - throw new IllegalArgumentException(string); - } - - public String getUrl() { - return url; - } - - public Map getAttributes(ObjectName on) { - J4pListRequest req = new J4pListRequest(on); - J4pResponse response = execute(req); - JSONObject listJSONResponse = response.getValue(); - JSONObject attributes = (JSONObject) listJSONResponse.get("attr"); - - // Empty attributes list - if(attributes == null) - return Collections.emptyMap(); - - Map listMap = new HashMap<>(); - - for (Object entryObject : attributes.entrySet()) { - Entry entry = (Entry) entryObject; - JSONObject entryVal = (JSONObject) entry.getValue(); - - // read value - listMap.put(entry.getKey(), entryVal); - } - J4pReadRequest j4pReadRequest = new J4pReadRequest(on, listMap.keySet() - .toArray(new String[0])); - J4pResponse readResponse = execute(j4pReadRequest); - Object readResponseValue = readResponse.getValue(); - // readResponseValue can be String if there is just one attribute or - // JSONObject - Map attribsToValues = new HashMap(); - if (readResponseValue instanceof JSONObject) { - JSONObject readJSONResponse = (JSONObject) readResponseValue; - for (Object entryObject : readJSONResponse.entrySet()) { - Entry entry = (Entry) entryObject; - String key = entry.getKey(); - Object value = entry.getValue(); - attribsToValues.put(key, value); - } - } - - Map resultMap = new HashMap(); - for (Entry entry : listMap.entrySet()) { - String key = entry.getKey(); - Object value = attribsToValues.size() > 0 ? attribsToValues - .get(key) : readResponseValue; - JSONObject listJSON = entry.getValue(); - String description = (String) listJSON.get("desc"); - String type = (String) listJSON.get("type"); - boolean rw = (Boolean) listJSON.get("rw"); - AttributeEntry attributeEntry = new AttributeEntry(key, - description, value, type, rw); - resultMap.put(key, attributeEntry); - } - - return resultMap; - } - - public String getConfigBeanDescripton(ObjectName on) { - J4pListRequest req = new J4pListRequest(on); - J4pResponse response = execute(req); - JSONObject jsonDesc = response.getValue(); - Object description = jsonDesc.get("desc"); - return description == null ? null : description.toString(); - } - - protected List jsonArrayToObjectNames(JSONArray jsonArray) { - List result = new ArrayList<>(jsonArray.size()); - for (Object entry : jsonArray) { - JSONObject jsonObject = (JSONObject) entry; - String objectNameString = (String) jsonObject.get("objectName"); - try { - result.add(new ObjectName(objectNameString)); - } catch (MalformedObjectNameException e) { - throw new IllegalStateException("Cannot convert " - + objectNameString + " to ObjectName", e); - } - } - return result; - } - - protected ObjectName extractObjectName(J4pResponse resp) { - JSONObject jsonResponse = resp.getValue(); - return extractObjectName(jsonResponse); - } - - protected ObjectName extractObjectName(JSONObject jsonResponse) { - String result = jsonResponse.get("objectName").toString(); - return ObjectNameUtil.createON(result); - } - - protected Set lookupSomething(String signature, - Object[] parameters) { - J4pExecRequest req = new J4pExecRequest(objectName, signature, - parameters); - JSONArray jsonArray = execute(req).getValue(); - return new HashSet<>(jsonArrayToObjectNames(jsonArray)); - } - - public Set lookupConfigBeans() { - return lookupSomething("lookupConfigBeans()", new Object[0]); - } - - public Set lookupConfigBeans(String ifcName) { - return lookupSomething("lookupConfigBeans(java.lang.String)", - new Object[] { ifcName }); - } - - public Set lookupConfigBeans(String ifcName, String instanceName) { - return lookupSomething( - "lookupConfigBeans(java.lang.String,java.lang.String)", - new Object[] { ifcName, instanceName }); - } - - public ObjectName lookupConfigBean(String ifcName, String instanceName) - throws InstanceNotFoundException { - J4pExecRequest req = new J4pExecRequest(objectName, - "lookupConfigBean(java.lang.String,java.lang.String)", - new Object[] { ifcName, instanceName }); - try { - J4pResponse resp = execute(req); - return extractObjectName(resp); - } catch (RuntimeException e) { - if (e.getMessage() != null - && e.getMessage().startsWith( - InstanceNotFoundException.class.getName())) - throw new InstanceNotFoundException(); - throw e; - } - } - - public Set getAvailableModuleNames() { - J4pReadRequest req = new J4pReadRequest(objectName, - "AvailableModuleNames"); - List value = execute(req).getValue(); - return new HashSet<>(value); - } -} diff --git a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java index 85397d2a20..4c99c7770a 100644 --- a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java +++ b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java @@ -7,49 +7,38 @@ */ package org.opendaylight.controller.config.util; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.junit.matchers.JUnitMatchers.containsString; - -import java.lang.management.ManagementFactory; -import java.util.Set; +import com.google.common.collect.Sets; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.config.api.ConfigRegistry; import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; import javax.management.ObjectName; +import java.lang.management.ManagementFactory; +import java.util.Set; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.opendaylight.controller.config.api.ConfigRegistry; -import org.opendaylight.controller.config.api.ValidationException; -import org.opendaylight.controller.config.util.jolokia.ConfigRegistryJolokiaClient; +import static org.junit.Assert.assertEquals; public class ConfigRegistryClientsTest { - private String jolokiaURL; - private TestingConfigRegistry testingRegistry; private ObjectName testingRegistryON; private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - private ConfigRegistryClient jmxRegistryClient, jolokiaRegistryClient; + private ConfigRegistryClient jmxRegistryClient; @Before public void setUp() throws Exception { - jolokiaURL = JolokiaHelper.startTestingJolokia(); testingRegistry = new TestingConfigRegistry(); testingRegistryON = ConfigRegistry.OBJECT_NAME; mbs.registerMBean(testingRegistry, testingRegistryON); jmxRegistryClient = new ConfigRegistryJMXClient( ManagementFactory.getPlatformMBeanServer()); - jolokiaRegistryClient = new ConfigRegistryJolokiaClient(jolokiaURL); } @After public void cleanUp() throws Exception { - JolokiaHelper.stopJolokia(); if (testingRegistryON != null) { mbs.unregisterMBean(testingRegistryON); } @@ -58,8 +47,7 @@ public class ConfigRegistryClientsTest { @Test public void testLookupRuntimeBeans() throws Exception { Set jmxLookup = lookupRuntimeBeans(jmxRegistryClient); - Set jolokiaLookup = lookupRuntimeBeans(jolokiaRegistryClient); - assertEquals(jmxLookup, jolokiaLookup); + assertEquals(Sets.newHashSet(testingRegistry.run2, testingRegistry.run1, testingRegistry.run3), jmxLookup); } private Set lookupRuntimeBeans(ConfigRegistryClient client) @@ -79,28 +67,19 @@ public class ConfigRegistryClientsTest { jmxRegistryClient, TestingConfigRegistry.moduleName1, TestingConfigRegistry.instName1); assertEquals(1, jmxLookup.size()); - Set jolokiaLookup = clientLookupRuntimeBeansWithModuleAndInstance( - jolokiaRegistryClient, TestingConfigRegistry.moduleName1, - TestingConfigRegistry.instName1); - assertEquals(jmxLookup, jolokiaLookup); + assertEquals(Sets.newHashSet(testingRegistry.run2), jmxLookup); jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance( jmxRegistryClient, TestingConfigRegistry.moduleName2, TestingConfigRegistry.instName2); assertEquals(1, jmxLookup.size()); - jolokiaLookup = clientLookupRuntimeBeansWithModuleAndInstance( - jolokiaRegistryClient, TestingConfigRegistry.moduleName2, - TestingConfigRegistry.instName2); - assertEquals(jmxLookup, jolokiaLookup); + assertEquals(Sets.newHashSet(testingRegistry.run3), jmxLookup); jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance( jmxRegistryClient, TestingConfigRegistry.moduleName1, TestingConfigRegistry.instName2); assertEquals(0, jmxLookup.size()); - jolokiaLookup = clientLookupRuntimeBeansWithModuleAndInstance( - jolokiaRegistryClient, TestingConfigRegistry.moduleName1, - TestingConfigRegistry.instName2); - assertEquals(jmxLookup, jolokiaLookup); + assertEquals(Sets.newHashSet(), jmxLookup); } private Set clientLookupRuntimeBeansWithModuleAndInstance( @@ -112,29 +91,4 @@ public class ConfigRegistryClientsTest { } return beans; } - - @Test - public void testValidationExceptionDeserialization() { - try { - jolokiaRegistryClient.commitConfig(null); - fail(); - } catch (ValidationException e) { - String moduleName = "moduleName", instanceName = "instanceName"; - assertThat(e.getFailedValidations().containsKey(moduleName), - is(true)); - assertThat(e.getFailedValidations().size(), is(1)); - assertThat(e.getFailedValidations().get(moduleName).size(), is(1)); - assertThat( - e.getFailedValidations().get(moduleName) - .containsKey(instanceName), is(true)); - assertThat( - e.getFailedValidations().get(moduleName).get(instanceName) - .getMessage(), is("message")); - assertThat( - e.getFailedValidations().get(moduleName).get(instanceName) - .getTrace(), - containsString("org.opendaylight.controller.config.util.TestingConfigRegistry.commitConfig")); - } - } - } diff --git a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigTransactionClientsTest.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigTransactionClientsTest.java index a6df1e91a5..5ce6d46799 100644 --- a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigTransactionClientsTest.java +++ b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigTransactionClientsTest.java @@ -7,47 +7,37 @@ */ package org.opendaylight.controller.config.util; -import static org.junit.Assert.assertEquals; - -import java.lang.management.ManagementFactory; -import java.util.Set; - -import javax.management.MBeanServer; -import javax.management.ObjectName; - +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.ConfigTransactionControllerMXBean; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; -import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient; -public class ConfigTransactionClientsTest { +import javax.management.MBeanServer; +import javax.management.ObjectName; +import java.lang.management.ManagementFactory; +import java.util.Set; +import static org.junit.Assert.assertEquals; + +public class ConfigTransactionClientsTest { private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - private String jolokiaURL; - private ConfigTransactionControllerMXBean transactionController; + private TestingConfigTransactionController transactionController; private ObjectName transactionControllerON; - private ConfigTransactionClient jmxTransactionClient, - jolokiaTransactionClient; + private ConfigTransactionClient jmxTransactionClient; @Before public void setUp() throws Exception { - jolokiaURL = JolokiaHelper.startTestingJolokia(); transactionController = new TestingConfigTransactionController(); transactionControllerON = new ObjectName(ObjectNameUtil.ON_DOMAIN + ":" + ObjectNameUtil.TYPE_KEY + "=TransactionController"); mbs.registerMBean(transactionController, transactionControllerON); - jmxTransactionClient = new ConfigTransactionJMXClient(null, - transactionControllerON, + jmxTransactionClient = new ConfigTransactionJMXClient(null, transactionControllerON, ManagementFactory.getPlatformMBeanServer()); - jolokiaTransactionClient = new ConfigTransactionJolokiaClient( - jolokiaURL, transactionControllerON, null); } @After public void cleanUp() throws Exception { - JolokiaHelper.stopJolokia(); if (transactionControllerON != null) { mbs.unregisterMBean(transactionControllerON); } @@ -56,8 +46,8 @@ public class ConfigTransactionClientsTest { @Test public void testLookupConfigBeans() throws Exception { Set jmxLookup = testClientLookupConfigBeans(jmxTransactionClient); - Set jolokiaLookup = testClientLookupConfigBeans(jolokiaTransactionClient); - assertEquals(jmxLookup, jolokiaLookup); + assertEquals(Sets.newHashSet(transactionController.conf1, + transactionController.conf2, transactionController.conf3), jmxLookup); } private Set testClientLookupConfigBeans( @@ -69,5 +59,4 @@ public class ConfigTransactionClientsTest { assertEquals(3, beans.size()); return beans; } - } diff --git a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/JolokiaHelper.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/JolokiaHelper.java deleted file mode 100644 index c0a25861e9..0000000000 --- a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/JolokiaHelper.java +++ /dev/null @@ -1,54 +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.config.util; - -import org.jolokia.jvmagent.JolokiaServer; -import org.jolokia.jvmagent.JvmAgentConfig; - -public class JolokiaHelper { - private static JolokiaServer jolokiaServer; - - /** - * Bind to port 17777. By convention, ports above 10000 are used for testing - * and < 10000 for production - * - * @return url that can be passed to new J4pClient(url) - */ - public static String startTestingJolokia() { - return startJolokia("localhost", 17777); - } - - /** - * @return url that can be passed to new J4pClient(url) - * @throws IOException - */ - public static String startJolokia(String host, int port) { - String agentArgs = "host=" + host + ",port=" + port; - JvmAgentConfig config = new JvmAgentConfig(agentArgs); - Exception lastException = null; - for (int i = 0; i < 10; i++) { - try { - jolokiaServer = new JolokiaServer(config, false); - jolokiaServer.start(); - return "http://" + host + ":" + port + "/jolokia/"; - } catch (Exception e) { - lastException = e; - try { - Thread.sleep(100); - } catch (InterruptedException ie) { - ie.printStackTrace(); - } - } - } - throw new RuntimeException(lastException); - } - - public static void stopJolokia() { - jolokiaServer.stop(); - } -} diff --git a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/LookupTest.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/LookupTest.java index 0749204324..4489762a47 100644 --- a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/LookupTest.java +++ b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/LookupTest.java @@ -7,19 +7,8 @@ */ package org.opendaylight.controller.config.util; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.lang.management.ManagementFactory; -import java.lang.reflect.Method; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.management.InstanceNotFoundException; -import javax.management.MBeanServer; -import javax.management.ObjectName; - +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -27,35 +16,40 @@ import org.opendaylight.controller.config.api.ConfigRegistry; import org.opendaylight.controller.config.api.LookupRegistry; import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; -import org.opendaylight.controller.config.util.jolokia.ConfigRegistryJolokiaClient; -import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Sets; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import java.lang.management.ManagementFactory; +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; public class LookupTest { - private String jolokiaURL; private TestingConfigRegistry testingRegistry; private ObjectName testingRegistryON; private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - private ConfigRegistryClient jmxRegistryClient, jolokiaRegistryClient; + private ConfigRegistryClient jmxRegistryClient; private ConfigTransactionControllerMXBean testingTransactionController; private ObjectName testingTransactionControllerON; - private ConfigTransactionClient jmxTransactionClient, - jolokiaTransactionClient; + private ConfigTransactionClient jmxTransactionClient; Map> lookupProvidersToClients; @Before public void setUp() throws Exception { - jolokiaURL = JolokiaHelper.startTestingJolokia(); testingRegistry = new TestingConfigRegistry(); testingRegistryON = ConfigRegistry.OBJECT_NAME; mbs.registerMBean(testingRegistry, testingRegistryON); jmxRegistryClient = new ConfigRegistryJMXClient( ManagementFactory.getPlatformMBeanServer()); - jolokiaRegistryClient = new ConfigRegistryJolokiaClient(jolokiaURL); + testingTransactionController = new TestingConfigTransactionController(); testingTransactionControllerON = new ObjectName( @@ -67,16 +61,15 @@ public class LookupTest { jmxTransactionClient = new ConfigTransactionJMXClient(null, testingTransactionControllerON, ManagementFactory.getPlatformMBeanServer()); - jolokiaTransactionClient = new ConfigTransactionJolokiaClient( - jolokiaURL, testingTransactionControllerON, null); - lookupProvidersToClients = ImmutableMap - .of(testingRegistry, Sets.newHashSet(jmxRegistryClient, jolokiaRegistryClient), - testingTransactionController, Sets.newHashSet(jmxTransactionClient, jolokiaTransactionClient)); + + HashSet registryClients = Sets.newHashSet(jmxRegistryClient); + HashSet configTransactionClients = Sets.newHashSet(jmxTransactionClient); + lookupProvidersToClients = ImmutableMap.of((LookupRegistry) testingRegistry, registryClients, + testingTransactionController, configTransactionClients); } @After public void cleanUp() throws Exception { - JolokiaHelper.stopJolokia(); mbs.unregisterMBean(testingRegistryON); mbs.unregisterMBean(testingTransactionControllerON); } 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 d4ae42d3de..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 @@ -8,6 +8,7 @@ package org.opendaylight.controller.config.util; import java.util.List; +import java.util.Map; import java.util.Set; import javax.management.InstanceNotFoundException; @@ -143,4 +144,48 @@ public class TestingConfigRegistry implements ConfigRegistryMXBean { } } + @Override + public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException { + throw new UnsupportedOperationException(); + } + + @Override + public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { + throw new UnsupportedOperationException(); + } + + @Override + public Map> getServiceMapping() { + throw new UnsupportedOperationException(); + } + + @Override + public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { + throw new UnsupportedOperationException(); + } + + @Override + public Set lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException { + throw new UnsupportedOperationException(); + } + + @Override + public String getServiceInterfaceName(String namespace, String localName) { + throw new UnsupportedOperationException(); + } + + @Override + 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 67e31b05e5..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 @@ -7,6 +7,7 @@ */ package org.opendaylight.controller.config.util; +import java.util.Map; import java.util.Set; import javax.management.InstanceAlreadyExistsException; @@ -22,7 +23,7 @@ import com.google.common.collect.Sets; public class TestingConfigTransactionController implements ConfigTransactionControllerMXBean { - private final ObjectName conf1, conf2, conf3; + public final ObjectName conf1, conf2, conf3; public static final String moduleName1 = "moduleA"; public static final String moduleName2 = "moduleB"; @@ -109,4 +110,69 @@ public class TestingConfigTransactionController implements return null; } } + + @Override + public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException { + throw new UnsupportedOperationException(); + } + + @Override + public ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException { + throw new UnsupportedOperationException(); + } + + @Override + public void removeServiceReference(String serviceInterfaceName, String refName) { + throw new UnsupportedOperationException(); + } + + @Override + public void removeAllServiceReferences() { + throw new UnsupportedOperationException(); + } + + @Override + public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) { + throw new UnsupportedOperationException(); + } + + @Override + public Map> getServiceMapping() { + throw new UnsupportedOperationException(); + } + + @Override + public Map lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) { + throw new UnsupportedOperationException(); + } + + @Override + public Set lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException { + throw new UnsupportedOperationException(); + } + + @Override + public String getServiceInterfaceName(String namespace, String localName) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException { + throw new UnsupportedOperationException(); + } + + @Override + 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/jolokia/ListableJolokiaClientTest.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/jolokia/ListableJolokiaClientTest.java deleted file mode 100644 index bff8006c51..0000000000 --- a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/jolokia/ListableJolokiaClientTest.java +++ /dev/null @@ -1,58 +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.config.util.jolokia; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import java.util.HashMap; -import java.util.Map; - -import org.json.simple.JSONObject; -import org.json.simple.JSONValue; -import org.junit.Before; -import org.junit.Test; -import org.opendaylight.controller.config.api.ValidationException; -import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace; - -public class ListableJolokiaClientTest { - - private Map> failedValidations; - - private ValidationException val; - - private final static String ex = "{\"message\":null," - + "\"failedValidations\":" - + "{\"ifc2\":{\"impl1\":{\"message\":\"abc\",\"trace\":\"vvv\"}," - + "\"impl2\":{\"message\":\"abc2\",\"trace\":\"vvv2\"}}," - + "\"ifc1\":" - + "{\"impl1\":{\"message\":\"abc\",\"trace\":\"vvv\"}," - + "\"impl2\":{\"message\":\"abc2\",\"trace\":\"vvv2\"}}}," - + "\"localizedMessage\":null," + "\"cause\":null}"; - - @Before - public void setUp() { - failedValidations = new HashMap>(); - Map map1 = new HashMap(); - map1.put("impl1", new ExceptionMessageWithStackTrace("abc", "vvv")); - map1.put("impl2", new ExceptionMessageWithStackTrace("abc2", "vvv2")); - failedValidations.put("ifc1", map1); - failedValidations.put("ifc2", map1); - val = new ValidationException(failedValidations); - } - - @Test - public void testParsing() { - JSONObject e = (JSONObject) JSONValue.parse(ex); - ValidationException val2 = ListableJolokiaClient - .createValidationExceptionFromJSONObject(e); - assertThat(val2.getMessage(), is(val.getMessage())); - assertThat(val2.getFailedValidations(), is(val.getFailedValidations())); - } - -} diff --git a/opendaylight/config/pom.xml b/opendaylight/config/pom.xml index 99437979de..eba5e07c0f 100644 --- a/opendaylight/config/pom.xml +++ b/opendaylight/config/pom.xml @@ -26,6 +26,7 @@ config-util config-persister-api config-persister-file-adapter + config-persister-file-xml-adapter yang-jmx-generator yang-jmx-generator-plugin yang-store-api @@ -39,6 +40,7 @@ netty-event-executor-config netty-timer-config config-persister-directory-adapter + config-persister-directory-xml-adapter yang-test-plugin @@ -63,7 +65,6 @@ 5.0.0 0.6.2.201302030002 1.7.2 - 1.1.1 0.5.9-SNAPSHOT 0.6.0-SNAPSHOT 0.1.1-SNAPSHOT @@ -110,22 +111,6 @@ guava 14.0.1 - - org.jolokia - jolokia-core - ${jolokia.version} - - - org.jolokia - jolokia-jvm - ${jolokia.version} - agent - - - org.jolokia - jolokia-client-java - ${jolokia.version} - junit junit diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.java index 47b68ebf9a..35dc7a3600 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.java @@ -14,6 +14,7 @@ import org.opendaylight.controller.config.api.ModuleIdentifier; import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.controller.config.spi.ModuleFactory; +import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry; import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Constructor; import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field; import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Header; @@ -33,11 +34,12 @@ public class AbstractFactoryTemplate extends GeneralClassTemplate { private final String globallyUniqueName, moduleInstanceType; private final List providedServices; + private final ModuleMXBeanEntry mbe; public AbstractFactoryTemplate(Header header, String packageName, - String abstractFactoryName, String globallyUniqueName, - String moduleInstanceType, List fields, - List providedServices) { + String abstractFactoryName, String globallyUniqueName, + String moduleInstanceType, List fields, + List providedServices, ModuleMXBeanEntry mbe) { super(header, packageName, abstractFactoryName, Collections . emptyList(), implementedIfcs, fields, Collections . emptyList(), true, false, Collections @@ -45,6 +47,7 @@ public class AbstractFactoryTemplate extends GeneralClassTemplate { this.globallyUniqueName = globallyUniqueName; this.moduleInstanceType = moduleInstanceType; this.providedServices = providedServices; + this.mbe = mbe; } public String getGloballyUniqueName() { @@ -92,4 +95,7 @@ public class AbstractFactoryTemplate extends GeneralClassTemplate { return "factory_abs_template.ftl"; } + public ModuleMXBeanEntry getMbe() { + return mbe; + } } 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 115bb85b61..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; @@ -210,8 +211,7 @@ public class TemplateFactory { sieTemplate.getAnnotations().add( Annotation.createDescriptionAnnotation(sie .getNullableDescription())); - sieTemplate.getAnnotations().add(Annotation.createSieAnnotation(sie.getQName(), sie.getExportedOsgiClassName - ())); + sieTemplate.getAnnotations().addAll(Annotation.createSieAnnotations(sie)); return sieTemplate; } @@ -236,7 +236,7 @@ public class TemplateFactory { mbe.getPackageName(), mbe.getAbstractFactoryName(), mbe.getGloballyUniqueName(), mbe.getFullyQualifiedName(mbe .getStubModuleName()), attrProcessor.getFields(), - Lists.newArrayList(transformed)); + Lists.newArrayList(transformed), mbe); } public static AbstractModuleTemplate abstractModuleTemplateFromMbe( @@ -624,6 +624,7 @@ public class TemplateFactory { } boolean isDependency = false; + boolean isListOfDependencies = false; Dependency dependency = null; Annotation overrideAnnotation = new Annotation("Override", Collections. emptyList()); @@ -636,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(); @@ -658,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/Annotation.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/Annotation.java index 5ec359ea8d..7cf241725d 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/Annotation.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/Annotation.java @@ -7,13 +7,15 @@ */ package org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import org.opendaylight.controller.config.api.annotations.Description; import org.opendaylight.controller.config.api.annotations.RequireInterface; import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; +import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName; import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry; -import org.opendaylight.yangtools.yang.common.QName; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; @@ -42,19 +44,36 @@ public class Annotation { Lists.newArrayList(new Parameter("value", q(description)))); } - public static Annotation createSieAnnotation(QName qname, - String exportedClassName) { - Preconditions.checkNotNull(qname, + public static Collection createSieAnnotations(ServiceInterfaceEntry sie){ + + String exportedClassName = sie.getExportedOsgiClassName(); + Preconditions.checkNotNull(sie.getQName(), "Cannot create annotation from null qname"); Preconditions.checkNotNull(exportedClassName, "Cannot create annotation from null exportedClassName"); + List result = new ArrayList<>(); + { + List params = Lists.newArrayList(new Parameter("value", q(sie.getQName().toString()))); + params.add(new Parameter("osgiRegistrationType", exportedClassName + ".class")); + + params.add(new Parameter("namespace", q(sie.getQName().getNamespace().toString()))); + params.add(new Parameter("revision", q(sie.getQName().getFormattedRevision()))); + params.add(new Parameter("localName", q(sie.getQName().getLocalName()))); + + Annotation sieAnnotation = new Annotation(ServiceInterfaceAnnotation.class.getCanonicalName(), params); + result.add(sieAnnotation); - List params = Lists.newArrayList(new Parameter("value", - q(qname.getLocalName()))); - params.add(new Parameter("osgiRegistrationType", exportedClassName - + ".class")); - return new Annotation( - ServiceInterfaceAnnotation.class.getCanonicalName(), params); + } + { + List params = new ArrayList<>(); + params.add(new Parameter("namespace", q(sie.getYangModuleQName().getNamespace().toString()))); + params.add(new Parameter("revision", q(sie.getYangModuleQName().getFormattedRevision()))); + params.add(new Parameter("name", q(sie.getYangModuleQName().getLocalName()))); + + Annotation moduleQNameAnnotation = new Annotation(ModuleQName.class.getCanonicalName(), params); + result.add(moduleQNameAnnotation); + } + return result; } public static Annotation createRequireIfcAnnotation( 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/factory_abs_template.ftl b/opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/factory_abs_template.ftl index a331e4e0c1..b9bbf1f1b5 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/factory_abs_template.ftl +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/factory_abs_template.ftl @@ -2,16 +2,19 @@ package ${packageName}; <@javadocD object=javadoc/> +@org.opendaylight.yangtools.yang.binding.annotations.ModuleQName(namespace="${mbe.getYangModuleQName().getNamespace().toString()}",revision="${mbe.getYangModuleQName().getFormattedRevision()}",name="${mbe.getYangModuleQName().getLocalName()}") <@typeDeclarationD object=typeDeclaration/> { public static final java.lang.String NAME = "${globallyUniqueName}"; - private static final java.util.Set> serviceIfcs = new java.util.HashSet>(); + private static final java.util.Set> serviceIfcs; <#if providedServices??> static { + java.util.Set> serviceIfcs2 = new java.util.HashSet>(); <#list providedServices as refId> - serviceIfcs.add(${refId}); + serviceIfcs2.add(${refId}); + serviceIfcs = java.util.Collections.unmodifiableSet(serviceIfcs2); } @@ -25,6 +28,12 @@ package ${packageName}; return false; } + @Override + public java.util.Set> getImplementedServiceIntefaces() { + return serviceIfcs; + } + + @Override public ${moduleType} createModule(String instanceName, ${dependencyResolverType} dependencyResolver, ${bundleContextType} bundleContext) { return instantiateModule(instanceName, dependencyResolver, bundleContext); 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-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java b/opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java index 1945cac1c2..3ef406694a 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java @@ -438,11 +438,11 @@ public class JMXGeneratorTest extends AbstractGeneratorTest { "public static final java.lang.String NAME=\"threadfactory-naming\""); assertDeclaredField( fieldDeclarations, - "private static final java.util.Set> serviceIfcs=new java.util.HashSet>()"); + "private static final java.util.Set> serviceIfcs"); assertEquals(2, fieldDeclarations.size()); - assertFactoryMethods(visitor.methods, 8); + assertFactoryMethods(visitor.methods, 9); assertEquals("Incorrenct number of generated method descriptions", 0, visitor.methodDescriptions.size()); assertEquals("Incorrenct number of generated method javadoc", 0, diff --git a/opendaylight/config/yang-jmx-generator/pom.xml b/opendaylight/config/yang-jmx-generator/pom.xml index c312cc8493..c66b112566 100644 --- a/opendaylight/config/yang-jmx-generator/pom.xml +++ b/opendaylight/config/yang-jmx-generator/pom.xml @@ -57,6 +57,10 @@ commons-lang3 test + + org.opendaylight.yangtools + binding-type-provider + diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java index 4eba739b46..869488e777 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java @@ -136,11 +136,13 @@ public class ModuleMXBeanEntry extends AbstractEntry { private final Map providedServices; private Collection runtimeBeans; + private final QName yangModuleQName; public ModuleMXBeanEntry(IdentitySchemaNode id, Map yangToAttributes, String packageName, Map providedServices2, String javaNamePrefix, - String namespace, Collection runtimeBeans) { + String namespace, Collection runtimeBeans, + QName yangModuleQName) { this.globallyUniqueName = id.getQName().getLocalName(); this.yangToAttributes = yangToAttributes; this.nullableDescription = id.getDescription(); @@ -149,6 +151,7 @@ public class ModuleMXBeanEntry extends AbstractEntry { this.namespace = checkNotNull(namespace); this.providedServices = Collections.unmodifiableMap(providedServices2); this.runtimeBeans = runtimeBeans; + this.yangModuleQName = yangModuleQName; } public String getMXBeanInterfaceName() { @@ -395,7 +398,8 @@ public class ModuleMXBeanEntry extends AbstractEntry { moduleIdentity, yangToAttributes, packageName, providedServices, javaNamePrefix, currentModule .getNamespace().toString(), - runtimeBeans); + runtimeBeans, + ModuleUtil.getQName(currentModule)); moduleMXBeanEntry.setYangModuleName(currentModule .getName()); moduleMXBeanEntry @@ -730,6 +734,10 @@ public class ModuleMXBeanEntry extends AbstractEntry { return nullableDescription; } + public QName getYangModuleQName() { + return yangModuleQName; + } + @Override public String toString() { return "ModuleMXBeanEntry{" + "globallyUniqueName='" diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleUtil.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleUtil.java new file mode 100644 index 0000000000..5fea8fd078 --- /dev/null +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleUtil.java @@ -0,0 +1,18 @@ +/* + * 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.yangjmxgenerator; + +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.Module; + +public class ModuleUtil { + + public static QName getQName(Module currentModule){ + return new QName(currentModule.getNamespace(), currentModule.getRevision(), currentModule.getName()); + } +} diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.java index 71cd0900eb..aa2d6a5d7f 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.java @@ -57,13 +57,14 @@ public class ServiceInterfaceEntry extends AbstractEntry { private final String exportedOsgiClassName; private final QName qName; private final String nullableDescription, packageName, typeName; + private final QName yangModuleQName; - private ServiceInterfaceEntry(IdentitySchemaNode id, String packageName) { - this(Optional. absent(), id, packageName); + private ServiceInterfaceEntry(IdentitySchemaNode id, String packageName, QName yangModuleQName) { + this(Optional. absent(), id, packageName, yangModuleQName); } private ServiceInterfaceEntry(Optional base, - IdentitySchemaNode id, String packageName) { + IdentitySchemaNode id, String packageName, QName yangModuleQName) { checkNotNull(base); this.maybeBaseCache = base; List unknownSchemaNodes = id.getUnknownSchemaNodes(); @@ -93,6 +94,7 @@ public class ServiceInterfaceEntry extends AbstractEntry { nullableDescription = id.getDescription(); typeName = getSimpleName(exportedOsgiClassName) + CLASS_NAME_SUFFIX; this.packageName = packageName; + this.yangModuleQName = yangModuleQName; } private static final String getSimpleName(String fullyQualifiedName) { @@ -120,14 +122,14 @@ public class ServiceInterfaceEntry extends AbstractEntry { * @return Map of QNames as keys and ServiceInterfaceEntry instances as * values */ - public static Map create(Module module, + public static Map create(Module currentModule, String packageName) { logger.debug("Generating ServiceInterfaces from {} to package {}", - module.getNamespace(), packageName); + currentModule.getNamespace(), packageName); Map identitiesToSIs = new HashMap<>(); Set notVisited = new HashSet<>( - module.getIdentities()); + currentModule.getIdentities()); int lastSize = notVisited.size() + 1; while (notVisited.size() > 0) { if (notVisited.size() == lastSize) { @@ -148,18 +150,18 @@ public class ServiceInterfaceEntry extends AbstractEntry { } else if (identity.getBaseIdentity().getQName() .equals(SERVICE_TYPE_Q_NAME)) { // this is a base type - created = new ServiceInterfaceEntry(identity, packageName); + created = new ServiceInterfaceEntry(identity, packageName, ModuleUtil.getQName(currentModule)); } else { ServiceInterfaceEntry foundBase = identitiesToSIs .get(identity.getBaseIdentity()); // derived type, did we convert the parent? if (foundBase != null) { created = new ServiceInterfaceEntry( - Optional.of(foundBase), identity, packageName); + Optional.of(foundBase), identity, packageName, ModuleUtil.getQName(currentModule)); } } if (created != null) { - created.setYangModuleName(module.getName()); + created.setYangModuleName(currentModule.getName()); // TODO how to get local name created.setYangModuleLocalname(identity.getQName() .getLocalName()); @@ -190,6 +192,10 @@ public class ServiceInterfaceEntry extends AbstractEntry { return typeName; } + public QName getYangModuleQName() { + return yangModuleQName; + } + @Override public boolean equals(Object o) { if (this == o) diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java index 764ecd3886..c43fead0fc 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java @@ -64,4 +64,8 @@ public class TypeProviderWrapper { public String getJMXParamForBaseType(TypeDefinition baseType) { return typeProvider.getConstructorPropertyName(baseType); } + + public String getJMXParamForUnionInnerType(TypeDefinition unionInnerType) { + return typeProvider.getParamNameFromType(unionInnerType); + } } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java index 3e20e4a55a..e01063ef92 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java @@ -7,20 +7,26 @@ */ package org.opendaylight.controller.config.yangjmxgenerator.attribute; +import com.google.common.base.Preconditions; import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper; import org.opendaylight.yangtools.sal.binding.model.api.Type; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; import javax.management.openmbean.OpenType; import javax.management.openmbean.SimpleType; +import java.util.Arrays; +import java.util.List; public class JavaAttribute extends AbstractAttribute implements TypedAttribute { + public static final String DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION = "valueOfArtificialUnionProperty"; + private final Type type; private final String nullableDescription, nullableDefault, nullableDefaultWrappedForCode; private final TypeProviderWrapper typeProviderWrapper; @@ -47,6 +53,11 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute { this.nullableDescription = leaf.getDescription(); } + public boolean isUnion() { + TypeDefinition base = getBaseType(typeProviderWrapper, typeDefinition); + return base instanceof UnionTypeDefinition; + } + public TypeDefinition getTypeDefinition() { return typeDefinition; } @@ -132,13 +143,70 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute { return getArrayType(); } else if (isEnum(baseType)) { return getSimpleType(baseType); - } else if (isDerivedType(baseType)) { + } else if (isUnion()) { + return getCompositeTypeForUnion(baseTypeDefinition); + } else if (isDerivedType(baseType, getType())) { return getCompositeType(baseType, baseTypeDefinition); } return getSimpleType(getType()); } + private OpenType getCompositeTypeForUnion(TypeDefinition baseTypeDefinition) { + Preconditions.checkArgument(baseTypeDefinition instanceof UnionTypeDefinition, + "Expected %s instance but was %s", UnionTypeDefinition.class, baseTypeDefinition); + + List> types = ((UnionTypeDefinition) baseTypeDefinition).getTypes(); + + String[] itemNames = new String[types.size()+1]; + OpenType[] itemTypes = new OpenType[itemNames.length]; + + addArtificialPropertyToUnionCompositeType(baseTypeDefinition, itemNames, itemTypes); + + String description = getNullableDescription() == null ? getAttributeYangName() : getNullableDescription(); + + int i = 1; + for (TypeDefinition innerTypeDefinition : types) { + + Type innerType = typeProviderWrapper.getType(innerTypeDefinition, innerTypeDefinition); + + TypeDefinition baseInnerTypeDefinition = getBaseType(typeProviderWrapper, innerTypeDefinition); + Type innerTypeBaseType = typeProviderWrapper.getType(baseInnerTypeDefinition, baseInnerTypeDefinition); + + OpenType innerCompositeType; + + if(isDerivedType(innerTypeBaseType, innerType)) { + innerCompositeType = getCompositeType(innerTypeBaseType, baseInnerTypeDefinition); + } else { + innerCompositeType = SimpleTypeResolver.getSimpleType(innerType); + } + + itemNames[i] = typeProviderWrapper.getJMXParamForUnionInnerType(innerTypeDefinition); + itemTypes[i++] = innerCompositeType; + } + + String[] descriptions = Arrays.copyOf(itemNames, itemNames.length); + descriptions[0] = DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION; + + try { + return new CompositeType(getUpperCaseCammelCase(), description, itemNames, descriptions, itemTypes); + } catch (OpenDataException e) { + throw new RuntimeException("Unable to create " + CompositeType.class + " with inner elements " + + Arrays.toString(itemTypes), e); + } + } + + public static final Class TYPE_OF_ARTIFICIAL_UNION_PROPERTY = char.class; + + private void addArtificialPropertyToUnionCompositeType(TypeDefinition baseTypeDefinition, String[] itemNames, OpenType[] itemTypes) { + String artificialPropertyName = typeProviderWrapper.getJMXParamForBaseType(baseTypeDefinition); + itemNames[0] = artificialPropertyName; + + OpenType artificialPropertyType = getArrayOpenTypeForSimpleType(TYPE_OF_ARTIFICIAL_UNION_PROPERTY.getName(), + SimpleTypeResolver.getSimpleType(TYPE_OF_ARTIFICIAL_UNION_PROPERTY.getName())); + itemTypes[0] = artificialPropertyType; + } + private boolean isEnum(Type baseType) { return baseType.getFullyQualifiedName().equals(Enum.class.getName()); } @@ -163,12 +231,15 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute { throw new RuntimeException("Unable to create " + CompositeType.class + " with inner element of type " + itemTypes, e); } - } private OpenType getArrayType() { String innerTypeFullyQName = getInnerType(getType()); SimpleType innerSimpleType = SimpleTypeResolver.getSimpleType(innerTypeFullyQName); + return getArrayOpenTypeForSimpleType(innerTypeFullyQName, innerSimpleType); + } + + private OpenType getArrayOpenTypeForSimpleType(String innerTypeFullyQName, SimpleType innerSimpleType) { try { ArrayType arrayType = isPrimitive(innerTypeFullyQName) ? new ArrayType<>(innerSimpleType, true) : new ArrayType<>(1, innerSimpleType); @@ -191,8 +262,8 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute { return type.getName().endsWith("[]"); } - private boolean isDerivedType(Type baseType) { - return baseType.equals(getType()) == false; + private boolean isDerivedType(Type baseType, Type currentType) { + return baseType.equals(currentType) == false; } private static String getInnerType(Type type) { diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java index 87b55f3756..f4bd979fac 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java @@ -59,6 +59,8 @@ public class SimpleTypeResolver { JAVA_TYPE_TO_SIMPLE_TYPE.put(Date.class.getName(), SimpleType.DATE); JAVA_TYPE_TO_SIMPLE_TYPE.put(Double.class.getName(), SimpleType.DOUBLE); JAVA_TYPE_TO_SIMPLE_TYPE.put(double.class.getName(), SimpleType.DOUBLE); + + JAVA_TYPE_TO_SIMPLE_TYPE.put(char.class.getName(), SimpleType.CHARACTER); } } 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/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/controller/config/test/types/rev131127/UnionTestBuilder.java b/opendaylight/config/yang-test/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/controller/config/test/types/rev131127/UnionTestBuilder.java new file mode 100644 index 0000000000..c49319be9f --- /dev/null +++ b/opendaylight/config/yang-test/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/controller/config/test/types/rev131127/UnionTestBuilder.java @@ -0,0 +1,24 @@ +/* + * 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127; + + +/** +**/ +public class UnionTestBuilder { + + public static UnionTest getDefaultInstance(String defaultValue) { + try { + int i = Integer.valueOf(defaultValue); + return new UnionTest(new ExtendTwice(i)); + } catch (NumberFormatException e) { + return new UnionTest(defaultValue); + } + } + +} diff --git a/opendaylight/config/yang-test/src/main/yang/config-test-impl.yang b/opendaylight/config/yang-test/src/main/yang/config-test-impl.yang index 9ad7a44915..f7cea0a52a 100644 --- a/opendaylight/config/yang-test/src/main/yang/config-test-impl.yang +++ b/opendaylight/config/yang-test/src/main/yang/config-test-impl.yang @@ -61,10 +61,6 @@ module config-test-impl { default 127.0.0.1; } - leaf ip { - type inet:ip-address; - // TODO defaults for union default 0:0:0:0:0:0:0:1; - } } leaf as-number { @@ -136,6 +132,16 @@ module config-test-impl { default ONE; } + leaf ip { + type inet:ip-address; + default 0:0:0:0:0:0:0:1; + } + + leaf union-test-attr { + type tt:unionTest; + default 456; + } + leaf sleep-factor { type decimal64 { fraction-digits 2; diff --git a/opendaylight/config/yang-test/src/main/yang/types/test-types.yang b/opendaylight/config/yang-test/src/main/yang/types/test-types.yang index 84fbcb089d..8c086d8ace 100644 --- a/opendaylight/config/yang-test/src/main/yang/types/test-types.yang +++ b/opendaylight/config/yang-test/src/main/yang/types/test-types.yang @@ -23,4 +23,12 @@ module test-types { } } + typedef unionTest { + type union { + type string; + type uint32; + type extend-twice; + } + } + } 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 4c0b81f7d7..b0f7ad89a4 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -223,11 +223,21 @@ config-persister-file-adapter ${config.version} - - org.opendaylight.controller - config-persister-directory-adapter - ${config.version} - + + org.opendaylight.controller + config-persister-file-xml-adapter + ${config.version} + + + org.opendaylight.controller + config-persister-directory-adapter + ${config.version} + + + org.opendaylight.controller + config-persister-directory-xml-adapter + ${config.version} + @@ -275,6 +285,11 @@ ietf-netconf-monitoring ${netconf.version} + + ${project.groupId} + ietf-netconf-monitoring-extension + ${netconf.version} + org.opendaylight.controller config-persister-impl @@ -449,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/config.ini b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini index 7d57e6005e..ba5d862c57 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini @@ -29,8 +29,16 @@ netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.confi netconf.config.persister.1.properties.directoryStorage=configuration/initial/ netconf.config.persister.1.readonly=true -netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter -netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.txt +#netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter +#netconf.config.persister.3.properties.directoryStorage=configuration/initialXml/ +#netconf.config.persister.3.readonly=true + +#netconf.config.persister.4.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter +#netconf.config.persister.4.properties.fileStorage=configuration/current/controller.currentconfig.txt +#netconf.config.persister.4.properties.numberOfBackups=1 + +netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter +netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.xml netconf.config.persister.2.properties.numberOfBackups=1 diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.conf b/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.conf index fa33215ea6..edee185c17 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.conf +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.conf @@ -16,9 +16,9 @@ dom-broker dom:dom-data-store - - ref_hash-map-data-store - + + hash-map-data-store + @@ -26,11 +26,11 @@ binding-broker-impl binding:binding-notification-service - ref_binding-notification-broker + binding-notification-broker binding:binding-data-broker - ref_binding-data-broker + binding-data-broker @@ -46,43 +46,43 @@ binding-data-broker dom:dom-broker-osgi-registry - ref_dom-broker + dom-broker binding:binding-dom-mapping-service - ref_runtime-mapping-singleton + runtime-mapping-singleton //SERVICES START dom:schema-service - ref_yang-schema-service + yang-schema-service /modules/module[type='schema-service-singleton'][name='yang-schema-service'] binding:binding-notification-service - ref_binding-notification-broker + binding-notification-broker /modules/module[type='binding-notification-broker'][name='binding-notification-broker'] dom:dom-data-store - ref_hash-map-data-store + hash-map-data-store /modules/module[type='hash-map-data-store'][name='hash-map-data-store'] - ref_cluster-data-store + cluster-data-store /modules/module[type='dom-clustered-store-impl'][name='cluster-data-store'] binding:binding-broker-osgi-registry - ref_binding-broker-impl + binding-osgi-broker /modules/module[type='binding-broker-impl'][name='binding-broker-impl'] @@ -96,21 +96,21 @@ binding-impl:binding-dom-mapping-service - ref_runtime-mapping-singleton + runtime-mapping-singleton /modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton'] dom:dom-broker-osgi-registry - ref_dom-broker + dom-broker /modules/module[type='dom-broker-impl'][name='dom-broker'] binding:binding-data-broker - ref_binding-data-broker + binding-data-broker /modules/module[type='binding-data-broker'][name='binding-data-broker'] 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/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/InventoryAndReadAdapter.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend index 8ac6f1b050..609ace4695 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 @@ -157,17 +157,39 @@ class InventoryAndReadAdapter implements IPluginInTopologyService, IPluginInRead } override onNodeRemoved(NodeRemoved notification) { - // NOOP + val properties = Collections.emptySet(); + val org.opendaylight.yangtools.yang.binding.InstanceIdentifier identifier = notification.nodeRef.value as org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + + 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); } override getNodeProps() { 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 f5c5620d7c..09585d6273 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 @@ -21,12 +21,22 @@ 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.Counter64; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsUpdatedBuilder; +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.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.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; @@ -292,4 +302,39 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, 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/model/model-flow-base/src/main/yang/match-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/match-types.yang index 7dcd254ad7..1ed1b6827b 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/match-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/match-types.yang @@ -9,7 +9,7 @@ module opendaylight-match-types { revision "2013-10-26" { description "Initial revision of macth types"; } - + grouping "mac-address-filter" { leaf address { mandatory true; @@ -61,14 +61,14 @@ module opendaylight-match-types { container vlan-id { description "VLAN id."; presence "Match field is active and set"; - + + leaf vlan-id-present { + type boolean; + } + leaf vlan-id { - mandatory true; type l2t:vlan-id; } - leaf mask { - type binary; - } } leaf vlan-pcp { description "VLAN priority."; diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-action-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-action-types.yang index 81303d6867..43754a1dfd 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-action-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-action-types.yang @@ -332,7 +332,11 @@ module opendaylight-action-types { } } } - + + case strip-vlan-action-case { + container strip-vlan-action { + } + } case sw-path-action-case { container sw-path-action { @@ -340,4 +344,4 @@ module opendaylight-action-types { } } } -} \ No newline at end of file +} 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 e83306db50..2bcd405223 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,41 @@ module opendaylight-flow-types { description "Initial revision of flow service"; } + typedef output-port-values { + type enumeration { + enum MAX { + value 1; + } + enum IN_PORT { + value 2; + } + enum TABLE { + value 3; + } + enum NORMAL { + value 4; + } + enum FLOOD { + value 5; + } + enum ALL { + value 6; + } + enum CONTROLLER { + value 7; + } + enum LOCAL { + value 8; + } + enum ANY { + value 9; + } + enum NONE { + value 10; + } + + } + } grouping instruction-list { list instruction { key "order"; @@ -227,4 +262,4 @@ module opendaylight-flow-types { uses match:match; } } -} \ No newline at end of file +} 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-base/src/main/yang/table-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/table-types.yang index 3774f950fc..5e747e4722 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/table-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/table-types.yang @@ -11,6 +11,10 @@ module opendaylight-table-types { description "Initial revision of table service"; } + typedef table-id { + type uint8; + } + typedef table-ref { type instance-identifier; } diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang index d717e87f76..e55c50fb29 100644 --- a/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang @@ -15,7 +15,60 @@ module flow-node-inventory { revision "2013-08-19" { description "Flow Capable Node extensions to the Inventory model"; } - + + identity feature-capability { + } + + identity flow-feature-capability-flow-stats { + description "Flow statistics"; + base feature-capability; + } + + identity flow-feature-capability-table-stats { + description "Table statistics"; + base feature-capability; + } + + identity flow-feature-capability-port-stats { + description "Port statistics"; + base feature-capability; + } + + identity flow-feature-capability-stp { + description "802.1d spanning tree"; + base feature-capability; + } + + identity flow-feature-capability-reserved { + description "Reserved, must be zero"; + base feature-capability; + } + + identity flow-feature-capability-ip-reasm { + description "Can reassemble IP fragments"; + base feature-capability; + } + + identity flow-feature-capability-queue-stats { + description "Queue statistics"; + base feature-capability; + } + + identity flow-feature-capability-arp-match-ip { + description "Match IP addresses in ARP pkts"; + base feature-capability; + } + + identity flow-feature-capability-group-stats { + description "Group statistics"; + base feature-capability; + } + + identity flow-feature-capability-port-blocked { + description "Switch will block looping ports"; + base feature-capability; + } + grouping feature { leaf support-state { type inv:support-type; @@ -70,7 +123,8 @@ module flow-node-inventory { uses meter:meter; } } - + + grouping flow-node { leaf manufacturer { @@ -122,6 +176,24 @@ module flow-node-inventory { } } } + + container switch-features { + + leaf max_buffers { + type uint32; + } + + leaf max_tables { + type uint8; + } + + leaf-list capabilities { + type identityref { + base feature-capability; + } + } + + } } grouping flow-node-connector { @@ -149,9 +221,10 @@ module flow-node-inventory { ext:augment-identifier "flow-capable-node-connector-update-fields"; uses flow-node-connector; } - + augment "/inv:node-connector-updated" { ext:augment-identifier "flow-capable-node-connector-updated"; uses flow-node-connector; } + } \ No newline at end of file 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..089469f045 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 @@ -81,14 +81,17 @@ module sal-flow { notification flow-added { uses node-flow; + uses tr:transaction-aware; } notification flow-updated { uses node-flow; + uses tr:transaction-aware; } notification flow-removed { 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..bbe4740e71 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 @@ -61,13 +61,16 @@ module sal-group { notification group-added { uses node-group; + uses tr:transaction-aware; } notification group-updated { uses node-group; + uses tr:transaction-aware; } notification group-removed { 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..65b22b29dd 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 @@ -61,13 +61,16 @@ module sal-meter { notification meter-added { uses node-meter; + uses tr:transaction-aware; } notification meter-updated { uses node-meter; + uses tr:transaction-aware; } notification meter-removed { 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 87d1559e49..3bd37bcf33 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 @@ -3,28 +3,156 @@ module opendaylight-flow-statistics { prefix flowstat; 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 opendaylight-flow-types {prefix flow-types;revision-date "2013-10-26";} - import sal-flow {prefix flow;} import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";} + import opendaylight-table-types {prefix table-types;revision-date "2013-10-26";} + import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";} + import flow-capable-transaction {prefix tr;} + import sal-flow {prefix flow;} + revision "2013-08-19" { - description "Initial revision of flow service"; + description "Initial revision of flow statistics service"; + } + + //Augment flow statistics data to the flow-capable-node->table->flow + augment "/inv:nodes/inv:node/flow-node:table/flow-node:flow" { + ext:augment-identifier "flow-statistics-data"; + uses flow-statistics; + } + + grouping flow-statistics { + container flow-statistics { + //config "false"; + uses flow-types:flow; + uses stat-types:generic-statistics; + } + } + + typedef flow-id { + description "flow id"; + type yang:counter32; + } + + grouping flow-and-statistics-map-list { + description "List of flow and statistics map"; + list flow-and-statistics-map-list { + key "flow-id"; + leaf flow-id { + type flow-id; + } + uses flow-and-statistics-map; + } + } + + grouping flow-and-statistics-map{ + description "Mapping between flow and its statistics"; + uses flow-types:flow; + uses stat-types:generic-statistics; + } + + // RPC calls to fetch flow statistics + rpc get-all-flows-statistics-from-all-flow-tables { + description "Fetch statistics of all the flow present in all the flow tables of the switch"; + input { + uses inv:node-context-ref; + } + output { + uses flow-and-statistics-map-list; + uses tr:transaction-aware; + } + } - rpc get-node-connector-statistics { + rpc get-all-flow-statistics-from-flow-table { + description "Fetch statistics of all the flow present in the specific flow table of the switch"; input { uses inv:node-context-ref; - leaf node-connector { - type inv:node-connector-ref; + leaf table-id { + type table-types:table-id; } } output { - uses stat-types:node-connector-statistics; + uses flow-and-statistics-map-list; + uses tr:transaction-aware; } } - rpc get-flow-statistics { + rpc get-flow-statistics-from-flow-table { + description "Fetch statistics of the specific flow present in the specific flow table of the switch"; + input { + uses inv:node-context-ref; + uses flow-types:flow; + } + output { + uses flow-and-statistics-map-list; + uses tr:transaction-aware; + } + } + + notification flows-statistics-update { + description "Flows statistics sent by switch"; + leaf moreReplies { + type boolean; + } + uses inv:node; + uses flow-and-statistics-map-list; + uses tr:transaction-aware; + } + + //Models for aggregate flow statistics collection + augment "/inv:nodes/inv:node/flow-node:table" { + ext:augment-identifier "aggregate-flow-statistics-data"; + uses aggregate-flow-statistics; + } + + grouping aggregate-flow-statistics { + container aggregate-flow-statistics { + //config "false"; + uses stat-types:aggregate-flow-statistics; + } + } + + // RPC calls to fetch 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 { + uses inv:node-context-ref; + leaf table-id { + type table-types:table-id; + } + } + output { + uses stat-types:aggregate-flow-statistics; + uses tr:transaction-aware; + } + } + rpc get-aggregate-flow-statistics-from-flow-table-for-given-match { + description "Fetch aggregate statistics for all the flow matches to the given match from the given table of the switch"; + input { + uses inv:node-context-ref; + uses flow-types:flow; + } + output { + uses stat-types:aggregate-flow-statistics; + uses tr:transaction-aware; + } + } + + notification aggregate-flow-statistics-update { + description "Aggregate flow statistics for a table, sent by switch"; + leaf moreReplies { + type boolean; + } + uses inv:node; + 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; @@ -45,6 +173,25 @@ module opendaylight-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; @@ -56,10 +203,6 @@ module opendaylight-flow-statistics { } } - notification flow-statistics-updated { - uses flow-types:flow-statistics; - } - rpc get-flow-table-statistics { input { uses inv:node-context-ref; @@ -79,6 +222,4 @@ module opendaylight-flow-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/flow-table-statistics.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-table-statistics.yang new file mode 100644 index 0000000000..b8233545c5 --- /dev/null +++ b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-table-statistics.yang @@ -0,0 +1,69 @@ +module opendaylight-flow-table-statistics { + namespace "urn:opendaylight:flow:table:statistics"; + prefix flowtablestat; + + 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-table-types {prefix table-types;revision-date "2013-10-26";} + import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";} + + + contact + "Anilkumar Vishnoi + Email: avishnoi@in.ibm.com"; + + revision "2013-12-15" { + description "Initial revision of flow table statistics model"; + } + + //Augment flow table statistics data to the table + augment "/inv:nodes/inv:node/flow-node:table" { + ext:augment-identifier "flow-table-statistics-data"; + uses flow-table-statistics; + } + + grouping flow-table-statistics { + container flow-table-statistics { + //config "false"; + uses stat-types:generic-table-statistics; + } + } + + //RPC calls to fetch flow table statistics + grouping flow-table-and-statistics-map { + list flow-table-and-statistics-map { + key "table-id"; + leaf table-id { + type table-types:table-id; + } + uses stat-types:generic-table-statistics; + } + } + + rpc get-flow-tables-statistics { + description "Fetch statistics of all the flow tables present on the tarnet node"; + input { + uses inv:node-context-ref; + } + output { + uses flow-table-and-statistics-map; + uses tr:transaction-aware; + } + } + + //Notification to receive table statistics update + + notification flow-table-statistics-update { + description "Receive flow table statistics update"; + + leaf moreReplies { + type boolean; + } + uses inv:node; + uses flow-table-and-statistics-map; + uses tr:transaction-aware; + } +} 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 new file mode 100644 index 0000000000..0cb6a60cfe --- /dev/null +++ b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/port-statistics.yang @@ -0,0 +1,78 @@ +module opendaylight-port-statistics { + namespace "urn:opendaylight:port:statistics"; + prefix portstat; + + 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 opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";} + + contact + "Anilkumar Vishnoi + Email: avishnoi@in.ibm.com"; + + revision "2013-12-14" { + description "Initial revision of port statistics model"; + } + + //Augment port statistics data to the flow-capable-node-connector + augment "/inv:nodes/inv:node/inv:node-connector" { + ext:augment-identifier "flow-capable-node-connector-statistics-data"; + uses flow-capable-node-connector-statistics; + } + + grouping flow-capable-node-connector-statistics { + container flow-capable-node-connector-statistics { + //config "false"; + uses stat-types:node-connector-statistics; + } + } + + // RPC calls + rpc get-all-ports-statistics { + description "Get statistics for all the ports from the node"; + input { + uses inv:node-context-ref; + } + output { + uses stat-types:node-connector-statistics; + uses tr:transaction-aware; + } + } + + rpc get-port-statistics { + description "Get statistics for given port from the node"; + input { + uses inv:node-context-ref; + leaf node-connector-id { + type inv:node-connector-id; + } + } + output { + uses stat-types:node-connector-statistics; + uses tr:transaction-aware; + } + } + + //Notification for port statistics update + grouping node-connector-statistics-and-port-number-map { + description "List of flow and statistics map"; + list node-connector-statistics-and-port-number-map { + key "node-connector-id"; + leaf node-connector-id { + type inv:node-connector-id; + } + uses stat-types:node-connector-statistics; + } + } + + notification port-statistics-update { + leaf moreReplies { + type boolean; + } + uses inv:node; + uses node-connector-statistics-and-port-number-map; + uses tr:transaction-aware; + } +} 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 d0b2e6a959..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,14 +61,62 @@ 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 { + description "Generic grouping for statistics"; + leaf packet-count { + type yang:counter64; + } + + leaf byte-count { + type yang:counter64; + } + uses duration; + } + + grouping generic-table-statistics { + description "Generic grouping holding generic statistics related to switch table"; + leaf active-flows { + type yang:counter32; + } + leaf packets-looked-up { + type yang:counter64; + } + leaf packets-matched { + type yang:counter64; + } + } + + grouping aggregate-flow-statistics { + description "Aggregate flow statistics"; + leaf packet-count { + type yang:counter64; + } + + leaf byte-count { + type yang:counter64; } + leaf flow-count { + type yang:counter32; + } + } + + 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 b34621d02d..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 @@ -120,6 +120,7 @@ https://sonar.opendaylight.org/ ${user.name}-private-view java + 3.0.0 @@ -427,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/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index f9f72094f8..1b0f78384f 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -250,6 +250,12 @@ ietf-inet-types 2010.09.24.2-SNAPSHOT + + org.opendaylight.yangtools.model + ietf-topology-l3-unicast-igp + 2013.10.21.0-SNAPSHOT + test + org.opendaylight.controller.model model-flow-base 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/codegen/util/JavassistUtils.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/JavassistUtils.xtend index 802e7acb5b..74efffafc6 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/JavassistUtils.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/util/JavassistUtils.xtend @@ -12,9 +12,16 @@ import javassist.LoaderClassPath import javassist.ClassClassPath import java.util.concurrent.locks.Lock import java.util.concurrent.locks.ReentrantLock +import org.slf4j.LoggerFactory +import java.util.HashMap +import java.util.WeakHashMap class JavassistUtils { + private static val LOG = LoggerFactory.getLogger(JavassistUtils); + + private val loaderClassPaths = new WeakHashMap(); + ClassPool classPool @Property @@ -95,14 +102,27 @@ class JavassistUtils { try { return pool.get(cls.name) } catch (NotFoundException e) { - pool.appendClassPath(new LoaderClassPath(cls.classLoader)); + appendClassLoaderIfMissing(cls.classLoader) try { return pool.get(cls.name) - } catch (NotFoundException ef) { + LOG.warn("Appending ClassClassPath for {}",cls); pool.appendClassPath(new ClassClassPath(cls)); + return pool.get(cls.name) } } } + + def void appendClassLoaderIfMissing(ClassLoader loader) { + if(loaderClassPaths.containsKey(loader)) { + return; + } + val ctLoader = new LoaderClassPath(loader); + classPool.appendClassPath(ctLoader); + } + + def void ensureClassLoader(Class child) { + appendClassLoaderIfMissing(child.classLoader); + } } 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 39bd0816f5..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); } @@ -389,8 +389,10 @@ public class LazyGeneratedCodecRegistry implements // public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) { pathToType.putAll(context.getChildNodes()); qnamesToIdentityMap.putAll(context.getIdentities()); - for(Entry identity : context.getIdentities().entrySet()) { - typeToQname.put(new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()),identity.getKey()); + for (Entry identity : context.getIdentities().entrySet()) { + typeToQname.put( + new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()), + identity.getKey()); } captureCases(context.getCases(), schemaContext); } @@ -947,12 +949,12 @@ public class LazyGeneratedCodecRegistry implements // @Override public Class deserialize(QName input) { Type type = qnamesToIdentityMap.get(input); - if(type == null) { + if (type == null) { return null; } ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName()); WeakReference softref = typeToClass.get(typeref); - if(softref == null) { + if (softref == null) { return null; } return softref.get(); @@ -963,12 +965,12 @@ public class LazyGeneratedCodecRegistry implements // checkArgument(BaseIdentity.class.isAssignableFrom(input)); bindingClassEncountered(input); QName qname = identityQNames.get(input); - if(qname != null) { + if (qname != null) { return qname; } ConcreteType typeref = Types.typeForClass(input); qname = typeToQname.get(typeref); - if(qname != null) { + if (qname != null) { identityQNames.put(input, qname); } return qname; @@ -980,4 +982,26 @@ public class LazyGeneratedCodecRegistry implements // return serialize((Class) input); } } + + public boolean isCodecAvailable(Class cls) { + if (containerCodecs.containsKey(cls)) { + return true; + } + if (identifierCodecs.containsKey(cls)) { + return true; + } + if (choiceCodecs.containsKey(cls)) { + return true; + } + if (caseCodecs.containsKey(cls)) { + return true; + } + if (augmentableCodecs.containsKey(cls)) { + return true; + } + if (augmentationCodecs.containsKey(cls)) { + return true; + } + return false; + } } \ No newline at end of file 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 13975cad4c..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) { @@ -170,7 +185,9 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer */ return; } - + if(registry.isCodecAvailable(class1)) { + return; + } val ref = Types.typeForClass(class1); getSchemaWithRetry(ref); } @@ -184,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) { @@ -241,30 +250,9 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable()); } } - - private def getTypeDefinition(Type type) { - val typeDef = typeToDefinition.get(type); - if (typeDef !== null) { - return typeDef; - } - return type.getTypeDefInFuture.get(); - } - - private def Future getTypeDefInFuture(Type type) { - val future = SettableFuture.create() - promisedTypeDefinitions.put(type, future); - return future; - } - - private def void updatePromisedTypeDefinitions(GeneratedTypeBuilder builder) { - val futures = promisedTypeDefinitions.get(builder); - if (futures === null || futures.empty) { - return; - } - for (future : futures) { - future.set(builder); - } - promisedTypeDefinitions.removeAll(builder); + + override getRpcQNamesFor(Class service) { + return serviceTypeToRpc.get(new ReferencedTypeImpl(service.package.name,service.simpleName)); } private def getSchemaWithRetry(Type type) { @@ -297,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 b2d25af885..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 @@ -51,6 +51,19 @@ import org.opendaylight.yangtools.yang.model.util.ExtendedType import org.opendaylight.yangtools.yang.model.util.EnumerationType import static com.google.common.base.Preconditions.* import org.opendaylight.yangtools.yang.model.api.SchemaPath +import javassist.CtMethod +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 { @@ -91,7 +104,7 @@ class TransformerGenerator { @Property var GeneratorListener listener; - + public static val CLASS_TYPE = Types.typeForClass(Class); public new(ClassPool pool) { @@ -132,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>>; ] @@ -238,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) { @@ -276,7 +298,7 @@ class TransformerGenerator { implementsType(BINDING_CODEC) method(Object, "toDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC - body = ''' + bodyChecked = ''' { «QName.name» _resultName; if($1 != null) { @@ -298,7 +320,7 @@ class TransformerGenerator { ] method(Object, "fromDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC - body = ''' + bodyChecked = ''' { if($2 == null){ return null; @@ -319,7 +341,7 @@ class TransformerGenerator { ''' ] method(Object, "serialize", Object) [ - body = ''' + bodyChecked = ''' { java.util.Map.Entry _input = (java.util.Map.Entry) $1; «QName.name» _localQName = («QName.name») _input.getKey(); @@ -329,13 +351,13 @@ class TransformerGenerator { ''' ] method(Object, "deserialize", Object) [ - body = ''' + bodyChecked = ''' return fromDomStatic(QNAME,$1); ''' ] ] 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); @@ -357,7 +379,7 @@ class TransformerGenerator { staticField(it, IDENTITYREF_CODEC, BindingCodec) method(Object, "toDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC - body = ''' + bodyChecked = ''' { «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName()); java.util.List _childNodes = new java.util.ArrayList(); @@ -368,7 +390,7 @@ class TransformerGenerator { ''' ] method(Object, "serialize", Object) [ - body = ''' + bodyChecked = ''' { java.util.Map.Entry _input = (java.util.Map.Entry) $1; «QName.name» _localName = QNAME; @@ -381,12 +403,12 @@ class TransformerGenerator { ] method(Object, "fromDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC - body = deserializeBody(type, node) + bodyChecked = deserializeBody(type, node) ] method(Object, "deserialize", Object) [ - body = ''' + 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()); } @@ -396,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); @@ -418,10 +440,10 @@ class TransformerGenerator { implementsType(BINDING_CODEC) method(Object, "toDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC - body = serializeBodyFacade(typeSpec, node) + bodyChecked = serializeBodyFacade(typeSpec, node) ] method(Object, "serialize", Object) [ - body = ''' + bodyChecked = ''' { java.util.Map.Entry _input = (java.util.Map.Entry) $1; «QName.name» _localName = QNAME; @@ -434,10 +456,10 @@ class TransformerGenerator { ] method(Object, "fromDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC - body = deserializeBody(typeSpec, node) + bodyChecked = deserializeBody(typeSpec, node) ] method(Object, "deserialize", Object) [ - body = ''' + bodyChecked = ''' return fromDomStatic(QNAME,$1); ''' ] @@ -445,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); @@ -468,16 +490,16 @@ class TransformerGenerator { implementsType(BINDING_CODEC) method(Object, "toDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC - body = ''' + 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; @@ -485,7 +507,7 @@ class TransformerGenerator { ''' ] method(Object, "serialize", Object) [ - body = ''' + bodyChecked = ''' { java.util.Map.Entry _input = (java.util.Map.Entry) $1; «QName.name» _localName = QNAME; @@ -498,7 +520,7 @@ class TransformerGenerator { ] method(Object, "fromDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC - body = ''' + bodyChecked = ''' { «QName.name» _localQName = QNAME; @@ -506,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» @@ -522,7 +544,7 @@ class TransformerGenerator { ''' ] method(Object, "deserialize", Object) [ - body = ''' + bodyChecked = ''' return fromDomStatic(QNAME,$1); ''' ] @@ -553,7 +575,7 @@ class TransformerGenerator { implementsType(BINDING_CODEC) method(List, "toDomStatic", QName, Object) [ modifiers = PUBLIC + FINAL + STATIC - body = ''' + bodyChecked = ''' { if($2 == null) { return null; @@ -566,19 +588,19 @@ 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; } ''' ] method(Object, "serialize", Object) [ - body = ''' + bodyChecked = ''' throw new «UnsupportedOperationException.name»("Direct invocation not supported."); ''' ] method(Object, "fromDomStatic", QName, Map) [ modifiers = PUBLIC + FINAL + STATIC - body = ''' + bodyChecked = ''' { «BINDING_CODEC.name» _codec = («BINDING_CODEC.name») «COMPOSITE_TO_CASE».get($2); if(_codec != null) { @@ -589,7 +611,7 @@ class TransformerGenerator { ''' ] method(Object, "deserialize", Object) [ - body = ''' + bodyChecked = ''' throw new «UnsupportedOperationException.name»("Direct invocation not supported."); ''' ] @@ -598,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); @@ -654,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)» @@ -669,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» @@ -684,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» @@ -717,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) { @@ -731,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(); @@ -740,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, @@ -765,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(); @@ -781,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)»; } ''' @@ -804,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; @@ -822,17 +847,10 @@ class TransformerGenerator { val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) return ret as Class, Object>>; } - var hasBinding = false; - try { - val bindingCodecClass = loadClassWithTCCL(BINDING_CODEC.name); - hasBinding = bindingCodecClass !== null; - } catch (ClassNotFoundException e) { - hasBinding = false; - } - val hasYangBinding = hasBinding + val ctCls = createClass(typeSpec.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); - if (hasYangBinding) { + if (inputType.isYangBindingAvailable) { implementsType(BINDING_CODEC) staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) staticField(it, IDENTITYREF_CODEC, BindingCodec) @@ -840,24 +858,25 @@ class TransformerGenerator { } method(Object, "toDomValue", Object) [ modifiers = PUBLIC + FINAL + STATIC - body = ''' + 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; } ''' ] method(Object, "serialize", Object) [ - body = ''' + bodyChecked = ''' { return toDomValue($1); } @@ -865,21 +884,21 @@ class TransformerGenerator { ] method(Object, "fromDomValue", Object) [ modifiers = PUBLIC + FINAL + STATIC - body = ''' + 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; } ''' ] method(Object, "deserialize", Object) [ - body = '''{ + bodyChecked = '''{ return fromDomValue($1); } ''' @@ -887,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); @@ -895,21 +914,215 @@ class TransformerGenerator { exception.addSuppressed(e); throw exception; } + } + 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; + } + ''' + ] + 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; + } + if($1 instanceof String) { + String _simpleValue = (String) $1; + return new «typeSpec.resolvedName»(_simpleValue.toCharArray()); + } + return null; + } + ''' + ] + 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; + } + } + + + 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) { + try { + val bindingCodecClass = class1.classLoader.loadClass(BINDING_CODEC.name); + return bindingCodecClass !== null; + } catch (ClassNotFoundException e) { + return false; + } } private def createDummyImplementation(Class object, GeneratedTransferObject typeSpec) { log.info("Generating Dummy DOM Codec for {} with {}", object, object.classLoader) return createClass(typeSpec.codecClassName) [ - //staticField(Map,"AUGMENTATION_SERIALIZERS"); - implementsType(BINDING_CODEC) - implementsType(BindingDeserializer.asCtClass) + if (object.isYangBindingAvailable) { + implementsType(BINDING_CODEC) + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) + implementsType(BindingDeserializer.asCtClass) + } + //implementsType(BindingDeserializer.asCtClass) method(Object, "toDomValue", Object) [ modifiers = PUBLIC + FINAL + STATIC - body = '''return null;''' + bodyChecked = '''{ + if($1 == null) { + return null; + } + return $1.toString(); + + }''' ] method(Object, "serialize", Object) [ - body = ''' + bodyChecked = ''' { return toDomValue($1); } @@ -917,10 +1130,10 @@ class TransformerGenerator { ] method(Object, "fromDomValue", Object) [ modifiers = PUBLIC + FINAL + STATIC - body = '''return null;''' + bodyChecked = '''return null;''' ] method(Object, "deserialize", Object) [ - body = '''{ + bodyChecked = '''{ return fromDomValue($1); } ''' @@ -940,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; @@ -952,7 +1165,7 @@ class TransformerGenerator { //implementsType(BINDING_CODEC) method(Object, "toDomValue", Object) [ modifiers = PUBLIC + FINAL + STATIC - body = '''{ + bodyChecked = '''{ if($1 == null) { return null; } @@ -967,13 +1180,13 @@ class TransformerGenerator { ''' ] method(Object, "serialize", Object) [ - body = ''' + bodyChecked = ''' return toDomValue($1); ''' ] method(Object, "fromDomValue", Object) [ modifiers = PUBLIC + FINAL + STATIC - body = ''' + bodyChecked = ''' { if($1 == null) { return null; @@ -989,14 +1202,14 @@ class TransformerGenerator { ''' ] method(Object, "deserialize", Object) [ - body = ''' + bodyChecked = ''' return fromDomValue($1); ''' ] ] 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); @@ -1026,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)) { @@ -1124,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» @@ -1166,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(); @@ -1184,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); @@ -1192,17 +1405,23 @@ 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)) { + } else if (CLASS_TYPE.equals(signature)) { return '''(«QName.resolvedName») «IDENTITYREF_CODEC».serialize(«property»)''' } + if ("char[]" == signature.name) { + return '''new String(«property»)'''; + } return '''«property»'''; } @@ -1215,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(); @@ -1316,6 +1535,21 @@ class TransformerGenerator { throw exception; } + private def setBodyChecked(CtMethod method, String body) { + try { + method.setBody(body); + } catch (CannotCompileException e) { + log.error("Cannot compile method: {}#{} {}, Reason: {} Body: {}", method.declaringClass, method.name, + method.signature, e.message, body) + throw e; + } + } + + private def V withClassLoaderAndLock(ClassLoader cls, Lock lock, Callable function) throws Exception { + appendClassLoaderIfMissing(cls); + ClassLoaderUtils.withClassLoaderAndLock(cls, lock, function); + } + } @Data 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/impl/util/ClassLoaderUtils.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java index d230fd17f9..e0eb102992 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java @@ -56,6 +56,8 @@ public final class ClassLoaderUtils { public static Class loadClassWithTCCL(String name) throws ClassNotFoundException { if ("byte[]".equals(name)) { return byte[].class; + } else if("char[]".equals(name)) { + return char[].class; } try { return Thread.currentThread().getContextClassLoader().loadClass(name); @@ -78,8 +80,7 @@ public final class ClassLoaderUtils { try { return loadClassWithTCCL(fullyQualifiedName); } catch (ClassNotFoundException e) { - + return null; } - return null; } } \ No newline at end of file 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/bugfix/UnionSerializationTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java new file mode 100644 index 0000000000..2057619bfd --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java @@ -0,0 +1,45 @@ +package org.opendaylight.controller.sal.binding.test.bugfix; + +import org.junit.Test; +import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.Prefix; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.PrefixBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; + + + + + + + + +import static org.junit.Assert.*; + +public class UnionSerializationTest extends AbstractDataServiceTest { + + public static final String PREFIX_STRING = "192.168.0.1/32"; + + + @Test + public void testPrefixSerialization() throws Exception { + + Ipv4Prefix ipv4prefix = new Ipv4Prefix(PREFIX_STRING); + IpPrefix ipPrefix = new IpPrefix(ipv4prefix); + Prefix prefix = new PrefixBuilder().setPrefix(ipPrefix).build(); + + CompositeNode serialized = testContext.getBindingToDomMappingService().toDataDom(prefix); + assertNotNull(serialized); + assertNotNull(serialized.getFirstSimpleByName(Prefix.QNAME)); + assertEquals(PREFIX_STRING, serialized.getFirstSimpleByName(Prefix.QNAME).getValue()); + + Prefix deserialized = (Prefix) testContext.getBindingToDomMappingService().dataObjectFromDataDom(InstanceIdentifier.builder().node(Prefix.class).build(), serialized); + assertNotNull(deserialized); + assertNotNull(deserialized.getPrefix()); + assertNotNull(deserialized.getPrefix().getIpv4Prefix()); + assertEquals(PREFIX_STRING, deserialized.getPrefix().getIpv4Prefix().getValue()); + } + +} 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/pom.xml b/opendaylight/md-sal/sal-binding-dom-it/pom.xml index 6525fa078e..7391139d0f 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/pom.xml +++ b/opendaylight/md-sal/sal-binding-dom-it/pom.xml @@ -13,7 +13,6 @@ scm:git:ssh://git.opendaylight.org:29418/controller.git https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL - @@ -49,6 +48,12 @@ + + org.ops4j.pax.exam + pax-exam-container-native + test + ${exam.version} + org.opendaylight.controller sal-binding-broker-impl diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java index 848fb6b190..c311161c44 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java @@ -7,9 +7,13 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import javassist.ClassPool; + +import org.junit.Ignore; 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.test.util.BindingBrokerTestFactory; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; @@ -23,6 +27,9 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + import static org.junit.Assert.*; public class DOMCodecBug02Test extends AbstractDataServiceTest { @@ -54,15 +61,32 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest { private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA); /** - * + * This test is ignored, till found out better way to test generation + * of classes without leaking of instances from previous run * * @throws Exception */ + + public void setUp() { + ListeningExecutorService executor = MoreExecutors.sameThreadExecutor(); + BindingBrokerTestFactory factory = new BindingBrokerTestFactory(); + factory.setExecutor(executor); + factory.setClassPool(new ClassPool()); + factory.setStartWithParsedSchema(getStartWithSchema()); + testContext = factory.getTestContext(); + testContext.start(); + + baDataService = testContext.getBindingDataBroker(); + biDataService = testContext.getDomDataBroker(); + dataStore = testContext.getDomDataStore(); + mappingService = testContext.getBindingToDomMappingService(); + }; + @Test public void testSchemaContextNotAvailable() throws Exception { ExecutorService testExecutor = Executors.newFixedThreadPool(1); - + testContext.loadYangSchemaFromClasspath(); Future>> future = testExecutor.submit(new Callable>>() { @Override public Future> call() throws Exception { @@ -74,11 +98,10 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest { } }); - testContext.loadYangSchemaFromClasspath(); + RpcResult result = future.get().get(); assertEquals(TransactionStatus.COMMITED, result.getResult()); - Nodes nodes = checkForNodes(); assertNotNull(nodes); 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-dom-broker/src/main/java/org/opendaylight/yangtools/yang/util/YangSchemaUtils.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/yangtools/yang/util/YangSchemaUtils.java index 44ee2a31b0..3ff1d1d6cb 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/yangtools/yang/util/YangSchemaUtils.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/yangtools/yang/util/YangSchemaUtils.java @@ -80,10 +80,11 @@ public class YangSchemaUtils { checkArgument(!iterator.hasNext(), "Path nests inside leaf node, which is not allowed."); return currentNode; } + checkState(currentNode != null, "Current node should not be null for %s",path); } + checkState(previous instanceof DataSchemaNode, "Schema node for %s should be instance of DataSchemaNode. Found %s",path,previous); return (DataSchemaNode) previous; } - private static DataSchemaNode searchInChoices(DataNodeContainer node, QName arg) { Set children = node.getChildNodes(); 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 fed56fe297..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,18 +30,14 @@ 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 org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition +import org.slf4j.LoggerFactory 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 class ControllerContext implements SchemaServiceListener { - + val static LOG = LoggerFactory.getLogger(ControllerContext) val static ControllerContext INSTANCE = new ControllerContext - val static NULL_VALUE = "null" var SchemaContext schemas; @@ -95,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] @@ -141,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) @@ -292,12 +308,10 @@ class ControllerContext implements SchemaServiceListener { checkArgument(node instanceof LeafSchemaNode); val urlDecoded = URLDecoder.decode(uriValue); 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) } @@ -329,8 +343,10 @@ class ControllerContext implements SchemaServiceListener { private def QName toQName(String name) { val module = name.toModuleName; val node = name.toNodeName; - val namespace = moduleNameToUri.get(module); - return new QName(namespace, null, node); + val namespace = FluentIterable.from(schemas.modules.sort[o1,o2 | o1.revision.compareTo(o2.revision)]) // + .transform[QName.create(namespace,revision,it.name)].findFirst[module == localName] + ; + return QName.create(namespace,node); } def getRpcDefinition(String name) { @@ -340,40 +356,9 @@ class ControllerContext implements SchemaServiceListener { override onGlobalContextUpdated(SchemaContext context) { this.schemas = context; for (operation : context.operations) { - val qname = new QName(operation.QName.namespace, null, operation.QName.localName); + val qname = operation.QName; qnameToRpc.put(qname, operation); } } - /** - * 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 new file mode 100644 index 0000000000..998d5d8faa --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java @@ -0,0 +1,67 @@ +/* + * Copyright IBM Corporation, 2013. 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.md.statistics.manager; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; + +/** + * Main responsibility of the class is to manage multipart response + * for multipart request. It also handles the flow aggregate request + * and response mapping. + * @author avishnoi@in.ibm.com + * + */ +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(){} + + public Short getTableIdForTxId(TransactionId id){ + + return txIdTotableIdMap.get(id); + + } + + 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 c48ac311ab..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 @@ -7,15 +7,26 @@ */ package org.opendaylight.controller.md.statistics.manager; +import java.util.HashMap; import java.util.List; +import java.util.Map; +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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; 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; public class NodeStatistics { @@ -33,6 +44,21 @@ public class NodeStatistics { private MeterFeatures meterFeatures; + private final Map> flowAndStatsMap= + new HashMap>(); + + private final Map tableAndAggregateFlowStatsMap = + new HashMap(); + + private final Map nodeConnectorStats = + new ConcurrentHashMap(); + + private final Map flowTableAndStatisticsMap = + new HashMap(); + + private final Map> NodeConnectorAndQueuesStatsMap = + new HashMap>(); + public NodeStatistics(){ } @@ -92,5 +118,23 @@ public class NodeStatistics { public void setMeterFeatures(MeterFeatures meterFeatures) { this.meterFeatures = meterFeatures; } - + + public Map> getFlowAndStatsMap() { + return flowAndStatsMap; + } + + public Map getFlowTableAndStatisticsMap() { + return flowTableAndStatisticsMap; + } + + public Map getTableAndAggregateFlowStatsMap() { + return tableAndAggregateFlowStatsMap; + } + 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/StatisticsProvider.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java index f22ca00b2a..95ba01cd54 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 @@ -7,16 +7,28 @@ */ package org.opendaylight.controller.md.statistics.manager; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +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; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInputBuilder; @@ -26,11 +38,18 @@ 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.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsOutput; 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.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; @@ -50,6 +69,16 @@ public class StatisticsProvider implements AutoCloseable { private OpendaylightMeterStatisticsService meterStatsService; + private OpendaylightFlowStatisticsService flowStatsService; + + private OpendaylightPortStatisticsService portStatsService; + + private OpendaylightFlowTableStatisticsService flowTableStatsService; + + private OpendaylightQueueStatisticsService queueStatsService; + + private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager(); + private Thread statisticsRequesterThread; private final InstanceIdentifier nodesIdentifier = InstanceIdentifier.builder(Nodes.class).toInstance(); @@ -76,6 +105,10 @@ public class StatisticsProvider implements AutoCloseable { this.nps = notificationService; } + public MultipartMessageManager getMultipartMessageManager() { + return multipartMessageManager; + } + private final StatisticsUpdateCommiter updateCommiter = new StatisticsUpdateCommiter(StatisticsProvider.this); private Registration listenerRegistration; @@ -92,7 +125,19 @@ public class StatisticsProvider implements AutoCloseable { meterStatsService = StatisticsManagerActivator.getProviderContext(). getRpcService(OpendaylightMeterStatisticsService.class); + + flowStatsService = StatisticsManagerActivator.getProviderContext(). + getRpcService(OpendaylightFlowStatisticsService.class); + portStatsService = StatisticsManagerActivator.getProviderContext(). + getRpcService(OpendaylightPortStatisticsService.class); + + flowTableStatsService = StatisticsManagerActivator.getProviderContext(). + getRpcService(OpendaylightFlowTableStatisticsService.class); + + queueStatsService = StatisticsManagerActivator.getProviderContext(). + getRpcService(OpendaylightQueueStatisticsService.class); + statisticsRequesterThread = new Thread( new Runnable(){ @Override @@ -124,21 +169,41 @@ public class StatisticsProvider implements AutoCloseable { private void statsRequestSender(){ - //Need to call API to receive all the nodes connected to controller. List targetNodes = getAllConnectedNodes(); if(targetNodes == null) return; + for (Node targetNode : targetNodes){ + + InstanceIdentifier targetInstanceId = InstanceIdentifier.builder(Nodes.class).child(Node.class,targetNode.getKey()).toInstance(); + NodeRef targetNodeRef = new NodeRef(targetInstanceId); + + System.out.println("ANIL: Target Node object ::"+targetNode.toString()); + + System.out.println("ANIL: FlowCapableNode augmentations ::"+targetNode.getAugmentation(FlowCapableNode.class)); + + try { + + sendAggregateFlowsStatsFromAllTablesRequest(targetNode.getKey()); - if(targetNode.getAugmentation(FlowCapableNode.class) != null){ + sendAllFlowsStatsFromAllTablesRequest(targetNodeRef); - spLogger.info("Send request for stats collection to node : {})",targetNode.getId()); + sendAllPortStatisticsRequest(targetNodeRef); - InstanceIdentifier targetInstanceId = InstanceIdentifier.builder(Nodes.class).child(Node.class,targetNode.getKey()).toInstance(); - NodeRef targetNodeRef = new NodeRef(targetInstanceId); + sendAllFlowTablesStatisticsRequest(targetNodeRef); + sendAllQueueStatsFromAllNodeConnector (targetNodeRef); + + }catch(Exception e){ + spLogger.error("Exception occured while sending statistics requests : {}",e); + } + + if(targetNode.getAugmentation(FlowCapableNode.class) != null){ + + spLogger.info("Send request for stats collection to node : {})",targetNode.getId()); + try{ sendAllGroupStatisticsRequest(targetNodeRef); Thread.sleep(1000); @@ -149,57 +214,159 @@ public class StatisticsProvider implements AutoCloseable { sendMeterConfigStatisticsRequest(targetNodeRef); Thread.sleep(1000); }catch(Exception e){ - spLogger.error("Exception occured while sending statistics request : {}", e); + spLogger.error("Exception occured while sending statistics requests : {}", e); } } } } + + private void sendAllFlowTablesStatisticsRequest(NodeRef targetNodeRef) throws InterruptedException, ExecutionException { + final GetFlowTablesStatisticsInputBuilder input = + new GetFlowTablesStatisticsInputBuilder(); + + input.setNode(targetNodeRef); + + Future> response = + flowTableStatsService.getFlowTablesStatistics(input.build()); + + this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId() + , StatsRequestType.ALL_FLOW_TABLE); + + } + + private void sendAllFlowsStatsFromAllTablesRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ + final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input = + new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder(); + + input.setNode(targetNode); + + Future> response = + flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build()); + + this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId() + , StatsRequestType.ALL_FLOW); + + } - private void sendAllGroupStatisticsRequest(NodeRef targetNode){ + private void sendAggregateFlowsStatsFromAllTablesRequest(NodeKey targetNodeKey) throws InterruptedException, ExecutionException{ - final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder(); + List tablesId = getTablesFromNode(targetNodeKey); + + if(tablesId.size() != 0){ + for(Short id : tablesId){ + + spLogger.info("Send aggregate stats request for flow table {} to node {}",id,targetNodeKey); + GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = + new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder(); + + input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance())); + input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(id)); + Future> response = + flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build()); + + multipartMessageManager.setTxIdAndTableIdMapEntry(response.get().getResult().getTransactionId(), id); + this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId() + , StatsRequestType.AGGR_FLOW); + } + } + + //Note: Just for testing, because i am not able to fetch table list from datastore + // Bug-225 is raised for investigation. + +// spLogger.info("Send aggregate stats request for flow table {} to node {}",1,targetNodeKey); +// GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = +// new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder(); +// +// input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance())); +// input.setTableId(new TableId((short)1)); +// Future> response = +// flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build());` +// +// multipartMessageManager.setTxIdAndTableIdMapEntry(response.get().getResult().getTransactionId(), (short)1); + + } + + private void sendAllPortStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ + + final GetAllPortsStatisticsInputBuilder input = new GetAllPortsStatisticsInputBuilder(); input.setNode(targetNode); + + Future> response = + portStatsService.getAllPortsStatistics(input.build()); + this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId() + , StatsRequestType.ALL_PORT); + + } + + 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; } @@ -213,6 +380,20 @@ public class StatisticsProvider implements AutoCloseable { spLogger.info("Number of connected nodes : {}",nodes.getNode().size()); return nodes.getNode(); } + + private List getTablesFromNode(NodeKey nodeKey){ + InstanceIdentifier nodesIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class,nodeKey).augmentation(FlowCapableNode.class).toInstance(); + + FlowCapableNode node = (FlowCapableNode)dps.readConfigurationData(nodesIdentifier); + List tablesId = new ArrayList(); + if(node != null && node.getTable()!=null){ + spLogger.info("Number of tables {} supported by node {}",node.getTable().size(),nodeKey); + for(Table table: node.getTable()){ + tablesId.add(table.getId()); + } + } + return tablesId; + } @SuppressWarnings("deprecation") @Override 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 86e6114b5f..edffb976c6 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 @@ -7,9 +7,47 @@ */ package org.opendaylight.controller.md.statistics.manager; +import java.util.HashMap; +import java.util.List; 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; +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.statistics.rev130819.AggregateFlowStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder; +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; +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.statistics.rev130819.flow.statistics.FlowStatisticsBuilder; +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.FlowTableStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate; +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; @@ -23,9 +61,17 @@ 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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; 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; @@ -39,16 +85,50 @@ 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.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 { + OpendaylightMeterStatisticsListener, + OpendaylightFlowStatisticsListener, + OpendaylightPortStatisticsListener, + OpendaylightFlowTableStatisticsListener, + OpendaylightQueueStatisticsListener{ + public final static Logger sucLogger = LoggerFactory.getLogger(StatisticsUpdateCommiter.class); + private final StatisticsProvider statisticsManager; + + private final int unaccountedFlowsCounter = 1; public StatisticsUpdateCommiter(final StatisticsProvider manager){ @@ -61,7 +141,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())){ @@ -70,29 +153,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())){ @@ -100,30 +194,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())){ @@ -132,30 +237,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())){ @@ -164,33 +279,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 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(); -// 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(); -// } + 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 @@ -264,9 +376,439 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList it.commit(); } + @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.debug("Received flow stats update : {}",notification.toString()); + + for(FlowAndStatisticsMapList map: notification.getFlowAndStatisticsMapList()){ + short tableId = map.getTableId(); + + DataModificationTransaction it = this.statisticsManager.startChange(); + + boolean foundOriginalFlow = false; + + FlowBuilder flowBuilder = new FlowBuilder(); + + FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder(); + + FlowBuilder flow = new FlowBuilder(); + flow.setContainerName(map.getContainerName()); + flow.setBufferId(map.getBufferId()); + flow.setCookie(map.getCookie()); + flow.setCookieMask(map.getCookieMask()); + flow.setFlags(map.getFlags()); + flow.setFlowName(map.getFlowName()); + flow.setHardTimeout(map.getHardTimeout()); + if(map.getFlowId() != null) + flow.setId(new FlowId(map.getFlowId().getValue())); + flow.setIdleTimeout(map.getIdleTimeout()); + flow.setInstallHw(map.isInstallHw()); + flow.setInstructions(map.getInstructions()); + if(map.getFlowId()!= null) + flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue()))); + flow.setMatch(map.getMatch()); + flow.setOutGroup(map.getOutGroup()); + flow.setOutPort(map.getOutPort()); + flow.setPriority(map.getPriority()); + flow.setStrict(map.isStrict()); + flow.setTableId(tableId); + + Flow flowRule = flow.build(); + + FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder(); + stats.setByteCount(map.getByteCount()); + stats.setPacketCount(map.getPacketCount()); + stats.setDuration(map.getDuration()); + + GenericStatistics flowStats = stats.build(); + + //Add statistics to local cache + ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); + if(!cache.containsKey(notification.getId())){ + cache.put(notification.getId(), new NodeStatistics()); + } + if(!cache.get(notification.getId()).getFlowAndStatsMap().containsKey(tableId)){ + cache.get(notification.getId()).getFlowAndStatsMap().put(tableId, new HashMap()); + } + cache.get(notification.getId()).getFlowAndStatsMap().get(tableId).put(flowRule,flowStats); + + //Augment the data to the flow node + + FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder(); + flowStatistics.setByteCount(flowStats.getByteCount()); + flowStatistics.setPacketCount(flowStats.getPacketCount()); + flowStatistics.setDuration(flowStats.getDuration()); + flowStatistics.setContainerName(map.getContainerName()); + flowStatistics.setBufferId(map.getBufferId()); + flowStatistics.setCookie(map.getCookie()); + flowStatistics.setCookieMask(map.getCookieMask()); + flowStatistics.setFlags(map.getFlags()); + flowStatistics.setFlowName(map.getFlowName()); + flowStatistics.setHardTimeout(map.getHardTimeout()); + flowStatistics.setIdleTimeout(map.getIdleTimeout()); + flowStatistics.setInstallHw(map.isInstallHw()); + flowStatistics.setInstructions(map.getInstructions()); + flowStatistics.setMatch(map.getMatch()); + flowStatistics.setOutGroup(map.getOutGroup()); + flowStatistics.setOutPort(map.getOutPort()); + flowStatistics.setPriority(map.getPriority()); + flowStatistics.setStrict(map.isStrict()); + flowStatistics.setTableId(tableId); + + flowStatisticsData.setFlowStatistics(flowStatistics.build()); + + 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(); + + Table table= (Table)it.readConfigurationData(tableRef); + + //TODO: Not a good way to do it, need to figure out better way. + //TODO: major issue in any alternate approach is that flow key is incrementally assigned + //to the flows stored in data store. + if(table != null){ + + for(Flow existingFlow : table.getFlow()){ + sucLogger.debug("Existing flow in data store : {}",existingFlow.toString()); + if(flowEquals(flowRule,existingFlow)){ + InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)) + .child(Flow.class,existingFlow.getKey()).toInstance(); + flowBuilder.setKey(existingFlow.getKey()); + flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); + sucLogger.debug("Found matching flow in the datastore, augmenting statistics"); + foundOriginalFlow = true; + it.putOperationalData(flowRef, flowBuilder.build()); + it.commit(); + break; + } + } + } + + if(!foundOriginalFlow){ + sucLogger.info("Associated original flow is not found in data store. Augmenting flow in operational data st"); + //TODO: Temporary fix: format [ 0+tableid+0+unaccounted flow counter] + long flowKey = Long.getLong(new String("0"+Short.toString(tableId)+"0"+Integer.toString(this.unaccountedFlowsCounter))); + FlowKey newFlowKey = new FlowKey(new FlowId(flowKey)); + InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)) + .child(Flow.class,newFlowKey).toInstance(); + flowBuilder.setKey(newFlowKey); + flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); + sucLogger.info("Flow was no present in data store, augmenting statistics as an unaccounted flow"); + it.putOperationalData(flowRef, flowBuilder.build()); + it.commit(); + } + } + } + + @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()); + + Short tableId = this.statisticsManager.getMultipartMessageManager().getTableIdForTxId(notification.getTransactionId()); + if(tableId != null){ + + DataModificationTransaction it = this.statisticsManager.startChange(); + + InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); + + AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder(); + AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(); + aggregateFlowStatisticsBuilder.setByteCount(notification.getByteCount()); + aggregateFlowStatisticsBuilder.setFlowCount(notification.getFlowCount()); + aggregateFlowStatisticsBuilder.setPacketCount(notification.getPacketCount()); + aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build()); + + ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); + if(!cache.containsKey(notification.getId())){ + cache.put(notification.getId(), new NodeStatistics()); + } + cache.get(notification.getId()).getTableAndAggregateFlowStatsMap().put(tableId,aggregateFlowStatisticsBuilder.build()); + + sucLogger.debug("Augment aggregate statistics: {} for table {} on Node {}",aggregateFlowStatisticsBuilder.build().toString(),tableId,key); + + TableBuilder tableBuilder = new TableBuilder(); + tableBuilder.setKey(new TableKey(tableId)); + tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build()); + it.putOperationalData(tableRef, tableBuilder.build()); + it.commit(); + + } + } + + @Override + public void onPortStatisticsUpdate(PortStatisticsUpdate 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 port 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 portsStats = notification.getNodeConnectorStatisticsAndPortNumberMap(); + for(NodeConnectorStatisticsAndPortNumberMap portStats : portsStats){ + + DataModificationTransaction it = this.statisticsManager.startChange(); + + FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder + = new FlowCapableNodeConnectorStatisticsBuilder(); + statisticsBuilder.setBytes(portStats.getBytes()); + statisticsBuilder.setCollisionCount(portStats.getCollisionCount()); + statisticsBuilder.setDuration(portStats.getDuration()); + statisticsBuilder.setPackets(portStats.getPackets()); + statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError()); + statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops()); + statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors()); + statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError()); + statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError()); + statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops()); + statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors()); + + //Update data in the cache + cache.get(notification.getId()).getNodeConnectorStats().put(portStats.getNodeConnectorId(), statisticsBuilder.build()); + + //Augment data to the node-connector + FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder = + new FlowCapableNodeConnectorStatisticsDataBuilder(); + + statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build()); + + InstanceIdentifier nodeConnectorRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance(); + + NodeConnector nodeConnector = (NodeConnector)it.readOperationalData(nodeConnectorRef); + + if(nodeConnector != null){ + sucLogger.debug("Augmenting port statistics {} to port {}",statisticsDataBuilder.build().toString(),nodeConnectorRef.toString()); + NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder(); + nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, statisticsDataBuilder.build()); + it.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build()); + it.commit(); + } + } + } + + @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()); + + List flowTablesStatsList = notification.getFlowTableAndStatisticsMap(); + for (FlowTableAndStatisticsMap ftStats : flowTablesStatsList){ + + DataModificationTransaction it = this.statisticsManager.startChange(); + + InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance(); + + FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder(); + + FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder(); + statisticsBuilder.setActiveFlows(ftStats.getActiveFlows()); + statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp()); + statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched()); + + statisticsDataBuilder.setFlowTableStatistics(statisticsBuilder.build()); + + ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); + if(!cache.containsKey(notification.getId())){ + cache.put(notification.getId(), new NodeStatistics()); + } + cache.get(notification.getId()).getFlowTableAndStatisticsMap().put(ftStats.getTableId().getValue(),statisticsBuilder.build()); + + sucLogger.debug("Augment flow table statistics: {} for table {} on Node {}",statisticsBuilder.build().toString(),ftStats.getTableId(),key); + + TableBuilder tableBuilder = new TableBuilder(); + tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue())); + tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build()); + it.putOperationalData(tableRef, tableBuilder.build()); + it.commit(); + } + } + + @Override + public void onQueueStatisticsUpdate(QueueStatisticsUpdate 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 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(); + + 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(); + + } + + } + + @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. + + } + + @Override + public void onFlowTableStatisticsUpdated(FlowTableStatisticsUpdated notification) { + // TODO Auto-generated method stub + //TODO: Need to implement it yet + + } + + @Override + public void onNodeConnectorStatisticsUpdated(NodeConnectorStatisticsUpdated notification) { + // TODO Auto-generated method stub + //TODO: Need to implement it yet + + } + private NodeRef getNodeRef(NodeKey nodeKey){ InstanceIdentifierBuilder builder = InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeKey); return new NodeRef(builder.toInstance()); } + + public 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/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java index 697b811d51..cf0e71e67a 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java @@ -29,12 +29,16 @@ public abstract class AttributeIfcSwitchStatement { this.lastAttribute = attributeIfc; + OpenType openType = attributeIfc.getOpenType(); + if (attributeIfc instanceof JavaAttribute) { try { if(((JavaAttribute)attributeIfc).getTypeDefinition() instanceof BinaryTypeDefinition) { - return caseJavaBinaryAttribute(attributeIfc.getOpenType()); + return caseJavaBinaryAttribute(openType); + } else if(((JavaAttribute)attributeIfc).isUnion()) { + return caseJavaUnionAttribute(openType); } else - return caseJavaAttribute(attributeIfc.getOpenType()); + return caseJavaAttribute(openType); } catch (UnknownOpenTypeException e) { throw getIllegalArgumentException(attributeIfc); } @@ -42,9 +46,9 @@ public abstract class AttributeIfcSwitchStatement { } else if (attributeIfc instanceof DependencyAttribute) { return caseDependencyAttribute(((DependencyAttribute) attributeIfc).getOpenType()); } else if (attributeIfc instanceof ListAttribute) { - return caseListAttribute((ArrayType) attributeIfc.getOpenType()); + return caseListAttribute((ArrayType) openType); } else if (attributeIfc instanceof ListDependenciesAttribute) { - return caseListDependeciesAttribute((ArrayType) attributeIfc.getOpenType()); + return caseListDependeciesAttribute((ArrayType) openType); } else if (attributeIfc instanceof TOAttribute) { return caseTOAttribute(((TOAttribute) attributeIfc).getOpenType()); } @@ -52,6 +56,10 @@ public abstract class AttributeIfcSwitchStatement { throw getIllegalArgumentException(attributeIfc); } + protected T caseJavaUnionAttribute(OpenType openType) { + return caseJavaAttribute(openType); + } + protected T caseJavaBinaryAttribute(OpenType openType) { return caseJavaAttribute(openType); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java new file mode 100644 index 0000000000..23cdabf69f --- /dev/null +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.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.netconf.confignetconfconnector.mapping.attributes; + +public class AttributesConstants { + + /** + * Property placed into object names for dependencies to preserve reference name + */ + public static final String REF_NAME_ON_PROPERTY_KEY = "X-refName"; +} diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectXmlReader.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectXmlReader.java index a2691f241c..97c0f4d834 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectXmlReader.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectXmlReader.java @@ -11,6 +11,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attri import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc; +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; @@ -47,6 +48,12 @@ public class ObjectXmlReader extends AttributeIfcSwitchStatement openType) { + String mappingKey = JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION; + return new SimpleUnionAttributeReadingStrategy(lastAttribute.getNullableDefault(), mappingKey); + } + @Override public AttributeReadingStrategy caseJavaSimpleAttribute(SimpleType openType) { return new SimpleAttributeReadingStrategy(lastAttribute.getNullableDefault()); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleUnionAttributeReadingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleUnionAttributeReadingStrategy.java new file mode 100644 index 0000000000..2e8b459b70 --- /dev/null +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleUnionAttributeReadingStrategy.java @@ -0,0 +1,43 @@ +/* + * 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.mapping.attributes.fromxml; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +import java.util.List; +import java.util.Map; + +public class SimpleUnionAttributeReadingStrategy extends SimpleAttributeReadingStrategy { + + private final String key; + + public SimpleUnionAttributeReadingStrategy(String nullableDefault, String key) { + super(nullableDefault); + this.key = key; + } + + protected Object postprocessParsedValue(String textContent) { + char[] charArray = textContent.toCharArray(); + List chars = Lists.newArrayListWithCapacity(charArray.length); + + for (char c : charArray) { + chars.add(Character.toString(c)); + } + + Map map = Maps.newHashMap(); + map.put(key, chars); + return map; + } + + @Override + protected Object postprocessNullableDefault(String nullableDefault) { + return nullableDefault == null ? null : postprocessParsedValue(nullableDefault); + } +} diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/CompositeAttributeMappingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/CompositeAttributeMappingStrategy.java index 252b13bf68..368e1f12a6 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/CompositeAttributeMappingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/CompositeAttributeMappingStrategy.java @@ -53,17 +53,21 @@ public class CompositeAttributeMappingStrategy extends Map retVal = Maps.newHashMap(); for (String jmxName : jmxToJavaNameMapping.keySet()) { - String innerAttrJmxName = jmxName; - Object innerValue = compositeData.get(innerAttrJmxName); - - AttributeMappingStrategy> attributeMappingStrategy = innerStrategies - .get(innerAttrJmxName); - Optional mapAttribute = attributeMappingStrategy.mapAttribute(innerValue); - if (mapAttribute.isPresent()) - retVal.put(jmxToJavaNameMapping.get(innerAttrJmxName), mapAttribute.get()); + Optional mapped = mapInnerAttribute(compositeData, jmxName, expectedType.getDescription(jmxName)); + if(mapped.isPresent()) + retVal.put(jmxToJavaNameMapping.get(jmxName), mapped.get()); } return Optional.of(retVal); } + protected Optional mapInnerAttribute(CompositeDataSupport compositeData, String jmxName, String description) { + Object innerValue = compositeData.get(jmxName); + + AttributeMappingStrategy> attributeMappingStrategy = innerStrategies + .get(jmxName); + Optional mapAttribute = attributeMappingStrategy.mapAttribute(innerValue); + return mapAttribute; + } + } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java index 6e5bd0d3fe..fb385221c8 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java @@ -90,6 +90,22 @@ public class ObjectMapper extends AttributeIfcSwitchStatement> caseJavaUnionAttribute(OpenType openType) { + Map>> innerStrategies = Maps.newHashMap(); + + Map attributeMapping = Maps.newHashMap(); + + CompositeType compositeType = (CompositeType) openType; + for (String innerAttributeKey : compositeType.keySet()) { + + innerStrategies.put(innerAttributeKey, caseJavaAttribute(compositeType.getType(innerAttributeKey))); + attributeMapping.put(innerAttributeKey, innerAttributeKey); + } + + return new UnionCompositeAttributeMappingStrategy(compositeType, innerStrategies, attributeMapping); + } + private String serviceNameOfDepAttr; private String namespaceOfDepAttr; diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectNameAttributeMappingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectNameAttributeMappingStrategy.java index f4d88c7c8e..8426341636 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectNameAttributeMappingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectNameAttributeMappingStrategy.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attri import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributesConstants; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.opendaylight.controller.netconf.confignetconfconnector.util.Util; @@ -42,7 +43,11 @@ public class ObjectNameAttributeMappingStrategy extends Util.checkType(value, ObjectName.class); ObjectName on = (ObjectName) value; - String refName = tracker.addServiceEntry(namespace, serviceName, on); + + String expectedRefName = on.getKeyProperty(AttributesConstants.REF_NAME_ON_PROPERTY_KEY); + + String refName = expectedRefName == null ? tracker.getRefName(namespace, serviceName, on, Optional. absent()) + : tracker.getRefName(namespace, serviceName, on, Optional.of(expectedRefName)); return Optional.of(new MappedDependency(namespace, serviceName, refName)); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/UnionCompositeAttributeMappingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/UnionCompositeAttributeMappingStrategy.java new file mode 100644 index 0000000000..81a1e53598 --- /dev/null +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/UnionCompositeAttributeMappingStrategy.java @@ -0,0 +1,34 @@ +/* + * 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.mapping.attributes.mapping; + +import com.google.common.base.Optional; +import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute; + +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import java.util.Map; + +public class UnionCompositeAttributeMappingStrategy extends + CompositeAttributeMappingStrategy { + + + public UnionCompositeAttributeMappingStrategy(CompositeType compositeType, Map>> innerStrategies, Map jmxToJavaNameMapping) { + super(compositeType, innerStrategies, jmxToJavaNameMapping); + } + + @Override + protected Optional mapInnerAttribute(CompositeDataSupport compositeData, String jmxName, String description) { + if(description.equals(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION) == false) + return Optional.absent(); + + return super.mapInnerAttribute(compositeData, jmxName, description); + } +} diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/CompositeAttributeResolvingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/CompositeAttributeResolvingStrategy.java index c477821051..e8e97f990f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/CompositeAttributeResolvingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/CompositeAttributeResolvingStrategy.java @@ -21,7 +21,7 @@ import javax.management.openmbean.OpenDataException; import javax.management.openmbean.OpenType; import java.util.Map; -final class CompositeAttributeResolvingStrategy extends +class CompositeAttributeResolvingStrategy extends AbstractAttributeResolvingStrategy { private final Map>> innerTypes; private final Map yangToJavaAttrMapping; @@ -49,6 +49,7 @@ final class CompositeAttributeResolvingStrategy extends Util.checkType(value, Map.class); Map valueMap = (Map) value; + valueMap = preprocessValueMap(valueMap); Map items = Maps.newHashMap(); Map> openTypes = Maps.newHashMap(); @@ -82,4 +83,8 @@ final class CompositeAttributeResolvingStrategy extends return Optional.of(parsedValue); } + + protected Map preprocessValueMap(Map valueMap) { + return valueMap; + } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectNameAttributeResolvingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectNameAttributeResolvingStrategy.java index c6f306b360..d8f0e2357e 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectNameAttributeResolvingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectNameAttributeResolvingStrategy.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attri import com.google.common.base.Optional; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributesConstants; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services.ServiceInstance; @@ -46,6 +47,8 @@ public class ObjectNameAttributeResolvingStrategy extends AbstractAttributeResol ServiceInstance byRefName = serviceTracker.getByServiceAndRefName(namespace, serviceName, refName); ObjectName on = ObjectNameUtil.createReadOnlyModuleON(byRefName.getModuleName(), byRefName.getInstanceName()); + on = ObjectNameUtil.createON(on.toString() + "," + AttributesConstants.REF_NAME_ON_PROPERTY_KEY + "=" + refName); + logger.debug("Attribute {} : {} parsed to type {}", attrName, value, getOpenType()); return Optional.of(on); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectResolver.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectResolver.java index f5a2511260..a3e2813fa0 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectResolver.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectResolver.java @@ -72,13 +72,30 @@ public class ObjectResolver extends AttributeIfcSwitchStatement> caseJavaCompositeAttribute(CompositeType openType) { Map>> innerMap = Maps.newHashMap(); - Map yangToJmxMapping = Maps.newHashMap(); + + fillMappingForComposite(openType, innerMap, yangToJmxMapping); + return new CompositeAttributeResolvingStrategy(innerMap, openType, yangToJmxMapping); + } + + private void fillMappingForComposite(CompositeType openType, Map>> innerMap, Map yangToJmxMapping) { for (String innerAttributeKey : openType.keySet()) { innerMap.put(innerAttributeKey, caseJavaAttribute(openType.getType(innerAttributeKey))); yangToJmxMapping.put(innerAttributeKey, innerAttributeKey); } - return new CompositeAttributeResolvingStrategy(innerMap, openType, yangToJmxMapping); + } + + @Override + protected AttributeResolvingStrategy> caseJavaUnionAttribute(OpenType openType) { + + Preconditions.checkState(openType instanceof CompositeType, "Unexpected open type, expected %s but was %s"); + CompositeType compositeType = (CompositeType) openType; + + Map>> innerMap = Maps.newHashMap(); + Map yangToJmxMapping = Maps.newHashMap(); + fillMappingForComposite(compositeType, innerMap, yangToJmxMapping); + + return new UnionCompositeAttributeResolvingStrategy(innerMap, compositeType, yangToJmxMapping); } @Override diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/UnionCompositeAttributeResolvingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/UnionCompositeAttributeResolvingStrategy.java new file mode 100644 index 0000000000..bc99ecf09a --- /dev/null +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/UnionCompositeAttributeResolvingStrategy.java @@ -0,0 +1,44 @@ +/* + * 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.mapping.attributes.resolving; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute; + +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import java.util.Map; + +final class UnionCompositeAttributeResolvingStrategy extends CompositeAttributeResolvingStrategy { + + UnionCompositeAttributeResolvingStrategy(Map>> innerTypes, + CompositeType openType, Map yangToJavaAttrMapping) { + super(innerTypes, openType, yangToJavaAttrMapping); + } + + protected Map preprocessValueMap(Map valueMap) { + CompositeType openType = getOpenType(); + + Preconditions.checkArgument( + valueMap.size() == 1 && valueMap.containsKey(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION), + "Unexpected structure of incoming map, expecting one element under %s, but was %s", + JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION, valueMap); + + Map newMap = Maps.newHashMap(); + + for (String key : openType.keySet()) { + if (openType.getDescription(key).equals(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION)) + newMap.put(key, valueMap.get(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION)); + else + newMap.put(key, null); + } + return newMap; + } +} diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectXmlWriter.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectXmlWriter.java index a174e9a251..4e870f042d 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectXmlWriter.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectXmlWriter.java @@ -73,6 +73,11 @@ public class ObjectXmlWriter extends AttributeIfcSwitchStatement openType) { + return new SimpleUnionAttributeWritingStrategy(document, key); + } + @Override protected AttributeWritingStrategy caseDependencyAttribute(SimpleType openType) { return new ObjectNameAttributeWritingStrategy(document, key); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleUnionAttributeWritingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleUnionAttributeWritingStrategy.java new file mode 100644 index 0000000000..d75feb273e --- /dev/null +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleUnionAttributeWritingStrategy.java @@ -0,0 +1,43 @@ +/* + * 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.mapping.attributes.toxml; + +import com.google.common.base.Preconditions; +import org.opendaylight.controller.netconf.confignetconfconnector.util.Util; +import org.w3c.dom.Document; + +import java.util.List; +import java.util.Map; + +public class SimpleUnionAttributeWritingStrategy extends SimpleAttributeWritingStrategy { + + /** + * @param document + * @param key + */ + public SimpleUnionAttributeWritingStrategy(Document document, String key) { + super(document, key); + } + + protected Object preprocess(Object value) { + Util.checkType(value, Map.class); + Preconditions.checkArgument(((Map)value).size() == 1, "Unexpected number of values in %s, expected 1", value); + Object listOfStrings = ((Map) value).values().iterator().next(); + Util.checkType(listOfStrings, List.class); + + StringBuilder b = new StringBuilder(); + for (Object character: (List)listOfStrings) { + Util.checkType(character, String.class); + b.append(character); + } + + return b.toString(); + } + +} diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java index f33a32271f..3a5fa1170f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java @@ -14,6 +14,7 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType; import org.opendaylight.controller.netconf.util.xml.XmlElement; @@ -53,7 +54,7 @@ public class Config { } public static Map>> getMappedInstances(Set instancesToMap, - Services serviceTracker, Map> configs) { + Map> configs) { Multimap moduleToInstances = mapInstancesToModules(instancesToMap); Map>> retVal = Maps.newLinkedHashMap(); @@ -75,13 +76,6 @@ public class Config { innerRetVal.put(moduleName, instances); - // All found instances add to service tracker in advance - // This way all instances will be serialized as all available - // services when get-config is triggered - // (even if they are not used as services by other instances) - // = more user friendly - addServices(serviceTracker, instances, mbeEntry.getValue().getProvidedServices()); - } retVal.put(namespace, innerRetVal); @@ -89,15 +83,6 @@ public class Config { return retVal; } - private static void addServices(Services serviceTracker, Collection instances, - Multimap providedServices) { - for (ObjectName instanceOn : instances) { - for (Entry serviceName : providedServices.entries()) { - serviceTracker.addServiceEntry(serviceName.getKey(), serviceName.getValue(), instanceOn); - } - } - } - private static Multimap mapInstancesToModules(Set instancesToMap) { Multimap retVal = HashMultimap.create(); @@ -114,11 +99,10 @@ public class Config { // } public Element toXml(Set instancesToMap, Optional maybeNamespace, Document document, - Element dataElement) { - Services serviceTracker = new Services(); + Element dataElement, Services serviceTracker) { Map>> moduleToInstances = getMappedInstances(instancesToMap, - serviceTracker, moduleConfigs); + moduleConfigs); Element root = dataElement; if (maybeNamespace.isPresent()) { @@ -167,13 +151,13 @@ public class Config { // TODO refactor, replace string representing namespace with namespace class // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved // class - public Map> fromXml(XmlElement xml, Set instancesForFillingServiceRefMapping, - EditStrategyType defaultEditStrategyType) { + public ConfigElementResolved fromXml(XmlElement xml, + EditStrategyType defaultEditStrategyType, ServiceReferenceReadableRegistry taClient) { Map> retVal = Maps.newHashMap(); List recognisedChildren = Lists.newArrayList(); - Services serviceTracker = fromXmlServices(xml, recognisedChildren, instancesForFillingServiceRefMapping); + Services serviceTracker = fromXmlServices(xml, recognisedChildren, taClient); List moduleElements = fromXmlModules(xml, recognisedChildren); xml.checkUnrecognisedElements(recognisedChildren); @@ -182,7 +166,26 @@ public class Config { resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType); } - return retVal; + return new ConfigElementResolved(retVal, serviceTracker); + } + + public static class ConfigElementResolved { + + private final Map> resolvedModules; + private final Services services; + + public ConfigElementResolved(Map> retVal, Services serviceTracker) { + this.resolvedModules = retVal; + this.services = serviceTracker; + } + + public Map> getResolvedModules() { + return resolvedModules; + } + + public Services getServices() { + return services; + } } private List fromXmlModules(XmlElement xml, List recognisedChildren) { @@ -224,7 +227,8 @@ public class Config { innerMap.put(factoryName, moduleElementResolved); } - private Services fromXmlServices(XmlElement xml, List recognisedChildren, Set instancesForFillingServiceRefMapping) { + private Services fromXmlServices(XmlElement xml, List recognisedChildren, + ServiceReferenceReadableRegistry taClient) { Optional servicesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG); @@ -235,22 +239,7 @@ public class Config { } else { mappedServices = new HashMap<>(); } - Services services = Services.resolveServices(mappedServices); - // merge with what candidate db contains by default - ref_ - - for(ObjectName existingON: instancesForFillingServiceRefMapping) { - logger.trace("Filling services from {}", existingON); - // get all its services - String factoryName = ObjectNameUtil.getFactoryName(existingON); - ModuleConfig moduleConfig = moduleNamesToConfigs.get(factoryName); - - checkState(moduleConfig != null, "Cannot find ModuleConfig with name " + factoryName + " in " + moduleNamesToConfigs); - // Set services = ; - for (Entry serviceName : moduleConfig.getProvidedServices().entries()) { - - services.addServiceEntry(serviceName.getKey(), serviceName.getValue(), existingON); - } - } + Services services = Services.resolveServices(mappedServices, taClient); return services; } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java index 33858746cb..aae1636165 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java @@ -12,6 +12,7 @@ import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; import org.opendaylight.controller.config.util.ConfigRegistryClient; import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry; import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc; @@ -128,7 +129,7 @@ public final class InstanceConfig { } public InstanceConfigElementResolved fromXml(XmlElement moduleElement, Services services, String moduleNamespace, - EditStrategyType defaultStrategy) { + EditStrategyType defaultStrategy, Multimap providedServices) { Map retVal = Maps.newHashMap(); Map strats = new ObjectXmlReader().prepareReading(yangToAttrConfig); @@ -153,7 +154,7 @@ public final class InstanceConfig { XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0); InstanceConfigElementResolved instanceConfigElementResolved = perInstanceEditStrategy.equals("") ? new InstanceConfigElementResolved( - retVal, defaultStrategy) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal, defaultStrategy); + retVal, defaultStrategy, providedServices) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal, defaultStrategy, providedServices); resolveConfiguration(instanceConfigElementResolved, services); return instanceConfigElementResolved; diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java index e4bd9212e9..55cb60bed5 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config; import com.google.common.base.Preconditions; +import com.google.common.collect.Multimap; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigStrategy; import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser; @@ -24,16 +25,19 @@ public class InstanceConfigElementResolved { private final EditStrategyType editStrategy; private final Map configuration; + private final Multimap providedServices; - public InstanceConfigElementResolved(String currentStrategy, Map configuration, EditStrategyType defaultStrategy) { + public InstanceConfigElementResolved(String currentStrategy, Map configuration, EditStrategyType defaultStrategy, Multimap providedServices) { EditStrategyType valueOf = checkStrategy(currentStrategy, defaultStrategy); this.editStrategy = valueOf; this.configuration = configuration; + this.providedServices = providedServices; } - public InstanceConfigElementResolved(Map configuration, EditStrategyType defaultStrategy) { + public InstanceConfigElementResolved(Map configuration, EditStrategyType defaultStrategy, Multimap providedServices) { editStrategy = defaultStrategy; this.configuration = configuration; + this.providedServices = providedServices; } @@ -54,7 +58,7 @@ public class InstanceConfigElementResolved { public EditConfigStrategy getEditStrategy() { - return editStrategy.getFittingStrategy(); + return editStrategy.getFittingStrategy(providedServices); } public Map getConfiguration() { diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java index 2e2a26400f..2ac6fe0a9b 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java @@ -87,7 +87,7 @@ public class ModuleConfig { public ModuleElementResolved fromXml(XmlElement moduleElement, Services depTracker, String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) { - InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy); + InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy, providedServices); return new ModuleElementResolved(instanceName, ice); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java index f522668733..77f3cf283f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java @@ -9,10 +9,14 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import com.google.common.collect.HashMultimap; import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; import com.google.common.collect.Sets; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectNameAttributeReadingStrategy; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; @@ -22,9 +26,9 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -import javax.annotation.Nullable; import javax.management.ObjectName; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -33,6 +37,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public final class Services { + private static final Logger logger = LoggerFactory.getLogger(Services.class); private static final String PROVIDER_KEY = "provider"; @@ -42,58 +47,33 @@ public final class Services { private long suffix = 1; - private final Map instanceToRef = Maps.newHashMap(); private final Map>> namespaceToServiceNameToRefNameToInstance = Maps .newHashMap(); + private ServiceReferenceReadableRegistry configServiceRefRegistry; - public String addServiceEntry(String namespace, String serviceName, ObjectName on) { - - String moduleName = on.getKeyProperty("moduleFactoryName"); - String instanceName = on.getKeyProperty("instanceName"); - - String refName = addServiceEntry(namespace, serviceName, moduleName, instanceName); - logger.trace("Added service entry to tracker. Service name {}, ref name {}, module name {}, instance name {}", - serviceName, refName, moduleName, instanceName); - return refName; + public Services(ServiceReferenceReadableRegistry configServiceRefRegistry) { + this.configServiceRefRegistry = configServiceRefRegistry; } @VisibleForTesting - public String addServiceEntry(String namespace, String serviceName, String moduleName, String instanceName) { - ServiceInstance serviceInstance = new ServiceInstance(moduleName, instanceName); - serviceInstance.setServiceName(serviceName); + public String getNewDefaultRefName(String namespace, String serviceName, String moduleName, String instanceName) { + String refName; + refName = "ref_" + instanceName; - String refName = instanceToRef.get(serviceInstance); + Map> serviceNameToRefNameToInstance = getMappedServices().get(namespace); - Map> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace); - if (serviceNameToRefNameToInstance == null) { - serviceNameToRefNameToInstance = Maps.newHashMap(); - namespaceToServiceNameToRefNameToInstance.put(namespace, serviceNameToRefNameToInstance); - } + Map refNameToInstance; + if(serviceNameToRefNameToInstance == null || serviceNameToRefNameToInstance.containsKey(serviceName) == false) { + refNameToInstance = Collections.emptyMap(); + } else + refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); - Map refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); - if (refNameToInstance == null) { - refNameToInstance = Maps.newHashMap(); - serviceNameToRefNameToInstance.put(serviceName, refNameToInstance); + final Set refNamesAsSet = toSet(refNameToInstance.keySet()); + if (refNamesAsSet.contains(refName)) { + refName = findAvailableRefName(refName, refNamesAsSet); } - if (refName != null) { - if (serviceNameToRefNameToInstance.get(serviceName).containsKey(moduleName) == false) { - refNameToInstance.put(refName, serviceInstance); - } - return refName; - } else { - refName = "ref_" + instanceName; - - final Set refNamesAsSet = toSet(instanceToRef.values()); - if (refNamesAsSet.contains(refName)) { - refName = findAvailableRefName(refName, refNamesAsSet); - } - - instanceToRef.put(serviceInstance, refName); - refNameToInstance.put(refName, serviceInstance); - - return refName; - } + return refName; } private Set toSet(Collection values) { @@ -109,15 +89,19 @@ public final class Services { } public ServiceInstance getByServiceAndRefName(String namespace, String serviceName, String refName) { - Map> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace); - Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace + " , " - + serviceNameToRefNameToInstance.keySet()); + Map> serviceNameToRefNameToInstance = getMappedServices().get(namespace); + + Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace); - Map refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); + Map refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); Preconditions.checkArgument(refNameToInstance != null, "No serviceInstances mapped to " + serviceName + " , " + serviceNameToRefNameToInstance.keySet()); - ServiceInstance serviceInstance = refNameToInstance.get(refName); + String instanceId = refNameToInstance.get(refName); + Preconditions.checkArgument(instanceId != null, "No serviceInstances mapped to " + serviceName + ":" + + refName + ", " + serviceNameToRefNameToInstance.keySet()); + + ServiceInstance serviceInstance = ServiceInstance.fromString(instanceId); Preconditions.checkArgument(serviceInstance != null, "No serviceInstance mapped to " + refName + " under service name " + serviceName + " , " + refNameToInstance.keySet()); return serviceInstance; @@ -136,26 +120,61 @@ public final class Services { for (String serviceName : serviceNameToRefNameToInstance.keySet()) { - Map innerInnerRetVal = Maps.transformValues( - serviceNameToRefNameToInstance.get(serviceName), new Function() { - @Nullable - @Override - public String apply(@Nullable ServiceInstance serviceInstance) { - return serviceInstance.toString(); - } - }); + Map innerInnerRetVal = Maps.newHashMap(); + for (Entry refNameToSi : serviceNameToRefNameToInstance.get(serviceName).entrySet()) { + innerInnerRetVal.put(refNameToSi.getKey(), refNameToSi.getValue().toString()); + } innerRetVal.put(serviceName, innerInnerRetVal); } retVal.put(namespace, innerRetVal); } + Map> serviceMapping = configServiceRefRegistry.getServiceMapping(); + for (String serviceQName : serviceMapping.keySet()) + for (String refName : serviceMapping.get(serviceQName).keySet()) { + + ObjectName on = serviceMapping.get(serviceQName).get(refName); + ServiceInstance si = ServiceInstance.fromObjectName(on); + + // FIXME use QName's new String constructor, after its implemented + Pattern p = Pattern.compile("\\(([^\\(\\?]+)\\?[^\\?\\)]*\\)([^\\)]+)"); + Matcher matcher = p.matcher(serviceQName); + Preconditions.checkArgument(matcher.matches()); + String namespace = matcher.group(1); + String localName = matcher.group(2); + + Map> serviceToRefs = retVal.get(namespace); + if(serviceToRefs==null) { + serviceToRefs = Maps.newHashMap(); + retVal.put(namespace, serviceToRefs); + } + + Map refsToSis = serviceToRefs.get(localName); + if(refsToSis==null) { + refsToSis = Maps.newHashMap(); + serviceToRefs.put(localName, refsToSis); + } + + Preconditions.checkState(refsToSis.containsKey(refName) == false, + "Duplicate reference name %s for service %s:%s, now for instance %s", refName, namespace, + localName, on); + refsToSis.put(refName, si.toString()); + } + return retVal; } + /** + * + */ + public Map>> getNamespaceToServiceNameToRefNameToInstance() { + return namespaceToServiceNameToRefNameToInstance; + } + // TODO hide resolveServices, call it explicitly in fromXml - public static Services resolveServices(Map>> mappedServices) { - Services tracker = new Services(); + public static Services resolveServices(Map>> mappedServices, ServiceReferenceReadableRegistry taClient) { + Services tracker = new Services(taClient); for (Entry>> namespaceEntry : mappedServices.entrySet()) { String namespace = namespaceEntry.getKey(); @@ -179,18 +198,18 @@ public final class Services { } String refName = refEntry.getKey(); - Preconditions.checkState(false == refNameToInstance.containsKey(refName), - "Duplicate reference name to service " + refName + " under service " + serviceName); + ServiceInstance serviceInstance = ServiceInstance.fromString(refEntry.getValue()); refNameToInstance.put(refName, serviceInstance); - tracker.instanceToRef.put(serviceInstance, refEntry.getKey()); } } } return tracker; } + // TODO support edit strategies on services + public static Map>> fromXml(XmlElement xml) { Map>> retVal = Maps.newHashMap(); @@ -275,6 +294,51 @@ public final class Services { return root; } + public String getRefName(String namespace, String serviceName, ObjectName on, Optional expectedRefName) { + Optional refNameOptional = getRefNameOptional(namespace, serviceName, on, expectedRefName); + Preconditions.checkState(refNameOptional.isPresent(), "No reference names mapped to %s, %s, %s", namespace, + serviceName, on); + return refNameOptional.get(); + } + + public Optional getRefNameOptional(String namespace, String serviceName, ObjectName on, + Optional expectedRefName) { + Map> services = getMappedServices().get(namespace); + + if(services == null) return Optional.absent(); + Map refs = services.get(serviceName); + + if(refs == null) return Optional.absent(); + Multimap reverted = revertMap(refs); + + ServiceInstance serviceInstance = ServiceInstance.fromObjectName(on); + Collection references = reverted.get(serviceInstance); + + if (expectedRefName.isPresent() && references.contains(expectedRefName.get())) { + logger.debug("Returning expected ref name {} for {}", expectedRefName.get(), on); + return expectedRefName; + } else if (references.size() > 0) { + String next = references.iterator().next(); + logger.debug("Returning random ref name {} for {}", next, on); + return Optional.of(next); + } else + return Optional.absent(); + } + + private Multimap revertMap(Map refs) { + Multimap multimap = HashMultimap.create(); + + for (Entry e : refs.entrySet()) { + multimap.put(ServiceInstance.fromString(e.getValue()), e.getKey()); + } + + return multimap; + } + + public boolean hasRefName(String key, String value, ObjectName on) { + return getRefNameOptional(key, value, on, Optional.absent()).isPresent(); + } + public static final class ServiceInstance { public ServiceInstance(String moduleName, String instanceName) { this.moduleName = moduleName; @@ -372,6 +436,13 @@ public final class Services { return true; } + public ObjectName getObjectName(String transactionName) { + return ObjectNameUtil.createTransactionModuleON(transactionName, moduleName, instanceName); + } + + public static ServiceInstance fromObjectName(ObjectName on) { + return new ServiceInstance(ObjectNameUtil.getFactoryName(on), ObjectNameUtil.getInstanceName(on)); + } } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java index 64f295a4d8..89c782c51c 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java @@ -11,6 +11,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.runti import com.google.common.collect.HashMultimap; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig; @@ -60,8 +61,8 @@ public class Runtime { return retVal; } - public Element toXml(Set instancesToMap, Set configBeans, Document document) { - Services serviceTracker = new Services(); + public Element toXml(Set instancesToMap, Set configBeans, Document document, ServiceReferenceReadableRegistry serviceRegistry) { + Services serviceTracker = new Services(serviceRegistry); Element root = document.createElement(XmlNetconfConstants.DATA_KEY); @@ -72,7 +73,7 @@ public class Runtime { Map> moduleToRuntimeInstance = mapInstancesToModules(instancesToMap); Map>> moduleToConfigInstance = Config.getMappedInstances( - configBeans, serviceTracker, moduleConfigs); + configBeans, moduleConfigs); for (String localNamespace : moduleConfigs.keySet()) { diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/AbstractEditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/AbstractEditConfigStrategy.java index d8ea7d7af7..65df965afd 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/AbstractEditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/AbstractEditConfigStrategy.java @@ -8,38 +8,38 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig; -import java.util.Map; - -import javax.management.InstanceNotFoundException; -import javax.management.ObjectName; - import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import java.util.Map; + public abstract class AbstractEditConfigStrategy implements EditConfigStrategy { private static final Logger logger = LoggerFactory.getLogger(AbstractEditConfigStrategy.class); @Override public void executeConfiguration(String module, String instance, Map configuration, - ConfigTransactionClient ta) { + ConfigTransactionClient ta, Services services) { try { ObjectName on = ta.lookupConfigBean(module, instance); logger.debug("ServiceInstance for {} {} located successfully under {}", module, instance, on); - executeStrategy(configuration, ta, on); + executeStrategy(configuration, ta, on, services); } catch (InstanceNotFoundException e) { - handleMissingInstance(configuration, ta, module, instance); + handleMissingInstance(configuration, ta, module, instance, services); } } abstract void handleMissingInstance(Map configuration, ConfigTransactionClient ta, - String module, String instance); + String module, String instance, Services services); abstract void executeStrategy(Map configuration, ConfigTransactionClient ta, - ObjectName objectName); + ObjectName objectName, Services services); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/DeleteEditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/DeleteEditConfigStrategy.java index ffe107f8ce..12beaf8f8e 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/DeleteEditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/DeleteEditConfigStrategy.java @@ -8,28 +8,40 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig; -import java.util.Map; - -import javax.management.InstanceNotFoundException; -import javax.management.ObjectName; - +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import java.util.Map; + public class DeleteEditConfigStrategy extends AbstractEditConfigStrategy { private static final Logger logger = LoggerFactory.getLogger(DeleteEditConfigStrategy.class); + private final Multimap providedServices; + + public DeleteEditConfigStrategy() { + this.providedServices = HashMultimap.create(); + } + + public DeleteEditConfigStrategy(Multimap providedServices) { + this.providedServices = providedServices; + } + @Override void handleMissingInstance(Map configuration, ConfigTransactionClient ta, - String module, String instance) { + String module, String instance, Services services) { throw new IllegalStateException("Unable to delete " + module + ":" + instance + " , ServiceInstance not found"); } @Override - void executeStrategy(Map configuration, ConfigTransactionClient ta, ObjectName on) { + void executeStrategy(Map configuration, ConfigTransactionClient ta, ObjectName on, Services services) { try { ta.destroyModule(on); logger.debug("ServiceInstance {} deleted successfully", on); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java index 1fca16433a..1bb1d9bfba 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java @@ -26,6 +26,7 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation; import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution; import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider; @@ -36,6 +37,7 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; +import javax.management.InstanceNotFoundException; import javax.management.ObjectName; import java.util.HashMap; import java.util.Map; @@ -61,6 +63,7 @@ public class EditConfig extends AbstractConfigNetconfOperation { @VisibleForTesting Element getResponseInternal(final Document document, final EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException { + if (editConfigExecution.shouldTest()) { executeTests(configRegistryClient, editConfigExecution); } @@ -91,7 +94,7 @@ public class EditConfig extends AbstractConfigNetconfOperation { private void executeTests(ConfigRegistryClient configRegistryClient, EditConfigExecution editConfigExecution) throws NetconfDocumentedException { try { - test(configRegistryClient, editConfigExecution.getResolvedXmlElements(), editConfigExecution.getDefaultStrategy()); + test(configRegistryClient, editConfigExecution, editConfigExecution.getDefaultStrategy()); } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) { logger.warn("Test phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e); final Map errorInfo = new HashMap<>(); @@ -103,7 +106,7 @@ public class EditConfig extends AbstractConfigNetconfOperation { } private void test(ConfigRegistryClient configRegistryClient, - Map> resolvedModules, EditStrategyType editStrategyType) { + EditConfigExecution execution, EditStrategyType editStrategyType) { ObjectName taON = transactionProvider.getTestTransaction(); try { @@ -111,7 +114,9 @@ public class EditConfig extends AbstractConfigNetconfOperation { if (editStrategyType == EditStrategyType.replace) { transactionProvider.wipeTestTransaction(taON); } - setOnTransaction(configRegistryClient, resolvedModules, taON); + + setOnTransaction(configRegistryClient, execution.getResolvedXmlElements(), execution.getServices(), taON); + // TODO add service reference persistance testing here transactionProvider.validateTestTransaction(taON); } finally { transactionProvider.abortTestTransaction(taON); @@ -126,11 +131,45 @@ public class EditConfig extends AbstractConfigNetconfOperation { if (editConfigExecution.getDefaultStrategy() == EditStrategyType.replace) { transactionProvider.wipeTransaction(); } - setOnTransaction(configRegistryClient, editConfigExecution.getResolvedXmlElements(), taON); + + setOnTransaction(configRegistryClient, editConfigExecution.getResolvedXmlElements(), + editConfigExecution.getServices(), taON); + setServicesOnTransaction(configRegistryClient, editConfigExecution.getServices(), taON); + } + + private void setServicesOnTransaction(ConfigRegistryClient configRegistryClient, Services services, + ObjectName taON) { + ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON); + + Map>> namespaceToServiceNameToRefNameToInstance = services + .getNamespaceToServiceNameToRefNameToInstance(); + + for (String serviceNamespace : namespaceToServiceNameToRefNameToInstance.keySet()) { + for (String serviceName : namespaceToServiceNameToRefNameToInstance.get(serviceNamespace).keySet()) { + + String qnameOfService = getQname(ta, serviceNamespace, serviceName); + Map refNameToInstance = namespaceToServiceNameToRefNameToInstance + .get(serviceNamespace).get(serviceName); + + for (String refName : refNameToInstance.keySet()) { + ObjectName on = refNameToInstance.get(refName).getObjectName(ta.getTransactionName()); + // TODO check for duplicates + try { + ta.saveServiceReference(qnameOfService, refName, on); + } catch (InstanceNotFoundException e) { + throw new IllegalStateException("Unable to save ref name " + refName + " for instance " + on, e); + } + } + } + } + } + + private String getQname(ConfigTransactionClient ta, String namespace, String serviceName) { + return ta.getServiceInterfaceName(namespace, serviceName); } private void setOnTransaction(ConfigRegistryClient configRegistryClient, - Map> resolvedXmlElements, ObjectName taON) { + Map> resolvedXmlElements, Services services, ObjectName taON) { ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON); for (Multimap modulesToResolved : resolvedXmlElements.values()) { @@ -142,7 +181,7 @@ public class EditConfig extends AbstractConfigNetconfOperation { InstanceConfigElementResolved ice = moduleElementResolved.getInstanceConfigElementResolved(); EditConfigStrategy strategy = ice.getEditStrategy(); - strategy.executeConfiguration(moduleName, instanceName, ice.getConfiguration(), ta); + strategy.executeConfiguration(moduleName, instanceName, ice.getConfiguration(), ta, services); } } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigStrategy.java index 6b7b622d56..23166e8cca 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigStrategy.java @@ -10,12 +10,13 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ed import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import java.util.Map; public interface EditConfigStrategy { void executeConfiguration(String module, String instance, Map configuration, - ConfigTransactionClient ta); + ConfigTransactionClient ta, Services services); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java index 3d4e5b6d0c..81327133b8 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java @@ -12,10 +12,13 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.Multimap; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.util.ConfigRegistryClient; +import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore; import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider; import org.opendaylight.controller.netconf.util.xml.XmlElement; @@ -25,9 +28,7 @@ import org.slf4j.LoggerFactory; import javax.management.ObjectName; import java.util.Arrays; -import java.util.Collections; import java.util.Map; -import java.util.Set; public class EditConfigXmlParser { @@ -47,6 +48,8 @@ public class EditConfigXmlParser { TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient) throws NetconfDocumentedException { + //TODO remove transactionProvider and CfgRegistry from parameters, accept only service ref store + EditStrategyType editStrategyType = EditStrategyType.getDefaultStrategy(); xml.checkName(EditConfigXmlParser.EDIT_CONFIG); @@ -92,21 +95,14 @@ public class EditConfigXmlParser { logger.trace("Setting merge strategy to {}", mergeStrategyString); editStrategyType = EditStrategyType.valueOf(mergeStrategyString); } - Set instancesForFillingServiceRefMapping = Collections.emptySet(); - if (editStrategyType == EditStrategyType.merge) { - instancesForFillingServiceRefMapping = Datastore.getInstanceQueryStrategy(targetDatastore, transactionProvider) - .queryInstances(configRegistryClient); - logger.trace("Pre-filling services from following instances: {}", instancesForFillingServiceRefMapping); - } XmlElement configElement = xml.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.CONFIG_KEY); - return new EditConfigXmlParser.EditConfigExecution(xml, cfgMapping, configElement, testOption, - instancesForFillingServiceRefMapping, editStrategyType); - } + ObjectName taON = transactionProvider.getOrCreateTransaction(); + ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON); - private void removeMountpointsFromConfig(XmlElement configElement, XmlElement mountpointsElement) { - configElement.getDomElement().removeChild(mountpointsElement.getDomElement()); + return new EditConfigXmlParser.EditConfigExecution(cfgMapping, configElement, testOption, + ta, editStrategyType); } @VisibleForTesting @@ -135,15 +131,16 @@ public class EditConfigXmlParser { @VisibleForTesting static class EditConfigExecution { - private final XmlElement editConfigXml; + private final Map> resolvedXmlElements; private final TestOption testOption; private final EditStrategyType defaultEditStrategyType; + private final Services services; - EditConfigExecution(XmlElement xml, Config configResolver, XmlElement configElement, TestOption testOption, Set instancesForFillingServiceRefMapping, - EditStrategyType defaultStrategy) { - this.editConfigXml = xml; - this.resolvedXmlElements = configResolver.fromXml(configElement, instancesForFillingServiceRefMapping, defaultStrategy); + EditConfigExecution(Config configResolver, XmlElement configElement, TestOption testOption, ServiceReferenceReadableRegistry ta, EditStrategyType defaultStrategy) { + Config.ConfigElementResolved configElementResolved = configResolver.fromXml(configElement, defaultStrategy, ta); + this.resolvedXmlElements = configElementResolved.getResolvedModules(); + this.services = configElementResolved.getServices(); this.testOption = testOption; this.defaultEditStrategyType = defaultStrategy; } @@ -163,5 +160,9 @@ public class EditConfigXmlParser { EditStrategyType getDefaultStrategy() { return defaultEditStrategyType; } + + Services getServices() { + return services; + } } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java index cb03342a1e..676467553b 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java @@ -8,6 +8,8 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig; +import com.google.common.collect.Multimap; + import java.util.EnumSet; import java.util.Set; @@ -40,14 +42,14 @@ public enum EditStrategyType { } } - public EditConfigStrategy getFittingStrategy() { + public EditConfigStrategy getFittingStrategy(Multimap providedServices) { switch (this) { case merge: - return new MergeEditConfigStrategy(); + return new MergeEditConfigStrategy(providedServices); case replace: - return new ReplaceEditConfigStrategy(); + return new ReplaceEditConfigStrategy(providedServices); case delete: - return new DeleteEditConfigStrategy(); + return new DeleteEditConfigStrategy(providedServices); case remove: return new RemoveEditConfigStrategy(); case none: diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/MergeEditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/MergeEditConfigStrategy.java index 2a4a784a8a..06befb0565 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/MergeEditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/MergeEditConfigStrategy.java @@ -8,37 +8,67 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig; -import java.util.Map; -import java.util.Map.Entry; - -import javax.management.Attribute; -import javax.management.InstanceAlreadyExistsException; -import javax.management.ObjectName; - +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.management.Attribute; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import java.util.Map; +import java.util.Map.Entry; + public class MergeEditConfigStrategy extends AbstractEditConfigStrategy { private static final Logger logger = LoggerFactory.getLogger(MergeEditConfigStrategy.class); + private final Multimap providedServices; + + public MergeEditConfigStrategy() { + this.providedServices = HashMultimap.create(); + } + + public MergeEditConfigStrategy(Multimap providedServices) { + this.providedServices = providedServices; + } @Override void handleMissingInstance(Map configuration, ConfigTransactionClient ta, - String module, String instance) { - ObjectName on; + String module, String instance, Services services) { + ObjectName on = null; try { on = ta.createModule(module, instance); logger.info("New instance for {} {} created under name {}", module, instance, on); - executeStrategy(configuration, ta, on); + addRefNames(services, providedServices, module, instance, ta, on); + executeStrategy(configuration, ta, on, services); } catch (InstanceAlreadyExistsException e1) { throw new IllegalStateException("Unable to create instance for " + module + " : " + instance); + } catch (InstanceNotFoundException e) { + throw new IllegalStateException("Unable to save default ref name for instance " + on, e); + } + } + + private void addRefNames(Services services, Multimap providedServices, String module, + String instance, ConfigTransactionClient ta, ObjectName on) throws InstanceNotFoundException { + for (Entry namespaceToService : providedServices.entries()) { + + if(services.hasRefName(namespaceToService.getKey(), + namespaceToService.getValue(), on)) + continue; + + String refName = services.getNewDefaultRefName(namespaceToService.getKey(), namespaceToService.getValue(), + module, instance); + ta.saveServiceReference( + ta.getServiceInterfaceName(namespaceToService.getKey(), namespaceToService.getValue()), refName, on); } } @Override - void executeStrategy(Map configuration, ConfigTransactionClient ta, ObjectName on) { + void executeStrategy(Map configuration, ConfigTransactionClient ta, ObjectName on, Services services) { for (Entry configAttributeEntry : configuration.entrySet()) { try { AttributeConfigElement ace = configAttributeEntry.getValue(); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/NoneEditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/NoneEditConfigStrategy.java index db11ce381e..8347c6b88e 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/NoneEditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/NoneEditConfigStrategy.java @@ -12,6 +12,7 @@ import java.util.Map; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,7 +22,7 @@ public class NoneEditConfigStrategy implements EditConfigStrategy { @Override public void executeConfiguration(String module, String instance, Map configuration, - ConfigTransactionClient ta) { + ConfigTransactionClient ta, Services services) { logger.debug("Skipping configuration element for {}:{}", module, instance); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/RemoveEditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/RemoveEditConfigStrategy.java index 76ca09433a..64f082da40 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/RemoveEditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/RemoveEditConfigStrategy.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ed import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,7 +22,7 @@ public class RemoveEditConfigStrategy extends DeleteEditConfigStrategy { @Override void handleMissingInstance(Map configuration, ConfigTransactionClient ta, - String module, String instance) { + String module, String instance, Services services) { logger.warn("Unable to delete {}:{}, ServiceInstance not found", module, instance); } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategy.java index 0091d6cc84..43d852e76a 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategy.java @@ -8,37 +8,68 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig; -import java.util.Map; -import java.util.Map.Entry; - -import javax.management.Attribute; -import javax.management.InstanceAlreadyExistsException; -import javax.management.ObjectName; - +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.management.Attribute; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import java.util.Map; +import java.util.Map.Entry; + public class ReplaceEditConfigStrategy extends AbstractEditConfigStrategy { private static final Logger logger = LoggerFactory.getLogger(ReplaceEditConfigStrategy.class); + private final Multimap providedServices; + + public ReplaceEditConfigStrategy() { + this.providedServices = HashMultimap.create(); + } + + public ReplaceEditConfigStrategy(Multimap providedServices) { + this.providedServices = providedServices; + } + @Override void handleMissingInstance(Map configuration, ConfigTransactionClient ta, - String module, String instance) { + String module, String instance, Services services) { + ObjectName on = null; try { - ObjectName on = ta.createModule(module, instance); + on = ta.createModule(module, instance); logger.debug("New instance for {} {} created under name {}", module, instance, on); - executeStrategy(configuration, ta, on); + addRefNames(services, providedServices, module, instance, ta, on); + executeStrategy(configuration, ta, on, services); } catch (InstanceAlreadyExistsException e) { logger.warn("Error creating instance {}:{}, replace failed", module, instance, e); throw new IllegalStateException("Unable to create new instance for " + module + " : " + instance, e); + } catch (InstanceNotFoundException e) { + throw new IllegalStateException("Unable to save default ref name for instance " + on, e); } } + private void addRefNames(Services services, Multimap providedServices, String module, + String instance, ConfigTransactionClient ta, ObjectName on) throws InstanceNotFoundException { + for (Entry namespaceToService : providedServices.entries()) { + + if(services.hasRefName(namespaceToService.getKey(), + namespaceToService.getValue(), on)) + continue; + + String refName = services.getNewDefaultRefName(namespaceToService.getKey(), namespaceToService.getValue(), + module, instance); + ta.saveServiceReference( + ta.getServiceInterfaceName(namespaceToService.getKey(), namespaceToService.getValue()), refName, on); + } + } @Override - void executeStrategy(Map configuration, ConfigTransactionClient ta, ObjectName on) { + void executeStrategy(Map configuration, ConfigTransactionClient ta, ObjectName on, Services services) { for (Entry configAttributeEntry : configuration.entrySet()) { try { AttributeConfigElement ace = configAttributeEntry.getValue(); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java index 7ee13aeb58..efe4f7dde9 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ge import com.google.common.collect.Maps; import org.opendaylight.controller.config.util.ConfigRegistryClient; +import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot; import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry; import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry; @@ -25,6 +26,7 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtim import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation; import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore; import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.GetConfig; +import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.slf4j.Logger; @@ -42,11 +44,13 @@ public class Get extends AbstractConfigNetconfOperation { private final YangStoreSnapshot yangStoreSnapshot; private static final Logger logger = LoggerFactory.getLogger(Get.class); + private final TransactionProvider transactionProvider; public Get(YangStoreSnapshot yangStoreSnapshot, ConfigRegistryClient configRegistryClient, - String netconfSessionIdForReporting) { + String netconfSessionIdForReporting, TransactionProvider transactionProvider) { super(configRegistryClient, netconfSessionIdForReporting); this.yangStoreSnapshot = yangStoreSnapshot; + this.transactionProvider = transactionProvider; } private Map> createModuleRuntimes(ConfigRegistryClient configRegistryClient, @@ -144,7 +148,9 @@ public class Get extends AbstractConfigNetconfOperation { final Runtime runtime = new Runtime(moduleRuntimes, moduleConfigs); - final Element element = runtime.toXml(runtimeBeans, configBeans, document); + ObjectName txOn = transactionProvider.getOrCreateTransaction(); + ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(txOn); + final Element element = runtime.toXml(runtimeBeans, configBeans, document, ta); logger.info("{} operation successful", XmlNetconfConstants.GET); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java index f2dfc7079c..d75cfd5d6f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java @@ -11,6 +11,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ge import com.google.common.base.Optional; import com.google.common.collect.Maps; import org.opendaylight.controller.config.util.ConfigRegistryClient; +import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot; import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; @@ -20,6 +21,7 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorT import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation; import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore; import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider; @@ -83,7 +85,13 @@ public class GetConfig extends AbstractConfigNetconfOperation { final Config configMapping = new Config(transform(configRegistryClient, yangStoreSnapshot.getModuleMXBeanEntryMap())); - dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement); + + + ObjectName on = transactionProvider.getOrCreateTransaction(); + ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(on); + + Services serviceTracker = new Services(ta); + dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement, serviceTracker); logger.info("{} operation successful", GET_CONFIG); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationProvider.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationProvider.java index ec1915d6fc..77c58501cd 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationProvider.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationProvider.java @@ -56,7 +56,7 @@ final class NetconfOperationProvider { ops.add(new EditConfig(yangStoreSnapshot, transactionProvider, configRegistryClient, netconfSessionIdForReporting)); ops.add(new Commit(transactionProvider, configRegistryClient, netconfSessionIdForReporting)); - ops.add(new Get(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting)); + ops.add(new Get(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting, transactionProvider)); ops.add(new DiscardChanges(transactionProvider, configRegistryClient, netconfSessionIdForReporting)); ops.add(new Validate(transactionProvider, configRegistryClient, netconfSessionIdForReporting)); ops.add(new RuntimeRpc(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting)); 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/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java index b8113a0903..0fa005e04a 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java @@ -137,13 +137,14 @@ public class TransactionProvider implements AutoCloseable { } /** - * Wiping means removing all module instances keeping the transaction open. + * Wiping means removing all module instances keeping the transaction open + service references. */ synchronized void wipeInternal(ObjectName taON, boolean isTest, String moduleName) { ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON); Set lookupConfigBeans = moduleName == null ? transactionClient.lookupConfigBeans() : transactionClient.lookupConfigBeans(moduleName); + int i = lookupConfigBeans.size(); for (ObjectName instance : lookupConfigBeans) { try { transactionClient.destroyModule(instance); @@ -156,7 +157,10 @@ public class TransactionProvider implements AutoCloseable { throw new IllegalStateException("Unable to clean configuration in transactiom " + taON, e); } } - logger.debug("Transaction {} wiped clean", taON); + logger.debug("Transaction {} wiped clean of {} config beans", taON, i); + + transactionClient.removeAllServiceReferences(); + logger.debug("Transaction {} wiped clean of all service references", taON); } public void wipeTransaction() { diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/util/Util.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/util/Util.java index 26719592bb..1c806742e9 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/util/Util.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/util/Util.java @@ -38,7 +38,7 @@ public final class Util { public static void checkType(final Object value, final Class clazz) { Preconditions.checkArgument(clazz.isAssignableFrom(value.getClass()), "Unexpected type " + value.getClass() - + " should be " + clazz); + + " should be " + clazz + " of " + value); } // TODO: add message and proper error types diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java index f8916ecac2..11cf1aae6a 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java @@ -12,12 +12,16 @@ import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.apache.commons.lang3.StringUtils; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.matchers.JUnitMatchers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; +import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; @@ -55,23 +59,28 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; import javax.management.ObjectName; import javax.xml.parsers.ParserConfigurationException; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -82,7 +91,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; public class NetconfMappingTest extends AbstractConfigTest { private static final Logger logger = LoggerFactory.getLogger(NetconfMappingTest.class); - private static final String INSTANCE_NAME = "test1"; + private static final String INSTANCE_NAME = "instance-from-code"; private static final String NETCONF_SESSION_ID = "foo"; private NetconfTestImplModuleFactory factory; private DepTestImplModuleFactory factory2; @@ -105,24 +114,122 @@ public class NetconfMappingTest extends AbstractConfigTest { transactionProvider = new TransactionProvider(this.configRegistryClient, NETCONF_SESSION_ID); } - private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException { + private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException { final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction(); final ObjectName on = transaction.createModule(this.factory.getImplementationName(), instanceName); final NetconfTestImplModuleMXBean mxBean = transaction.newMXBeanProxy(on, NetconfTestImplModuleMXBean.class); - setModule(mxBean, transaction); + setModule(mxBean, transaction, instanceName + "_dep"); + int i = 1; + for (Class sInterface : factory.getImplementedServiceIntefaces()) { + ServiceInterfaceAnnotation annotation = sInterface.getAnnotation(ServiceInterfaceAnnotation.class); + transaction.saveServiceReference( + transaction.getServiceInterfaceName(annotation.namespace(), annotation.localName()), "ref_from_code_to_" + instanceName + "_" + i++, + on); + + } transaction.commit(); return on; } + @Test + public void testServicePersistance() throws Exception { + createModule(INSTANCE_NAME); + + edit("netconfMessages/editConfig.xml"); + Element config = getConfigCandidate(); + assertCorrectServiceNames(config, 6, "ref_test2", "user_to_instance_from_code", "ref_dep_user", + "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1", + "ref_from_code_to_instance-from-code_1"); + + edit("netconfMessages/editConfig_addServiceName.xml"); + config = getConfigCandidate(); + assertCorrectServiceNames(config, 7, "ref_test2", "user_to_instance_from_code", "ref_dep_user", + "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1", + "ref_from_code_to_instance-from-code_1", "ref_dep_user_another"); + + commit(); + config = getConfigRunning(); + assertCorrectRefNamesForDependencies(config); + assertCorrectServiceNames(config, 7, "ref_test2", "user_to_instance_from_code", "ref_dep_user", + "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1", + "ref_from_code_to_instance-from-code_1", "ref_dep_user_another"); + + edit("netconfMessages/editConfig_replace_default.xml"); + config = getConfigCandidate(); + assertCorrectServiceNames(config, 2, "ref_dep", "ref_dep2"); + + edit("netconfMessages/editConfig_remove.xml"); + config = getConfigCandidate(); + assertCorrectServiceNames(config, 0); + + commit(); + config = getConfigCandidate(); + assertCorrectServiceNames(config, 0); + + } + + private void assertCorrectRefNamesForDependencies(Element config) { + NodeList modulesList = config.getElementsByTagName("modules"); + assertEquals(1, modulesList.getLength()); + + Element modules = (Element) modulesList.item(0); + + String trimmedModules = XmlUtil.toString(modules).replaceAll("\\s", ""); + int defaultRefNameCount = StringUtils.countMatches(trimmedModules, "ref_dep2"); + int userRefNameCount = StringUtils.countMatches(trimmedModules, "ref_dep_user_two"); + + assertEquals(0, defaultRefNameCount); + assertEquals(2, userRefNameCount); + } + + private void assertCorrectServiceNames(Element configCandidate, int servicesSize, String... refNames) { + NodeList elements = configCandidate.getElementsByTagName("provider"); + assertEquals(servicesSize, elements.getLength()); + + NodeList servicesList = configCandidate.getElementsByTagName("services"); + assertEquals(1, servicesList.getLength()); + + Element services = (Element) servicesList.item(0); + String trimmedServices = XmlUtil.toString(services).replaceAll("\\s", ""); + + for (String s : refNames) { + assertThat(trimmedServices, JUnitMatchers.containsString(s)); + } + } + + @Test + public void testConfigNetconfUnionTypes() throws Exception { + + createModule(INSTANCE_NAME); + + edit("netconfMessages/editConfig.xml"); + commit(); + Element response = getConfigRunning(); + String trimmedResponse = XmlUtil.toString(response).replaceAll("\\s", ""); + assertContainsString(trimmedResponse, "0:0:0:0:0:0:0:1"); + assertContainsString(trimmedResponse, "456"); + + + edit("netconfMessages/editConfig_setUnions.xml"); + commit(); + response = getConfigRunning(); + + trimmedResponse = XmlUtil.toString(response).replaceAll("\\s", ""); + assertContainsString(trimmedResponse, "127.1.2.3"); + assertContainsString(trimmedResponse, "randomStringForUnion"); + + } + @Test public void testConfigNetconf() throws Exception { createModule(INSTANCE_NAME); edit("netconfMessages/editConfig.xml"); - checkBinaryLeafEdited(getConfigCandidate()); + Element configCandidate = getConfigCandidate(); + checkBinaryLeafEdited(configCandidate); // default-operation:none, should not affect binary leaf @@ -205,6 +312,7 @@ public class NetconfMappingTest extends AbstractConfigTest { return executeOp(getConfigOp, "netconfMessages/getConfig.xml"); } + @Ignore("second edit message corrupted") @Test(expected = NetconfDocumentedException.class) public void testConfigNetconfReplaceDefaultEx() throws Exception { @@ -394,7 +502,7 @@ public class NetconfMappingTest extends AbstractConfigTest { for (XmlElement moduleElement : modulesElement.getChildElements("module")) { String name = moduleElement.getOnlyChildElement("name").getTextContent(); - if(name.equals("test1")) { + if(name.equals(INSTANCE_NAME)) { XmlElement enumAttr = moduleElement.getOnlyChildElement(enumName); assertEquals(enumContent, enumAttr.getTextContent()); @@ -415,16 +523,20 @@ public class NetconfMappingTest extends AbstractConfigTest { XmlElement modulesElement = XmlElement.fromDomElement(response).getOnlyChildElement("data") .getOnlyChildElement("modules"); - XmlElement configAttributeType = null; + List expectedValues = Lists.newArrayList("default-string", "configAttributeType"); + Set configAttributeType = Sets.newHashSet(); + for (XmlElement moduleElement : modulesElement.getChildElements("module")) { for (XmlElement type : moduleElement.getChildElements("type")) { if (type.getAttribute(XmlUtil.XMLNS_ATTRIBUTE_KEY).equals("") == false) { - configAttributeType = type; + configAttributeType.add(type.getTextContent()); } } } - assertEquals("configAttributeType", configAttributeType.getTextContent()); + for (String expectedValue : expectedValues) { + assertTrue(configAttributeType.contains(expectedValue)); + } } private Map> getMbes() throws Exception { @@ -480,7 +592,7 @@ public class NetconfMappingTest extends AbstractConfigTest { } private Element get() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException { - Get getOp = new Get(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID); + Get getOp = new Get(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID, transactionProvider); return executeOp(getOp, "netconfMessages/get.xml"); } @@ -516,8 +628,8 @@ public class NetconfMappingTest extends AbstractConfigTest { return Lists.newArrayList(yangDependencies); } - private void setModule(final NetconfTestImplModuleMXBean mxBean, final ConfigTransactionJMXClient transaction) - throws InstanceAlreadyExistsException { + private void setModule(final NetconfTestImplModuleMXBean mxBean, final ConfigTransactionJMXClient transaction, String depName) + throws InstanceAlreadyExistsException, InstanceNotFoundException { mxBean.setSimpleInt((long) 44); mxBean.setBinaryLeaf(new byte[] { 8, 7, 9 }); final DtoD dtob = getDtoD(); @@ -547,7 +659,15 @@ public class NetconfMappingTest extends AbstractConfigTest { mxBean.setComplexList(Lists. newArrayList()); mxBean.setSimpleList(Lists. newArrayList()); - final ObjectName testingDepOn = transaction.createModule(this.factory2.getImplementationName(), "dep"); + final ObjectName testingDepOn = transaction.createModule(this.factory2.getImplementationName(), depName); + int i = 1; + for (Class sInterface : factory2.getImplementedServiceIntefaces()) { + ServiceInterfaceAnnotation annotation = sInterface.getAnnotation(ServiceInterfaceAnnotation.class); + transaction.saveServiceReference( + transaction.getServiceInterfaceName(annotation.namespace(), annotation.localName()), "ref_from_code_to_" + depName + "_" + i++, + testingDepOn); + + } mxBean.setTestingDep(testingDepOn); } diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java index 425ecf6d02..d5ba976ccf 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java @@ -13,7 +13,6 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services.ServiceInstance; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; public class ServiceTrackerTest { @@ -28,44 +27,4 @@ public class ServiceTrackerTest { assertEquals(serviceInstance, serviceInstance2); } - @Test - public void testOneInstanceMultipleServices() { - Services services = new Services(); - services.addServiceEntry("nm", "s1", "module", "instance"); - assertEquals(1, services.getMappedServices().size()); - - services.addServiceEntry("nm2", "s2", "module", "instance"); - assertEquals(2, services.getMappedServices().size()); - } - - @Test - public void testMultipleInstancesOneName() throws Exception { - Services services = new Services(); - services.addServiceEntry("nm", "s1", "module", "instance"); - assertEquals(1, services.getMappedServices().size()); - - services.addServiceEntry("nm", "s1", "module2", "instance"); - assertEquals(1, services.getMappedServices().size()); - assertEquals(2, services.getMappedServices().get("nm").get("s1").size()); - assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance")); - assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_1")); - } - - @Test - public void testMultipleInstancesOneName2() throws Exception { - Services services = new Services(); - services.addServiceEntry("nm", "s1", "module", "instance_1"); - - services.addServiceEntry("nm2", "s2", "module2", "instance"); - services.addServiceEntry("nm2", "s2", "module3", "instance"); - services.addServiceEntry("nm", "s1", "module3", "instance"); - - assertEquals(2, services.getMappedServices().get("nm").get("s1").size()); - assertEquals(2, services.getMappedServices().get("nm2").get("s2").size()); - assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_2")); - assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_1")); - assertTrue(services.getMappedServices().get("nm2").get("s2").containsKey("ref_instance")); - assertTrue(services.getMappedServices().get("nm2").get("s2").containsKey("ref_instance_2")); - } - } diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java index 1b8e24702a..6e7a225f38 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java @@ -16,24 +16,23 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.util.ConfigRegistryClient; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; -import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.opendaylight.controller.netconf.confignetconfconnector.operations.ValidateTest; import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution; import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider; -import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import javax.management.ObjectName; import java.util.Collections; import java.util.Map; -import java.util.Set; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyMap; @@ -82,18 +81,11 @@ public class EditConfigTest { EditConfig edit = new EditConfig(yangStoreSnapshot, provider, configRegistry, ValidateTest.NETCONF_SESSION_ID_FOR_REPORTING); EditConfigStrategy editStrat = mock(EditConfigStrategy.class); - doNothing().when(editStrat).executeConfiguration(anyString(), anyString(), anyMap(), - any(ConfigTransactionClient.class)); - Map> resolvedXmlElements = getMapping(editStrat); - Config cfg = mock(Config.class); - XmlElement xmlElement = mock(XmlElement.class); - Set instancesForFillingServiceRefMapping = Collections.emptySet(); - EditStrategyType defaultStrategy = EditStrategyType.getDefaultStrategy(); - doReturn(resolvedXmlElements).when(cfg).fromXml(xmlElement, instancesForFillingServiceRefMapping, defaultStrategy); + doNothing().when(editStrat).executeConfiguration(anyString(), anyString(), anyMap(), + any(ConfigTransactionClient.class), any(Services.class)); - EditConfigExecution editConfigExecution = new EditConfigExecution(null, cfg, xmlElement, - EditConfigXmlParser.TestOption.testThenSet, instancesForFillingServiceRefMapping, defaultStrategy); + EditConfigExecution editConfigExecution = mockExecution(editStrat); edit.getResponseInternal(XmlUtil.newDocument(), editConfigExecution); @@ -105,7 +97,31 @@ public class EditConfigTest { // For every instance execute strat verify(editStrat, times(2/* Test */+ 2/* Set */)).executeConfiguration(anyString(), anyString(), anyMap(), - any(ConfigTransactionClient.class)); + any(ConfigTransactionClient.class), any(Services.class)); + } + + private EditConfigExecution mockExecution(EditConfigStrategy editStrat) { + EditConfigExecution mock = mock(EditConfigExecution.class); + doReturn(getMapping(editStrat)).when(mock).getResolvedXmlElements(); + doReturn(EditStrategyType.merge).when(mock).getDefaultStrategy(); + doReturn(true).when(mock).shouldSet(); + doReturn(true).when(mock).shouldTest(); + doReturn(mockServices()).when(mock).getServices(); + return mock; + } + + private static ServiceReferenceReadableRegistry mockServiceRegistry() { + ServiceReferenceReadableRegistry mock = mock(ServiceReferenceReadableRegistry.class); + doReturn( + Collections.emptyMap()) + .when(mock).getServiceMapping(); + doReturn("mockedServiceReg").when(mock).toString(); + + return mock; + } + + static Services mockServices() { + return new Services(mockServiceRegistry()); } private Map> getMapping(EditConfigStrategy editStrat) { diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java index 704da6dc0d..78a2043e20 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java @@ -48,7 +48,7 @@ public class ReplaceEditConfigStrategyTest { doReturn(Sets.newHashSet(mockON(), mockON())).when(ta).lookupConfigBeans(); - strat.executeConfiguration("m1", "i1", map, ta); + strat.executeConfiguration("m1", "i1", map, ta, EditConfigTest.mockServices()); verify(ta).lookupConfigBean(anyString(), anyString()); verify(ta).setAttribute(any(ObjectName.class), anyString(), any(Attribute.class)); 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 c6caf417a1..20bd386063 100644 --- a/opendaylight/netconf/config-persister-impl/pom.xml +++ b/opendaylight/netconf/config-persister-impl/pom.xml @@ -43,7 +43,9 @@ org.opendaylight.controller - config-persister-file-adapter + config-persister-file-xml-adapter + test + ${config.version} @@ -60,8 +62,8 @@ org.opendaylight.controller - config-persister-directory-adapter - ${parent.version} + config-persister-directory-xml-adapter + ${config.version} test @@ -88,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 044346e2c5..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); @@ -169,7 +177,7 @@ public class ConfigPusher { NetconfMessage message = createEditConfigMessage(xmlToBePersisted, "/netconfOp/editConfig.xml"); // sending message to netconf - NetconfMessage responseMessage = netconfClient.sendMessage(message, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY); + NetconfMessage responseMessage = getResponse(message, netconfClient); XmlElement element = XmlElement.fromDomDocument(responseMessage.getDocument()); Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY)); @@ -178,7 +186,7 @@ public class ConfigPusher { Util.checkIsOk(element, responseMessage); response.append(XmlUtil.toString(responseMessage.getDocument())); response.append("}"); - responseMessage = netconfClient.sendMessage(getNetconfMessageFromResource("/netconfOp/commit.xml"), NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY); + responseMessage = getResponse(getNetconfMessageFromResource("/netconfOp/commit.xml"), netconfClient); element = XmlElement.fromDomDocument(responseMessage.getDocument()); Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY)); @@ -192,6 +200,15 @@ public class ConfigPusher { logger.trace("Detailed message {}", response); } + private static NetconfMessage getResponse(NetconfMessage request, NetconfClient netconfClient) { + try { + return netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY); + } catch(RuntimeException e) { + logger.error("Error while sending message {} to {}", request, netconfClient); + throw e; + } + } + private static NetconfMessage createEditConfigMessage(Element dataElement, String editConfigResourcename) { try (InputStream stream = ConfigPersisterNotificationHandler.class.getResourceAsStream(editConfigResourcename)) { Preconditions.checkNotNull(stream, "Unable to load resource " + editConfigResourcename); diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java index 7e9dce67bd..f168bb3634 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java @@ -34,7 +34,7 @@ import java.util.ListIterator; * Example configuration:
  netconf.config.persister.active=2,3
  # read startup configuration
- netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.DirectoryStorageAdapter
+ netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
  netconf.config.persister.1.properties.fileStorage=configuration/initial/
 
  netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PropertiesProviderAdapterImpl.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PropertiesProviderAdapterImpl.java
index 981be827b7..d9466ff00b 100644
--- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PropertiesProviderAdapterImpl.java
+++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PropertiesProviderAdapterImpl.java
@@ -1,10 +1,9 @@
-/**
- * @author Tomas Olvecky
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
- * 11 2013
- *
- * Copyright (c) 2013 by Cisco Systems, Inc.
- * 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.persist.impl;
 
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java
index 227018bf5b..acea75a743 100644
--- a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java
+++ b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java
@@ -11,7 +11,7 @@ package org.opendaylight.controller.netconf.persist.impl;
 import org.junit.Test;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter;
+import org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter;
 import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
 import org.opendaylight.controller.netconf.persist.impl.osgi.PropertiesProviderBaseImpl;
 
@@ -93,7 +93,7 @@ public class PersisterAggregatorTest {
         List persisters = persisterAggregator.getPersisterWithConfigurations();
         assertEquals(1, persisters.size());
         PersisterWithConfiguration persister = persisters.get(0);
-        assertEquals(FileStorageAdapter.class.getName() ,persister.getStorage().getClass().getName());
+        assertEquals(XmlFileStorageAdapter.class.getName() ,persister.getStorage().getClass().getName());
         assertFalse(persister.isReadOnly());
     }
 
diff --git a/opendaylight/netconf/config-persister-impl/src/test/resources/test2.properties b/opendaylight/netconf/config-persister-impl/src/test/resources/test2.properties
index 222e7cef47..729c67d6c5 100644
--- a/opendaylight/netconf/config-persister-impl/src/test/resources/test2.properties
+++ b/opendaylight/netconf/config-persister-impl/src/test/resources/test2.properties
@@ -1,9 +1,9 @@
 netconf.config.persister.active=2
 # read startup configuration
-netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.DirectoryStorageAdapter
+netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
 netconf.config.persister.1.properties.directoryStorage=target/configuration/initial/
 netconf.config.persister.1.readonly=true
 
-netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
 netconf.config.persister.2.properties.fileStorage=target/configuration/current/controller.config.2.txt
 netconf.config.persister.2.properties.numberOfBackups=3
diff --git a/opendaylight/netconf/config-persister-impl/src/test/resources/test3.properties b/opendaylight/netconf/config-persister-impl/src/test/resources/test3.properties
index a1645ad8c4..90ba77273b 100644
--- a/opendaylight/netconf/config-persister-impl/src/test/resources/test3.properties
+++ b/opendaylight/netconf/config-persister-impl/src/test/resources/test3.properties
@@ -1,4 +1,4 @@
 netconf.config.persister.active=3
-netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
 netconf.config.persister.3.properties.fileStorage=target/configuration/current/controller.config.2.txt
 netconf.config.persister.3.properties.numberOfBackups=0
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/ietf-netconf-monitoring/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/netconf/monitoring/rev101004/netconf/state/schemas/LocationBuilder.java b/opendaylight/netconf/ietf-netconf-monitoring/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/netconf/monitoring/rev101004/netconf/state/schemas/LocationBuilder.java
new file mode 100644
index 0000000000..0a084b0ff6
--- /dev/null
+++ b/opendaylight/netconf/ietf-netconf-monitoring/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/netconf/monitoring/rev101004/netconf/state/schemas/LocationBuilder.java
@@ -0,0 +1,23 @@
+/*
+ * 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.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.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema.Location;
+
+
+/**
+**/
+public class LocationBuilder {
+
+    public static Location getDefaultInstance(String defaultValue) {
+        return defaultValue.equals("NETCONF") ? new Location(Location.Enumeration.NETCONF) : new Location(new Uri(
+                defaultValue));
+    }
+
+}
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/NetconfClient.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java
index 95f526b2ec..2ce779a1f5 100644
--- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java
+++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java
@@ -88,6 +88,7 @@ public class NetconfClient implements Closeable {
     }
 
     public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) {
+        long startTime = System.currentTimeMillis();
         Preconditions.checkState(clientSession.isUp(), "Session was not up yet");
         clientSession.sendMessage(message);
         try {
@@ -96,6 +97,9 @@ public class NetconfClient implements Closeable {
             throw new RuntimeException(this + " Cannot read message from " + address, e);
         } catch (IllegalStateException e) {
             throw new IllegalStateException(this + " Cannot read message from " + address, e);
+        } finally {
+            long diffMillis = System.currentTimeMillis() - startTime;
+            logger.debug("Total time spent waiting for response {}", diffMillis);
         }
     }
 
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 - dep + instance-from-code_dep test-impl:impl-dep @@ -29,7 +29,7 @@ test-impl:impl-netconf - test1 + instance-from-code 2.58 @@ -91,16 +91,16 @@ prefix:testing - ref_dep + ref_dep_user prefix:testing - ref_dep + ref_dep_user prefix:testing - ref_dep_2 + ref_dep_user_two @@ -113,7 +113,7 @@ prefix:testing - ref_dep_2 + ref_dep_user_two @@ -122,19 +122,19 @@ prefix:testing - ref_dep - /modules/module[type='impl-dep'][name='dep'] + ref_dep_user + /modules/module[type='impl-dep'][name='instance-from-code_dep'] - ref_dep_2 + ref_dep_user_two /config/modules/module[name='impl-dep']/instance[name='dep2'] - ref_test1 + user_to_instance_from_code - /modules/module[type='impl-netconf'][name='test1'] + /modules/module[type='impl-netconf'][name='instance-from-code'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_addServiceName.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_addServiceName.xml new file mode 100644 index 0000000000..30be98e6b5 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_addServiceName.xml @@ -0,0 +1,34 @@ + + + + + + + set + + merge + + + + + instance-from-code_dep + + test-impl:impl-dep + + + + + + + + prefix:testing + + ref_dep_user_another + /modules/module[type='impl-dep'][name='instance-from-code_dep'] + + + + + + + diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_threadfactory.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_threadfactory.xml index ad7c84f3c9..25976707d4 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_threadfactory.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_threadfactory.xml @@ -1,4 +1,4 @@ - + @@ -22,6 +22,16 @@ + + + prefix:threadfactory + + user_to_instance_from_code + + /modules/module[type='threadfactory-naming'][name='threadfactory-naming-instance'] + + + diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml index b48730d3f7..a7f1c86391 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml @@ -8,7 +8,7 @@ - dep + instance-from-code_dep test-impl:impl-dep @@ -21,6 +21,7 @@ + test-impl:impl-netconf @@ -66,42 +67,16 @@ 456 44 - - prefix:testing - ref_dep - test-impl:impl-netconf test2 - - prefix:testing - ref_dep - + - - prefix:testing - - ref_dep - /modules/module[type='impl-dep'][name='dep'] - - - - ref_dep_2 - /modules/module[type='impl-dep'][name='dep2'] - - - - ref_test1 - - /modules/module[type='impl-netconf'][name='test1'] - - - diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_remove.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_remove.xml index 9d06d98f1c..e07f18cb51 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_remove.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_remove.xml @@ -6,6 +6,15 @@ none + + instance-from-code_dep + + test-impl:impl-dep + + + + dep @@ -27,7 +36,7 @@ test-impl:impl-netconf - test1 + instance-from-code + + + + + + set + + merge + + + + + test-impl:impl-netconf + + + instance-from-code + + 127.1.2.3 + randomStringForUnion + + + + + + + + + + diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml index 46b833cf68..5de3de1de2 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml @@ -1,6 +1,6 @@ - /modules/module[type='impl-netconf' and name='test1'] + /modules/module[type='impl-netconf' and name='instance-from-code'] testarg1 diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml index 3d5117e3bd..da9afd7bf1 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml @@ -1,7 +1,7 @@ - /modules/module[name='test1'][type='impl-netconf']/inner-running-data-additional[key='1'] + /modules/module[name='instance-from-code'][type='impl-netconf']/inner-running-data-additional[key='1'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml index 4ba0349f9b..a5b83e6db6 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml @@ -2,7 +2,7 @@ - /modules/module[type='impl-netconf'][name='test1']/inner-running-data[key='0']/inner-inner-running-data[key='1'] + /modules/module[type='impl-netconf'][name='instance-from-code']/inner-running-data[key='0']/inner-inner-running-data[key='1'] diff --git a/opendaylight/netconf/pom.xml b/opendaylight/netconf/pom.xml index 52b7370e35..c4b1467220 100644 --- a/opendaylight/netconf/pom.xml +++ b/opendaylight/netconf/pom.xml @@ -31,6 +31,7 @@ ../../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/DiscoveryService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java index 012807eee9..811135252d 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java @@ -125,7 +125,7 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa private Boolean throttling = false; // if true, no more batching. private volatile Boolean shuttingDown = false; - private LLDPTLV chassisIdTlv, portIdTlv, ttlTlv, customTlv; + private LLDPTLV chassisIdTlv, systemNameTlv, portIdTlv, ttlTlv, customTlv; private IPluginOutConnectionService connectionOutService; class DiscoveryTransmit implements Runnable { @@ -217,6 +217,11 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()).setLength((short) cidValue.length) .setValue(cidValue); + // Create LLDP SystemName TLV + byte[] snValue = LLDPTLV.createSystemNameTLVValue(nodeConnector.getNode().toString()); + systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()).setLength((short) snValue.length) + .setValue(snValue); + // Create LLDP PortID TLV String portId = nodeConnector.getNodeConnectorIDString(); byte[] pidValue = LLDPTLV.createPortIDTLVValue(portId); @@ -233,7 +238,8 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa // Create discovery pkt LLDP discoveryPkt = new LLDP(); - discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setOptionalTLVList(customList); + discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setSystemNameId(systemNameTlv) + .setOptionalTLVList(customList); RawPacket rawPkt = null; try { @@ -1462,6 +1468,10 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa chassisIdTlv = new LLDPTLV(); chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()); + // Create LLDP SystemName TLV + systemNameTlv = new LLDPTLV(); + systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()); + // Create LLDP PortID TLV portIdTlv = new LLDPTLV(); portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue()); diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDP.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDP.java index 6a896c6c71..95edca943b 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDP.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDP.java @@ -21,9 +21,10 @@ import org.opendaylight.controller.sal.utils.NetUtils; public class LLDP extends Packet { private static final String CHASSISID = "ChassisId"; + private static final String SYSTEMNAMEID = "SystemNameID"; private static final String PORTID = "PortId"; private static final String TTL = "TTL"; - private static final int LLDPDefaultTlvs = 3; + private static final int LLDPDefaultTlvs = 4; private static LLDPTLV emptyTLV = new LLDPTLV().setLength((short) 0) .setType((byte) 0); public static final byte[] LLDPMulticastMac = { 1, (byte) 0x80, @@ -101,6 +102,22 @@ public class LLDP extends Packet { return this; } + /** + * @return the SystemName TLV + */ + public LLDPTLV getSystemNameId() { + return getTLV(SYSTEMNAMEID); + } + + /** + * @param LLDPTLV + * - the chassisId to set + */ + public LLDP setSystemNameId(LLDPTLV systemNameId) { + tlvList.put(getType(SYSTEMNAMEID), systemNameId); + return this; + } + /** * @return LLDPTLV - the portId TLV */ diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDPTLV.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDPTLV.java index bf67402259..27660221ce 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDPTLV.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDPTLV.java @@ -187,6 +187,18 @@ public class LLDPTLV extends Packet { getfieldnumBits(VALUE)); // variable } + /** + * Creates the SystemName TLV value + * + * @param nodeId + * node identifier string + * @return the SystemName TLV value in byte array + */ + static public byte[] createSystemNameTLVValue(String nodeId) { + byte[] nid = nodeId.getBytes(); + return nid; + } + /** * Creates the ChassisID TLV value including the subtype and ChassisID * string diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeConnectorCreator.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeConnectorCreator.java index da4cd53883..9cd551664c 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeConnectorCreator.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeConnectorCreator.java @@ -73,7 +73,11 @@ public abstract class NodeConnectorCreator { public static NodeConnector createNodeConnector( String nodeConnectorType, Object portId, Node node) { try { - return new NodeConnector(nodeConnectorType, portId, node); + if (nodeConnectorType.equals(Node.NodeIDType.OPENFLOW) && (portId.getClass() == String.class)) { + return new NodeConnector(nodeConnectorType, Short.parseShort((String) portId), node); + } else { + return new NodeConnector(nodeConnectorType, portId, node); + } } catch (ConstructionException e1) { logger.error("",e1); return null; 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 f33fa18e29..16c09fe3f6 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 @@ -244,10 +244,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/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 217b8d4690..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"); } } @@ -475,6 +475,16 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa status = updateConfig(conf, isAdding); if(!status.isSuccess()) { updateDatabase(conf, (!isAdding)); + } else { + // update the listeners + Subnet subnetCurr = subnets.get(conf.getIPAddress()); + Subnet subnet; + if (subnetCurr == null) { + subnet = new Subnet(conf); + } else { + subnet = subnetCurr.clone(); + } + notifySubnetChange(subnet, isAdding); } } @@ -496,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); @@ -681,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/topologymanager/integrationtest/pom.xml b/opendaylight/topologymanager/integrationtest/pom.xml index d4d3d1c857..5dfa1632f7 100644 --- a/opendaylight/topologymanager/integrationtest/pom.xml +++ b/opendaylight/topologymanager/integrationtest/pom.xml @@ -18,6 +18,12 @@ topologymanager.integrationtest 0.4.0-SNAPSHOT + + org.ops4j.pax.exam + pax-exam-container-native + ${exam.version} + test + org.opendaylight.controller protocol_plugins.stub 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