creates common test functions 57/73557/6
authorShweta V <sv111y@att.com>
Wed, 20 Dec 2017 11:15:51 +0000 (12:15 +0100)
committerguillaume.lambert <guillaume.lambert@orange.com>
Wed, 18 Jul 2018 15:18:42 +0000 (17:18 +0200)
adds a test-common folder at project root that contains several
functions to convert XML to DataObjectConverter and vice versa

Co-Authored-By: Dhruv Bhardwaj <db929a@att.com>
Co-Authored-By: Shweta Vachhani <sv111y@att.com>
Co-Authored-By: Masha Dorfman <>
Co-Authored-By: Archana Soundararajan <as7463@att.com>
Co-Authored-By: Juraj Veverka <Juraj.Veverka@pantheon.tech>
Co-Authored-By: Samuel Kontri <samuel.kontris@pantheon.sk>
Co-Authored-By: Andrej Zan <andrej.zan@pantheon.sk>
Co-Authored-By: Milan Fratrik <>
Co-authored-by: Martial COULIBALY <martial.coulibaly@gfi.fr>
Change-Id: Ie7fbe4db4678843bc89e67a2269a5587e722ef75
Signed-off-by: Shweta <sv111y@att.com>
Signed-off-by: Martial COULIBALY <martial.coulibaly@gfi.fr>
pom.xml
test-common/pom.xml [new file with mode: 0644]
test-common/src/main/java/org/opendaylight/transportpce/binding/converter/AbstractDataObjectConverter.java [new file with mode: 0644]
test-common/src/main/java/org/opendaylight/transportpce/binding/converter/JSONDataObjectConverter.java [new file with mode: 0644]
test-common/src/main/java/org/opendaylight/transportpce/binding/converter/XMLDataObjectConverter.java [new file with mode: 0644]
test-common/src/main/java/org/opendaylight/transportpce/binding/converter/api/DataObjectConverter.java [new file with mode: 0644]
test-common/src/main/java/org/opendaylight/transportpce/test/AbstractDeviceTest.java [new file with mode: 0644]
test-common/src/main/java/org/opendaylight/transportpce/test/AbstractTest.java [new file with mode: 0644]
test-common/src/main/java/org/opendaylight/transportpce/test/DeviceWrapper.java [new file with mode: 0644]
test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContext.java [new file with mode: 0644]
test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContextImpl.java [new file with mode: 0644]

diff --git a/pom.xml b/pom.xml
index 747bdde8993a0982b756a396ec44d6b8874d35df..be06885819943a6e44fee4cecd9212575c191c28 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -41,6 +41,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <module>servicehandler</module>
     <module>features</module>
     <module>karaf</module>
+    <module>test-common</module>
   </modules>
 
   <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
diff --git a/test-common/pom.xml b/test-common/pom.xml
new file mode 100644 (file)
index 0000000..1933e4a
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright © 2017 Orange 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 Author: Martial Coulibaly <martial.coulibaly@gfi.com>
+    on behalf of Orange -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>bundle-parent</artifactId>
+        <version>3.1.0</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.opendaylight.transportpce</groupId>
+    <artifactId>test-common</artifactId>
+    <version>0.2.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>mdsal-artifacts</artifactId>
+                <version>1.7.3-SNAPSHOT</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yangtools-artifacts</artifactId>
+                <version>2.0.7</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-broker-impl</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-codec-xml</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-codec-gson</artifactId>
+        </dependency>
+
+    </dependencies>
+</project>
diff --git a/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/AbstractDataObjectConverter.java b/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/AbstractDataObjectConverter.java
new file mode 100644 (file)
index 0000000..aa35cdf
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright © 2016 AT&T 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.transportpce.binding.converter;
+
+import com.google.common.base.Preconditions;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.transportpce.binding.converter.api.DataObjectConverter;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.Notification;
+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.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Converts XML and {@link DataObject} vice versa.
+ *
+ */
+public abstract class AbstractDataObjectConverter implements DataObjectConverter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractDataObjectConverter.class);
+
+    private final SchemaContext schemaContext;
+    private final BindingNormalizedNodeSerializer codecRegistry;
+
+    /**
+     * This is the default constructor, which should be used.
+     *
+     * @param schemaContext schema context for converter
+     * @param codecRegistry codec registry used for converting
+     *
+     */
+    protected AbstractDataObjectConverter(SchemaContext schemaContext, BindingNormalizedNodeSerializer codecRegistry) {
+        this.schemaContext = schemaContext;
+        this.codecRegistry = codecRegistry;
+    }
+
+    public SchemaContext getSchemaContext() {
+        return schemaContext;
+    }
+
+    public BindingNormalizedNodeSerializer getCodecRegistry() {
+        return codecRegistry;
+    }
+
+    /**
+     * Transforms the given input {@link NormalizedNode} into the given
+     * {@link DataObject}.
+     *
+     * @param normalizedNode normalized node you want to convert
+     * @param rootNode {@link QName} of converted normalized node root
+     *
+     * <p>
+     * The input object should be {@link ContainerNode}
+     * </p>
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T extends DataObject> Optional<T> getDataObject(
+            @Nonnull NormalizedNode<?, ?> normalizedNode,
+            @Nonnull QName rootNode) {
+        Preconditions.checkNotNull(normalizedNode);
+        if (normalizedNode instanceof ContainerNode) {
+            YangInstanceIdentifier.PathArgument directChildIdentifier =
+                    YangInstanceIdentifier.of(rootNode).getLastPathArgument();
+            Optional<NormalizedNode<?, ?>> directChild =
+                    NormalizedNodes.getDirectChild(normalizedNode, directChildIdentifier).toJavaUtil();
+            if (!directChild.isPresent()) {
+                throw new IllegalStateException(String.format("Could not get the direct child of %s", rootNode));
+            }
+            normalizedNode = directChild.get();
+        }
+        YangInstanceIdentifier rootNodeYangInstanceIdentifier = YangInstanceIdentifier.of(rootNode);
+
+        Map.Entry<?, ?> bindingNodeEntry =
+                codecRegistry.fromNormalizedNode(rootNodeYangInstanceIdentifier, normalizedNode);
+        if (bindingNodeEntry == null) {
+            return Optional.empty();
+        }
+        return Optional.ofNullable((T) bindingNodeEntry.getValue());
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T extends DataObject> Optional<T> getDataObjectFromRpc(
+            @Nonnull NormalizedNode<?, ?> normalizedNode,
+            @Nonnull SchemaPath rpcSchemaPath) {
+
+        if (! (normalizedNode instanceof ContainerNode)) {
+            LOG.error("converting normalized node is not ContainerNode. It's actual type is {}",
+                    normalizedNode.getClass().getSimpleName());
+            return Optional.empty();
+        }
+        T rpcDataObject = (T) codecRegistry.fromNormalizedNodeRpcData(rpcSchemaPath, (ContainerNode) normalizedNode);
+        return Optional.ofNullable(rpcDataObject);
+    }
+
+    @Override
+    public <T extends DataObject> Optional<NormalizedNode<?, ?>> toNormalizedNodes(@Nonnull T object,
+            Class<T> dataObjectClass) {
+        Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode =
+                codecRegistry.toNormalizedNode(InstanceIdentifier.create(dataObjectClass), object);
+        return Optional.ofNullable(normalizedNode.getValue());
+    }
+
+    @Override
+    public <T extends DataObject> ConvertType<T> dataContainer() {
+        return (object, objectClass) -> {
+            NormalizedNode<?, ?> value =
+                    getCodecRegistry().toNormalizedNode(InstanceIdentifier.create(objectClass), object).getValue();
+            return Optional.ofNullable(value);
+        };
+    }
+
+    @Override
+    public <T extends DataContainer> ConvertType<T> rpcData() {
+        return (object, objectClass) -> {
+            ContainerNode normalizedNodeRpcData = getCodecRegistry().toNormalizedNodeRpcData(object);
+            return Optional.ofNullable(normalizedNodeRpcData);
+        };
+    }
+
+    @Override
+    public <T extends Notification> ConvertType<T> notification() {
+        return (object, objectClass) -> {
+            ContainerNode normalizedNodeNotification = getCodecRegistry().toNormalizedNodeNotification(object);
+            return Optional.ofNullable(normalizedNodeNotification);
+        };
+    }
+}
diff --git a/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/JSONDataObjectConverter.java b/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/JSONDataObjectConverter.java
new file mode 100644 (file)
index 0000000..fced3dc
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright © 2016 AT&T 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.transportpce.binding.converter;
+
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Optional;
+import javax.annotation.Nonnull;
+import org.opendaylight.transportpce.binding.converter.api.DataObjectConverter;
+import org.opendaylight.transportpce.test.common.DataStoreContext;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+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.JSONCodecFactory;
+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.model.api.SchemaNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JSONDataObjectConverter extends AbstractDataObjectConverter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JSONDataObjectConverter.class);
+
+    private JSONDataObjectConverter(SchemaContext schemaContext, BindingNormalizedNodeCodecRegistry codecRegistry) {
+        super(schemaContext, codecRegistry);
+    }
+
+    /**
+     * extracts codec and schema context (?).
+     *
+     * @param dataStoreContextUtil datastore context util used to extract codec and schema context
+     * @return {@link AbstractDataObjectConverter}
+     */
+    public static DataObjectConverter createWithDataStoreUtil(@Nonnull DataStoreContext dataStoreContextUtil) {
+        return new JSONDataObjectConverter(dataStoreContextUtil.getSchemaContext(),
+                dataStoreContextUtil.getBindingToNormalizedNodeCodec());
+    }
+
+    /**
+     * extracts codec and schema context (?).
+     *
+     * @param schemaContext schema context for converter
+     * @param codecRegistry codec registry used for converting
+     * @return converter
+     */
+    public static DataObjectConverter createWithSchemaContext(@Nonnull SchemaContext schemaContext,
+            @Nonnull BindingNormalizedNodeCodecRegistry codecRegistry) {
+        return new JSONDataObjectConverter(schemaContext, codecRegistry);
+    }
+
+    /**
+     * Transforms the JSON input stream into normalized nodes.
+     *
+     * @param inputStream of the given JSON
+     * @return {@link Optional} instance of {@link NormalizedNode}.
+     */
+    @Override
+    public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
+            @Nonnull InputStream inputStream) {
+        try {
+            JsonReader reader = new JsonReader(new InputStreamReader(inputStream, "UTF-8"));
+            return parseInputJSON(reader);
+        } catch (IOException e) {
+            LOG.warn(e.getMessage(), e);
+            return Optional.empty();
+        }
+    }
+
+    @Override
+    public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
+            @Nonnull Reader inputReader, SchemaNode parentSchema) {
+        throw new UnsupportedOperationException("Not Implemented yet");
+    }
+
+    @Override
+    public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
+            @Nonnull Reader inputReader) {
+        JsonReader reader = new JsonReader(inputReader);
+        return parseInputJSON(reader);
+    }
+
+    @Override
+    public <T extends DataObject> Writer writerFromDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
+            ConvertType<T> convertType) {
+        Writer writer = new StringWriter();
+        JsonWriter jsonWriter = new JsonWriter(writer);
+        JSONCodecFactory jsonCodecFactory = JSONCodecFactory.createLazy(getSchemaContext());
+        NormalizedNodeStreamWriter create =
+                JSONNormalizedNodeStreamWriter.createExclusiveWriter(jsonCodecFactory, null, null, jsonWriter);
+
+        try (NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(create);) {
+            normalizedNodeWriter
+                    .write(convertType.toNormalizedNodes(dataObjectClass.cast(object), dataObjectClass).get());
+        } catch (IOException ioe) {
+            throw new IllegalStateException(ioe);
+        }
+        return writer;
+    }
+
+    @Override
+    public <T extends DataObject> Writer writerFromRpcDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
+            ConvertType<T> convertType, QName rpcOutputQName, String rpcName) {
+        return null;
+    }
+
+    /**
+     * Parses the input json with concrete implementation of {@link JsonParserStream}.
+     *
+     * @param reader of the given JSON
+     *
+     */
+    private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputJSON(
+            JsonReader reader) {
+        NormalizedNodeResult result = new NormalizedNodeResult();
+        try (NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+            JsonParserStream jsonParser = JsonParserStream.create(streamWriter, getSchemaContext(),
+            getSchemaContext())) {
+            jsonParser.parse(reader);
+        } catch (IOException e) {
+            LOG.warn("An error {} occured during parsing Json input stream", e.getMessage(), e);
+            return Optional.empty();
+        }
+        return Optional.ofNullable(result.getResult());
+    }
+
+}
diff --git a/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/XMLDataObjectConverter.java b/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/XMLDataObjectConverter.java
new file mode 100644 (file)
index 0000000..e882dd3
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright © 2016 AT&T 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.transportpce.binding.converter;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URISyntaxException;
+import java.util.Optional;
+import javax.annotation.Nonnull;
+import javax.xml.XMLConstants;
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.transportpce.test.common.DataStoreContext;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+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.xml.XMLStreamNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
+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.model.api.SchemaPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+
+public class XMLDataObjectConverter extends AbstractDataObjectConverter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(XMLDataObjectConverter.class);
+
+    private final XMLInputFactory xmlInputFactory;
+
+    /**
+     * This is the default constructor, which should be used.
+     *
+     * @param schemaContext schema context for converter
+     * @param codecRegistry codec registry used for converting
+     *
+     */
+    private XMLDataObjectConverter(SchemaContext schemaContext, BindingNormalizedNodeSerializer codecRegistry) {
+        super(schemaContext, codecRegistry);
+        this.xmlInputFactory = XMLInputFactory.newInstance();
+    }
+
+    /**
+     * Extract codec and schema context (?).
+     *
+     * @param dataStoreContextUtil datastore context util used to extract codec and schema context
+     * @return {@link AbstractDataObjectConverter}
+     */
+    public static XMLDataObjectConverter createWithDataStoreUtil(@Nonnull DataStoreContext dataStoreContextUtil) {
+        BindingNormalizedNodeSerializer bindingToNormalizedNodeCodec =
+                dataStoreContextUtil.getBindingToNormalizedNodeCodec();
+        return new XMLDataObjectConverter(dataStoreContextUtil.getSchemaContext(), bindingToNormalizedNodeCodec);
+    }
+
+    /**
+     * Extract codec and schema context (?).
+     *
+     * @param schemaContext schema context for converter
+     * @param codecRegistry codec registry used for converting
+     * @return new {@link XMLDataObjectConverter}
+     */
+    public static XMLDataObjectConverter createWithSchemaContext(@Nonnull SchemaContext schemaContext,
+            @Nonnull BindingNormalizedNodeSerializer codecRegistry) {
+        return new XMLDataObjectConverter(schemaContext, codecRegistry);
+    }
+
+    /**
+     * Transforms the XML input stream into normalized nodes.
+     *
+     * @param inputStream of the given XML
+     * @return {@link Optional} instance of {@link NormalizedNode}.
+     */
+    @Override
+    public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
+            @Nonnull InputStream inputStream) {
+        try {
+            XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputStream);
+            return parseInputXML(reader);
+        } catch (XMLStreamException e) {
+            LOG.warn(e.getMessage(), e);
+            return Optional.empty();
+        }
+    }
+
+    public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
+            @Nonnull Reader inputReader, SchemaNode parentSchema) {
+        try {
+            XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputReader);
+            return parseInputXML(reader, parentSchema);
+        } catch (XMLStreamException e) {
+            LOG.warn(e.getMessage(), e);
+            return Optional.empty();
+        }
+    }
+
+    /**
+     * Transforms the XML input stream into normalized nodes.
+     *
+     * @param inputReader of the given XML
+     * @return {@link Optional} instance of {@link NormalizedNode}.
+     */
+    @Override
+    public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
+            @Nonnull Reader inputReader) {
+        try {
+            XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputReader);
+            return parseInputXML(reader);
+        } catch (XMLStreamException e) {
+            LOG.warn(e.getMessage(), e);
+            return Optional.empty();
+        }
+    }
+
+    @Override
+    public <T extends DataObject> Writer writerFromRpcDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
+            ConvertType<T> convertType, QName rpcOutputQName, String rpcName) {
+        Writer writer = new StringWriter();
+        XMLStreamWriter xmlStreamWriter = createXmlStreamWriter(writer);
+        SchemaPath rpcOutputSchemaPath = SchemaPath.create(true, QName.create(rpcOutputQName.getModule(), rpcName),
+                rpcOutputQName);
+        try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(xmlStreamWriter,
+                rpcOutputSchemaPath)) {
+            xmlStreamWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX,
+                    rpcOutputQName.getLocalName(), rpcOutputQName.getNamespace().toString());
+            xmlStreamWriter.writeDefaultNamespace(rpcOutputQName.getNamespace().toString());
+            NormalizedNode<?, ?> rpcOutputNormalizedNode = convertType.toNormalizedNodes(dataObjectClass.cast(object),
+                    dataObjectClass).get();
+            for (final NormalizedNode<?, ?> child : ((ContainerNode)rpcOutputNormalizedNode).getValue()) {
+                normalizedNodeWriter.write(child);
+            }
+            normalizedNodeWriter.flush();
+            xmlStreamWriter.writeEndElement();
+            xmlStreamWriter.flush();
+        } catch (IOException | XMLStreamException ioe) {
+            throw new IllegalStateException(ioe);
+        }
+        return writer;
+    }
+
+    /**
+     * Returns a {@link Writer}.
+     *
+     * @param convertType converter used of converting into normalized node
+     * @param dataObjectClass class of converting object
+     * @param object object you want to convert
+     *
+     */
+    @Override
+    public <T extends DataObject> Writer writerFromDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
+            ConvertType<T> convertType) {
+        Writer writer = new StringWriter();
+
+        try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(writer, null)) {
+            normalizedNodeWriter
+                    .write(convertType.toNormalizedNodes(dataObjectClass.cast(object), dataObjectClass).get());
+            normalizedNodeWriter.flush();
+        } catch (IOException ioe) {
+            throw new IllegalStateException(ioe);
+        }
+        return writer;
+    }
+
+    private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputXML(
+            XMLStreamReader reader) {
+        return parseInputXML(reader, getSchemaContext());
+    }
+
+    private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputXML(
+            XMLStreamReader reader, SchemaNode parentSchemaNode) {
+        NormalizedNodeResult result = new NormalizedNodeResult();
+        try (NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+             XmlParserStream xmlParser = XmlParserStream.create(streamWriter, getSchemaContext(), parentSchemaNode)) {
+            xmlParser.parse(reader);
+        } catch (XMLStreamException | URISyntaxException | IOException | ParserConfigurationException
+                | SAXException e) {
+            LOG.warn("An error {} occured during parsing XML input stream", e.getMessage(), e);
+            return Optional.empty();
+        }
+        return Optional.ofNullable(result.getResult());
+    }
+
+    private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(Writer backingWriter, SchemaPath pathToParent) {
+        XMLStreamWriter createXMLStreamWriter = createXmlStreamWriter(backingWriter);
+        NormalizedNodeStreamWriter streamWriter;
+        if (pathToParent == null) {
+            streamWriter = XMLStreamNormalizedNodeStreamWriter.create(createXMLStreamWriter,
+                    getSchemaContext());
+        } else {
+            streamWriter = XMLStreamNormalizedNodeStreamWriter.create(createXMLStreamWriter,
+                    getSchemaContext(), pathToParent);
+        }
+        return NormalizedNodeWriter.forStreamWriter(streamWriter);
+    }
+
+    private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(XMLStreamWriter backingWriter,
+            SchemaPath pathToParent) {
+        NormalizedNodeStreamWriter streamWriter;
+        if (pathToParent == null) {
+            streamWriter = XMLStreamNormalizedNodeStreamWriter.create(backingWriter,
+                    getSchemaContext());
+        } else {
+            streamWriter = XMLStreamNormalizedNodeStreamWriter.create(backingWriter,
+                    getSchemaContext(), pathToParent);
+        }
+        return NormalizedNodeWriter.forStreamWriter(streamWriter);
+    }
+
+    private static XMLStreamWriter createXmlStreamWriter(Writer backingWriter) {
+        XMLStreamWriter xmlStreamWriter;
+        try {
+            XMLOutputFactory factory = XMLOutputFactory.newFactory();
+            factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
+            xmlStreamWriter = factory.createXMLStreamWriter(backingWriter);
+        } catch (XMLStreamException | FactoryConfigurationError e) {
+            LOG.error("Error [{}] while creating XML writer", e.getMessage(), e);
+            throw new IllegalStateException(e);
+        }
+        return xmlStreamWriter;
+    }
+}
diff --git a/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/api/DataObjectConverter.java b/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/api/DataObjectConverter.java
new file mode 100644 (file)
index 0000000..0ab5429
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 2016 AT&T 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.transportpce.binding.converter.api;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Optional;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Notification;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public interface DataObjectConverter {
+
+    <T extends DataObject> Optional<T> getDataObject(
+            @Nonnull NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?> normalizedNode,
+            @Nonnull QName rootNode);
+
+    <T extends DataObject> Optional<T> getDataObjectFromRpc(
+            @Nonnull NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?> normalizedNode,
+            @Nonnull SchemaPath rpcSchemaPath);
+
+    Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
+            @Nonnull InputStream inputStream);
+
+    Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
+            @Nonnull Reader inputReader, SchemaNode parentSchema);
+
+    Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
+            @Nonnull Reader inputReader);
+
+    <T extends DataObject> Writer writerFromDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
+            ConvertType<T> convertType);
+
+    <T extends DataObject> Writer writerFromRpcDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
+            ConvertType<T> convertType, QName rpcOutputQName, String rpcName);
+
+    <T extends DataObject> Optional<NormalizedNode<?, ?>> toNormalizedNodes(@Nonnull T object,
+            Class<T> dataObjectClass);
+
+    public interface ConvertType<T> {
+        Optional<NormalizedNode<?, ?>> toNormalizedNodes(T object, Class<T> clazz);
+    }
+
+    /**
+     * Returns a converter for {@link DataObject} container type.
+     *
+     * @return {@link ConvertType} converter for {@link DataContainer}
+     */
+    <T extends DataObject> ConvertType<T> dataContainer();
+
+    /**
+     * Returns converter for {@link DataContainer} rpc type.
+     *
+     * @return {@link ConvertType} converter for {@link DataContainer}
+     * representing rpc data
+     */
+    <T extends DataContainer> ConvertType<T> rpcData();
+
+    /**
+     * Return converter for {@link Notification}.
+     *
+     * @return {@link ConvertType} converter for {@link Notification}
+     */
+    <T extends Notification> ConvertType<T> notification();
+
+}
diff --git a/test-common/src/main/java/org/opendaylight/transportpce/test/AbstractDeviceTest.java b/test-common/src/main/java/org/opendaylight/transportpce/test/AbstractDeviceTest.java
new file mode 100644 (file)
index 0000000..3321a7f
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2016 AT&T 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.transportpce.test;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base class for device tests, should be used, when device databroker is needed
+ * in tests.
+ *
+ */
+public abstract class AbstractDeviceTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractDeviceTest.class);
+    private final Map<String, DeviceWrapper> internalStorage;
+
+    /**
+     * Default constructor only initializes the inner
+     * {@link AbstractDeviceTest#internalStorage} as asynchronized {@link Map}.
+     */
+    public AbstractDeviceTest() {
+        this.internalStorage = Collections.synchronizedMap(Maps.newHashMap());
+    }
+
+    /**
+     * Insert a created device into {@link AbstractDeviceTest#internalStorage}.
+     *
+     * @see DeviceWrapper#createDeviceWrapper(String, InputStream, QName)
+     * @param key identifier of device simulator (wrapper)
+     * @param initialDataXmlInputStream {@link InputStream} of xml with initial simulator data
+     * @param intialDataQName {@link QName} of initial simulator data
+     * @return device simulator (wrapper)
+     */
+    public DeviceWrapper createDeviceWrapper(@Nonnull String key, @Nonnull InputStream initialDataXmlInputStream,
+            @Nonnull QName intialDataQName) {
+        DeviceWrapper deviceWrapper =
+                DeviceWrapper.createDeviceWrapper(key, initialDataXmlInputStream, intialDataQName);
+        LOG.info("Creating a new device wrapper {}, {}", key, deviceWrapper);
+        internalStorage.put(key, deviceWrapper);
+        return deviceWrapper;
+    }
+
+    /**
+     * Returns the {@link DeviceWrapper} identified by the key provided as param.
+     *
+     * @param deviceIdentifier identifier of device simulator
+     * @return stored device or null if not found
+     */
+    public DeviceWrapper getDevice(@Nonnull String deviceIdentifier) {
+        Preconditions.checkArgument(!Strings.isNullOrEmpty(deviceIdentifier));
+        return internalStorage.get(deviceIdentifier);
+    }
+}
diff --git a/test-common/src/main/java/org/opendaylight/transportpce/test/AbstractTest.java b/test-common/src/main/java/org/opendaylight/transportpce/test/AbstractTest.java
new file mode 100644 (file)
index 0000000..571e706
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2016 AT&T 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.transportpce.test;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.transportpce.test.common.DataStoreContext;
+import org.opendaylight.transportpce.test.common.DataStoreContextImpl;
+
+public abstract class AbstractTest {
+
+    private final DataStoreContext dataStoreContextUtil;
+
+    protected AbstractTest() {
+        dataStoreContextUtil = new DataStoreContextImpl();
+    }
+
+    public DataBroker getDataBroker() {
+        return dataStoreContextUtil.getDataBroker();
+    }
+
+    public DOMDataBroker getDOMDataBroker() {
+        return dataStoreContextUtil.getDOMDataBroker();
+    }
+
+    public DataStoreContext getDataStoreContextUtil() {
+        return dataStoreContextUtil;
+    }
+
+}
diff --git a/test-common/src/main/java/org/opendaylight/transportpce/test/DeviceWrapper.java b/test-common/src/main/java/org/opendaylight/transportpce/test/DeviceWrapper.java
new file mode 100644 (file)
index 0000000..eb8f6e1
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright © 2016 AT&T 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.transportpce.test;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import java.io.InputStream;
+import java.util.AbstractMap;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.transportpce.binding.converter.XMLDataObjectConverter;
+import org.opendaylight.transportpce.binding.converter.api.DataObjectConverter;
+import org.opendaylight.transportpce.test.common.DataStoreContext;
+import org.opendaylight.transportpce.test.common.DataStoreContextImpl;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Wrapper class around {@link DataBroker} and {@link DOMDataBroker}.
+ *
+ */
+public class DeviceWrapper {
+    private static final Logger LOG = LoggerFactory.getLogger(DeviceWrapper.class);
+
+    private final String identifier;
+    private final DataBroker dataBroker;
+    private final DOMDataBroker domDataBroker;
+
+    /**
+     * May be created only inside of {@link AbstractDeviceTest}.
+     *
+     * @param identifier id of this simulator
+     * @param dataBroker data broker used in this simulator
+     * @param domDataBroker dom data broker used in this simulator
+     */
+    private DeviceWrapper(String identifier, DataBroker dataBroker, DOMDataBroker domDataBroker) {
+        this.identifier = identifier;
+        this.dataBroker = dataBroker;
+        this.domDataBroker = domDataBroker;
+    }
+
+    /**
+     * Gets the data broker.
+     *
+     * @return the dataBroker
+     */
+    public DataBroker getDataBroker() {
+        return dataBroker;
+    }
+
+    /**
+     * Gets the DOM data broker.
+     *
+     * @return the domDataBroker
+     */
+    public DOMDataBroker getDomDataBroker() {
+        return domDataBroker;
+    }
+
+    /**
+     * Gets the identifier.
+     *
+     * @return the identifier
+     */
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    /**
+     * Creates a device wrapper.
+     *
+     * @see #createDeviceWrapper(String, List) with a single list element
+     * @param key identifier of creating simulator
+     * @param initialDataXmlInputStream {@link InputStream} of xml with initial data for simulator
+     * @param intialDataQName {@link QName} of initial data
+     * @return device simulator
+     */
+    public static DeviceWrapper createDeviceWrapper(@Nonnull String key, @Nonnull InputStream initialDataXmlInputStream,
+            @Nonnull QName intialDataQName) {
+        Preconditions.checkNotNull(initialDataXmlInputStream, "Input stream cannot be null");
+        Preconditions.checkNotNull(intialDataQName, "QName cannot be null");
+        return createDeviceWrapper(key, Lists.newArrayList(
+                new AbstractMap.SimpleEntry<QName, InputStream>(intialDataQName, initialDataXmlInputStream)));
+    }
+
+    /**
+     * Creates an instance of {@link DeviceWrapper} with initial data provided via xml
+     * input streams and theirs {@link QName}s the xml data <b>must</b> be wrapped
+     * inside a <b>data</b> tag provided by
+     * <b>urn:ietf:params:xml:ns:netconf:base:1.0</b>.
+     *
+     * @param key string identifier for the device
+     * @param initialData {@link List} of {@link Entry} values
+     * @return created {@link DeviceWrapper} with all initial data provided by initial data
+     */
+    public static DeviceWrapper createDeviceWrapper(@Nonnull String key,
+            @Nonnull List<Entry<QName, InputStream>> initialData) {
+        Preconditions.checkArgument(!Strings.isNullOrEmpty(key), "The provided key cannot be null or empty");
+        Preconditions.checkArgument(initialData != null && !initialData.isEmpty(),
+                "Initial data cannot be null or empty");
+        DataStoreContext dsContext = new DataStoreContextImpl();
+        DataObjectConverter xmlConverter = XMLDataObjectConverter.createWithDataStoreUtil(dsContext);
+        for (Entry<QName, InputStream> entryData : initialData) {
+            insertDataIntoDS(xmlConverter, entryData.getValue(), entryData.getKey(), dsContext.getDOMDataBroker());
+        }
+        return new DeviceWrapper(key, dsContext.getDataBroker(), dsContext.getDOMDataBroker());
+    }
+
+    private static void insertDataIntoDS(DataObjectConverter xmlConverter, InputStream xmlDataInputStream,
+            QName dataQName, DOMDataBroker domDataBroker) {
+        Optional<NormalizedNode<? extends PathArgument, ?>> initialDataNormalizedNodes =
+                xmlConverter.transformIntoNormalizedNode(xmlDataInputStream);
+        Preconditions.checkArgument(initialDataNormalizedNodes.isPresent(),
+                "Initial data could not be converted to normalized nodes");
+        LOG.debug("Input data converted into normalizedNodes");
+
+        YangInstanceIdentifier initialDataIi = YangInstanceIdentifier.of(dataQName);
+        LOG.debug("Searching for {} inside {}", initialDataIi, initialDataNormalizedNodes.get());
+        Optional<NormalizedNode<?, ?>> dataNormalizedNodes =
+                NormalizedNodes.findNode(initialDataNormalizedNodes.get(), initialDataIi).toJavaUtil();
+        Preconditions.checkArgument(dataNormalizedNodes.isPresent());
+        LOG.info("Initial data was successfully stored into ds");
+        DOMDataWriteTransaction writeOnlyTransaction = domDataBroker.newWriteOnlyTransaction();
+        writeOnlyTransaction.put(LogicalDatastoreType.OPERATIONAL, initialDataIi, dataNormalizedNodes.get());
+        try {
+            writeOnlyTransaction.submit().get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("This should be not reached {}", e.getMessage(), e);
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("DeviceWrapper [identifier=");
+        builder.append(identifier);
+        builder.append(", dataBroker=");
+        builder.append(dataBroker);
+        builder.append(", domDataBroker=");
+        builder.append(domDataBroker);
+        builder.append("]");
+        return builder.toString();
+    }
+}
diff --git a/test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContext.java b/test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContext.java
new file mode 100644 (file)
index 0000000..d1e3dfd
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2016 AT&T 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.transportpce.test.common;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public interface DataStoreContext {
+
+    DataBroker getDataBroker();
+
+    DOMDataBroker getDOMDataBroker();
+
+    NotificationService createNotificationService();
+
+    NotificationPublishService createNotificationPublishService();
+
+    SchemaContext getSchemaContext();
+
+    BindingNormalizedNodeCodecRegistry getBindingToNormalizedNodeCodec();
+
+    NotificationService getNotificationService();
+
+    NotificationPublishService getNotificationPublishService();
+
+}
diff --git a/test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContextImpl.java b/test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContextImpl.java
new file mode 100644 (file)
index 0000000..5fc25db
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright © 2016 AT&T 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.transportpce.test.common;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.ServiceLoader;
+import java.util.concurrent.Executors;
+import javassist.ClassPool;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
+import org.opendaylight.controller.md.sal.binding.impl.BindingDOMDataBrokerAdapter;
+import org.opendaylight.controller.md.sal.binding.impl.BindingDOMNotificationPublishServiceAdapter;
+import org.opendaylight.controller.md.sal.binding.impl.BindingDOMNotificationServiceAdapter;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouter;
+import org.opendaylight.controller.md.sal.dom.broker.impl.SerializedDOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
+import org.opendaylight.controller.sal.core.spi.data.DOMStore;
+import org.opendaylight.mdsal.binding.generator.impl.GeneratedClassLoadingStrategy;
+import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataStoreContextImpl implements DataStoreContext {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DataStoreContextImpl.class);
+
+    private final Map<LogicalDatastoreType, DOMStore> datastores;
+    private final SchemaContextHolder mockedSchemaContext;
+    private final DOMNotificationRouter domNotificationRouter;
+    private final DOMDataBroker domDataBroker;
+    private final DataBroker dataBroker;
+    private final NotificationService notificationService;
+    private final NotificationPublishService notificationPublishService;
+
+    public DataStoreContextImpl() {
+        this(false);
+    }
+
+    public DataStoreContextImpl(boolean fromClasspath) {
+        this.mockedSchemaContext = new SchemaContextHolder(fromClasspath);
+        this.datastores = createDatastores();
+        this.domNotificationRouter = DOMNotificationRouter.create(16);
+        this.domDataBroker = createDOMDataBroker();
+        this.dataBroker = createDataBroker();
+        this.notificationService = createNotificationService();
+        this.notificationPublishService = createNotificationPublishService();
+        for (ListenerRegistration<SchemaContextListener> listener : mockedSchemaContext.listeners) {
+            listener.getInstance().onGlobalContextUpdated(mockedSchemaContext.schemaContext);
+        }
+    }
+
+    @Override
+    public DataBroker getDataBroker() {
+        return this.dataBroker;
+    }
+
+    @Override
+    public DOMDataBroker getDOMDataBroker() {
+        return this.domDataBroker;
+    }
+
+    @Override
+    public NotificationService createNotificationService() {
+        return new BindingDOMNotificationServiceAdapter(this.mockedSchemaContext.bindingStreamCodecs,
+                this.domNotificationRouter);
+    }
+
+    @Override
+    public NotificationPublishService createNotificationPublishService() {
+        return new BindingDOMNotificationPublishServiceAdapter(this.mockedSchemaContext.bindingToNormalized,
+                this.domNotificationRouter);
+    }
+
+    @Override
+    public SchemaContext getSchemaContext() {
+        return mockedSchemaContext.schemaContext;
+    }
+
+    @Override
+    public BindingNormalizedNodeCodecRegistry getBindingToNormalizedNodeCodec() {
+        return mockedSchemaContext.bindingStreamCodecs;
+    }
+
+    @Override
+    public NotificationService getNotificationService() {
+        return notificationService;
+    }
+
+    @Override
+    public NotificationPublishService getNotificationPublishService() {
+        return notificationPublishService;
+    }
+
+    private DOMDataBroker createDOMDataBroker() {
+        return new SerializedDOMDataBroker(datastores,
+                MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()));
+    }
+
+    private ListeningExecutorService getDataTreeChangeListenerExecutor() {
+        return MoreExecutors.newDirectExecutorService();
+    }
+
+    private DataBroker createDataBroker() {
+        return new BindingDOMDataBrokerAdapter(getDOMDataBroker(), this.mockedSchemaContext.bindingToNormalized);
+    }
+
+    private Map<LogicalDatastoreType, DOMStore> createDatastores() {
+        return ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
+                .put(LogicalDatastoreType.OPERATIONAL, createOperationalDatastore())
+                .put(LogicalDatastoreType.CONFIGURATION, createConfigurationDatastore()).build();
+    }
+
+    private DOMStore createConfigurationDatastore() {
+        final InMemoryDOMDataStore store = new InMemoryDOMDataStore("CFG", getDataTreeChangeListenerExecutor());
+        this.mockedSchemaContext.registerSchemaContextListener(store);
+        return store;
+    }
+
+    private DOMStore createOperationalDatastore() {
+        final InMemoryDOMDataStore store = new InMemoryDOMDataStore("OPER", getDataTreeChangeListenerExecutor());
+        this.mockedSchemaContext.registerSchemaContextListener(store);
+        return store;
+    }
+
+    private class SchemaContextHolder implements DOMSchemaService, SchemaContextProvider {
+
+        private final SchemaContext schemaContext;
+        private final ListenerRegistry<SchemaContextListener> listeners;
+        private final BindingNormalizedNodeCodecRegistry bindingStreamCodecs;
+        private final BindingToNormalizedNodeCodec bindingToNormalized;
+        private final ModuleInfoBackedContext moduleInfoBackedCntxt;
+
+        private SchemaContextHolder(boolean fromClasspath) {
+            List<YangModuleInfo> moduleInfos = loadModuleInfos();
+            this.moduleInfoBackedCntxt = ModuleInfoBackedContext.create();
+            this.schemaContext = getSchemaContext(moduleInfos);
+            this.listeners = ListenerRegistry.create();
+            this.bindingStreamCodecs = createBindingRegistry();
+            GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
+            this.bindingToNormalized = new BindingToNormalizedNodeCodec(loading, bindingStreamCodecs);
+            registerSchemaContextListener(this.bindingToNormalized);
+        }
+
+        @Override
+        public SchemaContext getSchemaContext() {
+            return schemaContext;
+        }
+
+        /**
+         * Get the schemacontext from loaded modules on classpath.
+         *
+         * @param moduleInfos a list of Yang module Infos
+         * @return SchemaContext a schema context
+         */
+        private SchemaContext getSchemaContext(List<YangModuleInfo> moduleInfos) {
+            moduleInfoBackedCntxt.addModuleInfos(moduleInfos);
+            Optional<SchemaContext> tryToCreateSchemaContext =
+                    moduleInfoBackedCntxt.tryToCreateSchemaContext().toJavaUtil();
+            if (!tryToCreateSchemaContext.isPresent()) {
+                LOG.error("Could not create the initial schema context. Schema context is empty");
+                throw new IllegalStateException();
+            }
+            return tryToCreateSchemaContext.get();
+        }
+
+        @Override
+        public SchemaContext getGlobalContext() {
+            return schemaContext;
+        }
+
+        @Override
+        public SchemaContext getSessionContext() {
+            return schemaContext;
+        }
+
+        @Override
+        public ListenerRegistration<SchemaContextListener> registerSchemaContextListener(
+                SchemaContextListener listener) {
+            return listeners.register(listener);
+        }
+
+        /**
+         * Loads all {@link YangModelBindingProvider} on the classpath.
+         *
+         * @return list of known {@link YangModuleInfo}
+         */
+        private List<YangModuleInfo> loadModuleInfos() {
+            List<YangModuleInfo> moduleInfos = new LinkedList<>();
+            ServiceLoader<YangModelBindingProvider> yangProviderLoader =
+                    ServiceLoader.load(YangModelBindingProvider.class);
+            for (YangModelBindingProvider yangModelBindingProvider : yangProviderLoader) {
+                moduleInfos.add(yangModelBindingProvider.getModuleInfo());
+                LOG.debug("Adding [{}] module into known modules", yangModelBindingProvider.getModuleInfo());
+            }
+            return moduleInfos;
+        }
+
+        /**
+         * Creates binding registry.
+         *
+         * @return BindingNormalizedNodeCodecRegistry the resulting binding registry
+         */
+        private BindingNormalizedNodeCodecRegistry createBindingRegistry() {
+            BindingRuntimeContext bindingContext = BindingRuntimeContext.create(moduleInfoBackedCntxt, schemaContext);
+            BindingNormalizedNodeCodecRegistry bindingNormalizedNodeCodecRegistry =
+                    new BindingNormalizedNodeCodecRegistry(
+                            StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault())));
+            bindingNormalizedNodeCodecRegistry.onBindingRuntimeContextUpdated(bindingContext);
+            return bindingNormalizedNodeCodecRegistry;
+        }
+    }
+}