2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.sal.connect.netconf
10 import com.google.common.base.Optional
11 import com.google.common.base.Preconditions
12 import com.google.common.collect.ImmutableList
14 import java.util.ArrayList
15 import java.util.Collections
18 import java.util.concurrent.atomic.AtomicInteger
19 import org.opendaylight.controller.sal.common.util.Rpcs
20 import org.opendaylight.yangtools.yang.data.api.CompositeNode
21 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
22 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
23 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
24 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
25 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode
26 import java.util.Collections
29 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
30 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
31 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
32 import org.opendaylight.yangtools.yang.data.api.Node
33 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
34 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils
35 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
36 import org.opendaylight.yangtools.yang.model.api.SchemaContext
37 import org.w3c.dom.Document
38 import org.w3c.dom.Element
39 import org.opendaylight.yangtools.yang.common.QName
40 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
41 import org.opendaylight.controller.netconf.api.NetconfMessage
42 import org.opendaylight.yangtools.yang.common.RpcResult
44 class NetconfMapping {
46 public static val NETCONF_URI = URI.create("urn:ietf:params:xml:ns:netconf:base:1.0")
47 public static val NETCONF_MONITORING_URI = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"
48 public static val NETCONF_NOTIFICATION_URI = URI.create("urn:ietf:params:xml:ns:netconf:notification:1.0")
51 public static val NETCONF_QNAME = QName.create(NETCONF_URI, null, "netconf");
52 public static val NETCONF_RPC_QNAME = QName.create(NETCONF_QNAME, "rpc");
53 public static val NETCONF_GET_QNAME = QName.create(NETCONF_QNAME, "get");
54 public static val NETCONF_FILTER_QNAME = QName.create(NETCONF_QNAME, "filter");
55 public static val NETCONF_TYPE_QNAME = QName.create(NETCONF_QNAME, "type");
56 public static val NETCONF_GET_CONFIG_QNAME = QName.create(NETCONF_QNAME, "get-config");
57 public static val NETCONF_EDIT_CONFIG_QNAME = QName.create(NETCONF_QNAME, "edit-config");
58 public static val NETCONF_DELETE_CONFIG_QNAME = QName.create(NETCONF_QNAME, "delete-config");
59 public static val NETCONF_OPERATION_QNAME = QName.create(NETCONF_QNAME, "operation");
60 public static val NETCONF_COMMIT_QNAME = QName.create(NETCONF_QNAME, "commit");
62 public static val NETCONF_CONFIG_QNAME = QName.create(NETCONF_QNAME, "config");
63 public static val NETCONF_SOURCE_QNAME = QName.create(NETCONF_QNAME, "source");
64 public static val NETCONF_TARGET_QNAME = QName.create(NETCONF_QNAME, "target");
66 public static val NETCONF_CANDIDATE_QNAME = QName.create(NETCONF_QNAME, "candidate");
67 public static val NETCONF_RUNNING_QNAME = QName.create(NETCONF_QNAME, "running");
70 public static val NETCONF_RPC_REPLY_QNAME = QName.create(NETCONF_QNAME, "rpc-reply");
71 public static val NETCONF_OK_QNAME = QName.create(NETCONF_QNAME, "ok");
72 public static val NETCONF_DATA_QNAME = QName.create(NETCONF_QNAME, "data");
73 public static val NETCONF_CREATE_SUBSCRIPTION_QNAME = QName.create(NETCONF_NOTIFICATION_URI,null,"create-subscription");
74 public static val NETCONF_CANCEL_SUBSCRIPTION_QNAME = QName.create(NETCONF_NOTIFICATION_URI,null,"cancel-subscription");
75 public static val IETF_NETCONF_MONITORING_MODULE = QName.create(NETCONF_MONITORING_URI, "2010-10-04","ietf-netconf-monitoring");
77 static List<Node<?>> RUNNING = Collections.<Node<?>>singletonList(
78 new SimpleNodeTOImpl(NETCONF_RUNNING_QNAME, null, null));
79 public static val CONFIG_SOURCE_RUNNING = new CompositeNodeTOImpl(NETCONF_SOURCE_QNAME, null, RUNNING);
81 static val messageId = new AtomicInteger(0);
83 static def Node<?> toFilterStructure(InstanceIdentifier identifier) {
84 var Node<?> previous = null;
85 if(identifier.path.empty) {
89 for (component : identifier.path.reverseView) {
90 val Node<?> current = component.toNode(previous);
93 return filter("subtree",previous);
96 static def dispatch Node<?> toNode(NodeIdentifierWithPredicates argument, Node<?> node) {
97 val list = new ArrayList<Node<?>>();
98 for (arg : argument.keyValues.entrySet) {
99 list.add = new SimpleNodeTOImpl(arg.key, null, arg.value);
104 return new CompositeNodeTOImpl(argument.nodeType, null, list)
107 static def dispatch Node<?> toNode(PathArgument argument, Node<?> node) {
109 return new CompositeNodeTOImpl(argument.nodeType, null, Collections.singletonList(node));
111 return new SimpleNodeTOImpl(argument.nodeType, null, null);
115 static def CompositeNode toCompositeNode(NetconfMessage message,Optional<SchemaContext> ctx) {
116 //TODO: implement general normalization to normalize incoming Netconf Message
117 // for Schema Context counterpart
121 static def CompositeNode toNotificationNode(NetconfMessage message,Optional<SchemaContext> ctx) {
123 val schemaContext = ctx.get
124 val notifications = schemaContext.notifications
125 val document = message.document
126 return XmlDocumentUtils.notificationToDomNodes(document, Optional.<Set<NotificationDefinition>>fromNullable(notifications))
131 static def NetconfMessage toRpcMessage(QName rpc, CompositeNode node,Optional<SchemaContext> ctx) {
132 val rpcPayload = wrap(NETCONF_RPC_QNAME, flattenInput(node))
133 val w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, XmlDocumentUtils.defaultValueCodecProvider)
134 w3cPayload.documentElement.setAttribute("message-id", "m-" + messageId.andIncrement)
135 return new NetconfMessage(w3cPayload);
138 def static flattenInput(CompositeNode node) {
139 val inputQName = QName.create(node.nodeType,"input");
140 val input = node.getFirstCompositeByName(inputQName);
141 if(input == null) return node;
142 if(input instanceof CompositeNode) {
144 val nodes = ImmutableList.builder() //
145 .addAll(input.children) //
146 .addAll(node.children.filter[nodeType != inputQName]) //
148 return ImmutableCompositeNode.create(node.nodeType,nodes);
153 static def RpcResult<CompositeNode> toRpcResult(NetconfMessage message,QName rpc,Optional<SchemaContext> context) {
154 var CompositeNode rawRpc;
155 if(context.present) {
156 if(isDataRetrievalReply(rpc)) {
158 val xmlData = message.document.dataSubtree
159 val dataNodes = XmlDocumentUtils.toDomNodes(xmlData, Optional.of(context.get.dataDefinitions))
161 val it = ImmutableCompositeNode.builder()
162 setQName(NETCONF_RPC_REPLY_QNAME)
163 add(ImmutableCompositeNode.create(NETCONF_DATA_QNAME, dataNodes));
165 rawRpc = it.toInstance;
168 val rpcSchema = context.get.operations.findFirst[QName == rpc]
169 rawRpc = message.document.toCompositeNode() as CompositeNode;
175 rawRpc = message.document.toCompositeNode() as CompositeNode;
178 return Rpcs.getRpcResult(true, rawRpc, Collections.emptySet());
181 def static Element getDataSubtree(Document doc) {
182 doc.getElementsByTagNameNS(NETCONF_URI.toString,"data").item(0) as Element
185 def static boolean isDataRetrievalReply(QName it) {
186 return NETCONF_URI == namespace && ( localName == NETCONF_GET_CONFIG_QNAME.localName || localName == NETCONF_GET_QNAME.localName)
189 static def wrap(QName name, Node<?> node) {
191 return new CompositeNodeTOImpl(name, null, Collections.singletonList(node));
193 return new CompositeNodeTOImpl(name, null, Collections.emptyList());
197 static def wrap(QName name, Node<?> additional, Node<?> node) {
199 return new CompositeNodeTOImpl(name, null, ImmutableList.of(additional, node));
201 return new CompositeNodeTOImpl(name, null, ImmutableList.of(additional));
205 static def filter(String type, Node<?> node) {
206 val it = ImmutableCompositeNode.builder(); //
207 setQName(NETCONF_FILTER_QNAME);
208 setAttribute(NETCONF_TYPE_QNAME,type);
210 return add(node).toInstance();
216 public static def Node<?> toCompositeNode(Document document) {
217 return XmlDocumentUtils.toDomNode(document) as Node<?>
220 public static def checkValidReply(NetconfMessage input, NetconfMessage output) {
221 val inputMsgId = input.document.documentElement.getAttribute("message-id")
222 val outputMsgId = output.document.documentElement.getAttribute("message-id")
223 Preconditions.checkState(inputMsgId == outputMsgId,"Rpc request and reply message IDs must be same.");