package org.opendaylight.netconf.client;
import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Interner;
+import com.google.common.collect.Interners;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.Timer;
import io.netty.util.concurrent.Promise;
-import java.util.Collection;
+import java.util.Set;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.netconf.api.NetconfClientSessionPreferences;
+import org.opendaylight.netconf.api.NetconfDocumentedException;
+import org.opendaylight.netconf.api.NetconfMessage;
+import org.opendaylight.netconf.api.messages.NetconfHelloMessage;
+import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.netconf.nettyutil.AbstractChannelInitializer;
import org.opendaylight.netconf.nettyutil.AbstractNetconfSessionNegotiator;
import org.opendaylight.netconf.nettyutil.handler.exi.NetconfStartExiMessage;
-import org.opendaylight.netconf.api.messages.NetconfHelloMessage;
import org.opendaylight.netconf.util.messages.NetconfMessageUtil;
import org.opendaylight.netconf.util.xml.XMLNetconfUtil;
-import org.opendaylight.netconf.api.NetconfClientSessionPreferences;
-import org.opendaylight.netconf.api.NetconfDocumentedException;
-import org.opendaylight.netconf.api.NetconfMessage;
-import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
private static final String EXI_1_0_CAPABILITY_MARKER = "exi:1.0";
+ private static final Interner<Set<String>> INTERNER = Interners.newWeakInterner();
+
protected NetconfClientSessionNegotiator(final NetconfClientSessionPreferences sessionPreferences,
final Promise<NetconfClientSession> promise,
final Channel channel,
@Override
protected NetconfClientSession getSession(final NetconfClientSessionListener sessionListener, final Channel channel,
- final NetconfHelloMessage message) throws NetconfDocumentedException {
- long sessionId = extractSessionId(message.getDocument());
+ final NetconfHelloMessage message) throws NetconfDocumentedException {
+ final long sessionId = extractSessionId(message.getDocument());
// Copy here is important: it disconnects the strings from the document
- Collection<String> capabilities = ImmutableList.copyOf(NetconfMessageUtil.extractCapabilitiesFromHello(message.getDocument()));
+ Set<String> capabilities = ImmutableSet.copyOf(NetconfMessageUtil.extractCapabilitiesFromHello(message.getDocument()));
+
+ capabilities = INTERNER.intern(capabilities);
- // FIXME: scalability: we could instantiate a cache to share the same collections
return new NetconfClientSession(sessionListener, channel, sessionId, capabilities);
}
package org.opendaylight.netconf.client;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertNotEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.verify;
import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.util.Timer;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.Promise;
+import java.io.InputStream;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.mockito.internal.util.collections.Sets;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.netconf.api.NetconfClientSessionPreferences;
import org.opendaylight.netconf.api.NetconfMessage;
+import org.opendaylight.netconf.api.messages.NetconfHelloMessage;
+import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
import org.opendaylight.netconf.nettyutil.handler.ChunkedFramingMechanismEncoder;
import org.opendaylight.netconf.nettyutil.handler.NetconfXMLToHelloMessageDecoder;
import org.opendaylight.netconf.nettyutil.handler.NetconfXMLToMessageDecoder;
import org.opendaylight.netconf.nettyutil.handler.exi.NetconfStartExiMessage;
-import org.opendaylight.netconf.api.messages.NetconfHelloMessage;
-import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.netconf.util.messages.NetconfMessageUtil;
import org.opendaylight.netconf.util.test.XmlFileLoader;
import org.openexi.proc.common.EXIOptions;
import org.w3c.dom.Document;
return new NetconfClientSessionNegotiator(preferences, promise, channel, timer, sessionListener, timeout);
}
+ private NetconfHelloMessage createHelloMsg(final String name) throws Exception {
+ final InputStream stream = NetconfClientSessionNegotiatorTest.class.getResourceAsStream(name);
+ final Document doc = XmlUtil.readXmlToDocument(stream);
+
+ return new NetconfHelloMessage(doc);
+ }
+
+ private Set<String> createCapabilities(String name) throws Exception {
+ NetconfHelloMessage hello = createHelloMsg(name);
+
+ return ImmutableSet.copyOf(NetconfMessageUtil.extractCapabilitiesFromHello(hello.getDocument()));
+ }
+
@Test
public void testNetconfClientSessionNegotiator() throws Exception {
Promise promise = mock(Promise.class);
// two calls for exiMessage, 2 for hello message
verify(pipeline, times(4)).replace(anyString(), anyString(), any(ChannelHandler.class));
}
+
+ @Test
+ public void testNetconfClientSessionNegotiatorGetCached() throws Exception {
+ Promise promise = mock(Promise.class);
+ doReturn(promise).when(promise).setSuccess(anyObject());
+ NetconfClientSessionListener sessionListener = mock(NetconfClientSessionListener.class);
+ NetconfClientSessionNegotiator negotiator = createNetconfClientSessionNegotiator(promise, null);
+
+ Set<String> set = createCapabilities("/helloMessage3.xml");
+
+ final Set<String> cachedS1 = (Set<String>) negotiator.getSession(sessionListener,channel,createHelloMsg("/helloMessage1.xml")).getServerCapabilities();
+
+ //helloMessage2 and helloMessage3 are the same with different order
+ final Set<String> cachedS2 = (Set<String>) negotiator.getSession(sessionListener,channel,createHelloMsg("/helloMessage2.xml")).getServerCapabilities();
+ final Set<String> cachedS3 = (Set<String>) negotiator.getSession(sessionListener,channel,createHelloMsg("/helloMessage3.xml")).getServerCapabilities();
+
+ assertEquals(cachedS3, set);
+ assertNotEquals(cachedS1, set);
+ assertEquals(cachedS2, set);
+ assertEquals(cachedS3, cachedS2);
+ assertNotEquals(cachedS3, cachedS1);
+ assertNotEquals(cachedS2, cachedS1);
+ assertTrue(cachedS2 == cachedS3);
+ }
}
--- /dev/null
+<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <capabilities>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24</capability>
+ <capability>urn:ietf:params:xml:ns:yang:iana-if-type?module=iana-if-type&revision=2014-05-08</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-interfaces?module=ietf-interfaces&revision=2014-05-08</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:flexible?module=threadpool-impl-flexible&revision=2013-12-01</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher?module=odl-netconfig-client-cfg&revision=2014-04-08</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:notification?module=netconf-northbound-notification&revision=2015-08-06</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl?module=netconf-northbound-impl&revision=2015-01-12</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:notification:impl?module=netconf-northbound-notification-impl&revision=2015-08-07</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:concurrent-data-broker?module=odl-concurrent-data-broker-cfg&revision=2014-11-24</capability>
+ <capability>urn:TBD:params:xml:ns:yang:nt:l3-unicast-igp-topology?module=l3-unicast-igp-topology&revision=2013-10-21</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:topology:shared:schema:repository?module=shared-schema-repository&revision=2015-07-27</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:cluster:admin?module=cluster-admin&revision=2015-10-13</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:general-entity?module=general-entity&revision=2015-08-20</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09</capability>
+ <capability>urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-network-topology?module=ietf-network-topology&revision=2015-06-08</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-notifications?module=ietf-netconf-notifications&revision=2012-02-06</capability>
+ <capability>urn:TBD:params:xml:ns:yang:ospf-topology?module=ospf-topology&revision=2013-10-21</capability>
+ <capability>config:aaa:authn:netconf:plugin?module=aaa-authn-netconf-plugin&revision=2015-07-15</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:netconf:auth?module=netconf-auth&revision=2015-07-15</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:operational-dom-store?module=opendaylight-operational-dom-datastore&revision=2014-06-17</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ospf-topology?module=ospf-topology&revision=2013-07-12</capability>
+ <capability>urn:ietf:params:netconf:capability:exi:1.0</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper?module=netconf-northbound-mapper&revision=2015-01-14</capability>
+ <capability>urn:ietf:params:xml:ns:netconf:base:1.0?module=ietf-netconf&revision=2011-06-01</capability>
+ <capability>urn:TBD:params:xml:ns:yang:network-topology?module=network-topology&revision=2013-10-21</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:shutdown:impl?module=shutdown-impl&revision=2013-12-18</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:topology?module=netconf-topology&revision=2015-07-27</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl?module=threadpool-impl&revision=2013-04-05</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2013-07-15</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh?module=netconf-northbound-ssh&revision=2015-01-14</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:shutdown?module=shutdown&revision=2013-12-18</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:aaa:credential-store?module=credential-store&revision=2015-02-26</capability>
+ <capability>urn:TBD:params:xml:ns:yang:network-topology?module=network-topology&revision=2013-07-12</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:pingpong?module=opendaylight-pingpong-broker&revision=2014-11-07</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup?module=threadgroup&revision=2013-11-07</capability>
+ <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-restconf?module=ietf-restconf&revision=2013-10-19</capability>
+ <capability>urn:opendaylight:netconf-node-inventory?module=netconf-node-inventory&revision=2014-01-08</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service?module=opendaylight-entity-ownership-service&revision=2015-08-10</capability>
+ <capability>urn:TBD:params:xml:ns:yang:nt:l3-unicast-igp-topology?module=l3-unicast-igp-topology&revision=2013-07-12</capability>
+ <capability>urn:TBD:params:xml:ns:yang:network:ted?module=ted&revision=2013-07-12</capability>
+ <capability>urn:TBD:params:xml:ns:yang:network:isis-topology?module=isis-topology&revision=2013-10-21</capability>
+ <capability>config:aaa:authn:idmlight?module=aaa-idmlight&revision=2015-12-04</capability>
+ <capability>urn:TBD:params:xml:ns:yang:network:isis-topology?module=isis-topology&revision=2013-07-12</capability>
+ <capability>config:aaa:authn:h2:store?module=aaa-h2-store&revision=2015-11-28</capability>
+ <capability>urn:TBD:params:xml:ns:yang:network:ted?module=ted&revision=2013-10-21</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:tcp?module=netconf-northbound-tcp&revision=2015-04-23</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology?module=clustered-netconf-topology&revision=2015-11-04</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:clustering:entity-owners?module=entity-owners&revision=2015-08-04</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:fixed?module=threadpool-impl-fixed&revision=2013-12-01</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:actor-system-provider:service?module=actor-system-provider-service&revision=2015-10-05</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf?module=odl-sal-netconf-connector-cfg&revision=2015-08-03</capability>
+ <capability>urn:opendaylight:netconf-node-topology?module=netconf-node-topology&revision=2015-01-14</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:distributed-entity-ownership-service?module=distributed-entity-ownership-service&revision=2015-08-10</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:inmemory-datastore-provider?module=opendaylight-inmemory-datastore-provider&revision=2014-06-17</capability>
+ <capability>urn:opendaylight:inventory?module=opendaylight-inventory&revision=2013-08-19</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:timer?module=netty-timer&revision=2013-11-19</capability>
+ <capability>urn:ietf:params:xml:ns:netconf:notification:1.0?module=notifications&revision=2008-07-14</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:cluster-admin-provider?module=cluster-admin-provider&revision=2015-10-13</capability>
+ <capability>urn:ietf:params:xml:ns:netmod:notification?module=nc-notifications&revision=2008-07-14</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring-extension?module=ietf-netconf-monitoring-extension&revision=2013-12-10</capability>
+ <capability>urn:ietf:params:netconf:base:1.1</capability>
+ <capability>urn:ietf:params:netconf:base:1.0</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:distributed-datastore-provider?module=distributed-datastore-provider&revision=2014-06-12</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:remote-rpc-connector?module=remote-rpc-connector&revision=2014-07-07</capability>
+ <capability>urn:ietf:params:netconf:capability:notification:1.0</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:config-dom-store?module=opendaylight-config-dom-datastore&revision=2014-06-17</capability>
+ <capability>urn:ietf:params:xml:ns:yang:iana-afn-safi?module=iana-afn-safi&revision=2013-07-04</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:netconf?module=odl-netconf-cfg&revision=2014-04-08</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound?module=netconf-northbound&revision=2015-01-14</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:scheduled?module=threadpool-impl-scheduled&revision=2013-12-01</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:actor-system-provider:impl?module=actor-system-provider-impl&revision=2015-10-05</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netty?module=netty&revision=2013-11-19</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:threadpool?module=threadpool&revision=2013-04-09</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-network?module=ietf-network&revision=2015-06-08</capability>
+ <capability>urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:protocol:framework?module=protocol-framework&revision=2014-03-13</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2013-07-15</capability>
+ </capabilities>
+ <session-id>1</session-id>
+</hello>
+
--- /dev/null
+<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <capabilities>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring-extension?module=ietf-netconf-monitoring-extension&revision=2013-12-10</capability>
+ <capability>urn:ietf:params:netconf:capability:exi:1.0</capability>
+ <capability>http://example.com/system?module=empolyees&revision=2007-06-09</capability>
+ <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24</capability>
+ <capability>urn:ietf:params:netconf:base:1.1</capability>
+ <capability>urn:ietf:params:netconf:base:1.0</capability>
+ </capabilities>
+ <session-id>1</session-id>
+</hello>
--- /dev/null
+<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <capabilities>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring-extension?module=ietf-netconf-monitoring-extension&revision=2013-12-10</capability>
+ <capability>urn:ietf:params:netconf:capability:exi:1.0</capability>
+ <capability>http://example.com/system?module=empolyees&revision=2007-06-09</capability>
+ <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
+ <capability>urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24</capability>
+ <capability>urn:ietf:params:netconf:base:1.0</capability>
+ <capability>urn:ietf:params:netconf:base:1.1</capability>
+ </capabilities>
+ <session-id>1</session-id>
+</hello>