diff options
author | Dan Timoney <dt5972@att.com> | 2018-08-24 19:29:26 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@onap.org> | 2018-08-24 19:29:26 +0000 |
commit | 5c41b487a093174b89f3a66806f115c4459c5065 (patch) | |
tree | c9a5819ce64f0ae6715aab977b500e26b03c8e56 /restconf-client | |
parent | 671c85f81d5263cc64309e4e97dd5c8a0ee1465c (diff) | |
parent | 51608f7e35fdad0242b3d801f2015a9db5fa93a1 (diff) |
Merge "Implementation of Data Format serializer"
Diffstat (limited to 'restconf-client')
25 files changed, 1088 insertions, 82 deletions
diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializer.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializer.java index 57280e2e..cab64391 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializer.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializer.java @@ -20,6 +20,8 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + import java.util.List; import java.util.Map; @@ -57,17 +59,20 @@ public abstract class DataFormatSerializer { * @param param context memory parameter * @param annotations annotations * @return data format body + * @throws SvcLogicException when serialization fails */ public abstract String encode(Map<String, String> param, - Map<String, List<Annotation>> annotations); + Map<String, List<Annotation>> annotations) throws SvcLogicException; /** * Decodes data format body to context memory parameters. * * @param dataFormatBody abstract node * @return context memory parameters + * @throws SvcLogicException when serialization fails */ - public abstract Map<String, String> decode(String dataFormatBody); + public abstract Map<String, String> decode(String dataFormatBody) + throws SvcLogicException; /** * Returns data format serializer context. diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonListener.java index 5e71eea3..107585a7 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonListener.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonListener.java @@ -21,8 +21,16 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; import com.fasterxml.jackson.databind.JsonNode; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_NODE; + /** * Representation of default implementation of JSON listener. @@ -54,13 +62,40 @@ public class DefaultJsonListener implements JsonListener { } @Override - public void enterJsonNode(String nodeName, JsonNode node, NodeType nodeType) { - //TODO: Implementation code. + public void enterJsonNode(String nodeName, JsonNode node, + NodeType nodeType) throws SvcLogicException { + getNodeName(nodeName); + + switch (nodeType) { + case SINGLE_INSTANCE_LEAF_NODE: + serializerHelper.addNode(name, modName, node.asText(), null, + SINGLE_INSTANCE_LEAF_NODE); + break; + + case MULTI_INSTANCE_LEAF_NODE: + serializerHelper.addNode(name, modName, node.asText(), null, + MULTI_INSTANCE_LEAF_NODE); + break; + + case SINGLE_INSTANCE_NODE: + serializerHelper.addNode(name, modName, null, null, + SINGLE_INSTANCE_NODE); + break; + + case MULTI_INSTANCE_NODE: + serializerHelper.addNode(name, modName, null, null, + MULTI_INSTANCE_NODE); + break; + + default: + throw new SvcLogicException(format(NODE_TYPE_ERR, + nodeType.toString())); + } } @Override - public void exitJsonNode(JsonNode node) { - //TODO: Implementation code. + public void exitJsonNode(JsonNode node) throws SvcLogicException { + serializerHelper.exitNode(); } @Override @@ -68,4 +103,20 @@ public class DefaultJsonListener implements JsonListener { return serializerHelper; } + /** + * Parses the abstract JSON name and fills the node name and node + * namespace of the current JSON node. + * + * @param abstractName abstract JSON name + */ + private void getNodeName(String abstractName) { + String[] val = abstractName.split(":"); + if (val.length == 2) { + modName = val[0]; + name = val[1]; + } else { + name = val[0]; + } + } + } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonWalker.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonWalker.java index 20d4fa77..47cb8b29 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonWalker.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonWalker.java @@ -21,6 +21,20 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeType; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; + +import java.util.Iterator; +import java.util.Map; + +import static com.fasterxml.jackson.databind.node.JsonNodeType.NUMBER; +import static com.fasterxml.jackson.databind.node.JsonNodeType.STRING; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_NODE; /** * Implementation of JSON walker to walk through the nodes and process it. @@ -28,8 +42,19 @@ import com.fasterxml.jackson.databind.JsonNode; public class DefaultJsonWalker implements JsonWalker { @Override - public void walk(JsonListener listener, JsonNode jsonNode) { - //TODO: Implementation code. + public void walk(JsonListener listener, JsonNode jsonNode) throws + SvcLogicException { + Iterator<Map.Entry<String, JsonNode>> children = jsonNode.fields(); + while (children.hasNext()) { + Map.Entry<String, JsonNode> child = children.next(); + JsonNode value = child.getValue(); + String key = child.getKey(); + if (value.isArray()) { + processMultiNodes(key, value, listener); + } else { + processSingleNode(key, value, listener); + } + } } /** @@ -39,10 +64,18 @@ public class DefaultJsonWalker implements JsonWalker { * @param key JSON name * @param value JSON node * @param listener JSON listener + * @throws SvcLogicException when processing the node fails */ private void processSingleNode(String key, JsonNode value, - JsonListener listener) { - //TODO: Implementation code. + JsonListener listener) + throws SvcLogicException { + NodeType nodeType; + if (!value.isContainerNode()) { + nodeType = SINGLE_INSTANCE_LEAF_NODE; + } else { + nodeType = SINGLE_INSTANCE_NODE; + } + processNode(key, value, nodeType, listener); } /** @@ -52,9 +85,57 @@ public class DefaultJsonWalker implements JsonWalker { * @param key JSON name * @param value JSON node * @param listener JSON listener + * @throws SvcLogicException when processing a single instance fails */ private void processMultiNodes(String key, JsonNode value, - JsonListener listener) { - //TODO: Implementation code. + JsonListener listener) + throws SvcLogicException { + NodeType nodeType; + Iterator<JsonNode> multiNodes = value.elements(); + while (multiNodes.hasNext()) { + if (isLeafListNode((ArrayNode) value)) { + nodeType = MULTI_INSTANCE_LEAF_NODE; + } else { + nodeType = MULTI_INSTANCE_NODE; + } + JsonNode multiNode = multiNodes.next(); + processNode(key, multiNode, nodeType, listener); + } + } + + /** + * Processes each node by first entering the JSON node through JSON + * listener, second a call back to walking the rest of the tree of the + * node and finally exiting the node. + * + * @param key JSON name + * @param node JSON node + * @param nodeType JSON node type + * @param listener JSON listener + * @throws SvcLogicException when entering a JSON node fails + */ + private void processNode(String key, JsonNode node, NodeType nodeType, + JsonListener listener) throws SvcLogicException { + listener.enterJsonNode(key, node, nodeType); + walk(listener, node); + listener.exitJsonNode(node); + } + + /** + * Returns true if the node corresponds to a leaf-list node; false + * otherwise. + * + * @param node JSON node + * @return true if node corresponds to leaf-list node; false otherwise + */ + private boolean isLeafListNode(ArrayNode node) { + Iterator<JsonNode> children = node.elements(); + while (children.hasNext()) { + JsonNodeType type = children.next().getNodeType(); + if (type != STRING && type != NUMBER) { + return false; + } + } + return true; } } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlListener.java index 7946d8d0..57969146 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlListener.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlListener.java @@ -21,6 +21,10 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; /** * Representation of default implementation of XML listener. @@ -42,17 +46,34 @@ public class DefaultXmlListener implements XmlListener { } @Override - public void enterXmlElement(Element element, XmlNodeType nodeType) { - //TODO: Implementation code. + public void enterXmlElement(Element element, XmlNodeType nodeType) + throws SvcLogicException { + switch (nodeType) { + case TEXT_NODE: + serializerHelper.addNode(element.getName(), + element.getNamespace().getURI(), + element.getText(), null, null); + break; + + case OBJECT_NODE: + serializerHelper.addNode(element.getName(), + element.getNamespace().getURI(), + null, null, null); + break; + + default: + throw new SvcLogicException(format(NODE_TYPE_ERR, + nodeType.toString())); + } } @Override - public void exitXmlElement(Element element) { - //TODO: Implementation code. + public void exitXmlElement(Element element) throws SvcLogicException { + serializerHelper.exitNode(); } @Override public SerializerHelper serializerHelper() { return serializerHelper; } - } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlWalker.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlWalker.java index cd2a3d49..cdc713f3 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlWalker.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlWalker.java @@ -21,6 +21,11 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import java.util.Iterator; + +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.getXmlNodeType; /** * Implementation of XML walker to walk through the nodes and process it. @@ -28,7 +33,16 @@ import org.dom4j.Element; public class DefaultXmlWalker implements XmlWalker { @Override - public void walk(XmlListener listener, Element xmlElement) { - //TODO: Implementation code. + public void walk(XmlListener listener, Element xmlElement) throws + SvcLogicException { + listener.enterXmlElement(xmlElement, getXmlNodeType(xmlElement)); + if (xmlElement.hasContent() && !xmlElement.isTextOnly()) { + Iterator i = xmlElement.elementIterator(); + while (i.hasNext()) { + Element childElement = (Element) i.next(); + walk(listener, childElement); + } + } + listener.exitXmlElement(xmlElement); } } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfListenerFactory.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfListenerFactory.java index 851f1b48..e10a085a 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfListenerFactory.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfListenerFactory.java @@ -20,6 +20,11 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.FORMAT_ERR; + /** * Represents the data format listener factory which will return JSON or XML * listener according to the serializer helper. @@ -52,9 +57,11 @@ public final class DfListenerFactory { * @param serHelper serializer helper * @param params parameters * @return data format listener + * @throws SvcLogicException when the data format type is wrong */ public Listener getListener(SerializerHelper serHelper, - YangParameters params) { + YangParameters params) + throws SvcLogicException { Listener listener; switch (params.format) { case JSON: @@ -65,9 +72,9 @@ public final class DfListenerFactory { listener = new DefaultXmlListener(serHelper); break; - //TODO: DataFormat Exception code to be added. default: - throw new IllegalArgumentException("In correct format"); + throw new SvcLogicException(format(FORMAT_ERR, + params.format)); } return listener; } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerFactory.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerFactory.java index 25b23fe2..bd0285e8 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerFactory.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerFactory.java @@ -20,6 +20,11 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.FORMAT_ERR; + /** * Represents the data format serializer factory which will return JSON or XML * serializer according to the serializer context. @@ -52,10 +57,11 @@ public final class DfSerializerFactory { * @param serCtx serializer context * @param params parameters * @return data format serializer + * @throws SvcLogicException when the data format type is wrong */ - public DataFormatSerializer getSerializer(DataFormatSerializerContext - serCtx, - YangParameters params) { + public DataFormatSerializer getSerializer(DataFormatSerializerContext serCtx, + YangParameters params) + throws SvcLogicException { DataFormatSerializer serializer; switch (params.format) { case JSON: @@ -66,9 +72,9 @@ public final class DfSerializerFactory { serializer = new XmlSerializer(serCtx); break; - //TODO: DataFormat Exception code to be added. default: - throw new IllegalArgumentException("In correct format"); + throw new SvcLogicException(format(FORMAT_ERR, + params.format)); } return serializer; } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerUtil.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerUtil.java new file mode 100644 index 00000000..6acb04a8 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerUtil.java @@ -0,0 +1,216 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URI; +import java.net.URISyntaxException; + +import static javax.xml.transform.OutputKeys.INDENT; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.XmlNodeType.OBJECT_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.XmlNodeType.TEXT_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getRevision; + +/** + * Utilities for data format serializer. + */ +public final class DfSerializerUtil { + + static final String JSON_WRITE_ERR = "Unable to write to JSON from " + + "properties."; + + static final String NODE_TYPE_ERR = "The node type %s is not supported."; + + static final String JSON_LIS_ERR = "The JSON serializer doesn't have " + + "JSON listener"; + + static final String XML_LIS_ERR = "The XML serializer doesn't have XML " + + "listener"; + + static final String JSON_TREE_ERR = "Unable to form JSON tree object from" + + " the JSON body provided."; + + static final String XML_TREE_ERR = "Unable to form XML tree object from " + + "the XML body provided."; + + static final String FORMAT_ERR = "Only JSON and XML formats are supported" + + ". %s is not supported"; + + static final String PROP_NODE_ERR = "The property node doesn't have " + + "schema node bound to it."; + + static final String DF_ERR = "Type mismatch for the node %s. The schema " + + "node does not match with the data format node type %s."; + + static final String UTF_HEADER = "<?xml version=\"1.0\" " + + "encoding=\"UTF-8\"?>"; + + static final String XML_PREFIX = "yangid"; + + private static final String YES = "yes"; + + private static final String INDENT_XMLNS = "{http://xml.apache" + + ".org/xslt}indent-amount"; + + private static final String XML_PARSE_ERR = "Unable to parse the xml to " + + "document : \n"; + + private static final String URI_ERR = "Unable to parse the URI"; + + //No instantiation. + private DfSerializerUtil() { + } + + /** + * Returns the writer which contains the pretty formatted XML string. + * + * @param input input XML + * @param indent indentation level + * @return writer with XML + * @throws SvcLogicException when transformation of source fails + */ + static Writer getXmlWriter(String input, String indent) + throws SvcLogicException { + try { + Transformer transformer = TransformerFactory.newInstance() + .newTransformer(); + transformer.setOutputProperty(INDENT, YES); + transformer.setOutputProperty(INDENT_XMLNS, indent); + StreamResult result = new StreamResult(new StringWriter()); + DOMSource source = new DOMSource(parseXml(input)); + transformer.transform(source, result); + return result.getWriter(); + } catch (TransformerException e) { + throw new SvcLogicException(XML_PARSE_ERR + input, e); + } + } + + /** + * Parses the XML and converts it into dom document which can be used for + * formatting the XML. + * + * @param in input XML + * @return dom document of XML + * @throws SvcLogicException when document building fails + */ + private static Document parseXml(String in) throws SvcLogicException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db; + try { + db = dbf.newDocumentBuilder(); + InputSource is = new InputSource(new StringReader(in)); + return db.parse(is); + } catch (SAXException | IOException | ParserConfigurationException e) { + throw new SvcLogicException(XML_PARSE_ERR + in, e); + } + } + + /** + * Returns the resolved namespace object from the input received from the + * abstract data format. + * + * @param mName module name + * @param curSchema current schema + * @param ctx schema context + * @param mUri module URI + * @param pNode properties node + * @return namespace + * @throws SvcLogicException when resolving namespace fails + */ + static Namespace getResolvedNamespace(String mName, SchemaNode curSchema, + SchemaContext ctx, String mUri, + PropertiesNode pNode) + throws SvcLogicException { + Module m = null; + URI namespace = curSchema.getQName().getNamespace(); + + if (mName != null) { + m = ctx.findModule(mName).get(); + namespace = m == null ? null : m.getNamespace(); + } + if (mUri != null) { + try { + m = ctx.findModule(new URI(mUri)).get(); + } catch (URISyntaxException e) { + throw new SvcLogicException(URI_ERR, e); + } + namespace = m == null ? null : m.getNamespace(); + mName = m.getName(); + } + + if (mName == null && mUri == null) { + return pNode.namespace(); + } + + return new Namespace(mName, namespace, getRevision(m.getRevision())); + } + + /** + * Returns the node type of a XML element. + * + * @param element XML element + * @return node type of the XML element + */ + static XmlNodeType getXmlNodeType(Element element) { + Element newElement = element.createCopy(); + newElement.remove(element.getNamespace()); + return newElement.hasContent() && newElement.isTextOnly() ? + TEXT_NODE : OBJECT_NODE; + } + + /** + * Resolves the super type to the base type from type definition. + * + * @param type super type + * @return base type definition + */ + static TypeDefinition<?> resolveBaseTypeFrom(TypeDefinition<?> type) { + TypeDefinition superType; + for(superType = type; superType.getBaseType() != null; + superType = superType.getBaseType()) { + } + return superType; + } + +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonListener.java index 2a9220ac..89fd4c8c 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonListener.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonListener.java @@ -21,6 +21,7 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; import com.fasterxml.jackson.databind.JsonNode; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; /** @@ -38,14 +39,17 @@ public interface JsonListener extends Listener { * @param nodeName JSON node name * @param node JSON node * @param nodeType JSON node type + * @throws SvcLogicException when node type is of wrong format */ - void enterJsonNode(String nodeName, JsonNode node, NodeType nodeType); + void enterJsonNode(String nodeName, JsonNode node, NodeType nodeType) + throws SvcLogicException; /** * Call back invoked during JSON node exit. All the related information * can be obtained from the JSON node. * * @param node JSON node + * @throws SvcLogicException when JSON node exit doesn't happen */ - void exitJsonNode(JsonNode node); + void exitJsonNode(JsonNode node) throws SvcLogicException; } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonSerializer.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonSerializer.java index b562e71d..1be1309b 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonSerializer.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonSerializer.java @@ -20,10 +20,20 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.DefaultPropertiesNodeWalker; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeWalker; + +import java.io.IOException; +import java.io.Writer; import java.util.List; import java.util.Map; import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormat.JSON; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.*; /** * Representation of JSON serializer which encodes properties to JSON and @@ -42,14 +52,38 @@ public class JsonSerializer extends DataFormatSerializer { @Override public String encode(Map<String, String> param, - Map<String, List<Annotation>> annotations) { - //TODO: Implementation code. - return null; + Map<String, List<Annotation>> annotations) + throws SvcLogicException { + PropertiesNode propNode = serializerContext().getPropNodeSerializer() + .encode(param); + PropertiesNodeWalker nodeWalker = new DefaultPropertiesNodeWalker<>(); + PropertiesNodeJsonListener jsonLis = new PropertiesNodeJsonListener(); + nodeWalker.walk(jsonLis, propNode); + Writer writer = jsonLis.getWriter(); + return writer.toString(); } @Override - public Map<String, String> decode(String dataFormatBody) { - //TODO: Implementation code. - return null; + public Map<String, String> decode(String dataFormatBody) + throws SvcLogicException { + if (!(serializerContext().listener() instanceof JsonListener)) { + throw new SvcLogicException(JSON_LIS_ERR); + } + + JsonListener listener = (JsonListener) serializerContext().listener(); + JsonWalker walker = new DefaultJsonWalker(); + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonNode; + + try { + jsonNode = mapper.readTree(dataFormatBody); + } catch (IOException e) { + throw new SvcLogicException(JSON_TREE_ERR, e); + } + + walker.walk(listener, jsonNode); + + return serializerContext().getPropNodeSerializer().decode( + listener.serializerHelper().getPropertiesNode()); } } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonWalker.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonWalker.java index e3fb4d51..588070a1 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonWalker.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonWalker.java @@ -21,6 +21,7 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; import com.fasterxml.jackson.databind.JsonNode; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; /** * Abstraction of an entity which provides interface for JSON walk. This @@ -36,6 +37,8 @@ public interface JsonWalker { * * @param listener JSON listener implemented by the protocol * @param jsonNode root node of the JSON data tree + * @throws SvcLogicException when walking the JSON node fails */ - void walk(JsonListener listener, JsonNode jsonNode); + void walk(JsonListener listener, JsonNode jsonNode) + throws SvcLogicException; } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/MdsalSerializerHelper.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/MdsalSerializerHelper.java index 1f8195e2..a3e30c4b 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/MdsalSerializerHelper.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/MdsalSerializerHelper.java @@ -20,10 +20,36 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.RootNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; + +import java.util.Deque; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.DF_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.PROP_NODE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.getResolvedNamespace; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.resolveBaseTypeFrom; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getRevision; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_HOLDER_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_HOLDER_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_NODE; +import static org.opendaylight.yangtools.yang.data.util.ParserStreamUtils.findSchemaNodeByNameAndNamespace; /** * Representation of MDSAL based serializer helper, which adds properties @@ -53,6 +79,12 @@ public class MdsalSerializerHelper extends SerializerHelper<SchemaNode, SchemaCo protected MdsalSerializerHelper(SchemaNode n, SchemaContext c, String u) { super(n, c, u); + Namespace ns = new Namespace(n.getQName().getLocalName(), + n.getQName().getNamespace(), + getRevision(n.getQName().getRevision())); + propNode = new RootNode<>(n.getQName().getLocalName(), ns, + getSchemaNode(), u); + curSchemaNode = getSchemaNode(); } @Override @@ -72,18 +104,166 @@ public class MdsalSerializerHelper extends SerializerHelper<SchemaNode, SchemaCo @Override protected void addNode(String name, String nameSpace, String value, - String valNameSpace, NodeType type) { - //TODO: Implementation code. + String valNameSpace, NodeType type) + throws SvcLogicException { + Namespace ns; + if (type == null) { + ns = getResolvedNamespace(null, curSchemaNode, getSchemaCtx(), + nameSpace, propNode); + } else { + ns = getResolvedNamespace(nameSpace, curSchemaNode, getSchemaCtx(), + nameSpace, propNode); + } + if (isChildPresent(name, ns)) { + addNodeToProperty(name, ns, value, valNameSpace, type); + } } @Override - protected void exitNode() { - //TODO: Implementation code. + protected void exitNode() throws SvcLogicException { + propNode = propNode.parent(); + if (propNode != null) { + NodeType type = propNode.nodeType(); + if (type == MULTI_INSTANCE_HOLDER_NODE || + type == MULTI_INSTANCE_LEAF_HOLDER_NODE) { + propNode = propNode.parent(); + } + } + if (propNode == null || propNode.appInfo() == null + || !(propNode.appInfo() instanceof SchemaNode)) { + throw new SvcLogicException(PROP_NODE_ERR); + } + curSchemaNode = (SchemaNode) propNode.appInfo(); } @Override protected PropertiesNode getPropertiesNode() { - //TODO: Implementation code. - return null; + return propNode; + } + + /** + * Adds the node to property node based on the type of the schema node, + * which is decided based on the name and namespace of the input + * information. + * + * @param name name of the node + * @param ns namespace of the node + * @param value value of the node if its a leaf/leaf-list + * @param valNamespace namespace of the value + * @param type type of the node + * @throws SvcLogicException when adding child fails + */ + private void addNodeToProperty(String name, Namespace ns, String value, + String valNamespace, NodeType type) + throws SvcLogicException { + Namespace valueNs; + if (type != null) { + validateNodeType(type); + } + if (curSchemaNode instanceof LeafSchemaNode) { + valueNs = getValueNs(curSchemaNode, valNamespace, type); + propNode = propNode.addChild(name, ns, + SINGLE_INSTANCE_LEAF_NODE, + value, valueNs, curSchemaNode); + } else if (curSchemaNode instanceof LeafListSchemaNode) { + valueNs = getValueNs(curSchemaNode, valNamespace, type); + propNode = propNode.addChild(null, name, ns, + MULTI_INSTANCE_LEAF_NODE, value, + valueNs, curSchemaNode); + } else if (curSchemaNode instanceof ListSchemaNode) { + propNode = propNode.addChild(null, name, ns, MULTI_INSTANCE_NODE, + curSchemaNode); + } else { + propNode = propNode.addChild(name, ns, SINGLE_INSTANCE_NODE, + curSchemaNode); + } + } + + /** + * Returns the namespace of the value namespace in case of identity ref. + * + * @param schemaNode schema node + * @param valNs value name space + * @param nodeType node type + * @return namespace of value namespace + * @throws SvcLogicException when namespace resolution fails for identityref + */ + private Namespace getValueNs(SchemaNode schemaNode, String valNs, + NodeType nodeType) throws SvcLogicException { + Namespace ns = null; + if (valNs != null) { + TypeDefinition type = ((LeafSchemaNode) schemaNode).getType(); + TypeDefinition<?> baseType = resolveBaseTypeFrom(type); + if (baseType instanceof IdentityrefTypeDefinition) { + if (nodeType == null) { + ns = getResolvedNamespace(null,schemaNode, getSchemaCtx(), + valNs, propNode); + } else { + ns = getResolvedNamespace(valNs, schemaNode, getSchemaCtx(), + null, propNode); + } + } + } + return ns; + } + + /** + * Validates that the node type from the data format matches with that of + * the corresponding schema node. + * + * @param type node type from the abstract data format + * @throws SvcLogicException when the node type is wrong + */ + private void validateNodeType(NodeType type) throws SvcLogicException { + boolean verify; + switch (type) { + case SINGLE_INSTANCE_LEAF_NODE: + verify = curSchemaNode instanceof LeafSchemaNode; + break; + + case MULTI_INSTANCE_LEAF_NODE: + verify = curSchemaNode instanceof LeafListSchemaNode; + break; + + case MULTI_INSTANCE_NODE: + verify = curSchemaNode instanceof ListSchemaNode; + break; + + case SINGLE_INSTANCE_NODE: + verify = (!(curSchemaNode instanceof LeafSchemaNode) && + !(curSchemaNode instanceof LeafListSchemaNode) && + !(curSchemaNode instanceof ListSchemaNode)); + break; + + default: + throw new SvcLogicException(format(NODE_TYPE_ERR, + type.toString())); + } + if (!verify) { + throw new SvcLogicException(format(DF_ERR, curSchemaNode + .getQName().getLocalName(), type.toString())); + } + } + + /** + * Returns true if the child schema is present with the name and + * namespace inside the current schema node, if present updates the + * current schema node; false otherwise. + * + * @param name name of the child schema node + * @param namespace namespace of the child schema node + * @return returns true if the child schema is available; false otherwise + */ + private boolean isChildPresent(String name, Namespace namespace) { + Deque<DataSchemaNode> dataSchema = findSchemaNodeByNameAndNamespace( + (DataSchemaNode) curSchemaNode, name, namespace.moduleNs()); + if (dataSchema != null) { + DataSchemaNode node = dataSchema.pop(); + if (node != null) { + curSchemaNode = node; + return true; + } + } + return false; } } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeJsonListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeJsonListener.java index ec130673..e51ccf7a 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeJsonListener.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeJsonListener.java @@ -21,10 +21,24 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; import com.google.gson.stream.JsonWriter; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.DefaultPropertiesNodeWalker; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.LeafNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeListener; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.RootNode; +import java.io.IOException; +import java.io.StringWriter; import java.io.Writer; +import java.util.Collection; +import java.util.Map; + +import static com.google.common.base.Strings.repeat; +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.JSON_WRITE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; /** * Representation of JSON implementation of properties node listener. @@ -46,25 +60,160 @@ public class PropertiesNodeJsonListener implements PropertiesNodeListener{ * indenting the writer. */ public PropertiesNodeJsonListener() { + writer = new StringWriter(); + jsonWriter = new JsonWriter(writer); + jsonWriter.setIndent(repeat(" ", 4)); } @Override - public void start(PropertiesNode node) { - //TODO: Implementation code. + public void start(PropertiesNode node) throws SvcLogicException { + try { + jsonWriter.beginObject(); + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } } @Override - public void end(PropertiesNode node) { - //TODO: Implementation code. + public void end(PropertiesNode node) throws SvcLogicException { + try { + jsonWriter.endObject(); + jsonWriter.flush(); + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } } @Override - public void enterPropertiesNode(PropertiesNode node) { - //TODO: Implementation code. + public void enterPropertiesNode(PropertiesNode node) + throws SvcLogicException { + String val; + String nodeName = getNodeName(node); + try { + switch (node.nodeType()) { + case SINGLE_INSTANCE_NODE: + jsonWriter.name(nodeName); + jsonWriter.beginObject(); + break; + + case MULTI_INSTANCE_NODE: + jsonWriter.beginObject(); + break; + + case SINGLE_INSTANCE_LEAF_NODE: + val = getValueWithNs((LeafNode) node); + jsonWriter.name(nodeName).value(val); + break; + + case MULTI_INSTANCE_HOLDER_NODE: + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + jsonWriter.name(nodeName); + jsonWriter.beginArray(); + break; + + case MULTI_INSTANCE_LEAF_NODE: + val = getValueWithNs((LeafNode) node); + jsonWriter.value(val); + break; + + default: + throw new SvcLogicException(format( + NODE_TYPE_ERR, node.nodeType().toString())); + + } + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } } @Override - public void exitPropertiesNode(PropertiesNode node) { - //TODO: Implementation code. + public void exitPropertiesNode(PropertiesNode node) throws SvcLogicException { + walkAugmentationNode(node); + try { + switch (node.nodeType()) { + case SINGLE_INSTANCE_NODE: + case MULTI_INSTANCE_NODE: + jsonWriter.endObject(); + break; + + case MULTI_INSTANCE_HOLDER_NODE: + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + jsonWriter.endArray(); + break; + + case SINGLE_INSTANCE_LEAF_NODE: + case MULTI_INSTANCE_LEAF_NODE: + break; + + default: + throw new SvcLogicException(format( + NODE_TYPE_ERR, node.nodeType().toString())); + } + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } + } + + /** + * Returns the writer. + * + * @return writer + */ + public Writer getWriter() { + return writer; + } + + /** + * Returns the abstract JSON node name to be used in JSON data format + * from the properties node. + * + * @param node properties node + * @return abstract JSON node + */ + private String getNodeName(PropertiesNode node) { + PropertiesNode parent = node.parent(); + if (parent instanceof RootNode || !parent.namespace().moduleName() + .equals(node.namespace().moduleName())) { + return node.namespace().moduleName() + ":" + node.name(); + } + return node.name(); + } + + /** + * Returns the value of JSON leaf node with module name if required. + * + * @param node properties node + * @return value with namespace + */ + private String getValueWithNs(LeafNode node) { + Namespace valNs = node.valueNs(); + String modName = (valNs == null) ? null : valNs.moduleName(); + if (modName != null) { + return modName + ":" + node.value(); + } + return node.value(); + } + + /** + * Gets all the augmentation of the given node and walks through it. + * + * @param node properties node + * @throws SvcLogicException when walking the properties node fails + */ + private void walkAugmentationNode(PropertiesNode node) + throws SvcLogicException { + for (Map.Entry<Object, Collection<PropertiesNode>> + augToChild : node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> augChild = augToChild.getValue(); + if (!augChild.isEmpty()) { + DefaultPropertiesNodeWalker walker = new + DefaultPropertiesNodeWalker(); + for (PropertiesNode p : augChild) { + enterPropertiesNode(p); + walker.walkChildNode(this, p); + exitPropertiesNode(p); + } + } + } } } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeXmlListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeXmlListener.java index cfc59ca1..cf59b779 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeXmlListener.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeXmlListener.java @@ -20,13 +20,29 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; +import org.dom4j.Document; +import org.dom4j.DocumentHelper; import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.DefaultPropertiesNodeWalker; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.LeafNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeListener; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.RootNode; import java.io.Writer; +import java.net.URI; +import java.util.Collection; +import java.util.Map; import java.util.Stack; +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.UTF_HEADER; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.XML_PREFIX; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.getXmlWriter; + /** * Representation of XML implementation of properties node listener. */ @@ -60,21 +76,169 @@ public class PropertiesNodeXmlListener implements PropertiesNodeListener { @Override public void start(PropertiesNode node) { - //TODO: Implementation code. + //Do Nothing. } @Override - public void end(PropertiesNode node) { - //TODO: Implementation code. + public void end(PropertiesNode node) throws SvcLogicException { + xmlData = UTF_HEADER + xmlData; + writer = getXmlWriter(xmlData, "4"); } @Override - public void enterPropertiesNode(PropertiesNode node) { - //TODO: Implementation code. + public void enterPropertiesNode(PropertiesNode node) + throws SvcLogicException { + Element element = null; + String ns = getNodeNamespace(node); + switch (node.nodeType()) { + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + case MULTI_INSTANCE_HOLDER_NODE: + break; + + case SINGLE_INSTANCE_NODE: + case MULTI_INSTANCE_NODE: + element = addElement(ns, node); + break; + + case MULTI_INSTANCE_LEAF_NODE: + case SINGLE_INSTANCE_LEAF_NODE: + element = addElement(ns, node); + setValueWithNs(element, (LeafNode) node); + break; + + default: + throw new SvcLogicException(format( + NODE_TYPE_ERR, node.nodeType().toString())); + } + if (element != null) { + if (elementStack.isEmpty()) { + rootElement = element; + } + elementStack.push(element); + } } @Override - public void exitPropertiesNode(PropertiesNode node) { - //TODO: Implementation code. + public void exitPropertiesNode(PropertiesNode node) + throws SvcLogicException { + walkAugmentationNode(node); + switch (node.nodeType()) { + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + case MULTI_INSTANCE_HOLDER_NODE: + break; + + case SINGLE_INSTANCE_NODE: + case MULTI_INSTANCE_NODE: + case MULTI_INSTANCE_LEAF_NODE: + case SINGLE_INSTANCE_LEAF_NODE: + if (!elementStack.isEmpty() && + elementStack.peek().equals(rootElement)) { + xmlData = rootElement.asXML(); + } else { + elementStack.pop(); + } + break; + + default: + throw new SvcLogicException(format( + NODE_TYPE_ERR, node.nodeType().toString())); + } + } + + /** + * Returns the writer. + * + * @return writer + */ + public Writer getWriter() { + return writer; + } + + /** + * Adds an XML element to the stack with namespace if present. If the + * stack is empty it creates new document and adds element else adds to + * the parent element. + * + * @param ns namespace of the element + * @param node properties node + * @return new added element + */ + private Element addElement(String ns, PropertiesNode node) { + Element element; + if (elementStack.isEmpty()) { + Document doc = DocumentHelper.createDocument(); + if (ns != null) { + element = doc.addElement(node.name(), ns); + } else { + element = doc.addElement(node.name()); + } + } else { + element = elementStack.peek(); + if (ns != null) { + element = element.addElement(node.name(), ns); + } else { + element = element.addElement(node.name()); + } + } + + return element; + } + + /** + * Returns the abstract XML namespace to be used in XML data format from + * the properties node. + * + * @param node properties node + * @return abstract XML namespace + */ + private String getNodeNamespace(PropertiesNode node) { + PropertiesNode parent = node.parent(); + if (parent instanceof RootNode || !parent.namespace().moduleName() + .equals(node.namespace().moduleName())) { + return node.namespace().moduleNs().toString(); + } + return null; + } + + /** + * Sets the value to the element for a leaf node and adds the value + * namespace if required. + * + * @param element XML element + * @param node leaf properties node + */ + private void setValueWithNs(Element element, LeafNode node) { + Namespace valNs = node.valueNs(); + URI modNs = (valNs == null) ? null : valNs.moduleNs(); + String val = node.value(); + if (modNs != null) { + element.addNamespace(XML_PREFIX, modNs.toString()); + element.setText(XML_PREFIX + ":" + val); + } else { + element.setText(val); + } + } + + /** + * Gets all the augmentation of the given node and walks through it. + * + * @param node properties node + * @throws SvcLogicException when walking the properties node fails + */ + private void walkAugmentationNode(PropertiesNode node) + throws SvcLogicException { + for (Map.Entry<Object, Collection<PropertiesNode>> + augToChild : node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> augChild = augToChild.getValue(); + if (!augChild.isEmpty()) { + DefaultPropertiesNodeWalker walker = new + DefaultPropertiesNodeWalker(); + for (PropertiesNode p : augChild) { + enterPropertiesNode(p); + walker.walkChildNode(this, p); + exitPropertiesNode(p); + } + } + } } } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/SerializerHelper.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/SerializerHelper.java index 2466023f..db9befb2 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/SerializerHelper.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/SerializerHelper.java @@ -20,6 +20,7 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; @@ -92,15 +93,19 @@ public abstract class SerializerHelper<T, P> { * @param valNameSpace value namespace for identityref, could be module * name or namespace * @param type type of node if known like in case of JSON + * @throws SvcLogicException when adding node fails */ protected abstract void addNode(String name, String nameSpace, String value, - String valNameSpace, NodeType type); + String valNameSpace, NodeType type) + throws SvcLogicException; /** * Exits the node, in case if it's leaf node then it adds to the properties * map. + * + * @throws SvcLogicException when properties node tree is improper */ - protected abstract void exitNode(); + protected abstract void exitNode() throws SvcLogicException; /** * Returns the built properties corresponding to the data. diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlListener.java index 0fbf4c33..784e7af1 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlListener.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlListener.java @@ -21,6 +21,7 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; /** * Abstraction of an entity which provides call back methods, which in turn @@ -36,14 +37,17 @@ public interface XmlListener extends Listener { * * @param element current XML element * @param nodeType node type of the element + * @throws SvcLogicException when node type is of wrong format */ - void enterXmlElement(Element element, XmlNodeType nodeType); + void enterXmlElement(Element element, XmlNodeType nodeType) + throws SvcLogicException; /** * Callback invoked during a node exit. All the related information about * the node can be obtained from the element. * * @param element current xml element. + * @throws SvcLogicException when XML node exit doesn't happen */ - void exitXmlElement(Element element); + void exitXmlElement(Element element) throws SvcLogicException; } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlSerializer.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlSerializer.java index 51647005..6eeb4b82 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlSerializer.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlSerializer.java @@ -20,10 +20,21 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.DefaultPropertiesNodeWalker; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeWalker; + +import java.io.Writer; import java.util.List; import java.util.Map; import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormat.XML; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.XML_LIS_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.XML_TREE_ERR; /** * Representation of XML serializer which encodes properties to XML and @@ -42,14 +53,36 @@ public class XmlSerializer extends DataFormatSerializer { @Override public String encode(Map<String, String> param, - Map<String, List<Annotation>> annotations) { - //TODO: Implementation code. - return null; + Map<String, List<Annotation>> annotations) + throws SvcLogicException { + PropertiesNode propNode = serializerContext().getPropNodeSerializer() + .encode(param); + PropertiesNodeWalker nodeWalker = new DefaultPropertiesNodeWalker<>(); + PropertiesNodeXmlListener xmlListener = new PropertiesNodeXmlListener(); + nodeWalker.walk(xmlListener, propNode); + Writer writer = xmlListener.getWriter(); + return writer.toString(); } @Override - public Map<String, String> decode(String dataFormatBody) { - //TODO: Implementation code. - return null; + public Map<String, String> decode(String dataFormatBody) + throws SvcLogicException { + if (!(serializerContext().listener() instanceof XmlListener)) { + throw new SvcLogicException(XML_LIS_ERR); + } + + XmlListener listener = (XmlListener) serializerContext().listener(); + XmlWalker walker = new DefaultXmlWalker(); + Document document; + + try { + document = DocumentHelper.parseText(dataFormatBody); + } catch (DocumentException e) { + throw new SvcLogicException(XML_TREE_ERR, e); + } + walker.walk(listener, document.getRootElement()); + + return serializerContext().getPropNodeSerializer().decode( + listener.serializerHelper().getPropertiesNode()); } }
\ No newline at end of file diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlWalker.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlWalker.java index 6fed510a..3835faa7 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlWalker.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlWalker.java @@ -21,6 +21,7 @@ package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; /** * Abstraction of an entity which provides interface for XML walk. This @@ -36,6 +37,8 @@ public interface XmlWalker { * * @param listener XML listener implemented by the protocol * @param xmlElement root element of the XML data tree + * @throws SvcLogicException when walking the XML node fails */ - void walk(XmlListener listener, Element xmlElement); + void walk(XmlListener listener, Element xmlElement) throws + SvcLogicException; } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeListener.java index a8a9b493..d9120912 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeListener.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeListener.java @@ -20,6 +20,8 @@ package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -40,7 +42,7 @@ public class DefaultPropertiesNodeListener implements PropertiesNodeListener { } @Override - public void end(PropertiesNode node) { + public void end(PropertiesNode node) throws SvcLogicException { exitPropertiesNode(node); } @@ -57,7 +59,8 @@ public class DefaultPropertiesNodeListener implements PropertiesNodeListener { } @Override - public void exitPropertiesNode(PropertiesNode node) { + public void exitPropertiesNode(PropertiesNode node) throws + SvcLogicException { if (!node.augmentations().isEmpty()) { for (Map.Entry<Object, Collection<PropertiesNode>> augmentationTochild : node.augmentations().asMap().entrySet()) { diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeWalker.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeWalker.java index 041210f2..8497805c 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeWalker.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeWalker.java @@ -20,6 +20,8 @@ package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + import java.util.Map; /** @@ -31,7 +33,7 @@ public class DefaultPropertiesNodeWalker<T extends NodeChild> implements Propert @Override public void walk(PropertiesNodeListener listener, - PropertiesNode propertiesNode) { + PropertiesNode propertiesNode) throws SvcLogicException { listener.start(propertiesNode); walkChildNode(listener, propertiesNode); listener.end(propertiesNode); @@ -42,9 +44,11 @@ public class DefaultPropertiesNodeWalker<T extends NodeChild> implements Propert * * @param listener properties node listener * @param propertiesNode properties node + * @throws SvcLogicException when properties node walking fails */ public void walkChildNode(PropertiesNodeListener listener, - PropertiesNode propertiesNode) { + PropertiesNode propertiesNode) + throws SvcLogicException { Map<String, T> children = getChildren(propertiesNode); if (children != null) { for (Map.Entry<String, T> entry : children.entrySet()) { diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeSerializer.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeSerializer.java index 20b06d0b..c2414626 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeSerializer.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeSerializer.java @@ -86,7 +86,8 @@ public class MdsalPropertiesNodeSerializer extends PropertiesNodeSerializer<Sche } @Override - public Map<String, String> decode(PropertiesNode propertiesNode) { + public Map<String, String> decode(PropertiesNode propertiesNode) + throws SvcLogicException { PropertiesNodeWalker walker = new DefaultPropertiesNodeWalker<>(); DefaultPropertiesNodeListener listener = new DefaultPropertiesNodeListener(); walker.walk(listener, propertiesNode); diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeListener.java index 5bf7fe9d..7b97ffaf 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeListener.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeListener.java @@ -20,6 +20,8 @@ package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + /** * Abstraction of properties node listener. */ @@ -29,27 +31,31 @@ public interface PropertiesNodeListener { * Pre-configurations required before starting the walking. * * @param node properties node + * @throws SvcLogicException when the pre-configuration fails */ - void start(PropertiesNode node); + void start(PropertiesNode node) throws SvcLogicException; /** * Post-configurations required after starting the walking. * * @param node properties node + * @throws SvcLogicException when the post-configuration fails */ - void end(PropertiesNode node); + void end(PropertiesNode node) throws SvcLogicException; /** * Enters the properties node. * * @param node properties node + * @throws SvcLogicException when entering the properties node fails */ - void enterPropertiesNode(PropertiesNode node); + void enterPropertiesNode(PropertiesNode node) throws SvcLogicException; /** * Enters the properties node. * * @param node properties node + * @throws SvcLogicException when exiting the properties node fails */ - void exitPropertiesNode(PropertiesNode node); + void exitPropertiesNode(PropertiesNode node) throws SvcLogicException; } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeSerializer.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeSerializer.java index 3e348372..fe6fed48 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeSerializer.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeSerializer.java @@ -77,10 +77,11 @@ public abstract class PropertiesNodeSerializer<T, P> { * Decodes from properties-node to properties map. * * @param propertiesNode properties-node - * @throws SvcLogicException fails to decode properties node to properties * @return parameter map + * @throws SvcLogicException fails to decode properties node to properties */ - public abstract Map<String, String> decode(PropertiesNode propertiesNode) throws SvcLogicException; + public abstract Map<String, String> decode(PropertiesNode propertiesNode) + throws SvcLogicException; /** * Returns the schema node of the property diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeWalker.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeWalker.java index 48433e2b..36ee4dd9 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeWalker.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeWalker.java @@ -20,16 +20,19 @@ package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + /** * Abstraction of properties node walker */ public interface PropertiesNodeWalker { - /** * Walks the properties node with the listener. * * @param listener properties node listener. * @param propertiesNode properties node + * @throws SvcLogicException when walking the properties node fails */ - void walk(PropertiesNodeListener listener, PropertiesNode propertiesNode); + void walk(PropertiesNodeListener listener, PropertiesNode propertiesNode) + throws SvcLogicException; } diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/RootNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/RootNode.java index 7d9035e0..c7f7340f 100644 --- a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/RootNode.java +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/RootNode.java @@ -44,7 +44,15 @@ public class RootNode<T extends NodeChild> extends PropertiesNode { private Map<String, T> children = new HashMap<String, T>(); - protected RootNode(String name, Namespace namespace, + /** + * Creates an instance of the root node to build the properties. + * + * @param name name of the node + * @param namespace namespace of the node + * @param appInfo application info + * @param uri URI of the node + */ + public RootNode(String name, Namespace namespace, Object appInfo, String uri) { super(name, namespace, uri, null, appInfo, null); } |