BUG-1041 Make rpc-request -> xml translation use schema context 32/7732/3
authorMaros Marsalek <mmarsale@cisco.com>
Thu, 5 Jun 2014 12:03:07 +0000 (14:03 +0200)
committerMaros Marsalek <mmarsale@cisco.com>
Fri, 6 Jun 2014 08:39:14 +0000 (10:39 +0200)
Sal-netconf-connector now uses schema context if available to transform between rpc-request represented as DOM nodes to Xml.

This is crucial for e.g. identity-ref type leaves in edit-config.

Change-Id: I5b8602e7bf21e52c27b94daa3ac55213375641b5
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NodeContainerProxy.java [new file with mode: 0644]

index c85a529..2adc1be 100644 (file)
@@ -7,12 +7,11 @@
  */
 package org.opendaylight.controller.sal.connect.netconf.schema.mapping;
 
+import com.google.common.base.Optional;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
-
 import javax.activation.UnsupportedDataTypeException;
-
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.sal.common.util.Rpcs;
 import org.opendaylight.controller.sal.connect.api.MessageTransformer;
@@ -24,15 +23,15 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider;
 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
 import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-import com.google.common.base.Optional;
-
 public class NetconfMessageTransformer implements MessageTransformer<NetconfMessage> {
 
     public static final String MESSAGE_ID_PREFIX = "m";
@@ -65,7 +64,17 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
                 NetconfMessageTransformUtil.NETCONF_RPC_QNAME, NetconfMessageTransformUtil.flattenInput(node));
         final Document w3cPayload;
         try {
-            w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, XmlDocumentUtils.defaultValueCodecProvider());
+            final XmlCodecProvider codecProvider = XmlDocumentUtils.defaultValueCodecProvider();
+            if(schemaContext.isPresent()) {
+                if (NetconfMessageTransformUtil.isDataEditOperation(rpc)) {
+                    final DataNodeContainer schemaForEdit = NetconfMessageTransformUtil.createSchemaForEdit(schemaContext.get());
+                    w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, schemaForEdit, codecProvider);
+                } else {
+                    w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, schemaContext.get(), codecProvider);
+                }
+            } else {
+                w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, codecProvider);
+            }
         } catch (final UnsupportedDataTypeException e) {
             throw new IllegalArgumentException("Unable to create message", e);
         }
index 0c6ad45..c51009f 100644 (file)
@@ -11,8 +11,8 @@ import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-
 import java.util.Map;
+
 import javax.annotation.Nullable;
 
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -26,8 +26,10 @@ import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
-import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
 import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -35,6 +37,7 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 
 public class NetconfMessageTransformUtil {
 
@@ -154,6 +157,36 @@ public class NetconfMessageTransformUtil {
                         NETCONF_GET_QNAME.getLocalName()));
     }
 
+    public static boolean isDataEditOperation(final QName rpc) {
+        return NETCONF_URI.equals(rpc.getNamespace())
+                && rpc.getLocalName().equals(NETCONF_EDIT_CONFIG_QNAME.getLocalName());
+    }
+
+    /**
+     * Creates artificial schema node for edit-config rpc. This artificial schema looks like:
+     * <pre>
+     * {@code
+     * rpc
+     *   edit-config
+     *     config
+     *         // All schema nodes from remote schema
+     *     config
+     *   edit-config
+     * rpc
+     * }
+     * </pre>
+     *
+     * This makes the translation of rpc edit-config request(especially the config node)
+     * to xml use schema which is crucial for some types of nodes e.g. identity-ref.
+     */
+    public static DataNodeContainer createSchemaForEdit(final SchemaContext schemaContext) {
+        final QName config = QName.create(NETCONF_EDIT_CONFIG_QNAME, "config");
+        final QName editConfig = QName.create(NETCONF_EDIT_CONFIG_QNAME, "edit-config");
+        final NodeContainerProxy configProxy = new NodeContainerProxy(config, schemaContext.getChildNodes());
+        final NodeContainerProxy editConfigProxy = new NodeContainerProxy(editConfig, Sets.<DataSchemaNode>newHashSet(configProxy));
+        return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.<DataSchemaNode>newHashSet(editConfigProxy));
+    }
+
     public static CompositeNodeTOImpl wrap(final QName name, final Node<?> node) {
         if (node != null) {
             return new CompositeNodeTOImpl(name, null, Collections.<Node<?>> singletonList(node));
diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NodeContainerProxy.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NodeContainerProxy.java
new file mode 100644 (file)
index 0000000..bd075d0
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.connect.netconf.util;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+
+class NodeContainerProxy implements ContainerSchemaNode {
+
+    private final Map<QName, DataSchemaNode> childNodes;
+    private final QName qName;
+
+    public NodeContainerProxy(final QName qName, final Map<QName, DataSchemaNode> childNodes) {
+        this.childNodes = Preconditions.checkNotNull(childNodes, "childNodes");
+        this.qName = Preconditions.checkNotNull(qName, "qName");
+    }
+
+    public NodeContainerProxy(final QName qName, final Set<DataSchemaNode> childNodes) {
+        this(qName, asMap(childNodes));
+    }
+
+    private static Map<QName, DataSchemaNode> asMap(final Set<DataSchemaNode> childNodes) {
+        final Map<QName, DataSchemaNode> mapped = Maps.newHashMap();
+        for (final DataSchemaNode childNode : childNodes) {
+            mapped.put(childNode.getQName(), childNode);
+        }
+        return mapped;
+    }
+
+    @Override
+    public Set<TypeDefinition<?>> getTypeDefinitions() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<DataSchemaNode> getChildNodes() {
+        return Sets.newHashSet(childNodes.values());
+    }
+
+    @Override
+    public Set<GroupingDefinition> getGroupings() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public DataSchemaNode getDataChildByName(final QName qName) {
+        return childNodes.get(qName);
+    }
+
+    @Override
+    public DataSchemaNode getDataChildByName(final String s) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<UsesNode> getUses() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public boolean isPresenceContainer() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<AugmentationSchema> getAvailableAugmentations() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isAugmenting() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isConfiguration() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ConstraintDefinition getConstraints() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public QName getQName() {
+        return qName;
+    }
+
+    @Override
+    public SchemaPath getPath() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getDescription() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getReference() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Status getStatus() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+        return Collections.emptyList();
+    }
+}