*/
package org.opendaylight.yangtools.yang.data.impl.tree;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
import java.io.InputStream;
import java.util.Collections;
-import java.util.Set;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
/**
* @author Lukas Sedlak <lsedlak@cisco.com>
return BenchmarkModel.class.getResourceAsStream(resourceName);
}
- public static SchemaContext createTestContext() {
- YangParserImpl parser = new YangParserImpl();
- Set<Module> modules = parser.parseYangModelsFromStreams(Collections.singletonList(
+ public static SchemaContext createTestContext() throws SourceException, ReactorException {
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ SchemaContext schemaContext = reactor.buildEffective(Collections.singletonList(
getDatastoreBenchmarkInputStream()));
- return parser.resolveSchemaContext(modules);
+
+ return schemaContext;
}
+
}
*/
package org.opendaylight.yangtools.yang.data.impl.tree;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
}
@Setup(Level.Trial)
- public void setup() throws DataValidationFailedException {
+ public void setup() throws DataValidationFailedException, SourceException, ReactorException {
schemaContext = BenchmarkModel.createTestContext();
final InMemoryDataTreeFactory factory = InMemoryDataTreeFactory.getInstance();
datastore = factory.create();
--- /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.it.yang.runtime.stmt.parser.retest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.ImmutableSet;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.junit.Test;
+import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+
+public class MultipleRevisionsSupportTest {
+
+ public static final YangModuleInfo TOPOLOGY_OLD_MODULE = org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev130712.$YangModuleInfoImpl
+ .getInstance();
+ public static final YangModuleInfo TOPOLOGY_NEW_MODULE = org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.$YangModuleInfoImpl
+ .getInstance();
+
+ public static final Set<YangModuleInfo> DEPENDENCIES = ImmutableSet.<YangModuleInfo> builder() //
+ .addAll(TOPOLOGY_OLD_MODULE.getImportedModules()) //
+ .addAll(TOPOLOGY_NEW_MODULE.getImportedModules()).build();
+
+ @Test
+ public void dependenciesOlderNewer() throws Exception {
+ List<InputStream> streams = ImmutableList.<InputStream> builder()//
+ .addAll(toInputStreams(DEPENDENCIES)) //
+ .add(TOPOLOGY_OLD_MODULE.getModuleSourceStream()) //
+ .add(TOPOLOGY_NEW_MODULE.getModuleSourceStream()) //
+ .build();
+ SchemaContext schemaContext = contextVerified(streams);
+ verifySchemaDifference(schemaContext, TOPOLOGY_OLD_MODULE, TOPOLOGY_NEW_MODULE);
+ verifyBindingDifference(schemaContext, TOPOLOGY_OLD_MODULE, TOPOLOGY_NEW_MODULE);
+ }
+
+ @Test
+ public void dependenciesNewerOlder() throws Exception {
+ List<InputStream> streams = ImmutableList.<InputStream> builder()//
+ .addAll(toInputStreams(DEPENDENCIES)) //
+ .add(TOPOLOGY_NEW_MODULE.getModuleSourceStream()) //
+ .add(TOPOLOGY_OLD_MODULE.getModuleSourceStream()) //
+ .build();
+ SchemaContext schemaContext = contextVerified(streams);
+ verifySchemaDifference(schemaContext, TOPOLOGY_OLD_MODULE, TOPOLOGY_NEW_MODULE);
+ verifyBindingDifference(schemaContext, TOPOLOGY_OLD_MODULE, TOPOLOGY_NEW_MODULE);
+ }
+
+ @Test
+ public void newerOlderDependencies() throws Exception {
+ List<InputStream> streams = ImmutableList.<InputStream> builder()//
+ .add(TOPOLOGY_NEW_MODULE.getModuleSourceStream()) //
+ .add(TOPOLOGY_OLD_MODULE.getModuleSourceStream()) //
+ .addAll(toInputStreams(DEPENDENCIES)) //
+ .build();
+ SchemaContext schemaContext = contextVerified(streams);
+ verifySchemaDifference(schemaContext, TOPOLOGY_OLD_MODULE, TOPOLOGY_NEW_MODULE);
+ verifyBindingDifference(schemaContext, TOPOLOGY_OLD_MODULE, TOPOLOGY_NEW_MODULE);
+ }
+
+ @Test
+ public void newerDependenciesOlder() throws Exception {
+ List<InputStream> streams = ImmutableList.<InputStream> builder()//
+ .add(TOPOLOGY_NEW_MODULE.getModuleSourceStream()) //
+ .addAll(toInputStreams(DEPENDENCIES)) //
+ .add(TOPOLOGY_OLD_MODULE.getModuleSourceStream()) //
+ .build();
+ SchemaContext schemaContext = contextVerified(streams);
+ verifySchemaDifference(schemaContext, TOPOLOGY_OLD_MODULE, TOPOLOGY_NEW_MODULE);
+ verifyBindingDifference(schemaContext, TOPOLOGY_OLD_MODULE, TOPOLOGY_NEW_MODULE);
+ }
+
+ @Test
+ public void OlderNewerDependencies() throws Exception {
+ List<InputStream> streams = ImmutableList.<InputStream> builder()//
+ .add(TOPOLOGY_OLD_MODULE.getModuleSourceStream()) //
+ .add(TOPOLOGY_NEW_MODULE.getModuleSourceStream()) //
+ .addAll(toInputStreams(DEPENDENCIES)) //
+ .build();
+ SchemaContext schemaContext = contextVerified(streams);
+ verifySchemaDifference(schemaContext, TOPOLOGY_OLD_MODULE, TOPOLOGY_NEW_MODULE);
+ verifyBindingDifference(schemaContext, TOPOLOGY_OLD_MODULE, TOPOLOGY_NEW_MODULE);
+ }
+
+ @Test
+ public void olderDependenciesNewer() throws Exception {
+ List<InputStream> streams = ImmutableList.<InputStream> builder()//
+ .add(TOPOLOGY_OLD_MODULE.getModuleSourceStream()) //
+ .add(TOPOLOGY_NEW_MODULE.getModuleSourceStream()) //
+ .addAll(toInputStreams(DEPENDENCIES)) //
+ .build();
+ SchemaContext schemaContext = contextVerified(streams);
+ verifySchemaDifference(schemaContext, TOPOLOGY_OLD_MODULE, TOPOLOGY_NEW_MODULE);
+ verifyBindingDifference(schemaContext, TOPOLOGY_OLD_MODULE, TOPOLOGY_NEW_MODULE);
+ }
+
+ private SchemaContext contextVerified(final List<InputStream> streams) throws SourceException, ReactorException {
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR
+ .newBuild();
+ return reactor.buildEffective(streams);
+ }
+
+ private void verifyBindingDifference(final SchemaContext schemaContext, final YangModuleInfo oldModule, final YangModuleInfo newModule) {
+ generatedTypesVerified(schemaContext, oldModule, newModule);
+ }
+
+ private Map<Module, ModuleContext> generatedTypesVerified(final SchemaContext schemaContext, final YangModuleInfo oldModule,
+ final YangModuleInfo newModule) {
+ BindingGeneratorImpl generator = new BindingGeneratorImpl();
+ generator.generateTypes(schemaContext);
+ return generator.getModuleContexts();
+ }
+
+ private void verifySchemaDifference(final SchemaContext context, final YangModuleInfo topologyOldModule,
+ final YangModuleInfo topologyNewModule) {
+ Module oldModel = context.findModuleByNamespaceAndRevision(//
+ URI.create(TOPOLOGY_OLD_MODULE.getNamespace()), QName.parseRevision(TOPOLOGY_OLD_MODULE.getRevision()));
+
+ Module newModel = context.findModuleByNamespaceAndRevision(//
+ URI.create(TOPOLOGY_NEW_MODULE.getNamespace()), QName.parseRevision(TOPOLOGY_NEW_MODULE.getRevision()));
+
+ SchemaNode oldNode = findSchemaNode(oldModel, "network-topology", "topology", "link");
+ SchemaNode newNode = findSchemaNode(newModel, "network-topology", "topology", "link");
+
+ assertNotNull(oldNode);
+ assertNotNull(newNode);
+
+ assertDeepRevision(TOPOLOGY_OLD_MODULE.getRevision(), oldNode);
+ assertDeepRevision(TOPOLOGY_NEW_MODULE.getRevision(), newNode);
+ }
+
+ private static void assertDeepRevision(final String revision, final SchemaNode node) {
+ assertEquals("Wrong revision: " + node.getPath(), revision, node.getQName().getFormattedRevision());
+ if (node instanceof DataNodeContainer) {
+ for (DataSchemaNode child : ((DataNodeContainer) node).getChildNodes()) {
+ assertDeepRevision(revision, child);
+ }
+ } else if (node instanceof ChoiceSchemaNode) {
+ for (DataSchemaNode child : ((ChoiceSchemaNode) node).getCases()) {
+ assertDeepRevision(revision, child);
+ }
+ }
+ }
+
+ private static final SchemaNode findSchemaNode(final DataNodeContainer container, final String... pathArgs) {
+ DataNodeContainer previous = container;
+
+ SchemaNode result = (container instanceof SchemaNode) ? (SchemaNode) container : null;
+ for (String arg : pathArgs) {
+ if (previous == null) {
+ return null;
+ }
+ for (DataSchemaNode child : previous.getChildNodes()) {
+ if (child.getQName().getLocalName().equals(arg)) {
+ if (child instanceof DataNodeContainer) {
+ previous = (DataNodeContainer) child;
+ } else {
+ previous = null;
+ }
+ result = child;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ private static final Iterable<? extends InputStream> toInputStreams(final Set<YangModuleInfo> moduleInfos)
+ throws Exception {
+ Builder<InputStream> streams = ImmutableList.<InputStream> builder();
+ for (YangModuleInfo yangModuleInfo : moduleInfos) {
+ streams.add(yangModuleInfo.getModuleSourceStream());
+ }
+ return streams.build();
+ }
+
+}
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.opendaylight.yangtools.yang.validation.tool.Main</mainClass>
</transformer>
+ <transformer
+ implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+ <mainClass>org.opendaylight.yangtools.yang.validation.tool.retest.Main</mainClass>
+ </transformer>
</transformers>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>executable</shadedClassifierName>
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.validation.tool.retest;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+
+public final class Main {
+ private Main() {
+
+ }
+
+ public static void main(final String[] args) throws URISyntaxException {
+ final Params params = ParamsUtil.parseArgs(args, Params.getParser());
+
+ if (params.isValid()) {
+ final File[] yangModels = params.getYangSourceDir().listFiles();
+
+ try {
+ RetestUtils.parseYangSources(Arrays.asList(yangModels));
+ } catch (Exception e) {
+
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.validation.tool.retest;
+
+import java.io.File;
+import java.net.URISyntaxException;
+
+import net.sourceforge.argparse4j.ArgumentParsers;
+import net.sourceforge.argparse4j.annotation.Arg;
+import net.sourceforge.argparse4j.inf.ArgumentParser;
+
+final class Params {
+
+ @Arg(dest = "yang-source-dir")
+ private File yangSourceDir;
+
+ static ArgumentParser getParser() throws URISyntaxException {
+ final ArgumentParser parser = ArgumentParsers.newArgumentParser("jar_file_name");
+ parser.description("Validation Tool for Yang Models")
+ .formatUsage();
+
+ parser.addArgumentGroup("Required arguments")
+ .addArgument("--yang-source-dir")
+ .type(File.class)
+ .required(true)
+ .help("directory containing yang models which will be parsed")
+ .dest("yang-source-dir")
+ .metavar("");
+
+ return parser;
+ }
+
+ public boolean isValid() {
+ if (yangSourceDir == null) {
+ return false;
+ }
+ if (!yangSourceDir.exists()) {
+ System.err.println("Yang source directory has to exist");
+ return false;
+ }
+ if (!yangSourceDir.canRead()) {
+ System.err.println("Yang source directory has to be readable");
+ return false;
+ }
+ if (yangSourceDir.list().length == 0) {
+ System.err.printf("Yang source directory '%s' does't contain any model%n", yangSourceDir.getPath());
+ return false;
+ }
+
+ return true;
+ }
+
+ public File getYangSourceDir() {
+ return yangSourceDir;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.validation.tool.retest;
+
+import net.sourceforge.argparse4j.inf.ArgumentParser;
+import net.sourceforge.argparse4j.inf.ArgumentParserException;
+
+final class ParamsUtil {
+ private ParamsUtil() {
+
+ }
+
+ public static Params parseArgs(final String[] args, final ArgumentParser parser) {
+ final Params params = new Params();
+ try {
+ parser.parseArgs(args, params);
+ return params;
+ } catch (final ArgumentParserException e) {
+ parser.handleError(e);
+ }
+ System.exit(1);
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.validation.tool.retest;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.Collection;
+
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
+
+public class RetestUtils {
+
+ private RetestUtils() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static SchemaContext parseYangSources(StatementStreamSource... sources) throws SourceException,
+ ReactorException {
+
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSources(sources);
+
+ return reactor.buildEffective();
+ }
+
+ public static SchemaContext parseYangSources(File... files) throws SourceException, ReactorException,
+ FileNotFoundException {
+
+ StatementStreamSource[] sources = new StatementStreamSource[files.length];
+
+ for (int i = 0; i < files.length; i++) {
+ sources[i] = new YangStatementSourceImpl(new FileInputStream(files[i]));
+ }
+
+ return parseYangSources(sources);
+ }
+
+ public static SchemaContext parseYangSources(Collection<File> files) throws SourceException, ReactorException,
+ FileNotFoundException {
+ return parseYangSources(files.toArray(new File[files.size()]));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.codec.gson.retest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.opendaylight.yangtools.yang.data.codec.gson.retest.TestUtils.loadModules;
+import static org.opendaylight.yangtools.yang.data.codec.gson.retest.TestUtils.loadTextFile;
+import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.augmentationBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.choiceBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.containerBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.leafNode;
+
+import com.google.common.collect.Sets;
+import com.google.gson.stream.JsonReader;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.URISyntaxException;
+
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+/**
+ *
+ * Each test tests whether json input is correctly transformed to normalized node structure
+ */
+public class JsonStreamToNormalizedNodeTest {
+
+ private static final QName CONT_1 = QName.create("ns:complex:json", "2014-08-11", "cont1");
+ private static final QName EMPTY_LEAF = QName.create(CONT_1,"empty");
+ private static SchemaContext schemaContext;
+
+ @BeforeClass
+ public static void initialization() throws IOException, URISyntaxException, ReactorException {
+ schemaContext = loadModules("/complexjson/yang");
+ }
+
+ /**
+ * case when anyxml contains simple value will be implemented when anyxml normalized node reprezentation will be
+ * specified
+ */
+ @Ignore
+ @Test
+ public void anyXmlNodeWithSimpleValueInContainer() throws IOException, URISyntaxException {
+
+ }
+
+ /**
+ * case when anyxml contains complex xml will be implemented when anyxml normalized node reprezentation will be
+ * specified
+ */
+ @Ignore
+ @Test
+ public void anyXmlNodeWithCompositeValueInContainer() throws IOException, URISyntaxException {
+
+ }
+
+ @Test
+ public void leafNodeInContainer() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/leaf-node-in-container.json");
+ verifyTransformationToNormalizedNode(inputJson, TestingNormalizedNodeStructuresCreator.leafNodeInContainer());
+ }
+
+ @Test
+ public void leafNodeViaAugmentationInContainer() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/leaf-node-via-augmentation-in-container.json");
+ verifyTransformationToNormalizedNode(inputJson,
+ TestingNormalizedNodeStructuresCreator.leafNodeViaAugmentationInContainer());
+ }
+
+ @Test
+ public void leafListNodeInContainer() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/leaflist-node-in-container.json");
+ verifyTransformationToNormalizedNode(inputJson,
+ TestingNormalizedNodeStructuresCreator.leafListNodeInContainer());
+ }
+
+ @Test
+ public void keyedListNodeInContainer() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/keyed-list-node-in-container.json");
+ verifyTransformationToNormalizedNode(inputJson,
+ TestingNormalizedNodeStructuresCreator.keyedListNodeInContainer());
+ }
+
+ @Test
+ public void choiceNodeInContainer() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/choice-node-in-container.json");
+ verifyTransformationToNormalizedNode(inputJson, TestingNormalizedNodeStructuresCreator.choiceNodeInContainer());
+ }
+
+ /**
+ * Test of translating internal augmentations to normalized nodes structure
+ *
+ * 2 nodes are added via internal augmentation A, 1 node via internal augmentation B and one node is originally
+ * member of case.
+ *
+ */
+ @Test
+ public void caseNodeAugmentationInChoiceInContainer() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/case-node-augmentation-in-choice-in-container.json");
+ verifyTransformationToNormalizedNode(inputJson,
+ TestingNormalizedNodeStructuresCreator.caseNodeAugmentationInChoiceInContainer());
+ }
+
+ /**
+ * also test using of namesakes (equal local names with different
+ *
+ * @throws IOException
+ * @throws URISyntaxException
+ */
+ @Test
+ public void caseNodeExternalAugmentationInChoiceInContainer() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/case-node-external-augmentation-in-choice-in-container.json");
+ verifyTransformationToNormalizedNode(inputJson,
+ TestingNormalizedNodeStructuresCreator.caseNodeExternalAugmentationInChoiceInContainer());
+ }
+
+ /**
+ * augmentation of choice - adding new case
+ */
+ @Test
+ public void choiceNodeAugmentationInContainer() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/choice-node-augmentation-in-container.json");
+ verifyTransformationToNormalizedNode(inputJson,
+ TestingNormalizedNodeStructuresCreator.choiceNodeAugmentationInContainer());
+ }
+
+ @Test
+ public void unkeyedNodeInContainer() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/unkeyed-node-in-container.json");
+ verifyTransformationToNormalizedNode(inputJson, TestingNormalizedNodeStructuresCreator.unkeyedNodeInContainer());
+ }
+
+ /**
+ * Top level JSON element contains no information about module name.
+ *
+ * It should be possible to find out potential module name from available schema context.
+ *
+ */
+ @Test
+ public void missingModuleInfoInTopLevelElement() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/missing-module-in-top-level.json");
+ verifyTransformationToNormalizedNode(inputJson, TestingNormalizedNodeStructuresCreator.topLevelContainer());
+ }
+
+ /**
+ *
+ * Exception expected.
+ *
+ * It tests case when several elements with the same name and various namespaces exists and are in JSON specified
+ * without module name prefix.
+ */
+ @Test
+ public void leafNamesakes() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/namesakes.json");
+ try {
+ //second parameter isn't necessary because error will be raised before it is used.
+ verifyTransformationToNormalizedNode(inputJson, null);
+ fail("Expected exception not raised");
+ } catch (final IllegalStateException e) {
+ final String errorMessage = e.getMessage();
+ assertTrue(errorMessage.contains("Choose suitable module name for element lf11-namesake:"));
+ assertTrue(errorMessage.contains("complexjson-augmentation"));
+ assertTrue(errorMessage.contains("complexjson-augmentation-namesake"));
+ }
+ }
+
+ @Test
+ public void emptyTypeTest() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/type-empty.json");
+ final ContainerNode awaitedStructure = containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(CONT_1))
+ .addChild(leafNode(EMPTY_LEAF, null))
+ .build();
+
+ verifyTransformationToNormalizedNode(inputJson, awaitedStructure);
+ }
+
+ /**
+ *
+ * Exception expected.
+ *
+ * Json input contains element which doesn't exist in YANG schema
+ */
+ @Test
+ public void parsingNotExistingElement() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/not-existing-element.json");
+ try {
+ //second parameter isn't necessary because error will be raised before it is used.
+ verifyTransformationToNormalizedNode(inputJson, null);
+ } catch (final IllegalStateException e) {
+ assertTrue(e.getMessage().contains("Schema node with name dummy-element wasn't found"));
+ }
+ }
+
+
+ @Test
+ public void listItemWithoutArray() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/keyed-list-restconf-behaviour.json");
+
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+ final SchemaNode parentNode = schemaContext.getDataChildByName("cont1");
+ final JsonParserStream jsonParser = JsonParserStream.create(streamWriter, schemaContext, parentNode);
+ jsonParser.parse(new JsonReader(new StringReader(inputJson)));
+ final NormalizedNode<?, ?> transformedInput = result.getResult();
+ assertNotNull(transformedInput);
+ }
+
+ @Test
+ public void listItemWithArray() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/keyed-list-yang-json-behaviour.json");
+
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+ final SchemaNode parentNode = schemaContext.getDataChildByName("cont1");
+ final JsonParserStream jsonParser = JsonParserStream.create(streamWriter, schemaContext, parentNode);
+ jsonParser.parse(new JsonReader(new StringReader(inputJson)));
+ final NormalizedNode<?, ?> transformedInput = result.getResult();
+ assertNotNull(transformedInput);
+ }
+
+ @Test
+ public void multipleChoiceAugmentation() throws IOException, URISyntaxException {
+ final String inputJson = loadTextFile("/complexjson/multiple-choice-augmentation-in-container.json");
+
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+ final SchemaNode parentNode = schemaContext.getDataChildByName("cont1");
+
+ QName augmentChoice1QName = QName.create(parentNode.getQName(), "augment-choice1");
+ QName augmentChoice2QName = QName.create(augmentChoice1QName, "augment-choice2");
+ final QName containerQName = QName.create(augmentChoice1QName, "case11-choice-case-container");
+ final QName leafQName = QName.create(augmentChoice1QName, "case11-choice-case-leaf");
+
+ final YangInstanceIdentifier.AugmentationIdentifier aug1Id =
+ new YangInstanceIdentifier.AugmentationIdentifier(Sets.newHashSet(augmentChoice1QName));
+ final YangInstanceIdentifier.AugmentationIdentifier aug2Id =
+ new YangInstanceIdentifier.AugmentationIdentifier(Sets.newHashSet(augmentChoice2QName));
+ final YangInstanceIdentifier.NodeIdentifier augmentChoice1Id =
+ new YangInstanceIdentifier.NodeIdentifier(augmentChoice1QName);
+ final YangInstanceIdentifier.NodeIdentifier augmentChoice2Id =
+ new YangInstanceIdentifier.NodeIdentifier(augmentChoice2QName);
+ final YangInstanceIdentifier.NodeIdentifier containerId =
+ new YangInstanceIdentifier.NodeIdentifier(containerQName);
+
+ final NormalizedNode<?, ?> cont1Normalized =
+ containerBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(parentNode.getQName()))
+ .withChild(augmentationBuilder().withNodeIdentifier(aug1Id)
+ .withChild(choiceBuilder().withNodeIdentifier(augmentChoice1Id)
+ .withChild(augmentationBuilder().withNodeIdentifier(aug2Id)
+ .withChild(choiceBuilder().withNodeIdentifier(augmentChoice2Id)
+ .withChild(containerBuilder().withNodeIdentifier(containerId)
+ .withChild(leafNode(leafQName, "leaf-value"))
+ .build())
+ .build())
+ .build())
+ .build())
+ .build()).build();
+
+ final JsonParserStream jsonParser = JsonParserStream.create(streamWriter, schemaContext);
+ jsonParser.parse(new JsonReader(new StringReader(inputJson)));
+ final NormalizedNode<?, ?> transformedInput = result.getResult();
+ assertNotNull(transformedInput);
+ assertEquals(cont1Normalized, transformedInput);
+ }
+
+ private void verifyTransformationToNormalizedNode(final String inputJson,
+ final NormalizedNode<?, ?> awaitedStructure) {
+ final NormalizedNodeResult result = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+ final JsonParserStream jsonParser = JsonParserStream.create(streamWriter, schemaContext);
+ jsonParser.parse(new JsonReader(new StringReader(inputJson)));
+ final NormalizedNode<?, ?> transformedInput = result.getResult();
+ assertEquals("Transformation of json input to normalized node wasn't successful.", awaitedStructure,
+ transformedInput);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.codec.gson.retest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.yangtools.yang.data.codec.gson.retest.TestUtils.childArray;
+import static org.opendaylight.yangtools.yang.data.codec.gson.retest.TestUtils.childPrimitive;
+import static org.opendaylight.yangtools.yang.data.codec.gson.retest.TestUtils.loadModules;
+import static org.opendaylight.yangtools.yang.data.codec.gson.retest.TestUtils.resolveCont1;
+
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactory;
+import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+import com.google.common.collect.Sets;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonNull;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URISyntaxException;
+import java.util.HashSet;
+import java.util.Iterator;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+/**
+ * Each test tests whether json output obtained after transformation contains is corect. The transformation takes
+ * normalized node data structure and transform it to json output. To make it easier validate json output it is loaded
+ * via gson as structure of json elements which are walked and compared with awaited values.
+ *
+ */
+public class NormalizedNodeToJsonStreamTest {
+
+ private static final QName CONT_1 = QName.create("ns:complex:json", "2014-08-11", "cont1");
+ private static final QName EMPTY_LEAF = QName.create(CONT_1, "empty");
+ private static SchemaContext schemaContext;
+
+ public interface JsonValidator {
+ void validate(final String jsonOutput);
+ }
+
+ @BeforeClass
+ public static void initialization() throws IOException, URISyntaxException, ReactorException {
+ schemaContext = loadModules("/complexjson/yang");
+ }
+
+ /**
+ * case when anyxml contains simple value will be implemented when anyxml normalized node reprezentation will be
+ * specified
+ */
+ @Ignore
+ @Test
+ public void anyXmlNodeWithSimpleValueInContainer() throws IOException, URISyntaxException {
+
+ }
+
+ /**
+ * case when anyxml contains complex xml will be implemented when anyxml normalized node reprezentation will be
+ * specified
+ */
+ @Ignore
+ @Test
+ public void anyXmlNodeWithCompositeValueInContainer() throws IOException, URISyntaxException {
+
+ }
+
+ @Test
+ public void leafNodeInContainer() throws IOException, URISyntaxException {
+ final Writer writer = new StringWriter();
+ final NormalizedNode<?, ?> leafNodeInContainer = TestingNormalizedNodeStructuresCreator.leafNodeInContainer();
+ final String jsonOutput = normalizedNodeToJsonStreamTransformation(writer, leafNodeInContainer);
+ new JsonValidator() {
+
+ @Override
+ public void validate(final String jsonOutput) {
+ final JsonObject cont1 = resolveCont1(jsonOutput);
+ assertNotNull(cont1);
+
+ final JsonPrimitive lf11 = childPrimitive(cont1, "complexjson:lf11", "lf11");
+ assertNotNull(lf11);
+ final int asInt = lf11.getAsInt();
+ assertEquals(453, asInt);
+ }
+ }.validate(jsonOutput);
+
+ }
+
+ @Test
+ public void leafListNodeInContainerMultiline() throws IOException, URISyntaxException {
+ final Writer writer = new StringWriter();
+ final NormalizedNode<?, ?> leafListNodeInContainer = TestingNormalizedNodeStructuresCreator
+ .leafListNodeInContainerMultiline();
+ final String jsonOutput = normalizedNodeToJsonStreamTransformation(writer, leafListNodeInContainer);
+ new JsonValidator() {
+
+ @Override
+ public void validate(final String jsonOutput) {
+ final JsonObject cont1 = resolveCont1(jsonOutput);
+ assertNotNull(cont1);
+ final JsonArray lflst11 = childArray(cont1, "complexjson:lflst11", "lflst11");
+ assertNotNull(lflst11);
+
+ final HashSet<Object> lflst11Values = Sets.newHashSet();
+ for (final JsonElement jsonElement : lflst11) {
+ assertTrue(jsonElement instanceof JsonPrimitive);
+ lflst11Values.add(((JsonPrimitive) jsonElement).getAsString());
+ }
+
+ assertEquals(Sets.newHashSet("lflst11 value2\r\nanother line 2", "lflst11 value1\nanother line 1"),
+ lflst11Values);
+ }
+ }.validate(jsonOutput);
+
+ }
+
+ @Test
+ public void leafNodeViaAugmentationInContainer() throws IOException, URISyntaxException {
+ final Writer writer = new StringWriter();
+ final NormalizedNode<?, ?> leafNodeViaAugmentationInContainer = TestingNormalizedNodeStructuresCreator
+ .leafNodeViaAugmentationInContainer();
+ final String jsonOutput = normalizedNodeToJsonStreamTransformation(writer, leafNodeViaAugmentationInContainer);
+ new JsonValidator() {
+
+ @Override
+ public void validate(final String jsonOutput) {
+ final JsonObject cont1 = resolveCont1(jsonOutput);
+ assertNotNull(cont1);
+
+ final JsonPrimitive lf12_1 = childPrimitive(cont1, "complexjson:lf12_1", "lf12_1");
+ assertNotNull(lf12_1);
+ final String asString = lf12_1.getAsString();
+ assertEquals("lf12 value", asString);
+ }
+ }.validate(jsonOutput);
+
+ }
+
+ @Test
+ public void leafListNodeInContainer() throws IOException, URISyntaxException {
+ final Writer writer = new StringWriter();
+ final NormalizedNode<?, ?> leafListNodeInContainer = TestingNormalizedNodeStructuresCreator
+ .leafListNodeInContainer();
+ final String jsonOutput = normalizedNodeToJsonStreamTransformation(writer, leafListNodeInContainer);
+ new JsonValidator() {
+
+ @Override
+ public void validate(final String jsonOutput) {
+ final JsonObject cont1 = resolveCont1(jsonOutput);
+ assertNotNull(cont1);
+ final JsonArray lflst11 = childArray(cont1, "complexjson:lflst11", "lflst11");
+ assertNotNull(lflst11);
+
+ final HashSet<Object> lflst11Values = Sets.newHashSet();
+ for (final JsonElement jsonElement : lflst11) {
+ assertTrue(jsonElement instanceof JsonPrimitive);
+ lflst11Values.add(((JsonPrimitive) jsonElement).getAsString());
+ }
+
+ assertEquals(Sets.newHashSet("lflst11 value2", "lflst11 value1"), lflst11Values);
+ }
+ }.validate(jsonOutput);
+ }
+
+ @Test
+ public void keyedListNodeInContainer() throws IOException, URISyntaxException {
+ final Writer writer = new StringWriter();
+ final NormalizedNode<?, ?> keyedListNodeInContainer = TestingNormalizedNodeStructuresCreator
+ .keyedListNodeInContainer();
+ final String jsonOutput = normalizedNodeToJsonStreamTransformation(writer, keyedListNodeInContainer);
+ new JsonValidator() {
+
+ @Override
+ public void validate(final String jsonOutput) {
+ final JsonObject cont1 = resolveCont1(jsonOutput);
+ assertNotNull(cont1);
+ final JsonArray lst11 = childArray(cont1, "complexjson:lst11", "lst11");
+ assertNotNull(lst11);
+
+ final Iterator<JsonElement> iterator = lst11.iterator();
+ assertTrue(iterator.hasNext());
+ final JsonElement lst11Entry1Raw = iterator.next();
+ assertFalse(iterator.hasNext());
+ assertTrue(lst11Entry1Raw instanceof JsonObject);
+ final JsonObject lst11Entry1 = (JsonObject) lst11Entry1Raw;
+
+ final JsonPrimitive key111 = childPrimitive(lst11Entry1, "complexjson:key111", "key111");
+ assertNotNull(key111);
+ final JsonPrimitive lf112 = childPrimitive(lst11Entry1, "complexjson:lf112", "lf112");
+ assertNotNull(lf112);
+ final JsonPrimitive lf113 = childPrimitive(lst11Entry1, "complexjson:lf113", "lf113");
+ assertNotNull(lf113);
+ final JsonPrimitive lf111 = childPrimitive(lst11Entry1, "complexjson:lf111", "lf111");
+ assertNotNull(lf111);
+
+ assertEquals("key111 value", key111.getAsString());
+ assertEquals("/complexjson:cont1/complexjson:lflst11[.='foo']", lf112.getAsString());
+ assertEquals("lf113 value", lf113.getAsString());
+ assertEquals("lf111 value", lf111.getAsString());
+ }
+ }.validate(jsonOutput);
+ }
+
+ @Test
+ public void choiceNodeInContainer() throws IOException, URISyntaxException {
+ final Writer writer = new StringWriter();
+ final NormalizedNode<?, ?> choiceNodeInContainer = TestingNormalizedNodeStructuresCreator
+ .choiceNodeInContainer();
+ final String jsonOutput = normalizedNodeToJsonStreamTransformation(writer, choiceNodeInContainer);
+ new JsonValidator() {
+
+ @Override
+ public void validate(final String jsonOutput) {
+ final JsonObject cont1 = resolveCont1(jsonOutput);
+ assertNotNull(cont1);
+ final JsonPrimitive lf13 = childPrimitive(cont1, "complexjson:lf13", "lf13");
+ assertNotNull(lf13);
+
+ assertEquals("lf13 value", lf13.getAsString());
+ }
+ }.validate(jsonOutput);
+ }
+
+ /**
+ * tested case when case c11A in choice choc11 is augmented (two leaves (augment A) and one leaf (augment B) are
+ * added)
+ *
+ * after running this test following exception is raised
+ *
+ * java.lang.IllegalArgumentException: Augmentation allowed only in DataNodeContainer
+ * [ChoiceNodeImpl[qname=(ns:complex:json?revision=2014-08-11)choc11]]
+ *
+ */
+ // @Ignore
+ @Test
+ public void caseNodeAugmentationInChoiceInContainer() throws IOException, URISyntaxException {
+ final Writer writer = new StringWriter();
+ final NormalizedNode<?, ?> caseNodeAugmentationInChoiceInContainer = TestingNormalizedNodeStructuresCreator
+ .caseNodeAugmentationInChoiceInContainer();
+ final String jsonOutput = normalizedNodeToJsonStreamTransformation(writer,
+ caseNodeAugmentationInChoiceInContainer);
+ new JsonValidator() {
+
+ @Override
+ public void validate(final String jsonOutput) {
+ final JsonObject cont1 = resolveCont1(jsonOutput);
+ assertNotNull(cont1);
+
+ final JsonPrimitive lf15_21 = childPrimitive(cont1, "complexjson:lf15_21", "lf15_21");
+ assertNotNull(lf15_21);
+ final JsonPrimitive lf13 = childPrimitive(cont1, "complexjson:lf13", "lf13");
+ assertNotNull(lf13);
+ final JsonPrimitive lf15_11 = childPrimitive(cont1, "complexjson:lf15_11", "lf15_11");
+ assertNotNull(lf15_11);
+ final JsonPrimitive lf15_12 = childPrimitive(cont1, "complexjson:lf15_12", "lf15_12");
+ assertNotNull(lf15_12);
+
+ assertEquals("lf15_21 value", lf15_21.getAsString());
+ assertEquals("lf13 value", lf13.getAsString());
+ assertTrue("one two".equals(lf15_11.getAsString()) || "two one".equals(lf15_11.getAsString()));
+ assertEquals("complexjson:lf11", lf15_12.getAsString());
+
+ }
+ }.validate(jsonOutput);
+ }
+
+ /**
+ * tested case when case c11A in choice choc11 is augmented (two leaves (augment A) internally and one two leaves
+ * with the same names externally (augment B) are added)
+ *
+ * after running this test following exception is raised
+ *
+ * java.lang.IllegalArgumentException: Augmentation allowed only in DataNodeContainer
+ * [ChoiceNodeImpl[qname=(ns:complex:json?revision=2014-08-11)choc11]]
+ *
+ */
+ // @Ignore
+ @Test
+ public void caseNodeExternalAugmentationInChoiceInContainer() throws IOException, URISyntaxException {
+ final Writer writer = new StringWriter();
+ final NormalizedNode<?, ?> caseNodeExternalAugmentationInChoiceInContainer = TestingNormalizedNodeStructuresCreator
+ .caseNodeExternalAugmentationInChoiceInContainer();
+ final String jsonOutput = normalizedNodeToJsonStreamTransformation(writer,
+ caseNodeExternalAugmentationInChoiceInContainer);
+ new JsonValidator() {
+
+ @Override
+ public void validate(final String jsonOutput) {
+ final JsonObject cont1 = resolveCont1(jsonOutput);
+ assertNotNull(cont1);
+
+ final JsonPrimitive lf15_11Augment = childPrimitive(cont1, "complexjson-augmentation:lf15_11");
+ assertNotNull(lf15_11Augment);
+ final JsonPrimitive lf15_12Augment = childPrimitive(cont1, "complexjson-augmentation:lf15_12");
+ assertNotNull(lf15_12Augment);
+ final JsonPrimitive lf13 = childPrimitive(cont1, "complexjson:lf13", "lf13");
+ assertNotNull(lf13);
+ final JsonPrimitive lf15_11 = childPrimitive(cont1, "complexjson:lf15_11", "lf15_11");
+ assertNotNull(lf15_11);
+ final JsonPrimitive lf15_12 = childPrimitive(cont1, "complexjson:lf15_12", "lf15_12");
+ assertNotNull(lf15_12);
+
+ assertEquals("lf15_11 value from augmentation", lf15_11Augment.getAsString());
+ assertEquals("lf15_12 value from augmentation", lf15_12Augment.getAsString());
+ assertEquals("lf13 value", lf13.getAsString());
+ assertTrue("one two".equals(lf15_11.getAsString()) || "two one".equals(lf15_11.getAsString()));
+ assertEquals("complexjson:lf11", lf15_12.getAsString());
+
+ }
+ }.validate(jsonOutput);
+ }
+
+ /**
+ * augmentation of choice - adding new case
+ *
+ * after running this test following exception is raised
+ *
+ * java.lang.IllegalArgumentException: Augmentation allowed only in DataNodeContainer
+ * [ChoiceNodeImpl[qname=(ns:complex:json?revision=2014-08-11)choc11]]
+ *
+ */
+ // @Ignore
+ @Test
+ public void choiceNodeAugmentationInContainer() throws IOException, URISyntaxException {
+ final Writer writer = new StringWriter();
+ final NormalizedNode<?, ?> choiceNodeAugmentationInContainer = TestingNormalizedNodeStructuresCreator
+ .choiceNodeAugmentationInContainer();
+ final String jsonOutput = normalizedNodeToJsonStreamTransformation(writer, choiceNodeAugmentationInContainer);
+ new JsonValidator() {
+
+ @Override
+ public void validate(final String jsonOutput) {
+ final JsonObject cont1 = resolveCont1(jsonOutput);
+ assertNotNull(cont1);
+
+ final JsonPrimitive lf17 = childPrimitive(cont1, "complexjson:lf17", "lf17");
+ assertNotNull(lf17);
+ assertEquals("lf17 value", lf17.getAsString());
+ }
+ }.validate(jsonOutput);
+ }
+
+ @Test
+ public void unkeyedNodeInContainer() throws IOException, URISyntaxException {
+ final Writer writer = new StringWriter();
+ final NormalizedNode<?, ?> unkeyedNodeInContainer = TestingNormalizedNodeStructuresCreator
+ .unkeyedNodeInContainer();
+ final String jsonOutput = normalizedNodeToJsonStreamTransformation(writer, unkeyedNodeInContainer);
+ new JsonValidator() {
+
+ @Override
+ public void validate(final String jsonOutput) {
+ final JsonObject cont1 = resolveCont1(jsonOutput);
+ assertNotNull(cont1);
+
+ final JsonArray lst12 = childArray(cont1, "complexjson:lst12", "lst12");
+ assertNotNull(lst12);
+
+ final Iterator<JsonElement> iterator = lst12.iterator();
+ assertTrue(iterator.hasNext());
+ final JsonElement lst12Entry1Raw = iterator.next();
+ assertFalse(iterator.hasNext());
+
+ assertTrue(lst12Entry1Raw instanceof JsonObject);
+ final JsonObject lst12Entry1 = (JsonObject) lst12Entry1Raw;
+ final JsonPrimitive lf121 = childPrimitive(lst12Entry1, "complexjson:lf121", "lf121");
+ assertNotNull(lf121);
+
+ assertEquals("lf121 value", lf121.getAsString());
+
+ }
+ }.validate(jsonOutput);
+
+ }
+
+ @Test
+ public void emptyTypeTest() throws IOException, URISyntaxException {
+ final StringWriter writer = new StringWriter();
+ final ContainerNode emptyStructure = Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(CONT_1))
+ .addChild(ImmutableNodes.leafNode(EMPTY_LEAF, null)).build();
+ final String jsonOutput = normalizedNodeToJsonStreamTransformation(writer, emptyStructure);
+ final JsonObject cont1 = resolveCont1(jsonOutput);
+ final JsonElement emptyObj = cont1.get("empty");
+ assertNotNull(emptyObj);
+ assertTrue(emptyObj instanceof JsonArray);
+ assertEquals(1, emptyObj.getAsJsonArray().size());
+ assertTrue(emptyObj.getAsJsonArray().get(0) instanceof JsonNull);
+ }
+
+ private String normalizedNodeToJsonStreamTransformation(final Writer writer,
+ final NormalizedNode<?, ?> inputStructure) throws IOException {
+
+ final NormalizedNodeStreamWriter jsonStream = JSONNormalizedNodeStreamWriter.
+ createExclusiveWriter(JSONCodecFactory.create(schemaContext), SchemaPath.ROOT, null,
+ JsonWriterFactory.createJsonWriter(writer, 2));
+ final NormalizedNodeWriter nodeWriter = NormalizedNodeWriter.forStreamWriter(jsonStream);
+ nodeWriter.write(inputStructure);
+
+ nodeWriter.close();
+ return writer.toString();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.codec.gson.retest;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
+
+public class RetestUtils {
+
+ private RetestUtils() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static SchemaContext parseYangSources(StatementStreamSource... sources)
+ throws SourceException, ReactorException {
+
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR
+ .newBuild();
+ reactor.addSources(sources);
+
+ return reactor.buildEffective();
+ }
+
+ public static SchemaContext parseYangSources(File... files) throws SourceException, ReactorException, FileNotFoundException {
+
+ StatementStreamSource[] sources = new StatementStreamSource[files.length];
+
+ for(int i = 0; i<files.length; i++) {
+ sources[i] = new YangStatementSourceImpl(new FileInputStream(files[i]));
+ }
+
+ return parseYangSources(sources);
+ }
+
+ public static SchemaContext parseYangSources(Collection<File> files) throws SourceException, ReactorException, FileNotFoundException {
+ return parseYangSources(files.toArray(new File[files.size()]));
+ }
+
+
+ public static SchemaContext parseYangStreams(List<InputStream> streams)
+ throws SourceException, ReactorException {
+
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR
+ .newBuild();
+ return reactor.buildEffective(streams);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.codec.gson.retest;
+
+import static org.opendaylight.yangtools.yang.data.codec.gson.retest.TestUtils.loadModules;
+import static org.opendaylight.yangtools.yang.data.codec.gson.retest.TestUtils.loadTextFile;
+
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactory;
+import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+import com.google.gson.stream.JsonReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.net.URISyntaxException;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.LoggingNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class StreamToNormalizedNodeTest {
+ private static final Logger LOG = LoggerFactory.getLogger(StreamToNormalizedNodeTest.class);
+ private static SchemaContext schemaContext;
+ private static String streamAsString;
+
+ @BeforeClass
+ public static void initialization() throws IOException, URISyntaxException, ReactorException {
+ schemaContext = loadModules("/complexjson/yang");
+ streamAsString = loadTextFile(new File(StreamToNormalizedNodeTest.class.getResource(
+ "/complexjson/complex-json.json").toURI()));
+ }
+
+ /**
+ * Demonstrates how to log events produced by a {@link JsonReader}.
+ *
+ * @throws IOException
+ */
+ @Test
+ public void ownStreamWriterImplementationDemonstration() throws IOException {
+ // GSON's JsonReader reading from the loaded string (our event source)
+ final JsonReader reader = new JsonReader(new StringReader(streamAsString));
+
+ // StreamWriter which outputs SLF4J events
+ final LoggingNormalizedNodeStreamWriter logWriter = new LoggingNormalizedNodeStreamWriter();
+
+ // JSON -> StreamWriter parser
+ try (final JsonParserStream jsonHandler = JsonParserStream.create(logWriter, schemaContext)) {
+ // Process multiple readers, flush()/close() as needed
+ jsonHandler.parse(reader);
+ }
+ }
+
+ /**
+ * Demonstrates how to create an immutable NormalizedNode tree from a {@link JsonReader} and
+ * then writes the data back into string representation.
+ *
+ * @throws IOException
+ */
+ @Ignore
+ @Test
+ public void immutableNormalizedNodeStreamWriterDemonstration() throws IOException {
+ /*
+ * This is the parsing part
+ */
+ // This is where we will output the nodes
+ NormalizedNodeResult result = new NormalizedNodeResult();
+
+ // StreamWriter which attaches NormalizedNode under parent
+ final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+
+ // JSON -> StreamWriter parser
+ try (JsonParserStream handler = JsonParserStream.create(streamWriter, schemaContext)) {
+ handler.parse(new JsonReader(new StringReader(streamAsString)));
+ }
+
+ // Finally build the node
+ final NormalizedNode<?, ?> parsedData = result.getResult();
+ LOG.debug("Parsed NormalizedNodes: {}", parsedData);
+
+ /*
+ * This is the serialization part.
+ */
+ // We want to write the first child out
+ final DataContainerChild<? extends PathArgument, ?> firstChild = (DataContainerChild<? extends PathArgument, ?>) parsedData;
+ LOG.debug("Serializing first child: {}", firstChild);
+
+ // String holder
+ final StringWriter writer = new StringWriter();
+
+ // StreamWriter which outputs JSON strings
+ // StreamWriter which outputs JSON strings
+ final NormalizedNodeStreamWriter jsonStream = JSONNormalizedNodeStreamWriter.
+ createExclusiveWriter(JSONCodecFactory.create(schemaContext), SchemaPath.ROOT, null,
+ JsonWriterFactory.createJsonWriter(writer, 2));
+
+ // NormalizedNode -> StreamWriter
+ final NormalizedNodeWriter nodeWriter = NormalizedNodeWriter.forStreamWriter(jsonStream);
+
+ // Write multiple NormalizedNodes fluently, flush()/close() as needed
+ nodeWriter.write(firstChild).close();
+
+ // Just to put it somewhere
+ LOG.debug("Serialized JSON: {}", writer.toString());
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.codec.gson.retest;
+
+import static org.junit.Assert.assertTrue;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class TestUtils {
+
+ private TestUtils() {
+ }
+
+ static SchemaContext loadModules(final String resourceDirectory) throws IOException, URISyntaxException,
+ ReactorException {
+ URI path = StreamToNormalizedNodeTest.class.getResource(resourceDirectory).toURI();
+ final File testDir = new File(path);
+ final String[] fileList = testDir.list();
+ final List<File> testFiles = new ArrayList<File>();
+ if (fileList == null) {
+ throw new FileNotFoundException(resourceDirectory);
+ }
+ for (String fileName : fileList) {
+ if (new File(testDir, fileName).isDirectory() == false) {
+ testFiles.add(new File(testDir, fileName));
+ }
+ }
+ return RetestUtils.parseYangSources(testFiles);
+ }
+
+ static String loadTextFile(final File file) throws IOException {
+ FileReader fileReader = new FileReader(file);
+ BufferedReader bufReader = new BufferedReader(fileReader);
+
+ String line = null;
+ StringBuilder result = new StringBuilder();
+ while ((line = bufReader.readLine()) != null) {
+ result.append(line);
+ }
+ bufReader.close();
+ return result.toString();
+ }
+
+ static String loadTextFile(final String relativePath) throws IOException, URISyntaxException {
+ return loadTextFile(new File(TestUtils.class.getResource(relativePath).toURI()));
+ }
+
+ static JsonObject childObject(final JsonObject jsonObject, final String... names) {
+ for (String name : names) {
+ JsonObject childJsonObject = jsonObject.getAsJsonObject(name);
+ if (childJsonObject != null) {
+ return childJsonObject;
+ }
+ }
+ return null;
+ }
+
+ static JsonPrimitive childPrimitive(final JsonObject jsonObject, final String... names) {
+ for (String name : names) {
+ JsonPrimitive childJsonPrimitive = jsonObject.getAsJsonPrimitive(name);
+ if (childJsonPrimitive != null) {
+ return childJsonPrimitive;
+ }
+ }
+ return null;
+ }
+
+ static JsonArray childArray(final JsonObject jsonObject, final String... names) {
+ for (String name : names) {
+ JsonArray childJsonArray = jsonObject.getAsJsonArray(name);
+ if (childJsonArray != null) {
+ return childJsonArray;
+ }
+ }
+ return null;
+ }
+
+ static JsonObject resolveCont1(String jsonOutput) {
+ JsonParser parser = new JsonParser();
+ JsonElement rootElement = parser.parse(jsonOutput);
+ assertTrue(rootElement.isJsonObject());
+ JsonObject rootObject = rootElement.getAsJsonObject();
+ JsonObject cont1 = childObject(rootObject, "complexjson:cont1", "cont1");
+ return cont1;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.codec.gson.retest;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
+
+public class TestingNormalizedNodeStructuresCreator {
+
+ static NormalizedNode<?, ?> cont1Node(
+ DataContainerChild<? extends PathArgument, ?>... children) {
+ DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> cont1 = Builders.containerBuilder();
+ cont1.withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "cont1")));
+
+ cont1.withValue(Lists.newArrayList(children));
+ return cont1.build();
+ }
+
+ private static DataContainerChild<? extends PathArgument, ?> lst12Node() {
+ CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> lst12Builder = Builders.unkeyedListBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lst12")));
+ lst12Builder.withChild(lst12Entry1Node());
+ return lst12Builder.build();
+ }
+
+ private static UnkeyedListEntryNode lst12Entry1Node() {
+ DataContainerNodeAttrBuilder<NodeIdentifier, UnkeyedListEntryNode> lst12Entry1Builder = Builders
+ .unkeyedListEntryBuilder();
+ lst12Entry1Builder
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lst12")));
+ lst12Entry1Builder.withChild(Builders.leafBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lf121")))
+ .withValue("lf121 value").build());
+ return lst12Entry1Builder.build();
+ }
+
+ private static DataContainerChild<? extends PathArgument, ?> choc12Node() {
+ DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> choc12Builder = Builders.choiceBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "choc12")));
+
+ choc12Builder.withChild(lf17Node());
+ return choc12Builder.build();
+ }
+
+ protected static LeafNode<Object> lf17Node() {
+ return Builders.leafBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lf17")))
+ .withValue("lf17 value").build();
+ }
+
+ private static DataContainerChild<? extends PathArgument, ?> externalAugmentC11AWithLf15_11AndLf15_12Node() {
+ DataContainerNodeBuilder<AugmentationIdentifier, AugmentationNode> augmentationBuilder = Builders
+ .augmentationBuilder();
+ augmentationBuilder.withNodeIdentifier(new AugmentationIdentifier(Sets.newHashSet(
+ QName.create("ns:complex:json:augmentation", "2014-08-14", "lf15_11"),
+ QName.create("ns:complex:json:augmentation", "2014-08-14", "lf15_12"))));
+ augmentationBuilder.withChild(lf15_11NodeExternal());
+ augmentationBuilder.withChild(lf15_12NodeExternal());
+ return augmentationBuilder.build();
+ }
+
+ private static LeafNode<Object> lf15_12NodeExternal() {
+ return Builders
+ .leafBuilder()
+ .withNodeIdentifier(
+ new NodeIdentifier(QName.create("ns:complex:json:augmentation", "2014-08-14", "lf15_12")))
+ .withValue("lf15_12 value from augmentation").build();
+ }
+
+ private static LeafNode<Object> lf15_11NodeExternal() {
+ return Builders
+ .leafBuilder()
+ .withNodeIdentifier(
+ new NodeIdentifier(QName.create("ns:complex:json:augmentation", "2014-08-14", "lf15_11")))
+ .withValue("lf15_11 value from augmentation").build();
+ }
+
+ private static DataContainerChild<? extends PathArgument, ?> choc11Node(
+ DataContainerChild<? extends PathArgument, ?>... children) {
+ DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> choc11Builder = Builders.choiceBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "choc11")));
+ choc11Builder.withValue(Lists.newArrayList(children));
+ // choc11Builder.addChild(lf13Node());
+ // choc11Builder.addChild(augmentChoc11_c11A_lf1511AndLf1512Children());
+ // choc11Builder.addChild(augmentChoc11_c11_lf1521Children());
+ return choc11Builder.build();
+ }
+
+ private static LeafNode<Object> lf13Node() {
+ return Builders.leafBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lf13")))
+ .withValue("lf13 value").build();
+ }
+
+ private static DataContainerChild<? extends PathArgument, ?> augmentC11AWithLf15_21Node() {
+ DataContainerNodeBuilder<AugmentationIdentifier, AugmentationNode> choc11_c11AugmentBuilder = Builders
+ .augmentationBuilder();
+ choc11_c11AugmentBuilder.withNodeIdentifier(new AugmentationIdentifier(Sets.newHashSet(QName.create(
+ "ns:complex:json", "2014-08-11", "lf15_21"))));
+
+ choc11_c11AugmentBuilder.withChild(lf15_21Node());
+ return choc11_c11AugmentBuilder.build();
+ }
+
+ private static LeafNode<Object> lf15_21Node() {
+ return Builders.leafBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lf15_21")))
+ .withValue("lf15_21 value").build();
+ }
+
+ private static DataContainerChild<? extends PathArgument, ?> augmentC11AWithLf15_11AndLf15_12Node() {
+ DataContainerNodeBuilder<AugmentationIdentifier, AugmentationNode> choc11_c11AugmentBuilder = Builders
+ .augmentationBuilder();
+ choc11_c11AugmentBuilder.withNodeIdentifier(new AugmentationIdentifier(Sets.newHashSet(
+ QName.create("ns:complex:json", "2014-08-11", "lf15_11"),
+ QName.create("ns:complex:json", "2014-08-11", "lf15_12"))));
+ choc11_c11AugmentBuilder.withChild(lf15_11Node());
+ choc11_c11AugmentBuilder.withChild(lf15_12Node());
+ return choc11_c11AugmentBuilder.build();
+ }
+
+ private static LeafNode<Object> lf15_12Node() {
+ return Builders.leafBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lf15_12")))
+ .withValue(QName.create("ns:complex:json", "2014-08-11", "lf11")).build();
+ }
+
+ private static LeafNode<Object> lf15_11Node() {
+ return Builders.leafBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lf15_11")))
+ .withValue(Sets.newHashSet("one", "two")).build();
+ }
+
+ private static DataContainerChild<? extends PathArgument, ?> lf12_1Node() {
+ DataContainerNodeBuilder<AugmentationIdentifier, AugmentationNode> augmentBuilder = Builders
+ .augmentationBuilder().withNodeIdentifier(
+ new AugmentationIdentifier(Sets.newHashSet(
+ QName.create("ns:complex:json", "2014-08-11", "lf12_1"),
+ QName.create("ns:complex:json", "2014-08-11", "lf12_2"))));
+ augmentBuilder.withChild(Builders.leafBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lf12_1")))
+ .withValue("lf12 value").build());
+ return augmentBuilder.build();
+ }
+
+ private static DataContainerChild<? extends PathArgument, ?> childLst11() {
+ CollectionNodeBuilder<MapEntryNode, MapNode> lst11 = Builders.mapBuilder().withNodeIdentifier(
+ new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lst11")));
+
+ DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> lst11Entry1Builder = Builders
+ .mapEntryBuilder();
+
+ Map<QName, Object> key = new HashMap<>();
+ key.put(QName.create("ns:complex:json", "2014-08-11", "key111"), "key111 value");
+ key.put(QName.create("ns:complex:json", "2014-08-11", "lf111"), "lf111 value");
+
+ lst11Entry1Builder.withNodeIdentifier(new NodeIdentifierWithPredicates(QName.create("ns:complex:json",
+ "2014-08-11", "lst11"), key));
+ lst11Entry1Builder.withChild(Builders.leafBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "key111")))
+ .withValue("key111 value").build());
+ lst11Entry1Builder.withChild(Builders.leafBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lf112")))
+ .withValue(lf112Value()).build());
+ lst11Entry1Builder.withChild(Builders.leafBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lf113")))
+ .withValue("lf113 value").build());
+ lst11Entry1Builder.withChild(Builders.leafBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lf111")))
+ .withValue("lf111 value").build());
+ lst11.withChild(lst11Entry1Builder.build());
+ return lst11.build();
+ }
+
+ private static Object lf112Value() {
+ return YangInstanceIdentifier.create(
+ new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "cont1")),
+ new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lflst11")),
+ new NodeWithValue(QName.create("ns:complex:json", "2014-08-11", "lflst11"),"foo")
+ );
+ }
+
+ private static DataContainerChild<? extends PathArgument, ?> childLflst11() {
+ ListNodeBuilder<Object, LeafSetEntryNode<Object>> lflst11 = Builders.leafSetBuilder().withNodeIdentifier(
+ new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lflst11")));
+ lflst11.withChild(Builders
+ .leafSetEntryBuilder()
+ .withNodeIdentifier(
+ new NodeWithValue(QName.create("ns:complex:json", "2014-08-11", "lflst11"), "lflst11 value1"))
+ .withValue("lflst11 value1").build());
+ lflst11.withChild(Builders
+ .leafSetEntryBuilder()
+ .withNodeIdentifier(
+ new NodeWithValue(QName.create("ns:complex:json", "2014-08-11", "lflst11"), "lflst11 value2"))
+ .withValue("lflst11 value2").build());
+ return lflst11.build();
+ }
+
+ private static DataContainerChild<? extends PathArgument, ?> childLflst11Multiline() {
+ ListNodeBuilder<Object, LeafSetEntryNode<Object>> lflst11 = Builders.leafSetBuilder().withNodeIdentifier(
+ new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lflst11")));
+ lflst11.withChild(Builders
+ .leafSetEntryBuilder()
+ .withNodeIdentifier(
+ new NodeWithValue(QName.create("ns:complex:json", "2014-08-11", "lflst11"), "lflst11 value1\nanother line 1"))
+ .withValue("lflst11 value1\nanother line 1").build());
+ lflst11.withChild(Builders
+ .leafSetEntryBuilder()
+ .withNodeIdentifier(
+ new NodeWithValue(QName.create("ns:complex:json", "2014-08-11", "lflst11"), "lflst11 value2\r\nanother line 2"))
+ .withValue("lflst11 value2\r\nanother line 2").build());
+ return lflst11.build();
+ }
+
+ public static NormalizedNode<?, ?> leafNodeInContainer() {
+ LeafNode<Object> lf11 = Builders.leafBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lf11")))
+ .withValue(453).build();
+ return cont1Node(lf11);
+ }
+
+ public static NormalizedNode<?, ?> leafListNodeInContainer() {
+ return cont1Node(childLflst11());
+ }
+ public static NormalizedNode<?, ?> leafListNodeInContainerMultiline() {
+ return cont1Node(childLflst11Multiline());
+ }
+
+ public static NormalizedNode<?, ?> keyedListNodeInContainer() {
+ return cont1Node(childLst11());
+ }
+
+ public static NormalizedNode<?, ?> leafNodeViaAugmentationInContainer() {
+ return cont1Node(lf12_1Node());
+ }
+
+ public static NormalizedNode<?, ?> choiceNodeInContainer() {
+ return cont1Node(choc11Node(lf13Node()));
+ }
+
+ /**
+ * choc11 contains lf13, lf15_11 and lf15_12 are added via external augmentation
+ *
+ * @return
+ */
+ public static NormalizedNode<?, ?> caseNodeAugmentationInChoiceInContainer() {
+ return cont1Node(choc11Node(augmentC11AWithLf15_11AndLf15_12Node(), lf13Node(), augmentC11AWithLf15_21Node()));
+ }
+
+ public static NormalizedNode<?, ?> caseNodeExternalAugmentationInChoiceInContainer() {
+ return cont1Node(choc11Node(lf13Node(), augmentC11AWithLf15_11AndLf15_12Node(), externalAugmentC11AWithLf15_11AndLf15_12Node()));
+ }
+
+ public static NormalizedNode<?, ?> choiceNodeAugmentationInContainer() {
+ return cont1Node(choc12Node());
+ }
+
+ public static NormalizedNode<?, ?> unkeyedNodeInContainer() {
+ return cont1Node(lst12Node());
+ }
+
+ public static NormalizedNode<?, ?> topLevelContainer() {
+ return cont1Node();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.codec.xml.retest;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+
+import java.net.URI;
+import java.util.Map;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+
+class RandomPrefix {
+ // 32 characters, carefully chosen
+ private static final String LOOKUP = "abcdefghiknoprstABCDEFGHIKNOPRST";
+ private static final int MASK = 0x1f;
+ private static final int SHIFT = 5;
+
+ private int counter = 0;
+
+ // BiMap to make values lookup faster
+ private final BiMap<URI, String> prefixes = HashBiMap.create();
+ private final NamespaceContext context;
+
+ RandomPrefix() {
+ this.context = null;
+ }
+
+ RandomPrefix(final NamespaceContext context) {
+ this.context = Preconditions.checkNotNull(context);
+ }
+
+ Iterable<Map.Entry<URI, String>> getPrefixes() {
+ return prefixes.entrySet();
+ }
+
+ String encodePrefix(final URI namespace) {
+ String prefix = prefixes.get(namespace);
+ if (prefix != null) {
+ return prefix;
+ }
+
+ do {
+ prefix = encode(counter);
+ counter++;
+ } while (alreadyUsedPrefix(prefix));
+
+ prefixes.put(namespace, prefix);
+ return prefix;
+ }
+
+ private boolean alreadyUsedPrefix(final String prefix) {
+ if (context == null) {
+ return false;
+ }
+
+ final String str = context.getNamespaceURI(prefix);
+ return !XMLConstants.NULL_NS_URI.equals(str);
+ }
+
+ @VisibleForTesting
+ static int decode(final String str) {
+ int ret = 0;
+ for (char c : str.toCharArray()) {
+ int idx = LOOKUP.indexOf(c);
+ Preconditions.checkArgument(idx != -1, "Invalid string %s", str);
+ ret = (ret << SHIFT) + idx;
+ }
+
+ return ret;
+ }
+
+ @VisibleForTesting
+ static String encode(int num) {
+ final StringBuilder sb = new StringBuilder();
+
+ do {
+ sb.append(LOOKUP.charAt(num & MASK));
+ num >>>= SHIFT;
+ } while (num != 0);
+
+ return sb.reverse().toString();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.codec.xml.retest;
+
+import java.net.URI;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.util.AbstractStringInstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+final class RandomPrefixInstanceIdentifierSerializer extends AbstractStringInstanceIdentifierCodec {
+ private final RandomPrefix prefixes = new RandomPrefix();
+ private final DataSchemaContextTree schemaTree;
+
+
+ RandomPrefixInstanceIdentifierSerializer(SchemaContext ctx) {
+ schemaTree = DataSchemaContextTree.from(ctx);
+ }
+
+ Iterable<Map.Entry<URI, String>> getPrefixes() {
+ return prefixes.getPrefixes();
+ }
+
+ @Override
+ protected String prefixForNamespace(final URI namespace) {
+ return prefixes.encodePrefix(namespace);
+ }
+
+ @Override
+ protected QName createQName(final String prefix, final String localName) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ @Override
+ protected DataSchemaContextTree getDataContextTree() {
+ return schemaTree;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.codec.xml.retest;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import java.net.URI;
+import java.util.Map.Entry;
+import javax.annotation.Nonnull;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class for bridging JAXP Stream and YANG Data APIs. Note that the definition of this class by no means final
+ * and subject to change as more functionality is centralized here.
+ */
+@Beta
+public class XmlStreamUtils {
+ private static final Logger LOG = LoggerFactory.getLogger(XmlStreamUtils.class);
+ private final XmlCodecProvider codecProvider;
+ private final Optional<SchemaContext> schemaContext;
+
+ protected XmlStreamUtils(final XmlCodecProvider codecProvider) {
+ this(codecProvider, null);
+ }
+
+ private XmlStreamUtils(final XmlCodecProvider codecProvider, final SchemaContext schemaContext) {
+ this.codecProvider = Preconditions.checkNotNull(codecProvider);
+ this.schemaContext = Optional.fromNullable(schemaContext);
+ }
+
+ /**
+ * Create a new instance encapsulating a particular codec provider.
+ *
+ * @param codecProvider
+ * XML codec provider
+ * @return A new instance
+ */
+ public static XmlStreamUtils create(final XmlCodecProvider codecProvider) {
+ return new XmlStreamUtils(codecProvider);
+ }
+
+ /**
+ * Write an InstanceIdentifier into the output stream. Calling corresponding
+ * {@link XMLStreamWriter#writeStartElement(String)} and {@link XMLStreamWriter#writeEndElement()} is the
+ * responsibility of the caller.
+ *
+ * @param writer
+ * XML Stream writer
+ * @param id
+ * InstanceIdentifier
+ * @throws XMLStreamException
+ *
+ * @deprecated Use {@link #writeInstanceIdentifier(XMLStreamWriter, YangInstanceIdentifier)} instead.
+ */
+ @Deprecated
+ public static void write(@Nonnull final XMLStreamWriter writer, @Nonnull final YangInstanceIdentifier id)
+ throws XMLStreamException {
+ Preconditions.checkNotNull(writer, "Writer may not be null");
+ Preconditions.checkNotNull(id, "Variable should contain instance of instance identifier and can't be null");
+
+ final RandomPrefix prefixes = new RandomPrefix();
+ final String str = XmlUtils.encodeIdentifier(prefixes, id);
+ writeNamespaceDeclarations(writer, prefixes.getPrefixes());
+ writer.writeCharacters(str);
+ }
+
+ @VisibleForTesting
+ static void writeAttribute(final XMLStreamWriter writer, final Entry<QName, String> attribute,
+ final RandomPrefix randomPrefix) throws XMLStreamException {
+ final QName key = attribute.getKey();
+ final String prefix = randomPrefix.encodePrefix(key.getNamespace());
+ writer.writeAttribute("xmlns:" + prefix, key.getNamespace().toString());
+ writer.writeAttribute(prefix, key.getNamespace().toString(), key.getLocalName(), attribute.getValue());
+ }
+
+ /**
+ * Write a value into a XML stream writer. This method assumes the start and end of element is emitted by the
+ * caller.
+ *
+ * @param writer
+ * XML Stream writer
+ * @param schemaNode
+ * Schema node that describes the value
+ * @param value
+ * data value
+ * @param parent
+ * optional parameter of a module QName owning the leaf definition
+ * @throws XMLStreamException
+ * if an encoding problem occurs
+ */
+ public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final SchemaNode schemaNode,
+ final Object value, final Optional<QNameModule> parent) throws XMLStreamException {
+ if (value == null) {
+ LOG.debug("Value of {}:{} is null, not encoding it", schemaNode.getQName().getNamespace(), schemaNode
+ .getQName().getLocalName());
+ return;
+ }
+
+ Preconditions
+ .checkArgument(
+ schemaNode instanceof LeafSchemaNode || schemaNode instanceof LeafListSchemaNode,
+ "Unable to write value for node %s, only nodes of type: leaf and leaf-list can be written at this point",
+ schemaNode.getQName());
+
+ TypeDefinition<?> type = schemaNode instanceof LeafSchemaNode ? ((LeafSchemaNode) schemaNode).getType()
+ : ((LeafListSchemaNode) schemaNode).getType();
+
+ TypeDefinition<?> baseType = XmlUtils.resolveBaseTypeFrom(type);
+
+ if (schemaContext.isPresent() && baseType instanceof LeafrefTypeDefinition) {
+ LeafrefTypeDefinition leafrefTypeDefinition = (LeafrefTypeDefinition) baseType;
+ baseType = SchemaContextUtil.getBaseTypeForLeafRef(leafrefTypeDefinition, schemaContext.get(), schemaNode);
+ }
+
+ writeValue(writer, baseType, value, parent);
+ }
+
+ public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final SchemaNode schemaNode,
+ final Object value) throws XMLStreamException {
+ writeValue(writer, schemaNode, value, Optional.<QNameModule> absent());
+ }
+
+ public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final SchemaNode schemaNode,
+ final Object value, final QNameModule parent) throws XMLStreamException {
+ writeValue(writer, schemaNode, value, Optional.of(parent));
+ }
+
+ /**
+ * Write a value into a XML stream writer. This method assumes the start and end of element is emitted by the
+ * caller.
+ *
+ * @param writer
+ * XML Stream writer
+ * @param type
+ * data type. In case of leaf ref this should be the type of leaf being referenced
+ * @param value
+ * data value
+ * @param parent
+ * optional parameter of a module QName owning the leaf definition
+ * @throws XMLStreamException
+ * if an encoding problem occurs
+ */
+ public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final TypeDefinition<?> type,
+ final Object value, final Optional<QNameModule> parent) throws XMLStreamException {
+ if (value == null) {
+ LOG.debug("Value of {}:{} is null, not encoding it", type.getQName().getNamespace(), type.getQName()
+ .getLocalName());
+ return;
+ }
+ TypeDefinition<?> baseType = XmlUtils.resolveBaseTypeFrom(type);
+
+ if (baseType instanceof IdentityrefTypeDefinition) {
+ if (parent.isPresent()) {
+ write(writer, (IdentityrefTypeDefinition) baseType, value, parent);
+ } else {
+ write(writer, (IdentityrefTypeDefinition) baseType, value, Optional.<QNameModule> absent());
+ }
+ } else if (baseType instanceof InstanceIdentifierTypeDefinition) {
+ write(writer, (InstanceIdentifierTypeDefinition) baseType, value);
+ } else {
+ final TypeDefinitionAwareCodec<Object, ?> codec = codecProvider.codecFor(type);
+ String text;
+ if (codec != null) {
+ try {
+ text = codec.serialize(value);
+ } catch (ClassCastException e) {
+ LOG.error("Provided node value {} did not have type {} required by mapping. Using stream instead.",
+ value, type, e);
+ text = String.valueOf(value);
+ }
+ } else {
+ LOG.error("Failed to find codec for {}, falling back to using stream", type);
+ text = String.valueOf(value);
+ }
+ writer.writeCharacters(text);
+ }
+ }
+
+ public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final TypeDefinition<?> type,
+ final Object value, final QNameModule parent) throws XMLStreamException {
+ writeValue(writer, type, value, Optional.of(parent));
+ }
+
+ public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final TypeDefinition<?> type,
+ final Object value) throws XMLStreamException {
+ writeValue(writer, type, value, Optional.<QNameModule> absent());
+ }
+
+ @VisibleForTesting
+ static void write(@Nonnull final XMLStreamWriter writer, @Nonnull final IdentityrefTypeDefinition type,
+ @Nonnull final Object value, final Optional<QNameModule> parent) throws XMLStreamException {
+ if (value instanceof QName) {
+ final QName qname = (QName) value;
+ final String prefix = "x";
+
+ // in case parent is present and same as element namespace write value without namespace
+ if (parent.isPresent() && qname.getNamespace().equals(parent.get().getNamespace())) {
+ writer.writeCharacters(qname.getLocalName());
+ } else {
+ final String ns = qname.getNamespace().toString();
+ writer.writeNamespace(prefix, ns);
+ writer.writeCharacters(prefix + ':' + qname.getLocalName());
+ }
+
+ } else {
+ LOG.debug("Value of {}:{} is not a QName but {}", type.getQName().getNamespace(), type.getQName()
+ .getLocalName(), value.getClass());
+ writer.writeCharacters(String.valueOf(value));
+ }
+ }
+
+ private void write(@Nonnull final XMLStreamWriter writer, @Nonnull final InstanceIdentifierTypeDefinition type,
+ @Nonnull final Object value) throws XMLStreamException {
+ if (value instanceof YangInstanceIdentifier) {
+ writeInstanceIdentifier(writer, (YangInstanceIdentifier) value);
+ } else {
+ LOG.warn("Value of {}:{} is not an InstanceIdentifier but {}", type.getQName().getNamespace(), type
+ .getQName().getLocalName(), value.getClass());
+ writer.writeCharacters(String.valueOf(value));
+ }
+ }
+
+ public void writeInstanceIdentifier(XMLStreamWriter writer, YangInstanceIdentifier value) throws XMLStreamException {
+ if (schemaContext.isPresent()) {
+ RandomPrefixInstanceIdentifierSerializer iiCodec = new RandomPrefixInstanceIdentifierSerializer(
+ schemaContext.get());
+ String serializedValue = iiCodec.serialize(value);
+ writeNamespaceDeclarations(writer, iiCodec.getPrefixes());
+ writer.writeCharacters(serializedValue);
+ } else {
+ LOG.warn("Schema context not present in {}, serializing {} without schema.", this, value);
+ write(writer, value);
+ }
+ }
+
+ private static void writeNamespaceDeclarations(XMLStreamWriter writer, Iterable<Entry<URI, String>> prefixes)
+ throws XMLStreamException {
+ for (Entry<URI, String> e : prefixes) {
+ final String ns = e.getKey().toString();
+ final String p = e.getValue();
+ writer.writeNamespace(p, ns);
+ }
+ }
+
+ public static XmlStreamUtils create(final XmlCodecProvider codecProvider, final SchemaContext schemaContext) {
+ return new XmlStreamUtils(codecProvider, schemaContext);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.codec.xml.retest;
+
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+
+/**
+ * Common XML-related utility methods, which are not specific to a particular JAXP API.
+ */
+public final class XmlUtils {
+ public static final XmlCodecProvider DEFAULT_XML_CODEC_PROVIDER = new XmlCodecProvider() {
+ @Override
+ public TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> codecFor(final TypeDefinition<?> baseType) {
+ return TypeDefinitionAwareCodec.from(baseType);
+ }
+ };
+
+ private XmlUtils() {
+ }
+
+ public static TypeDefinition<?> resolveBaseTypeFrom(final @Nonnull TypeDefinition<?> type) {
+ TypeDefinition<?> superType = type;
+ while (superType.getBaseType() != null) {
+ superType = superType.getBaseType();
+ }
+ return superType;
+ }
+
+ /**
+ *
+ * @deprecated Use {@link RandomPrefixInstanceIdentifierSerializer} instead.
+ */
+ @Deprecated
+ static String encodeIdentifier(final RandomPrefix prefixes, final YangInstanceIdentifier id) {
+ StringBuilder textContent = new StringBuilder();
+ for (PathArgument pathArgument : id.getPathArguments()) {
+ textContent.append('/');
+
+ final QName nt = pathArgument.getNodeType();
+ textContent.append(prefixes.encodePrefix(nt.getNamespace()));
+ textContent.append(':');
+ textContent.append(nt.getLocalName());
+
+ if (pathArgument instanceof NodeIdentifierWithPredicates) {
+ Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArgument).getKeyValues();
+
+ for (Map.Entry<QName, Object> entry : predicates.entrySet()) {
+ final QName key = entry.getKey();
+ textContent.append('[');
+ textContent.append(prefixes.encodePrefix(key.getNamespace()));
+ textContent.append(':');
+ textContent.append(key.getLocalName());
+ textContent.append("='");
+ textContent.append(String.valueOf(entry.getValue()));
+ textContent.append("']");
+ }
+ } else if (pathArgument instanceof NodeWithValue) {
+ textContent.append("[.='");
+ textContent.append(((NodeWithValue) pathArgument).getValue());
+ textContent.append("']");
+ }
+ }
+
+ return textContent.toString();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
+
+public class RetestUtils {
+
+ private RetestUtils() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static SchemaContext parseYangSources(StatementStreamSource... sources) throws SourceException,
+ ReactorException {
+
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSources(sources);
+
+ return reactor.buildEffective();
+ }
+
+ public static SchemaContext parseYangSources(File... files) throws SourceException, ReactorException,
+ FileNotFoundException {
+
+ StatementStreamSource[] sources = new StatementStreamSource[files.length];
+
+ for (int i = 0; i < files.length; i++) {
+ sources[i] = new YangStatementSourceImpl(new FileInputStream(files[i]));
+ }
+
+ return parseYangSources(sources);
+ }
+
+ public static SchemaContext parseYangSources(Collection<File> files) throws SourceException, ReactorException,
+ FileNotFoundException {
+ return parseYangSources(files.toArray(new File[files.size()]));
+ }
+
+ public static SchemaContext parseYangStreams(List<InputStream> streams)
+ throws SourceException, ReactorException {
+
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR
+ .newBuild();
+ return reactor.buildEffective(streams);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.codec.xml.retest;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import com.google.common.base.Charsets;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+public class Bug2964Test {
+
+ public static final String XML_CONTENT = "<cont2 xmlns=\"urn:opendaylight:yangtools:leafref:test\">\n"
+ + "<point-to-identityrefleaf>test-identity</point-to-identityrefleaf>\n" + "</cont2>";
+
+ private static final DocumentBuilderFactory BUILDERFACTORY;
+
+ private static final String NAMESPACE = "urn:opendaylight:yangtools:leafref:test";
+ private static final String TEST_IDENTITY = "test-identity";
+ private static final String CONT_2 = "cont2";
+ private static final String IDENTITY_LEAFREF = "point-to-identityrefleaf";
+
+ static {
+ final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setCoalescing(true);
+ factory.setIgnoringElementContentWhitespace(true);
+ factory.setIgnoringComments(true);
+ BUILDERFACTORY = factory;
+ }
+
+ private SchemaContext schema;
+
+ @Before
+ public void setUp() throws Exception {
+ File leafRefTestYang = new File(getClass().getResource("/leafref-test.yang").toURI());
+ schema = RetestUtils.parseYangSources(leafRefTestYang);
+ }
+
+ public static Document readXmlToDocument(final String xmlContent) throws SAXException, IOException {
+ return readXmlToDocument(new ByteArrayInputStream(xmlContent.getBytes(Charsets.UTF_8)));
+ }
+
+ @Test
+ public void testLeafrefIdentityRefDeserialization() throws Exception {
+ final URI namespaceUri = new URI(NAMESPACE);
+
+ final Document document = readXmlToDocument(XML_CONTENT);
+ final Element identityLeafRefElement = (Element) document.getDocumentElement().getFirstChild().getNextSibling();
+
+ final Module leafrefModule = schema.findModuleByNamespaceAndRevision(namespaceUri, null);
+ final ContainerSchemaNode cont2 = (ContainerSchemaNode) leafrefModule.getDataChildByName(CONT_2);
+ final DataSchemaNode identityLeafRefSchema = cont2.getDataChildByName(IDENTITY_LEAFREF);
+ final Object parsedValue = DomUtils.parseXmlValue(identityLeafRefElement, DomUtils.defaultValueCodecProvider(),
+ identityLeafRefSchema, ((LeafSchemaNode) identityLeafRefSchema).getType(), schema);
+
+ assertThat(parsedValue, instanceOf(QName.class));
+ final QName parsedQName = (QName) parsedValue;
+ assertEquals(namespaceUri, parsedQName.getNamespace());
+ assertEquals(TEST_IDENTITY, parsedQName.getLocalName());
+ }
+
+ public static Document readXmlToDocument(final InputStream xmlContent) throws SAXException, IOException {
+ final DocumentBuilder dBuilder;
+ try {
+ dBuilder = BUILDERFACTORY.newDocumentBuilder();
+ } catch (final ParserConfigurationException e) {
+ throw new IllegalStateException("Failed to parse XML document", e);
+ }
+ final Document doc = dBuilder.parse(xmlContent);
+
+ doc.getDocumentElement().normalize();
+ return doc;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.codec.xml.retest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+
+public class RandomPrefixTest {
+ static final int MAX_COUNTER = 4000;
+
+ @Test
+ public void testEncodeDecode() throws Exception {
+
+ final List<String> allGenerated = Lists.newArrayList();
+ for (int i = 0; i < MAX_COUNTER; i++) {
+ final String encoded = RandomPrefix.encode(i);
+ assertEquals(RandomPrefix.decode(encoded), i);
+ allGenerated.add(encoded);
+ }
+
+ assertEquals(allGenerated.size(), MAX_COUNTER);
+ assertEquals("dPT", allGenerated.get(MAX_COUNTER - 1));
+ assertEquals("a", allGenerated.get(0));
+ assertEquals(allGenerated.size(), Sets.newHashSet(allGenerated).size());
+ }
+
+ @Test
+ public void testQNameWithPrefix() throws Exception {
+ final RandomPrefix a = new RandomPrefix();
+
+ final List<String> allGenerated = Lists.newArrayList();
+ for (int i = 0; i < MAX_COUNTER; i++) {
+ final String prefix = RandomPrefix.encode(i);
+ final URI uri = new URI("localhost:" + prefix);
+ final QName qName = QName.create(QNameModule.create(uri, new Date()), "local-name");
+ allGenerated.add(a.encodePrefix(qName.getNamespace()));
+ }
+
+ assertEquals(MAX_COUNTER, allGenerated.size());
+ // We are generating MAX_COUNTER_VALUE + 27 prefixes total, so we should encounter a reset in prefix a start
+ // from 0 at some point
+ // At the end, there should be only 27 values in RandomPrefix cache
+ assertEquals(MAX_COUNTER, Iterables.size(a.getPrefixes()));
+ assertThat(allGenerated, CoreMatchers.not(CoreMatchers.hasItem("xml")));
+ assertThat(allGenerated, CoreMatchers.not(CoreMatchers.hasItem("xmla")));
+ assertThat(allGenerated, CoreMatchers.not(CoreMatchers.hasItem("xmlz")));
+
+ assertEquals(1, Iterables.frequency(allGenerated, "a"));
+ }
+
+ @Test
+ public void test2QNames1Namespace() throws Exception {
+ final RandomPrefix a = new RandomPrefix();
+
+ final URI uri = URI.create("localhost");
+ final QName qName = QName.create(QNameModule.create(uri, new Date()), "local-name");
+ final QName qName2 = QName.create(QNameModule.create(uri, new Date()), "local-name");
+
+ assertEquals(a.encodePrefix(qName.getNamespace()), a.encodePrefix(qName2.getNamespace()));
+ }
+
+ @Test
+ public void testQNameNoPrefix() throws Exception {
+ final RandomPrefix a = new RandomPrefix();
+
+ final URI uri = URI.create("localhost");
+ QName qName = QName.create(uri, new Date(), "local-name");
+ assertEquals("a", a.encodePrefix(qName.getNamespace()));
+ qName = QName.create(QNameModule.create(uri, new Date()), "local-name");
+ assertEquals("a", a.encodePrefix(qName.getNamespace()));
+ qName = QName.create(QNameModule.create(URI.create("second"), new Date()), "local-name");
+ assertEquals("b", a.encodePrefix(qName.getNamespace()));
+
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.codec.xml.retest;
+
+import com.google.common.base.Charsets;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.junit.Before;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+public class XmlDocumentUtilsTest {
+
+ private static final DocumentBuilderFactory BUILDERFACTORY;
+
+ static {
+ final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setCoalescing(true);
+ factory.setIgnoringElementContentWhitespace(true);
+ factory.setIgnoringComments(true);
+ BUILDERFACTORY = factory;
+ }
+
+ public static final String XML_CONTENT = "<input xmlns=\"urn:opendaylight:controller:rpc:test\">\n"
+ + "<a>value</a>\n" + "<ref xmlns:ltha=\"urn:opendaylight:controller:rpc:test\">"
+ + "/ltha:cont/ltha:l[ ltha:id='id/foo/bar' ]" + "</ref>\n" + "</input>";
+
+ public static final String RPC_REPLY = "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"m-1\">\n"
+ + " <ok/>\n" + "</rpc-reply>";
+
+ private SchemaContext schema;
+ private RpcDefinition testRpc;
+
+ @Before
+ public void setUp() throws Exception {
+ File rpcTestYang = new File(getClass().getResource("/rpc-test.yang").toURI());
+ schema = RetestUtils.parseYangSources(rpcTestYang);
+ final Module rpcTestModule = schema.getModules().iterator().next();
+ testRpc = rpcTestModule.getRpcs().iterator().next();
+ }
+
+ public static Document readXmlToDocument(final String xmlContent) throws SAXException, IOException {
+ return readXmlToDocument(new ByteArrayInputStream(xmlContent.getBytes(Charsets.UTF_8)));
+ }
+
+ public static Document readXmlToDocument(final InputStream xmlContent) throws SAXException, IOException {
+ final DocumentBuilder dBuilder;
+ try {
+ dBuilder = BUILDERFACTORY.newDocumentBuilder();
+ } catch (final ParserConfigurationException e) {
+ throw new IllegalStateException("Failed to parse XML document", e);
+ }
+ final Document doc = dBuilder.parse(xmlContent);
+
+ doc.getDocumentElement().normalize();
+ return doc;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.codec.xml.retest;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import com.google.common.base.Optional;
+import com.google.common.collect.Maps;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.AbstractMap;
+import java.util.Date;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamWriter;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.opendaylight.yangtools.yang.model.util.StringType;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.w3c.dom.Document;
+
+public class XmlStreamUtilsTest {
+
+ public static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newFactory();
+
+ private static SchemaContext schemaContext;
+ private static Module leafRefModule;
+
+ @BeforeClass
+ public static void initialize() throws URISyntaxException, FileNotFoundException, ReactorException {
+ final File file = new File(XmlStreamUtils.class.getResource("/leafref-test.yang").toURI());
+ schemaContext = RetestUtils.parseYangSources(file);
+ assertNotNull(schemaContext);
+ assertEquals(1, schemaContext.getModules().size());
+ leafRefModule = schemaContext.getModules().iterator().next();
+ assertNotNull(leafRefModule);
+ }
+
+ @Test
+ public void testWriteAttribute() throws Exception {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final XMLStreamWriter writer = XML_OUTPUT_FACTORY.createXMLStreamWriter(out);
+ writer.writeStartElement("element");
+
+ QName name = getAttrQName("namespace", "2012-12-12", "attr", Optional.of("prefix"));
+ final Map.Entry<QName, String> attributeEntry = new AbstractMap.SimpleEntry<>(name, "value");
+
+ name = getAttrQName("namespace2", "2012-12-12", "attr", Optional.<String> absent());
+ final Map.Entry<QName, String> attributeEntryNoPrefix = new AbstractMap.SimpleEntry<>(name, "value");
+
+ final RandomPrefix randomPrefix = new RandomPrefix();
+ XmlStreamUtils.writeAttribute(writer, attributeEntry, randomPrefix);
+ XmlStreamUtils.writeAttribute(writer, attributeEntryNoPrefix, randomPrefix);
+
+ writer.writeEndElement();
+ writer.close();
+ out.close();
+
+ final String xmlAsString = new String(out.toByteArray());
+
+ final Map<String, String> mappedPrefixes = mapPrefixed(randomPrefix.getPrefixes());
+ assertEquals(2, mappedPrefixes.size());
+ final String randomPrefixValue = mappedPrefixes.get("namespace2");
+
+ final String expectedXmlAsString = "<element xmlns:a=\"namespace\" a:attr=\"value\" xmlns:" + randomPrefixValue
+ + "=\"namespace2\" " + randomPrefixValue + ":attr=\"value\"></element>";
+
+ XMLUnit.setIgnoreAttributeOrder(true);
+ final Document control = XMLUnit.buildControlDocument(expectedXmlAsString);
+ final Document test = XMLUnit.buildTestDocument(xmlAsString);
+ final Diff diff = XMLUnit.compareXML(control, test);
+
+ final boolean identical = diff.identical();
+ assertTrue("Xml differs: " + diff.toString(), identical);
+ }
+
+ @Test
+ public void testWriteIdentityRef() throws Exception {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final XMLStreamWriter writer = XML_OUTPUT_FACTORY.createXMLStreamWriter(out);
+
+ writer.writeStartElement("element");
+ final QNameModule parent = QNameModule.create(URI.create("parent:uri"), new Date());
+ XmlStreamUtils.write(writer, null, QName.create(parent, "identity"), Optional.of(parent));
+ writer.writeEndElement();
+
+ writer.writeStartElement("elementDifferent");
+ XmlStreamUtils.write(writer, null, QName.create("different:namespace", "identity"), Optional.of(parent));
+ writer.writeEndElement();
+
+ writer.close();
+ out.close();
+
+ final String xmlAsString = new String(out.toByteArray()).replaceAll("\\s*", "");
+ assertThat(xmlAsString, containsString("element>identity"));
+
+ final Pattern prefixedIdentityPattern = Pattern.compile(".*\"different:namespace\">(.*):identity.*");
+ final Matcher matcher = prefixedIdentityPattern.matcher(xmlAsString);
+ assertTrue("Xml: " + xmlAsString + " should match: " + prefixedIdentityPattern, matcher.matches());
+ }
+
+ /**
+ * One leafref reference to other leafref via relative references
+ */
+ @Test
+ public void testLeafRefRelativeChaining() {
+ getTargetNodeForLeafRef("leafname3", StringType.class);
+ }
+
+ @Test
+ public void testLeafRefRelative() {
+ getTargetNodeForLeafRef("pointToStringLeaf", StringType.class);
+ }
+
+ @Test
+ public void testLeafRefAbsoluteWithSameTarget() {
+ getTargetNodeForLeafRef("absname", InstanceIdentifierType.class);
+ }
+
+ /**
+ * Tests relative path with double point inside path (e. g. "../../lf:interface/../lf:cont2/lf:stringleaf")
+ */
+ @Ignore
+ // ignored because this isn't implemented
+ @Test
+ public void testLeafRefWithDoublePointInPath() {
+ getTargetNodeForLeafRef("lf-with-double-point-inside", StringType.class);
+ }
+
+ @Test
+ public void testLeafRefRelativeAndAbsoluteWithSameTarget() {
+ final TypeDefinition<?> targetNodeForAbsname = getTargetNodeForLeafRef("absname", InstanceIdentifierType.class);
+ final TypeDefinition<?> targetNodeForRelname = getTargetNodeForLeafRef("relname", InstanceIdentifierType.class);
+ assertEquals(targetNodeForAbsname, targetNodeForRelname);
+ }
+
+ private TypeDefinition<?> getTargetNodeForLeafRef(final String nodeName, final Class<?> clas) {
+ final LeafSchemaNode schemaNode = findSchemaNodeWithLeafrefType(leafRefModule, nodeName);
+ assertNotNull(schemaNode);
+ final LeafrefTypeDefinition leafrefTypedef = findLeafrefType(schemaNode);
+ assertNotNull(leafrefTypedef);
+ final TypeDefinition<?> targetBaseType = SchemaContextUtil.getBaseTypeForLeafRef(leafrefTypedef, schemaContext,
+ schemaNode);
+ assertEquals("Wrong class found.", clas, targetBaseType.getClass());
+ return targetBaseType;
+ }
+
+ private static Map<String, String> mapPrefixed(final Iterable<Map.Entry<URI, String>> prefixes) {
+ final Map<String, String> mappedPrefixes = Maps.newHashMap();
+ for (final Map.Entry<URI, String> prefix : prefixes) {
+ mappedPrefixes.put(prefix.getKey().toString(), prefix.getValue());
+ }
+ return mappedPrefixes;
+ }
+
+ private static QName getAttrQName(final String namespace, final String revision, final String localName,
+ final Optional<String> prefix) {
+ if (prefix.isPresent()) {
+ final QName moduleQName = QName.create(namespace, revision, "module");
+ final QNameModule module = QNameModule.create(moduleQName.getNamespace(), moduleQName.getRevision());
+ return QName.create(module, localName);
+ } else {
+ return QName.create(namespace, revision, localName);
+ }
+ }
+
+ private LeafSchemaNode findSchemaNodeWithLeafrefType(final DataNodeContainer module, final String nodeName) {
+ for (final DataSchemaNode childNode : module.getChildNodes()) {
+ if (childNode instanceof DataNodeContainer) {
+ LeafSchemaNode leafrefFromRecursion = findSchemaNodeWithLeafrefType((DataNodeContainer) childNode,
+ nodeName);
+ if (leafrefFromRecursion != null) {
+ return leafrefFromRecursion;
+ }
+ } else if (childNode.getQName().getLocalName().equals(nodeName) && childNode instanceof LeafSchemaNode) {
+ final TypeDefinition<?> leafSchemaNodeType = ((LeafSchemaNode) childNode).getType();
+ if (leafSchemaNodeType instanceof LeafrefTypeDefinition) {
+ return (LeafSchemaNode) childNode;
+ }
+ }
+ }
+ return null;
+ }
+
+ private static LeafrefTypeDefinition findLeafrefType(final LeafSchemaNode schemaNode) {
+ final TypeDefinition<?> type = schemaNode.getType();
+ if (type instanceof LeafrefTypeDefinition) {
+ return (LeafrefTypeDefinition) type;
+ }
+ return null;
+ }
+}
.takeSnapshot().newModification();
writeModification.write(devicesPath, devicesContainer);
+ writeModification.ready();
final DataTreeCandidate writeDevicesCandidate = inMemoryDataTree
.prepare(writeModification);
final YangInstanceIdentifier path2 = YangInstanceIdentifier.of(deviceTypeStr);
initialDataTreeModification.write(path2, deviceTypesContainer);
+ initialDataTreeModification.ready();
final DataTreeCandidate writeChipsCandidate = inMemoryDataTree
.prepare(initialDataTreeModification);
.takeSnapshot().newModification();
writeModification.write(devicesPath, devicesContainer);
+ writeModification.ready();
final DataTreeCandidate writeDevicesCandidate = inMemoryDataTree
.prepare(writeModification);
mergeModification.write(devicesPath, devicesContainer);
mergeModification.merge(devicesPath, devicesContainer);
+ mergeModification.ready();
final DataTreeCandidate mergeDevicesCandidate = inMemoryDataTree
.prepare(mergeModification);
final YangInstanceIdentifier path2 = YangInstanceIdentifier.of(deviceTypeStr);
initialDataTreeModification.write(path2, deviceTypesContainer);
+ initialDataTreeModification.ready();
final DataTreeCandidate writeChipsCandidate = inMemoryDataTree
.prepare(initialDataTreeModification);
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.leafref.context.test.retest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import org.apache.log4j.BasicConfigurator;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+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.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefDataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefValidatation;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataTreeCandidateValidatorTest {
+
+ private static SchemaContext context;
+ private static Module valModule;
+ private static QNameModule valModuleQname;
+ private static LeafRefContext rootLeafRefContext;
+ public static TipProducingDataTree inMemoryDataTree;
+
+ private static QName odl;
+ private static QName project;
+ private static QName name;
+ private static QName desc;
+ private static QName lead;
+ private static QName owner;
+ private static QName odlContributor;
+ private static QName contributor;
+ private static QName odlProjectName;
+ private static QName odlProjectDesc;
+ private static QName login;
+ private static QName contributorName;
+ private static QName l1;
+ private static QName l2;
+ private static QName con1;
+ private static QName ch1;
+ private static QName ch2;
+ private static QName leafrefInChoice;
+ private static QName listInChoice;
+
+ private static QName leafrefInChoiceToChoice;
+ private static QName con3;
+ private static QName list3InChoice;
+ private static QName l3;
+ private static QName choiceInCon3;
+
+ private static QName listInChoiceKey;
+ private static QName k;
+
+ private static QName leafrefLeafList;
+
+ private static final Logger LOG = LoggerFactory.getLogger("");
+ private static final String NEW_LINE = System.getProperty("line.separator");
+
+ static {
+ BasicConfigurator.configure();
+ }
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException,
+ URISyntaxException {
+ initSchemaContext();
+
+ initLeafRefContext();
+
+ initQnames();
+
+ initDataTree();
+
+ }
+
+ private static void initSchemaContext() throws URISyntaxException,
+ FileNotFoundException, ReactorException {
+ final File resourceFile = new File(DataTreeCandidateValidatorTest.class
+ .getResource("/leafref-validation/leafref-validation.yang")
+ .toURI());
+ final File resourceDir = resourceFile.getParentFile();
+
+ context = RetestUtils.parseYangSources(Arrays.asList(resourceDir
+ .listFiles()));
+
+ final Set<Module> modules = context.getModules();
+ for (final Module module : modules) {
+ if (module.getName().equals("leafref-validation")) {
+ valModule = module;
+ }
+ }
+
+ valModuleQname = valModule.getQNameModule();
+ }
+
+ private static void initLeafRefContext() {
+ rootLeafRefContext = LeafRefContext.create(context);
+ }
+
+ private static void initQnames() {
+ odl = QName.create(valModuleQname, "odl-project");
+ project = QName.create(valModuleQname, "project");
+ name = QName.create(valModuleQname, "name");
+ desc = QName.create(valModuleQname, "desc");
+ lead = QName.create(valModuleQname, "project-lead");
+ owner = QName.create(valModuleQname, "project-owner");
+
+ odlContributor = QName.create(valModuleQname, "odl-contributor");
+ contributor = QName.create(valModuleQname, "contributor");
+ odlProjectName = QName.create(valModuleQname, "odl-project-name");
+ login = QName.create(valModuleQname, "login");
+ contributorName = QName.create(valModuleQname, "contributor-name");
+
+ con1 = QName.create(valModuleQname, "con1");
+ l1 = QName.create(valModuleQname, "l1");
+ l2 = QName.create(valModuleQname, "l2");
+ odlProjectDesc = QName.create(valModuleQname, "odl-project-desc");
+
+ ch1 = QName.create(valModuleQname, "ch1");
+ ch2 = QName.create(valModuleQname, "ch2");
+ leafrefInChoice = QName.create(valModuleQname, "leafref-in-choice");
+ listInChoice = QName.create(valModuleQname, "list-in-choice");
+
+ leafrefInChoiceToChoice = QName.create(valModuleQname,
+ "leafref-in-choice-to-choice");
+ con3 = QName.create(valModuleQname, "con3");
+ list3InChoice = QName.create(valModuleQname, "list3-in-choice");
+ l3 = QName.create(valModuleQname, "l3");
+ choiceInCon3 = QName.create(valModuleQname, "choice-in-con3");
+
+ listInChoiceKey = QName.create(valModuleQname, "list-in-choice-key");
+ k = QName.create(valModuleQname, "k");
+
+ leafrefLeafList = QName.create(valModuleQname, "leafref-leaf-list");
+
+ }
+
+ private static void initDataTree() {
+ inMemoryDataTree = InMemoryDataTreeFactory.getInstance().create();
+ inMemoryDataTree.setSchemaContext(context);
+
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+
+ final ContainerSchemaNode odlProjContSchemaNode = (ContainerSchemaNode) valModule
+ .getDataChildByName(odl);
+
+ final ContainerNode odlProjectContainer = createOdlContainer(odlProjContSchemaNode);
+
+ final YangInstanceIdentifier path = YangInstanceIdentifier.of(odl);
+ initialDataTreeModification.write(path, odlProjectContainer);
+ initialDataTreeModification.ready();
+
+ final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+ .prepare(initialDataTreeModification);
+ inMemoryDataTree.commit(writeContributorsCandidate);
+
+ }
+
+ @Test
+ public void dataTreeCanditateValidationTest() {
+ write();
+
+ write2();
+
+ delete();
+
+ writeContributors();
+
+ writeMapEntry();
+
+ writeIntoMapEntry();
+ }
+
+ private static void writeContributors() {
+
+ final ContainerSchemaNode contributorContSchemaNode = (ContainerSchemaNode) valModule
+ .getDataChildByName(odlContributor);
+
+ final ContainerNode contributorContainer = createBasicContributorContainer(contributorContSchemaNode);
+
+ final YangInstanceIdentifier contributorPath = YangInstanceIdentifier
+ .of(odlContributor);
+ final DataTreeModification writeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+ writeModification.write(contributorPath, contributorContainer);
+ writeModification.ready();
+
+ final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+ .prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before write of contributors: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeContributorsCandidate,
+ rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(3, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ inMemoryDataTree.commit(writeContributorsCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After write of contributors: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ assertTrue(exception);
+
+ }
+
+ private static void writeIntoMapEntry() {
+
+ final Map<QName, Object> keys = new HashMap<QName, Object>();
+ keys.put(name, "New Project");
+ final NodeIdentifierWithPredicates mapEntryPath = new NodeIdentifierWithPredicates(
+ project, keys);
+
+ final YangInstanceIdentifier leaderPath = YangInstanceIdentifier
+ .of(odl).node(project).node(mapEntryPath).node(lead);
+
+ final LeafNode<String> leader = ImmutableNodes.leafNode(lead,
+ "Updated leader");
+
+ final DataTreeModification writeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+ writeModification.write(leaderPath, leader);
+ writeModification.ready();
+
+ final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+ .prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before write into map entry (update of leader name): ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeContributorsCandidate,
+ rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(1, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ inMemoryDataTree.commit(writeContributorsCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After write into map entry (update of leader name): ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ assertTrue(exception);
+
+ }
+
+ private static void writeMapEntry() {
+
+ final Map<QName, Object> keys = new HashMap<QName, Object>();
+ keys.put(name, "New Project");
+ final NodeIdentifierWithPredicates mapEntryPath = new NodeIdentifierWithPredicates(
+ project, keys);
+
+ final YangInstanceIdentifier newOdlProjectMapEntryPath = YangInstanceIdentifier
+ .of(odl).node(project).node(mapEntryPath);
+
+ final ContainerSchemaNode odlProjContSchemaNode = (ContainerSchemaNode) valModule
+ .getDataChildByName(odl);
+ final ListSchemaNode projListSchemaNode = (ListSchemaNode) odlProjContSchemaNode
+ .getDataChildByName(project);
+ final MapEntryNode newProjectMapEntry = createProjectListEntry(
+ "New Project", "New Project description ...",
+ "Leader of New Project", "Owner of New Project",
+ projListSchemaNode);
+
+ final DataTreeModification writeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+ writeModification.write(newOdlProjectMapEntryPath, newProjectMapEntry);
+ writeModification.ready();
+
+ final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+ .prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before map entry write: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeContributorsCandidate,
+ rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(2, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ inMemoryDataTree.commit(writeContributorsCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After map entry write: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ assertTrue(exception);
+
+ }
+
+ private static void write() {
+
+ final ContainerSchemaNode contributorContSchemaNode = (ContainerSchemaNode) valModule
+ .getDataChildByName(odlContributor);
+
+ final ContainerNode contributorContainer = createContributorContainer(contributorContSchemaNode);
+
+ final YangInstanceIdentifier contributorPath = YangInstanceIdentifier
+ .of(odlContributor);
+ final DataTreeModification writeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+ writeModification.write(contributorPath, contributorContainer);
+
+ writeModification.write(YangInstanceIdentifier.of(l1),
+ ImmutableNodes.leafNode(l1, "Leafref l1 under the root"));
+ writeModification
+ .write(YangInstanceIdentifier.of(l2), ImmutableNodes.leafNode(
+ l2, "Leafref target l2 under the root"));
+
+ writeModification.ready();
+ final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+ .prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before write: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeContributorsCandidate,
+ rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(12, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ inMemoryDataTree.commit(writeContributorsCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After write: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ assertTrue(exception);
+ }
+
+ private static void write2() {
+
+ final ContainerSchemaNode odlCon = (ContainerSchemaNode) valModule
+ .getDataChildByName(odl);
+ final ContainerSchemaNode con1Con = (ContainerSchemaNode) odlCon
+ .getDataChildByName(con1);
+ final LeafNode<String> l1Leaf = ImmutableNodes.leafNode(l1, "l1 value");
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> containerBuilder = Builders
+ .containerBuilder(con1Con);
+ containerBuilder.addChild(l1Leaf);
+ final ContainerNode con1Node = containerBuilder.build();
+
+ final YangInstanceIdentifier con1Path = YangInstanceIdentifier.of(odl)
+ .node(con1);
+ final DataTreeModification writeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+ writeModification.write(con1Path, con1Node);
+
+ final ChoiceNode choiceNode = createChoiceNode();
+ final YangInstanceIdentifier choicePath = YangInstanceIdentifier
+ .of(odl).node(ch1);
+ writeModification.write(choicePath, choiceNode);
+
+ final ContainerNode con3Node = createCon3Node();
+ final YangInstanceIdentifier con3Path = YangInstanceIdentifier.of(odl)
+ .node(con3);
+ writeModification.write(con3Path, con3Node);
+
+ final LeafSetNode<?> leafListNode = createLeafRefLeafListNode();
+ final YangInstanceIdentifier leafListPath = YangInstanceIdentifier.of(
+ odl).node(leafrefLeafList);
+ writeModification.write(leafListPath, leafListNode);
+ writeModification.ready();
+
+ final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+ .prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before write2: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeContributorsCandidate,
+ rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(6, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ assertTrue(exception);
+
+ inMemoryDataTree.commit(writeContributorsCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After write2: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ }
+
+ private static LeafSetNode<?> createLeafRefLeafListNode() {
+
+ final ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafSetBuilder = Builders
+ .leafSetBuilder();
+ leafSetBuilder.withNodeIdentifier(new NodeIdentifier(leafrefLeafList));
+
+ leafSetBuilder.addChild(createLeafSetEntry(leafrefLeafList, "k1"));
+ leafSetBuilder.addChild(createLeafSetEntry(leafrefLeafList, "k2"));
+ leafSetBuilder.addChild(createLeafSetEntry(leafrefLeafList, "k3"));
+
+ return leafSetBuilder.build();
+ }
+
+ private static ContainerNode createCon3Node() {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> mapBuilder = Builders
+ .mapBuilder();
+ mapBuilder.withNodeIdentifier(new NodeIdentifier(list3InChoice));
+
+ mapBuilder.addChild(createList3Entry("k1", "val1", "valA", "valX"));
+ mapBuilder.addChild(createList3Entry("k2", "val2", "valB", "valY"));
+
+ final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> choiceBuilder = Builders
+ .choiceBuilder();
+ choiceBuilder.withNodeIdentifier(new NodeIdentifier(choiceInCon3));
+
+ choiceBuilder.addChild(mapBuilder.build());
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> containerBuilder = Builders
+ .containerBuilder();
+ containerBuilder.withNodeIdentifier(new NodeIdentifier(con3));
+
+ containerBuilder.addChild(choiceBuilder.build());
+
+ return containerBuilder.build();
+ }
+
+ private static MapEntryNode createList3Entry(final String kVal,
+ final String l3Val1, final String l3Val2, final String l3Val3) {
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = Builders
+ .mapEntryBuilder();
+ mapEntryBuilder.withNodeIdentifier(new NodeIdentifierWithPredicates(
+ list3InChoice, k, kVal));
+
+ final ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafSetBuilder = Builders
+ .leafSetBuilder();
+ leafSetBuilder.withNodeIdentifier(new NodeIdentifier(l3));
+
+ leafSetBuilder.addChild(createLeafSetEntry(l3, l3Val1));
+ leafSetBuilder.addChild(createLeafSetEntry(l3, l3Val2));
+ leafSetBuilder.addChild(createLeafSetEntry(l3, l3Val3));
+
+ mapEntryBuilder.addChild(ImmutableNodes.leafNode(k, kVal));
+ mapEntryBuilder.addChild(leafSetBuilder.build());
+
+ return mapEntryBuilder.build();
+ }
+
+ private static LeafSetEntryNode<Object> createLeafSetEntry(
+ final QName qname, final String val) {
+ final NormalizedNodeAttrBuilder<NodeWithValue, Object, LeafSetEntryNode<Object>> leafSetEntryBuilder = Builders
+ .leafSetEntryBuilder();
+ leafSetEntryBuilder.withNodeIdentifier(new NodeWithValue(qname, val));
+ leafSetEntryBuilder.withValue(val);
+ return leafSetEntryBuilder.build();
+ }
+
+ private static ChoiceNode createChoiceNode() {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> listInChoiceBuilder = Builders
+ .mapBuilder();
+ listInChoiceBuilder
+ .withNodeIdentifier(new NodeIdentifier(listInChoice));
+
+ listInChoiceBuilder.addChild(createListInChoiceEntry("key1",
+ "leafref-in-choice value", "val1"));
+ listInChoiceBuilder.addChild(createListInChoiceEntry("key2",
+ "l1 value", "val2"));
+ listInChoiceBuilder.addChild(createListInChoiceEntry("key3",
+ "l1 value", "val3"));
+
+ final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> choice2Builder = Builders
+ .choiceBuilder();
+ choice2Builder.withNodeIdentifier(new NodeIdentifier(ch2));
+
+ choice2Builder.addChild(listInChoiceBuilder.build());
+
+ final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> choiceBuilder = Builders
+ .choiceBuilder();
+ choiceBuilder.withNodeIdentifier(new NodeIdentifier(ch1));
+ choiceBuilder.addChild(choice2Builder.build());
+
+ return choiceBuilder.build();
+ }
+
+ private static MapEntryNode createListInChoiceEntry(final String keyVal,
+ final String leafrefInChoiceVal,
+ final String leafrefInChoiceToChoiceVal) {
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = Builders
+ .mapEntryBuilder();
+
+ mapEntryBuilder.withNodeIdentifier(new NodeIdentifierWithPredicates(
+ listInChoice, listInChoiceKey, keyVal));
+
+ mapEntryBuilder.addChild(ImmutableNodes.leafNode(listInChoiceKey,
+ keyVal));
+ mapEntryBuilder.addChild(ImmutableNodes.leafNode(leafrefInChoice,
+ leafrefInChoiceVal));
+ mapEntryBuilder.addChild(ImmutableNodes.leafNode(
+ leafrefInChoiceToChoice, leafrefInChoiceToChoiceVal));
+
+ return mapEntryBuilder.build();
+ }
+
+ private static void delete() {
+
+ final YangInstanceIdentifier contributorPath = YangInstanceIdentifier
+ .of(odlContributor);
+ final DataTreeModification delete = inMemoryDataTree.takeSnapshot()
+ .newModification();
+ delete.delete(contributorPath);
+ delete.ready();
+
+ final DataTreeCandidate deleteContributorsCanditate = inMemoryDataTree
+ .prepare(delete);
+
+ LOG.debug("*************************");
+ LOG.debug("Before delete: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(deleteContributorsCanditate,
+ rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(6, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ assertTrue(exception);
+
+ inMemoryDataTree.commit(deleteContributorsCanditate);
+
+ LOG.debug("*************************");
+ LOG.debug("After delete: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ }
+
+ private static ContainerNode createContributorContainer(
+ final ContainerSchemaNode contributorContSchemaNode) {
+
+ final ListSchemaNode contributorListSchemaNode = (ListSchemaNode) contributorContSchemaNode
+ .getDataChildByName(contributor);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> contributorContainerBldr = Builders
+ .containerBuilder(contributorContSchemaNode);
+
+ final MapNode contributorMap = createContributorList(contributorListSchemaNode);
+ contributorContainerBldr.addChild(contributorMap);
+
+ final ContainerNode contributorContainer = contributorContainerBldr
+ .build();
+
+ return contributorContainer;
+
+ }
+
+ private static MapNode createContributorList(
+ final ListSchemaNode contributorListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> contributorMapBldr = Builders
+ .mapBuilder(contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry1 = createContributorListEntry(
+ "Leader of Yangtools", "Yangtools Leader name", "Yangtools",
+ "Yangtools description ...", contributorListSchemaNode);
+ final MapEntryNode contributorMapEntry2 = createContributorListEntry(
+ "Leader of MD-SAL", "MD-SAL Leader name", "MD-SAL",
+ "MD-SAL description ...", contributorListSchemaNode);
+ final MapEntryNode contributorMapEntry3 = createContributorListEntry(
+ "Leader of Controller", "Controller Leader name", "Controller",
+ "Controller description ...", contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry4 = createContributorListEntry(
+ "jdoe", "John Doe", "MD-SAL", "Yangtools description ...",
+ contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry5 = createContributorListEntry(
+ "foo", "foo name", "Controller", "MD-SAL description ...",
+ contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry6 = createContributorListEntry(
+ "bar", "bar name", "Yangtools", "Controller description ...",
+ contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry7 = createContributorListEntry(
+ "baz", "baz name", "Unknown Project",
+ "Unknown Project description ...", contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry8 = createContributorListEntry(
+ "pk", "pk name", "Unknown Project 2",
+ "Controller description ...", contributorListSchemaNode);
+
+ contributorMapBldr.addChild(contributorMapEntry1);
+ contributorMapBldr.addChild(contributorMapEntry2);
+ contributorMapBldr.addChild(contributorMapEntry3);
+ contributorMapBldr.addChild(contributorMapEntry4);
+ contributorMapBldr.addChild(contributorMapEntry5);
+ contributorMapBldr.addChild(contributorMapEntry6);
+ contributorMapBldr.addChild(contributorMapEntry7);
+ contributorMapBldr.addChild(contributorMapEntry8);
+
+ final MapNode contributorMap = contributorMapBldr.build();
+
+ return contributorMap;
+
+ }
+
+ private static MapEntryNode createContributorListEntry(
+ final String loginVal, final String contributorNameVal,
+ final String odlProjectNameVal, final String odlProjectDescVal,
+ final ListSchemaNode contributorListSchemaNode) {
+
+ final LeafNode<String> loginLeaf = ImmutableNodes.leafNode(login,
+ loginVal);
+ final LeafNode<String> contributorNameLeaf = ImmutableNodes.leafNode(
+ contributorName, contributorNameVal);
+ final LeafNode<String> odlProjectNameLeafRef = ImmutableNodes.leafNode(
+ odlProjectName, odlProjectNameVal);
+ final LeafNode<String> odlProjectDescLeafRef = ImmutableNodes.leafNode(
+ odlProjectDesc, odlProjectDescVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> contributorMapEntryBldr = Builders
+ .mapEntryBuilder(contributorListSchemaNode);
+
+ contributorMapEntryBldr.addChild(loginLeaf);
+ contributorMapEntryBldr.addChild(contributorNameLeaf);
+ contributorMapEntryBldr.addChild(odlProjectNameLeafRef);
+ contributorMapEntryBldr.addChild(odlProjectDescLeafRef);
+
+ final MapEntryNode contributorMapEntry = contributorMapEntryBldr
+ .build();
+
+ return contributorMapEntry;
+ }
+
+ private static ContainerNode createOdlContainer(
+ final ContainerSchemaNode container) {
+
+ final ListSchemaNode projListSchemaNode = (ListSchemaNode) container
+ .getDataChildByName(project);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> odlProjectContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode projectMap = createProjectList(projListSchemaNode);
+ odlProjectContainerBldr.addChild(projectMap);
+
+ final ContainerNode odlProjectContainer = odlProjectContainerBldr
+ .build();
+
+ return odlProjectContainer;
+ }
+
+ private static MapNode createProjectList(
+ final ListSchemaNode projListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> projectMapBldr = Builders
+ .mapBuilder(projListSchemaNode);
+
+ final MapEntryNode projMapEntry1 = createProjectListEntry("Yangtools",
+ "Yangtools description ...", "Leader of Yangtools",
+ "Owner of Yangtools", projListSchemaNode);
+ final MapEntryNode projMapEntry2 = createProjectListEntry("MD-SAL",
+ "MD-SAL description ...", "Leader of MD-SAL",
+ "Owner of MD-SAL", projListSchemaNode);
+ final MapEntryNode projMapEntry3 = createProjectListEntry("Controller",
+ "Controller description ...", "Leader of Controller",
+ "Owner of Controller", projListSchemaNode);
+
+ projectMapBldr.addChild(projMapEntry1);
+ projectMapBldr.addChild(projMapEntry2);
+ projectMapBldr.addChild(projMapEntry3);
+
+ final MapNode projectMap = projectMapBldr.build();
+
+ return projectMap;
+ }
+
+ private static MapEntryNode createProjectListEntry(final String nameVal,
+ final String descVal, final String leadVal, final String ownerVal,
+ final ListSchemaNode projListSchemaNode) {
+
+ final LeafNode<String> nameLeaf = ImmutableNodes
+ .leafNode(name, nameVal);
+ final LeafNode<String> descLeaf = ImmutableNodes
+ .leafNode(desc, descVal);
+ final LeafNode<String> leadLeafRef = ImmutableNodes.leafNode(lead,
+ leadVal);
+ final LeafNode<String> ownerLeafRef = ImmutableNodes.leafNode(owner,
+ ownerVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> projMapEntryBldr = Builders
+ .mapEntryBuilder(projListSchemaNode);
+
+ projMapEntryBldr.addChild(nameLeaf);
+ projMapEntryBldr.addChild(descLeaf);
+ projMapEntryBldr.addChild(leadLeafRef);
+ projMapEntryBldr.addChild(ownerLeafRef);
+ final MapEntryNode projMapEntry = projMapEntryBldr.build();
+
+ return projMapEntry;
+ }
+
+ private static ContainerNode createBasicContributorContainer(
+ final ContainerSchemaNode contributorContSchemaNode) {
+
+ final ListSchemaNode contributorListSchemaNode = (ListSchemaNode) contributorContSchemaNode
+ .getDataChildByName(contributor);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> contributorContainerBldr = Builders
+ .containerBuilder(contributorContSchemaNode);
+
+ final MapNode contributorMap = createBasicContributorList(contributorListSchemaNode);
+ contributorContainerBldr.addChild(contributorMap);
+
+ final ContainerNode contributorContainer = contributorContainerBldr
+ .build();
+
+ return contributorContainer;
+
+ }
+
+ private static MapNode createBasicContributorList(
+ final ListSchemaNode contributorListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> contributorMapBldr = Builders
+ .mapBuilder(contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry1 = createContributorListEntry(
+ "Leader of Yangtools", "Yangtools Leader name", "Yangtools",
+ "Yangtools description ...", contributorListSchemaNode);
+ final MapEntryNode contributorMapEntry2 = createContributorListEntry(
+ "Leader of MD-SAL", "MD-SAL Leader name", "MD-SAL",
+ "MD-SAL description ...", contributorListSchemaNode);
+ final MapEntryNode contributorMapEntry3 = createContributorListEntry(
+ "Leader of Controller", "Controller Leader name", "Controller",
+ "Controller description ...", contributorListSchemaNode);
+
+ contributorMapBldr.addChild(contributorMapEntry1);
+ contributorMapBldr.addChild(contributorMapEntry2);
+ contributorMapBldr.addChild(contributorMapEntry3);
+
+ final MapNode contributorMap = contributorMapBldr.build();
+
+ return contributorMap;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.leafref.context.test.retest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Set;
+import org.apache.log4j.BasicConfigurator;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+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.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefDataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefValidatation;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataTreeCandidateValidatorTest2 {
+
+ private static SchemaContext context;
+ private static Module mainModule;
+ private static QNameModule rootModuleQname;
+ private static LeafRefContext rootLeafRefContext;
+ public static TipProducingDataTree inMemoryDataTree;
+
+ private static QName chips;
+ private static QName chip;
+ private static QName devType;
+ private static QName chipDesc;
+
+ private static QName devices;
+ private static QName device;
+ private static QName typeChoice;
+ private static QName typeText;
+ private static QName devDesc;
+ private static QName sn;
+ private static QName defaultIp;
+
+ private static QName deviceTypeStr;
+ private static QName deviceType;
+ private static QName type;
+ private static QName desc;
+
+ private static final Logger LOG = LoggerFactory.getLogger("");
+ private static final String NEW_LINE = System.getProperty("line.separator");
+
+ static {
+ BasicConfigurator.configure();
+ }
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException, URISyntaxException {
+
+ initSchemaContext();
+ initLeafRefContext();
+ initQnames();
+ initDataTree();
+ }
+
+ @Test
+ public void dataTreeCanditateValidationTest2() {
+
+ writeDevices();
+ }
+
+ private static void writeDevices() {
+
+ final ContainerSchemaNode devicesContSchemaNode = (ContainerSchemaNode) mainModule.getDataChildByName(devices);
+
+ final ContainerNode devicesContainer = createDevicesContainer(devicesContSchemaNode);
+
+ final YangInstanceIdentifier devicesPath = YangInstanceIdentifier.of(devices);
+ final DataTreeModification writeModification = inMemoryDataTree.takeSnapshot().newModification();
+ writeModification.write(devicesPath, devicesContainer);
+
+ writeModification.ready();
+ final DataTreeCandidate writeDevicesCandidate = inMemoryDataTree.prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before writeDevices: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeDevicesCandidate, rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+
+ assertEquals(4, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ assertTrue(exception);
+
+ inMemoryDataTree.commit(writeDevicesCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After write: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+ }
+
+ private static void initQnames() {
+
+ chips = QName.create(rootModuleQname, "chips");
+ chip = QName.create(rootModuleQname, "chip");
+ devType = QName.create(rootModuleQname, "dev_type");
+ chipDesc = QName.create(rootModuleQname, "chip_desc");
+
+ devices = QName.create(rootModuleQname, "devices");
+ device = QName.create(rootModuleQname, "device");
+ typeText = QName.create(rootModuleQname, "type_text");
+ devDesc = QName.create(rootModuleQname, "dev_desc");
+ sn = QName.create(rootModuleQname, "sn");
+ defaultIp = QName.create(rootModuleQname, "default_ip");
+
+ deviceTypeStr = QName.create(rootModuleQname, "device_types");
+ deviceType = QName.create(rootModuleQname, "device_type");
+ type = QName.create(rootModuleQname, "type");
+ desc = QName.create(rootModuleQname, "desc");
+ }
+
+ private static void initSchemaContext() throws URISyntaxException, FileNotFoundException, ReactorException {
+
+ final File resourceFile = new File(DataTreeCandidateValidatorTest.class.getResource(
+ "/leafref-validation/leafref-validation2.yang").toURI());
+ final File resourceDir = resourceFile.getParentFile();
+
+ context = RetestUtils.parseYangSources(Arrays.asList(resourceDir.listFiles()));
+
+ final Set<Module> modules = context.getModules();
+ for (final Module module : modules) {
+ if (module.getName().equals("leafref-validation2")) {
+ mainModule = module;
+ }
+ }
+
+ rootModuleQname = mainModule.getQNameModule();
+ }
+
+ private static void initDataTree() {
+
+ inMemoryDataTree = InMemoryDataTreeFactory.getInstance().create();
+ inMemoryDataTree.setSchemaContext(context);
+
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+
+ final ContainerSchemaNode chipsListContSchemaNode = (ContainerSchemaNode) mainModule.getDataChildByName(chips);
+ final ContainerNode chipsContainer = createChipsContainer(chipsListContSchemaNode);
+ final YangInstanceIdentifier path1 = YangInstanceIdentifier.of(chips);
+ initialDataTreeModification.write(path1, chipsContainer);
+
+ final ContainerSchemaNode devTypesListContSchemaNode = (ContainerSchemaNode) mainModule
+ .getDataChildByName(deviceTypeStr);
+ final ContainerNode deviceTypesContainer = createDevTypeStrContainer(devTypesListContSchemaNode);
+ final YangInstanceIdentifier path2 = YangInstanceIdentifier.of(deviceTypeStr);
+ initialDataTreeModification.write(path2, deviceTypesContainer);
+
+ initialDataTreeModification.ready();
+ final DataTreeCandidate writeChipsCandidate = inMemoryDataTree.prepare(initialDataTreeModification);
+
+ inMemoryDataTree.commit(writeChipsCandidate);
+
+ System.out.println(inMemoryDataTree.toString());
+ }
+
+ private static void initLeafRefContext() {
+ rootLeafRefContext = LeafRefContext.create(context);
+ }
+
+ private static ContainerNode createDevTypeStrContainer(final ContainerSchemaNode container) {
+
+ final ListSchemaNode devTypeListSchemaNode = (ListSchemaNode) container.getDataChildByName(deviceType);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devTypeContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode devTypeMap = createDevTypeList(devTypeListSchemaNode);
+ devTypeContainerBldr.addChild(devTypeMap);
+
+ return devTypeContainerBldr.build();
+ }
+
+ private static MapNode createDevTypeList(final ListSchemaNode devTypeListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> devTypeMapBldr = Builders.mapBuilder(devTypeListSchemaNode);
+
+ devTypeMapBldr.addChild(createDevTypeListEntry("dev_type_1", "typedesc1", devTypeListSchemaNode));
+ devTypeMapBldr.addChild(createDevTypeListEntry("dev_type_2", "typedesc2", devTypeListSchemaNode));
+ devTypeMapBldr.addChild(createDevTypeListEntry("dev_type_3", "typedesc3", devTypeListSchemaNode));
+
+ return devTypeMapBldr.build();
+ }
+
+ private static MapEntryNode createDevTypeListEntry(final String typeVal, final String descVal,
+ final ListSchemaNode devTypeListSchemaNode) {
+
+ final LeafNode<String> typeLeaf = ImmutableNodes.leafNode(type, typeVal);
+ final LeafNode<String> descLeaf = ImmutableNodes.leafNode(desc, descVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> devTypeMapEntryBldr = Builders
+ .mapEntryBuilder(devTypeListSchemaNode);
+
+ devTypeMapEntryBldr.addChild(typeLeaf);
+ devTypeMapEntryBldr.addChild(descLeaf);
+
+ return devTypeMapEntryBldr.build();
+ }
+
+ private static ContainerNode createChipsContainer(final ContainerSchemaNode container) {
+
+ final ListSchemaNode chipsListSchemaNode = (ListSchemaNode) container.getDataChildByName(chip);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> chipsContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode chipsMap = createChipsList(chipsListSchemaNode);
+ chipsContainerBldr.addChild(chipsMap);
+
+ return chipsContainerBldr.build();
+ }
+
+ private static MapNode createChipsList(final ListSchemaNode chipsListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> chipsMapBldr = Builders.mapBuilder(chipsListSchemaNode);
+
+ chipsMapBldr.addChild(createChipsListEntry("dev_type_1", "desc1", chipsListSchemaNode));
+ chipsMapBldr.addChild(createChipsListEntry("dev_type_2", "desc2", chipsListSchemaNode));
+
+ return chipsMapBldr.build();
+ }
+
+ private static MapEntryNode createChipsListEntry(final String devTypeVal, final String chipDescVal,
+ final ListSchemaNode chipsListSchemaNode) {
+
+ final LeafNode<String> devTypeLeaf = ImmutableNodes.leafNode(devType, devTypeVal);
+ final LeafNode<String> chipDescLeaf = ImmutableNodes.leafNode(chipDesc, chipDescVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> chipsMapEntryBldr = Builders
+ .mapEntryBuilder(chipsListSchemaNode);
+
+ chipsMapEntryBldr.addChild(devTypeLeaf);
+ chipsMapEntryBldr.addChild(chipDescLeaf);
+
+ return chipsMapEntryBldr.build();
+ }
+
+ private static ContainerNode createDevicesContainer(final ContainerSchemaNode container) {
+
+ final ListSchemaNode devicesListSchemaNode = (ListSchemaNode) container.getDataChildByName(device);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devicesContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode devicesMap = createDeviceList(devicesListSchemaNode);
+ devicesContainerBldr.addChild(devicesMap);
+
+ return devicesContainerBldr.build();
+ }
+
+ private static MapNode createDeviceList(final ListSchemaNode deviceListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> devicesMapBldr = Builders.mapBuilder(deviceListSchemaNode);
+
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type_1", "typedesc1", 123456, "192.168.0.1",
+ deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type_2", "typedesc2", 123457, "192.168.0.1",
+ deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type_2", "typedesc3", 123457, "192.168.0.1",
+ deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type_1", "typedesc2", 123458, "192.168.0.1",
+ deviceListSchemaNode));
+ devicesMapBldr
+ .addChild(createDeviceListEntry("unknown", "unknown", 123457, "192.168.0.1", deviceListSchemaNode));
+
+ return devicesMapBldr.build();
+ }
+
+ private static MapEntryNode createDeviceListEntry(final String typeTextVal, final String descVal, final int snVal,
+ final String defaultIpVal, final ListSchemaNode devicesListSchemaNode) {
+
+ final LeafNode<String> typeTextLeaf = ImmutableNodes.leafNode(typeText, typeTextVal);
+ final LeafNode<String> descLeaf = ImmutableNodes.leafNode(devDesc, descVal);
+ final LeafNode<Integer> snValLeaf = ImmutableNodes.leafNode(sn, snVal);
+ final LeafNode<String> defaultIpLeaf = ImmutableNodes.leafNode(defaultIp, defaultIpVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> devicesMapEntryBldr = Builders
+ .mapEntryBuilder(devicesListSchemaNode);
+
+ devicesMapEntryBldr.addChild(typeTextLeaf);
+ devicesMapEntryBldr.addChild(descLeaf);
+ devicesMapEntryBldr.addChild(snValLeaf);
+ devicesMapEntryBldr.addChild(defaultIpLeaf);
+
+ return devicesMapEntryBldr.build();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.leafref.context.test.retest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Set;
+import org.apache.log4j.BasicConfigurator;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+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.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefDataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefValidatation;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataTreeCandidateValidatorTest3 {
+
+ private static SchemaContext context;
+ private static Module mainModule;
+ private static QNameModule rootModuleQname;
+ private static LeafRefContext rootLeafRefContext;
+ public static TipProducingDataTree inMemoryDataTree;
+
+ private static QName chips;
+ private static QName chip;
+ private static QName devType;
+ private static QName chipDesc;
+
+ private static QName devices;
+ private static QName device;
+ private static QName typeText1;
+ private static QName typeText2;
+ private static QName typeText3;
+ private static QName devDesc;
+ private static QName sn;
+ private static QName defaultIp;
+
+ private static QName deviceTypeStr;
+ private static QName deviceType;
+ private static QName type1;
+ private static QName type2;
+ private static QName type3;
+ private static QName desc;
+
+ private static final Logger LOG = LoggerFactory.getLogger("");
+ private static final String NEW_LINE = System.getProperty("line.separator");
+
+ static {
+ BasicConfigurator.configure();
+ }
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException, URISyntaxException {
+
+ initSchemaContext();
+ initLeafRefContext();
+ initQnames();
+ initDataTree();
+ }
+
+ @Test
+ public void dataTreeCanditateValidationTest2() {
+
+ writeDevices();
+
+ mergeDevices();
+ }
+
+ private static void writeDevices() {
+
+ final ContainerSchemaNode devicesContSchemaNode = (ContainerSchemaNode) mainModule.getDataChildByName(devices);
+
+ final ContainerNode devicesContainer = createDevicesContainer(devicesContSchemaNode);
+
+ final YangInstanceIdentifier devicesPath = YangInstanceIdentifier.of(devices);
+ final DataTreeModification writeModification = inMemoryDataTree.takeSnapshot().newModification();
+ writeModification.write(devicesPath, devicesContainer);
+
+ writeModification.ready();
+ final DataTreeCandidate writeDevicesCandidate = inMemoryDataTree.prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before writeDevices: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeDevicesCandidate, rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(6, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ assertTrue(exception);
+
+ inMemoryDataTree.commit(writeDevicesCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After writeDevices: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+ }
+
+ private static void mergeDevices() {
+
+ final ContainerSchemaNode devicesContSchemaNode = (ContainerSchemaNode) mainModule.getDataChildByName(devices);
+
+ final ContainerNode devicesContainer = createDevices2Container(devicesContSchemaNode);
+
+ final YangInstanceIdentifier devicesPath = YangInstanceIdentifier.of(devices);
+ final DataTreeModification mergeModification = inMemoryDataTree.takeSnapshot().newModification();
+ mergeModification.write(devicesPath, devicesContainer);
+ mergeModification.merge(devicesPath, devicesContainer);
+
+ mergeModification.ready();
+ final DataTreeCandidate mergeDevicesCandidate = inMemoryDataTree.prepare(mergeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before mergeDevices: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(mergeDevicesCandidate, rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ // :TODO verify errors count gz
+ assertEquals(6, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ inMemoryDataTree.commit(mergeDevicesCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After mergeDevices: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ assertTrue(exception);
+ }
+
+ private static void initQnames() {
+
+ chips = QName.create(rootModuleQname, "chips");
+ chip = QName.create(rootModuleQname, "chip");
+ devType = QName.create(rootModuleQname, "dev_type");
+ chipDesc = QName.create(rootModuleQname, "chip_desc");
+
+ devices = QName.create(rootModuleQname, "devices");
+ device = QName.create(rootModuleQname, "device");
+ typeText1 = QName.create(rootModuleQname, "type_text1");
+ typeText2 = QName.create(rootModuleQname, "type_text2");
+ typeText3 = QName.create(rootModuleQname, "type_text3");
+ devDesc = QName.create(rootModuleQname, "dev_desc");
+ sn = QName.create(rootModuleQname, "sn");
+ defaultIp = QName.create(rootModuleQname, "default_ip");
+
+ deviceTypeStr = QName.create(rootModuleQname, "device_types");
+ deviceType = QName.create(rootModuleQname, "device_type");
+ type1 = QName.create(rootModuleQname, "type1");
+ type2 = QName.create(rootModuleQname, "type2");
+ type3 = QName.create(rootModuleQname, "type3");
+ desc = QName.create(rootModuleQname, "desc");
+ }
+
+ private static void initSchemaContext() throws URISyntaxException, FileNotFoundException, ReactorException {
+
+ final File resourceFile = new File(DataTreeCandidateValidatorTest.class.getResource(
+ "/leafref-validation/leafref-validation3.yang").toURI());
+ final File resourceDir = resourceFile.getParentFile();
+
+ context = RetestUtils.parseYangSources(Arrays.asList(resourceDir.listFiles()));
+
+ final Set<Module> modules = context.getModules();
+ for (final Module module : modules) {
+ if (module.getName().equals("leafref-validation3")) {
+ mainModule = module;
+ }
+ }
+
+ rootModuleQname = mainModule.getQNameModule();
+ }
+
+ private static void initDataTree() {
+
+ inMemoryDataTree = InMemoryDataTreeFactory.getInstance().create();
+ inMemoryDataTree.setSchemaContext(context);
+
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+
+ final ContainerSchemaNode chipsListContSchemaNode = (ContainerSchemaNode) mainModule.getDataChildByName(chips);
+ final ContainerNode chipsContainer = createChipsContainer(chipsListContSchemaNode);
+ final YangInstanceIdentifier path1 = YangInstanceIdentifier.of(chips);
+ initialDataTreeModification.write(path1, chipsContainer);
+
+ final ContainerSchemaNode devTypesListContSchemaNode = (ContainerSchemaNode) mainModule
+ .getDataChildByName(deviceTypeStr);
+ final ContainerNode deviceTypesContainer = createDevTypeStrContainer(devTypesListContSchemaNode);
+ final YangInstanceIdentifier path2 = YangInstanceIdentifier.of(deviceTypeStr);
+ initialDataTreeModification.write(path2, deviceTypesContainer);
+
+ initialDataTreeModification.ready();
+ final DataTreeCandidate writeChipsCandidate = inMemoryDataTree.prepare(initialDataTreeModification);
+
+ inMemoryDataTree.commit(writeChipsCandidate);
+
+ System.out.println(inMemoryDataTree.toString());
+ }
+
+ private static void initLeafRefContext() {
+ rootLeafRefContext = LeafRefContext.create(context);
+ }
+
+ private static ContainerNode createDevTypeStrContainer(final ContainerSchemaNode container) {
+
+ final ListSchemaNode devTypeListSchemaNode = (ListSchemaNode) container.getDataChildByName(deviceType);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devTypeContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode devTypeMap = createDevTypeList(devTypeListSchemaNode);
+ devTypeContainerBldr.addChild(devTypeMap);
+
+ return devTypeContainerBldr.build();
+ }
+
+ private static MapNode createDevTypeList(final ListSchemaNode devTypeListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> devTypeMapBldr = Builders.mapBuilder(devTypeListSchemaNode);
+
+ devTypeMapBldr.addChild(createDevTypeListEntry("dev_type1_1", "dev_type2_1", "dev_type3_1", "typedesc1",
+ devTypeListSchemaNode));
+ devTypeMapBldr.addChild(createDevTypeListEntry("dev_type1_2", "dev_type2_2", "dev_type3_2", "typedesc2",
+ devTypeListSchemaNode));
+ devTypeMapBldr.addChild(createDevTypeListEntry("dev_type1_3", "dev_type2_3", "dev_type3_3", "typedesc3",
+ devTypeListSchemaNode));
+
+ return devTypeMapBldr.build();
+ }
+
+ private static MapEntryNode createDevTypeListEntry(final String type1Val, final String type2Val,
+ final String type3Val, final String descVal, final ListSchemaNode devTypeListSchemaNode) {
+
+ final LeafNode<String> type1Leaf = ImmutableNodes.leafNode(type1, type1Val);
+ final LeafNode<String> type2Leaf = ImmutableNodes.leafNode(type2, type2Val);
+ final LeafNode<String> type3Leaf = ImmutableNodes.leafNode(type3, type3Val);
+ final LeafNode<String> descLeaf = ImmutableNodes.leafNode(desc, descVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> devTypeMapEntryBldr = Builders
+ .mapEntryBuilder(devTypeListSchemaNode);
+
+ devTypeMapEntryBldr.addChild(type1Leaf);
+ devTypeMapEntryBldr.addChild(type2Leaf);
+ devTypeMapEntryBldr.addChild(type3Leaf);
+ devTypeMapEntryBldr.addChild(descLeaf);
+
+ return devTypeMapEntryBldr.build();
+ }
+
+ private static ContainerNode createChipsContainer(final ContainerSchemaNode container) {
+
+ final ListSchemaNode chipsListSchemaNode = (ListSchemaNode) container.getDataChildByName(chip);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> chipsContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode chipsMap = createChipsList(chipsListSchemaNode);
+ chipsContainerBldr.addChild(chipsMap);
+
+ return chipsContainerBldr.build();
+ }
+
+ private static MapNode createChipsList(final ListSchemaNode chipsListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> chipsMapBldr = Builders.mapBuilder(chipsListSchemaNode);
+
+ chipsMapBldr.addChild(createChipsListEntry("dev_type_1", "desc1", chipsListSchemaNode));
+ chipsMapBldr.addChild(createChipsListEntry("dev_type_2", "desc2", chipsListSchemaNode));
+
+ return chipsMapBldr.build();
+ }
+
+ private static MapEntryNode createChipsListEntry(final String devTypeVal, final String chipDescVal,
+ final ListSchemaNode chipsListSchemaNode) {
+
+ final LeafNode<String> devTypeLeaf = ImmutableNodes.leafNode(devType, devTypeVal);
+ final LeafNode<String> chipDescLeaf = ImmutableNodes.leafNode(chipDesc, chipDescVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> chipsMapEntryBldr = Builders
+ .mapEntryBuilder(chipsListSchemaNode);
+
+ chipsMapEntryBldr.addChild(devTypeLeaf);
+ chipsMapEntryBldr.addChild(chipDescLeaf);
+
+ return chipsMapEntryBldr.build();
+ }
+
+ private static ContainerNode createDevicesContainer(final ContainerSchemaNode container) {
+
+ final ListSchemaNode devicesListSchemaNode = (ListSchemaNode) container.getDataChildByName(device);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devicesContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode devicesMap = createDeviceList(devicesListSchemaNode);
+ devicesContainerBldr.addChild(devicesMap);
+
+ return devicesContainerBldr.build();
+ }
+
+ private static MapNode createDeviceList(final ListSchemaNode deviceListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> devicesMapBldr = Builders.mapBuilder(deviceListSchemaNode);
+
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type1_1", "dev_type2_1", "dev_type3_1", "typedesc1", 123456,
+ "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type1_2", "dev_type2_2", "dev_type3_2", "typedesc1", 123457,
+ "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type1_1", "dev_type2_2", "dev_type3_3", "typedesc2", 123458,
+ "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("unk11", "unk22", "unk33", "unk_desc2", 123457, "192.168.0.1",
+ deviceListSchemaNode));
+
+ return devicesMapBldr.build();
+ }
+
+ private static ContainerNode createDevices2Container(final ContainerSchemaNode container) {
+
+ final ListSchemaNode devicesListSchemaNode = (ListSchemaNode) container.getDataChildByName(device);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devicesContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode devicesMap = createDevice2List(devicesListSchemaNode);
+ devicesContainerBldr.addChild(devicesMap);
+
+ return devicesContainerBldr.build();
+ }
+
+ private static MapNode createDevice2List(final ListSchemaNode deviceListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> devicesMapBldr = Builders.mapBuilder(deviceListSchemaNode);
+
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type1_3", "dev_type2_3", "dev_type3_3", "typedesc3", 123459,
+ "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type1_3", "dev_type2_3", "dev_type3_3", "typedesc2", 123460,
+ "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type1_3", "dev_type2_2", "dev_type3_1", "typedesc1", 123461,
+ "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("unk1", "unk2", "unk3", "unk_desc", 123462, "192.168.0.1",
+ deviceListSchemaNode));
+
+ return devicesMapBldr.build();
+ }
+
+ private static MapEntryNode createDeviceListEntry(final String type1TextVal, final String type2TextVal,
+ final String type3TextVal, final String descVal, final int snVal, final String defaultIpVal,
+ final ListSchemaNode devicesListSchemaNode) {
+
+ final LeafNode<String> typeText1Leaf = ImmutableNodes.leafNode(typeText1, type1TextVal);
+ final LeafNode<String> typeText2Leaf = ImmutableNodes.leafNode(typeText2, type2TextVal);
+ final LeafNode<String> typeText3Leaf = ImmutableNodes.leafNode(typeText3, type3TextVal);
+ final LeafNode<String> descLeaf = ImmutableNodes.leafNode(devDesc, descVal);
+ final LeafNode<Integer> snValLeaf = ImmutableNodes.leafNode(sn, snVal);
+ final LeafNode<String> defaultIpLeaf = ImmutableNodes.leafNode(defaultIp, defaultIpVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> devicesMapEntryBldr = Builders
+ .mapEntryBuilder(devicesListSchemaNode);
+
+ devicesMapEntryBldr.addChild(typeText1Leaf);
+ devicesMapEntryBldr.addChild(typeText2Leaf);
+ devicesMapEntryBldr.addChild(typeText3Leaf);
+ devicesMapEntryBldr.addChild(descLeaf);
+ devicesMapEntryBldr.addChild(snValLeaf);
+ devicesMapEntryBldr.addChild(defaultIpLeaf);
+
+ return devicesMapEntryBldr.build();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.leafref.context.test.retest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContextUtils;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class LeafRefContextTest {
+
+ private static SchemaContext context;
+ private static Module rootMod;
+ private static QNameModule root;
+ private static LeafRefContext rootLeafRefContext;
+
+ @BeforeClass
+ public static void init() throws URISyntaxException, FileNotFoundException, ReactorException {
+
+ final File resourceFile = new File(LeafRefContextTreeBuilderTest.class.getResource(
+ "/leafref-context-test/correct-modules/leafref-test2.yang").toURI());
+
+ final File resourceDir = resourceFile.getParentFile();
+
+ context = RetestUtils.parseYangSources(Arrays.asList(resourceDir.listFiles()));
+
+ final Set<Module> modules = context.getModules();
+ for (final Module module : modules) {
+ if (module.getName().equals("leafref-test2")) {
+ rootMod = module;
+ }
+ }
+
+ root = rootMod.getQNameModule();
+ rootLeafRefContext = LeafRefContext.create(context);
+ }
+
+ @Test
+ public void test() {
+
+ final QName q1 = QName.create(root, "ref1");
+ final QName q2 = QName.create(root, "leaf1");
+ final QName q3 = QName.create(root, "cont1");
+ final QName q4 = QName.create(root, "cont2");
+ final QName q5 = QName.create(root, "list1");
+ final QName q6 = QName.create(root, "name");
+
+ final DataSchemaNode leafRefNode = rootMod.getDataChildByName(q1);
+ final DataSchemaNode targetNode = rootMod.getDataChildByName(q2);
+ final DataSchemaNode cont1Node = rootMod.getDataChildByName(q3);
+ final DataSchemaNode cont2Node = rootMod.getDataChildByName(q4);
+ final DataSchemaNode name1Node = ((DataNodeContainer) ((DataNodeContainer) rootMod.getDataChildByName(q3))
+ .getDataChildByName(q5)).getDataChildByName(q6);
+
+ assertTrue(LeafRefContextUtils.isLeafRef(leafRefNode, rootLeafRefContext));
+ assertFalse(LeafRefContextUtils.isLeafRef(targetNode, rootLeafRefContext));
+
+ assertTrue(LeafRefContextUtils.hasLeafRefChild(cont1Node, rootLeafRefContext));
+ assertFalse(LeafRefContextUtils.hasLeafRefChild(leafRefNode, rootLeafRefContext));
+
+ assertTrue(LeafRefContextUtils.isReferencedByLeafRef(targetNode, rootLeafRefContext));
+ assertFalse(LeafRefContextUtils.isReferencedByLeafRef(leafRefNode, rootLeafRefContext));
+
+ assertTrue(LeafRefContextUtils.hasChildReferencedByLeafRef(cont2Node, rootLeafRefContext));
+ assertFalse(LeafRefContextUtils.hasChildReferencedByLeafRef(leafRefNode, rootLeafRefContext));
+
+ Map<QName, LeafRefContext> leafRefs = LeafRefContextUtils.getAllLeafRefsReferencingThisNode(name1Node,
+ rootLeafRefContext);
+ assertEquals(4, leafRefs.size());
+ leafRefs = LeafRefContextUtils.getAllLeafRefsReferencingThisNode(leafRefNode, rootLeafRefContext);
+ assertTrue(leafRefs.isEmpty());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.leafref.context.test.retest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContextUtils;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class LeafRefContextTreeBuilderTest {
+
+ private static SchemaContext context;
+ private static Module impMod;
+ private static Module tstMod;
+ private static QNameModule imp;
+ private static QNameModule tst;
+ private static LeafRefContext rootLeafRefContext;
+
+ @BeforeClass
+ public static void init() throws URISyntaxException, FileNotFoundException, ReactorException {
+ final File resourceFile = new File(LeafRefContextTreeBuilderTest.class.getResource(
+ "/leafref-context-test/correct-modules/leafref-test.yang").toURI());
+ final File resourceDir = resourceFile.getParentFile();
+
+ context = RetestUtils.parseYangSources(Arrays.asList(resourceDir.listFiles()));
+
+ final Set<Module> modules = context.getModules();
+ for (final Module module : modules) {
+ if (module.getName().equals("import-mod")) {
+ impMod = module;
+ }
+ if (module.getName().equals("leafref-test")) {
+ tstMod = module;
+ }
+ }
+
+ imp = impMod.getQNameModule();
+ tst = tstMod.getQNameModule();
+
+ rootLeafRefContext = LeafRefContext.create(context);
+ }
+
+ @Test
+ public void buildLeafRefContextTreeTest1() {
+
+ final QName q1 = QName.create(tst, "odl-project");
+ final QName q2 = QName.create(tst, "project");
+ final QName q3 = QName.create(tst, "project-lead");
+
+ final LeafRefContext leafRefCtx = rootLeafRefContext.getReferencingChildByName(q1)
+ .getReferencingChildByName(q2).getReferencingChildByName(q3);
+
+ assertTrue(leafRefCtx.isReferencing());
+ assertNotNull(leafRefCtx.getLeafRefTargetPath());
+ assertFalse(leafRefCtx.getLeafRefTargetPath().isAbsolute());
+ assertNotNull(leafRefCtx.getAbsoluteLeafRefTargetPath());
+ assertTrue(leafRefCtx.getAbsoluteLeafRefTargetPath().isAbsolute());
+
+ System.out.println();
+ System.out.println("******* Test 1 ************");
+ System.out.println("Original definition string:");
+ System.out.println(leafRefCtx.getLeafRefTargetPathString());
+ System.out.println("Parsed leafref path:");
+ System.out.println(leafRefCtx.getLeafRefTargetPath().toString());
+ System.out.println("Absolute leafref path:");
+ System.out.println(leafRefCtx.getAbsoluteLeafRefTargetPath().toString());
+ }
+
+ @Test
+ public void buildLeafRefContextTreeTest2() {
+
+ final QName q1 = QName.create(tst, "odl-project");
+ final QName q2 = QName.create(tst, "project");
+ final QName q4 = QName.create(tst, "project-lead2");
+
+ final LeafRefContext leafRefCtx2 = rootLeafRefContext.getReferencingChildByName(q1)
+ .getReferencingChildByName(q2).getReferencingChildByName(q4);
+
+ assertTrue(leafRefCtx2.isReferencing());
+ assertNotNull(leafRefCtx2.getLeafRefTargetPath());
+ assertTrue(leafRefCtx2.getLeafRefTargetPath().isAbsolute());
+ assertNotNull(leafRefCtx2.getAbsoluteLeafRefTargetPath());
+ assertTrue(leafRefCtx2.getAbsoluteLeafRefTargetPath().isAbsolute());
+
+ System.out.println();
+ System.out.println("******* Test 2 ************");
+ System.out.println("Original definition string2:");
+ System.out.println(leafRefCtx2.getLeafRefTargetPathString());
+ System.out.println("Parsed leafref path2:");
+ System.out.println(leafRefCtx2.getLeafRefTargetPath().toString());
+ System.out.println("Absolute leafref path2:");
+ System.out.println(leafRefCtx2.getAbsoluteLeafRefTargetPath().toString());
+ System.out.println();
+
+ }
+
+ @Test
+ public void buildLeafRefContextTreeXPathTest() {
+ final QName q1 = QName.create(tst, "odl-project");
+ final QName q2 = QName.create(tst, "project");
+ final QName q5 = QName.create(tst, "ch1");
+ final QName q6 = QName.create(tst, "c1");
+ final QName q7 = QName.create(tst, "ch2");
+ final QName q8 = QName.create(tst, "l1");
+ final LeafRefContext leafRefCtx3 = rootLeafRefContext.getReferencingChildByName(q1)
+ .getReferencingChildByName(q2).getReferencingChildByName(q5).getReferencingChildByName(q6)
+ .getReferencingChildByName(q7).getReferencingChildByName(q6).getReferencingChildByName(q8);
+
+ assertTrue(leafRefCtx3.isReferencing());
+ assertNotNull(leafRefCtx3.getLeafRefTargetPath());
+ assertFalse(leafRefCtx3.getLeafRefTargetPath().isAbsolute());
+ assertNotNull(leafRefCtx3.getAbsoluteLeafRefTargetPath());
+ assertTrue(leafRefCtx3.getAbsoluteLeafRefTargetPath().isAbsolute());
+
+ System.out.println();
+ System.out.println("******* Test 3 ************");
+ System.out.println("Original definition string2:");
+ System.out.println(leafRefCtx3.getLeafRefTargetPathString());
+ System.out.println("Parsed leafref path2:");
+ System.out.println(leafRefCtx3.getLeafRefTargetPath().toString());
+ System.out.println("Absolute leafref path2:");
+ System.out.println(leafRefCtx3.getAbsoluteLeafRefTargetPath().toString());
+ System.out.println();
+ }
+
+ @Test
+ public void buildLeafRefContextTreeTest4() {
+ final QName q9 = QName.create(tst, "odl-project");
+ final QName q10 = QName.create(tst, "project");
+ final QName q11 = QName.create(tst, "name");
+
+ final LeafRefContext leafRefCtx4 = rootLeafRefContext.getReferencedChildByName(q9)
+ .getReferencedChildByName(q10).getReferencedChildByName(q11);
+
+ assertNotNull(leafRefCtx4);
+ assertTrue(leafRefCtx4.isReferenced());
+ assertEquals(6, leafRefCtx4.getAllReferencedByLeafRefCtxs().size());
+
+ }
+
+ @Test
+ public void leafRefContextUtilsTest() {
+ final QName q1 = QName.create(tst, "odl-contributor");
+ final QName q2 = QName.create(tst, "contributor");
+ final QName q3 = QName.create(tst, "odl-project-name");
+
+ final LeafRefContext odlContrProjNameCtx = rootLeafRefContext.getReferencingChildByName(q1)
+ .getReferencingChildByName(q2).getReferencingChildByName(q3);
+
+ final DataSchemaNode odlContrProjNameNode = ((DataNodeContainer) ((DataNodeContainer) tstMod
+ .getDataChildByName(q1)).getDataChildByName(q2)).getDataChildByName(q3);
+
+ final LeafRefContext foundOdlContrProjNameCtx = LeafRefContextUtils.getLeafRefReferencingContext(
+ odlContrProjNameNode, rootLeafRefContext);
+
+ assertNotNull(foundOdlContrProjNameCtx);
+ assertTrue(foundOdlContrProjNameCtx.isReferencing());
+ assertNotNull(foundOdlContrProjNameCtx.getLeafRefTargetPath());
+ assertEquals(odlContrProjNameCtx, foundOdlContrProjNameCtx);
+ }
+
+ @Test
+ public void leafRefContextUtilsTest2() {
+ final QName q1 = QName.create(tst, "odl-project");
+ final QName q2 = QName.create(tst, "project");
+ final QName q3 = QName.create(tst, "name");
+
+ final LeafRefContext leafRefCtx = rootLeafRefContext.getReferencedChildByName(q1).getReferencedChildByName(q2)
+ .getReferencedChildByName(q3);
+
+ final DataSchemaNode odlProjNameNode = ((DataNodeContainer) ((DataNodeContainer) tstMod.getDataChildByName(q1))
+ .getDataChildByName(q2)).getDataChildByName(q3);
+
+ LeafRefContext foundOdlProjNameCtx = LeafRefContextUtils.getLeafRefReferencingContext(odlProjNameNode,
+ rootLeafRefContext);
+
+ assertNull(foundOdlProjNameCtx);
+
+ foundOdlProjNameCtx = LeafRefContextUtils.getLeafRefReferencedByContext(odlProjNameNode, rootLeafRefContext);
+
+ assertNotNull(foundOdlProjNameCtx);
+ assertTrue(foundOdlProjNameCtx.isReferenced());
+ assertFalse(foundOdlProjNameCtx.getAllReferencedByLeafRefCtxs().isEmpty());
+ assertEquals(6, foundOdlProjNameCtx.getAllReferencedByLeafRefCtxs().size());
+ assertEquals(leafRefCtx, foundOdlProjNameCtx);
+ }
+
+ @Test
+ public void leafRefContextUtilsTest3() {
+ final QName q16 = QName.create(tst, "con1");
+ final DataSchemaNode con1 = tstMod.getDataChildByName(q16);
+ final List<LeafRefContext> allLeafRefChilds = LeafRefContextUtils
+ .findAllLeafRefChilds(con1, rootLeafRefContext);
+
+ assertNotNull(allLeafRefChilds);
+ assertFalse(allLeafRefChilds.isEmpty());
+ assertEquals(4, allLeafRefChilds.size());
+
+ final QName q17 = QName.create(tst, "odl-contributor");
+ final DataSchemaNode odlContributorNode = tstMod.getDataChildByName(q17);
+ List<LeafRefContext> allChildsReferencedByLeafRef = LeafRefContextUtils.findAllChildsReferencedByLeafRef(
+ odlContributorNode, rootLeafRefContext);
+
+ assertNotNull(allChildsReferencedByLeafRef);
+ assertFalse(allChildsReferencedByLeafRef.isEmpty());
+ assertEquals(1, allChildsReferencedByLeafRef.size());
+
+ allChildsReferencedByLeafRef = LeafRefContextUtils.findAllChildsReferencedByLeafRef(con1, rootLeafRefContext);
+
+ assertNotNull(allChildsReferencedByLeafRef);
+ assertTrue(allChildsReferencedByLeafRef.isEmpty());
+
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void incorrectLeafRefPathTest() throws URISyntaxException, FileNotFoundException, ReactorException {
+ final File resourceFile = new File(getClass().getResource(
+ "/leafref-context-test/incorrect-modules/leafref-test.yang").toURI());
+ final File resourceDir = resourceFile.getParentFile();
+
+ final SchemaContext context = RetestUtils.parseYangSources(Arrays.asList(resourceDir.listFiles()));
+
+ LeafRefContext.create(context);
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.schema.retest;
+
+import static org.junit.Assert.assertEquals;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class InstanceIdToNodesTest {
+
+ private static final String NS = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:normalization:test";
+ private static final String REVISION = "2014-03-13";
+ private static final QName ID = QName.create(NS, REVISION, "id");
+ private static SchemaContext ctx;
+
+ private final YangInstanceIdentifier.NodeIdentifier rootContainer = new YangInstanceIdentifier.NodeIdentifier(
+ QName.create(NS, REVISION, "test"));
+ private final YangInstanceIdentifier.NodeIdentifier outerContainer = new YangInstanceIdentifier.NodeIdentifier(
+ QName.create(NS, REVISION, "outer-container"));
+ private final YangInstanceIdentifier.NodeIdentifier augmentedLeaf = new YangInstanceIdentifier.NodeIdentifier(
+ QName.create(NS, REVISION, "augmented-leaf"));
+ private final YangInstanceIdentifier.AugmentationIdentifier augmentation = new YangInstanceIdentifier.AugmentationIdentifier(
+ Collections.singleton(augmentedLeaf.getNodeType()));
+
+ private final YangInstanceIdentifier.NodeIdentifier outerList = new YangInstanceIdentifier.NodeIdentifier(
+ QName.create(NS, REVISION, "outer-list"));
+ private final YangInstanceIdentifier.NodeIdentifierWithPredicates outerListWithKey = new YangInstanceIdentifier.NodeIdentifierWithPredicates(
+ QName.create(NS, REVISION, "outer-list"), ID, 1);
+ private final YangInstanceIdentifier.NodeIdentifier choice = new YangInstanceIdentifier.NodeIdentifier(
+ QName.create(NS, REVISION, "outer-choice"));
+ private final YangInstanceIdentifier.NodeIdentifier leafFromCase = new YangInstanceIdentifier.NodeIdentifier(
+ QName.create(NS, REVISION, "one"));
+
+ private final YangInstanceIdentifier.NodeIdentifier leafList = new YangInstanceIdentifier.NodeIdentifier(
+ QName.create(NS, REVISION, "ordered-leaf-list"));
+ private final YangInstanceIdentifier.NodeWithValue leafListWithValue = new YangInstanceIdentifier.NodeWithValue(
+ leafList.getNodeType(), "abcd");
+
+ static SchemaContext createTestContext() throws URISyntaxException, FileNotFoundException, ReactorException {
+ final File resourceFile = new File(InstanceIdToNodesTest.class.getResource("/filter-test.yang").toURI());
+ return RetestUtils.parseYangSources(resourceFile);
+ }
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ ctx = createTestContext();
+
+ }
+
+ @Test
+ public void testInAugment() throws Exception {
+ final ContainerNode expectedFilter = Builders
+ .containerBuilder()
+ .withNodeIdentifier(rootContainer)
+ .withChild(
+ Builders.containerBuilder()
+ .withNodeIdentifier(outerContainer)
+ .withChild(
+ Builders.augmentationBuilder()
+ .withNodeIdentifier(augmentation)
+ .withChild(
+ Builders.leafBuilder().withNodeIdentifier(augmentedLeaf)
+ .build()).build()).build()).build();
+
+ final NormalizedNode<?, ?> filter = ImmutableNodes.fromInstanceId(ctx,
+ YangInstanceIdentifier.create(rootContainer, outerContainer, augmentation, augmentedLeaf));
+ assertEquals(expectedFilter, filter);
+ }
+
+ @Test
+ public void testInAugmentLeafOverride() throws Exception {
+ final LeafNode<Object> lastLeaf = Builders.leafBuilder().withNodeIdentifier(augmentedLeaf)
+ .withValue("randomValue").build();
+
+ final ContainerNode expectedFilter = Builders
+ .containerBuilder()
+ .withNodeIdentifier(rootContainer)
+ .withChild(
+ Builders.containerBuilder()
+ .withNodeIdentifier(outerContainer)
+ .withChild(
+ Builders.augmentationBuilder().withNodeIdentifier(augmentation)
+ .withChild(lastLeaf).build()).build()).build();
+
+ final NormalizedNode<?, ?> filter = ImmutableNodes.fromInstanceId(ctx,
+ YangInstanceIdentifier.create(rootContainer, outerContainer, augmentation, augmentedLeaf), lastLeaf);
+ assertEquals(expectedFilter, filter);
+ }
+
+ @Test
+ public void testListChoice() throws Exception {
+ final ContainerNode expectedFilter = Builders
+ .containerBuilder()
+ .withNodeIdentifier(rootContainer)
+ .withChild(
+ Builders.mapBuilder()
+ .withNodeIdentifier(outerList)
+ .withChild(
+ Builders.mapEntryBuilder()
+ .withNodeIdentifier(outerListWithKey)
+ .withChild(
+ Builders.leafBuilder()
+ .withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifier(ID))
+ .withValue(1).build())
+ .withChild(
+ Builders.choiceBuilder()
+ .withNodeIdentifier(choice)
+ .withChild(
+ Builders.leafBuilder()
+ .withNodeIdentifier(leafFromCase)
+ .build()).build()).build()).build())
+ .build();
+
+ final NormalizedNode<?, ?> filter = ImmutableNodes.fromInstanceId(ctx,
+ YangInstanceIdentifier.create(rootContainer, outerList, outerListWithKey, choice, leafFromCase));
+ assertEquals(expectedFilter, filter);
+ }
+
+ @Test
+ public void testTopContainerLastChildOverride() throws Exception {
+ final ContainerNode expectedStructure = Builders
+ .containerBuilder()
+ .withNodeIdentifier(rootContainer)
+ .withChild(
+ Builders.mapBuilder()
+ .withNodeIdentifier(outerList)
+ .withChild(
+ Builders.mapEntryBuilder()
+ .withNodeIdentifier(outerListWithKey)
+ .withChild(
+ Builders.leafBuilder()
+ .withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifier(ID))
+ .withValue(1).build())
+ .withChild(
+ Builders.choiceBuilder()
+ .withNodeIdentifier(choice)
+ .withChild(
+ Builders.leafBuilder()
+ .withNodeIdentifier(leafFromCase)
+ .build()).build()).build()).build())
+ .build();
+
+ final NormalizedNode<?, ?> filter = ImmutableNodes.fromInstanceId(ctx,
+ YangInstanceIdentifier.create(rootContainer), expectedStructure);
+ assertEquals(expectedStructure, filter);
+ }
+
+ @Test
+ public void testListLastChildOverride() throws Exception {
+ final MapEntryNode outerListEntry = Builders
+ .mapEntryBuilder()
+ .withNodeIdentifier(outerListWithKey)
+ .withChild(
+ Builders.leafBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(ID))
+ .withValue(1).build()).build();
+ final MapNode lastChild = Builders.mapBuilder().withNodeIdentifier(this.outerList).withChild(outerListEntry)
+ .build();
+ final ContainerNode expectedStructure = Builders.containerBuilder().withNodeIdentifier(rootContainer)
+ .withChild(lastChild).build();
+
+ NormalizedNode<?, ?> filter = ImmutableNodes.fromInstanceId(ctx,
+ YangInstanceIdentifier.create(rootContainer, outerList, outerListWithKey), outerListEntry);
+ assertEquals(expectedStructure, filter);
+ filter = ImmutableNodes.fromInstanceId(ctx,
+ YangInstanceIdentifier.create(rootContainer, outerList, outerListWithKey));
+ assertEquals(expectedStructure, filter);
+ }
+
+ @Test
+ public void testLeafList() throws Exception {
+ final ContainerNode expectedFilter = Builders
+ .containerBuilder()
+ .withNodeIdentifier(rootContainer)
+ .withChild(
+ Builders.orderedLeafSetBuilder()
+ .withNodeIdentifier(leafList)
+ .withChild(
+ Builders.leafSetEntryBuilder().withNodeIdentifier(leafListWithValue)
+ .withValue(leafListWithValue.getValue()).build()).build()).build();
+
+ final NormalizedNode<?, ?> filter = ImmutableNodes.fromInstanceId(ctx,
+ YangInstanceIdentifier.create(rootContainer, leafList, leafListWithValue));
+ assertEquals(expectedFilter, filter);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.schema.retest;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.data.impl.leafref.context.test.retest.LeafRefContextTreeBuilderTest;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeSchemaAwareBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeSchemaAwareBuilder;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class NormalizedDataBuilderTest {
+
+ private ContainerSchemaNode containerNode;
+ private SchemaContext schema;
+
+ @Before
+ public void setUp() throws URISyntaxException, FileNotFoundException, ReactorException {
+ final File resourceFile = new File(getClass().getResource(
+ "../test.yang").toURI());
+ schema = RetestUtils.parseYangSources(resourceFile);
+ containerNode = (ContainerSchemaNode) getSchemaNode(schema, "test", "container");
+ }
+
+ @Test
+ public void testSchemaUnaware() {
+ // Container
+ DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> builder = Builders
+ .containerBuilder().withNodeIdentifier(getNodeIdentifier("container"));
+
+ // leaf
+ LeafNode<String> leafChild = Builders.<String> leafBuilder().withNodeIdentifier(getNodeIdentifier("leaf"))
+ .withValue("String").build();
+ builder.withChild(leafChild);
+
+ // leafList
+ LeafSetNode<Integer> leafList = Builders
+ .<Integer> leafSetBuilder()
+ .withNodeIdentifier(getNodeIdentifier("leaf"))
+ .withChildValue(1)
+ .withChild(
+ Builders.<Integer> leafSetEntryBuilder()
+ .withNodeIdentifier(getNodeWithValueIdentifier("leaf", 3)).withValue(3).build())
+ .build();
+ builder.withChild(leafList);
+
+ // list
+ MapEntryNode listChild1 = Builders
+ .mapEntryBuilder()
+ .withChild(
+ Builders.<Integer> leafBuilder().withNodeIdentifier(getNodeIdentifier("uint32InList"))
+ .withValue(1).build())
+ .withChild(Builders.containerBuilder().withNodeIdentifier(getNodeIdentifier("containerInList")).build())
+ .withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifierWithPredicates(
+ getNodeIdentifier("list").getNodeType(), Collections.singletonMap(
+ getNodeIdentifier("uint32InList").getNodeType(), (Object) 1))).build();
+
+ MapNode list = Builders.mapBuilder().withChild(listChild1).withNodeIdentifier(getNodeIdentifier("list"))
+ .build();
+ builder.withChild(list);
+
+ AugmentationNode augmentation = Builders
+ .augmentationBuilder()
+ .withNodeIdentifier(
+ new YangInstanceIdentifier.AugmentationIdentifier(Sets.newHashSet(getQName("augmentUint32"))))
+ .withChild(
+ Builders.<Integer>leafBuilder().withNodeIdentifier(getNodeIdentifier("augmentUint32"))
+ .withValue(11).build()).build();
+
+ builder.withChild(augmentation);
+
+ // This works without schema (adding child from augment as a direct
+ // child)
+ builder.withChild(Builders.<Integer> leafBuilder().withNodeIdentifier(getNodeIdentifier("augmentUint32"))
+ .withValue(11).build());
+ }
+
+ @Test
+ public void testSchemaAware() {
+ DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> builder = Builders
+ .containerBuilder(containerNode);
+
+ LeafSchemaNode schemaNode = (LeafSchemaNode) getSchemaNode(schema, "test", "uint32");
+ LeafNode<String> leafChild = Builders.<String> leafBuilder(schemaNode).withValue("String").build();
+ builder.withChild(leafChild);
+
+ LeafListSchemaNode leafListSchemaNode = (LeafListSchemaNode) getSchemaNode(schema, "test", "leafList");
+ LeafSetNode<Integer> leafList = Builders.<Integer> leafSetBuilder(leafListSchemaNode).withChildValue(1)
+ .withChild(Builders.<Integer> leafSetEntryBuilder(leafListSchemaNode).withValue(3).build()).build();
+ builder.withChild(leafList);
+
+ ListSchemaNode listSchema = (ListSchemaNode) getSchemaNode(schema, "test", "list");
+ LeafSchemaNode uint32InListSchemaNode = (LeafSchemaNode) getSchemaNode(schema, "test", "uint32InList");
+ ContainerSchemaNode containerInListSchemaNode = (ContainerSchemaNode) getSchemaNode(schema, "test",
+ "containerInList");
+
+ MapEntryNode listChild1 = Builders.mapEntryBuilder(listSchema)
+ .withChild(Builders.<Integer> leafBuilder(uint32InListSchemaNode).withValue(1).build())
+ .withChild(Builders.containerBuilder(containerInListSchemaNode).build()).build();
+
+ MapNode list = ImmutableMapNodeSchemaAwareBuilder.create(listSchema).withChild(listChild1).build();
+ builder.withChild(list);
+
+ LeafSchemaNode augmentUint32SchemaNode = (LeafSchemaNode) getSchemaNode(schema, "test", "augmentUint32");
+ AugmentationSchema augmentationSchema = getAugmentationSchemaForChild(containerNode,
+ augmentUint32SchemaNode.getQName());
+
+ AugmentationNode augmentation = Builders.augmentationBuilder(augmentationSchema)
+ .withChild(Builders.<Integer> leafBuilder(augmentUint32SchemaNode).withValue(11).build()).build();
+
+ builder.withChild(augmentation);
+
+ // This should fail with schema, since the leaf comes from augmentation
+ // builder.withChild(ImmutableLeafNodeSchemaAwareBuilder.<Integer>get(augmentUint32SchemaNode).withValue(11).build());
+
+ LeafSchemaNode augumentString1SchemaNode = (LeafSchemaNode) getSchemaNode(schema, "test", "augmentString1");
+ LeafSchemaNode augumentString2SchemaNode = (LeafSchemaNode) getSchemaNode(schema, "test", "augmentString2");
+
+ ChoiceSchemaNode choice1SchemaNode = (ChoiceSchemaNode) getSchemaNode(schema, "test", "choice");
+ ChoiceNode choice = ImmutableChoiceNodeSchemaAwareBuilder.create(choice1SchemaNode)
+ .withChild(Builders.<String> leafBuilder(augumentString1SchemaNode).withValue("case1").build())
+ // This should fail, since child node belongs to different case
+ // .withChild(Builders.<String>leafBuilder(augumentString2SchemaNode).withValue("case2")
+ // .build())
+ .build();
+
+ ;
+ builder.withChild(choice);
+
+ // This should fail, child from case
+ // builder.withChild(Builders.<String>leafBuilder(augumentString1SchemaNode).withValue("case1")
+ // .build());
+ }
+
+ private static AugmentationSchema getAugmentationSchemaForChild(final ContainerSchemaNode containerNode,
+ final QName qName) {
+ for (AugmentationSchema augmentationSchema : containerNode.getAvailableAugmentations()) {
+ if (augmentationSchema.getDataChildByName(qName) != null) {
+ return augmentationSchema;
+ }
+ }
+ throw new IllegalStateException("Unable to find child augmentation in " + containerNode);
+ }
+
+ private static YangInstanceIdentifier.NodeWithValue getNodeWithValueIdentifier(final String localName,
+ final Object value) {
+ return new YangInstanceIdentifier.NodeWithValue(getQName(localName), value);
+ }
+
+ private static QName getQName(final String localName) {
+ String namespace = "namespace";
+ return new QName(URI.create(namespace), localName);
+ }
+
+ private static YangInstanceIdentifier.NodeIdentifier getNodeIdentifier(final String localName) {
+ return new YangInstanceIdentifier.NodeIdentifier(getQName(localName));
+ }
+
+ public static DataSchemaNode getSchemaNode(final SchemaContext context, final String moduleName,
+ final String childNodeName) {
+ for (Module module : context.getModules()) {
+ if (module.getName().equals(moduleName)) {
+ DataSchemaNode found = findChildNode(module.getChildNodes(), childNodeName);
+ Preconditions.checkState(found != null, "Unable to find %s", childNodeName);
+ return found;
+ }
+ }
+ throw new IllegalStateException("Unable to find child node " + childNodeName);
+ }
+
+ private static DataSchemaNode findChildNode(final Iterable<DataSchemaNode> children, final String name) {
+ List<DataNodeContainer> containers = Lists.newArrayList();
+
+ for (DataSchemaNode dataSchemaNode : children) {
+ if (dataSchemaNode.getQName().getLocalName().equals(name)) {
+ return dataSchemaNode;
+ }
+ if (dataSchemaNode instanceof DataNodeContainer) {
+ containers.add((DataNodeContainer) dataSchemaNode);
+ } else if (dataSchemaNode instanceof ChoiceSchemaNode) {
+ containers.addAll(((ChoiceSchemaNode) dataSchemaNode).getCases());
+ }
+ }
+
+ for (DataNodeContainer container : containers) {
+ DataSchemaNode retVal = findChildNode(container.getChildNodes(), name);
+ if (retVal != null) {
+ return retVal;
+ }
+ }
+
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.schema.transform.dom.serializer.retest;
+
+import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.augmentationBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.choiceBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.containerBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.leafNode;
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.net.URI;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedDataBuilderTest;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+@RunWith(Parameterized.class)
+public class NormalizedNodeXmlTranslationTest {
+ private static final Logger logger = LoggerFactory.getLogger(NormalizedNodeXmlTranslationTest.class);
+ private final SchemaContext schema;
+
+ @Parameterized.Parameters()
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {
+ { "augment_choice_hell.yang", "augment_choice_hell_ok.xml", augmentChoiceHell() },
+ { "augment_choice_hell.yang", "augment_choice_hell_ok2.xml", null },
+ { "augment_choice_hell.yang", "augment_choice_hell_ok3.xml", augmentChoiceHell2() },
+ { "test.yang", "simple.xml", null }, { "test.yang", "simple2.xml", null },
+ // TODO check attributes
+ { "test.yang", "simple_xml_with_attributes.xml", withAttributes() }
+ });
+ }
+
+ public static final String NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:test";
+ private static Date revision;
+ static {
+ try {
+ revision = new SimpleDateFormat("yyyy-MM-dd").parse("2014-03-13");
+ } catch (final ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static ContainerNode augmentChoiceHell2() {
+ final YangInstanceIdentifier.NodeIdentifier container = getNodeIdentifier("container");
+ QName augmentChoice1QName = QName.create(container.getNodeType(), "augment-choice1");
+ QName augmentChoice2QName = QName.create(augmentChoice1QName, "augment-choice2");
+ final QName containerQName = QName.create(augmentChoice1QName, "case11-choice-case-container");
+ final QName leafQName = QName.create(augmentChoice1QName, "case11-choice-case-leaf");
+
+ final YangInstanceIdentifier.AugmentationIdentifier aug1Id = new YangInstanceIdentifier.AugmentationIdentifier(
+ Sets.newHashSet(augmentChoice1QName));
+ final YangInstanceIdentifier.AugmentationIdentifier aug2Id = new YangInstanceIdentifier.AugmentationIdentifier(
+ Sets.newHashSet(augmentChoice2QName));
+ final YangInstanceIdentifier.NodeIdentifier augmentChoice1Id = new YangInstanceIdentifier.NodeIdentifier(
+ augmentChoice1QName);
+ final YangInstanceIdentifier.NodeIdentifier augmentChoice2Id = new YangInstanceIdentifier.NodeIdentifier(
+ augmentChoice2QName);
+ final YangInstanceIdentifier.NodeIdentifier containerId = new YangInstanceIdentifier.NodeIdentifier(
+ containerQName);
+
+ return containerBuilder().withNodeIdentifier(container)
+ .withChild(augmentationBuilder().withNodeIdentifier(aug1Id)
+ .withChild(choiceBuilder().withNodeIdentifier(augmentChoice1Id)
+ .withChild(augmentationBuilder().withNodeIdentifier(aug2Id)
+ .withChild(choiceBuilder().withNodeIdentifier(augmentChoice2Id)
+ .withChild(containerBuilder().withNodeIdentifier(containerId)
+ .withChild(leafNode(leafQName, "leaf-value"))
+ .build())
+ .build())
+ .build())
+ .build())
+ .build()).build();
+ }
+
+ private static ContainerNode withAttributes() {
+ final DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> b = containerBuilder();
+ b.withNodeIdentifier(getNodeIdentifier("container"));
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> listBuilder = Builders.mapBuilder().withNodeIdentifier(
+ getNodeIdentifier("list"));
+
+ final Map<QName, Object> predicates = Maps.newHashMap();
+ predicates.put(getNodeIdentifier("uint32InList").getNodeType(), 3L);
+
+ final DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> list1Builder = Builders
+ .mapEntryBuilder().withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifierWithPredicates(
+ getNodeIdentifier("list").getNodeType(), predicates));
+ final NormalizedNodeBuilder<YangInstanceIdentifier.NodeIdentifier, Object, LeafNode<Object>> uint32InListBuilder = Builders
+ .leafBuilder().withNodeIdentifier(getNodeIdentifier("uint32InList"));
+
+ list1Builder.withChild(uint32InListBuilder.withValue(3L).build());
+
+ listBuilder.withChild(list1Builder.build());
+ b.withChild(listBuilder.build());
+
+ final NormalizedNodeBuilder<YangInstanceIdentifier.NodeIdentifier, Object, LeafNode<Object>> booleanBuilder = Builders
+ .leafBuilder().withNodeIdentifier(getNodeIdentifier("boolean"));
+ booleanBuilder.withValue(false);
+ b.withChild(booleanBuilder.build());
+
+ final ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafListBuilder = Builders.leafSetBuilder()
+ .withNodeIdentifier(getNodeIdentifier("leafList"));
+
+ final NormalizedNodeBuilder<YangInstanceIdentifier.NodeWithValue, Object, LeafSetEntryNode<Object>> leafList1Builder = Builders
+ .leafSetEntryBuilder().withNodeIdentifier(
+ new YangInstanceIdentifier.NodeWithValue(getNodeIdentifier("leafList").getNodeType(), "a"));
+
+ leafList1Builder.withValue("a");
+
+ leafListBuilder.withChild(leafList1Builder.build());
+ b.withChild(leafListBuilder.build());
+
+ return b.build();
+ }
+
+ private static ContainerNode augmentChoiceHell() {
+
+ final DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> b = containerBuilder();
+ b.withNodeIdentifier(getNodeIdentifier("container"));
+
+ b.withChild(choiceBuilder()
+ .withNodeIdentifier(getNodeIdentifier("ch2"))
+ .withChild(
+ Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("c2Leaf")).withValue("2").build())
+ .withChild(
+ choiceBuilder()
+ .withNodeIdentifier(getNodeIdentifier("c2DeepChoice"))
+ .withChild(
+ Builders.leafBuilder()
+ .withNodeIdentifier(getNodeIdentifier("c2DeepChoiceCase1Leaf2"))
+ .withValue("2").build()).build()).build());
+
+ b.withChild(choiceBuilder()
+ .withNodeIdentifier(getNodeIdentifier("ch3"))
+ .withChild(
+ Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("c3Leaf")).withValue("3").build())
+ .build());
+
+ b.withChild(augmentationBuilder()
+ .withNodeIdentifier(getAugmentIdentifier("augLeaf"))
+ .withChild(
+ Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("augLeaf")).withValue("augment")
+ .build()).build());
+
+ b.withChild(augmentationBuilder()
+ .withNodeIdentifier(getAugmentIdentifier("ch"))
+ .withChild(
+ choiceBuilder()
+ .withNodeIdentifier(getNodeIdentifier("ch"))
+ .withChild(
+ Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("c1Leaf"))
+ .withValue("1").build())
+ .withChild(
+ augmentationBuilder()
+ .withNodeIdentifier(
+ getAugmentIdentifier("c1Leaf_AnotherAugment", "deepChoice"))
+ .withChild(
+ Builders.leafBuilder()
+ .withNodeIdentifier(
+ getNodeIdentifier("c1Leaf_AnotherAugment"))
+ .withValue("1").build())
+ .withChild(
+ choiceBuilder()
+ .withNodeIdentifier(getNodeIdentifier("deepChoice"))
+ .withChild(
+ Builders.leafBuilder()
+ .withNodeIdentifier(
+ getNodeIdentifier("deepLeafc1"))
+ .withValue("1").build()).build())
+ .build()).build()).build());
+
+ return b.build();
+ }
+
+ private static YangInstanceIdentifier.NodeIdentifier getNodeIdentifier(final String localName) {
+ return new YangInstanceIdentifier.NodeIdentifier(QName.create(URI.create(NAMESPACE), revision, localName));
+ }
+
+ public static YangInstanceIdentifier.AugmentationIdentifier getAugmentIdentifier(final String... childNames) {
+ final Set<QName> qn = Sets.newHashSet();
+
+ for (final String childName : childNames) {
+ qn.add(getNodeIdentifier(childName).getNodeType());
+ }
+
+ return new YangInstanceIdentifier.AugmentationIdentifier(qn);
+ }
+
+ public NormalizedNodeXmlTranslationTest(final String yangPath, final String xmlPath,
+ final ContainerNode expectedNode) throws ReactorException {
+ schema = parseTestSchema(yangPath);
+ this.xmlPath = xmlPath;
+ this.containerNode = (ContainerSchemaNode) NormalizedDataBuilderTest.getSchemaNode(schema, "test", "container");
+ this.expectedNode = expectedNode;
+ }
+
+ private final ContainerNode expectedNode;
+ private final ContainerSchemaNode containerNode;
+ private final String xmlPath;
+
+ SchemaContext parseTestSchema(final String... yangPath) throws ReactorException {
+ return RetestUtils.parseYangStreams(getTestYangs(yangPath));
+ }
+
+ List<InputStream> getTestYangs(final String... yangPaths) {
+
+ return Lists.newArrayList(Collections2.transform(Lists.newArrayList(yangPaths),
+ new Function<String, InputStream>() {
+ @Override
+ public InputStream apply(final String input) {
+ final InputStream resourceAsStream = NormalizedDataBuilderTest.class.getResourceAsStream(input);
+ Preconditions.checkNotNull(resourceAsStream, "File %s was null", resourceAsStream);
+ return resourceAsStream;
+ }
+ }));
+ }
+
+ @Test
+ public void testTranslation() throws Exception {
+ final Document doc = loadDocument(xmlPath);
+
+ final ContainerNode built = DomToNormalizedNodeParserFactory
+ .getInstance(DomUtils.defaultValueCodecProvider(), schema).getContainerNodeParser()
+ .parse(Collections.singletonList(doc.getDocumentElement()), containerNode);
+
+ if (expectedNode != null) {
+ org.junit.Assert.assertEquals(expectedNode, built);
+ }
+
+ System.err.println(built);
+ logger.info("{}", built);
+
+ final Element elementNS = XmlDocumentUtils.getDocument().createElementNS(
+ containerNode.getQName().getNamespace().toString(), containerNode.getQName().getLocalName());
+ writeNormalizedNode(built, new DOMResult(elementNS), SchemaPath.create(true), schema);
+
+ XMLUnit.setIgnoreWhitespace(true);
+ XMLUnit.setIgnoreComments(true);
+ XMLUnit.setIgnoreAttributeOrder(true);
+ XMLUnit.setNormalize(true);
+
+ System.err.println(toString(doc.getDocumentElement()));
+ System.err.println(toString(elementNS));
+
+ final Diff diff = new Diff(XMLUnit.buildControlDocument(toString(doc.getDocumentElement())),
+ XMLUnit.buildTestDocument(toString(elementNS)));
+
+ // FIXME the comparison cannot be performed, since the qualifiers supplied by XMlUnit do not work correctly in
+ // this case
+ // We need to implement custom qualifier so that the element ordering does not mess the DIFF
+ // dd.overrideElementQualifier(new MultiLevelElementNameAndTextQualifier(100, true));
+ // assertTrue(dd.toString(), dd.similar());
+ }
+
+ static final XMLOutputFactory XML_FACTORY;
+ static {
+ XML_FACTORY = XMLOutputFactory.newFactory();
+ XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false);
+ }
+
+ private static void writeNormalizedNode(final NormalizedNode<?, ?> normalized, final DOMResult result,
+ final SchemaPath schemaPath, final SchemaContext context) throws IOException, XMLStreamException {
+ NormalizedNodeWriter normalizedNodeWriter = null;
+ NormalizedNodeStreamWriter normalizedNodeStreamWriter = null;
+ XMLStreamWriter writer = null;
+ try {
+ writer = XML_FACTORY.createXMLStreamWriter(result);
+ normalizedNodeStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(writer, context, schemaPath);
+ normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(normalizedNodeStreamWriter);
+
+ normalizedNodeWriter.write(normalized);
+
+ normalizedNodeWriter.flush();
+ } finally {
+ if (normalizedNodeWriter != null) {
+ normalizedNodeWriter.close();
+ }
+ if (normalizedNodeStreamWriter != null) {
+ normalizedNodeStreamWriter.close();
+ }
+ if (writer != null) {
+ writer.close();
+ }
+ }
+ }
+
+ private static Document loadDocument(final String xmlPath) throws IOException, SAXException {
+ final InputStream resourceAsStream = NormalizedDataBuilderTest.class.getResourceAsStream(xmlPath);
+
+ final Document currentConfigElement = readXmlToDocument(resourceAsStream);
+ Preconditions.checkNotNull(currentConfigElement);
+ return currentConfigElement;
+ }
+
+ private static final DocumentBuilderFactory BUILDERFACTORY;
+
+ static {
+ final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setCoalescing(true);
+ factory.setIgnoringElementContentWhitespace(true);
+ factory.setIgnoringComments(true);
+ BUILDERFACTORY = factory;
+ }
+
+ private static Document readXmlToDocument(final InputStream xmlContent) throws IOException, SAXException {
+ final DocumentBuilder dBuilder;
+ try {
+ dBuilder = BUILDERFACTORY.newDocumentBuilder();
+ } catch (final ParserConfigurationException e) {
+ throw new RuntimeException("Failed to parse XML document", e);
+ }
+ final Document doc = dBuilder.parse(xmlContent);
+
+ doc.getDocumentElement().normalize();
+ return doc;
+ }
+
+ public static String toString(final Element xml) {
+ try {
+ final Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+
+ final StreamResult result = new StreamResult(new StringWriter());
+ final DOMSource source = new DOMSource(xml);
+ transformer.transform(source, result);
+
+ return result.getWriter().toString();
+ } catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) {
+ throw new RuntimeException("Unable to serialize xml element " + xml, e);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.schema.tree;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class RetestModel {
+
+ public static final QName TEST_QNAME = QName.create(
+ "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test", "2014-03-13", "test");
+ public static final QName OUTER_LIST_QNAME = QName.create(TEST_QNAME, "outer-list");
+ public static final QName INNER_LIST_QNAME = QName.create(TEST_QNAME, "inner-list");
+ public static final QName OUTER_CHOICE_QNAME = QName.create(TEST_QNAME, "outer-choice");
+ public static final QName ID_QNAME = QName.create(TEST_QNAME, "id");
+ public static final QName NAME_QNAME = QName.create(TEST_QNAME, "name");
+ public static final QName VALUE_QNAME = QName.create(TEST_QNAME, "value");
+ private static final String DATASTORE_TEST_YANG = "/odl-datastore-test.yang";
+
+ public static final YangInstanceIdentifier TEST_PATH = YangInstanceIdentifier.of(TEST_QNAME);
+ public static final YangInstanceIdentifier OUTER_LIST_PATH = YangInstanceIdentifier.builder(TEST_PATH)
+ .node(OUTER_LIST_QNAME).build();
+ public static final QName TWO_QNAME = QName.create(TEST_QNAME, "two");
+ public static final QName THREE_QNAME = QName.create(TEST_QNAME, "three");
+
+ public static final InputStream getDatastoreTestInputStream() {
+ return RetestModel.class.getResourceAsStream(DATASTORE_TEST_YANG);
+ }
+
+ public static SchemaContext createTestContext() throws ReactorException {
+ return RetestUtils.parseYangStreams(Arrays.asList(getDatastoreTestInputStream()));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.schema.tree;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import com.google.common.base.Optional;
+import java.io.InputStream;
+import java.util.Collections;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class Retest_Bug2690Fix {
+ private static final String ODL_DATASTORE_TEST_YANG = "/odl-datastore-test.yang";
+ private SchemaContext schemaContext;
+ private RootModificationApplyOperation rootOper;
+
+ private InMemoryDataTree inMemoryDataTree;
+
+ @Before
+ public void prepare() throws ReactorException {
+ schemaContext = createTestContext();
+ assertNotNull("Schema context must not be null.", schemaContext);
+ rootOper = RootModificationApplyOperation.from(SchemaAwareApplyOperation.from(schemaContext,
+ TreeType.OPERATIONAL));
+ inMemoryDataTree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create();
+ inMemoryDataTree.setSchemaContext(schemaContext);
+ }
+
+ public static final InputStream getDatastoreTestInputStream() {
+ return getInputStream(ODL_DATASTORE_TEST_YANG);
+ }
+
+ private static InputStream getInputStream(final String resourceName) {
+ return TestModel.class.getResourceAsStream(ODL_DATASTORE_TEST_YANG);
+ }
+
+ public static SchemaContext createTestContext() throws ReactorException {
+ return RetestUtils.parseYangStreams(Collections.singletonList(getDatastoreTestInputStream()));
+ }
+
+ @Test
+ public void testWriteMerge1() throws DataValidationFailedException {
+ final MapEntryNode fooEntryNode = ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1);
+ final MapEntryNode barEntryNode = ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2);
+ final MapNode mapNode1 = ImmutableNodes.mapNodeBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.OUTER_LIST_QNAME))
+ .withChild(fooEntryNode).build();
+ final MapNode mapNode2 = ImmutableNodes.mapNodeBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.OUTER_LIST_QNAME))
+ .withChild(barEntryNode).build();
+
+ final ContainerNode cont1 = Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
+ .withChild(mapNode1).build();
+
+ final ContainerNode cont2 = Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
+ .withChild(mapNode2).build();
+
+ final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+ modificationTree.write(TestModel.TEST_PATH, cont1);
+ modificationTree.merge(TestModel.TEST_PATH, cont2);
+ modificationTree.ready();
+
+ inMemoryDataTree.validate(modificationTree);
+ final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
+ inMemoryDataTree.commit(prepare);
+
+ final InMemoryDataTreeSnapshot snapshotAfterTx = inMemoryDataTree.takeSnapshot();
+ final InMemoryDataTreeModification modificationAfterTx = snapshotAfterTx.newModification();
+ final Optional<NormalizedNode<?, ?>> readNode = modificationAfterTx.readNode(TestModel.OUTER_LIST_PATH);
+ assertTrue(readNode.isPresent());
+ assertEquals(2, ((NormalizedNodeContainer<?,?,?>)readNode.get()).getValue().size());
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.schema.tree;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+/**
+ * BUG-3674: issuing a delete on a non-existent entry must be preserved in
+ * DataTreeModification, but should appear as UNMODIFIED in the
+ * resulting DataTreeCandidate.
+ */
+public class Retest_Bug3674Test {
+ private DataTree tree;
+
+ @Before
+ public void setUp() throws ReactorException {
+ tree = InMemoryDataTreeFactory.getInstance().create();
+ tree.setSchemaContext(RetestModel.createTestContext());
+
+ // Create the top-level container
+ final DataTreeModification mod = tree.takeSnapshot().newModification();
+ mod.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ mod.ready();
+ tree.commit(tree.prepare(mod));
+ }
+
+ @Test
+ public void testDeleteOfNonExistingNode() {
+ final DataTreeModification mod = tree.takeSnapshot().newModification();
+ mod.delete(TestModel.OUTER_LIST_PATH);
+ mod.ready();
+
+ final DataTreeCandidate candidate = tree.prepare(mod);
+ final DataTreeCandidateNode root = candidate.getRootNode();
+ assertEquals(ModificationType.UNMODIFIED, root.getModificationType());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.schema.tree;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
+import com.google.common.base.Optional;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Retest_ConcurrentTreeModificationTest {
+ private static final Logger LOG = LoggerFactory.getLogger(Retest_ConcurrentTreeModificationTest.class);
+
+ private static final Short ONE_ID = 1;
+ private static final Short TWO_ID = 2;
+
+ private static final YangInstanceIdentifier OUTER_LIST_1_PATH = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+ .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID) //
+ .build();
+
+ private static final YangInstanceIdentifier OUTER_LIST_2_PATH = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+ .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID) //
+ .build();
+
+ private static final MapEntryNode FOO_NODE = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID) //
+ .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME) //
+ .build()) //
+ .build();
+
+ private static final MapEntryNode BAR_NODE = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID) //
+ .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME) //
+ .build()) //
+ .build();
+
+ private SchemaContext schemaContext;
+ private RootModificationApplyOperation rootOper;
+ private InMemoryDataTree inMemoryDataTree;
+
+ @Before
+ public void prepare() throws ReactorException {
+ schemaContext = RetestModel.createTestContext();
+ assertNotNull("Schema context must not be null.", schemaContext);
+ rootOper = RootModificationApplyOperation.from(SchemaAwareApplyOperation.from(schemaContext,TreeType.OPERATIONAL));
+ inMemoryDataTree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create();
+ inMemoryDataTree.setSchemaContext(schemaContext);
+ }
+
+ private static ContainerNode createFooTestContainerNode() {
+ return ImmutableContainerNodeBuilder
+ .create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
+ .withChild(
+ mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
+ .withChild(FOO_NODE).build()).build();
+ }
+
+ private static ContainerNode createBarTestContainerNode() {
+ return ImmutableContainerNodeBuilder
+ .create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
+ .withChild(
+ mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
+ .withChild(BAR_NODE).build()).build();
+ }
+
+ private static <T> T assertPresentAndType(final Optional<?> potential, final Class<T> type) {
+ assertNotNull(potential);
+ assertTrue(potential.isPresent());
+ assertTrue(type.isInstance(potential.get()));
+ return type.cast(potential.get());
+ }
+
+ @Test
+ public void writeWrite1stLevelEmptyTreeTest() throws DataValidationFailedException {
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ modificationTree2.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+
+ modificationTree1.ready();
+ modificationTree2.ready();
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ try {
+ inMemoryDataTree.validate(modificationTree2);
+ fail("Exception should have been thrown.");
+ } catch (final ConflictingModificationAppliedException ex) {
+ LOG.debug("ConflictingModificationAppliedException - '{}' was thrown as expected.");
+ }
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+
+ final Optional<NormalizedNode<?, ?>> testNodeAfterCommits = modificationTree1.readNode(TestModel.TEST_PATH);
+ assertPresentAndType(testNodeAfterCommits, ContainerNode.class);
+ }
+
+ @Test
+ public void writeMerge1stLevelEmptyTreeTest() throws DataValidationFailedException {
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ modificationTree2.merge(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ inMemoryDataTree.validate(modificationTree2);
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+
+ final Optional<NormalizedNode<?, ?>> testNodeAfterCommits = modificationTree1.readNode(TestModel.TEST_PATH);
+ assertPresentAndType(testNodeAfterCommits, ContainerNode.class);
+ }
+
+ @Test
+ public void writeWriteFooBar1stLevelEmptyTreeTest() throws DataValidationFailedException {
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.write(TestModel.TEST_PATH, createFooTestContainerNode());
+ modificationTree2.write(TestModel.TEST_PATH, createBarTestContainerNode());
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ try {
+ inMemoryDataTree.validate(modificationTree2);
+ fail("Exception should have been thrown.");
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+ } catch (final ConflictingModificationAppliedException ex) {
+ LOG.debug("ConflictingModificationAppliedException - '{}' was thrown as expected.");
+ }
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
+ assertFalse(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH).isPresent());
+ }
+
+ @Test
+ public void writeMergeFooBar1stLevelEmptyTreeTest() throws DataValidationFailedException {
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.write(TestModel.TEST_PATH, createFooTestContainerNode());
+ modificationTree2.merge(TestModel.TEST_PATH, createBarTestContainerNode());
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ inMemoryDataTree.validate(modificationTree2);
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
+ }
+
+ @Test
+ public void mergeWriteFooBar1stLevelEmptyTreeTest() throws DataValidationFailedException {
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.merge(TestModel.TEST_PATH, createFooTestContainerNode());
+ modificationTree2.write(TestModel.TEST_PATH, createBarTestContainerNode());
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ try {
+ inMemoryDataTree.validate(modificationTree2);
+ fail("Exception should have been thrown.");
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+ } catch (final ConflictingModificationAppliedException ex) {
+ LOG.debug("ConflictingModificationAppliedException - '{}' was thrown as expected.");
+ }
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
+ assertFalse(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH).isPresent());
+ }
+
+ @Test
+ public void mergeMergeFooBar1stLevelEmptyTreeTest() throws DataValidationFailedException {
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.merge(TestModel.TEST_PATH, createFooTestContainerNode());
+ modificationTree2.merge(TestModel.TEST_PATH, createBarTestContainerNode());
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ inMemoryDataTree.validate(modificationTree2);
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
+ }
+
+ @Test
+ public void writeWriteFooBar1stLevelEmptyContainerTest() throws DataValidationFailedException {
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+ initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initialDataTreeModification.ready();
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.write(TestModel.TEST_PATH, createFooTestContainerNode());
+ modificationTree2.write(TestModel.TEST_PATH, createBarTestContainerNode());
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ try {
+ inMemoryDataTree.validate(modificationTree2);
+ fail("Exception should have been thrown.");
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+ } catch (final ConflictingModificationAppliedException ex) {
+ LOG.debug("ConflictingModificationAppliedException - '{}' was thrown as expected.");
+ }
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
+ assertFalse(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH).isPresent());
+ }
+
+ @Test
+ public void writeMergeFooBar1stLevelEmptyContainerTest() throws DataValidationFailedException {
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+ initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initialDataTreeModification.ready();
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.write(TestModel.TEST_PATH, createFooTestContainerNode());
+ modificationTree2.merge(TestModel.TEST_PATH, createBarTestContainerNode());
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ inMemoryDataTree.validate(modificationTree2);
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
+ }
+
+ @Test
+ public void mergeWriteFooBar1stLevelEmptyContainerTest() throws DataValidationFailedException {
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+ initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initialDataTreeModification.ready();
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.merge(TestModel.TEST_PATH, createFooTestContainerNode());
+ modificationTree2.write(TestModel.TEST_PATH, createBarTestContainerNode());
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ try {
+ inMemoryDataTree.validate(modificationTree2);
+ fail("Exception should have been thrown.");
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+ } catch (final ConflictingModificationAppliedException ex) {
+ LOG.debug("ConflictingModificationAppliedException - '{}' was thrown as expected.");
+ }
+
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
+ assertFalse(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH).isPresent());
+ }
+
+ @Test
+ public void mergeMergeFooBar1stLevelEmptyContainerTest() throws DataValidationFailedException {
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+ initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initialDataTreeModification.ready();
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.merge(TestModel.TEST_PATH, createFooTestContainerNode());
+ modificationTree2.merge(TestModel.TEST_PATH, createBarTestContainerNode());
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ inMemoryDataTree.validate(modificationTree2);
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
+ }
+
+ @Test
+ public void deleteWriteFooBar1stLevelEmptyContainerTest() throws DataValidationFailedException {
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+ initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initialDataTreeModification.ready();
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.delete(TestModel.TEST_PATH);
+ modificationTree2.write(TestModel.TEST_PATH, createBarTestContainerNode());
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ try {
+ inMemoryDataTree.validate(modificationTree2);
+ fail("Exception should have been thrown.");
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+ } catch (final ConflictingModificationAppliedException ex) {
+ LOG.debug("ConflictingModificationAppliedException - '{}' was thrown as expected.");
+ }
+
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertFalse(snapshotAfterCommits.readNode(TestModel.TEST_PATH).isPresent());
+ }
+
+ @Test
+ public void deleteMergeFooBar1stLevelEmptyContainerTest() throws DataValidationFailedException {
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+ initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initialDataTreeModification.ready();
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.delete(TestModel.TEST_PATH);
+ modificationTree2.merge(TestModel.TEST_PATH, createBarTestContainerNode());
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ inMemoryDataTree.validate(modificationTree2);
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
+ }
+
+ @Test
+ public void writeWriteFooBar2ndLevelEmptyContainerTest() throws DataValidationFailedException {
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+ initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initialDataTreeModification.write(TestModel.OUTER_LIST_PATH, mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+ initialDataTreeModification.ready();
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.write(OUTER_LIST_1_PATH, FOO_NODE);
+ modificationTree2.write(OUTER_LIST_2_PATH, BAR_NODE);
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ inMemoryDataTree.validate(modificationTree2);
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
+ }
+
+ @Test
+ public void writeMergeFooBar2ndLevelEmptyContainerTest() throws DataValidationFailedException {
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+ initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initialDataTreeModification.write(TestModel.OUTER_LIST_PATH, mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+ initialDataTreeModification.ready();
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.write(OUTER_LIST_1_PATH, FOO_NODE);
+ modificationTree2.merge(OUTER_LIST_2_PATH, BAR_NODE);
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ inMemoryDataTree.validate(modificationTree2);
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
+ }
+
+ @Test
+ public void mergeWriteFooBar2ndLevelEmptyContainerTest() throws DataValidationFailedException {
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+ initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initialDataTreeModification.write(TestModel.OUTER_LIST_PATH, mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+ initialDataTreeModification.ready();
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.merge(OUTER_LIST_1_PATH, FOO_NODE);
+ modificationTree2.write(OUTER_LIST_2_PATH, BAR_NODE);
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ inMemoryDataTree.validate(modificationTree2);
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
+ }
+
+ @Test
+ public void mergeMergeFooBar2ndLevelEmptyContainerTest() throws DataValidationFailedException {
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+ initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initialDataTreeModification.write(TestModel.OUTER_LIST_PATH, mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+ initialDataTreeModification.ready();
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.merge(OUTER_LIST_1_PATH, FOO_NODE);
+ modificationTree2.merge(OUTER_LIST_2_PATH, BAR_NODE);
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ inMemoryDataTree.validate(modificationTree2);
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_1_PATH), MapEntryNode.class);
+ assertPresentAndType(snapshotAfterCommits.readNode(OUTER_LIST_2_PATH), MapEntryNode.class);
+ }
+
+ @Test
+ public void deleteWriteFooBar2ndLevelEmptyContainerTest() throws DataValidationFailedException {
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+ initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initialDataTreeModification.write(TestModel.OUTER_LIST_PATH, mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+ initialDataTreeModification.ready();
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.delete(TestModel.TEST_PATH);
+ modificationTree2.merge(OUTER_LIST_2_PATH, BAR_NODE);
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ try {
+ inMemoryDataTree.validate(modificationTree2);
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+ fail("Exception should have been thrown");
+ } catch (final Exception e) {
+ LOG.debug("Exception was thrown because path no longer exist in tree");
+ }
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertFalse(snapshotAfterCommits.readNode(TestModel.TEST_PATH).isPresent());
+ }
+
+ @Test
+ public void deleteMergeFooBar2ndLevelEmptyContainerTest() throws DataValidationFailedException {
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree.takeSnapshot().newModification();
+ initialDataTreeModification.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initialDataTreeModification.write(TestModel.OUTER_LIST_PATH, mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+ initialDataTreeModification.ready();
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(initialDataTreeModification));
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+
+ final DataTreeModification modificationTree1 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+ final DataTreeModification modificationTree2 = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree1.delete(TestModel.TEST_PATH);
+ modificationTree2.merge(OUTER_LIST_2_PATH, BAR_NODE);
+ modificationTree1.ready();
+ modificationTree2.ready();
+
+ inMemoryDataTree.validate(modificationTree1);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree1);
+ inMemoryDataTree.commit(prepare1);
+
+ try {
+ inMemoryDataTree.validate(modificationTree2);
+ final DataTreeCandidate prepare2 = inMemoryDataTree.prepare(modificationTree2);
+ inMemoryDataTree.commit(prepare2);
+ fail("Exception should have been thrown");
+ } catch (final Exception e) {
+ LOG.debug("Exception was thrown because path no longer exist in tree");
+ }
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot();
+ assertFalse(snapshotAfterCommits.readNode(TestModel.TEST_PATH).isPresent());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.schema.tree;
+
+import static org.junit.Assert.assertNotNull;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.leafNode;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+// TODO: expand these tests to catch some more obscure cases
+public class Retest_ConfigStatementValidationTest {
+ private static final Logger LOG = LoggerFactory.getLogger(Retest_ConfigStatementValidationTest.class);
+
+ private static final Short ONE_ID = 1;
+ private static final Short TWO_ID = 2;
+
+ private static final YangInstanceIdentifier OUTER_LIST_1_PATH = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+ .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID) //
+ .build();
+
+ private static final YangInstanceIdentifier OUTER_LIST_2_PATH = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+ .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID) //
+ .build();
+
+ private static final MapEntryNode INNER_FOO_ENTRY_NODE =
+ ImmutableNodes.mapEntry(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "foo");
+
+ private static final MapEntryNode INNER_BAR_ENTRY_NODE =
+ ImmutableNodes.mapEntryBuilder(QName.create(TestModel.TEST_QNAME, "inner-list2"), TestModel.NAME_QNAME, "foo")
+ .withChild(ImmutableNodes.leafNode(TestModel.VALUE_QNAME, "value")).build();
+
+ private static final MapEntryNode FOO_NODE = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID) //
+ .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(INNER_FOO_ENTRY_NODE) //
+ .build()) //
+ .build();
+
+ private static final MapEntryNode BAR_NODE = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID) //
+ .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(INNER_BAR_ENTRY_NODE) //
+ .build()) //
+ .build();
+
+ private SchemaContext schemaContext;
+
+ private ContainerNode createFooTestContainerNode() {
+ return ImmutableContainerNodeBuilder
+ .create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
+ .withChild(
+ mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
+ .withChild(FOO_NODE).build()).build();
+ }
+
+ private ContainerNode createBarTestContainerNode() {
+ return ImmutableContainerNodeBuilder
+ .create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
+ .withChild(
+ mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
+ .withChild(BAR_NODE).build()).build();
+ }
+
+ @Before
+ public void prepare() throws ReactorException {
+ schemaContext = RetestModel.createTestContext();
+ assertNotNull("Schema context must not be null.", schemaContext);
+ }
+
+ @Test(expected=SchemaValidationFailedException.class)
+ public void testOnPathFail() throws DataValidationFailedException {
+ final InMemoryDataTree inMemoryDataTree =
+ (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION);
+ inMemoryDataTree.setSchemaContext(schemaContext);
+ final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+ final YangInstanceIdentifier ii = OUTER_LIST_1_PATH.node(new YangInstanceIdentifier.NodeIdentifier(TestModel.INNER_LIST_QNAME))
+ .node(INNER_FOO_ENTRY_NODE.getIdentifier());
+ modificationTree.write(ii, INNER_FOO_ENTRY_NODE);
+
+ inMemoryDataTree.validate(modificationTree);
+ final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
+ inMemoryDataTree.commit(prepare);
+ }
+
+ @Test(expected=SchemaValidationFailedException.class)
+ public void testOnDataFail() throws DataValidationFailedException {
+ final InMemoryDataTree inMemoryDataTree =
+ (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION);
+ inMemoryDataTree.setSchemaContext(schemaContext);
+ final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+ modificationTree.write(TestModel.TEST_PATH, createFooTestContainerNode());
+ modificationTree.ready();
+ inMemoryDataTree.validate(modificationTree);
+ final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
+ inMemoryDataTree.commit(prepare);
+ }
+
+ @Test(expected=SchemaValidationFailedException.class)
+ public void testOnDataLeafFail() throws DataValidationFailedException {
+ final InMemoryDataTree inMemoryDataTree =
+ (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION);
+ inMemoryDataTree.setSchemaContext(schemaContext);
+ final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+ modificationTree.write(TestModel.TEST_PATH, createBarTestContainerNode());
+ modificationTree.ready();
+ inMemoryDataTree.validate(modificationTree);
+ final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
+ inMemoryDataTree.commit(prepare);
+ }
+
+ @Test(expected=SchemaValidationFailedException.class)
+ public void testOnPathCaseLeafFail() throws DataValidationFailedException {
+ final InMemoryDataTree inMemoryDataTree =
+ (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION);
+ inMemoryDataTree.setSchemaContext(schemaContext);
+ final YangInstanceIdentifier.NodeIdentifier choice1Id = new YangInstanceIdentifier.NodeIdentifier(
+ QName.create(TestModel.TEST_QNAME, "choice1"));
+ final YangInstanceIdentifier.NodeIdentifier case2ContId = new YangInstanceIdentifier.NodeIdentifier(
+ QName.create(TestModel.TEST_QNAME, "case2-cont"));
+ final YangInstanceIdentifier ii = TestModel.TEST_PATH.node(choice1Id).node(case2ContId);
+ final ContainerNode case2Cont = Builders.containerBuilder().withNodeIdentifier(case2ContId)
+ .withChild(leafNode(QName.create(TestModel.TEST_QNAME, "case2-leaf1"), "leaf-value")).build();
+
+ final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+ modificationTree.write(ii, case2Cont);
+
+ inMemoryDataTree.validate(modificationTree);
+ final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
+ inMemoryDataTree.commit(prepare);
+ }
+
+ @Test(expected=SchemaValidationFailedException.class)
+ public void testOnDataCaseLeafFail() throws DataValidationFailedException {
+ final InMemoryDataTree inMemoryDataTree =
+ (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION);
+ inMemoryDataTree.setSchemaContext(schemaContext);
+ final YangInstanceIdentifier.NodeIdentifier choice1Id = new YangInstanceIdentifier.NodeIdentifier(
+ QName.create(TestModel.TEST_QNAME, "choice1"));
+ final YangInstanceIdentifier ii = TestModel.TEST_PATH.node(choice1Id);
+ final ChoiceNode choice1 = Builders.choiceBuilder().withNodeIdentifier(choice1Id)
+ .withChild(leafNode(QName.create(TestModel.TEST_QNAME, "case1-leaf1"), "leaf-value")).build();
+
+ final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+ modificationTree.write(ii, choice1);
+ modificationTree.ready();
+ inMemoryDataTree.validate(modificationTree);
+ final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
+ inMemoryDataTree.commit(prepare);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.schema.tree;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModifiedNodeDoesNotExistException;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class Retest_ErrorReportingTest {
+
+ private InMemoryDataTree tree;
+
+ @Before
+ public void setup() throws ReactorException {
+ tree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create();
+ tree.setSchemaContext(RetestModel.createTestContext());
+ }
+
+ @Test
+ public void writeWithoutParentExisting() {
+ InMemoryDataTreeModification modification = tree.takeSnapshot().newModification();
+ // We write node without creating parent
+ modification.write(TestModel.OUTER_LIST_PATH, ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+ modification.ready();
+ try {
+ tree.validate(modification);
+ fail("ModifiedNodeDoesNotExistException should be raised");
+ } catch (ModifiedNodeDoesNotExistException e) {
+ assertEquals(TestModel.TEST_PATH, e.getPath());
+ } catch (DataValidationFailedException e) {
+ fail("ModifiedNodeDoesNotExistException expected");
+ }
+ }
+
+ @Test
+ public void parentConcurrentlyDeletedExisting() {
+ InMemoryDataTreeModification initial = tree.takeSnapshot().newModification();
+ // We write node without creating parent
+ initial.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initial.ready();
+ // We commit transaction
+ tree.commit(tree.prepare(initial));
+
+ InMemoryDataTreeModification writeTx = tree.takeSnapshot().newModification();
+ InMemoryDataTreeModification deleteTx = tree.takeSnapshot().newModification();
+ deleteTx.delete(TestModel.TEST_PATH);
+ deleteTx.ready();
+ // We commit delete modification
+ tree.commit(tree.prepare(deleteTx));
+
+ writeTx.write(TestModel.OUTER_LIST_PATH, ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+ writeTx.ready();
+ try {
+ tree.validate(writeTx);
+ fail("ConflictingModificationAppliedException should be raised");
+ } catch (ConflictingModificationAppliedException e) {
+ assertEquals(TestModel.TEST_PATH, e.getPath());
+ } catch (DataValidationFailedException e) {
+ fail("ConflictingModificationAppliedException expected");
+ }
+
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.schema.tree;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import com.google.common.base.Optional;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
+import org.opendaylight.yangtools.yang.data.impl.RetestUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Retest_ListConstraintsValidation {
+ private static final Logger LOG = LoggerFactory.getLogger(Retest_ListConstraintsValidation.class);
+
+ private static final String CONSTRAINTS_VALIDATION_TEST_YANG = "/list-constraints-validation-test-model.yang";
+ private SchemaContext schemaContext;
+ private RootModificationApplyOperation rootOper;
+
+ private InMemoryDataTree inMemoryDataTree;
+
+ private static final QName MASTER_CONTAINER_QNAME = QName.create(
+ "urn:opendaylight:params:xml:ns:yang:list-constraints-validation-test-model", "2015-02-02",
+ "master-container");
+ private static final QName MIN_MAX_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-list");
+ private static final QName MIN_MAX_KEY_LEAF_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-key-leaf");
+ private static final QName UNBOUNDED_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "unbounded-list");
+ private static final QName UNBOUNDED_KEY_LEAF_QNAME = QName.create(MASTER_CONTAINER_QNAME, "unbounded-key-leaf");
+ private static final QName MIN_MAX_LEAF_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "min-max-leaf-list");
+ private static final QName UNBOUNDED_LEAF_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "unbounded-leaf-list");
+ private static final QName UNKEYED_LIST_QNAME = QName.create(MASTER_CONTAINER_QNAME, "unkeyed-list");
+ private static final QName UNKEYED_LEAF_QNAME = QName.create(MASTER_CONTAINER_QNAME, "unkeyed-leaf");
+
+ private static final YangInstanceIdentifier MASTER_CONTAINER_PATH = YangInstanceIdentifier
+ .of(MASTER_CONTAINER_QNAME);
+ private static final YangInstanceIdentifier MIN_MAX_LIST_PATH = YangInstanceIdentifier
+ .builder(MASTER_CONTAINER_PATH).node(MIN_MAX_LIST_QNAME).build();
+ private static final YangInstanceIdentifier UNBOUNDED_LIST_PATH = YangInstanceIdentifier
+ .builder(MASTER_CONTAINER_PATH).node(UNBOUNDED_LIST_QNAME).build();
+ private static final YangInstanceIdentifier MIN_MAX_LEAF_LIST_PATH = YangInstanceIdentifier
+ .builder(MASTER_CONTAINER_PATH).node(MIN_MAX_LEAF_LIST_QNAME).build();
+ private static final YangInstanceIdentifier UNBOUNDED_LEAF_LIST_PATH = YangInstanceIdentifier
+ .builder(MASTER_CONTAINER_PATH).node(UNBOUNDED_LEAF_LIST_QNAME).build();
+ private static final YangInstanceIdentifier UNKEYED_LIST_PATH = YangInstanceIdentifier
+ .builder(MASTER_CONTAINER_PATH).node(UNKEYED_LIST_QNAME).build();
+
+ @Before
+ public void prepare() throws ReactorException {
+ schemaContext = createTestContext();
+ assertNotNull("Schema context must not be null.", schemaContext);
+ rootOper = RootModificationApplyOperation.from(SchemaAwareApplyOperation.from(schemaContext, TreeType.OPERATIONAL));
+ inMemoryDataTree = (InMemoryDataTree) InMemoryDataTreeFactory.getInstance().create();
+ inMemoryDataTree.setSchemaContext(schemaContext);
+ final InMemoryDataTreeSnapshot initialDataTreeSnapshot = inMemoryDataTree.takeSnapshot();
+ final DataTreeModification modificationTree = new InMemoryDataTreeModification(initialDataTreeSnapshot,
+ rootOper);
+
+ modificationTree.write(MASTER_CONTAINER_PATH, ImmutableNodes.containerNode(MASTER_CONTAINER_QNAME));
+ modificationTree.ready();
+ inMemoryDataTree.commit(inMemoryDataTree.prepare(modificationTree));
+ }
+
+ public static final InputStream getDatastoreTestInputStream() {
+ return getInputStream(CONSTRAINTS_VALIDATION_TEST_YANG);
+ }
+
+ private static InputStream getInputStream(final String resourceName) {
+ return TestModel.class.getResourceAsStream(CONSTRAINTS_VALIDATION_TEST_YANG);
+ }
+
+ public static SchemaContext createTestContext() throws ReactorException {
+ return RetestUtils.parseYangStreams(Collections.singletonList(getDatastoreTestInputStream()));
+ }
+
+ @Test
+ public void minMaxListTestPass() throws DataValidationFailedException {
+
+ final MapEntryNode fooEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME, "foo");
+ final MapEntryNode barEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME, "bar");
+ final MapNode mapNode1 = ImmutableNodes.mapNodeBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(MIN_MAX_LIST_QNAME))
+ .withChild(fooEntryNode).build();
+ final MapNode mapNode2 = ImmutableNodes.mapNodeBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(MIN_MAX_LIST_QNAME))
+ .withChild(barEntryNode).build();
+
+ final InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+ modificationTree.write(MIN_MAX_LIST_PATH, mapNode1);
+ modificationTree.merge(MIN_MAX_LIST_PATH, mapNode2);
+ // TODO: check why write and then merge on list commits only "bar" child
+ modificationTree.ready();
+
+ inMemoryDataTree.validate(modificationTree);
+ final DataTreeCandidate prepare = inMemoryDataTree.prepare(modificationTree);
+ inMemoryDataTree.commit(prepare);
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
+ final Optional<NormalizedNode<?, ?>> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_PATH);
+ assertTrue(minMaxListRead.isPresent());
+ assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 2);
+ }
+
+ @Test(expected=DataValidationFailedException.class)
+ public void minMaxListFail() throws DataValidationFailedException {
+ InMemoryDataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+
+ final MapEntryNode fooEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME, "foo");
+ final MapEntryNode barEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME, "bar");
+ final MapEntryNode gooEntryNode = ImmutableNodes.mapEntry(MIN_MAX_LIST_QNAME, MIN_MAX_KEY_LEAF_QNAME, "goo");
+ final MapNode mapNode = ImmutableNodes.mapNodeBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(MIN_MAX_LIST_QNAME))
+ .withChild(fooEntryNode).build();
+
+ final YangInstanceIdentifier fooPath = MIN_MAX_LIST_PATH.node(fooEntryNode.getIdentifier());
+ final YangInstanceIdentifier barPath = MIN_MAX_LIST_PATH.node(barEntryNode.getIdentifier());
+ final YangInstanceIdentifier gooPath = MIN_MAX_LIST_PATH.node(gooEntryNode.getIdentifier());
+
+ modificationTree.write(MIN_MAX_LIST_PATH, mapNode);
+ modificationTree.merge(barPath, barEntryNode);
+ modificationTree.write(gooPath, gooEntryNode);
+ modificationTree.delete(gooPath);
+ modificationTree.ready();
+
+ inMemoryDataTree.validate(modificationTree);
+ DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree);
+ inMemoryDataTree.commit(prepare1);
+
+ InMemoryDataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
+ Optional<NormalizedNode<?, ?>> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_PATH);
+ assertTrue(minMaxListRead.isPresent());
+ assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 2);
+
+ modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+ modificationTree.write(gooPath, gooEntryNode);
+ modificationTree.ready();
+
+ inMemoryDataTree.validate(modificationTree);
+ prepare1 = inMemoryDataTree.prepare(modificationTree);
+ inMemoryDataTree.commit(prepare1);
+
+ snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
+ minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_PATH);
+ assertTrue(minMaxListRead.isPresent());
+ assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 3);
+
+ modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+
+ modificationTree.delete(gooPath);
+ modificationTree.delete(fooPath);
+ modificationTree.ready();
+
+ inMemoryDataTree.validate(modificationTree);
+ }
+
+ @Test
+ public void minMaxLeafListPass() throws DataValidationFailedException {
+ final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+
+ final YangInstanceIdentifier.NodeWithValue barPath = new YangInstanceIdentifier.NodeWithValue(MIN_MAX_LIST_QNAME, "bar");
+ final YangInstanceIdentifier.NodeWithValue gooPath = new YangInstanceIdentifier.NodeWithValue(MIN_MAX_LIST_QNAME, "goo");
+
+ final LeafSetEntryNode<Object> barLeafSetEntry = ImmutableLeafSetEntryNodeBuilder.create()
+ .withNodeIdentifier(barPath)
+ .withValue("bar").build();
+ final LeafSetEntryNode<Object> gooLeafSetEntry = ImmutableLeafSetEntryNodeBuilder.create()
+ .withNodeIdentifier(gooPath)
+ .withValue("goo").build();
+
+ final LeafSetNode<Object> fooLeafSetNode = ImmutableLeafSetNodeBuilder.create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME))
+ .withChildValue("foo").build();
+
+ modificationTree.write(MIN_MAX_LEAF_LIST_PATH, fooLeafSetNode);
+ modificationTree.write(MIN_MAX_LEAF_LIST_PATH.node(barPath), barLeafSetEntry);
+ modificationTree.merge(MIN_MAX_LEAF_LIST_PATH.node(gooPath), gooLeafSetEntry);
+ modificationTree.delete(MIN_MAX_LEAF_LIST_PATH.node(gooPath));
+ modificationTree.ready();
+
+ inMemoryDataTree.validate(modificationTree);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree);
+ inMemoryDataTree.commit(prepare1);
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
+ final Optional<NormalizedNode<?, ?>> masterContainer = snapshotAfterCommit.readNode(MASTER_CONTAINER_PATH);
+ assertTrue(masterContainer.isPresent());
+ final Optional<NormalizedNodeContainer<?, ?, ?>> leafList = ((NormalizedNodeContainer) masterContainer.get()).getChild(
+ new YangInstanceIdentifier.NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME));
+ assertTrue(leafList.isPresent());
+ assertTrue(leafList.get().getValue().size() == 2);
+ }
+
+ @Test(expected=DataValidationFailedException.class)
+ public void minMaxLeafListFail() throws DataValidationFailedException {
+ final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+
+ final YangInstanceIdentifier.NodeWithValue fooPath = new YangInstanceIdentifier.NodeWithValue(MIN_MAX_LIST_QNAME, "foo");
+ final YangInstanceIdentifier.NodeWithValue barPath = new YangInstanceIdentifier.NodeWithValue(MIN_MAX_LIST_QNAME, "bar");
+ final YangInstanceIdentifier.NodeWithValue gooPath = new YangInstanceIdentifier.NodeWithValue(MIN_MAX_LIST_QNAME, "goo");
+ final YangInstanceIdentifier.NodeWithValue fuuPath = new YangInstanceIdentifier.NodeWithValue(MIN_MAX_LIST_QNAME, "fuu");
+
+ final LeafSetEntryNode<Object> barLeafSetEntry = ImmutableLeafSetEntryNodeBuilder.create()
+ .withNodeIdentifier(barPath)
+ .withValue("bar").build();
+ final LeafSetEntryNode<Object> gooLeafSetEntry = ImmutableLeafSetEntryNodeBuilder.create()
+ .withNodeIdentifier(gooPath)
+ .withValue("goo").build();
+ final LeafSetEntryNode<Object> fuuLeafSetEntry = ImmutableLeafSetEntryNodeBuilder.create()
+ .withNodeIdentifier(fuuPath)
+ .withValue("fuu").build();
+
+ final LeafSetNode<Object> fooLeafSetNode = ImmutableLeafSetNodeBuilder.create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME))
+ .withChildValue("foo").build();
+
+ modificationTree.write(MIN_MAX_LEAF_LIST_PATH, fooLeafSetNode);
+ modificationTree.write(MIN_MAX_LEAF_LIST_PATH.node(barPath), barLeafSetEntry);
+ modificationTree.merge(MIN_MAX_LEAF_LIST_PATH.node(gooPath), gooLeafSetEntry);
+ modificationTree.write(MIN_MAX_LEAF_LIST_PATH.node(fuuPath), fuuLeafSetEntry);
+ modificationTree.ready();
+
+ inMemoryDataTree.validate(modificationTree);
+ }
+
+ @Test
+ public void unkeyedListTestPass() throws DataValidationFailedException {
+ final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+
+ final UnkeyedListEntryNode foo = ImmutableUnkeyedListEntryNodeBuilder.create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(UNKEYED_LEAF_QNAME))
+ .withChild(ImmutableNodes.leafNode(UNKEYED_LEAF_QNAME, "foo")).build();
+ final List<UnkeyedListEntryNode> unkeyedEntries = new ArrayList<>();
+ unkeyedEntries.add(foo);
+ final UnkeyedListNode unkeyedListNode = ImmutableUnkeyedListNodeBuilder.create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(UNKEYED_LIST_QNAME))
+ .withValue(unkeyedEntries).build();
+
+ modificationTree.write(MASTER_CONTAINER_PATH, ImmutableNodes.containerNode(MASTER_CONTAINER_QNAME));
+ modificationTree.merge(UNKEYED_LIST_PATH, unkeyedListNode);
+ modificationTree.ready();
+
+ inMemoryDataTree.validate(modificationTree);
+ final DataTreeCandidate prepare1 = inMemoryDataTree.prepare(modificationTree);
+ inMemoryDataTree.commit(prepare1);
+
+ final InMemoryDataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
+ final Optional<NormalizedNode<?, ?>> unkeyedListRead = snapshotAfterCommit.readNode(UNKEYED_LIST_PATH);
+ assertTrue(unkeyedListRead.isPresent());
+ assertTrue(((UnkeyedListNode) unkeyedListRead.get()).getSize() == 1);
+ }
+
+ @Test(expected=DataValidationFailedException.class)
+ public void unkeyedListTestFail() throws DataValidationFailedException {
+ final DataTreeModification modificationTree = inMemoryDataTree.takeSnapshot().newModification();
+
+ final UnkeyedListEntryNode foo = ImmutableUnkeyedListEntryNodeBuilder.create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(UNKEYED_LEAF_QNAME))
+ .withChild(ImmutableNodes.leafNode(UNKEYED_LEAF_QNAME, "foo")).build();
+ final UnkeyedListEntryNode bar = ImmutableUnkeyedListEntryNodeBuilder.create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(UNKEYED_LEAF_QNAME))
+ .withChild(ImmutableNodes.leafNode(UNKEYED_LEAF_QNAME, "bar")).build();
+ final List<UnkeyedListEntryNode> unkeyedEntries = new ArrayList<>();
+ unkeyedEntries.add(foo);
+ unkeyedEntries.add(bar);
+ final UnkeyedListNode unkeyedListNode = ImmutableUnkeyedListNodeBuilder.create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(UNKEYED_LIST_QNAME))
+ .withValue(unkeyedEntries).build();
+
+ modificationTree.write(UNKEYED_LIST_PATH, unkeyedListNode);
+ modificationTree.ready();
+
+ inMemoryDataTree.validate(modificationTree);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.schema.tree;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
+
+import com.google.common.base.Optional;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNodeFactory;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+/**
+ *
+ * Schema structure of document is
+ *
+ * <pre>
+ * container root {Â
+ * list list-a {
+ * key leaf-a;
+ * leaf leaf-a;
+ * choice choice-a {
+ * case one {
+ * leaf one;
+ * }
+ * case two-three {
+ * leaf two;
+ * leaf three;
+ * }
+ * }
+ * list list-b {
+ * key leaf-b;
+ * leaf leaf-b;
+ * }
+ * }
+ * }
+ * </pre>
+ *
+ */
+public class Retest_ModificationMetadataTreeTest {
+
+ private static final Short ONE_ID = 1;
+ private static final Short TWO_ID = 2;
+ private static final String TWO_ONE_NAME = "one";
+ private static final String TWO_TWO_NAME = "two";
+
+ private static final YangInstanceIdentifier OUTER_LIST_1_PATH = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+ .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID) //
+ .build();
+
+ private static final YangInstanceIdentifier OUTER_LIST_2_PATH = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+ .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID) //
+ .build();
+
+ private static final YangInstanceIdentifier TWO_TWO_PATH = YangInstanceIdentifier.builder(OUTER_LIST_2_PATH)
+ .node(TestModel.INNER_LIST_QNAME) //
+ .nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, TWO_TWO_NAME) //
+ .build();
+
+ private static final YangInstanceIdentifier TWO_TWO_VALUE_PATH = YangInstanceIdentifier.builder(TWO_TWO_PATH)
+ .node(TestModel.VALUE_QNAME) //
+ .build();
+
+ private static final MapEntryNode BAR_NODE = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID) //
+ .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME) //
+ .withChild(mapEntry(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, TWO_ONE_NAME)) //
+ .withChild(mapEntry(TestModel.INNER_LIST_QNAME,TestModel.NAME_QNAME, TWO_TWO_NAME)) //
+ .build()) //
+ .build();
+
+ private SchemaContext schemaContext;
+ private RootModificationApplyOperation rootOper;
+
+ @Before
+ public void prepare() throws ReactorException {
+ schemaContext = RetestModel.createTestContext();
+ assertNotNull("Schema context must not be null.", schemaContext);
+ rootOper = RootModificationApplyOperation.from(SchemaAwareApplyOperation.from(schemaContext, TreeType.OPERATIONAL));
+ }
+
+ /**
+ * Returns a test document
+ *
+ * <pre>
+ * test
+ * outer-list
+ * id 1
+ * outer-list
+ * id 2
+ * inner-list
+ * name "one"
+ * inner-list
+ * name "two"
+ *
+ * </pre>
+ *
+ * @return
+ */
+ public NormalizedNode<?, ?> createDocumentOne() {
+ return ImmutableContainerNodeBuilder
+ .create()
+ .withNodeIdentifier(new NodeIdentifier(schemaContext.getQName()))
+ .withChild(createTestContainer()).build();
+
+ }
+
+ private static ContainerNode createTestContainer() {
+ return ImmutableContainerNodeBuilder
+ .create()
+ .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
+ .withChild(
+ mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
+ .withChild(mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID))
+ .withChild(BAR_NODE).build()).build();
+ }
+
+ @Test
+ public void basicReadWrites() {
+ final DataTreeModification modificationTree = new InMemoryDataTreeModification(new InMemoryDataTreeSnapshot(schemaContext,
+ TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper),
+ rootOper);
+ final Optional<NormalizedNode<?, ?>> originalBarNode = modificationTree.readNode(OUTER_LIST_2_PATH);
+ assertTrue(originalBarNode.isPresent());
+ assertSame(BAR_NODE, originalBarNode.get());
+
+ // writes node to /outer-list/1/inner_list/two/value
+ modificationTree.write(TWO_TWO_VALUE_PATH, ImmutableNodes.leafNode(TestModel.VALUE_QNAME, "test"));
+
+ // reads node to /outer-list/1/inner_list/two/value
+ // and checks if node is already present
+ final Optional<NormalizedNode<?, ?>> barTwoCModified = modificationTree.readNode(TWO_TWO_VALUE_PATH);
+ assertTrue(barTwoCModified.isPresent());
+ assertEquals(ImmutableNodes.leafNode(TestModel.VALUE_QNAME, "test"), barTwoCModified.get());
+
+ // delete node to /outer-list/1/inner_list/two/value
+ modificationTree.delete(TWO_TWO_VALUE_PATH);
+ final Optional<NormalizedNode<?, ?>> barTwoCAfterDelete = modificationTree.readNode(TWO_TWO_VALUE_PATH);
+ assertFalse(barTwoCAfterDelete.isPresent());
+ }
+
+
+ public DataTreeModification createEmptyModificationTree() {
+ /**
+ * Creates empty Snapshot with associated schema context.
+ */
+ final DataTree t = InMemoryDataTreeFactory.getInstance().create();
+ t.setSchemaContext(schemaContext);
+
+ /**
+ *
+ * Creates Mutable Data Tree based on provided snapshot and schema
+ * context.
+ *
+ */
+ return t.takeSnapshot().newModification();
+ }
+
+ @Test
+ public void createFromEmptyState() {
+
+ final DataTreeModification modificationTree = createEmptyModificationTree();
+ /**
+ * Writes empty container node to /test
+ *
+ */
+ modificationTree.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+
+ /**
+ * Writes empty list node to /test/outer-list
+ */
+ modificationTree.write(TestModel.OUTER_LIST_PATH, ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+
+ /**
+ * Reads list node from /test/outer-list
+ */
+ final Optional<NormalizedNode<?, ?>> potentialOuterList = modificationTree.readNode(TestModel.OUTER_LIST_PATH);
+ assertTrue(potentialOuterList.isPresent());
+
+ /**
+ * Reads container node from /test and verifies that it contains test
+ * node
+ */
+ final Optional<NormalizedNode<?, ?>> potentialTest = modificationTree.readNode(TestModel.TEST_PATH);
+ final ContainerNode containerTest = assertPresentAndType(potentialTest, ContainerNode.class);
+
+ /**
+ *
+ * Gets list from returned snapshot of /test and verifies it contains
+ * outer-list
+ *
+ */
+ assertPresentAndType(containerTest.getChild(new NodeIdentifier(TestModel.OUTER_LIST_QNAME)), MapNode.class);
+
+ }
+
+ @Test
+ public void writeSubtreeReadChildren() {
+ final DataTreeModification modificationTree = createEmptyModificationTree();
+ modificationTree.write(TestModel.TEST_PATH, createTestContainer());
+ final Optional<NormalizedNode<?, ?>> potential = modificationTree.readNode(TWO_TWO_PATH);
+ assertPresentAndType(potential, MapEntryNode.class);
+ }
+
+ @Test
+ public void writeSubtreeDeleteChildren() {
+ final DataTreeModification modificationTree = createEmptyModificationTree();
+ modificationTree.write(TestModel.TEST_PATH, createTestContainer());
+
+ // We verify data are present
+ final Optional<NormalizedNode<?, ?>> potentialBeforeDelete = modificationTree.readNode(TWO_TWO_PATH);
+ assertPresentAndType(potentialBeforeDelete, MapEntryNode.class);
+
+ modificationTree.delete(TWO_TWO_PATH);
+ final Optional<NormalizedNode<?, ?>> potentialAfterDelete = modificationTree.readNode(TWO_TWO_PATH);
+ assertFalse(potentialAfterDelete.isPresent());
+
+ }
+
+ private static <T> T assertPresentAndType(final Optional<?> potential, final Class<T> type) {
+ assertNotNull(potential);
+ assertTrue(potential.isPresent());
+ assertTrue(type.isInstance(potential.get()));
+ return type.cast(potential.get());
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.impl.schema.tree;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
+
+import com.google.common.base.Optional;
+
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.StoreTreeNodes;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNodeFactory;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Retest_StoreTreeNodesTest {
+ private static final Logger LOG = LoggerFactory.getLogger(Retest_StoreTreeNodesTest.class);
+
+ private static final Short ONE_ID = 1;
+ private static final Short TWO_ID = 2;
+ private static final String TWO_ONE_NAME = "one";
+ private static final String TWO_TWO_NAME = "two";
+
+ private static final YangInstanceIdentifier OUTER_LIST_1_PATH = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+ .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID) //
+ .build();
+
+ private static final YangInstanceIdentifier OUTER_LIST_2_PATH = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+ .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID) //
+ .build();
+
+ private static final YangInstanceIdentifier TWO_TWO_PATH = YangInstanceIdentifier.builder(OUTER_LIST_2_PATH)
+ .node(TestModel.INNER_LIST_QNAME) //
+ .nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, TWO_TWO_NAME) //
+ .build();
+
+ private static final MapEntryNode BAR_NODE = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, TWO_ID) //
+ .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME) //
+ .withChild(mapEntry(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, TWO_ONE_NAME)) //
+ .withChild(mapEntry(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, TWO_TWO_NAME)) //
+ .build()) //
+ .build();
+
+ private SchemaContext schemaContext;
+ private RootModificationApplyOperation rootOper;
+
+ @Before
+ public void prepare() throws ReactorException {
+ schemaContext = RetestModel.createTestContext();
+ assertNotNull("Schema context must not be null.", schemaContext);
+ rootOper = RootModificationApplyOperation.from(SchemaAwareApplyOperation.from(schemaContext, TreeType.OPERATIONAL));
+ }
+
+ public NormalizedNode<?, ?> createDocumentOne() {
+ return ImmutableContainerNodeBuilder
+ .create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(schemaContext.getQName()))
+ .withChild(createTestContainer()).build();
+
+ }
+
+ private static ContainerNode createTestContainer() {
+ return ImmutableContainerNodeBuilder
+ .create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
+ .withChild(
+ mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
+ .withChild(mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, ONE_ID))
+ .withChild(BAR_NODE).build()).build();
+ }
+
+ private static <T> T assertPresentAndType(final Optional<?> potential, final Class<T> type) {
+ assertNotNull(potential);
+ assertTrue(potential.isPresent());
+ assertTrue(type.isInstance(potential.get()));
+ return type.cast(potential.get());
+ }
+
+ @Test
+ public void findNodeTestNodeFound() {
+ final InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+ TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
+ final TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+ final Optional<TreeNode> node = StoreTreeNodes.findNode(rootNode, OUTER_LIST_1_PATH);
+ assertPresentAndType(node, TreeNode.class);
+ }
+
+ @Test
+ public void findNodeTestNodeNotFound() {
+ final InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+ TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
+ final TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+ final YangInstanceIdentifier outerList1InvalidPath = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+ .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3) //
+ .build();
+ final Optional<TreeNode> node = StoreTreeNodes.findNode(rootNode, outerList1InvalidPath);
+ assertFalse(node.isPresent());
+ }
+
+ @Test
+ public void findNodeCheckedTestNodeFound() {
+ final InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+ TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
+ final TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+ TreeNode foundNode = null;
+ try {
+ foundNode = StoreTreeNodes.findNodeChecked(rootNode, OUTER_LIST_1_PATH);
+ } catch (final IllegalArgumentException e) {
+ fail("Illegal argument exception was thrown and should not have been" + e.getMessage());
+ }
+ assertNotNull(foundNode);
+ }
+
+ @Test
+ public void findNodeCheckedTestNodeNotFound() {
+ final InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+ TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
+ final TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+ final YangInstanceIdentifier outerList1InvalidPath = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+ .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3) //
+ .build();
+ try {
+ StoreTreeNodes.findNodeChecked(rootNode, outerList1InvalidPath);
+ fail("Illegal argument exception should have been thrown");
+ } catch (final IllegalArgumentException e) {
+ LOG.debug("Illegal argument exception was thrown as expected: '{}' - '{}'", e.getClass(), e.getMessage());
+ }
+ }
+
+ @Test
+ public void findClosestOrFirstMatchTestNodeExists() {
+ final InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+ TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
+ final TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+ final Optional<TreeNode> expectedNode = StoreTreeNodes.findNode(rootNode, TWO_TWO_PATH);
+ assertPresentAndType(expectedNode, TreeNode.class);
+ final Map.Entry<YangInstanceIdentifier, TreeNode> actualNode = StoreTreeNodes.findClosest(rootNode, TWO_TWO_PATH);
+ assertEquals("Expected node and actual node are not the same", expectedNode.get(), actualNode.getValue());
+ }
+
+ @Test
+ public void findClosestOrFirstMatchTestNodeDoesNotExist() {
+ final InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+ TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
+ final TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+ final YangInstanceIdentifier outerListInnerListPath = YangInstanceIdentifier.builder(OUTER_LIST_2_PATH)
+ .node(TestModel.INNER_LIST_QNAME)
+ .build();
+ final YangInstanceIdentifier twoTwoInvalidPath = YangInstanceIdentifier.builder(OUTER_LIST_2_PATH)
+ .node(TestModel.INNER_LIST_QNAME) //
+ .nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "three") //
+ .build();
+ final Optional<TreeNode> expectedNode = StoreTreeNodes.findNode(rootNode, outerListInnerListPath);
+ assertPresentAndType(expectedNode, TreeNode.class);
+ final Map.Entry<YangInstanceIdentifier, TreeNode> actualNode = StoreTreeNodes.findClosest(rootNode, twoTwoInvalidPath);
+ assertEquals("Expected node and actual node are not the same", expectedNode.get(), actualNode.getValue());
+ }
+
+ @Test
+ public void getChildTestChildFound() {
+ final InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+ TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
+ final TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+ final Optional<TreeNode> node = StoreTreeNodes.getChild(Optional.fromNullable(rootNode),
+ TestModel.TEST_PATH.getLastPathArgument());
+ assertPresentAndType(node, TreeNode.class);
+ }
+
+ @Test
+ public void getChildTestChildNotFound() {
+ final InMemoryDataTreeSnapshot inMemoryDataTreeSnapshot = new InMemoryDataTreeSnapshot(schemaContext,
+ TreeNodeFactory.createTreeNodeRecursively(createDocumentOne(), Version.initial()), rootOper);
+ final TreeNode rootNode = inMemoryDataTreeSnapshot.getRootNode();
+ final Optional<TreeNode> node = StoreTreeNodes.getChild(Optional.fromNullable(rootNode),
+ TestModel.OUTER_LIST_PATH.getLastPathArgument());
+ assertFalse(node.isPresent());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.operations.retest;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.Collection;
+
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
+
+public class RetestUtils {
+
+ private RetestUtils() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static SchemaContext parseYangSources(StatementStreamSource... sources) throws SourceException,
+ ReactorException {
+
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSources(sources);
+
+ return reactor.buildEffective();
+ }
+
+ public static SchemaContext parseYangSources(File... files) throws SourceException, ReactorException,
+ FileNotFoundException {
+
+ StatementStreamSource[] sources = new StatementStreamSource[files.length];
+
+ for (int i = 0; i < files.length; i++) {
+ sources[i] = new YangStatementSourceImpl(new FileInputStream(files[i]));
+ }
+
+ return parseYangSources(sources);
+ }
+
+ public static SchemaContext parseYangSources(Collection<File> files) throws SourceException, ReactorException,
+ FileNotFoundException {
+ return parseYangSources(files.toArray(new File[files.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.yangtools.yang.data.operations.retest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.opendaylight.yangtools.yang.data.operations.DataOperations;
+
+import org.opendaylight.yangtools.yang.data.operations.DataModificationException;
+import java.util.Arrays;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class YangDataOperationsNegativeTest extends YangDataOperationsTest{
+
+ private static final String XML_NEG_FOLDER_NAME = "/xmls-negative";
+ private final Class<? extends DataModificationException> expected;
+
+ @Parameterized.Parameters()
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {
+
+ // Container
+ { "/containerTest_noneContainerActualMissing", DataModificationException.DataMissingException.class },
+ { "/containerTest_createContainerActualPresent", DataModificationException.DataExistsException.class },
+ { "/containerTest_deleteContainerActualMissing", DataModificationException.DataMissingException.class },
+ // List
+ { "/listTest_createListActualPresent", DataModificationException.DataExistsException.class },
+ { "/listTest_deleteListActualMissing", DataModificationException.DataMissingException.class },
+ { "/listTest_noneListActualMissing", DataModificationException.DataMissingException.class },
+ // Leaf
+ { "/leafTest_createLeafActualPresent", DataModificationException.DataExistsException.class },
+ { "/leafTest_deleteLeafActualMissing", DataModificationException.DataMissingException.class },
+ // Leaf list
+ { "/leafListTest_createLeafActualPresent", DataModificationException.DataExistsException.class },
+ { "/leafListTest_deleteLeafActualMissing", DataModificationException.DataMissingException.class },
+ });
+ }
+
+ public YangDataOperationsNegativeTest(String testDir, Class<? extends DataModificationException> e) throws Exception {
+ super(testDir);
+ this.expected = e;
+ }
+
+ @Override
+ protected String getXmlFolderName() {
+ return XML_NEG_FOLDER_NAME;
+ }
+
+ @Test
+ public void testModification() throws Exception {
+ try {
+ DataOperations.modify(containerNode,
+ currentConfig.orNull(), modification.orNull(), modifyAction);
+ fail("Negative test for " + testDirName + " should have failed");
+ } catch (Exception e) {
+ assertEquals(e.getClass(), expected);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.yang.data.operations.retest;
+
+import static org.junit.Assert.assertNull;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.io.Files;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import javax.activation.UnsupportedDataTypeException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory;
+import org.opendaylight.yangtools.yang.data.operations.DataOperations;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+@RunWith(Parameterized.class)
+public class YangDataOperationsTest {
+
+ public static final String CURRENT_XML_NAME = "/current.xml";
+ public static final String MODIFICATION_XML_NAME = "/merge.xml";
+ private static final String XML_FOLDER_NAME = "/xmls";
+ public static final String RESULT_XML_NAME = "/result.xml";
+ private static final Object OPERATION_XML_NAME = "/defaultOperation.txt";
+
+ protected final ContainerSchemaNode containerNode;
+ protected final String testDirName;
+ protected final Optional<ContainerNode> currentConfig;
+ protected final Optional<ContainerNode> modification;
+ protected final ModifyAction modifyAction;
+ private final SchemaContext schema;
+
+ @Parameterized.Parameters()
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {
+ // Container
+ { "/containerTest_createContainer" },
+ { "/containerTest_deleteContainer" },
+ { "/containerTest_innerContainerContainer" },
+ { "/containerTest_innerLeavesBaseOperationsContainer" },
+ { "/containerTest_noneContainer" },
+ { "/containerTest_removeContainer"},
+ { "/containerTest_replaceContainer"},
+ { "/containerTest_choiceActualModificationSameCase"},
+ { "/containerTest_choiceActualModificationDifferentCases"},
+ { "/containerTest_choiceActualOneCaseModificationOtherCase"},
+ // LeafList
+ { "/leafListTest" },
+ // List
+ { "/listTest" },
+ // Additional
+ {"/none_NoChange"},
+ {"/listTest_alterInnerValue"}
+ });
+ }
+
+ public YangDataOperationsTest(final String testDir) throws Exception {
+ schema = parseTestSchema();
+ containerNode = (ContainerSchemaNode) getSchemaNode(schema, "test", "container");
+ this.testDirName = testDir;
+
+ currentConfig = loadXmlToCompositeNode(getXmlFolderName() + testDirName + CURRENT_XML_NAME);
+ modification = loadXmlToCompositeNode(getXmlFolderName() + testDirName + MODIFICATION_XML_NAME);
+ Preconditions.checkState(modification.isPresent(), "Modification xml has to be present under "
+ + getXmlFolderName() + testDirName + MODIFICATION_XML_NAME);
+
+ modifyAction = loadModifyAction(getXmlFolderName() + testDirName + OPERATION_XML_NAME);
+ }
+
+ protected String getXmlFolderName() {
+ return XML_FOLDER_NAME;
+ }
+
+ // TODO unite testing resources e.g. schemas with yang-data-impl
+ // TODO create extract common testing infrastructure from this and yang-data-impl e.g. xml dom handling
+
+ @Test
+ public void testModification() throws Exception {
+
+ Optional<ContainerNode> result = DataOperations.modify(containerNode,
+ currentConfig.orNull(), modification.orNull(), modifyAction);
+
+ String expectedResultXmlPath = getXmlFolderName() + testDirName + RESULT_XML_NAME;
+ Optional<ContainerNode> expectedResult = loadXmlToCompositeNode(expectedResultXmlPath);
+
+ if (result.isPresent()) {
+ verifyModificationResult(result, expectedResult);
+ } else {
+ assertNull("Result of modification is empty node, result xml should not be present "
+ + expectedResultXmlPath, getClass().getResourceAsStream(expectedResultXmlPath));
+ }
+
+ }
+
+ private ModifyAction loadModifyAction(final String path) throws Exception {
+ URL resource = getClass().getResource(path);
+ if (resource == null) {
+ return ModifyAction.MERGE;
+ }
+
+ return ModifyAction.fromXmlValue(Files.toString(new File(resource.toURI()), Charsets.UTF_8).trim());
+ }
+
+ private void verifyModificationResult(final Optional<ContainerNode> result, final Optional<ContainerNode> expectedResult)
+ throws UnsupportedDataTypeException {
+ Assert.assertEquals(
+ String.format(
+ "Test result %n %s %n Expected %n %s %n",
+ toString(toDom(result.get())),
+ toString(toDom(expectedResult.get()))), expectedResult.get(), result.get());
+ }
+
+ private Element toDom(final ContainerNode container) {
+ Iterable<Element> a =
+ DomFromNormalizedNodeSerializerFactory.getInstance(newDocument(), DomUtils.defaultValueCodecProvider())
+ .getContainerNodeSerializer().serialize(containerNode, container);
+ return a.iterator().next();
+ }
+
+ private Document newDocument() {
+ try {
+ return BUILDERFACTORY.newDocumentBuilder().newDocument();
+ } catch (ParserConfigurationException e) {
+ throw new RuntimeException("Failed to parse XML document", e);
+ }
+ }
+
+ private Optional<ContainerNode> loadXmlToCompositeNode(final String xmlPath) throws IOException, SAXException {
+ InputStream resourceAsStream = getClass().getResourceAsStream(xmlPath);
+ if (resourceAsStream == null) {
+ return Optional.absent();
+ }
+
+ Document currentConfigElement = readXmlToDocument(resourceAsStream);
+ Preconditions.checkNotNull(currentConfigElement);
+
+ return Optional.fromNullable(DomToNormalizedNodeParserFactory.getInstance(DomUtils.defaultValueCodecProvider(), schema).getContainerNodeParser().parse(
+ Collections.singletonList(currentConfigElement.getDocumentElement()), containerNode));
+ }
+
+ SchemaContext parseTestSchema() throws URISyntaxException, FileNotFoundException, ReactorException {
+ File testYang = new File(getClass().getResource("/schemas/test.yang").toURI());
+ return RetestUtils.parseYangSources(testYang);
+ }
+
+ DataSchemaNode getSchemaNode(final SchemaContext context, final String moduleName, final String childNodeName) {
+ for (Module module : context.getModules()) {
+ if (module.getName().equals(moduleName)) {
+ for (DataSchemaNode dataSchemaNode : module.getChildNodes()) {
+ if (dataSchemaNode.getQName().getLocalName().equals(childNodeName)) {
+ return dataSchemaNode;
+ }
+ }
+ }
+ }
+
+ throw new IllegalStateException("Unable to find child node " + childNodeName);
+ }
+
+ private static final DocumentBuilderFactory BUILDERFACTORY;
+
+ static {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setCoalescing(true);
+ factory.setIgnoringElementContentWhitespace(true);
+ factory.setIgnoringComments(true);
+ BUILDERFACTORY = factory;
+ }
+
+ private Document readXmlToDocument(final InputStream xmlContent) throws IOException, SAXException {
+ DocumentBuilder dBuilder;
+ try {
+ dBuilder = BUILDERFACTORY.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new RuntimeException("Failed to parse XML document", e);
+ }
+ Document doc = dBuilder.parse(xmlContent);
+
+ doc.getDocumentElement().normalize();
+ return doc;
+ }
+
+ public static String toString(final Element xml) {
+ try {
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+
+ StreamResult result = new StreamResult(new StringWriter());
+ DOMSource source = new DOMSource(xml);
+ transformer.transform(source, result);
+
+ return result.getWriter().toString();
+ } catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) {
+ throw new RuntimeException("Unable to serialize xml element " + xml, e);
+ }
+ }
+
+}
} catch (VerificationException e) {
assertVerificationException(
e,
- "org.opendaylight.yangtools.yang.parser.util.YangValidationException: Not existing module imported:unknownDep:2013-02-27 by:private:2013-02-27");
+ "org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException: Imported module " +
+ "[ModuleIdentifierImpl{name='unknownDep', namespace=null, revision=Wed Feb 27 00:00:00 ");
return;
}
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
import org.opendaylight.yangtools.yang2sources.plugin.ConfigArg.CodeGeneratorArg;
import org.opendaylight.yangtools.yang2sources.spi.BasicCodeGenerator;
import org.sonatype.plexus.build.incremental.BuildContext;
* {@link BasicCodeGenerator}s. Steps of this process:
* <ol>
* <li>List yang files from {@link #yangFilesRootDir}</li>
- * <li>Process yang files using {@link YangParserImpl}</li>
+ * <li>Process yang files using Yang Parser</li>
* <li>For each {@link BasicCodeGenerator} from {@link #codeGenerators}:
* <ol>
* <li>Instantiate using default constructor</li>
*/
package org.opendaylight.yangtools.yang2sources.plugin;
+import java.util.HashSet;
+
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.maven.project.MavenProject;
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.opendaylight.yangtools.yang.parser.repo.URLSchemaContextResolver;
import org.opendaylight.yangtools.yang.parser.util.NamedFileInputStream;
import org.opendaylight.yangtools.yang2sources.plugin.ConfigArg.CodeGeneratorArg;
}
private ContextHolder processYang() throws MojoExecutionException {
- YangParserImpl parser = new YangParserImpl();
+ final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ SchemaContext resolveSchemaContext;
List<Closeable> closeables = new ArrayList<>();
log.info(Util.message("Inspecting %s", LOG_PREFIX, yangFilesRootDir));
try {
List<InputStream> all = new ArrayList<>(yangsInProject);
closeables.addAll(yangsInProject);
- Map<InputStream, Module> allYangModules;
/**
* Set contains all modules generated from input sources. Number of
closeables.addAll(yangStreams);
}
- allYangModules = parser.parseYangModelsFromStreamsMapped(all);
+ resolveSchemaContext = reactor.buildEffective(all);
+ Set<Module> parsedAllYangModules = resolveSchemaContext.getModules();
projectYangModules = new HashSet<>();
- for (InputStream inProject : yangsInProject) {
- Module module = allYangModules.get(inProject);
- if (module != null) {
+ for (Module module : parsedAllYangModules) {
+ if(module.getModuleSourcePath()!=null) {
projectYangModules.add(module);
}
}
-
} finally {
for (AutoCloseable closeable : closeables) {
closeable.close();
}
}
- Set<Module> parsedAllYangModules = new HashSet<>(allYangModules.values());
- SchemaContext resolveSchemaContext = parser.resolveSchemaContext(parsedAllYangModules);
log.info(Util.message("%s files parsed from %s", LOG_PREFIX, Util.YANG_SUFFIX.toUpperCase(), yangsInProject));
return new ContextHolder(resolveSchemaContext, projectYangModules);
@Override
public void enterStatement(final YangStatementParser.StatementContext ctx) {
- final StatementSourceReference ref = DeclarationInTextSource.atPosition(sourceName, ctx.getText(), ctx
+ final StatementSourceReference ref = DeclarationInTextSource.atPosition(sourceName, ctx
.getStart().getLine(), ctx.getStart().getCharPositionInLine());
boolean action = true;
QName identifier;
@Override
public void exitStatement(final YangStatementParser.StatementContext ctx) {
- final StatementSourceReference ref = DeclarationInTextSource.atPosition(sourceName, ctx.getText(), ctx.getStart().getLine(), ctx
+ final StatementSourceReference ref = DeclarationInTextSource.atPosition(sourceName, ctx.getStart().getLine(), ctx
.getStart().getCharPositionInLine());
for (int i = 0; i < ctx.getChildCount(); i++) {
ParseTree child = ctx.getChild(i);
package org.opendaylight.yangtools.yang.parser.impl.util;
import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.getArgumentString;
-import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.getFirstContext;
+
+import org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils;
import com.google.common.base.Optional;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
+import java.util.HashSet;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.StatementContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser;
import com.google.common.collect.ImmutableSet;
import java.io.InputStream;
import java.util.Date;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtContext;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtsContext;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_stmtContext;
-import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.ModuleImport;
import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
/**
* Helper transfer object which holds basic and dependency information for YANG
private final ImmutableSet<ModuleImport> dependencies;
YangModelDependencyInfo(final String name, final String formattedRevision,
- final ImmutableSet<ModuleImport> imports, final ImmutableSet<ModuleImport> includes) {
+ final ImmutableSet<ModuleImport> imports,
+ final ImmutableSet<ModuleImport> includes) {
this.name = name;
this.formattedRevision = formattedRevision;
- this.revision = formattedRevision == null ? null : QName.parseRevision(formattedRevision);
+ this.revision = formattedRevision == null ? null : QName
+ .parseRevision(formattedRevision);
this.moduleImports = imports;
this.submoduleIncludes = includes;
this.dependencies = ImmutableSet.<ModuleImport> builder()
- .addAll(moduleImports)
- .addAll(submoduleIncludes)
- .build();
+ .addAll(moduleImports).addAll(submoduleIncludes).build();
}
/**
* Returns immutable collection of all module imports.
*
- * This collection contains both <code>import</code> statements
- * and <code>include</code> statements for submodules.
+ * This collection contains both <code>import</code> statements and
+ * <code>include</code> statements for submodules.
*
* @return Immutable collection of imports.
*/
}
/**
- * Extracts {@link YangModelDependencyInfo} from an abstract syntax tree
- * of a YANG model.
+ * Extracts {@link YangModelDependencyInfo} from an abstract syntax tree of
+ * a YANG model.
*
- * @param tree Abstract syntax tree
+ * @param tree
+ * Abstract syntax tree
* @return {@link YangModelDependencyInfo}
* @throws YangSyntaxErrorException
* If the AST is not a valid YANG module/submodule
*/
- public static YangModelDependencyInfo fromAST(final String name, final ParserRuleContext tree) throws YangSyntaxErrorException {
- final Optional<Module_stmtContext> moduleCtx = getFirstContext(tree, Module_stmtContext.class);
+ public static YangModelDependencyInfo fromAST(final String name,
+ final ParserRuleContext tree) throws YangSyntaxErrorException {
+
+ if (tree instanceof YangStatementParser.StatementContext) {
+ YangStatementParser.StatementContext rootStatement = (YangStatementParser.StatementContext) tree;
+ return parseAST(rootStatement);
+ }
+
+ final Optional<Module_stmtContext> moduleCtx = ParserListenerUtils
+ .getFirstContext(tree, Module_stmtContext.class);
if (moduleCtx.isPresent()) {
return parseModuleContext(moduleCtx.get());
}
- final Optional<Submodule_stmtContext> submoduleCtx = getFirstContext(tree, Submodule_stmtContext.class);
+ final Optional<Submodule_stmtContext> submoduleCtx = ParserListenerUtils
+ .getFirstContext(tree, Submodule_stmtContext.class);
if (submoduleCtx.isPresent()) {
return parseSubmoduleContext(submoduleCtx.get());
}
throw new YangSyntaxErrorException(name, 0, 0, "Unknown YANG text type");
}
+ private static YangModelDependencyInfo parseAST(
+ YangStatementParser.StatementContext rootStatement) {
+ if (rootStatement
+ .keyword()
+ .getText()
+ .equals(Rfc6020Mapping.MODULE.getStatementName().getLocalName())) {
+ return parseModuleContext(rootStatement);
+ } else if (rootStatement
+ .keyword()
+ .getText()
+ .equals(Rfc6020Mapping.SUBMODULE.getStatementName()
+ .getLocalName())) {
+ return parseSubmoduleContext(rootStatement);
+ }
+
+ throw new IllegalArgumentException(
+ "Root of parsed AST must be either module or submodule");
+ }
+
/**
- * Extracts {@link YangModelDependencyInfo} from input stream
- * containing YANG model.
+ * Extracts {@link YangModelDependencyInfo} from input stream containing
+ * YANG model.
*
- * This parsing does not validate full YANG module, only
- * parses header up to the revisions and imports.
+ * This parsing does not validate full YANG module, only parses header up to
+ * the revisions and imports.
*
* @param yangStream
* Opened Input stream containing text source of YANG model
* @throws IllegalArgumentException
* If input stream is not valid YANG stream
*/
- public static YangModelDependencyInfo fromInputStream(final InputStream yangStream) {
- YangContext yangContext = YangParserImpl.parseStreamWithoutErrorListeners(yangStream);
-
- Optional<Module_stmtContext> moduleCtx = getFirstContext(yangContext, Module_stmtContext.class);
- if (moduleCtx.isPresent()) {
- return parseModuleContext(moduleCtx.get());
- }
- Optional<Submodule_stmtContext> submoduleCtx = getFirstContext(yangContext, Submodule_stmtContext.class);
- if (submoduleCtx.isPresent()) {
- return parseSubmoduleContext(submoduleCtx.get());
- }
- throw new IllegalArgumentException("Supplied stream is not valid yang file.");
+ public static YangModelDependencyInfo fromInputStream(
+ final InputStream yangStream) {
+ StatementContext yangAST = new YangStatementSourceImpl(yangStream)
+ .getYangAST();
+ return parseAST(yangAST);
}
- private static YangModelDependencyInfo parseModuleContext(final Module_stmtContext module) {
+ private static YangModelDependencyInfo parseModuleContext(
+ final Module_stmtContext module) {
String name = getArgumentString(module);
String latestRevision = getLatestRevision(module.revision_stmts());
- ImmutableSet<ModuleImport> imports = parseImports(module.linkage_stmts().import_stmt());
- ImmutableSet<ModuleImport> includes = parseIncludes(module.linkage_stmts().include_stmt());
+ ImmutableSet<ModuleImport> imports = parseImports(module
+ .linkage_stmts().import_stmt());
+ ImmutableSet<ModuleImport> includes = parseIncludes(module
+ .linkage_stmts().include_stmt());
+
+ return new ModuleDependencyInfo(name, latestRevision, imports, includes);
+ }
+
+ private static YangModelDependencyInfo parseModuleContext(
+ final YangStatementParser.StatementContext module) {
+ String name = Utils.stringFromStringContext(module.argument());
+ String latestRevision = getLatestRevision(module);
+ ImmutableSet<ModuleImport> imports = parseImports(module);
+ ImmutableSet<ModuleImport> includes = parseIncludes(module);
return new ModuleDependencyInfo(name, latestRevision, imports, includes);
}
- private static ImmutableSet<ModuleImport> parseImports(final List<Import_stmtContext> importStatements) {
+ private static ImmutableSet<ModuleImport> parseImports(
+ final YangStatementParser.StatementContext module) {
+ Set<ModuleImport> result = new HashSet<>();
+ List<StatementContext> subStatements = module.statement();
+ for (StatementContext subStatementContext : subStatements) {
+ if (subStatementContext
+ .keyword()
+ .getText()
+ .equals(Rfc6020Mapping.IMPORT.getStatementName()
+ .getLocalName())) {
+ String revisionDateStr = getRevisionDateString(subStatementContext);
+ String importedModuleName = Utils
+ .stringFromStringContext(subStatementContext.argument());
+ Date revisionDate = (revisionDateStr == null) ? null : QName
+ .parseRevision(revisionDateStr);
+ result.add(new ModuleImportImpl(importedModuleName,
+ revisionDate));
+ }
+ }
+ return ImmutableSet.copyOf(result);
+ }
+
+ private static ImmutableSet<ModuleImport> parseIncludes(
+ final YangStatementParser.StatementContext module) {
+ Set<ModuleImport> result = new HashSet<>();
+ List<StatementContext> subStatements = module.statement();
+ for (StatementContext subStatementContext : subStatements) {
+ if (subStatementContext
+ .keyword()
+ .getText()
+ .equals(Rfc6020Mapping.INCLUDE.getStatementName()
+ .getLocalName())) {
+ String revisionDateStr = getRevisionDateString(subStatementContext);
+ String IncludeModuleName = Utils
+ .stringFromStringContext(subStatementContext.argument());
+ Date revisionDate = (revisionDateStr == null) ? null : QName
+ .parseRevision(revisionDateStr);
+ result.add(new ModuleImportImpl(IncludeModuleName, revisionDate));
+ }
+ }
+ return ImmutableSet.copyOf(result);
+ }
+
+ private static String getRevisionDateString(StatementContext importStatement) {
+ List<StatementContext> importSubStatements = importStatement
+ .statement();
+ String revisionDateStr = null;
+ for (StatementContext importSubStatement : importSubStatements) {
+ if (importSubStatement
+ .keyword()
+ .getText()
+ .equals(Rfc6020Mapping.REVISION_DATE.getStatementName()
+ .getLocalName())) {
+ revisionDateStr = Utils
+ .stringFromStringContext(importSubStatement.argument());
+ }
+ }
+ return revisionDateStr;
+ }
+
+ private static ImmutableSet<ModuleImport> parseImports(
+ final List<Import_stmtContext> importStatements) {
ImmutableSet.Builder<ModuleImport> builder = ImmutableSet.builder();
for (Import_stmtContext importStmt : importStatements) {
String moduleName = getArgumentString(importStmt);
return builder.build();
}
- public static String getLatestRevision(final Revision_stmtsContext revisionStmts) {
- List<Revision_stmtContext> revisions = revisionStmts.getRuleContexts(Revision_stmtContext.class);
+ public static String getLatestRevision(
+ final YangStatementParser.StatementContext module) {
+ List<StatementContext> subStatements = module.statement();
+ String latestRevision = null;
+ for (StatementContext subStatementContext : subStatements) {
+ if (subStatementContext
+ .keyword()
+ .getText()
+ .equals(Rfc6020Mapping.REVISION.getStatementName()
+ .getLocalName())) {
+ String currentRevision = Utils
+ .stringFromStringContext(subStatementContext.argument());
+ if (latestRevision == null
+ || latestRevision.compareTo(currentRevision) == -1) {
+ latestRevision = currentRevision;
+ }
+ }
+ }
+ return latestRevision;
+ }
+
+ public static String getLatestRevision(
+ final Revision_stmtsContext revisionStmts) {
+ List<Revision_stmtContext> revisions = revisionStmts
+ .getRuleContexts(Revision_stmtContext.class);
String latestRevision = null;
for (Revision_stmtContext revisionStmt : revisions) {
String currentRevision = getArgumentString(revisionStmt);
- if (latestRevision == null || latestRevision.compareTo(currentRevision) == -1) {
+ if (latestRevision == null
+ || latestRevision.compareTo(currentRevision) == -1) {
latestRevision = currentRevision;
}
}
return latestRevision;
}
- private static YangModelDependencyInfo parseSubmoduleContext(final Submodule_stmtContext submodule) {
+ private static YangModelDependencyInfo parseSubmoduleContext(
+ final YangStatementParser.StatementContext submodule) {
+ String name = Utils.stringFromStringContext(submodule.argument());
+ String belongsTo = parseBelongsTo(submodule);
+
+ String latestRevision = getLatestRevision(submodule);
+ ImmutableSet<ModuleImport> imports = parseImports(submodule);
+ ImmutableSet<ModuleImport> includes = parseIncludes(submodule);
+
+ return new SubmoduleDependencyInfo(name, latestRevision, belongsTo,
+ imports, includes);
+ }
+
+ private static String parseBelongsTo(StatementContext submodule) {
+ List<StatementContext> subStatements = submodule.statement();
+ for (StatementContext subStatementContext : subStatements) {
+ if (subStatementContext
+ .keyword()
+ .getText()
+ .equals(Rfc6020Mapping.BELONGS_TO.getStatementName()
+ .getLocalName())) {
+ return Utils.stringFromStringContext(subStatementContext
+ .argument());
+ }
+ }
+ return null;
+ }
+
+ private static YangModelDependencyInfo parseSubmoduleContext(
+ final Submodule_stmtContext submodule) {
String name = getArgumentString(submodule);
- Belongs_to_stmtContext belongsToStmt = submodule.submodule_header_stmts().belongs_to_stmt(0);
+ Belongs_to_stmtContext belongsToStmt = submodule
+ .submodule_header_stmts().belongs_to_stmt(0);
String belongsTo = getArgumentString(belongsToStmt);
String latestRevision = getLatestRevision(submodule.revision_stmts());
- ImmutableSet<ModuleImport> imports = parseImports(submodule.linkage_stmts().import_stmt());
- ImmutableSet<ModuleImport> includes = parseIncludes(submodule.linkage_stmts().include_stmt());
+ ImmutableSet<ModuleImport> imports = parseImports(submodule
+ .linkage_stmts().import_stmt());
+ ImmutableSet<ModuleImport> includes = parseIncludes(submodule
+ .linkage_stmts().include_stmt());
- return new SubmoduleDependencyInfo(name, latestRevision, belongsTo, imports, includes);
+ return new SubmoduleDependencyInfo(name, latestRevision, belongsTo,
+ imports, includes);
}
- private static ImmutableSet<ModuleImport> parseIncludes(final List<Include_stmtContext> importStatements) {
+ private static ImmutableSet<ModuleImport> parseIncludes(
+ final List<Include_stmtContext> importStatements) {
ImmutableSet.Builder<ModuleImport> builder = ImmutableSet.builder();
for (Include_stmtContext importStmt : importStatements) {
String moduleName = getArgumentString(importStmt);
return builder.build();
}
- private static Date getRevision(final Revision_date_stmtContext revisionDateStmt) {
+ private static Date getRevision(
+ final Revision_date_stmtContext revisionDateStmt) {
if (revisionDateStmt == null) {
return null;
}
* Dependency information for YANG module.
*
*/
- public static final class ModuleDependencyInfo extends YangModelDependencyInfo {
+ public static final class ModuleDependencyInfo extends
+ YangModelDependencyInfo {
- private ModuleDependencyInfo(final String name, final String latestRevision,
- final ImmutableSet<ModuleImport> imports, final ImmutableSet<ModuleImport> includes) {
+ private ModuleDependencyInfo(final String name,
+ final String latestRevision,
+ final ImmutableSet<ModuleImport> imports,
+ final ImmutableSet<ModuleImport> includes) {
super(name, latestRevision, imports, includes);
}
@Override
public String toString() {
- return "Module [name=" + getName() + ", revision=" + getRevision() + ", dependencies=" + getDependencies()
- + "]";
+ return "Module [name=" + getName() + ", revision=" + getRevision()
+ + ", dependencies=" + getDependencies() + "]";
}
}
/**
*
- * Dependency information for submodule, also provides name
- * for parent module.
+ * Dependency information for submodule, also provides name for parent
+ * module.
*
*/
- public static final class SubmoduleDependencyInfo extends YangModelDependencyInfo {
+ public static final class SubmoduleDependencyInfo extends
+ YangModelDependencyInfo {
private final String belongsTo;
- private SubmoduleDependencyInfo(final String name, final String latestRevision, final String belongsTo,
- final ImmutableSet<ModuleImport> imports, final ImmutableSet<ModuleImport> includes) {
+ private SubmoduleDependencyInfo(final String name,
+ final String latestRevision, final String belongsTo,
+ final ImmutableSet<ModuleImport> imports,
+ final ImmutableSet<ModuleImport> includes) {
super(name, latestRevision, imports, includes);
this.belongsTo = belongsTo;
}
@Override
public String toString() {
- return "Submodule [name=" + getName() + ", revision=" + getRevision() + ", dependencies="
- + getDependencies() + "]";
+ return "Submodule [name=" + getName() + ", revision="
+ + getRevision() + ", dependencies=" + getDependencies()
+ + "]";
}
}
@Override
public String toString() {
- return "ModuleImportImpl [name=" + name + ", revision=" + QName.formattedRevision(revision) + "]";
+ return "ModuleImportImpl [name=" + name + ", revision="
+ + QName.formattedRevision(revision) + "]";
}
}
}
*/
package org.opendaylight.yangtools.yang.parser.repo;
+import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
+
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
import com.google.common.base.Function;
-import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.cache.Cache;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-import java.net.URI;
import java.util.Collection;
import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.NavigableMap;
import java.util.Set;
import javax.annotation.Nullable;
import org.antlr.v4.runtime.ParserRuleContext;
-import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
import org.opendaylight.yangtools.util.concurrent.ReflectiveExceptionMapper;
-import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
-import org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils;
-import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserListenerImpl;
-import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final AsyncFunction<List<ASTSchemaSource>, SchemaContext> assembleSources = new AsyncFunction<List<ASTSchemaSource>, SchemaContext>() {
@Override
- public ListenableFuture<SchemaContext> apply(final List<ASTSchemaSource> sources) throws SchemaResolutionException {
+ public ListenableFuture<SchemaContext> apply(final List<ASTSchemaSource> sources) throws SchemaResolutionException, SourceException, ReactorException {
final Map<SourceIdentifier, ASTSchemaSource> srcs =
Maps.uniqueIndex(sources, ASTSchemaSource.GET_IDENTIFIER);
final Map<SourceIdentifier, YangModelDependencyInfo> deps =
final DependencyResolver res = DependencyResolver.create(deps);
if (!res.getUnresolvedSources().isEmpty()) {
LOG.debug("Omitting models {} due to unsatisfied imports {}", res.getUnresolvedSources(), res.getUnsatisfiedImports());
-
- // FIXME: push into DependencyResolver
-
throw new SchemaResolutionException("Failed to resolve required models",
res.getResolvedSources(), res.getUnsatisfiedImports());
}
final Map<SourceIdentifier, ParserRuleContext> asts =
Maps.transformValues(srcs, ASTSchemaSource.GET_AST);
- final Map<String, NavigableMap<Date, URI>> namespaceContext = BuilderUtils.createYangNamespaceContext(
- asts.values(), Optional.<SchemaContext>absent());
- final ParseTreeWalker walker = new ParseTreeWalker();
- final Map<SourceIdentifier, ModuleBuilder> sourceToBuilder = new LinkedHashMap<>();
-
- for (final Entry<SourceIdentifier, ParserRuleContext> entry : asts.entrySet()) {
- final ModuleBuilder moduleBuilder = YangParserListenerImpl.create(namespaceContext, entry.getKey().getName(),
- walker, entry.getValue()).getModuleBuilder();
-
- moduleBuilder.setSource(srcs.get(entry.getKey()).getYangText());
- sourceToBuilder.put(entry.getKey(), moduleBuilder);
+ CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR
+ .newBuild();
+
+ for (final Entry<SourceIdentifier, ParserRuleContext> entry : asts
+ .entrySet()) {
+ ParserRuleContext parserRuleCtx = entry.getValue();
+ if (parserRuleCtx instanceof YangStatementParser.StatementContext) {
+ YangStatementSourceImpl source = new YangStatementSourceImpl(
+ entry.getKey(),
+ (YangStatementParser.StatementContext) parserRuleCtx);
+ reactor.addSource(source);
+ } else {
+ throw new IllegalArgumentException("Only YangStatementParser.StatementContext is supported.");
+ }
}
- LOG.debug("Modules ready for integration");
- final YangParserImpl parser = YangParserImpl.getInstance();
- final Collection<Module> modules = parser.buildModules(sourceToBuilder.values());
- LOG.debug("Integrated cross-references modules");
- return Futures.immediateCheckedFuture(parser.assembleContext(modules));
+ SchemaContext schemaContext = reactor.buildEffective();
+
+ return Futures.immediateCheckedFuture(schemaContext);
}
};
*
* To create source reference use one of this static factories:
* <ul>
- * <li>{@link #atPosition(String, String, int, int)} - provides most specific reference of statement location,
+ * <li>{@link #atPosition(String, int, int)} - provides most specific reference of statement location,
* this is most prefered since it provides most context to debug YANG model.
* </li>
- * <li>{@link #atLine(String, String, int)}- provides source and line of statement location.
+ * <li>{@link #atLine(String, int)}- provides source and line of statement location.
* </li>
- * <li>{@link #inSource(String, String)} - least specific reference, should be used only if any of previous
+ * <li>{@link #inSource(String)} - least specific reference, should be used only if any of previous
* references are unable to create / derive from source.
* </li>
* </ul>
*/
public abstract class DeclarationInTextSource implements StatementSourceReference {
- private final String sourceText;
private final String sourceName;
- DeclarationInTextSource(String sourceName, String sourceText) {
+ DeclarationInTextSource(String sourceName) {
this.sourceName = sourceName;
- this.sourceText = sourceText;
}
public String getSourceName() {
return sourceName;
}
- public String getSourceText() {
- return sourceText;
- }
-
@Override
public StatementSource getStatementSource() {
return StatementSource.DECLARATION;
@Override
public abstract String toString();
- public static final DeclarationInTextSource inSource(String sourceName, String sourceText) {
- return new InSource(sourceName, sourceText);
+ public static final DeclarationInTextSource inSource(String sourceName) {
+ return new InSource(sourceName);
}
- public static final DeclarationInTextSource atLine(String sourceName, String sourceText, int line) {
- return new AtLine(sourceName, sourceText, line);
+ public static final DeclarationInTextSource atLine(String sourceName, int line) {
+ return new AtLine(sourceName, line);
}
- public static final DeclarationInTextSource atPosition(String sourceName, String sourceText, int line, int position) {
- return new AtPosition(sourceName, sourceText, line,position);
+ public static final DeclarationInTextSource atPosition(String sourceName, int line, int position) {
+ return new AtPosition(sourceName, line,position);
}
private static class InSource extends DeclarationInTextSource {
- public InSource(String sourceName, String sourceText) {
- super(sourceName, sourceText);
+ InSource(String sourceName) {
+ super(sourceName);
}
@Override
}
- private static class AtLine extends DeclarationInTextSource {
+ private static class AtLine extends InSource {
private final int line;
- public AtLine(String sourceName, String sourceText, int line) {
- super(sourceName, sourceText);
+ AtLine(String sourceName, int line) {
+ super(sourceName);
this.line = line;
}
public String toString() {
return String.format("%s:%d", getSourceName(),line);
}
+
+ public int getLine() {
+ return line;
+ }
}
- private static class AtPosition extends DeclarationInTextSource {
+ private static class AtPosition extends AtLine {
- private int line;
- private int character;
+ private final int character;
- public AtPosition(String sourceName, String sourceText, int line, int character) {
- super(sourceName, sourceText);
- this.line = line;
+ AtPosition(String sourceName, int line, int character) {
+ super(sourceName, line);
this.character = character;
}
@Override
public String toString() {
- return String.format("%s:%d:%d", getSourceName(),line,character);
+ return String.format("%s:%d:%d", getSourceName(),getLine(),character);
}
}
*/
package org.opendaylight.yangtools.yang.parser.stmt.reactor;
-import java.util.Set;
+import java.io.IOException;
+import com.google.common.io.ByteSource;
+import java.util.Set;
import java.io.FileNotFoundException;
import org.opendaylight.yangtools.yang.parser.util.NamedFileInputStream;
import java.util.HashMap;
return context.buildEffective();
}
+ public SchemaContext buildEffective(Collection<ByteSource> yangByteSources) throws SourceException, ReactorException, IOException {
+
+ for(ByteSource yangByteSource : yangByteSources) {
+ addSource(new YangStatementSourceImpl(yangByteSource.openStream()));
+ }
+
+ return buildEffective();
+ }
+
public SchemaContext buildEffective(List<InputStream> yangInputStreams) throws SourceException, ReactorException {
for(InputStream yangInputStream : yangInputStreams) {
public class EffectiveSchemaContext extends AbstractEffectiveSchemaContext {
- private final Map<ModuleIdentifier, String> identifiersToSources;
private final SetMultimap<URI, Module> namespaceToModules;
private final SetMultimap<String, Module> nameToModules;
private final Set<Module> modules;
namespaceToModules = ImmutableSetMultimap.copyOf(nsMap);
nameToModules = ImmutableSetMultimap.copyOf(nameMap);
- identifiersToSources = ImmutableMap.copyOf(isMap);
-
}
- public EffectiveSchemaContext(final Set<Module> modules, final Map<ModuleIdentifier, String> identifiersToSources) {
- this.identifiersToSources = ImmutableMap.copyOf(identifiersToSources);
-
+ public EffectiveSchemaContext(final Set<Module> modules) {
+
/*
* Instead of doing this on each invocation of getModules(), pre-compute
* it once and keep it around -- better than the set we got in.
}
public static SchemaContext resolveSchemaContext(final Set<Module> modules) {
- Map<ModuleIdentifier, String> identifiersToSources = new HashMap<>();
- for (Module module : modules) {
- identifiersToSources.put(module, module.getSource());
- }
- return new EffectiveSchemaContext(modules, identifiersToSources);
+ return new EffectiveSchemaContext(modules);
}
public ImmutableList<DeclaredStatement<?>> getRootDeclaredStatements() {
@Override
protected Map<ModuleIdentifier, String> getIdentifiersToSources() {
- return identifiersToSources;
+ return ImmutableMap.of();
}
@Override
private ImmutableList<ExtensionDefinition> extensionNodes;
private ImmutableSet<IdentitySchemaNode> identities;
private ImmutableList<UnknownSchemaNode> unknownNodes;
- private final String source;
private ImmutableList<EffectiveStatement<?, ?>> substatementsOfSubmodules;
private ImmutableMap<QName, DataSchemaNode> childNodes;
if (yangVersion == null) {
yangVersion = "1";
}
+ if(ctx.getStatementSourceReference() instanceof DeclarationInTextSource) {
+ sourcePath = ((DeclarationInTextSource) ctx.getStatementSourceReference()).getSourceName();
+ } else {
+ sourcePath = null;
+ }
- DeclarationInTextSource sourceReference = (DeclarationInTextSource) ctx.getStatementSourceReference();
- sourcePath = sourceReference.getSourceName();
- source = sourceReference.getSourceText();
initSubmodules(ctx);
initSubstatementCollections(ctx);
@Override
public String getSource() {
- return source;
+ return null;
}
@Override
package org.opendaylight.yangtools.yang.parser.util;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
import com.google.common.annotations.Beta;
import com.google.common.base.Charsets;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.Futures;
import java.io.IOException;
import java.io.InputStream;
-import org.antlr.v4.runtime.tree.ParseTreeWalker;
-import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext;
import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
import org.opendaylight.yangtools.yang.model.repo.util.SchemaSourceTransformer;
-import org.opendaylight.yangtools.yang.parser.impl.YangModelBasicValidationListener;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
*/
@Beta
public final class TextToASTTransformer extends SchemaSourceTransformer<YangTextSchemaSource, ASTSchemaSource> {
+
public static final class TextToASTTransformation implements Transformation<YangTextSchemaSource, ASTSchemaSource> {
@Override
public CheckedFuture<ASTSchemaSource, SchemaSourceException> apply(final YangTextSchemaSource input) throws IOException, YangSyntaxErrorException {
try (InputStream is = input.openStream()) {
- final YangContext ctx = YangParserImpl.parseYangSource(is);
+ final ParserRuleContext ctx = new YangStatementSourceImpl(is).getYangAST();
LOG.debug("Model {} parsed successfully", input);
- final ParseTreeWalker walker = new ParseTreeWalker();
- final YangModelBasicValidationListener validator = new YangModelBasicValidationListener();
- walker.walk(validator, ctx);
- LOG.debug("Model {} validated successfully", input);
+ //:TODO missing validation (YangModelBasicValidationListener should be re-implemented to new parser)
// Backwards compatibility
final String text = input.asCharSource(Charsets.UTF_8).read();
+++ /dev/null
-package org.opendaylight.yangtools.yang.stmt.test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.Set;
-import org.junit.Test;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
-import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
-
-public class ModuleSourceTest {
-
- @Test
- public void test() throws SourceException, ReactorException, URISyntaxException, IOException {
- SchemaContext schema = StmtTestUtils.parseYangSources("/module-source");
-
- assertNotNull(schema);
-
- Set<Module> modules = schema.getModules();
- assertNotNull(modules);
- assertEquals(1,modules.size());
-
- Module simpleModule = modules.iterator().next();
- String source = simpleModule.getSource();
- String moduleSourcePath = simpleModule.getModuleSourcePath();
-
- File simpleYang = new File(getClass().getResource("/module-source/simple-module.yang").toURI());
-
- assertEquals(simpleYang.getPath(), moduleSourcePath);
- assertEquals(readFile(moduleSourcePath), source);
- }
-
- private static String readFile(final String fileName) throws IOException {
- BufferedReader br = new BufferedReader(new FileReader(fileName));
- try {
- StringBuilder sb = new StringBuilder();
- String line = br.readLine();
-
- while (line != null) {
- sb.append(line);
- sb.append(System.lineSeparator());
- line = br.readLine();
- }
- return sb.toString();
- } finally {
- br.close();
- }
- }
-}