<artifactId>guava</artifactId>
</dependency>
<dependency>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>org.eclipse.xtend.lib</artifactId>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-test-model</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency><groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
</dependency>
</dependencies>
import java.util.Map;
import java.util.Map.Entry;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
/**
* Serialization service, which provides two-way serialization between
* Java Binding Data representation and NormalizedNode representation.
- *
*/
public interface BindingNormalizedNodeSerializer {
* @param binding Binding Instance Identifier
* @return DOM Instance Identifier
*/
- YangInstanceIdentifier toYangInstanceIdentifier(InstanceIdentifier<?> binding);
+ YangInstanceIdentifier toYangInstanceIdentifier(@Nonnull InstanceIdentifier<?> binding);
/**
* Translates supplied YANG Instance Identifier into Binding instance identifier.
*
* @param dom YANG Instance Identifier
- * @return Binding Instance Identifier
+ * @return Binding Instance Identifier, or null if the instance identifier is not
+ * representable.
*/
- InstanceIdentifier<?> fromYangInstanceIdentifier(YangInstanceIdentifier dom);
+ @Nullable InstanceIdentifier<?> fromYangInstanceIdentifier(@Nonnull YangInstanceIdentifier dom);
/**
* Translates supplied Binding Instance Identifier and data into NormalizedNode representation.
* @param data Data object representing data
* @return NormalizedNode representation
*/
- <T extends DataObject> Entry<YangInstanceIdentifier,NormalizedNode<?,?>> toNormalizedNode(InstanceIdentifier<T> path, T data);
+ <T extends DataObject> Entry<YangInstanceIdentifier, NormalizedNode<?,?>> toNormalizedNode(InstanceIdentifier<T> path, T data);
/**
* Translates supplied YANG Instance Identifier and NormalizedNode into Binding data.
* @param data NormalizedNode representing data
* @return DOM Instance Identifier
*/
- Entry<InstanceIdentifier<?>,DataObject> fromNormalizedNode(YangInstanceIdentifier path, NormalizedNode<?, ?> data);
+ @Nullable Entry<InstanceIdentifier<?>,DataObject> fromNormalizedNode(@Nonnull YangInstanceIdentifier path, NormalizedNode<?, ?> data);
/**
* Returns map view which contains translated set of entries to normalized nodes.
import java.lang.reflect.Type;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
import org.opendaylight.yangtools.binding.data.codec.impl.NodeCodecContext.CodecContextFactory;
import org.opendaylight.yangtools.concepts.Codec;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
class BindingCodecContext implements CodecContextFactory, Immutable {
-
+ private static final Logger LOG = LoggerFactory.getLogger(BindingCodecContext.class);
private static final String GETTER_PREFIX = "get";
+
private final SchemaRootCodecContext root;
private final BindingRuntimeContext context;
private final Codec<YangInstanceIdentifier, InstanceIdentifier<?>> instanceIdentifierCodec =
return context;
}
- public Codec<YangInstanceIdentifier, InstanceIdentifier<?>> getInstanceIdentifierCodec() {
+ Codec<YangInstanceIdentifier, InstanceIdentifier<?>> getInstanceIdentifierCodec() {
return instanceIdentifierCodec;
}
return currentNode;
}
- public NodeCodecContext getCodecContextNode(final YangInstanceIdentifier dom,
- final List<InstanceIdentifier.PathArgument> builder) {
+ /**
+ * Multi-purpose utility function. Traverse the codec tree, looking for
+ * the appropriate codec for the specified {@link YangInstanceIdentifier}.
+ * As a side-effect, gather all traversed binding {@link InstanceIdentifier.PathArgument}s
+ * into the supplied collection.
+ *
+ * @param dom {@link YangInstanceIdentifier} which is to be translated
+ * @param bindingArguments Collection for traversed path arguments
+ * @return Codec for target node, or @null if the node does not have a
+ * binding representation (choice, case, leaf).
+ */
+ @Nullable NodeCodecContext getCodecContextNode(final @Nonnull YangInstanceIdentifier dom,
+ final @Nonnull Collection<InstanceIdentifier.PathArgument> bindingArguments) {
NodeCodecContext currentNode = root;
ListNodeCodecContext currentList = null;
+
for (YangInstanceIdentifier.PathArgument domArg : dom.getPathArguments()) {
- Preconditions.checkArgument(currentNode instanceof DataContainerCodecContext<?>);
- DataContainerCodecContext<?> previous = (DataContainerCodecContext<?>) currentNode;
- NodeCodecContext nextNode = previous.getYangIdentifierChild(domArg);
+ Preconditions.checkArgument(currentNode instanceof DataContainerCodecContext<?>, "Unexpected child of non-container node %s", currentNode);
+ final DataContainerCodecContext<?> previous = (DataContainerCodecContext<?>) currentNode;
+ final NodeCodecContext nextNode = previous.getYangIdentifierChild(domArg);
+
/*
* List representation in YANG Instance Identifier consists of two
* arguments: first is list as a whole, second is list as an item so
* Identifier as Item or IdentifiableItem
*/
if (currentList != null) {
+ Preconditions.checkArgument(currentList == nextNode, "List should be referenced two times in YANG Instance Identifier %s", dom);
- if (currentList == nextNode) {
-
- // We entered list, so now we have all information to emit
- // list
- // path using second list argument.
- builder.add(currentList.getBindingPathArgument(domArg));
- currentList = null;
- currentNode = nextNode;
- } else {
- throw new IllegalArgumentException(
- "List should be referenced two times in YANG Instance Identifier");
- }
+ // We entered list, so now we have all information to emit
+ // list path using second list argument.
+ bindingArguments.add(currentList.getBindingPathArgument(domArg));
+ currentList = null;
+ currentNode = nextNode;
} else if (nextNode instanceof ListNodeCodecContext) {
// We enter list, we do not update current Node yet,
// since we need to verify
// it is not supported by binding instance identifier.
currentNode = nextNode;
} else if (nextNode instanceof DataContainerCodecContext<?>) {
- builder.add(((DataContainerCodecContext<?>) nextNode).getBindingPathArgument(domArg));
+ bindingArguments.add(((DataContainerCodecContext<?>) nextNode).getBindingPathArgument(domArg));
currentNode = nextNode;
} else if (nextNode instanceof LeafNodeCodecContext) {
- Preconditions.checkArgument(builder == null, "Instance Identifier for leaf is not representable.");
-
+ LOG.debug("Instance identifier referencing a leaf is not representable (%s)", dom);
+ return null;
}
}
+
// Algorithm ended in list as whole representation
// we sill need to emit identifier for list
-
- if (builder != null) {
- Preconditions.checkArgument(!(currentNode instanceof ChoiceNodeCodecContext),
- "Instance Identifier for choice is not representable.");
- Preconditions.checkArgument(!(currentNode instanceof CaseNodeCodecContext),
- "Instance Identifier for case is not representable.");
+ if (currentNode instanceof ChoiceNodeCodecContext) {
+ LOG.debug("Instance identifier targeting a choice is not representable (%s)", dom);
+ return null;
+ }
+ if (currentNode instanceof CaseNodeCodecContext) {
+ LOG.debug("Instance identifier targeting a case is not representable (%s)", dom);
+ return null;
}
+
if (currentList != null) {
- builder.add(currentList.getBindingPathArgument(null));
+ bindingArguments.add(currentList.getBindingPathArgument(null));
return currentList;
}
return currentNode;
} else if (rootType instanceof InstanceIdentifierTypeDefinition) {
return ValueTypeCodec.encapsulatedValueCodecFor(valueType, instanceIdentifierCodec);
} else if (rootType instanceof UnionTypeDefinition) {
- Callable<UnionTypeCodec> loader = UnionTypeCodec.loader(valueType, (UnionTypeDefinition) rootType,
- getInstanceIdentifierCodec(), getIdentityCodec());
+ Callable<UnionTypeCodec> loader = UnionTypeCodec.loader(valueType, (UnionTypeDefinition) rootType);
try {
return loader.call();
} catch (Exception e) {
- throw new IllegalStateException("Unable to load codec for "+valueType,e);
+ throw new IllegalStateException("Unable to load codec for " + valueType, e);
}
}
return ValueTypeCodec.getCodecFor(valueType, instantiatedType);
@Override
public YangInstanceIdentifier serialize(final InstanceIdentifier<?> input) {
- List<YangInstanceIdentifier.PathArgument> domArgs = new LinkedList<>();
+ List<YangInstanceIdentifier.PathArgument> domArgs = new ArrayList<>();
getCodecContextNode(input, domArgs);
return YangInstanceIdentifier.create(domArgs);
}
@Override
public InstanceIdentifier<?> deserialize(final YangInstanceIdentifier input) {
- List<InstanceIdentifier.PathArgument> builder = new LinkedList<>();
- getCodecContextNode(input, builder);
- return InstanceIdentifier.create(builder);
+ final List<InstanceIdentifier.PathArgument> builder = new ArrayList<>();
+ final NodeCodecContext codec = getCodecContextNode(input, builder);
+ return codec == null ? null : InstanceIdentifier.create(builder);
}
}
import java.io.IOException;
import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@Override
public InstanceIdentifier<?> fromYangInstanceIdentifier(final YangInstanceIdentifier dom) {
return codecContext.getInstanceIdentifierCodec().deserialize(dom);
- }
+ }
@Override
public <T extends DataObject> Entry<YangInstanceIdentifier,NormalizedNode<?,?>> toNormalizedNode(final InstanceIdentifier<T> path, final T data) {
NormalizedNodeResult result = new NormalizedNodeResult();
- // We create dom stream writer which produces normalized nodes
+ // We create DOM stream writer which produces normalized nodes
NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
- // We create Binding Stream Writer wchich translates from Binding to Normalized Nodes
+ // We create Binding Stream Writer which translates from Binding to Normalized Nodes
Entry<YangInstanceIdentifier, BindingStreamEventWriter> writeCtx = codecContext.newWriter(path, domWriter);
// We get serializer which reads binding data and uses Binding To Normalized Node writer to write result
return new SimpleEntry<YangInstanceIdentifier,NormalizedNode<?,?>>(writeCtx.getKey(),result.getResult());
}
- private boolean isBindingRepresentable(final NormalizedNode<?, ?> data) {
- return !(data instanceof MapNode) && !(data instanceof UnkeyedListNode) && !(data instanceof LeafSetNode) && !(data instanceof LeafNode<?>);
- }
+ private static boolean isBindingRepresentable(final NormalizedNode<?, ?> data) {
+ if (data instanceof LeafNode<?>) {
+ return false;
+ }
+ if (data instanceof LeafSetNode) {
+ return false;
+ }
+ if (data instanceof MapNode) {
+ return false;
+ }
+ if (data instanceof UnkeyedListNode) {
+ return false;
+ }
+ return true;
+ }
@Override
- public Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode(final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> data) {
- List<PathArgument> builder = new LinkedList<>();
- if(isBindingRepresentable(data)) {
- DataObject lazyObj = (DataObject) codecContext.getCodecContextNode(path, builder).dataFromNormalizedNode(data);
- InstanceIdentifier<?> bindingPath = InstanceIdentifier.create(builder);
- return new SimpleEntry<InstanceIdentifier<?>, DataObject>(bindingPath,lazyObj);
+ public Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ if (!isBindingRepresentable(data)) {
+ return null;
}
- return null;
+
+ final List<PathArgument> builder = new ArrayList<>();
+ final NodeCodecContext codec = codecContext.getCodecContextNode(path, builder);
+ if (codec == null) {
+ // FIXME: do we allow data == null?
+ if (data != null) {
+ LOG.warn("Path %s does not have a binding equivalent, should have been caught earlier", path);
+ }
+ return null;
+ }
+
+ final DataObject lazyObj = (DataObject) codec.dataFromNormalizedNode(data);
+ final InstanceIdentifier<?> bindingPath = InstanceIdentifier.create(builder);
+ return new SimpleEntry<InstanceIdentifier<?>, DataObject>(bindingPath, lazyObj);
}
@Override
- public Map<InstanceIdentifier<?>, DataObject> fromNormalizedNodes(
- final Map<YangInstanceIdentifier, NormalizedNode<?, ?>> dom) {
+ public Map<InstanceIdentifier<?>, DataObject> fromNormalizedNodes(final Map<YangInstanceIdentifier, NormalizedNode<?, ?>> dom) {
throw new UnsupportedOperationException("Not implemented yet");
}
private static class DeserializeFunction<T> implements Function<Optional<NormalizedNode<?, ?>>, Optional<T>> {
-
private final DataObjectCodecContext<?> ctx;
+
public DeserializeFunction(final DataObjectCodecContext<?> ctx) {
super();
this.ctx = ctx;
}
return Optional.absent();
}
-
-
}
private class GeneratorLoader extends CacheLoader<Class<? extends DataObject>, DataObjectSerializer> {
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
+
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
Map<YangInstanceIdentifier.PathArgument, DataContainerCodecPrototype<?>> byYangCaseChildBuilder = new HashMap<>();
Map<Class<?>, DataContainerCodecPrototype<?>> byClassBuilder = new HashMap<>();
Map<Class<?>, DataContainerCodecPrototype<?>> byCaseChildClassBuilder = new HashMap<>();
-
+ Set<Class<?>> potentialSubstitutions = new HashSet<>();
+ // Walks all cases for supplied choice in current runtime context
for (Class<?> caze : factory().getRuntimeContext().getCases(bindingClass())) {
+ // We try to load case using exact match thus name
+ // and original schema must equals
DataContainerCodecPrototype<ChoiceCaseNode> cazeDef = loadCase(caze);
+ // If we have case definition, this case is instantiated
+ // at current location and thus is valid in context of parent choice
if (cazeDef != null) {
byClassBuilder.put(cazeDef.getBindingClass(), cazeDef);
+ // Updates collection of case children
for (Class<? extends DataObject> cazeChild : BindingReflections.getChildrenClasses((Class) caze)) {
byCaseChildClassBuilder.put(cazeChild, cazeDef);
}
+ // Updates collection of YANG instance identifier to case
for (DataSchemaNode cazeChild : cazeDef.getSchema().getChildNodes()) {
byYangCaseChildBuilder.put(new NodeIdentifier(cazeChild.getQName()), cazeDef);
}
+ } else {
+ /*
+ * If case definition is not available, we store it for
+ * later check if it could be used as substitution of existing one.
+ */
+ potentialSubstitutions.add(caze);
}
}
+ Map<Class<?>, DataContainerCodecPrototype<?>> bySubstitutionBuilder = new HashMap<>();
+ /*
+ * Walks all cases which are not directly instantiated and
+ * tries to match them to instantiated cases - represent same data as instantiated case,
+ * only case name or schema path is different. This is required due property of
+ * binding specification, that if choice is in grouping schema path location is lost,
+ * and users may use incorrect case class using copy builders.
+ */
+ for(Class<?> substitution : potentialSubstitutions) {
+ search: for(Entry<Class<?>, DataContainerCodecPrototype<?>> real : byClassBuilder.entrySet()) {
+ if(BindingReflections.isSubstitutionFor(substitution, real.getKey())) {
+ bySubstitutionBuilder.put(substitution, real.getValue());
+ break search;
+ }
+ }
+ }
+ byClassBuilder.putAll(bySubstitutionBuilder);
byYangCaseChild = ImmutableMap.copyOf(byYangCaseChildBuilder);
byClass = ImmutableMap.copyOf(byClassBuilder);
byCaseChildClass = ImmutableMap.copyOf(byCaseChildClassBuilder);
@Override
protected DataContainerCodecContext<?> getStreamChild(final Class<?> childClass) {
DataContainerCodecPrototype<?> childProto = byStreamClass.get(childClass);
+ if (childProto != null) {
+ return childProto.get();
+ }
+
+ if (Augmentation.class.isAssignableFrom(childClass)) {
+ /*
+ * It is potentially mismatched valid augmentation - we look up equivalent augmentation
+ * using reflection and walk all stream child and compare augmenations classes
+ * if they are equivalent.
+ *
+ * FIXME: Cache mapping of mismatched augmentation to real one, to speed up lookup.
+ */
+ Class<?> augTarget = BindingReflections.findAugmentationTarget((Class) childClass);
+ if ((bindingClass().equals(augTarget))) {
+ for (DataContainerCodecPrototype<?> realChild : byStreamClass.values()) {
+ if (Augmentation.class.isAssignableFrom(realChild.getBindingClass())
+ && BindingReflections.isSubstitutionFor(childClass,realChild.getBindingClass())) {
+ childProto = realChild;
+ break;
+ }
+ }
+ }
+ }
Preconditions.checkArgument(childProto != null, " Child %s is not valid child.",childClass);
return childProto.get();
}
package org.opendaylight.yangtools.binding.data.codec.impl;
import com.google.common.collect.ImmutableSet;
+
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
-import org.opendaylight.yangtools.concepts.Codec;
+
import org.opendaylight.yangtools.yang.binding.BindingMapping;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
}
}
- @SuppressWarnings("rawtypes")
- static final Callable<UnionTypeCodec> loader(final Class<?> unionCls,final UnionTypeDefinition unionType, final Codec instanceIdentifier, final Codec identity) {
+ static final Callable<UnionTypeCodec> loader(final Class<?> unionCls, final UnionTypeDefinition unionType) {
return new Callable<UnionTypeCodec>() {
-
@Override
- public UnionTypeCodec call() throws Exception {
+ public UnionTypeCodec call() throws NoSuchMethodException, SecurityException {
Set<UnionValueOptionContext> values = new HashSet<>();
for(TypeDefinition<?> subtype : unionType.getTypes()) {
String methodName = "get" + BindingMapping.getClassName(subtype.getQName());
--- /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.yangtools.binding.data.codec.test;
+
+import org.junit.Before;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public abstract class AbstractBindingRuntimeTest {
+
+ private SchemaContext schemaContext;
+ private BindingRuntimeContext runtimeContext;
+
+ @Before
+ public void setup() {
+ ModuleInfoBackedContext ctx = ModuleInfoBackedContext.create();
+ ctx.addModuleInfos(BindingReflections.loadModuleInfos());
+ schemaContext = ctx.tryToCreateSchemaContext().get();
+ runtimeContext = BindingRuntimeContext.create(ctx, schemaContext);
+
+ }
+
+ public SchemaContext getSchemaContext() {
+ return schemaContext;
+ }
+
+ public BindingRuntimeContext getRuntimeContext() {
+ return runtimeContext;
+ }
+}
--- /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.yangtools.binding.data.codec.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.Map.Entry;
+
+import javassist.ClassPool;
+
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.RpcComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.RpcComplexUsesAugmentBuilder;
+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.TreeLeafOnlyAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ContainerWithUsesBuilder;
+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.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.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.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+
+public class AugmentationSubstitutionTest extends AbstractBindingRuntimeTest {
+
+ 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 BindingNormalizedNodeCodecRegistry registry;
+
+ @Override
+ public void setup() {
+ super.setup();
+ JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
+ registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils));
+ registry.onBindingRuntimeContextUpdated(getRuntimeContext());
+ }
+
+ @Test
+ public void augmentationInGroupingSubstituted() {
+ TopLevelList baRpc = new TopLevelListBuilder()
+ .setKey(TOP_FOO_KEY)
+ .addAugmentation(RpcComplexUsesAugment.class, new RpcComplexUsesAugmentBuilder(createComplexData()).build())
+ .build();
+ TopLevelList baTree = new TopLevelListBuilder()
+ .setKey(TOP_FOO_KEY)
+ .addAugmentation(TreeComplexUsesAugment.class, new TreeComplexUsesAugmentBuilder(createComplexData()).build())
+ .build();
+ NormalizedNode<?, ?> domTreeEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baTree).getValue();
+ NormalizedNode<?, ?> domRpcEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baRpc).getValue();
+ assertEquals(domTreeEntry, domRpcEntry);
+ }
+
+ private RpcComplexUsesAugment createComplexData() {
+ return new RpcComplexUsesAugmentBuilder()
+ .setContainerWithUses(new ContainerWithUsesBuilder()
+ .setLeafFromGrouping("foo")
+ .build())
+ .setListViaUses(Collections.<ListViaUses>emptyList())
+ .build();
+ }
+
+}
--- /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.yangtools.binding.data.codec.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.Map.Entry;
+
+import javassist.ClassPool;
+
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.RpcComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.RpcComplexUsesAugmentBuilder;
+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.TreeLeafOnlyAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ContainerWithUsesBuilder;
+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.put.top.input.top.level.list.choice.in.list.ComplexViaUsesWithDifferentNameBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.top.top.level.list.choice.in.list.ComplexViaUsesBuilder;
+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.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.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+
+public class CaseSubstitutionTest extends AbstractBindingRuntimeTest {
+
+ 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 BindingNormalizedNodeCodecRegistry registry;
+
+ @Override
+ public void setup() {
+ super.setup();
+ JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
+ registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils));
+ registry.onBindingRuntimeContextUpdated(getRuntimeContext());
+ }
+
+ @Test
+ public void choiceInGroupingSubstituted() {
+ TopLevelList baRpc = new TopLevelListBuilder()
+ .setKey(TOP_FOO_KEY)
+ .setChoiceInList(new ComplexViaUsesWithDifferentNameBuilder(createComplexData()).build())
+ .build();
+ TopLevelList baTree = new TopLevelListBuilder()
+ .setKey(TOP_FOO_KEY)
+ .setChoiceInList(new ComplexViaUsesBuilder(createComplexData()).build())
+ .build();
+ NormalizedNode<?, ?> domTreeEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baTree).getValue();
+ NormalizedNode<?, ?> domRpcEntry = registry.toNormalizedNode(BA_TOP_LEVEL_LIST, baRpc).getValue();
+ assertEquals(domTreeEntry, domRpcEntry);
+ }
+
+ private RpcComplexUsesAugment createComplexData() {
+ return new RpcComplexUsesAugmentBuilder()
+ .setContainerWithUses(new ContainerWithUsesBuilder()
+ .setLeafFromGrouping("foo")
+ .build())
+ .setListViaUses(Collections.<ListViaUses>emptyList())
+ .build();
+ }
+
+}
--- /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.yangtools.binding.data.codec.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import javassist.ClassPool;
+
+import org.junit.Test;
+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.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+
+
+public class InstanceIdentifierTest extends AbstractBindingRuntimeTest {
+
+ 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 BindingNormalizedNodeCodecRegistry registry;
+
+ @Override
+ public void setup() {
+ super.setup();
+ JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
+ registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils));
+ registry.onBindingRuntimeContextUpdated(getRuntimeContext());
+ }
+
+ @Test
+ public void testComplexAugmentationSerialization() {
+ YangInstanceIdentifier yangII = registry.toYangInstanceIdentifier(BA_TREE_COMPLEX_USES);
+ PathArgument lastArg = yangII.getLastPathArgument();
+ assertTrue("Last argument should be AugmentationIdentifier", lastArg instanceof AugmentationIdentifier);
+ InstanceIdentifier<?> bindingII = registry.fromYangInstanceIdentifier(yangII);
+ assertEquals(BA_TREE_COMPLEX_USES, bindingII);
+ }
+
+ @Test
+ public void testLeafOnlyAugmentationSerialization() {
+ PathArgument leafOnlyLastArg = registry.toYangInstanceIdentifier(BA_TREE_LEAF_ONLY).getLastPathArgument();
+ assertTrue("Last argument should be AugmentationIdentifier", leafOnlyLastArg instanceof AugmentationIdentifier);
+ assertTrue(((AugmentationIdentifier) leafOnlyLastArg).getPossibleChildNames().contains(SIMPLE_VALUE_QNAME));
+ }
+
+}
package org.opendaylight.yangtools.sal.binding.generator.impl;
import com.google.common.collect.ImmutableList;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
-
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.Node;
import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
public InstanceIdentifier<? extends Object> deserialize(
final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier input) {
Class<?> baType = null;
- List<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument> biArgs = input.getPath();
- List<QName> scannedPath = new ArrayList<>(biArgs.size());
- List<InstanceIdentifier.PathArgument> baArgs = new ArrayList<InstanceIdentifier.PathArgument>(biArgs.size());
+ Iterable<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument> biArgs = input.getPathArguments();
+ List<QName> scannedPath = new ArrayList<>();
+ List<InstanceIdentifier.PathArgument> baArgs = new ArrayList<InstanceIdentifier.PathArgument>();
for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument biArg : biArgs) {
scannedPath.add(biArg.getNodeType());
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>yang-ext</artifactId>
+ </dependency>
+ </dependencies>
+
+ <artifactId>binding-test-model</artifactId>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ <configuration>
+ <codeGenerators>
+ <generator>
+ <codeGeneratorClass>
+ org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+ </codeGeneratorClass>
+ <outputBaseDir>
+ target/generated-sources/sal
+ </outputBaseDir>
+ </generator>
+ </codeGenerators>
+ <inspectDependencies>true</inspectDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+
+</project>
--- /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 com.google.common.collect.ImmutableList;
+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.TreeLeafOnlyUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeLeafOnlyUsesAugmentBuilder;
+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 java.util.Arrays;
+
+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();
+ }
+
+ public static TreeLeafOnlyUsesAugment leafOnlyUsesAugment(String leafFromGroupingValue) {
+
+ return new TreeLeafOnlyUsesAugmentBuilder().setLeafFromGrouping(leafFromGroupingValue).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;
+ }
+ }
+
+ augment "/test:top/test:top-level-list/test:choice-in-list" {
+ case simple-via-uses {
+ uses leaf-from-grouping;
+ }
+ case complex-via-uses {
+ uses complex-from-grouping;
+ }
+ }
+
+ augment "/test:put-top/test:input/test:top-level-list/test:choice-in-list" {
+ case simple-via-uses {
+ uses leaf-from-grouping;
+ }
+ case complex-via-uses-with-different-name {
+ uses complex-from-grouping;
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+module opendaylight-mdsal-list-test {
+
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:list";
+ prefix list-test;
+
+
+ description
+ "This module contains a collection of YANG definitions used for
+ some test cases.";
+
+ revision 2014-07-01 {
+ description
+ "Test model for testing data broker with nested lists.";
+ }
+
+ grouping two-level-list {
+ list top-level-list {
+ description
+ "Top Level List";
+ key "name";
+ leaf name {
+ type string;
+ }
+
+ choice choice-in-list {
+ case simple-case {
+ leaf simple {
+ type string;
+ }
+ }
+ }
+
+ list nested-list {
+ key "name";
+ leaf name {
+ type string;
+ }
+ leaf type {
+ type string;
+ mandatory true;
+ description
+ "Mandatory type of list.";
+ }
+ ordered-by user;
+ description
+ "A list of service functions that compose the service chain";
+ }
+ }
+ }
+
+ container top {
+ uses two-level-list;
+ }
+
+ rpc put-top {
+ input {
+ uses two-level-list;
+ }
+ }
+}
\ No newline at end of file
</ul>
«ENDIF»
- «IF !path.path.empty»
+ «IF path.pathArguments.iterator.hasNext»
<h3>XML example</h3>
- «nodes.xmlExample(path.path.last.nodeType,path)»
+ «nodes.xmlExample(path.pathArguments.last.nodeType,path)»
</h3>
«ENDIF»
«FOR childNode : containers»
def header(int level,YangInstanceIdentifier name) '''
- <h«level» id="«FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">
- «FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»
+ <h«level» id="«FOR cmp : name.pathArguments SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">
+ «FOR cmp : name.pathArguments SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»
</h«level»>
'''
}
def CharSequence localLink(YangInstanceIdentifier identifier, CharSequence text) '''
- <a href="#«FOR cmp : identifier.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">«text»</a>
+ <a href="#«FOR cmp : identifier.pathArguments SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">«text»</a>
'''
append(currentModule.name)
append(":")
var previous = false;
- for(arg : identifier.path) {
+ for(arg : identifier.pathArguments) {
if(previous) append("/")
append(arg.nodeType.localName);
previous = true;
<module>binding-java-api-generator</module>
<module>binding-type-provider</module>
<module>maven-sal-api-gen-plugin</module>
+ <module>binding-test-model</module>
<module>binding-data-codec</module>
</modules>
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.collect.Sets;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public static Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Augmentable<?> input) {
return AugmentationFieldGetter.getGetter(input.getClass()).getAugmentations(input);
}
+
+ /**
+ *
+ * Determines if two augmentation classes or case classes represents same data.
+ * <p>
+ * Two augmentations or cases could be substituted only if and if:
+ * <ul>
+ * <li>Both implements same interfaces</li>
+ * <li>Both have same children</li>
+ * <li>If augmentations: Both have same augmentation target class. Target class was generated for data node in grouping.</li>
+ * <li>If cases: Both are from same choice. Choice class was generated for data node in grouping.</li>
+ * </ul>
+ * <p>
+ * <b>Explanation:</b> Binding Specification reuses classes generated for groupings as part of normal data tree,
+ * this classes from grouping could be used at various locations and user may not be aware of it
+ * and may use incorrect case or augmentation in particular subtree (via copy constructors, etc).
+ *
+ * @param potential Class which is potential substition
+ * @param target Class which should be used at particular subtree
+ * @return true if and only if classes represents same data.
+ */
+ @SuppressWarnings({"rawtypes","unchecked"})
+ public static boolean isSubstitutionFor(Class potential, Class target) {
+ HashSet<Class> subImplemented = Sets.newHashSet(potential.getInterfaces());
+ HashSet<Class> targetImplemented = Sets.newHashSet(target.getInterfaces());
+ if(!subImplemented.equals(targetImplemented)) {
+ return false;
+ }
+ if(Augmentation.class.isAssignableFrom(potential)
+ && !BindingReflections.findAugmentationTarget(potential).equals(BindingReflections.findAugmentationTarget(target))) {
+ return false;
+ }
+ for(Method potentialMethod : potential.getMethods()) {
+ try {
+ Method targetMethod = target.getMethod(potentialMethod.getName(), potentialMethod.getParameterTypes());
+ if(!potentialMethod.getReturnType().equals(targetMethod.getReturnType())) {
+ return false;
+ }
+ } catch (NoSuchMethodException e) {
+ // Counterpart method is missing, so classes could not be substituted.
+ return false;
+ } catch (SecurityException e) {
+ throw new IllegalStateException("Could not compare methods",e);
+ }
+ }
+ return true;
+ }
}