Implementation of Data Format serializer
[ccsdk/sli/plugins.git] / restconf-client / provider / src / main / java / org / onap / ccsdk / sli / plugins / yangserializers / dfserializer / MdsalSerializerHelper.java
index 1f8195e..a3e30c4 100644 (file)
 
 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;
     }
 }