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