Merge "sal-restconf-broker initial implementation needs https://git.opendaylight...
[controller.git] / opendaylight / netconf / netconf-impl / src / main / java / org / opendaylight / controller / netconf / impl / NetconfServerSessionNegotiatorFactory.java
1 /*
2  * Copyright (c) 2013 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
9 package org.opendaylight.controller.netconf.impl;
10
11 import io.netty.channel.Channel;
12 import io.netty.util.Timer;
13 import io.netty.util.concurrent.Promise;
14
15 import java.io.InputStream;
16
17 import javax.xml.xpath.XPathConstants;
18 import javax.xml.xpath.XPathExpression;
19
20 import org.opendaylight.controller.netconf.api.NetconfMessage;
21 import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
22 import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
23 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
24 import org.opendaylight.controller.netconf.util.NetconfUtil;
25 import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
26 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
27 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
28 import org.opendaylight.protocol.framework.SessionListenerFactory;
29 import org.opendaylight.protocol.framework.SessionNegotiator;
30 import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
31 import org.w3c.dom.Document;
32 import org.w3c.dom.Element;
33 import org.w3c.dom.Node;
34
35 import com.google.common.base.Preconditions;
36
37 public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory<NetconfMessage, NetconfServerSession, NetconfServerSessionListener> {
38
39     public static final String SERVER_HELLO_XML_LOCATION = "/server_hello.xml";
40
41     private final Timer timer;
42
43     private static final Document helloMessageTemplate = loadHelloMessageTemplate();
44     private final SessionIdProvider idProvider;
45     private final NetconfOperationServiceFactoryListener factoriesListener;
46     private final long connectionTimeoutMillis;
47
48     public NetconfServerSessionNegotiatorFactory(Timer timer, NetconfOperationServiceFactoryListener factoriesListener,
49             SessionIdProvider idProvider, long connectionTimeoutMillis) {
50         this.timer = timer;
51         this.factoriesListener = factoriesListener;
52         this.idProvider = idProvider;
53         this.connectionTimeoutMillis = connectionTimeoutMillis;
54     }
55
56     private static Document loadHelloMessageTemplate() {
57         InputStream resourceAsStream = NetconfServerSessionNegotiatorFactory.class
58                 .getResourceAsStream(SERVER_HELLO_XML_LOCATION);
59         Preconditions.checkNotNull(resourceAsStream, "Unable to load server hello message blueprint from %s",
60                 SERVER_HELLO_XML_LOCATION);
61         return NetconfUtil.createMessage(resourceAsStream).getDocument();
62     }
63
64     @Override
65     public SessionNegotiator<NetconfServerSession> getSessionNegotiator(SessionListenerFactory<NetconfServerSessionListener> sessionListenerFactory, Channel channel,
66             Promise<NetconfServerSession> promise) {
67         long sessionId = idProvider.getNextSessionId();
68
69         NetconfServerSessionPreferences proposal = new NetconfServerSessionPreferences(createHelloMessage(sessionId),
70                 sessionId);
71         return new NetconfServerSessionNegotiator(proposal, promise, channel, timer,
72                 sessionListenerFactory.getSessionListener(), connectionTimeoutMillis);
73     }
74
75     private static final XPathExpression sessionIdXPath = XMLNetconfUtil
76             .compileXPath("/netconf:hello/netconf:session-id");
77     private static final XPathExpression capabilitiesXPath = XMLNetconfUtil
78             .compileXPath("/netconf:hello/netconf:capabilities");
79
80     private NetconfMessage createHelloMessage(long sessionId) {
81         Document helloMessageTemplate = getHelloTemplateClone();
82
83         // change session ID
84         final Node sessionIdNode = (Node) XmlUtil.evaluateXPath(sessionIdXPath, helloMessageTemplate,
85                 XPathConstants.NODE);
86         sessionIdNode.setTextContent(String.valueOf(sessionId));
87
88         // add capabilities from yang store
89         final Element capabilitiesElement = (Element) XmlUtil.evaluateXPath(capabilitiesXPath, helloMessageTemplate,
90                 XPathConstants.NODE);
91
92         CapabilityProvider capabilityProvider = new CapabilityProviderImpl(factoriesListener.getSnapshot(sessionId));
93
94         for (String capability : capabilityProvider.getCapabilities()) {
95             final Element capabilityElement = helloMessageTemplate.createElement(XmlNetconfConstants.CAPABILITY);
96             capabilityElement.setTextContent(capability);
97             capabilitiesElement.appendChild(capabilityElement);
98         }
99         return new NetconfMessage(helloMessageTemplate);
100     }
101
102     private synchronized Document getHelloTemplateClone() {
103         return (Document) helloMessageTemplate.cloneNode(true);
104     }
105 }