BUG-472 Initial EXI encoder/decoder implementation in Netconf
[controller.git] / opendaylight / netconf / netconf-client / src / main / java / org / opendaylight / controller / netconf / client / NetconfClientSessionNegotiatorFactory.java
index cff214401c0ff2ac8a24548adda3e44c8a4f186b..07e088e117d636502be739aabff6952eeac62fb9 100644 (file)
@@ -8,62 +8,79 @@
 
 package org.opendaylight.controller.netconf.client;
 
-import io.netty.channel.Channel;
-import io.netty.util.Timer;
-import io.netty.util.concurrent.Promise;
-
-import java.io.IOException;
-import java.io.InputStream;
-
+import org.opendaylight.controller.netconf.api.NetconfClientSessionPreferences;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.netconf.util.messages.NetconfStartExiMessage;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
 import org.opendaylight.protocol.framework.SessionNegotiator;
 import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
-import org.xml.sax.SAXException;
+import org.openexi.proc.common.AlignmentType;
+import org.openexi.proc.common.EXIOptions;
+import org.openexi.proc.common.EXIOptionsException;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+
+import io.netty.channel.Channel;
+import io.netty.util.Timer;
+import io.netty.util.concurrent.Promise;
 
 public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory<NetconfMessage, NetconfClientSession, NetconfClientSessionListener> {
 
+    public static final java.util.Set<String> CLIENT_CAPABILITIES = Sets.newHashSet(
+            XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0,
+            XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_1,
+            XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_CAPABILITY_EXI_1_0);
+
+    private static final String START_EXI_MESSAGE_ID = "default-start-exi";
+
     private final Optional<NetconfHelloMessageAdditionalHeader> additionalHeader;
     private final long connectionTimeoutMillis;
     private final Timer timer;
+    private final EXIOptions options;
+
+    public NetconfClientSessionNegotiatorFactory(Timer timer,
+                                                 Optional<NetconfHelloMessageAdditionalHeader> additionalHeader,
+                                                 long connectionTimeoutMillis) {
+        this(timer, additionalHeader, connectionTimeoutMillis, DEFAULT_OPTIONS);
+    }
 
-    public NetconfClientSessionNegotiatorFactory(Timer timer, Optional<NetconfHelloMessageAdditionalHeader> additionalHeader, long connectionTimeoutMillis) {
+    public NetconfClientSessionNegotiatorFactory(Timer timer,
+                                                 Optional<NetconfHelloMessageAdditionalHeader> additionalHeader,
+                                                 long connectionTimeoutMillis, EXIOptions exiOptions) {
         this.timer = Preconditions.checkNotNull(timer);
         this.additionalHeader = additionalHeader;
         this.connectionTimeoutMillis = connectionTimeoutMillis;
-    }
-
-    private static NetconfMessage loadHelloMessageTemplate() {
-        final String helloMessagePath = "/client_hello.xml";
-        try (InputStream is = NetconfClientSessionNegotiatorFactory.class.getResourceAsStream(helloMessagePath)) {
-            Preconditions.checkState(is != null, "Input stream from %s was null", helloMessagePath);
-            return new NetconfMessage(XmlUtil.readXmlToDocument(is));
-        } catch (SAXException | IOException e) {
-            throw new RuntimeException("Unable to load hello message", e);
-        }
+        this.options = exiOptions;
     }
 
     @Override
-    public SessionNegotiator<NetconfClientSession> getSessionNegotiator(SessionListenerFactory<NetconfClientSessionListener> sessionListenerFactory, Channel channel,
+    public SessionNegotiator<NetconfClientSession> getSessionNegotiator(SessionListenerFactory<NetconfClientSessionListener> sessionListenerFactory,
+                                                                        Channel channel,
             Promise<NetconfClientSession> promise) {
-        // Hello message needs to be recreated every time
-        NetconfMessage helloMessage = loadHelloMessageTemplate();
 
-        if(this.additionalHeader.isPresent()) {
-            helloMessage = new NetconfHelloMessage(helloMessage.getDocument(), additionalHeader.get());
-        } else {
-            helloMessage = new NetconfHelloMessage(helloMessage.getDocument());
-        }
+        NetconfMessage startExiMessage = NetconfStartExiMessage.create(options, START_EXI_MESSAGE_ID);
+        NetconfHelloMessage helloMessage = NetconfHelloMessage.createClientHello(CLIENT_CAPABILITIES, additionalHeader);
 
-        NetconfSessionPreferences proposal = new NetconfSessionPreferences(helloMessage);
+        NetconfClientSessionPreferences proposal = new NetconfClientSessionPreferences(helloMessage,startExiMessage);
         return new NetconfClientSessionNegotiator(proposal, promise, channel, timer,
-                sessionListenerFactory.getSessionListener(), connectionTimeoutMillis);
+                sessionListenerFactory.getSessionListener(),connectionTimeoutMillis);
+    }
+
+    private static final EXIOptions DEFAULT_OPTIONS = new EXIOptions();
+    static {
+        try {
+            DEFAULT_OPTIONS.setPreserveDTD(true);
+            DEFAULT_OPTIONS.setPreserveNS(true);
+            DEFAULT_OPTIONS.setPreserveLexicalValues(true);
+            DEFAULT_OPTIONS.setAlignmentType(AlignmentType.preCompress);
+        } catch (EXIOptionsException e) {
+            // Should not happen since DEFAULT_OPTIONS are still the same
+            throw new IllegalStateException("Unable to create EXI DEFAULT_OPTIONS");
+        }
     }
 }