From 4d25f8a9129d7584aaf71950a30789b629073815 Mon Sep 17 00:00:00 2001 From: Shweta V Date: Wed, 20 Dec 2017 12:15:51 +0100 Subject: [PATCH] creates common test functions 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 Co-Authored-By: Shweta Vachhani Co-Authored-By: Masha Dorfman <> Co-Authored-By: Archana Soundararajan Co-Authored-By: Juraj Veverka Co-Authored-By: Samuel Kontri Co-Authored-By: Andrej Zan Co-Authored-By: Milan Fratrik <> Co-authored-by: Martial COULIBALY Change-Id: Ie7fbe4db4678843bc89e67a2269a5587e722ef75 Signed-off-by: Shweta Signed-off-by: Martial COULIBALY --- pom.xml | 1 + test-common/pom.xml | 74 ++++++ .../AbstractDataObjectConverter.java | 146 +++++++++++ .../converter/JSONDataObjectConverter.java | 145 +++++++++++ .../converter/XMLDataObjectConverter.java | 241 ++++++++++++++++++ .../converter/api/DataObjectConverter.java | 78 ++++++ .../transportpce/test/AbstractDeviceTest.java | 67 +++++ .../transportpce/test/AbstractTest.java | 35 +++ .../transportpce/test/DeviceWrapper.java | 163 ++++++++++++ .../test/common/DataStoreContext.java | 35 +++ .../test/common/DataStoreContextImpl.java | 239 +++++++++++++++++ 11 files changed, 1224 insertions(+) create mode 100644 test-common/pom.xml create mode 100644 test-common/src/main/java/org/opendaylight/transportpce/binding/converter/AbstractDataObjectConverter.java create mode 100644 test-common/src/main/java/org/opendaylight/transportpce/binding/converter/JSONDataObjectConverter.java create mode 100644 test-common/src/main/java/org/opendaylight/transportpce/binding/converter/XMLDataObjectConverter.java create mode 100644 test-common/src/main/java/org/opendaylight/transportpce/binding/converter/api/DataObjectConverter.java create mode 100644 test-common/src/main/java/org/opendaylight/transportpce/test/AbstractDeviceTest.java create mode 100644 test-common/src/main/java/org/opendaylight/transportpce/test/AbstractTest.java create mode 100644 test-common/src/main/java/org/opendaylight/transportpce/test/DeviceWrapper.java create mode 100644 test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContext.java create mode 100644 test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContextImpl.java diff --git a/pom.xml b/pom.xml index 747bdde89..be0688581 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL servicehandler features karaf + test-common diff --git a/test-common/pom.xml b/test-common/pom.xml new file mode 100644 index 000000000..1933e4acf --- /dev/null +++ b/test-common/pom.xml @@ -0,0 +1,74 @@ + + + + + 4.0.0 + + + org.opendaylight.odlparent + bundle-parent + 3.1.0 + + + + org.opendaylight.transportpce + test-common + 0.2.0-SNAPSHOT + bundle + + + + + org.opendaylight.controller + mdsal-artifacts + 1.7.3-SNAPSHOT + pom + import + + + org.opendaylight.yangtools + yangtools-artifacts + 2.0.7 + pom + import + + + + + + + com.google.guava + guava + + + + org.slf4j + slf4j-api + + + + org.opendaylight.controller + sal-binding-broker-impl + + + + org.opendaylight.controller + sal-binding-api + + + + org.opendaylight.yangtools + yang-data-codec-xml + + + + org.opendaylight.yangtools + yang-data-codec-gson + + + + 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 index 000000000..aa35cdf50 --- /dev/null +++ b/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/AbstractDataObjectConverter.java @@ -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 + * + *

+ * The input object should be {@link ContainerNode} + *

+ */ + @Override + @SuppressWarnings("unchecked") + public Optional getDataObject( + @Nonnull NormalizedNode normalizedNode, + @Nonnull QName rootNode) { + Preconditions.checkNotNull(normalizedNode); + if (normalizedNode instanceof ContainerNode) { + YangInstanceIdentifier.PathArgument directChildIdentifier = + YangInstanceIdentifier.of(rootNode).getLastPathArgument(); + Optional> 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 Optional 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 Optional> toNormalizedNodes(@Nonnull T object, + Class dataObjectClass) { + Entry> normalizedNode = + codecRegistry.toNormalizedNode(InstanceIdentifier.create(dataObjectClass), object); + return Optional.ofNullable(normalizedNode.getValue()); + } + + @Override + public ConvertType dataContainer() { + return (object, objectClass) -> { + NormalizedNode value = + getCodecRegistry().toNormalizedNode(InstanceIdentifier.create(objectClass), object).getValue(); + return Optional.ofNullable(value); + }; + } + + @Override + public ConvertType rpcData() { + return (object, objectClass) -> { + ContainerNode normalizedNodeRpcData = getCodecRegistry().toNormalizedNodeRpcData(object); + return Optional.ofNullable(normalizedNodeRpcData); + }; + } + + @Override + public ConvertType 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 index 000000000..fced3dc79 --- /dev/null +++ b/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/JSONDataObjectConverter.java @@ -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> 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> transformIntoNormalizedNode( + @Nonnull Reader inputReader, SchemaNode parentSchema) { + throw new UnsupportedOperationException("Not Implemented yet"); + } + + @Override + public Optional> transformIntoNormalizedNode( + @Nonnull Reader inputReader) { + JsonReader reader = new JsonReader(inputReader); + return parseInputJSON(reader); + } + + @Override + public Writer writerFromDataObject(@Nonnull DataObject object, Class dataObjectClass, + ConvertType 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 Writer writerFromRpcDataObject(@Nonnull DataObject object, Class dataObjectClass, + ConvertType 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> 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 index 000000000..e882dd384 --- /dev/null +++ b/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/XMLDataObjectConverter.java @@ -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> 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> 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> 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 Writer writerFromRpcDataObject(@Nonnull DataObject object, Class dataObjectClass, + ConvertType 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 Writer writerFromDataObject(@Nonnull DataObject object, Class dataObjectClass, + ConvertType 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> parseInputXML( + XMLStreamReader reader) { + return parseInputXML(reader, getSchemaContext()); + } + + private Optional> 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 index 000000000..0ab542968 --- /dev/null +++ b/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/api/DataObjectConverter.java @@ -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 { + + Optional getDataObject( + @Nonnull NormalizedNode normalizedNode, + @Nonnull QName rootNode); + + Optional getDataObjectFromRpc( + @Nonnull NormalizedNode normalizedNode, + @Nonnull SchemaPath rpcSchemaPath); + + Optional> transformIntoNormalizedNode( + @Nonnull InputStream inputStream); + + Optional> transformIntoNormalizedNode( + @Nonnull Reader inputReader, SchemaNode parentSchema); + + Optional> transformIntoNormalizedNode( + @Nonnull Reader inputReader); + + Writer writerFromDataObject(@Nonnull DataObject object, Class dataObjectClass, + ConvertType convertType); + + Writer writerFromRpcDataObject(@Nonnull DataObject object, Class dataObjectClass, + ConvertType convertType, QName rpcOutputQName, String rpcName); + + Optional> toNormalizedNodes(@Nonnull T object, + Class dataObjectClass); + + public interface ConvertType { + Optional> toNormalizedNodes(T object, Class clazz); + } + + /** + * Returns a converter for {@link DataObject} container type. + * + * @return {@link ConvertType} converter for {@link DataContainer} + */ + ConvertType dataContainer(); + + /** + * Returns converter for {@link DataContainer} rpc type. + * + * @return {@link ConvertType} converter for {@link DataContainer} + * representing rpc data + */ + ConvertType rpcData(); + + /** + * Return converter for {@link Notification}. + * + * @return {@link ConvertType} converter for {@link Notification} + */ + ConvertType 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 index 000000000..3321a7f3e --- /dev/null +++ b/test-common/src/main/java/org/opendaylight/transportpce/test/AbstractDeviceTest.java @@ -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 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 index 000000000..571e7063e --- /dev/null +++ b/test-common/src/main/java/org/opendaylight/transportpce/test/AbstractTest.java @@ -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 index 000000000..eb8f6e151 --- /dev/null +++ b/test-common/src/main/java/org/opendaylight/transportpce/test/DeviceWrapper.java @@ -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(intialDataQName, initialDataXmlInputStream))); + } + + /** + * Creates an instance of {@link DeviceWrapper} with initial data provided via xml + * input streams and theirs {@link QName}s the xml data must be wrapped + * inside a data tag provided by + * urn:ietf:params:xml:ns:netconf:base:1.0. + * + * @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> 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 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> 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> 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 index 000000000..d1e3dfd65 --- /dev/null +++ b/test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContext.java @@ -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 index 000000000..5fc25dbeb --- /dev/null +++ b/test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContextImpl.java @@ -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 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 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 createDatastores() { + return ImmutableMap.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 listeners; + private final BindingNormalizedNodeCodecRegistry bindingStreamCodecs; + private final BindingToNormalizedNodeCodec bindingToNormalized; + private final ModuleInfoBackedContext moduleInfoBackedCntxt; + + private SchemaContextHolder(boolean fromClasspath) { + List 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 moduleInfos) { + moduleInfoBackedCntxt.addModuleInfos(moduleInfos); + Optional 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 registerSchemaContextListener( + SchemaContextListener listener) { + return listeners.register(listener); + } + + /** + * Loads all {@link YangModelBindingProvider} on the classpath. + * + * @return list of known {@link YangModuleInfo} + */ + private List loadModuleInfos() { + List moduleInfos = new LinkedList<>(); + ServiceLoader 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; + } + } +} -- 2.36.6