dot1q.setVid(vlan);
dot1q.setEtherType(EtherTypes.ARP.shortValue());
dot1q.setPayload(arp);
+ dot1q.setCfi((byte)0);
+ dot1q.setPcp((byte)0);
ethernet.setEtherType(EtherTypes.VLANTAGGED.shortValue());
ethernet.setPayload(dot1q);
}
<artifactId>sal-restconf-broker</artifactId>
<version>${mdsal.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-test-model</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
<!-- SAL Extension bundles -->
<dependency>
private final ReadOnlyAtomicBoolean configBeanModificationDisabled;
public DynamicWritableWrapper(Module module,
- ModuleIdentifier moduleIdentifier,
- TransactionIdentifier transactionIdentifier,
- ReadOnlyAtomicBoolean configBeanModificationDisabled,
- MBeanServer internalServer, MBeanServer configMBeanServer) {
+ ModuleIdentifier moduleIdentifier,
+ TransactionIdentifier transactionIdentifier,
+ ReadOnlyAtomicBoolean configBeanModificationDisabled,
+ MBeanServer internalServer, MBeanServer configMBeanServer) {
super(module, true, moduleIdentifier, ObjectNameUtil
- .createTransactionModuleON(transactionIdentifier.getName(), moduleIdentifier), getOperations(moduleIdentifier),
+ .createTransactionModuleON(transactionIdentifier.getName(), moduleIdentifier), getOperations(moduleIdentifier),
internalServer, configMBeanServer);
this.configBeanModificationDisabled = configBeanModificationDisabled;
}
ModuleIdentifier moduleIdentifier) {
Method validationMethod;
try {
- validationMethod = DynamicWritableWrapper.class.getMethod(
- "validate", new Class<?>[0]);
+ validationMethod = DynamicWritableWrapper.class.getMethod("validate");
} catch (NoSuchMethodException e) {
- throw new IllegalStateException("No such method exception on "
- + moduleIdentifier, e);
+ throw new IllegalStateException("No such method exception on " + moduleIdentifier, e);
}
- return new MBeanOperationInfo[] { new MBeanOperationInfo("Validation",
- validationMethod) };
+ return new MBeanOperationInfo[]{new MBeanOperationInfo("Validation", validationMethod)};
}
@Override
public synchronized void setAttribute(Attribute attribute)
- throws AttributeNotFoundException, InvalidAttributeValueException,
- MBeanException, ReflectionException {
- if (configBeanModificationDisabled.get() == true)
+ throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
+ if (configBeanModificationDisabled.get() == true) {
throw new IllegalStateException("Operation is not allowed now");
+ }
if (attribute.getName().equals("Attribute")) {
setAttribute((Attribute) attribute.getValue());
try {
if (attribute.getValue() instanceof ObjectName) {
attribute = fixDependencyAttribute(attribute);
- } else if(attribute.getValue() instanceof ObjectName[]) {
+ } else if (attribute.getValue() instanceof ObjectName[]) {
attribute = fixDependencyListAttribute(attribute);
}
}
private Attribute fixDependencyListAttribute(Attribute attribute) {
- AttributeHolder attributeHolder = attributeHolderMap
- .get(attribute.getName());
+ AttributeHolder attributeHolder = attributeHolderMap.get(attribute.getName());
if (attributeHolder.getRequireInterfaceOrNull() != null) {
- attribute = new Attribute(attribute.getName(),
- fixObjectNames((ObjectName[]) attribute.getValue()));
+ attribute = new Attribute(attribute.getName(), fixObjectNames((ObjectName[]) attribute.getValue()));
}
return attribute;
}
private Attribute fixDependencyAttribute(Attribute attribute) {
- AttributeHolder attributeHolder = attributeHolderMap
- .get(attribute.getName());
+ AttributeHolder attributeHolder = attributeHolderMap.get(attribute.getName());
if (attributeHolder.getRequireInterfaceOrNull() != null) {
- attribute = new Attribute(attribute.getName(),
- fixObjectName((ObjectName) attribute.getValue()));
+ attribute = new Attribute(attribute.getName(), fixObjectName((ObjectName) attribute.getValue()));
} else {
- attribute = new Attribute(attribute.getName(),
- attribute.getValue());
+ attribute = new Attribute(attribute.getName(), attribute.getValue());
}
return attribute;
}
setAttribute(attribute);
result.add(attribute);
} catch (Exception e) {
- logger.warn("Setting attribute {} failed on {}",
- attribute.getName(), moduleIdentifier, e);
+ logger.warn("Setting attribute {} failed on {}", attribute.getName(), moduleIdentifier, e);
throw new IllegalArgumentException(
"Setting attribute failed - " + attribute.getName()
+ " on " + moduleIdentifier, e);
void destroyModule(String moduleName, String instanceName) throws InstanceNotFoundException;
void setAttribute(ObjectName on, String jmxName, Attribute attribute);
+
+ /*
+ * Get the attribute named jmxName from the Object with ObjectName on
+ *
+ * @param on - ObjectName of the Object from which the attribute should be read
+ * @param jmxName - name of the attribute to be read
+ *
+ * @return Attribute of Object on with attribute name jmxName
+ */
+ Attribute getAttribute(ObjectName on, String jmxName);
}
import java.util.Map;
import java.util.Set;
+
import javax.management.Attribute;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
+
import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
}
}
+ @Override
+ public Attribute getAttribute(ObjectName on, String attrName) {
+ if (ObjectNameUtil.getTransactionName(on) == null)
+ throw new IllegalArgumentException("Not in transaction instance "
+ + on + ", no transaction name present");
+
+ try {
+ return new Attribute(attrName, configMBeanServer.getAttribute(on,attrName));
+ } catch (JMException e) {
+ throw new IllegalStateException("Unable to get attribute "
+ + attrName + " for " + on, e);
+ }
+ }
+
@Override
public Set<String> getAvailableModuleFactoryQNames() {
return configTransactionControllerMXBeanProxy.getAvailableModuleFactoryQNames();
+++ /dev/null
-src/main/java/org/opendaylight/controller/config/yang/test/impl/*
+++ /dev/null
-package org.opendaylight.controller.config.yang.test.impl;
-public class DepTestImplModule extends org.opendaylight.controller.config.yang.test.impl.AbstractDepTestImplModule {
- public DepTestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
- super(identifier, dependencyResolver);
- }
-
- public DepTestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.test.impl.DepTestImplModule oldModule, java.lang.AutoCloseable oldInstance) {
- super(identifier, dependencyResolver, oldModule, oldInstance);
- }
-
- @Override
- public void customValidation() {
- // add custom validation form module attributes here.
- }
-
- @Override
- public java.lang.AutoCloseable createInstance() {
- return new AutoCloseable() {
- @Override
- public void close() throws Exception {
- }
- };
-
- }
-
-}
+++ /dev/null
-
-
-package org.opendaylight.controller.config.yang.test.impl;
-public class DepTestImplModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractDepTestImplModuleFactory {
-
-}
+++ /dev/null
-package org.opendaylight.controller.config.yang.test.impl;
-public class IdentityTestModule extends org.opendaylight.controller.config.yang.test.impl.AbstractIdentityTestModule {
- public IdentityTestModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
- super(identifier, dependencyResolver);
- }
-
- public IdentityTestModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.test.impl.IdentityTestModule oldModule, java.lang.AutoCloseable oldInstance) {
- super(identifier, dependencyResolver, oldModule, oldInstance);
- }
-
- @Override
- public void customValidation() {
- // add custom validation form module attributes here.
- }
-
- @Override
- public java.lang.AutoCloseable createInstance() {
- org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
- logger.info("Afi: {}", getAfi());
- logger.info("Afi class: {}", getAfiIdentity());
-
- for (Identities identities : getIdentities()) {
- logger.info("Identities Afi class: {}", identities.resolveAfi());
- logger.info("Identities Safi class: {}", identities.resolveSafi());
-
- }
- logger.info("IdentityContainer Afi class: {}", getIdentitiesContainer().resolveAfi());
-
- return new AutoCloseable() {
- @Override
- public void close() throws Exception {
- }
- };
-
- }
-
-}
+++ /dev/null
-
-
-package org.opendaylight.controller.config.yang.test.impl;
-public class IdentityTestModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractIdentityTestModuleFactory {
-
-}
--- /dev/null
+ return new AutoCloseable() {
+ @Override
+ public void close() throws Exception {
+ }
+ };
+++ /dev/null
-package org.opendaylight.controller.config.yang.test.impl;
-public class NetconfTestImplModule extends org.opendaylight.controller.config.yang.test.impl.AbstractNetconfTestImplModule {
- public NetconfTestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
- super(identifier, dependencyResolver);
- }
-
- public NetconfTestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModule oldModule, java.lang.AutoCloseable oldInstance) {
- super(identifier, dependencyResolver, oldModule, oldInstance);
- }
-
- @Override
- public void customValidation() {
- // add custom validation form module attributes here.
- }
-
- @Override
- public java.lang.AutoCloseable createInstance() {
-return NetconfTestImplModuleUtil.registerRuntimeBeans(this);
-
- }
-
-}
+++ /dev/null
-
-
-package org.opendaylight.controller.config.yang.test.impl;
-public class NetconfTestImplModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractNetconfTestImplModuleFactory {
-
-}
-return NetconfTestImplModuleUtil.registerRuntimeBeans(this);
+return org.opendaylight.controller.config.yang.test.util.NetconfTestImplModuleUtil.registerRuntimeBeans(this);
+++ /dev/null
-package org.opendaylight.controller.config.yang.test.impl;
-public class TestImplModule extends org.opendaylight.controller.config.yang.test.impl.AbstractTestImplModule {
- public TestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
- super(identifier, dependencyResolver);
- }
-
- public TestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.test.impl.TestImplModule oldModule, java.lang.AutoCloseable oldInstance) {
- super(identifier, dependencyResolver, oldModule, oldInstance);
- }
-
- @Override
- public void customValidation() {
- // add custom validation form module attributes here.
- }
-
- @Override
- public java.lang.AutoCloseable createInstance() {
- return new AutoCloseable() {
- @Override
- public void close() throws Exception {
- }
- };
-
- }
-
-}
+++ /dev/null
-
-
-package org.opendaylight.controller.config.yang.test.impl;
-public class TestImplModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractTestImplModuleFactory {
-
-}
-package org.opendaylight.controller.config.yang.test.impl;
+/*
+ * Copyright (c) 2014 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
+ */
-import com.google.common.collect.Lists;
+package org.opendaylight.controller.config.yang.test.util;
+import com.google.common.collect.Lists;
import java.util.List;
+import org.opendaylight.controller.config.yang.test.impl.Asdf;
+import org.opendaylight.controller.config.yang.test.impl.Deep2;
+import org.opendaylight.controller.config.yang.test.impl.Deep3;
+import org.opendaylight.controller.config.yang.test.impl.Deep4;
+import org.opendaylight.controller.config.yang.test.impl.InnerInnerRunningDataRuntimeMXBean;
+import org.opendaylight.controller.config.yang.test.impl.InnerRunningDataAdditionalRuntimeMXBean;
+import org.opendaylight.controller.config.yang.test.impl.InnerRunningDataRuntimeMXBean;
+import org.opendaylight.controller.config.yang.test.impl.InnerRunningDataRuntimeRegistration;
+import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModule;
+import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplRuntimeMXBean;
+import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplRuntimeRegistration;
+import org.opendaylight.controller.config.yang.test.impl.NotStateBean;
+import org.opendaylight.controller.config.yang.test.impl.RetValContainer;
+import org.opendaylight.controller.config.yang.test.impl.RetValList;
public class NetconfTestImplModuleUtil {
- static NetconfTestImplRuntimeRegistration registerRuntimeBeans(final NetconfTestImplModule module) {
+ public static NetconfTestImplRuntimeRegistration registerRuntimeBeans(final NetconfTestImplModule module) {
NetconfTestImplRuntimeRegistration reg = module.getRootRuntimeBeanRegistratorWrapper().register(new NetconfTestImplRuntimeMXBean() {
@Override
config:java-name-prefix IdentityTest;
}
+ identity multiple-dependencies {
+ base config:module-type;
+ config:provided-service test:testing;
+ config:java-name-prefix MultipleDependencies;
+ }
+
augment "/config:modules/config:module/config:configuration" {
case impl-identity-test {
when "/config:modules/config:module/config:type = 'impl-identity-test'";
}
}
+
+ augment "/config:modules/config:module/config:configuration" {
+ case multiple-dependencies {
+ when "/config:modules/config:module/config:type = 'multiple-dependencies'";
+ container multiple-dependencies {
+ list testing-deps {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity test:testing;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
identity test-rpc;
identity inner-test-rpc;
identity inner-inner-test-rpc;
--- /dev/null
+/*
+ * Copyright (c) 2014 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.test.impl;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.opendaylight.controller.config.api.jmx.ObjectNameUtil.getInstanceName;
+import static org.opendaylight.controller.config.api.jmx.ObjectNameUtil.getTransactionName;
+
+import java.util.List;
+import javax.management.ObjectName;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+
+public class MultipleDependenciesModuleTest extends AbstractConfigTest {
+ private static final MultipleDependenciesModuleFactory factory = new MultipleDependenciesModuleFactory();
+
+ @Before
+ public void setUp() throws Exception {
+ super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, factory));
+ }
+
+ @Test
+ public void testMultipleDependencies() throws Exception {
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+ ObjectName d1 = transaction.createModule(factory.getImplementationName(), "d1");
+ ObjectName d2 = transaction.createModule(factory.getImplementationName(), "d2");
+
+ assertEquals(transaction.getTransactionName(), getTransactionName(d1));
+
+ ObjectName parent = transaction.createModule(factory.getImplementationName(), "parent");
+ MultipleDependenciesModuleMXBean multipleDependenciesModuleMXBean = transaction.newMXBeanProxy(parent, MultipleDependenciesModuleMXBean.class);
+ multipleDependenciesModuleMXBean.setTestingDeps(asList(d1, d2));
+ List<ObjectName> found = multipleDependenciesModuleMXBean.getTestingDeps();
+ ObjectName d1WithoutTxName = found.get(0);
+ assertEquals(getInstanceName(d1), getInstanceName(d1WithoutTxName));
+ // check that transaction name gets stripped automatically from attribute.
+ // d1,2 contained tx name, found doesn't
+ assertNull(getTransactionName(d1WithoutTxName));
+ transaction.commit();
+ }
+}
-->
<Host>
- <!-- Filters are allowed here, only serving as a template -->
- <filter-template>
- <filter-name>CorsFilter</filter-name>
- <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
- <init-param>
- <param-name>cors.allowed.origins</param-name>
- <param-value>*</param-value>
- </init-param>
- <init-param>
- <param-name>cors.allowed.methods</param-name>
- <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
- </init-param>
- <init-param>
- <param-name>cors.allowed.headers</param-name>
- <param-value>Content-Type,X-Requested-With,accept,authorization,
- origin,Origin,Access-Control-Request-Method,Access-Control-Request-Headers
- </param-value>
- </init-param>
- <init-param>
- <param-name>cors.exposed.headers</param-name>
- <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
- </init-param>
- <init-param>
- <param-name>cors.support.credentials</param-name>
- <param-value>true</param-value>
- </init-param>
- <init-param>
- <param-name>cors.preflight.maxage</param-name>
- <param-value>10</param-value>
- </init-param>
- </filter-template>
+ <!-- Filters are allowed here, only serving as a template -->
+ <filter-template>
+ <filter-name>CorsFilter</filter-name>
+ <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
+ <init-param>
+ <param-name>cors.allowed.origins</param-name>
+ <param-value>*</param-value>
+ </init-param>
+ <init-param>
+ <param-name>cors.allowed.methods</param-name>
+ <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
+ </init-param>
+ <init-param>
+ <param-name>cors.allowed.headers</param-name>
+ <param-value>Content-Type,X-Requested-With,accept,authorization,
+ origin,Origin,Access-Control-Request-Method,Access-Control-Request-Headers
+ </param-value>
+ </init-param>
+ <init-param>
+ <param-name>cors.exposed.headers</param-name>
+ <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
+ </init-param>
+ <init-param>
+ <param-name>cors.support.credentials</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <init-param>
+ <param-name>cors.preflight.maxage</param-name>
+ <param-value>10</param-value>
+ </init-param>
+ </filter-template>
+
+ <Context path="/restconf">
+ <filter>
+ <filter-name>CorsFilter</filter-name>
+ <!-- init params can be added/overriden if template is used -->
+ </filter>
+ <!-- references to templates without <filter> declaration are not allowed -->
+ <filter-mapping>
+ <filter-name>CorsFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+ </Context>
+
+ <Context path="/apidoc">
+ <filter>
+ <filter-name>CorsFilter</filter-name>
+ <!-- init params can be added/overriden if template is used -->
+ </filter>
+ <!-- references to templates without <filter> declaration are not allowed -->
+ <filter-mapping>
+ <filter-name>CorsFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+ </Context>
- <Context path="/restconf">
- <filter>
- <filter-name>CorsFilter</filter-name>
- <!-- init params can be added/overriden if template is used -->
- </filter>
- <!-- references to templates without <filter> declaration are not allowed -->
- <filter-mapping>
- <filter-name>CorsFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- </Context>
</Host>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>ietf-inet-types</artifactId>
</dependency>
- <dependency>
- <groupId>org.reflections</groupId>
- <artifactId>reflections</artifactId>
- <scope>compile</scope>
- </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<artifactId>ietf-topology-l3-unicast-igp</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-test-model</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
package org.opendaylight.controller.md.sal.binding.impl;
import java.lang.reflect.Method;
-import java.lang.reflect.Type;
import java.util.AbstractMap.SimpleEntry;
+import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Map.Entry;
+import java.util.Set;
import javax.annotation.Nullable;
import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation;
import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
-import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
import org.slf4j.Logger;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.base.Supplier;
+import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
if (child instanceof AugmentationNode) {
ImmutableList<PathArgument> childArgs = ImmutableList.<PathArgument> builder()
.addAll(normalizedEntry.getKey().getPathArguments()).add(child.getIdentifier()).build();
- org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.create(
- childArgs);
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+ .create(childArgs);
return toDOMEntry(childPath, child);
}
}
*/
public Optional<InstanceIdentifier<? extends DataObject>> toBinding(
final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
- throws DeserializationException {
+ throws DeserializationException {
PathArgument lastArgument = Iterables.getLast(normalized.getPathArguments());
// Used instance-identifier codec do not support serialization of last
private Optional<InstanceIdentifier<? extends DataObject>> toBindingAugmented(
final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
- throws DeserializationException {
+ throws DeserializationException {
Optional<InstanceIdentifier<? extends DataObject>> potential = toBindingImpl(normalized);
// Shorthand check, if codec already supports deserialization
// of AugmentationIdentifier we will return
private Optional<InstanceIdentifier<? extends DataObject>> toBindingImpl(
final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
- throws DeserializationException {
+ throws DeserializationException {
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier legacyPath;
try {
private boolean isNotRepresentable(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
throws DataNormalizationException {
DataNormalizationOperation<?> op = findNormalizationOperation(normalized);
- if( op.isMixin() && op.getIdentifier() instanceof NodeIdentifier) {
+ if (op.isMixin() && op.getIdentifier() instanceof NodeIdentifier) {
return true;
}
- if(op.isLeaf()) {
+ if (op.isLeaf()) {
return true;
}
return false;
private DataNormalizationOperation<?> findNormalizationOperation(
final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
- throws DataNormalizationException {
+ throws DataNormalizationException {
DataNormalizationOperation<?> current = legacyToNormalized.getRootOperation();
for (PathArgument arg : normalized.getPathArguments()) {
current = current.getChild(arg);
}
private static final Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> toDOMEntry(
- final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier key,
- final NormalizedNode<?, ?> value) {
- return new SimpleEntry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>>(
- key, value);
+ final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier key, final NormalizedNode<?, ?> value) {
+ return new SimpleEntry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>>(key,
+ value);
}
public DataObject toBinding(final InstanceIdentifier<?> path, final NormalizedNode<?, ?> normalizedNode)
public Optional<Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject>> toBinding(
final Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, ? extends NormalizedNode<?, ?>> normalized)
- throws DeserializationException {
+ throws DeserializationException {
Optional<InstanceIdentifier<? extends DataObject>> potentialPath = toBinding(normalized.getKey());
if (potentialPath.isPresent()) {
InstanceIdentifier<? extends DataObject> bindingPath = potentialPath.get();
if (isAugmentationIdentifier(processed)) {
return processed;
}
- // Here we employ small trick - DataNormalizer injects augmentation
- // identifier if child is
- // also part of the path (since using a child we can safely identify
- // augmentation)
- // so, we scan augmentation for children add it to path
- // and use original algorithm, then shorten it to last augmentation
- for (@SuppressWarnings("rawtypes")
- Class augChild : getAugmentationChildren(augPath.getTargetType())) {
+ Optional<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> additionalSerialized;
+ additionalSerialized = toNormalizedAugmentedUsingChildContainers(augPath, processed);
+
+ if (additionalSerialized.isPresent()) {
+ return additionalSerialized.get();
+ }
+ additionalSerialized = toNormalizedAugmentedUsingChildLeafs(augPath, processed);
+ if (additionalSerialized.isPresent()) {
+ return additionalSerialized.get();
+ }
+ throw new IllegalStateException("Unabled to construct augmentation identfier for " + augPath);
+ }
+
+ /**
+ * Tries to find correct augmentation identifier using children leafs
+ *
+ * This method uses normalized Instance Identifier of parent node to fetch
+ * schema and {@link BindingReflections#getModuleInfo(Class)} to learn about
+ * augmentation namespace, specificly, in which module it was defined.
+ *
+ * Then it uses it to filter all available augmentations for parent by
+ * module. After that it walks augmentations in particular module and
+ * pick-up first which at least one leaf name matches supplied augmentation.
+ * We could do this safely since YANG explicitly states that no any existing
+ * augmentations must differ in leaf fully qualified names.
+ *
+ *
+ * @param augPath
+ * Binding Aware Path which ends with augment
+ * @param parentPath
+ * Processed path
+ * @return
+ */
+ private Optional<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toNormalizedAugmentedUsingChildLeafs(
+ final InstanceIdentifier<?> augPath,
+ final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier parentPath) {
+ try {
+ DataNormalizationOperation<?> parentOp = legacyToNormalized.getOperation(parentPath);
+ if(!parentOp.getDataSchemaNode().isPresent()) {
+ return Optional.absent();
+ }
+ DataSchemaNode parentSchema = parentOp.getDataSchemaNode().get();
+ if (parentSchema instanceof AugmentationTarget) {
+ Set<AugmentationSchema> augmentations = ((AugmentationTarget) parentSchema).getAvailableAugmentations();
+ LOG.info("Augmentations for {}, {}", augPath, augmentations);
+ Optional<AugmentationSchema> schema = findAugmentation(augPath.getTargetType(), augmentations);
+ if (schema.isPresent()) {
+ AugmentationIdentifier augmentationIdentifier = DataNormalizationOperation
+ .augmentationIdentifierFrom(schema.get());
+ return Optional.of(parentPath.node(augmentationIdentifier));
+ }
+ }
+ } catch (DataNormalizationException e) {
+ throw new IllegalArgumentException(e);
+ }
+ return Optional.absent();
+ }
+
+ /**
+ * Creates instance identifier for augmentation child, tries to serialize it
+ * Instance Identifier is then shortened to last augmentation.
+ *
+ * This is for situations, where underlying codec is implementing hydrogen
+ * style DOM APIs (which did not supported {@link AugmentationIdentifier}.)
+ *
+ * @param augPath
+ * @param parentPath
+ * Path to parent node
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ private Optional<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toNormalizedAugmentedUsingChildContainers(
+ final InstanceIdentifier<?> augPath,
+ final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier parentPath) {
+ for (Class augChild : BindingReflections.getChildrenClasses(augPath.getTargetType())) {
@SuppressWarnings("unchecked")
InstanceIdentifier<?> childPath = augPath.child(augChild);
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized = toNormalizedImpl(childPath);
- org.opendaylight.yangtools.yang.data.api.InstanceIdentifier potentialDiscovered = shortenToLastAugmentation(normalized);
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier potentialDiscovered = shortenToLastAugmentation(
+ normalized, parentPath);
if (potentialDiscovered != null) {
- return potentialDiscovered;
+ return Optional.of(potentialDiscovered);
+ }
+ }
+ return Optional.absent();
+ }
+
+ private Optional<AugmentationSchema> findAugmentation(final Class targetType,
+ final Set<AugmentationSchema> augmentations) {
+ YangModuleInfo moduleInfo;
+ try {
+ moduleInfo = BindingReflections.getModuleInfo(targetType);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ Iterable<AugmentationSchema> filtered = filteredByModuleInfo(augmentations,
+ BindingReflections.getModuleQName(moduleInfo).getModule());
+ filtered.toString();
+ Set<String> targetTypeGetters = getYangModeledGetters(targetType);
+ for (AugmentationSchema schema : filtered) {
+ for (DataSchemaNode child : schema.getChildNodes()) {
+ String getterName = "get" + BindingMapping.getClassName(child.getQName());
+ if (targetTypeGetters.contains(getterName)) {
+ return Optional.of(schema);
+ }
}
}
- return processed;
+ return Optional.absent();
+ }
+
+ private static Iterable<AugmentationSchema> filteredByModuleInfo(final Iterable<AugmentationSchema> augmentations,
+ final QNameModule module) {
+ return Iterables.filter(augmentations, new Predicate<AugmentationSchema>() {
+ @Override
+ public boolean apply(final AugmentationSchema schema) {
+ final Set<DataSchemaNode> childNodes = schema.getChildNodes();
+ return !schema.getChildNodes().isEmpty()
+ && module.equals(Iterables.get(childNodes, 0).getQName().getModule());
+ }
+ });
+ }
+
+ public static final Set<String> getYangModeledGetters(final Class<?> targetType) {
+ HashSet<String> ret = new HashSet<String>();
+ for (Method method : targetType.getMethods()) {
+ if (isYangModeledGetter(method)) {
+ ret.add(method.getName());
+ }
+ }
+ return ret;
+ }
+
+ /**
+ *
+ * Returns true if supplied method represent getter for YANG modeled value
+ *
+ * @param method
+ * Method to be tested
+ * @return true if method represent getter for YANG Modeled value.
+ */
+ private static final boolean isYangModeledGetter(final Method method) {
+ return !method.getName().equals("getClass") && !method.getName().equals("getImplementedInterface")
+ && method.getName().startsWith("get") && method.getParameterTypes().length == 0;
}
private org.opendaylight.yangtools.yang.data.api.InstanceIdentifier shortenToLastAugmentation(
- final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) {
+ final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized,
+ final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier parentPath) {
+ int parentSize = Iterables.size(parentPath.getPathArguments());
int position = 0;
int foundPosition = -1;
for (PathArgument arg : normalized.getPathArguments()) {
foundPosition = position;
}
}
- if (foundPosition > 0) {
+ if (foundPosition > 0 && foundPosition > parentSize) {
Iterable<PathArgument> shortened = Iterables.limit(normalized.getPathArguments(), foundPosition);
return org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.create(shortened);
}
return normalized;
}
- @SuppressWarnings("unchecked")
- private Iterable<Class<? extends DataObject>> getAugmentationChildren(final Class<?> targetType) {
- List<Class<? extends DataObject>> ret = new LinkedList<>();
- for (Method method : targetType.getMethods()) {
- Class<?> entity = getYangModeledType(method);
- if (entity != null) {
- ret.add((Class<? extends DataObject>) entity);
- }
- }
- return ret;
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private Class<? extends DataObject> getYangModeledType(final Method method) {
- if (method.getName().equals("getClass") || !method.getName().startsWith("get")
- || method.getParameterTypes().length > 0) {
- return null;
- }
-
- Class<?> returnType = method.getReturnType();
- if (DataContainer.class.isAssignableFrom(returnType)) {
- return (Class) returnType;
- } else if (List.class.isAssignableFrom(returnType)) {
- try {
- return ClassLoaderUtils.withClassLoader(method.getDeclaringClass().getClassLoader(),
- new Supplier<Class>() {
- @Override
- public Class get() {
- Type listResult = ClassLoaderUtils.getFirstGenericParameter(method
- .getGenericReturnType());
- if (listResult instanceof Class
- && DataObject.class.isAssignableFrom((Class) listResult)) {
- return (Class<?>) listResult;
- }
- return null;
- }
-
- });
- } catch (Exception e) {
- LOG.debug("Could not get YANG modeled entity for {}", method, e);
- return null;
- }
-
- }
- return null;
- }
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- private static InstanceIdentifier<?> toWildcarded(final InstanceIdentifier<?> orig) {
- List<org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument> wildArgs = new LinkedList<>();
- for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : orig.getPathArguments()) {
- wildArgs.add(new Item(arg.getType()));
- }
- return InstanceIdentifier.create(wildArgs);
- }
-
private static boolean isAugmentation(final Class<? extends DataObject> type) {
return Augmentation.class.isAssignableFrom(type);
}
private static int getAugmentationCount(final InstanceIdentifier<?> potential) {
int count = 0;
- for(org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : potential.getPathArguments()) {
- if(isAugmentation(arg.getType())) {
+ for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : potential.getPathArguments()) {
+ if (isAugmentation(arg.getType())) {
count++;
}
-
}
return count;
}
private static int getAugmentationCount(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier potential) {
int count = 0;
- for(PathArgument arg : potential.getPathArguments()) {
- if(arg instanceof AugmentationIdentifier) {
+ for (PathArgument arg : potential.getPathArguments()) {
+ if (arg instanceof AugmentationIdentifier) {
count++;
}
}
return count;
}
- public Function<Optional<NormalizedNode<?, ?>>, Optional<DataObject>> deserializeFunction(final InstanceIdentifier<?> path) {
+ public Function<Optional<NormalizedNode<?, ?>>, Optional<DataObject>> deserializeFunction(
+ final InstanceIdentifier<?> path) {
return new DeserializeFunction(this, path);
}
/**
* Returns an default object according to YANG schema for supplied path.
*
- * @param path DOM Path
+ * @param path
+ * DOM Path
* @return Node with defaults set on.
*/
public NormalizedNode<?, ?> getDefaultNodeFor(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path) {
--- /dev/null
+package org.opendaylight.controller.md.sal.binding.impl.test;
+
+import static org.junit.Assert.assertTrue;
+import javassist.ClassPool;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.controller.md.sal.binding.test.AbstractSchemaAwareTest;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeLeafOnlyAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class BindingNormalizedCodecTest extends AbstractSchemaAwareTest {
+
+ private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo");
+ private static final InstanceIdentifier<TopLevelList> BA_TOP_LEVEL_LIST = InstanceIdentifier
+ .builder(Top.class).child(TopLevelList.class, TOP_FOO_KEY).toInstance();
+ private static final InstanceIdentifier<TreeLeafOnlyAugment> BA_TREE_LEAF_ONLY = BA_TOP_LEVEL_LIST.augmentation(TreeLeafOnlyAugment.class);
+ private static final InstanceIdentifier<TreeComplexUsesAugment> BA_TREE_COMPLEX_USES = BA_TOP_LEVEL_LIST.augmentation(TreeComplexUsesAugment.class);
+ private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value");
+
+
+ private RuntimeGeneratedMappingServiceImpl mappingService;
+ private BindingToNormalizedNodeCodec codec;
+
+ @Override
+ protected void setupWithSchema(final SchemaContext context) {
+ mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault());
+ codec = new BindingToNormalizedNodeCodec(mappingService);
+ mappingService.onGlobalContextUpdated(context);
+ codec.onGlobalContextUpdated(context);
+ };
+
+ @Test
+ public void testComplexAugmentationSerialization() {
+
+ PathArgument lastArg = codec.toNormalized(BA_TREE_COMPLEX_USES).getLastPathArgument();
+ assertTrue(lastArg instanceof AugmentationIdentifier);
+ }
+
+
+ @Test
+ public void testLeafOnlyAugmentationSerialization() {
+
+ PathArgument leafOnlyLastArg = codec.toNormalized(BA_TREE_LEAF_ONLY).getLastPathArgument();
+ assertTrue(leafOnlyLastArg instanceof AugmentationIdentifier);
+ assertTrue(((AugmentationIdentifier) leafOnlyLastArg).getPossibleChildNames().contains(SIMPLE_VALUE_QNAME));
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.md.sal.binding.impl.test;
+import static org.junit.Assert.assertFalse;
+import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertContains;
+import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertEmpty;
+import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertNotContains;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.TOP_BAR_KEY;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.TOP_FOO_KEY;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.top;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.topLevelList;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataChangeListenerTest;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ *
+ * This testsuite tests explanation for data change scope and data modifications
+ * which were described in
+ * https://lists.opendaylight.org/pipermail/controller-dev/2014-July/005541.html
+ *
+ *
+ */
+public class ListInsertionDataChangeListenerTest extends AbstractDataChangeListenerTest{
+
+ private static final InstanceIdentifier<Top> TOP = InstanceIdentifier.create(Top.class);
+ private static final InstanceIdentifier<TopLevelList> WILDCARDED = TOP.child(TopLevelList.class);
+ private static final InstanceIdentifier<TopLevelList> TOP_FOO = TOP.child(TopLevelList.class, TOP_FOO_KEY);
+ private static final InstanceIdentifier<TopLevelList> TOP_BAR = TOP.child(TopLevelList.class, TOP_BAR_KEY);
+
+
+ @Override
+ protected void setupWithDataBroker(final DataBroker dataBroker) {
+ WriteTransaction initialTx = dataBroker.newWriteOnlyTransaction();
+ initialTx.put(CONFIGURATION, TOP, top(topLevelList(TOP_FOO_KEY)));
+ assertCommit(initialTx.commit());
+ }
+
+ @Test
+ public void replaceTopNodeSubtreeListeners() {
+ TestListener topListener = createListener(CONFIGURATION, TOP, DataChangeScope.SUBTREE);
+ TestListener allListener = createListener(CONFIGURATION, WILDCARDED, DataChangeScope.SUBTREE);
+ TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, DataChangeScope.SUBTREE);
+ TestListener barListener = createListener(CONFIGURATION, TOP_BAR, DataChangeScope.SUBTREE);
+
+ ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
+ writeTx.put(CONFIGURATION, TOP, top(topLevelList(TOP_BAR_KEY)));
+ assertCommit(writeTx.commit());
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> top = topListener.event();
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> all = allListener.event();
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> foo = fooListener.event();
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> bar = barListener.event();
+
+ // Listener for TOP element
+ assertContains(top.getOriginalData(), TOP,TOP_FOO);
+ assertContains(top.getCreatedData(), TOP_BAR);
+ assertContains(top.getUpdatedData(), TOP);
+ assertContains(top.getRemovedPaths(), TOP_FOO);
+
+ /*
+ * Listener for all list items
+ *
+ * Updated should be empty, since no list item was
+ * updated, items were only removed and added
+ */
+ assertContains(all.getOriginalData(), TOP_FOO);
+ assertContains(all.getCreatedData(), TOP_BAR);
+ assertEmpty(all.getUpdatedData());
+ assertContains(all.getRemovedPaths(), TOP_FOO);
+
+
+ /*
+ * Listener for all Foo item
+ *
+ * This one should see only Foo item removed
+ */
+ assertContains(foo.getOriginalData(), TOP_FOO);
+ assertEmpty(foo.getCreatedData());
+ assertEmpty(foo.getUpdatedData());
+ assertContains(foo.getRemovedPaths(), TOP_FOO);
+
+ /*
+ * Listener for bar list items
+ *
+ * Updated should be empty, since no list item was
+ * updated, items were only removed and added
+ */
+ assertEmpty(bar.getOriginalData());
+ assertContains(bar.getCreatedData(), TOP_BAR);
+ assertEmpty(bar.getUpdatedData());
+ assertEmpty(bar.getRemovedPaths());
+ }
+
+ @Test
+ public void mergeTopNodeSubtreeListeners() {
+ TestListener topListener = createListener(CONFIGURATION, TOP, DataChangeScope.SUBTREE);
+ TestListener allListener = createListener(CONFIGURATION, WILDCARDED, DataChangeScope.SUBTREE);
+ TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, DataChangeScope.SUBTREE);
+ TestListener barListener = createListener(CONFIGURATION, TOP_BAR, DataChangeScope.SUBTREE);
+
+ ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
+ writeTx.merge(CONFIGURATION, TOP, top(topLevelList(TOP_BAR_KEY)));
+ assertCommit(writeTx.commit());
+
+ verifyBarOnlyAdded(topListener,allListener,fooListener,barListener);
+ }
+
+ @Test
+ public void putTopBarNodeSubtreeListeners() {
+ TestListener topListener = createListener(CONFIGURATION, TOP, DataChangeScope.SUBTREE);
+ TestListener allListener = createListener(CONFIGURATION, WILDCARDED, DataChangeScope.SUBTREE);
+ TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, DataChangeScope.SUBTREE);
+ TestListener barListener = createListener(CONFIGURATION, TOP_BAR, DataChangeScope.SUBTREE);
+
+ ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
+ writeTx.put(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY));
+ assertCommit(writeTx.commit());
+
+ verifyBarOnlyAdded(topListener,allListener,fooListener,barListener);
+ }
+
+ @Test
+ public void mergeTopBarNodeSubtreeListeners() {
+ TestListener topListener = createListener(CONFIGURATION, TOP, DataChangeScope.SUBTREE);
+ TestListener allListener = createListener(CONFIGURATION, WILDCARDED, DataChangeScope.SUBTREE);
+ TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, DataChangeScope.SUBTREE);
+ TestListener barListener = createListener(CONFIGURATION, TOP_BAR, DataChangeScope.SUBTREE);
+
+ ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
+ writeTx.merge(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY));
+ assertCommit(writeTx.commit());
+
+ verifyBarOnlyAdded(topListener,allListener,fooListener,barListener);
+ }
+
+ private void verifyBarOnlyAdded(final TestListener top, final TestListener all, final TestListener foo,
+ final TestListener bar) {
+
+ assertFalse(foo.hasEvent());
+
+ // Listener for TOP element
+ assertContains(top.event().getOriginalData(), TOP);
+ assertNotContains(top.event().getOriginalData(),TOP_FOO);
+ assertContains(top.event().getCreatedData(), TOP_BAR);
+ assertContains(top.event().getUpdatedData(), TOP);
+ assertEmpty(top.event().getRemovedPaths());
+
+ /*
+ * Listener for all list items
+ *
+ * Updated should be empty, since no list item was
+ * updated, items were only removed and added
+ */
+ assertEmpty(all.event().getOriginalData());
+ assertContains(all.event().getCreatedData(), TOP_BAR);
+ assertEmpty(all.event().getUpdatedData());
+ assertEmpty(all.event().getRemovedPaths());
+
+ /*
+ * Listener for all Foo item
+ *
+ * Foo Listener should not have foo event
+ */
+ assertFalse(foo.hasEvent());
+
+ /*
+ * Listener for bar list items
+ *
+ * Updated should be empty, since no list item was
+ * updated, items were only removed and added
+ */
+ assertEmpty(bar.event().getOriginalData());
+ assertContains(bar.event().getCreatedData(), TOP_BAR);
+ assertEmpty(bar.event().getUpdatedData());
+ assertEmpty(bar.event().getRemovedPaths());
+ }
+
+}
import java.util.concurrent.ExecutionException;
import org.junit.Test;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
-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.NodesBuilder;
-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.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.TopBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-public class WriteTransactionTest extends AbstractDataServiceTest {
+public class WriteTransactionTest extends AbstractDataBrokerTest {
- private DataBroker dataBroker;
-
- private static final InstanceIdentifier<Nodes> NODES_PATH = InstanceIdentifier.create(Nodes.class);
-
- private static final NodeKey NODE_KEY = new NodeKey(new NodeId("foo"));
-
- private static final InstanceIdentifier<Node> NODE_PATH = NODES_PATH.child(Node.class, NODE_KEY);
-
- @Override
- public void setUp() {
- super.setUp();
-
- dataBroker = testContext.getDataBroker();
- }
+ private static final InstanceIdentifier<Top> TOP_PATH = InstanceIdentifier.create(Top.class);
+ private static final TopLevelListKey TOP_LIST_KEY = new TopLevelListKey("foo");
+ private static final InstanceIdentifier<TopLevelList> NODE_PATH = TOP_PATH.child(TopLevelList.class, TOP_LIST_KEY);
@Test
public void test() throws InterruptedException, ExecutionException {
- WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
- writeTx.put(LogicalDatastoreType.OPERATIONAL, NODES_PATH, new NodesBuilder().build());
- writeTx.put(LogicalDatastoreType.OPERATIONAL, NODE_PATH, new NodeBuilder().setKey(NODE_KEY).build());
+ WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+ writeTx.put(LogicalDatastoreType.OPERATIONAL, TOP_PATH, new TopBuilder().build());
+ writeTx.put(LogicalDatastoreType.OPERATIONAL, NODE_PATH, new TopLevelListBuilder().setKey(TOP_LIST_KEY).build());
assertEquals(TransactionStatus.COMMITED, writeTx.commit().get().getResult());
}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.md.sal.binding.test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class AbstractDataBrokerTest extends AbstractSchemaAwareTest {
+
+ private DataBrokerTestCustomizer testCustomizer;
+ private DataBroker dataBroker;
+ private DOMDataBroker domBroker;
+
+
+ @Override
+ protected void setupWithSchema(final SchemaContext context) {
+ testCustomizer = createDataBrokerTestCustomizer();
+ dataBroker = testCustomizer.createDataBroker();
+ domBroker = testCustomizer.createDOMDataBroker();
+ testCustomizer.updateSchema(context);
+ setupWithDataBroker(dataBroker);
+ }
+
+ protected void setupWithDataBroker(final DataBroker dataBroker) {
+ // Intentionally left No-op, subclasses may customize it
+ }
+
+ protected DataBrokerTestCustomizer createDataBrokerTestCustomizer() {
+ return new DataBrokerTestCustomizer();
+ }
+
+ public DataBroker getDataBroker() {
+ return dataBroker;
+ }
+
+ public DOMDataBroker getDomBroker() {
+ return domBroker;
+ }
+
+ protected static final void assertCommit(final ListenableFuture<RpcResult<TransactionStatus>> commit) {
+ try {
+ assertEquals(TransactionStatus.COMMITED,commit.get(500, TimeUnit.MILLISECONDS).getResult());
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.md.sal.binding.test;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+public abstract class AbstractDataChangeListenerTest extends AbstractDataBrokerTest {
+
+ protected static final class TestListener implements DataChangeListener {
+
+ private final SettableFuture<AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject>> event;
+ private boolean capture = false;
+
+ private TestListener() {
+ event = SettableFuture.create();
+ }
+
+ @Override
+ public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> arg) {
+ if (capture) {
+ event.set(arg);
+ }
+ }
+
+ public AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> event() {
+ try {
+ return event.get(500, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException | TimeoutException | ExecutionException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public boolean hasEvent() {
+ return event.isDone();
+ }
+
+ public void startCapture() {
+ this.capture = true;
+ }
+ }
+
+ protected final TestListener createListener(final LogicalDatastoreType store, final InstanceIdentifier<?> path,
+ final DataChangeScope scope) {
+ TestListener listener = new TestListener();
+ getDataBroker().registerDataChangeListener(store, path, listener, scope);
+ listener.startCapture();
+ return listener;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.md.sal.binding.test;
+
+import org.junit.Before;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public abstract class AbstractSchemaAwareTest {
+
+ private Iterable<YangModuleInfo> moduleInfos;
+ private SchemaContext schemaContext;
+
+
+ protected Iterable<YangModuleInfo> getModuleInfos() {
+ return BindingReflections.loadModuleInfos();
+ }
+
+
+ @Before
+ public final void setup() {
+ moduleInfos = getModuleInfos();
+ ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create();
+ moduleContext.addModuleInfos(moduleInfos);
+ schemaContext = moduleContext.tryToCreateSchemaContext().get();
+ setupWithSchema(schemaContext);
+ }
+
+ /**
+ * Setups test with Schema context.
+ * This method is called before {@link #setupWithSchemaService(SchemaService)}
+ *
+ * @param context
+ */
+ protected abstract void setupWithSchema(SchemaContext context);
+
+}
--- /dev/null
+package org.opendaylight.controller.md.sal.binding.test;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.junit.Assert;
+
+public class AssertCollections {
+
+ public static void assertEmpty(final Collection<?> set) {
+ Assert.assertTrue(set.isEmpty());
+ }
+
+ public static void assertEmpty(final Map<?,?> set) {
+ Assert.assertTrue(set.isEmpty());
+ }
+
+ public static void assertContains(final Collection<?> set, final Object... values) {
+ for (Object key : values) {
+ Assert.assertTrue(set.contains(key));
+ }
+
+ }
+
+ public static void assertNotContains(final Collection<?> set, final Object... values) {
+ for (Object key : values) {
+ Assert.assertFalse(set.contains(key));
+ }
+ }
+
+ public static void assertContains(final Map<?,?> map, final Object... values) {
+ for (Object key : values) {
+ Assert.assertTrue(map.containsKey(key));
+ }
+ }
+
+ public static void assertNotContains(final Map<?,?> map, final Object... values) {
+ for (Object key : values) {
+ Assert.assertFalse(map.containsKey(key));
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.md.sal.binding.test;
+
+import javassist.ClassPool;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl;
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
+import org.opendaylight.controller.sal.binding.test.util.MockSchemaService;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.core.spi.data.DOMStore;
+import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+public class DataBrokerTestCustomizer {
+
+ private DOMDataBroker domDataBroker;
+ private final RuntimeGeneratedMappingServiceImpl mappingService;
+ private final MockSchemaService schemaService;
+ private ImmutableMap<LogicalDatastoreType, DOMStore> datastores;
+
+ public ImmutableMap<LogicalDatastoreType, DOMStore> createDatastores() {
+ return ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
+ .put(LogicalDatastoreType.OPERATIONAL, createOperationalDatastore())
+ .put(LogicalDatastoreType.CONFIGURATION,createConfigurationDatastore())
+ .build();
+ }
+
+ public DataBrokerTestCustomizer() {
+ schemaService = new MockSchemaService();
+ mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault());
+ }
+
+ public DOMStore createConfigurationDatastore() {
+ InMemoryDOMDataStore store = new InMemoryDOMDataStore("CFG", MoreExecutors.sameThreadExecutor());
+ schemaService.registerSchemaServiceListener(store);
+ return store;
+ }
+
+ public DOMStore createOperationalDatastore() {
+ InMemoryDOMDataStore store = new InMemoryDOMDataStore("OPER", MoreExecutors.sameThreadExecutor());
+ schemaService.registerSchemaServiceListener(store);
+ return store;
+ }
+
+ public DOMDataBroker createDOMDataBroker() {
+ return new DOMDataBrokerImpl(getDatastores(), getCommitCoordinatorExecutor());
+ }
+
+ public ListeningExecutorService getCommitCoordinatorExecutor() {
+ return MoreExecutors.sameThreadExecutor();
+ }
+
+ public DataBroker createDataBroker() {
+ return new ForwardedBindingDataBroker(getDOMDataBroker(), getMappingService(), getSchemaService());
+ }
+
+ private SchemaService getSchemaService() {
+ return schemaService;
+ }
+
+ private BindingIndependentMappingService getMappingService() {
+ return mappingService;
+ }
+
+ private DOMDataBroker getDOMDataBroker() {
+ if(domDataBroker == null) {
+ domDataBroker = createDOMDataBroker();
+ }
+ return domDataBroker;
+ }
+
+ private ImmutableMap<LogicalDatastoreType, DOMStore> getDatastores() {
+ if(datastores == null) {
+ datastores = createDatastores();
+ }
+ return datastores;
+ }
+
+ public void updateSchema(final SchemaContext ctx) {
+ schemaService.changeSchema(ctx);
+ mappingService.onGlobalContextUpdated(ctx);
+ }
+
+}
*/
package org.opendaylight.controller.sal.binding.test;
-import org.junit.After;
import org.junit.Before;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
-import org.opendaylight.controller.sal.core.api.data.DataStore;
-import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
+@SuppressWarnings("deprecation")
public abstract class AbstractDataServiceTest {
- private static Logger log = LoggerFactory.getLogger(AbstractDataServiceTest.class);
protected org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
protected DataProviderService baDataService;
protected BindingIndependentMappingService mappingService;
- private DataStoreStatsWrapper dataStoreStats;
- protected DataStore dataStore;
protected BindingTestContext testContext;
@Before
baDataService = testContext.getBindingDataBroker();
biDataService = testContext.getDomDataBroker();
- dataStore = testContext.getDomDataStore();
mappingService = testContext.getBindingToDomMappingService();
}
protected boolean getStartWithSchema() {
return true;
}
-
- @After
- public void afterTest() {
-
- testContext.logDataStoreStatistics();
-
- }
}
import javassist.ClassPool;
+import com.google.common.annotations.Beta;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
+@Beta
public class BindingBrokerTestFactory {
private static final ClassPool CLASS_POOL = ClassPool.getDefault();
import static com.google.common.base.Preconditions.checkState;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Set;
import java.util.concurrent.Future;
import org.opendaylight.controller.sal.core.api.RpcImplementation;
import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
-import org.opendaylight.controller.sal.core.api.data.DataStore;
import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
import org.opendaylight.controller.sal.core.spi.data.DOMStore;
import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl;
-import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
-import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
-import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
-import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import org.reflections.Reflections;
-import org.reflections.scanners.ResourcesScanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Predicate;
+import com.google.common.annotations.Beta;
import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.ImmutableClassToInstanceMap;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.MutableClassToInstanceMap;
import com.google.common.util.concurrent.ListeningExecutorService;
+@Beta
public class BindingTestContext implements AutoCloseable {
public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier TREE_ROOT = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
private BindingIndependentConnector baConnectImpl;
private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl;
+ @SuppressWarnings("deprecation")
private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataLegacyBroker;
private BrokerImpl biBrokerImpl;
- private HashMapDataStore rawDataStore;
- private SchemaAwareDataStoreAdapter schemaAwareDataStore;
- private DataStoreStatsWrapper dataStoreStats;
- private DataStore dataStore;
-
- private final boolean dataStoreStatisticsEnabled = false;
private final ListeningExecutorService executor;
private final ClassPool classPool;
private BackwardsCompatibleDataBroker biCompatibleBroker;
+ @SuppressWarnings("deprecation")
private DataProviderService baData;
private DOMDataBroker newDOMDataBroker;
this.startWithSchema = startWithSchema;
}
- @Deprecated
- public void startDomDataStore() {
- checkState(dataStore == null, "DataStore already started.");
- checkState(biDataImpl != null, "Dom Data Broker not present");
- rawDataStore = new HashMapDataStore();
- schemaAwareDataStore = new SchemaAwareDataStoreAdapter();
- schemaAwareDataStore.changeDelegate(rawDataStore);
- if (dataStoreStatisticsEnabled) {
- dataStoreStats = new DataStoreStatsWrapper(schemaAwareDataStore);
- dataStore = dataStoreStats;
- } else {
- dataStore = schemaAwareDataStore;
- }
- mockSchemaService.registerSchemaServiceListener(schemaAwareDataStore);
- biDataImpl.registerConfigurationReader(TREE_ROOT, dataStore);
- biDataImpl.registerOperationalReader(TREE_ROOT, dataStore);
- biDataImpl.registerCommitHandler(TREE_ROOT, dataStore);
- }
-
public void startDomDataBroker() {
checkState(executor != null, "Executor needs to be set");
biDataImpl = new org.opendaylight.controller.sal.dom.broker.DataBrokerImpl();
private ProviderSession createMockContext() {
+ @SuppressWarnings("deprecation")
final ClassToInstanceMap<BrokerService> domBrokerServices = ImmutableClassToInstanceMap
.<BrokerService> builder()
//
mockSchemaService.registerSchemaServiceListener(mappingServiceImpl);
}
- public void updateYangSchema(final String[] files) {
- mockSchemaService.changeSchema(getContext(files));
+ private void updateYangSchema(final ImmutableSet<YangModuleInfo> moduleInfos) {
+ mockSchemaService.changeSchema(getContext(moduleInfos));
}
- public static String[] getAllYangFilesOnClasspath() {
- Predicate<String> predicate = new Predicate<String>() {
- @Override
- public boolean apply(final String input) {
- return input.endsWith(".yang");
- }
- };
- Reflections reflection = new Reflections("META-INF.yang", new ResourcesScanner());
- Set<String> result = reflection.getResources(predicate);
- return result.toArray(new String[result.size()]);
- }
-
- private static SchemaContext getContext(final String[] yangFiles) {
- ClassLoader loader = BindingTestContext.class.getClassLoader();
- List<InputStream> streams = new ArrayList<>();
- for (String string : yangFiles) {
- InputStream stream = loader.getResourceAsStream(string);
- streams.add(stream);
- }
- YangParserImpl parser = new YangParserImpl();
- Set<Module> modules = parser.parseYangModelsFromStreams(streams);
- return parser.resolveSchemaContext(modules);
- }
-
- public void startLegacy() {
- startBindingDataBroker();
- startBindingNotificationBroker();
- startBindingBroker();
- startDomDataBroker();
- startDomDataStore();
- startDomBroker();
- startDomMountPoint();
- startBindingToDomMappingService();
- startForwarding();
- if (startWithSchema) {
- loadYangSchemaFromClasspath();
- }
+ private SchemaContext getContext(final ImmutableSet<YangModuleInfo> moduleInfos) {
+ ModuleInfoBackedContext ctx = ModuleInfoBackedContext.create();
+ ctx.addModuleInfos(moduleInfos);
+ return ctx.tryToCreateSchemaContext().get();
}
public void start() {
}
public void loadYangSchemaFromClasspath() {
- String[] files = getAllYangFilesOnClasspath();
- updateYangSchema(files);
+ ImmutableSet<YangModuleInfo> moduleInfos = BindingReflections.loadModuleInfos();
+ updateYangSchema(moduleInfos);
}
+ @SuppressWarnings("deprecation")
public DataProviderService getBindingDataBroker() {
return baData;
}
+ @SuppressWarnings("deprecation")
public org.opendaylight.controller.sal.core.api.data.DataProviderService getDomDataBroker() {
return biDataLegacyBroker;
}
- public DataStore getDomDataStore() {
- return dataStore;
- }
-
public BindingIndependentMappingService getBindingToDomMappingService() {
return mappingServiceImpl;
}
- public void logDataStoreStatistics() {
- if (dataStoreStats == null) {
- return;
- }
-
- LOG.info("BIDataStore Statistics: Configuration Read Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
- dataStoreStats.getConfigurationReadCount(), dataStoreStats.getConfigurationReadTotalTime(),
- dataStoreStats.getConfigurationReadAverageTime());
-
- LOG.info("BIDataStore Statistics: Operational Read Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
- dataStoreStats.getOperationalReadCount(), dataStoreStats.getOperationalReadTotalTime(),
- dataStoreStats.getOperationalReadAverageTime());
-
- LOG.info("BIDataStore Statistics: Request Commit Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
- dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(),
- dataStoreStats.getRequestCommitAverageTime());
- }
-
public RpcProviderRegistry getBindingRpcRegistry() {
return baBrokerImpl.getRoot();
}
baDataService = testContext.getBindingDataBroker();
biDataService = testContext.getDomDataBroker();
- dataStore = testContext.getDomDataStore();
mappingService = testContext.getBindingToDomMappingService();
};
* This initial event will contain all preexisting data as created.
*
* <p>
- * <b>Note</b> that this method may be invoked from a shared thread pool, so
- * implementations SHOULD NOT perform CPU-intensive operations and they
- * definitely MUST NOT invoke any potentially blocking operations.
+ * <b>Note</b>: This method may be invoked from a shared thread pool.
+ * <li>Implementations <b>SHOULD NOT</b> perform CPU-intensive operations on the calling thread.
+ * <li>Implementations <b>MUST NOT block the calling thread</b> - to do so could lead to deadlock
+ * scenarios.
+ *
+ *<br>
*
* @param change
* Data Change Event being delivered.
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
-import com.google.common.base.Optional;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
public abstract class DataNormalizationOperation<T extends PathArgument> implements Identifiable<T> {
private final T identifier;
+ private final Optional<DataSchemaNode> dataSchemaNode;
@Override
public T getIdentifier() {
return identifier;
};
- protected DataNormalizationOperation(final T identifier) {
+ protected DataNormalizationOperation(final T identifier, final SchemaNode schema) {
super();
this.identifier = identifier;
+ if(schema instanceof DataSchemaNode) {
+ this.dataSchemaNode = Optional.of((DataSchemaNode) schema);
+ } else {
+ this.dataSchemaNode = Optional.absent();
+ }
}
public boolean isMixin() {
public abstract boolean isLeaf();
+ public Optional<DataSchemaNode> getDataSchemaNode() {
+ // FIXME
+ return dataSchemaNode;
+ }
+
private static abstract class SimpleTypeNormalization<T extends PathArgument> extends DataNormalizationOperation<T> {
- protected SimpleTypeNormalization(final T identifier) {
- super(identifier);
+ protected SimpleTypeNormalization(final T identifier, final DataSchemaNode potential) {
+ super(identifier,potential);
}
@Override
private static final class LeafNormalization extends SimpleTypeNormalization<NodeIdentifier> {
- protected LeafNormalization(final NodeIdentifier identifier) {
- super(identifier);
+ protected LeafNormalization(final LeafSchemaNode potential) {
+ super(new NodeIdentifier(potential.getQName()),potential);
}
@Override
private static final class LeafListEntryNormalization extends SimpleTypeNormalization<NodeWithValue> {
public LeafListEntryNormalization(final LeafListSchemaNode potential) {
- super(new NodeWithValue(potential.getQName(), null));
+ super(new NodeWithValue(potential.getQName(), null),potential);
}
@Override
private static abstract class CompositeNodeNormalizationOperation<T extends PathArgument> extends
DataNormalizationOperation<T> {
- protected CompositeNodeNormalizationOperation(final T identifier) {
- super(identifier);
+ protected CompositeNodeNormalizationOperation(final T identifier, final DataSchemaNode schema) {
+ super(identifier,schema);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private final Map<QName, DataNormalizationOperation<?>> byQName;
private final Map<PathArgument, DataNormalizationOperation<?>> byArg;
- protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
- super(identifier);
+ protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema, final DataSchemaNode node) {
+ super(identifier,node);
this.schema = schema;
this.byArg = new ConcurrentHashMap<>();
this.byQName = new ConcurrentHashMap<>();
private final List<QName> keyDefinition;
protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
- super(identifier, schema);
+ super(identifier, schema,schema);
keyDefinition = schema.getKeyDefinition();
}
private static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
protected UnkeyedListItemNormalization(final ListSchemaNode schema) {
- super(new NodeIdentifier(schema.getQName()), schema);
+ super(new NodeIdentifier(schema.getQName()), schema,schema);
}
@Override
private static final class ContainerNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
protected ContainerNormalization(final ContainerSchemaNode schema) {
- super(new NodeIdentifier(schema.getQName()), schema);
+ super(new NodeIdentifier(schema.getQName()),schema, schema);
}
@Override
private static abstract class MixinNormalizationOp<T extends PathArgument> extends
CompositeNodeNormalizationOperation<T> {
- protected MixinNormalizationOp(final T identifier) {
- super(identifier);
+ protected MixinNormalizationOp(final T identifier, final DataSchemaNode schema) {
+ super(identifier,schema);
}
@Override
private final DataNormalizationOperation<?> innerOp;
public UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
- super(new NodeIdentifier(potential.getQName()));
+ super(new NodeIdentifier(potential.getQName()),potential);
innerOp = new LeafListEntryNormalization(potential);
}
public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
//super();
- super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation,schema));
+ super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation,schema),null);
}
@Override
private final ListItemNormalization innerNode;
public UnorderedMapMixinNormalization(final ListSchemaNode list) {
- super(new NodeIdentifier(list.getQName()));
+ super(new NodeIdentifier(list.getQName()),list);
this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(),
Collections.<QName, Object> emptyMap()), list);
}
private final UnkeyedListItemNormalization innerNode;
public UnkeyedListMixinNormalization(final ListSchemaNode list) {
- super(new NodeIdentifier(list.getQName()));
+ super(new NodeIdentifier(list.getQName()),list);
this.innerNode = new UnkeyedListItemNormalization(list);
}
private final ImmutableMap<PathArgument, DataNormalizationOperation<?>> byArg;
protected ChoiceNodeNormalization(final org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
- super(new NodeIdentifier(schema.getQName()));
+ super(new NodeIdentifier(schema.getQName()),schema);
ImmutableMap.Builder<QName, DataNormalizationOperation<?>> byQNameBuilder = ImmutableMap.builder();
ImmutableMap.Builder<PathArgument, DataNormalizationOperation<?>> byArgBuilder = ImmutableMap.builder();
private static class AnyXmlNormalization extends DataNormalizationOperation<NodeIdentifier> {
- protected AnyXmlNormalization( final NodeIdentifier identifier ) {
- super( identifier );
+ protected AnyXmlNormalization( final AnyXmlSchemaNode schema) {
+ super( new NodeIdentifier(schema.getQName()), schema);
}
@Override
return fromListSchemaNode((ListSchemaNode) potential);
} else if (potential instanceof LeafSchemaNode) {
- return new LeafNormalization(new NodeIdentifier(potential.getQName()));
+ return new LeafNormalization((LeafSchemaNode) potential);
} else if (potential instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) {
return new ChoiceNodeNormalization((org.opendaylight.yangtools.yang.model.api.ChoiceNode) potential);
} else if (potential instanceof LeafListSchemaNode) {
return fromLeafListSchemaNode((LeafListSchemaNode) potential);
} else if (potential instanceof AnyXmlSchemaNode) {
- return new AnyXmlNormalization( new NodeIdentifier(potential.getQName() ) );
+ return new AnyXmlNormalization( (AnyXmlSchemaNode) potential);
}
return null;
}
import static com.google.common.base.Preconditions.checkArgument;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicates;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Iterator;
import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
public class DataNormalizer {
private final DataNormalizationOperation<?> operation;
return InstanceIdentifier.create(normalizedArgs.build());
}
+ public DataNormalizationOperation<?> getOperation(final InstanceIdentifier legacy) throws DataNormalizationException {
+ DataNormalizationOperation<?> currentOp = operation;
+ Iterator<PathArgument> arguments = legacy.getPathArguments().iterator();
+
+ while (arguments.hasNext()) {
+ currentOp = currentOp.getChild(arguments.next());
+ }
+ return currentOp;
+ }
+
public Map.Entry<InstanceIdentifier, NormalizedNode<?, ?>> toNormalized(
final Map.Entry<InstanceIdentifier, CompositeNode> legacy) {
return toNormalized(legacy.getKey(), legacy.getValue());
DataNormalizationOperation<?> currentOp = operation;
for (PathArgument normalizedArg : normalized.getPathArguments()) {
currentOp = currentOp.getChild(normalizedArg);
- if(!currentOp.isMixin()) {
+ if (!currentOp.isMixin()) {
legacyArgs.add(normalizedArg);
}
}
return toLegacyFromDataContainer((DataContainerNode<?>) normalizedData);
} else if (normalizedData instanceof AnyXmlNode) {
Node<?> value = ((AnyXmlNode) normalizedData).getValue();
- return value instanceof CompositeNode ? (CompositeNode)value : null;
+ return value instanceof CompositeNode ? (CompositeNode) value : null;
}
return null;
}
for (NormalizedNode<?, ?> child : node.getValue()) {
if (child instanceof MixinNode && child instanceof NormalizedNodeContainer<?, ?, ?>) {
builder.addAll(toLegacyNodesFromMixin((NormalizedNodeContainer) child));
- } else if( child instanceof UnkeyedListNode) {
+ } else if (child instanceof UnkeyedListNode) {
builder.addAll(toLegacyNodesFromUnkeyedList((UnkeyedListNode) child));
} else {
addToBuilder(builder, toLegacy(child));
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-binding</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>yang-ext</artifactId>
+ </dependency>
</dependencies>
<artifactId>sal-test-model</artifactId>
--- /dev/null
+/*
+ * Copyright (c) 2014 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.md.sal.test.model.util;
+
+import java.util.Arrays;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUses;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUsesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUsesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.TopBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedListKey;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.collect.ImmutableList;
+
+public class ListsBindingUtils {
+
+ private static final InstanceIdentifier<Top> TOP_PATH = InstanceIdentifier.create(Top.class);
+
+ private ListsBindingUtils() {
+ throw new UnsupportedOperationException();
+ }
+
+ public static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo");
+ public static final TopLevelListKey TOP_BAR_KEY = new TopLevelListKey("bar");
+ public static final ListViaUsesKey USES_ONE_KEY = new ListViaUsesKey("one");
+ public static final ListViaUsesKey USES_TWO_KEY = new ListViaUsesKey("two");
+
+
+ public static InstanceIdentifier<TopLevelList> path(final TopLevelListKey key) {
+ return TOP_PATH.child(TopLevelList.class, key);
+ }
+
+ public static InstanceIdentifier<NestedList> path(final TopLevelListKey top,final NestedListKey nested) {
+ return path(top).child(NestedList.class, nested);
+ }
+
+ public static InstanceIdentifier<ListViaUses> path(final TopLevelListKey top,final ListViaUsesKey uses) {
+ return path(top).augmentation(TreeComplexUsesAugment.class).child(ListViaUses.class, uses);
+ }
+
+ public static <T extends DataObject & Augmentation<TopLevelList>> InstanceIdentifier<T> path(final TopLevelListKey key, final Class<T> augmentation) {
+ return path(key).augmentation(augmentation);
+ }
+
+ public static Top top(final TopLevelList... listItems) {
+ return new TopBuilder().setTopLevelList(Arrays.asList(listItems)).build();
+ }
+
+ public static TopLevelList topLevelList(final TopLevelListKey key) {
+ return new TopLevelListBuilder().setKey(key).build();
+ }
+
+ public static TopLevelList topLevelList(final TopLevelListKey key, final TreeComplexUsesAugment augment) {
+ TopLevelListBuilder builder = new TopLevelListBuilder().setKey(key);
+ builder.addAugmentation(TreeComplexUsesAugment.class, augment);
+ return builder.build();
+ }
+
+ public static TreeComplexUsesAugment complexUsesAugment(final ListViaUsesKey... keys) {
+ ImmutableList.Builder<ListViaUses> listViaUses = ImmutableList.<ListViaUses> builder();
+ for (ListViaUsesKey key : keys) {
+ listViaUses.add(new ListViaUsesBuilder().setKey(key).build());
+ }
+ return new TreeComplexUsesAugmentBuilder().setListViaUses(listViaUses.build()).build();
+ }
+
+}
--- /dev/null
+module opendaylight-mdsal-augment-test {
+
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:augment";
+ prefix aug-test;
+
+ import opendaylight-mdsal-list-test {
+ prefix test;
+ }
+ import yang-ext {
+ prefix ext;
+ }
+
+ description
+ "This module contains a collection of YANG augmentations used for
+ some test cases.";
+
+ revision 2014-07-09 {
+ description
+ "Test model for testing data broker with nested lists.";
+ }
+
+ grouping leaf-from-grouping {
+ leaf leaf-from-grouping {
+ type string;
+ }
+ }
+
+ grouping complex-from-grouping {
+ container container-with-uses {
+ uses leaf-from-grouping;
+ }
+ list list-via-uses {
+ key "name";
+ leaf name {
+ type string;
+ }
+ }
+
+ }
+
+ augment "/test:top/test:top-level-list" {
+ ext:augment-identifier tree-leaf-only-uses-augment;
+ uses leaf-from-grouping;
+ }
+
+ augment "/test:put-top/test:input/test:top-level-list" {
+ ext:augment-identifier rpc-leaf-only-uses-augment;
+ uses leaf-from-grouping;
+ }
+
+ augment "/test:top/test:top-level-list" {
+ ext:augment-identifier tree-complex-uses-augment;
+ uses complex-from-grouping;
+ }
+
+ augment "/test:put-top/test:input/test:top-level-list" {
+ ext:augment-identifier rpc-complex-uses-augment;
+ uses complex-from-grouping;
+ }
+
+ augment "/test:top/test:top-level-list" {
+ ext:augment-identifier tree-leaf-only-augment;
+
+ leaf simple-value {
+ type string;
+ }
+ }
+
+ augment "/test:top/test:top-level-list" {
+ ext:augment-identifier tree-second-leaf-only-augment;
+
+ leaf second-simple-value {
+ type string;
+ }
+ }
+
+ augment "/test:put-top/test:input/test:top-level-list" {
+ ext:augment-identifier rpc-leaf-only-augment;
+
+ leaf simple-value {
+ type string;
+ }
+ }
+
+ augment "/test:put-top/test:input/test:top-level-list" {
+ ext:augment-identifier rpc-second-leaf-only-augment;
+
+ leaf second-simple-value {
+ type string;
+ }
+ }
+
+}
\ No newline at end of file
import javax.management.InstanceNotFoundException;
import javax.management.ObjectName;
import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.yangtools.yang.common.QName;
public class ServiceRegistryWrapper {
- private ServiceReferenceReadableRegistry configServiceRefRegistry;
+ private final ServiceReferenceReadableRegistry configServiceRefRegistry;
public ServiceRegistryWrapper(ServiceReferenceReadableRegistry configServiceRefRegistry) {
this.configServiceRefRegistry = configServiceRefRegistry;
String qNameOfService = configServiceRefRegistry.getServiceInterfaceName(namespace, serviceName);
try {
- return configServiceRefRegistry.getServiceReference(qNameOfService, refName);
+ /*
+ Remove transaction name as this is redundant - will be stripped in DynamicWritableWrapper,
+ and makes it hard to compare with service references got from MXBean attributes
+ */
+ return ObjectNameUtil.withoutTransactionName(
+ configServiceRefRegistry.getServiceReference(qNameOfService, refName));
} catch (InstanceNotFoundException e) {
throw new IllegalArgumentException("No serviceInstance mapped to " + refName
+ " under service name " + serviceName + " , " + refNameToInstance.keySet(), e);
String serviceName = ObjectNameAttributeReadingStrategy.checkPrefixAndExtractServiceName(typeElement, prefixNamespace);
- Map<String, String> innerMap = Maps.newHashMap();
- namespaceToServices.put(serviceName, innerMap);
+ Map<String, String> innerMap = namespaceToServices.get(serviceName);
+ if (innerMap == null) {
+ innerMap = Maps.newHashMap();
+ namespaceToServices.put(serviceName, innerMap);
+ }
List<XmlElement> instances = service.getChildElements(XmlNetconfConstants.INSTANCE_KEY);
service.checkUnrecognisedElements(instances, typeElement);
package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
+import static java.util.Arrays.asList;
+
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.management.Attribute;
@Override
void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
+ String module, String instance, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
throw new NetconfConfigHandlingException(
String.format("Unable to handle missing instance, no missing instances should appear at this point, missing: %s : %s ",
module,
NetconfDocumentedException.ErrorTag.operation_failed,
NetconfDocumentedException.ErrorSeverity.error);
}
+
@Override
void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
continue;
}
- Object value = ace.getResolvedValue().get();
- ta.setAttribute(on, ace.getJmxName(), new Attribute(ace.getJmxName(), value));
- logger.debug("Attribute {} set to {} for {}", configAttributeEntry.getKey(), value, on);
+ Object toBeMergedIn = ace.getResolvedValue().get();
+ // Get the existing values so we can merge the new values with them.
+ Attribute currentAttribute = ta.getAttribute(on, ace.getJmxName());
+ Object oldValue = (currentAttribute != null ? currentAttribute.getValue() : null);
+ // Merge value with currentValue
+ toBeMergedIn = merge(oldValue, toBeMergedIn);
+ ta.setAttribute(on, ace.getJmxName(), new Attribute(ace.getJmxName(), toBeMergedIn));
+ logger.debug("Attribute {} set to {} for {}", configAttributeEntry.getKey(), toBeMergedIn, on);
} catch (Exception e) {
+ logger.error("Error while merging objectnames of {}", on, e);
throw new NetconfConfigHandlingException(String.format("Unable to set attributes for %s, Error with attribute %s : %s ",
on,
configAttributeEntry.getKey(),
}
}
}
+
+ /**
+ * Merge value into current value
+ * Currently, this is only implemented for arrays of ObjectNames, but that is the
+ * most common case for which it is needed.
+ */
+ protected Object merge(Object oldValue, Object toBeMergedIn) {
+ if (oldValue instanceof ObjectName[] && toBeMergedIn instanceof ObjectName[]) {
+ toBeMergedIn = mergeObjectNameArrays((ObjectName[]) oldValue, (ObjectName[]) toBeMergedIn);
+ }
+ return toBeMergedIn;
+ }
+
+ /**
+ * Merge value into current values
+ * This implements for arrays of ObjectNames, but that is the
+ * most common case for which it is needed.
+ *
+ * @param oldValue - the new values to be merged into existing values
+ * @param toBeMergedIn - the existing values
+ *
+ * @return an ObjectName[] consisting the elements of currentValue with an elements from values not already present in currentValue added
+ *
+ */
+ protected ObjectName[] mergeObjectNameArrays(ObjectName[] oldValue, ObjectName[] toBeMergedIn) {
+ List<ObjectName> newValueList = new ArrayList<>();
+ newValueList.addAll(asList(oldValue));
+ /*
+ It is guaranteed that old values do not contain transaction name.
+ Since toBeMergedIn is filled using service references translated by ServiceRegistryWrapper, it
+ is also guaranteed that this list will not contain transaction names.
+ Run through the list of values to be merged. If we don't have them already, add them to the list.
+ */
+ for (ObjectName objName : toBeMergedIn) {
+ if (!newValueList.contains(objName)) {
+ newValueList.add(objName);
+ }
+ }
+ return newValueList.toArray(new ObjectName[newValueList.size()]);
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.operations.editconfig;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.controller.config.api.jmx.ObjectNameUtil.createReadOnlyModuleON;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import java.util.List;
+import java.util.Map;
+import javax.management.ObjectName;
+import org.junit.Before;
+import org.junit.Test;
+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 org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModule;
+import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleMXBean;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
+
+public class MergeEditConfigStrategyTest extends AbstractConfigTest {
+ private static final MultipleDependenciesModuleFactory factory = new MultipleDependenciesModuleFactory();
+ public static final String PARENT = "parent";
+ public static final String D1 = "d1";
+ public static final String D2 = "d2";
+ public static final String D3 = "d3";
+
+ private static final String factoryName = factory.getImplementationName();
+
+ @Before
+ public void setUp() throws Exception {
+ super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, factory));
+
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+ ObjectName d1 = transaction.createModule(factoryName, D1);
+ ObjectName d2 = transaction.createModule(factoryName, D2);
+ ObjectName parent = transaction.createModule(factoryName, PARENT);
+ MultipleDependenciesModuleMXBean multipleDependenciesModuleMXBean = transaction.newMXBeanProxy(parent,
+ MultipleDependenciesModuleMXBean.class);
+ multipleDependenciesModuleMXBean.setTestingDeps(asList(d1, d2));
+ transaction.createModule(factoryName, D3);
+ transaction.commit();
+ }
+
+ @Test
+ public void testMergingOfObjectNames() throws Exception {
+ MergeEditConfigStrategy strategy = new MergeEditConfigStrategy();
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+
+ // add D3
+
+ AttributeConfigElement attributeConfigElement = mock(AttributeConfigElement.class);
+ doReturn(Optional.of(new ObjectName[] {createReadOnlyModuleON(factoryName, D3)})).when(attributeConfigElement).getResolvedValue();
+ doReturn("mocked").when(attributeConfigElement).toString();
+ String attributeName = MultipleDependenciesModule.testingDepsJmxAttribute.getAttributeName();
+ doReturn(attributeName).when(attributeConfigElement).getJmxName();
+ Map<String, AttributeConfigElement> configuration = ImmutableMap.of(
+ attributeName,
+ attributeConfigElement);
+
+ strategy.executeConfiguration(factoryName, PARENT, configuration, transaction,
+ mock(ServiceRegistryWrapper.class));
+ transaction.commit();
+
+ // parent's attribute should contain d1,d2,d3
+ MultipleDependenciesModuleMXBean proxy = configRegistryClient.newMXBeanProxy(
+ createReadOnlyModuleON(factoryName, PARENT),
+ MultipleDependenciesModuleMXBean.class);
+ List<ObjectName> testingDeps = proxy.getTestingDeps();
+ List<ObjectName> expected = asList(createReadOnlyModuleON(factoryName, D1),
+ createReadOnlyModuleON(factoryName, D2),
+ createReadOnlyModuleON(factoryName, D3));
+ assertEquals(expected, testingDeps);
+ }
+}
import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertElementsCount;
import static org.opendaylight.controller.netconf.util.xml.XmlUtil.readXmlToDocument;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import io.netty.channel.ChannelFuture;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.List;
import java.util.Set;
-
import javax.management.InstanceNotFoundException;
import javax.management.Notification;
import javax.management.NotificationListener;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import io.netty.channel.ChannelFuture;
-
public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
@Before
public void setUp() throws Exception {
- super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,NetconfITTest.getModuleFactoriesS().toArray(
- new ModuleFactory[0])));
+ super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,NetconfITTest.FACTORIES));
NetconfMonitoringServiceImpl monitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
package org.opendaylight.controller.netconf.it;
+import static java.util.Arrays.asList;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
}
protected List<ModuleFactory> getModuleFactories() {
- return NetconfITTest.getModuleFactoriesS();
+ return asList(NetconfITTest.FACTORIES);
}
@Test
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.matchers.JUnitMatchers;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
import org.opendaylight.controller.config.yang.test.impl.IdentityTestModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleMXBean;
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;
private NetconfMessage getConfig, getConfigCandidate, editConfig, closeSession;
- private DefaultCommitNotificationProducer commitNot;
+ private DefaultCommitNotificationProducer commitNotificationProducer;
private NetconfServerDispatcher dispatch;
private NetconfClientDispatcherImpl clientDispatcher;
+ static ModuleFactory[] FACTORIES = {new TestImplModuleFactory(), new DepTestImplModuleFactory(),
+ new NetconfTestImplModuleFactory(), new IdentityTestModuleFactory(),
+ new MultipleDependenciesModuleFactory()};
+
@Before
public void setUp() throws Exception {
- super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,getModuleFactories().toArray(
- new ModuleFactory[0])));
+ initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,
+ FACTORIES
+ ));
loadMessages();
NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
-
- commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
+ commitNotificationProducer = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
dispatch = createDispatcher(factoriesListener);
ChannelFuture s = dispatch.createServer(tcpAddress);
}
private NetconfServerDispatcher createDispatcher(NetconfOperationServiceFactoryListenerImpl factoriesListener) {
- return super.createDispatcher(factoriesListener, getNetconfMonitoringListenerService(), commitNot);
+ return super.createDispatcher(factoriesListener, getNetconfMonitoringListenerService(), commitNotificationProducer);
}
static NetconfMonitoringServiceImpl getNetconfMonitoringListenerService() {
@After
public void tearDown() throws Exception {
- commitNot.close();
+ commitNotificationProducer.close();
clientDispatcher.close();
}
return yangDependencies;
}
- protected List<ModuleFactory> getModuleFactories() {
- return getModuleFactoriesS();
- }
-
- static List<ModuleFactory> getModuleFactoriesS() {
- return Lists.newArrayList(new TestImplModuleFactory(), new DepTestImplModuleFactory(),
- new NetconfTestImplModuleFactory(), new IdentityTestModuleFactory());
- }
@Test
public void testNetconfClientDemonstration() throws Exception {
doReturn(codec).when(ret).getIdentityCodec();
return ret;
}
+
+
+ @Test
+ public void testMultipleDependencies() throws Exception {
+ // push first xml, should add parent and d1,d2 dependencies
+ try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
+ Document rpcReply = netconfClient.sendMessage(
+ XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_merge_multiple-deps1.xml"))
+ .getDocument();
+ assertIsOK(rpcReply);
+ commit(netconfClient);
+ }
+ // verify that parent.getTestingDeps == d1,d2
+ MultipleDependenciesModuleMXBean parentProxy = configRegistryClient.newMXBeanProxy(
+ configRegistryClient.lookupConfigBean(MultipleDependenciesModuleFactory.NAME, "parent"),
+ MultipleDependenciesModuleMXBean.class);
+ {
+ List<ObjectName> testingDeps = parentProxy.getTestingDeps();
+ assertEquals(2, testingDeps.size());
+ Set<String> actualRefs = getServiceReferences(testingDeps);
+ assertEquals(Sets.newHashSet("ref_d1", "ref_d2"), actualRefs);
+ }
+
+ // push second xml, should add d3 to parent's dependencies
+ mergeD3(parentProxy);
+ // push second xml again, to test that d3 is not added again
+ mergeD3(parentProxy);
+ }
+
+ public void mergeD3(MultipleDependenciesModuleMXBean parentProxy) throws Exception {
+ try (TestingNetconfClient netconfClient = new TestingNetconfClient(
+ "test " + tcpAddress.toString(), clientDispatcher, getClientConfiguration(tcpAddress, 5000))) {
+
+ Document rpcReply = netconfClient.sendMessage(
+ XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_merge_multiple-deps2.xml"))
+ .getDocument();
+ assertIsOK(rpcReply);
+ commit(netconfClient);
+ }
+ {
+ List<ObjectName> testingDeps = parentProxy.getTestingDeps();
+ assertEquals(3, testingDeps.size());
+ Set<String> actualRefs = getServiceReferences(testingDeps);
+ assertEquals(Sets.newHashSet("ref_d1", "ref_d2", "ref_d3"), actualRefs);
+ }
+ }
+
+ public Set<String> getServiceReferences(List<ObjectName> testingDeps) {
+ return new HashSet<>(Lists.transform(testingDeps, new Function<ObjectName, String>() {
+ @Override
+ public String apply(ObjectName input) {
+ return ObjectNameUtil.getReferenceName(input);
+ }
+ }));
+ }
+
+ public void commit(TestingNetconfClient netconfClient) throws Exception {
+ Document rpcReply;
+ rpcReply = netconfClient.sendMessage(XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/commit.xml"))
+ .getDocument();
+ assertIsOK(rpcReply);
+ }
}
import static org.mockito.Mockito.mock;
import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+import io.netty.channel.ChannelFuture;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Set;
-
import junit.framework.Assert;
-
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
-import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
-import io.netty.channel.ChannelFuture;
-
public class NetconfMonitoringITTest extends AbstractNetconfConfigTest {
private static final Logger logger = LoggerFactory.getLogger(NetconfITTest.class);
@Before
public void setUp() throws Exception {
- super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, NetconfITTest.getModuleFactoriesS().toArray(
- new ModuleFactory[0])));
+ super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, NetconfITTest.FACTORIES));
monitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
}
public static SSLContext initializeSecureContext(final String pass, final InputStream ksKeysFile, final InputStream ksTrustFile,
- final String algorithm) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
+ final String algorithm) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
UnrecoverableKeyException, KeyManagementException {
Preconditions.checkNotNull(ksTrustFile, "ksTrustFile cannot be null");
</encoder>
</appender>
- <logger name="org.opendaylight.controller.netconf" level="DEBUG"/>
+ <logger name="org.opendaylight.controller.netconf" level="TRACE"/>
<root level="error">
<appender-ref ref="STDOUT" />
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<rpc message-id="6"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <target>
+ <candidate/>
+ </target>
+ <default-operation>merge</default-operation>
+ <test-option>set</test-option>
+ <config>
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <name>d1</name>
+ <type xmlns:th-java="urn:opendaylight:params:xml:ns:yang:controller:test:impl">th-java:multiple-dependencies</type>
+ </module>
+ <module>
+ <name>d2</name>
+ <type xmlns:th-java="urn:opendaylight:params:xml:ns:yang:controller:test:impl">th-java:multiple-dependencies</type>
+ </module>
+ <module>
+ <name>parent</name>
+ <type xmlns:th-java="urn:opendaylight:params:xml:ns:yang:controller:test:impl">th-java:multiple-dependencies</type>
+
+ <multiple-dependencies xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <testing-deps>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_d1</name>
+ </testing-deps>
+ <testing-deps>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_d2</name>
+ </testing-deps>
+ </multiple-dependencies>
+
+ </module>
+
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <instance>
+ <name>ref_d1</name>
+ <provider>/modules/module[type='multiple-dependencies'][name='d1']
+ </provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <instance>
+ <name>ref_d2</name>
+ <provider>/modules/module[type='multiple-dependencies'][name='d2']
+ </provider>
+ </instance>
+ </service>
+ </services>
+ </config>
+ </edit-config>
+</rpc>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<rpc message-id="6"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <target>
+ <candidate/>
+ </target>
+ <default-operation>merge</default-operation>
+ <test-option>set</test-option>
+ <config>
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <name>d3</name>
+ <type xmlns:th-java="urn:opendaylight:params:xml:ns:yang:controller:test:impl">th-java:multiple-dependencies</type>
+ </module>
+ <module>
+ <name>parent</name>
+ <type xmlns:th-java="urn:opendaylight:params:xml:ns:yang:controller:test:impl">th-java:multiple-dependencies</type>
+ <multiple-dependencies xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <testing-deps>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <name>ref_d3</name>
+ </testing-deps>
+ </multiple-dependencies>
+ </module>
+ </modules>
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <instance>
+ <name>ref_d3</name>
+ <provider>/modules/module[type='multiple-dependencies'][name='d3']
+ </provider>
+ </instance>
+ </service>
+ </services>
+ </config>
+ </edit-config>
+</rpc>
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
+
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.opendaylight.controller.sal.match.Match;
match.setField(MatchType.DL_VLAN_PR, this.getPcp());
match.setField(MatchType.DL_TYPE, this.getEtherType());
}
+
+ /**
+ * Gets the header size in bits
+ * @return The .1Q header size in bits
+ */
+ @Override
+ public int getHeaderSize() {
+ return 32;
+ }
+
}