Merge "Fixed publishDataChangeEvent in 2phase commit"
[controller.git] / opendaylight / md-sal / sal-netconf-connector / src / main / java / org / opendaylight / controller / sal / connect / netconf / NetconfMapping.xtend
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.sal.connect.netconf
9
10 import org.opendaylight.controller.netconf.api.NetconfMessage
11 import org.opendaylight.yangtools.yang.data.api.CompositeNode
12 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
13 import org.opendaylight.yangtools.yang.common.QName
14 import org.opendaylight.yangtools.yang.common.RpcResult
15 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
16 import java.net.URI
17 import java.util.Collections
18 import org.opendaylight.yangtools.yang.data.api.Node
19 import org.opendaylight.yangtools.yang.data.impl.NodeUtils
20 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
21 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
22 import java.util.ArrayList
23 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
24 import java.util.concurrent.atomic.AtomicInteger
25 import org.w3c.dom.Document
26 import org.w3c.dom.Element
27 import org.opendaylight.controller.sal.common.util.Rpcs
28 import java.util.List
29 import com.google.common.collect.ImmutableList
30 import org.opendaylight.yangtools.yang.data.api.SimpleNode
31 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode
32 import com.google.common.base.Preconditions
33 import com.google.common.base.Optional
34 import org.opendaylight.yangtools.yang.model.api.SchemaContext
35 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils
36 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
37 import java.util.Set
38
39 class NetconfMapping {
40
41     public static val NETCONF_URI = URI.create("urn:ietf:params:xml:ns:netconf:base:1.0")
42     public static val NETCONF_MONITORING_URI = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"
43     public static val NETCONF_NOTIFICATION_URI = URI.create("urn:ietf:params:xml:ns:netconf:notification:1.0")
44     
45     
46     public static val NETCONF_QNAME = QName.create(NETCONF_URI, null, "netconf");
47     public static val NETCONF_RPC_QNAME = QName.create(NETCONF_QNAME, "rpc");
48     public static val NETCONF_GET_QNAME = QName.create(NETCONF_QNAME, "get");
49     public static val NETCONF_FILTER_QNAME = QName.create(NETCONF_QNAME, "filter");
50     public static val NETCONF_TYPE_QNAME = QName.create(NETCONF_QNAME, "type");
51     public static val NETCONF_GET_CONFIG_QNAME = QName.create(NETCONF_QNAME, "get-config");
52     public static val NETCONF_EDIT_CONFIG_QNAME = QName.create(NETCONF_QNAME, "edit-config");
53     public static val NETCONF_DELETE_CONFIG_QNAME = QName.create(NETCONF_QNAME, "delete-config");
54     public static val NETCONF_ACTION_QNAME = QName.create(NETCONF_QNAME, "action");
55     public static val NETCONF_COMMIT_QNAME = QName.create(NETCONF_QNAME, "commit");
56     
57     public static val NETCONF_CONFIG_QNAME = QName.create(NETCONF_QNAME, "config");
58     public static val NETCONF_SOURCE_QNAME = QName.create(NETCONF_QNAME, "source");
59     public static val NETCONF_TARGET_QNAME = QName.create(NETCONF_QNAME, "target");
60     
61     public static val NETCONF_CANDIDATE_QNAME = QName.create(NETCONF_QNAME, "candidate");
62     public static val NETCONF_RUNNING_QNAME = QName.create(NETCONF_QNAME, "running");
63     
64     
65     public static val NETCONF_RPC_REPLY_QNAME = QName.create(NETCONF_QNAME, "rpc-reply");
66     public static val NETCONF_OK_QNAME = QName.create(NETCONF_QNAME, "ok");
67     public static val NETCONF_DATA_QNAME = QName.create(NETCONF_QNAME, "data");
68     public static val NETCONF_CREATE_SUBSCRIPTION_QNAME = QName.create(NETCONF_NOTIFICATION_URI,null,"create-subscription");
69     public static val NETCONF_CANCEL_SUBSCRIPTION_QNAME = QName.create(NETCONF_NOTIFICATION_URI,null,"cancel-subscription");
70     public static val IETF_NETCONF_MONITORING_MODULE = QName.create(NETCONF_MONITORING_URI, "2010-10-04","ietf-netconf-monitoring");
71
72     static List<Node<?>> RUNNING = Collections.<Node<?>>singletonList(
73         new SimpleNodeTOImpl(NETCONF_RUNNING_QNAME, null, null));
74     public static val CONFIG_SOURCE_RUNNING = new CompositeNodeTOImpl(NETCONF_SOURCE_QNAME, null, RUNNING);
75
76     static val messageId = new AtomicInteger(0);
77
78     static def Node<?> toFilterStructure(InstanceIdentifier identifier) {
79         var Node<?> previous = null;
80         if(identifier.path.empty) {
81             return null;
82         }
83         
84         for (component : identifier.path.reverseView) {
85             val Node<?> current = component.toNode(previous);
86             previous = current;
87         }
88         return filter("subtree",previous);
89     }
90
91     static def dispatch Node<?> toNode(NodeIdentifierWithPredicates argument, Node<?> node) {
92         val list = new ArrayList<Node<?>>();
93         for (arg : argument.keyValues.entrySet) {
94             list.add = new SimpleNodeTOImpl(arg.key, null, arg.value);
95         }
96         return new CompositeNodeTOImpl(argument.nodeType, null, list)
97     }
98
99     static def dispatch Node<?> toNode(PathArgument argument, Node<?> node) {
100         if (node != null) {
101             return new CompositeNodeTOImpl(argument.nodeType, null, Collections.singletonList(node));
102         } else {
103             return new SimpleNodeTOImpl(argument.nodeType, null, null);
104         }
105     }
106
107     static def CompositeNode toCompositeNode(NetconfMessage message,Optional<SchemaContext> ctx) {
108         //TODO: implement general normalization to normalize incoming Netconf Message 
109         // for Schema Context counterpart
110         return null
111     }
112     
113     static def CompositeNode toNotificationNode(NetconfMessage message,Optional<SchemaContext> ctx) {
114         if (ctx.present) {
115             val schemaContext = ctx.get
116             val notifications = schemaContext.notifications
117             val document = message.document
118             return XmlDocumentUtils.notificationToDomNodes(document, Optional.<Set<NotificationDefinition>>fromNullable(notifications))
119         }
120         return null
121     }
122
123     static def NetconfMessage toRpcMessage(QName rpc, CompositeNode node,Optional<SchemaContext> ctx) {
124         val rpcPayload = wrap(NETCONF_RPC_QNAME, flattenInput(node));
125         val w3cPayload = NodeUtils.buildShadowDomTree(rpcPayload);
126         w3cPayload.documentElement.setAttribute("message-id", "m-" + messageId.andIncrement);
127         return new NetconfMessage(w3cPayload);
128     }
129     
130     def static flattenInput(CompositeNode node) {
131         val inputQName = QName.create(node.nodeType,"input");
132         val input = node.getFirstCompositeByName(inputQName);
133         if(input == null) return node;
134         if(input instanceof CompositeNode) {
135             
136             val nodes = ImmutableList.builder() //
137                 .addAll(input.children) //
138                 .addAll(node.children.filter[nodeType != inputQName]) //
139                 .build()
140             return ImmutableCompositeNode.create(node.nodeType,nodes);
141         } 
142         
143     }
144
145     static def RpcResult<CompositeNode> toRpcResult(NetconfMessage message,QName rpc,Optional<SchemaContext> context) {
146         var CompositeNode rawRpc;
147         if(context.present) {
148             if(isDataRetrievalReply(rpc)) {
149                 
150                 val xmlData = message.document.dataSubtree
151                 val dataNodes = XmlDocumentUtils.toDomNodes(xmlData, Optional.of(context.get.dataDefinitions))
152                 
153                 val it = ImmutableCompositeNode.builder()
154                 setQName(NETCONF_RPC_REPLY_QNAME)
155                 add(ImmutableCompositeNode.create(NETCONF_DATA_QNAME, dataNodes));
156                 
157                 rawRpc = it.toInstance;
158                 //sys(xmlData)
159             } else {
160                 val rpcSchema = context.get.operations.findFirst[QName == rpc]
161                 rawRpc = message.document.toCompositeNode() as CompositeNode;
162             }
163             
164             
165             
166         } else {
167             rawRpc = message.document.toCompositeNode() as CompositeNode;
168         }
169         //rawRpc.
170         return Rpcs.getRpcResult(true, rawRpc, Collections.emptySet());
171     }
172     
173     def static Element getDataSubtree(Document doc) {
174         doc.getElementsByTagNameNS(NETCONF_URI.toString,"data").item(0) as Element
175     }
176     
177     def static boolean isDataRetrievalReply(QName it) {
178         return NETCONF_URI == namespace && ( localName == NETCONF_GET_CONFIG_QNAME.localName || localName == NETCONF_GET_QNAME.localName) 
179     }
180
181     static def wrap(QName name, Node<?> node) {
182         if (node != null) {
183             return new CompositeNodeTOImpl(name, null, Collections.singletonList(node));
184         } else {
185             return new CompositeNodeTOImpl(name, null, Collections.emptyList());
186         }
187     }
188
189     static def wrap(QName name, Node<?> additional, Node<?> node) {
190         if (node != null) {
191             return new CompositeNodeTOImpl(name, null, ImmutableList.of(additional, node));
192         } else {
193             return new CompositeNodeTOImpl(name, null, ImmutableList.of(additional));
194         }
195     }
196
197     static def filter(String type, Node<?> node) {
198         val it = ImmutableCompositeNode.builder(); //
199         setQName(NETCONF_FILTER_QNAME);
200         setAttribute(NETCONF_TYPE_QNAME,type);
201         if (node != null) {
202             return add(node).toInstance();
203         } else {
204             return toInstance();
205         }
206     }
207
208     public static def Node<?> toCompositeNode(Document document) {
209         return XmlDocumentUtils.toDomNode(document) as Node<?>
210     }
211     
212     public static def checkValidReply(NetconfMessage input, NetconfMessage output) {
213         val inputMsgId = input.document.documentElement.getAttribute("message-id")
214         val outputMsgId = output.document.documentElement.getAttribute("message-id")
215         Preconditions.checkState(inputMsgId == outputMsgId,"Rpc request and reply message IDs must be same.");
216         
217     }
218     
219 }