Factor out SchemaResourceManager 71/89371/11
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 25 Apr 2020 09:46:44 +0000 (11:46 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 27 Apr 2020 18:26:10 +0000 (20:26 +0200)
Management of schema cache on the filesystem is copy&pasted in two
places, which creates a compatibility problem. Furthermore current
code relies on static wiring, which is going to be non-workable
very soon.

Refactor AbstractTopology to split out schema management into a
separate component within sal-netconf-connector, which is injected
into both AbstractTopology subclasses and clustered topology.

JIRA: NETCONF-672
Change-Id: If1284a08f9525a3396f2d39e2a4399366edee7ae
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
22 files changed:
netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/BaseCallHomeTopology.java
netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcher.java
netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeTopology.java
netconf/callhome-provider/src/main/resources/OSGI-INF/blueprint/callhome-topology.xml
netconf/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcherTest.java
netconf/netconf-topology-impl/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java
netconf/netconf-topology-impl/src/main/resources/OSGI-INF/blueprint/netconf-topology.xml
netconf/netconf-topology-impl/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtils.java
netconf/netconf-topology-singleton/src/main/resources/OSGI-INF/blueprint/netconf-topology-singleton.xml
netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/MountPointEndToEndTest.java
netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfNodeActorTest.java
netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java
netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImplTest.java
netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/api/SchemaRepositoryProvider.java [deleted file]
netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/AbstractNetconfTopology.java
netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/SharedSchemaRepositoryProvider.java [deleted file]
netconf/sal-netconf-connector/pom.xml
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/api/SchemaResourceManager.java [new file with mode: 0644]
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/impl/DefaultSchemaResourceManager.java [new file with mode: 0644]
netconf/sal-netconf-connector/src/main/resources/OSGI-INF/blueprint/sal-netconf-connector.xml

index 1405267c2dabe6a08e54ed5441c74e919f4a9b5d..844e474586d617cddc7462d12322a820d16a93e0 100644 (file)
@@ -15,7 +15,7 @@ import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
-import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
+import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
 
 abstract class BaseCallHomeTopology extends AbstractNetconfTopology {
@@ -23,7 +23,7 @@ abstract class BaseCallHomeTopology extends AbstractNetconfTopology {
                          final EventExecutor eventExecutor,
                          final ScheduledThreadPool keepaliveExecutor,
                          final ThreadPool processingExecutor,
-                         final SchemaRepositoryProvider schemaRepositoryProvider,
+                         final SchemaResourceManager schemaRepositoryProvider,
                          final DataBroker dataBroker,
                          final DOMMountPointService mountPointService,
                          final AAAEncryptionService encryptionService,
index b73cddfda47cca9000e0f427c2f59108b517b166..de843caab21ff7826fb247e8cfb5725b28b9ca7a 100644 (file)
@@ -25,7 +25,7 @@ import org.opendaylight.netconf.client.NetconfClientSession;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
-import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
+import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.slf4j.Logger;
@@ -39,7 +39,7 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom
     private final EventExecutor eventExecutor;
     private final ScheduledThreadPool keepaliveExecutor;
     private final ThreadPool processingExecutor;
-    private final SchemaRepositoryProvider schemaRepositoryProvider;
+    private final SchemaResourceManager schemaRepositoryProvider;
     private final CallHomeMountSessionManager sessionManager;
     private final DataBroker dataBroker;
     private final DOMMountPointService mountService;
@@ -56,7 +56,7 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom
 
     public CallHomeMountDispatcher(final String topologyId, final EventExecutor eventExecutor,
                                    final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor,
-                                   final SchemaRepositoryProvider schemaRepositoryProvider, final DataBroker dataBroker,
+                                   final SchemaResourceManager schemaRepositoryProvider, final DataBroker dataBroker,
                                    final DOMMountPointService mountService,
                                    final AAAEncryptionService encryptionService) {
         this(topologyId, eventExecutor, keepaliveExecutor, processingExecutor, schemaRepositoryProvider, dataBroker,
@@ -65,7 +65,7 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom
 
     public CallHomeMountDispatcher(final String topologyId, final EventExecutor eventExecutor,
             final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor,
-            final SchemaRepositoryProvider schemaRepositoryProvider, final DataBroker dataBroker,
+            final SchemaResourceManager schemaRepositoryProvider, final DataBroker dataBroker,
             final DOMMountPointService mountService,
             final AAAEncryptionService encryptionService, final DeviceActionFactory deviceActionFactory) {
         this.topologyId = topologyId;
index e032637cd83b2886584013e841edbfea29945d3a..f6f185dc05ab3d2d2392ac41797963c26dd749ad 100644 (file)
@@ -16,17 +16,17 @@ import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalFacade;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
 
 public class CallHomeTopology extends BaseCallHomeTopology {
 
     public CallHomeTopology(final String topologyId, final NetconfClientDispatcher clientDispatcher,
             final EventExecutor eventExecutor,
             final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor,
-            final SchemaRepositoryProvider schemaRepositoryProvider,
+            final SchemaResourceManager schemaRepositoryProvider,
             final DataBroker dataBroker, final DOMMountPointService mountPointService,
             final AAAEncryptionService encryptionService) {
         this(topologyId, clientDispatcher, eventExecutor,
@@ -37,7 +37,7 @@ public class CallHomeTopology extends BaseCallHomeTopology {
     public CallHomeTopology(final String topologyId, final NetconfClientDispatcher clientDispatcher,
                             final EventExecutor eventExecutor,
                             final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor,
-                            final SchemaRepositoryProvider schemaRepositoryProvider,
+                            final SchemaResourceManager schemaRepositoryProvider,
                             final DataBroker dataBroker, final DOMMountPointService mountPointService,
                             final AAAEncryptionService encryptionService,
                             final DeviceActionFactory deviceActionFactory) {
index d4cd6195a30b43a7f98ab14c084e4752465f1915..c3a6c2dfd191dd347c8636a4aa7b28a6d63547d8 100644 (file)
                interface="org.opendaylight.aaa.encrypt.AAAEncryptionService" />
     <reference id="deviceActionFactory"
                interface="org.opendaylight.netconf.sal.connect.api.DeviceActionFactory"/>
-
-    <bean id="schemaRepository" class="org.opendaylight.netconf.topology.spi.SharedSchemaRepositoryProvider">
-        <argument value="callhome-topology-schemas"/>
-    </bean>
+    <reference id="schemaManager"
+               interface="org.opendaylight.netconf.sal.connect.api.SchemaResourceManager"/>
 
     <bean id="callhomeProvider" class="org.opendaylight.netconf.callhome.mount.IetfZeroTouchCallHomeServerProvider"
           init-method="init"
@@ -45,7 +43,7 @@
         <argument ref="eventExecutor"/>
         <argument ref="keepAliveExecutor"/>
         <argument ref="processingExecutor"/>
-        <argument ref="schemaRepository"/>
+        <argument ref="schemaManager"/>
         <argument ref="dataBroker"/>
         <argument ref="domMountPointService"/>
         <argument ref="encryptionService"/>
index ecac3cc607db4b666054d4396539ab4d65ff636c..d2037dcf33bb3933350973c919867b6403ceeeba 100644 (file)
@@ -35,7 +35,7 @@ import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
 import org.opendaylight.netconf.nettyutil.ReconnectStrategy;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
-import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
+import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 
@@ -44,7 +44,7 @@ public class CallHomeMountDispatcherTest {
     private EventExecutor mockExecutor;
     private ScheduledThreadPool mockKeepAlive;
     private ThreadPool mockProcessingExecutor;
-    private SchemaRepositoryProvider mockSchemaRepoProvider;
+    private SchemaResourceManager mockSchemaRepoProvider;
 
     private CallHomeMountDispatcher instance;
     private DataBroker mockDataBroker;
@@ -61,7 +61,7 @@ public class CallHomeMountDispatcherTest {
         mockExecutor = mock(EventExecutor.class);
         mockKeepAlive = mock(ScheduledThreadPool.class);
         mockProcessingExecutor = mock(ThreadPool.class);
-        mockSchemaRepoProvider = mock(SchemaRepositoryProvider.class);
+        mockSchemaRepoProvider = mock(SchemaResourceManager.class);
         mockDataBroker = mock(DataBroker.class);
         mockMount = mock(DOMMountPointService.class);
         mockSessMgr = mock(CallHomeMountSessionManager.class);
index dc17c5105de0939e1eb3c0b971343a16984c765f..1a3a443b2317f1a9575b26dfc00f160359f1c33b 100644 (file)
@@ -27,10 +27,10 @@ import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalFacade;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
@@ -58,7 +58,7 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology
     public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
             final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
             final ThreadPool processingExecutor,
-            final SchemaRepositoryProvider schemaRepositoryProvider,
+            final SchemaResourceManager schemaRepositoryProvider,
             final DataBroker dataBroker, final DOMMountPointService mountPointService,
             final AAAEncryptionService encryptionService) {
         this(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
@@ -68,7 +68,7 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology
     public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
             final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
             final ThreadPool processingExecutor,
-            final SchemaRepositoryProvider schemaRepositoryProvider,
+            final SchemaResourceManager schemaRepositoryProvider,
             final DataBroker dataBroker, final DOMMountPointService mountPointService,
             final AAAEncryptionService encryptionService,
             final DeviceActionFactory deviceActionFactory) {
index e95c26948a8b40d39d0e81d398ae9e0ceae812fe..06b7c198994f65b5bda15810fd74b7d77132b9c2 100644 (file)
                interface="org.opendaylight.aaa.encrypt.AAAEncryptionService" />
     <reference id="deviceActionFactory"
                interface="org.opendaylight.netconf.sal.connect.api.DeviceActionFactory"/>
-
-    <bean id="schemaRepository" class="org.opendaylight.netconf.topology.spi.SharedSchemaRepositoryProvider">
-        <argument value="netconf-topology-schemas"/>
-    </bean>
+    <reference id="schemaManager"
+               interface="org.opendaylight.netconf.sal.connect.api.SchemaResourceManager"/>
 
     <cm:property-placeholder persistent-id="org.opendaylight.netconf.topology.sb.keypair" update-strategy="none">
       <cm:default-properties>
@@ -54,7 +52,7 @@
         <argument ref="eventExecutor"/>
         <argument ref="keepAliveExecutor"/>
         <argument ref="processingExecutor"/>
-        <argument ref="schemaRepository"/>
+        <argument ref="schemaManager"/>
         <argument ref="dataBroker"/>
         <argument ref="mountPointService"/>
         <property name="privateKeyPath" value="${private-key-path}"/>
index 372dc443eae5b1542720fae3d48d6f9ed83819e5..96a6696152e300979b6e325342bebce676d2dc0f 100644 (file)
@@ -21,16 +21,14 @@ import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
 import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.ImmediateEventExecutor;
-import io.netty.util.concurrent.SucceededFuture;
 import java.util.Collection;
 import java.util.HashSet;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
 import org.opendaylight.controller.config.threadpool.ThreadPool;
@@ -44,8 +42,8 @@ import org.opendaylight.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
+import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
-import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
@@ -68,10 +66,12 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.common.Uint16;
 import org.opendaylight.yangtools.yang.common.Uint32;
-import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
 
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
 public class NetconfTopologyImplTest {
 
     private static final NodeId NODE_ID = new NodeId("testing-node");
@@ -90,7 +90,7 @@ public class NetconfTopologyImplTest {
     private ThreadPool mockedProcessingExecutor;
 
     @Mock
-    private SchemaRepositoryProvider mockedSchemaRepositoryProvider;
+    private SchemaResourceManager mockedResourceManager;
 
     @Mock
     private DataBroker dataBroker;
@@ -106,18 +106,11 @@ public class NetconfTopologyImplTest {
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
-        when(mockedSchemaRepositoryProvider.getSharedSchemaRepository())
-                .thenReturn(new SharedSchemaRepository("testingSharedSchemaRepo"));
         when(mockedProcessingExecutor.getExecutor()).thenReturn(MoreExecutors.newDirectExecutorService());
-        final Future future = new SucceededFuture(ImmediateEventExecutor.INSTANCE, new NetconfDeviceCapabilities());
-        when(mockedClientDispatcher.createReconnectingClient(any(NetconfReconnectingClientConfiguration.class)))
-                .thenReturn(future);
 
-        topology = new TestingNetconfTopologyImpl(TOPOLOGY_ID, mockedClientDispatcher,
-                mockedEventExecutor, mockedKeepaliveExecutor, mockedProcessingExecutor, mockedSchemaRepositoryProvider,
-                dataBroker, mountPointService, encryptionService);
+        topology = new TestingNetconfTopologyImpl(TOPOLOGY_ID, mockedClientDispatcher, mockedEventExecutor,
+            mockedKeepaliveExecutor, mockedProcessingExecutor, mockedResourceManager, dataBroker, mountPointService,
+            encryptionService);
 
         spyTopology = spy(topology);
     }
@@ -150,14 +143,7 @@ public class NetconfTopologyImplTest {
         final DataObjectModification<Node> newNode = mock(DataObjectModification.class);
         when(newNode.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
 
-        InstanceIdentifier.PathArgument pa = null;
-
-        for (final InstanceIdentifier.PathArgument p
-                : NetconfTopologyImpl.createTopologyListPath(TOPOLOGY_ID)
-                    .child(Node.class, new NodeKey(NODE_ID)).getPathArguments()) {
-            pa = p;
-        }
-
+        PathArgument pa = IdentifiableItem.of(Node.class, new NodeKey(NODE_ID));
         when(newNode.getIdentifier()).thenReturn(pa);
 
 
@@ -283,7 +269,7 @@ public class NetconfTopologyImplTest {
                                           final EventExecutor eventExecutor,
                                           final ScheduledThreadPool keepaliveExecutor,
                                           final ThreadPool processingExecutor,
-                                          final SchemaRepositoryProvider schemaRepositoryProvider,
+                                          final SchemaResourceManager schemaRepositoryProvider,
                                           final DataBroker dataBroker, final DOMMountPointService mountPointService,
                                           final AAAEncryptionService encryptionService) {
             super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor,
index c36d69acfcb7ffd6383d313b6ffac1d49f658ba3..ce4f0868b5a6fd1a3d435293aa04e60d79158fb7 100644 (file)
@@ -41,6 +41,8 @@ import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegist
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
+import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.netconf.topology.singleton.api.NetconfTopologySingletonService;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup.NetconfTopologySetupBuilder;
@@ -84,6 +86,7 @@ public class NetconfTopologyManager
     private final DOMMountPointService mountPointService;
     private final AAAEncryptionService encryptionService;
     private final DeviceActionFactory deviceActionFactory;
+    private final SchemaResourceManager resourceManager;
     private ListenerRegistration<NetconfTopologyManager> dataChangeListenerRegistration;
     private String privateKeyPath;
     private String privateKeyPassphrase;
@@ -97,8 +100,8 @@ public class NetconfTopologyManager
                                   final String topologyId, final Config config,
                                   final DOMMountPointService mountPointService,
                                   final AAAEncryptionService encryptionService,
-                                  final DeviceActionFactory deviceActionFactory) {
-
+                                  final DeviceActionFactory deviceActionFactory,
+                                  final SchemaResourceManager resourceManager) {
         this.dataBroker = requireNonNull(dataBroker);
         this.rpcProviderRegistry = requireNonNull(rpcProviderRegistry);
         this.actionProviderRegistry = requireNonNull(actionProviderService);
@@ -113,7 +116,7 @@ public class NetconfTopologyManager
         this.mountPointService = mountPointService;
         this.encryptionService = requireNonNull(encryptionService);
         this.deviceActionFactory = requireNonNull(deviceActionFactory);
-
+        this.resourceManager = requireNonNull(resourceManager);
     }
 
     // Blueprint init method
@@ -282,6 +285,9 @@ public class NetconfTopologyManager
     }
 
     private NetconfTopologySetup createSetup(final InstanceIdentifier<Node> instanceIdentifier, final Node node) {
+        final NetconfNode netconfNode = node.augmentation(NetconfNode.class);
+        final RemoteDeviceId deviceId = NetconfTopologyUtils.createRemoteDeviceId(node.getNodeId(), netconfNode);
+
         final NetconfTopologySetupBuilder builder = NetconfTopologySetupBuilder.create()
                 .setClusterSingletonServiceProvider(clusterSingletonServiceProvider)
                 .setDataBroker(dataBroker)
@@ -295,7 +301,7 @@ public class NetconfTopologyManager
                 .setProcessingExecutor(processingExecutor)
                 .setTopologyId(topologyId)
                 .setNetconfClientDispatcher(clientDispatcher)
-                .setSchemaResourceDTO(NetconfTopologyUtils.setupSchemaCacheDTO(node))
+                .setSchemaResourceDTO(resourceManager.getSchemaResources(netconfNode, deviceId))
                 .setIdleTimeout(writeTxIdleTimeout)
                 .setPrivateKeyPath(privateKeyPath)
                 .setPrivateKeyPassphrase(privateKeyPassphrase)
index 022005d6f5612304d5c636dd39d21d06a19f4175..a005f53d249659ad2482c094b8ce656e1026835c 100644 (file)
@@ -8,17 +8,9 @@
 
 package org.opendaylight.netconf.topology.singleton.impl.utils;
 
-import com.google.common.base.Strings;
-import com.google.common.util.concurrent.Uninterruptibles;
-import java.io.File;
 import java.math.BigDecimal;
 import java.net.InetSocketAddress;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
 import org.opendaylight.netconf.api.DocumentedException;
-import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
-import org.opendaylight.netconf.sal.connect.netconf.NetconfStateSchemasResolverImpl;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
@@ -32,23 +24,12 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yangtools.yang.binding.Identifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
-import org.opendaylight.yangtools.yang.model.repo.api.EffectiveModelContextFactory;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
-import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
-import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache;
-import org.opendaylight.yangtools.yang.model.repo.util.InMemorySchemaSourceCache;
-import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
-import org.opendaylight.yangtools.yang.parser.rfc7950.repo.ASTSchemaSource;
-import org.opendaylight.yangtools.yang.parser.rfc7950.repo.TextToASTTransformer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public final class NetconfTopologyUtils {
     private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyUtils.class);
 
-    private static final String DEFAULT_SCHEMA_REPOSITORY_NAME = "sal-netconf-connector";
-
     public static final long DEFAULT_REQUEST_TIMEOUT_MILLIS = 60000L;
     public static final int DEFAULT_KEEPALIVE_DELAY = 0;
     public static final boolean DEFAULT_RECONNECT_ON_CHANGED_SCHEMA = false;
@@ -59,157 +40,10 @@ public final class NetconfTopologyUtils {
     public static final long DEFAULT_CONNECTION_TIMEOUT_MILLIS = 20000L;
     public static final BigDecimal DEFAULT_SLEEP_FACTOR = new BigDecimal(1.5);
 
-
-    // The default cache directory relative to <code>CACHE_DIRECTORY</code>
-
-    public static final String DEFAULT_CACHE_DIRECTORY = "schema";
-
-    // Filesystem based caches are stored relative to the cache directory.
-    public static final String CACHE_DIRECTORY = "cache";
-
-    // The qualified schema cache directory <code>cache/schema</code>
-    public static final String QUALIFIED_DEFAULT_CACHE_DIRECTORY =
-            CACHE_DIRECTORY + File.separator + DEFAULT_CACHE_DIRECTORY;
-
-    // The default schema repository in the case that one is not specified.
-    public static final SharedSchemaRepository DEFAULT_SCHEMA_REPOSITORY =
-            new SharedSchemaRepository(DEFAULT_SCHEMA_REPOSITORY_NAME);
-
-    public static final InMemorySchemaSourceCache<ASTSchemaSource> DEFAULT_AST_CACHE =
-            InMemorySchemaSourceCache.createSoftCache(DEFAULT_SCHEMA_REPOSITORY, ASTSchemaSource.class);
-
-    // The default factory for creating <code>SchemaContext</code> instances.
-    public static final EffectiveModelContextFactory DEFAULT_SCHEMA_CONTEXT_FACTORY =
-            DEFAULT_SCHEMA_REPOSITORY.createEffectiveModelContextFactory();
-
-    /**
-     * Keeps track of initialized Schema resources.  A Map is maintained in which the key represents the name
-     * of the schema cache directory, and the value is a corresponding <code>SchemaResourcesDTO</code>.  The
-     * <code>SchemaResourcesDTO</code> is essentially a container that allows for the extraction of the
-     * <code>SchemaRegistry</code> and <code>SchemaContextFactory</code> which should be used for a particular
-     * Netconf mount.  Access to <code>SCHEMA_RESOURCES_DTO_MAP</code> should be surrounded by appropriate
-     * synchronization locks.
-     */
-    private static final Map<String, NetconfDevice.SchemaResourcesDTO> SCHEMA_RESOURCES_DTO_MAP = new HashMap<>();
-
-    // Initializes default constant instances for the case when the default schema repository
-    // directory cache/schema is used.
-    static {
-        SCHEMA_RESOURCES_DTO_MAP.put(DEFAULT_CACHE_DIRECTORY,
-                new NetconfDevice.SchemaResourcesDTO(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY,
-                        DEFAULT_SCHEMA_CONTEXT_FACTORY, new NetconfStateSchemasResolverImpl()));
-        DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(DEFAULT_AST_CACHE);
-        DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(
-                TextToASTTransformer.create(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY));
-
-        /*
-         * Create the default <code>FilesystemSchemaSourceCache</code>, which stores cached files
-         * in <code>cache/schema</code>. Try up to 3 times - we've seen intermittent failures on jenkins where
-         * FilesystemSchemaSourceCache throws an IAE due to mkdirs failure. The theory is that there's a race
-         * creating the dir and it already exists when mkdirs is called (mkdirs returns false in this case). In this
-         * scenario, a retry should succeed.
-         */
-        int tries = 1;
-        while (true) {
-            try {
-                FilesystemSchemaSourceCache<YangTextSchemaSource> defaultCache =
-                        new FilesystemSchemaSourceCache<>(DEFAULT_SCHEMA_REPOSITORY, YangTextSchemaSource.class,
-                                new File(QUALIFIED_DEFAULT_CACHE_DIRECTORY));
-                DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(defaultCache);
-                break;
-            } catch (IllegalArgumentException e) {
-                if (tries++ >= 3) {
-                    LOG.error("Error creating default schema cache", e);
-                    break;
-                }
-                Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS);
-            }
-        }
-    }
-
     private NetconfTopologyUtils() {
 
     }
 
-    public static NetconfDevice.SchemaResourcesDTO setupSchemaCacheDTO(final Node node) {
-        final NetconfNode netconfNode = node.augmentation(NetconfNode.class);
-        final String moduleSchemaCacheDirectory = netconfNode.getSchemaCacheDirectory();
-        final RemoteDeviceId deviceId = createRemoteDeviceId(node.getNodeId(), netconfNode);
-
-        // Setup information related to the SchemaRegistry, SchemaResourceFactory, etc.
-        NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = null;
-        // Only checks to ensure the String is not empty or null;  further checks related to directory accessibility
-        // and file permissions are handled during the FilesystemSchemaSourceCache initialization.
-        if (!Strings.isNullOrEmpty(moduleSchemaCacheDirectory)) {
-            // If a custom schema cache directory is specified, create the backing DTO; otherwise, the SchemaRegistry
-            // and SchemaContextFactory remain the default values.
-            if (!moduleSchemaCacheDirectory.equals(DEFAULT_CACHE_DIRECTORY)) {
-                // Multiple modules may be created at once;  synchronize to avoid issues with data consistency among
-                // threads.
-                synchronized (SCHEMA_RESOURCES_DTO_MAP) {
-                    // Look for the cached DTO to reuse SchemaRegistry and SchemaContextFactory variables if
-                    // they already exist
-                    schemaResourcesDTO = SCHEMA_RESOURCES_DTO_MAP.get(moduleSchemaCacheDirectory);
-                    if (schemaResourcesDTO == null) {
-                        schemaResourcesDTO = createSchemaResourcesDTO(moduleSchemaCacheDirectory);
-                        schemaResourcesDTO.getSchemaRegistry().registerSchemaSourceListener(
-                                TextToASTTransformer.create((SchemaRepository) schemaResourcesDTO.getSchemaRegistry(),
-                                        schemaResourcesDTO.getSchemaRegistry())
-                        );
-                        SCHEMA_RESOURCES_DTO_MAP.put(moduleSchemaCacheDirectory, schemaResourcesDTO);
-                    }
-                }
-                LOG.info("{} : netconf connector will use schema cache directory {} instead of {}",
-                        deviceId, moduleSchemaCacheDirectory, DEFAULT_CACHE_DIRECTORY);
-            }
-        }
-
-        if (schemaResourcesDTO == null) {
-            synchronized (SCHEMA_RESOURCES_DTO_MAP) {
-                schemaResourcesDTO = SCHEMA_RESOURCES_DTO_MAP.get(DEFAULT_CACHE_DIRECTORY);
-            }
-            LOG.info("{} : using the default directory {}",
-                    deviceId, QUALIFIED_DEFAULT_CACHE_DIRECTORY);
-        }
-
-        return schemaResourcesDTO;
-    }
-
-    /**
-     * Creates the backing Schema classes for a particular directory.
-     *
-     * @param moduleSchemaCacheDirectory The string directory relative to "cache"
-     * @return A DTO containing the Schema classes for the Netconf mount.
-     */
-    private static NetconfDevice.SchemaResourcesDTO createSchemaResourcesDTO(final String moduleSchemaCacheDirectory) {
-        final SharedSchemaRepository repository = new SharedSchemaRepository(moduleSchemaCacheDirectory);
-        final EffectiveModelContextFactory schemaContextFactory
-                = repository.createEffectiveModelContextFactory();
-
-        final FilesystemSchemaSourceCache<YangTextSchemaSource> deviceCache =
-                createDeviceFilesystemCache(moduleSchemaCacheDirectory, repository);
-        repository.registerSchemaSourceListener(deviceCache);
-        repository.registerSchemaSourceListener(InMemorySchemaSourceCache.createSoftCache(repository,
-                ASTSchemaSource.class));
-        return new NetconfDevice.SchemaResourcesDTO(repository, repository, schemaContextFactory,
-                new NetconfStateSchemasResolverImpl());
-    }
-
-    /**
-     * Creates a <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory.
-     *
-     * @param schemaCacheDirectory The custom cache directory relative to "cache"
-     * @return A <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory
-     */
-    private static FilesystemSchemaSourceCache<YangTextSchemaSource> createDeviceFilesystemCache(
-            final String schemaCacheDirectory, final SchemaSourceRegistry schemaRegistry) {
-        final String relativeSchemaCacheDirectory =
-                NetconfTopologyUtils.CACHE_DIRECTORY + File.separator + schemaCacheDirectory;
-        return new FilesystemSchemaSourceCache<>(schemaRegistry, YangTextSchemaSource.class,
-                new File(relativeSchemaCacheDirectory));
-    }
-
-
     public static RemoteDeviceId createRemoteDeviceId(final NodeId nodeId, final NetconfNode node) {
         final IpAddress ipAddress = node.getHost().getIpAddress();
         final InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null
index 91ef4f842b33c4b8d23ee731381c8f8ce01fa1c9..b2e2e59dd0ae0ea2536d3f8126eb0e824330a3b1 100644 (file)
@@ -39,6 +39,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
                odl:type="default"/>
     <reference id="deviceActionFactory"
                interface="org.opendaylight.netconf.sal.connect.api.DeviceActionFactory"/>
+    <reference id="schemaManager"
+               interface="org.opendaylight.netconf.sal.connect.api.SchemaResourceManager"/>
     <odl:clustered-app-config
             id="singletonConfig"
             binding-class="org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.topology.singleton.config.rev170419.Config"
@@ -75,6 +77,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
         <property name="privateKeyPassphrase" value="${private-key-passphrase}"/>
         <argument ref="encryptionService" />
         <argument ref="deviceActionFactory"/>
+        <argument ref="schemaManager"/>
     </bean>
     <service ref="netconfTopologyManager"
              interface="org.opendaylight.netconf.topology.singleton.api.NetconfTopologySingletonService"/>
index 638de1831b4c26935527022b409a5055f69214db..9ff232a71b545d0828018b6ee927bc42e24eb014 100644 (file)
@@ -21,7 +21,6 @@ import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
-import static org.mockito.MockitoAnnotations.initMocks;
 
 import akka.actor.ActorSystem;
 import akka.testkit.javadsl.TestKit;
@@ -52,7 +51,9 @@ import org.apache.commons.io.FileUtils;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
 import org.opendaylight.controller.cluster.ActorSystemProvider;
 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
@@ -96,6 +97,9 @@ import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.mdsal.singleton.dom.impl.DOMClusterSingletonServiceProviderImpl;
 import org.opendaylight.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
+import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
+import org.opendaylight.netconf.sal.connect.impl.DefaultSchemaResourceManager;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice.SchemaResourcesDTO;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
 import org.opendaylight.netconf.topology.singleton.impl.utils.ClusteringRpcException;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
@@ -156,6 +160,7 @@ import org.slf4j.LoggerFactory;
  *
  * @author Thomas Pantelis
  */
+@RunWith(MockitoJUnitRunner.class)
 public class MountPointEndToEndTest {
     private static final Logger LOG = LoggerFactory.getLogger(MountPointEndToEndTest.class);
 
@@ -166,6 +171,9 @@ public class MountPointEndToEndTest {
     private static final InstanceIdentifier<Node> NODE_INSTANCE_ID = NetconfTopologyUtils.createTopologyNodeListPath(
             new NodeKey(NODE_ID), TOPOLOGY_ID);
 
+    private static final String TEST_ROOT_DIRECTORY = "test-cache-root";
+    private static final String TEST_DEFAULT_SUBDIR = "test-schema";
+
     @Mock private DOMRpcProviderService mockRpcProviderRegistry;
     @Mock private DOMActionProviderService mockActionProviderRegistry;
     @Mock private NetconfClientDispatcher mockClientDispatcher;
@@ -206,13 +214,15 @@ public class MountPointEndToEndTest {
     private YangInstanceIdentifier yangNodeInstanceId;
     private final TopDOMRpcImplementation topRpcImplementation = new TopDOMRpcImplementation();
 
+    private SchemaResourceManager resourceManager;
+
     @SuppressWarnings({ "unchecked", "rawtypes" })
     @Before
     public void setUp() throws Exception {
-        initMocks(this);
-
         deleteCacheDir();
 
+        resourceManager = new DefaultSchemaResourceManager(TEST_ROOT_DIRECTORY, TEST_DEFAULT_SUBDIR);
+
         topModuleInfo = BindingReflections.getModuleInfo(Top.class);
 
         final ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create();
@@ -240,7 +250,7 @@ public class MountPointEndToEndTest {
     }
 
     private static void deleteCacheDir() {
-        FileUtils.deleteQuietly(new File(NetconfTopologyUtils.CACHE_DIRECTORY));
+        FileUtils.deleteQuietly(new File(TEST_ROOT_DIRECTORY));
     }
 
     @After
@@ -266,7 +276,9 @@ public class MountPointEndToEndTest {
 
         doReturn(MoreExecutors.newDirectExecutorService()).when(mockThreadPool).getExecutor();
 
-        NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY.registerSchemaSource(
+        final SchemaResourcesDTO resources =  resourceManager.getSchemaResources(
+            new NetconfNodeBuilder().setSchemaCacheDirectory(TEST_DEFAULT_SUBDIR).build(), "test");
+        resources.getSchemaRegistry().registerSchemaSource(
             id -> Futures.immediateFuture(YangTextSchemaSource.delegateForByteSource(id,
                     topModuleInfo.getYangTextByteSource())),
             PotentialSchemaSource.create(RevisionSourceIdentifier.create(TOP_MODULE_NAME,
@@ -275,7 +287,7 @@ public class MountPointEndToEndTest {
         masterNetconfTopologyManager = new NetconfTopologyManager(masterDataBroker, mockRpcProviderRegistry,
             mockActionProviderRegistry, masterClusterSingletonServiceProvider, mockKeepaliveExecutor, mockThreadPool,
                 mockMasterActorSystemProvider, eventExecutor, mockClientDispatcher, TOPOLOGY_ID, config,
-                masterMountPointService, mockEncryptionService, deviceActionFactory) {
+                masterMountPointService, mockEncryptionService, deviceActionFactory, resourceManager) {
             @Override
             protected NetconfTopologyContext newNetconfTopologyContext(final NetconfTopologySetup setup,
                 final ServiceGroupIdentifier serviceGroupIdent, final Timeout actorResponseWaitTime,
@@ -314,7 +326,7 @@ public class MountPointEndToEndTest {
         slaveNetconfTopologyManager = new NetconfTopologyManager(slaveDataBroker, mockRpcProviderRegistry,
             mockActionProviderRegistry, mockSlaveClusterSingletonServiceProvider, mockKeepaliveExecutor, mockThreadPool,
                 mockSlaveActorSystemProvider, eventExecutor, mockClientDispatcher, TOPOLOGY_ID, config,
-                slaveMountPointService, mockEncryptionService, deviceActionFactory) {
+                slaveMountPointService, mockEncryptionService, deviceActionFactory, resourceManager) {
             @Override
             protected NetconfTopologyContext newNetconfTopologyContext(final NetconfTopologySetup setup,
                 final ServiceGroupIdentifier serviceGroupIdent, final Timeout actorResponseWaitTime,
@@ -360,7 +372,7 @@ public class MountPointEndToEndTest {
     private MasterSalFacade testMaster() throws InterruptedException, ExecutionException, TimeoutException {
         LOG.info("****** Testing master");
 
-        writeNetconfNode(NetconfTopologyUtils.DEFAULT_CACHE_DIRECTORY, masterDataBroker);
+        writeNetconfNode(TEST_DEFAULT_SUBDIR, masterDataBroker);
 
         final MasterSalFacade masterSalFacade = masterSalFacadeFuture.get(5, TimeUnit.SECONDS);
 
@@ -433,7 +445,7 @@ public class MountPointEndToEndTest {
         slaveMountPointService.registerProvisionListener(slaveMountPointListener);
 
         masterSalFacadeFuture = SettableFuture.create();
-        writeNetconfNode(NetconfTopologyUtils.DEFAULT_CACHE_DIRECTORY, masterDataBroker);
+        writeNetconfNode(TEST_DEFAULT_SUBDIR, masterDataBroker);
 
         verify(masterMountPointListener, timeout(5000)).onMountPointRemoved(yangNodeInstanceId);
 
index 6e6d3d6f5ec11288fa33e97c2200089eceb5cdee..8fc8473b4542302188abcfc04db477ca5c0bd328 100644 (file)
@@ -26,7 +26,6 @@ import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.MockitoAnnotations.initMocks;
-import static org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY;
 
 import akka.actor.ActorRef;
 import akka.actor.ActorSystem;
@@ -408,9 +407,11 @@ public class NetconfNodeActorTest {
 
     @Test(expected = MissingSchemaSourceException.class)
     public void testMissingSchemaSourceOnMissingProvider() throws Exception {
+        final SharedSchemaRepository repository = new SharedSchemaRepository("test");
+
         SchemaResourcesDTO schemaResourceDTO2 = mock(SchemaResourcesDTO.class);
-        doReturn(DEFAULT_SCHEMA_REPOSITORY).when(schemaResourceDTO2).getSchemaRegistry();
-        doReturn(DEFAULT_SCHEMA_REPOSITORY).when(schemaResourceDTO2).getSchemaRepository();
+        doReturn(repository).when(schemaResourceDTO2).getSchemaRegistry();
+        doReturn(repository).when(schemaResourceDTO2).getSchemaRepository();
         final NetconfTopologySetup setup = NetconfTopologySetupBuilder.create().setActorSystem(system)
                 .setSchemaResourceDTO(schemaResourceDTO2).setIdleTimeout(Duration.apply(1, TimeUnit.SECONDS)).build();
         final Props props = NetconfNodeActor.props(setup, remoteDeviceId, TIMEOUT, mockMountPointService);
index 82b2d325cb11437ca2b47d8edb4f7bafb2472920..fe0e001268d3e0ab9112c48ab080ad1b6a066472 100644 (file)
@@ -60,6 +60,7 @@ import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegist
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
+import org.opendaylight.netconf.sal.connect.impl.DefaultSchemaResourceManager;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
@@ -130,7 +131,7 @@ public class NetconfTopologyManagerTest {
         netconfTopologyManager = new NetconfTopologyManager(dataBroker, rpcProviderRegistry, actionProviderRegistry,
                 clusterSingletonServiceProvider, keepaliveExecutor, processingThreadPool,
                 actorSystemProvider, eventExecutor, clientDispatcher, TOPOLOGY_ID, config,
-                mountPointService, encryptionService, deviceActionFactory) {
+                mountPointService, encryptionService, deviceActionFactory, new DefaultSchemaResourceManager()) {
             @Override
             protected NetconfTopologyContext newNetconfTopologyContext(final NetconfTopologySetup setup,
                 final ServiceGroupIdentifier serviceGroupIdent, final Timeout actorResponseWaitTime,
index 8fa8ee6357b426a603bdb81fcc8e69a856dce29f..48dfab7f5f825f5bc0e1910b3614ed679b50ce01 100644 (file)
@@ -44,13 +44,13 @@ import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.impl.DefaultSchemaResourceManager;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
 import org.opendaylight.netconf.sal.connect.netconf.sal.KeepaliveSalFacade;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfConnectorDTO;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
-import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
@@ -188,7 +188,8 @@ public class RemoteDeviceConnectorImplTest {
                 .build();
 
         final Node node = new NodeBuilder().setNodeId(NODE_ID).addAugmentation(NetconfNode.class, netconfNode).build();
-        builder.setSchemaResourceDTO(NetconfTopologyUtils.setupSchemaCacheDTO(node));
+
+        builder.setSchemaResourceDTO(new DefaultSchemaResourceManager().getSchemaResources(netconfNode, "foo"));
 
         final RemoteDeviceConnectorImpl remoteDeviceConnection =
                 new RemoteDeviceConnectorImpl(builder.build(), remoteDeviceId, deviceActionFactory);
diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/api/SchemaRepositoryProvider.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/api/SchemaRepositoryProvider.java
deleted file mode 100644 (file)
index c0c38cf..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.netconf.topology.api;
-
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
-
-public interface SchemaRepositoryProvider {
-
-    @NonNull SharedSchemaRepository getSharedSchemaRepository();
-}
index fd31e9a7589a459f1043734af752c7f7da5ccd5f..478ca7f6e328d7e66e3e39d1ce7dd42baf2f53f8 100644 (file)
@@ -11,16 +11,13 @@ import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.Uninterruptibles;
 import io.netty.util.concurrent.EventExecutor;
-import java.io.File;
 import java.math.BigDecimal;
 import java.net.InetSocketAddress;
 import java.net.URL;
@@ -29,7 +26,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.concurrent.TimeUnit;
 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
 import org.opendaylight.controller.config.threadpool.ThreadPool;
@@ -48,10 +44,11 @@ import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPasswo
 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
 import org.opendaylight.netconf.sal.connect.api.RemoteDevice;
 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
 import org.opendaylight.netconf.sal.connect.netconf.LibraryModulesSchemas;
 import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice.SchemaResourcesDTO;
 import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceBuilder;
-import org.opendaylight.netconf.sal.connect.netconf.NetconfStateSchemasResolverImpl;
 import org.opendaylight.netconf.sal.connect.netconf.SchemalessNetconfDevice;
 import org.opendaylight.netconf.sal.connect.netconf.auth.DatastoreBackedPublicKeyAuth;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
@@ -64,9 +61,9 @@ import org.opendaylight.netconf.sal.connect.netconf.schema.YangLibrarySchemaYang
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.netconf.sal.connect.util.SslHandlerFactoryImpl;
 import org.opendaylight.netconf.topology.api.NetconfTopology;
-import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.optional.rev190614.NetconfNodeAugmentedOptional;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.Protocol;
@@ -79,27 +76,18 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev15
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.key.auth.KeyBased;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.login.pw.LoginPassword;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.login.pw.unencrypted.LoginPasswordUnencrypted;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.schema.storage.YangLibrary;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yangtools.yang.model.repo.api.EffectiveModelContextFactory;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactoryConfiguration;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
-import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache;
-import org.opendaylight.yangtools.yang.model.repo.util.InMemorySchemaSourceCache;
-import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
-import org.opendaylight.yangtools.yang.parser.rfc7950.repo.ASTSchemaSource;
-import org.opendaylight.yangtools.yang.parser.rfc7950.repo.TextToASTTransformer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public abstract class AbstractNetconfTopology implements NetconfTopology {
-
     private static final Logger LOG = LoggerFactory.getLogger(AbstractNetconfTopology.class);
 
     protected static final long DEFAULT_REQUEST_TIMEOUT_MILLIS = 60000L;
@@ -112,103 +100,18 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
     private static final long DEFAULT_CONNECTION_TIMEOUT_MILLIS = 20000L;
     private static final BigDecimal DEFAULT_SLEEP_FACTOR = new BigDecimal(1.5);
 
-    // constants related to Schema Cache(s)
-    /**
-     * Filesystem based caches are stored relative to the cache directory.
-     */
-    private static final String CACHE_DIRECTORY = "cache";
-
-    /**
-     * The default cache directory relative to <code>CACHE_DIRECTORY</code>.
-     */
-    private static final String DEFAULT_CACHE_DIRECTORY = "schema";
-
-    /**
-     * The qualified schema cache directory <code>cache/schema</code>.
-     */
-    private static final String QUALIFIED_DEFAULT_CACHE_DIRECTORY =
-            CACHE_DIRECTORY + File.separator + DEFAULT_CACHE_DIRECTORY;
-
-    /**
-     * The name for the default schema repository.
-     */
-    private static final String DEFAULT_SCHEMA_REPOSITORY_NAME = "sal-netconf-connector";
-
-    /**
-     * The default schema repository in the case that one is not specified.
-     */
-    private static final SharedSchemaRepository DEFAULT_SCHEMA_REPOSITORY =
-            new SharedSchemaRepository(DEFAULT_SCHEMA_REPOSITORY_NAME);
-
-    public static final InMemorySchemaSourceCache<ASTSchemaSource> DEFAULT_AST_CACHE =
-            InMemorySchemaSourceCache.createSoftCache(DEFAULT_SCHEMA_REPOSITORY, ASTSchemaSource.class);
-
-    /**
-     * The default factory for creating <code>SchemaContext</code> instances.
-     */
-    private static final EffectiveModelContextFactory DEFAULT_SCHEMA_CONTEXT_FACTORY =
-            DEFAULT_SCHEMA_REPOSITORY.createEffectiveModelContextFactory(
-                SchemaContextFactoryConfiguration.getDefault());
-
-    /**
-     * Keeps track of initialized Schema resources.  A Map is maintained in which the key represents the name
-     * of the schema cache directory, and the value is a corresponding <code>SchemaResourcesDTO</code>.  The
-     * <code>SchemaResourcesDTO</code> is essentially a container that allows for the extraction of the
-     * <code>SchemaRegistry</code> and <code>SchemaContextFactory</code> which should be used for a particular
-     * Netconf mount.  Access to <code>SCHEMA_RESOURCES_DTO_MAP</code> should be surrounded by appropriate
-     * synchronization locks.
-     */
-    private static final Map<String, NetconfDevice.SchemaResourcesDTO> SCHEMA_RESOURCES_DTO_MAP = new HashMap<>();
-
-    // Initializes default constant instances for the case when the default schema repository
-    // directory cache/schema is used.
-    static {
-        SCHEMA_RESOURCES_DTO_MAP.put(DEFAULT_CACHE_DIRECTORY,
-                new NetconfDevice.SchemaResourcesDTO(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY,
-                        DEFAULT_SCHEMA_CONTEXT_FACTORY,
-                        new NetconfStateSchemasResolverImpl()));
-        DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(DEFAULT_AST_CACHE);
-        DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(
-                TextToASTTransformer.create(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY));
-
-        /*
-         * Create the default <code>FilesystemSchemaSourceCache</code>, which stores cached files
-         * in <code>cache/schema</code>. Try up to 3 times - we've seen intermittent failures on jenkins where
-         * FilesystemSchemaSourceCache throws an IAE due to mkdirs failure. The theory is that there's a race
-         * creating the dir and it already exists when mkdirs is called (mkdirs returns false in this case). In this
-         * scenario, a retry should succeed.
-         */
-        int tries = 1;
-        while (true) {
-            try {
-                FilesystemSchemaSourceCache<YangTextSchemaSource> defaultCache =
-                        new FilesystemSchemaSourceCache<>(DEFAULT_SCHEMA_REPOSITORY, YangTextSchemaSource.class,
-                                new File(QUALIFIED_DEFAULT_CACHE_DIRECTORY));
-                DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(defaultCache);
-                break;
-            } catch (IllegalArgumentException e) {
-                if (tries++ >= 3) {
-                    LOG.error("Error creating default schema cache", e);
-                    break;
-                }
-                Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS);
-            }
-        }
-    }
 
     private final NetconfClientDispatcher clientDispatcher;
     private final EventExecutor eventExecutor;
     private final DeviceActionFactory deviceActionFactory;
     private final NetconfKeystoreAdapter keystoreAdapter;
+    private final SchemaResourceManager schemaManager;
+
     protected final ScheduledThreadPool keepaliveExecutor;
     protected final ListeningExecutorService processingExecutor;
-    protected final SharedSchemaRepository sharedSchemaRepository;
     protected final DataBroker dataBroker;
     protected final DOMMountPointService mountPointService;
     protected final String topologyId;
-    protected SchemaSourceRegistry schemaRegistry = DEFAULT_SCHEMA_REPOSITORY;
-    protected SchemaRepository schemaRepository = DEFAULT_SCHEMA_REPOSITORY;
-    protected SchemaContextFactory schemaContextFactory = DEFAULT_SCHEMA_CONTEXT_FACTORY;
     protected String privateKeyPath;
     protected String privateKeyPassphrase;
     protected final AAAEncryptionService encryptionService;
@@ -216,8 +119,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
 
     protected AbstractNetconfTopology(final String topologyId, final NetconfClientDispatcher clientDispatcher,
                                       final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
-                                      final ThreadPool processingExecutor,
-                                      final SchemaRepositoryProvider schemaRepositoryProvider,
+                                      final ThreadPool processingExecutor, final SchemaResourceManager schemaManager,
                                       final DataBroker dataBroker, final DOMMountPointService mountPointService,
                                       final AAAEncryptionService encryptionService,
                                       final DeviceActionFactory deviceActionFactory) {
@@ -226,8 +128,8 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
         this.eventExecutor = eventExecutor;
         this.keepaliveExecutor = keepaliveExecutor;
         this.processingExecutor = MoreExecutors.listeningDecorator(processingExecutor.getExecutor());
+        this.schemaManager = requireNonNull(schemaManager);
         this.deviceActionFactory = deviceActionFactory;
-        this.sharedSchemaRepository = schemaRepositoryProvider.getSharedSchemaRepository();
         this.dataBroker = dataBroker;
         this.mountPointService = mountPointService;
         this.encryptionService = encryptionService;
@@ -235,14 +137,6 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
         this.keystoreAdapter = new NetconfKeystoreAdapter(dataBroker);
     }
 
-    public void setSchemaRegistry(final SchemaSourceRegistry schemaRegistry) {
-        this.schemaRegistry = schemaRegistry;
-    }
-
-    public void setSchemaContextFactory(final SchemaContextFactory schemaContextFactory) {
-        this.schemaContextFactory = schemaContextFactory;
-    }
-
     @Override
     public ListenableFuture<NetconfDeviceCapabilities> connectNode(final NodeId nodeId, final Node configNode) {
         LOG.info("Connecting RemoteDevice{{}} , with config {}", nodeId, hideCredentials(configNode));
@@ -323,8 +217,6 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
                 ? DEFAULT_REQUEST_TIMEOUT_MILLIS : node.getDefaultRequestTimeoutMillis().toJava();
         final long keepaliveDelay = node.getKeepaliveDelay() == null
                 ? DEFAULT_KEEPALIVE_DELAY : node.getKeepaliveDelay().toJava();
-        final boolean reconnectOnChangedSchema = node.isReconnectOnChangedSchema() == null
-                ? DEFAULT_RECONNECT_ON_CHANGED_SCHEMA : node.isReconnectOnChangedSchema();
 
         final IpAddress ipAddress = node.getHost().getIpAddress();
         final InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null
@@ -332,8 +224,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
                 node.getPort().getValue().toJava());
         final RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address);
 
-        RemoteDeviceHandler<NetconfSessionPreferences> salFacade =
-                createSalFacade(remoteDeviceId);
+        RemoteDeviceHandler<NetconfSessionPreferences> salFacade = createSalFacade(remoteDeviceId);
 
         if (keepaliveDelay > 0) {
             LOG.warn("Adding keepalive facade, for device {}", nodeId);
@@ -341,49 +232,11 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
                     keepaliveDelay, defaultRequestTimeoutMillis);
         }
 
-        // pre register yang library sources as fallback schemas to schema registry
-        final List<SchemaSourceRegistration<YangTextSchemaSource>> registeredYangLibSources = Lists.newArrayList();
-        if (node.getYangLibrary() != null) {
-            final String yangLibURL = node.getYangLibrary().getYangLibraryUrl().getValue();
-            final String yangLibUsername = node.getYangLibrary().getUsername();
-            final String yangLigPassword = node.getYangLibrary().getPassword();
-
-            final LibraryModulesSchemas libraryModulesSchemas;
-            if (yangLibURL != null) {
-                if (yangLibUsername != null && yangLigPassword != null) {
-                    libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL, yangLibUsername, yangLigPassword);
-                } else {
-                    libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL);
-                }
-
-                for (final Map.Entry<SourceIdentifier, URL> sourceIdentifierURLEntry
-                        : libraryModulesSchemas.getAvailableModels().entrySet()) {
-                    registeredYangLibSources
-                        .add(schemaRegistry.registerSchemaSource(
-                                new YangLibrarySchemaYangSourceProvider(remoteDeviceId,
-                                        libraryModulesSchemas.getAvailableModels()),
-                                PotentialSchemaSource.create(sourceIdentifierURLEntry.getKey(),
-                                        YangTextSchemaSource.class, PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
-                }
-            }
-        }
-
-        final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = setupSchemaCacheDTO(nodeId, node);
         final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> device;
         if (node.isSchemaless()) {
             device = new SchemalessNetconfDevice(remoteDeviceId, salFacade);
         } else {
-            NetconfDeviceBuilder netconfDeviceBuilder = new NetconfDeviceBuilder()
-                    .setReconnectOnSchemasChange(reconnectOnChangedSchema)
-                    .setSchemaResourcesDTO(schemaResourcesDTO)
-                    .setGlobalProcessingExecutor(this.processingExecutor)
-                    .setId(remoteDeviceId)
-                    .setSalFacade(salFacade)
-                    .setNode(node)
-                    .setEventExecutor(eventExecutor)
-                    .setNodeOptional(nodeOptional)
-                    .setDeviceActionFactory(deviceActionFactory);
-            device = netconfDeviceBuilder.build();
+            device = createNetconfDevice(remoteDeviceId, salFacade, nodeId, node, nodeOptional);
         }
 
         final Optional<UserPreferences> userCapabilities = getUserCapabilities(node);
@@ -405,79 +258,63 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
         return new NetconfConnectorDTO(netconfDeviceCommunicator, salFacade);
     }
 
-    protected NetconfDevice.SchemaResourcesDTO setupSchemaCacheDTO(final NodeId nodeId, final NetconfNode node) {
-        // Setup information related to the SchemaRegistry, SchemaResourceFactory, etc.
-        NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = null;
-        final String moduleSchemaCacheDirectory = node.getSchemaCacheDirectory();
-        // Only checks to ensure the String is not empty or null; further checks related to directory
-        // accessibility and file permissionsare handled during the FilesystemSchemaSourceCache initialization.
-        if (!Strings.isNullOrEmpty(moduleSchemaCacheDirectory)) {
-            // If a custom schema cache directory is specified, create the backing DTO; otherwise,
-            // the SchemaRegistry and SchemaContextFactory remain the default values.
-            if (!moduleSchemaCacheDirectory.equals(DEFAULT_CACHE_DIRECTORY)) {
-                // Multiple modules may be created at once;
-                // synchronize to avoid issues with data consistency among threads.
-                synchronized (SCHEMA_RESOURCES_DTO_MAP) {
-                    // Look for the cached DTO to reuse SchemaRegistry and SchemaContextFactory variables
-                    // if they already exist
-                    schemaResourcesDTO = SCHEMA_RESOURCES_DTO_MAP.get(moduleSchemaCacheDirectory);
-                    if (schemaResourcesDTO == null) {
-                        schemaResourcesDTO = createSchemaResourcesDTO(moduleSchemaCacheDirectory);
-                        schemaResourcesDTO.getSchemaRegistry().registerSchemaSourceListener(
-                                TextToASTTransformer.create((SchemaRepository) schemaResourcesDTO.getSchemaRegistry(),
-                                        schemaResourcesDTO.getSchemaRegistry())
-                        );
-                        SCHEMA_RESOURCES_DTO_MAP.put(moduleSchemaCacheDirectory, schemaResourcesDTO);
-                    }
-                }
-                LOG.info("Netconf connector for device {} will use schema cache directory {} instead of {}",
-                        nodeId.getValue(), moduleSchemaCacheDirectory, DEFAULT_CACHE_DIRECTORY);
-            }
-        } else {
-            LOG.warn("schema-cache-directory for {} is null or empty;  using the default {}",
-                    nodeId.getValue(), QUALIFIED_DEFAULT_CACHE_DIRECTORY);
-        }
+    private NetconfDevice createNetconfDevice(final RemoteDeviceId remoteDeviceId,
+            final RemoteDeviceHandler<NetconfSessionPreferences> salFacade, final NodeId nodeId, final NetconfNode node,
+            final NetconfNodeAugmentedOptional nodeOptional) {
+        final boolean reconnectOnChangedSchema = node.isReconnectOnChangedSchema() == null
+                ? DEFAULT_RECONNECT_ON_CHANGED_SCHEMA : node.isReconnectOnChangedSchema();
 
-        if (schemaResourcesDTO == null) {
-            schemaResourcesDTO = new NetconfDevice.SchemaResourcesDTO(schemaRegistry, schemaRepository,
-                    schemaContextFactory, new NetconfStateSchemasResolverImpl());
-        }
+        final SchemaResourcesDTO resources = schemaManager.getSchemaResources(node, nodeId.getValue());
+
+        final NetconfDevice device = new NetconfDeviceBuilder()
+                .setReconnectOnSchemasChange(reconnectOnChangedSchema)
+                .setSchemaResourcesDTO(resources)
+                .setGlobalProcessingExecutor(this.processingExecutor)
+                .setId(remoteDeviceId)
+                .setSalFacade(salFacade)
+                .setNode(node)
+                .setEventExecutor(eventExecutor)
+                .setNodeOptional(nodeOptional)
+                .setDeviceActionFactory(deviceActionFactory)
+                .build();
 
-        return schemaResourcesDTO;
-    }
+        final YangLibrary yangLibrary = node.getYangLibrary();
+        if (yangLibrary != null) {
+            final Uri uri = yangLibrary.getYangLibraryUrl();
+            if (uri != null) {
+                // FIXME: NETCONF-675: these registrations need to be torn down with the device. This does not look
+                //                     quite right, though, as we can end up adding a lot of registrations on a
+                //                     per-device basis.
+                //                     This leak is also detected by SpotBugs as soon as this initialization is switched
+                //                     to proper "new ArrayList<>" and hence we really need to attach these somewhere
+                //                     else.
+                //                     It seems we should be subclassing NetconfConnectorDTO for this purpose as a
+                //                     first step and then perhaps do some refcounting or similar based on the
+                //                     schemaRegistry instance.
+                final List<SchemaSourceRegistration<?>> registeredYangLibSources = Lists.newArrayList();
+                final String yangLibURL = uri.getValue();
+                final SchemaSourceRegistry schemaRegistry = resources.getSchemaRegistry();
+
+                // pre register yang library sources as fallback schemas to schema registry
+                final LibraryModulesSchemas schemas;
+                final String yangLibUsername = yangLibrary.getUsername();
+                final String yangLigPassword = yangLibrary.getPassword();
+                if (yangLibUsername != null && yangLigPassword != null) {
+                    schemas = LibraryModulesSchemas.create(yangLibURL, yangLibUsername, yangLigPassword);
+                } else {
+                    schemas = LibraryModulesSchemas.create(yangLibURL);
+                }
 
-    /**
-     * Creates the backing Schema classes for a particular directory.
-     *
-     * @param moduleSchemaCacheDirectory The string directory relative to "cache"
-     * @return A DTO containing the Schema classes for the Netconf mount.
-     */
-    private NetconfDevice.SchemaResourcesDTO createSchemaResourcesDTO(final String moduleSchemaCacheDirectory) {
-        final SharedSchemaRepository repository = new SharedSchemaRepository(moduleSchemaCacheDirectory);
-        final EffectiveModelContextFactory contextFactory
-                = repository.createEffectiveModelContextFactory(SchemaContextFactoryConfiguration.getDefault());
-        setSchemaRegistry(repository);
-        setSchemaContextFactory(contextFactory);
-        final FilesystemSchemaSourceCache<YangTextSchemaSource> deviceCache =
-                createDeviceFilesystemCache(moduleSchemaCacheDirectory);
-        repository.registerSchemaSourceListener(deviceCache);
-        repository.registerSchemaSourceListener(
-            InMemorySchemaSourceCache.createSoftCache(repository, ASTSchemaSource.class));
-        return new NetconfDevice.SchemaResourcesDTO(repository, repository, contextFactory,
-                new NetconfStateSchemasResolverImpl());
-    }
+                for (final Map.Entry<SourceIdentifier, URL> entry : schemas.getAvailableModels().entrySet()) {
+                    registeredYangLibSources.add(schemaRegistry.registerSchemaSource(
+                        new YangLibrarySchemaYangSourceProvider(remoteDeviceId, schemas.getAvailableModels()),
+                        PotentialSchemaSource.create(entry.getKey(), YangTextSchemaSource.class,
+                            PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
+                }
+            }
+        }
 
-    /**
-     * Creates a <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory.
-     *
-     * @param schemaCacheDirectory The custom cache directory relative to "cache"
-     * @return A <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory
-     */
-    private FilesystemSchemaSourceCache<YangTextSchemaSource> createDeviceFilesystemCache(
-            final String schemaCacheDirectory) {
-        final String relativeSchemaCacheDirectory = CACHE_DIRECTORY + File.separator + schemaCacheDirectory;
-        return new FilesystemSchemaSourceCache<>(schemaRegistry, YangTextSchemaSource.class,
-                new File(relativeSchemaCacheDirectory));
+        return device;
     }
 
     /**
diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/SharedSchemaRepositoryProvider.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/SharedSchemaRepositoryProvider.java
deleted file mode 100644 (file)
index 36d0d28..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2016 Inocybe Technologies and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.netconf.topology.spi;
-
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
-import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
-
-public class SharedSchemaRepositoryProvider implements SchemaRepositoryProvider {
-    private final @NonNull SharedSchemaRepository schemaRepository;
-
-    public SharedSchemaRepositoryProvider(final String moduleName) {
-        schemaRepository = new SharedSchemaRepository(moduleName);
-    }
-
-    @Override
-    public SharedSchemaRepository getSharedSchemaRepository() {
-        return schemaRepository;
-    }
-}
\ No newline at end of file
index 7921f94b63aa02fa0d7d0689c6d1a3d82b9ddd16..58f54729785133d4ba4e3b6cc3fb7b9e6346cb38 100644 (file)
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>javax.inject</groupId>
+      <artifactId>javax.inject</artifactId>
+      <scope>provided</scope>
+      <optional>true</optional>
+    </dependency>
     <dependency>
       <groupId>org.xmlunit</groupId>
       <artifactId>xmlunit-legacy</artifactId>
diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/api/SchemaResourceManager.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/api/SchemaResourceManager.java
new file mode 100644 (file)
index 0000000..19048d8
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.connect.api;
+
+import com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice.SchemaResourcesDTO;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+
+@Beta
+@NonNullByDefault
+public interface SchemaResourceManager {
+
+    SchemaResourcesDTO getSchemaResources(NetconfNode node, Object nodeId);
+}
diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/impl/DefaultSchemaResourceManager.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/impl/DefaultSchemaResourceManager.java
new file mode 100644 (file)
index 0000000..60f4cf5
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.connect.impl;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Strings;
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.checkerframework.checker.lock.qual.GuardedBy;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice.SchemaResourcesDTO;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfStateSchemasResolverImpl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactoryConfiguration;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache;
+import org.opendaylight.yangtools.yang.model.repo.util.InMemorySchemaSourceCache;
+import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
+import org.opendaylight.yangtools.yang.parser.rfc7950.repo.ASTSchemaSource;
+import org.opendaylight.yangtools.yang.parser.rfc7950.repo.TextToASTTransformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Simple single-node implementation of the {@link SchemaResourceManager} contract. Operates on the specified base
+ * root directory, where a number of independent subdirectories are created, each for a global default and anything
+ * encountered based on configuration.
+ */
+@Beta
+@Singleton
+public final class DefaultSchemaResourceManager implements SchemaResourceManager {
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultSchemaResourceManager.class);
+
+    @GuardedBy("this")
+    private final Map<String, SchemaResourcesDTO> resources = new HashMap<>();
+    private final @NonNull SchemaResourcesDTO defaultResources;
+    private final String defaultSubdirectory;
+    private final String rootDirectory;
+
+    @Inject
+    public DefaultSchemaResourceManager() {
+        this("cache", "schema");
+    }
+
+    public DefaultSchemaResourceManager(final String rootDirectory, final String defaultSubdirectory) {
+        this.rootDirectory = requireNonNull(rootDirectory);
+        this.defaultSubdirectory = requireNonNull(defaultSubdirectory);
+        this.defaultResources = createResources(defaultSubdirectory);
+    }
+
+    @Override
+    public SchemaResourcesDTO getSchemaResources(final NetconfNode node, final Object nodeId) {
+        final String subdir = node.getSchemaCacheDirectory();
+        if (defaultSubdirectory.equals(subdir)) {
+            // Fast path for default devices
+            return defaultResources;
+        }
+        if (Strings.isNullOrEmpty(subdir)) {
+            // FIXME: we probably want to change semantics here:
+            //        - update model to not allow empty name
+            //        - silently default to the default
+            LOG.warn("schema-cache-directory for {} is null or empty;  using the default {}", nodeId,
+                defaultSubdirectory);
+            return defaultResources;
+        }
+
+        LOG.info("Netconf connector for device {} will use schema cache directory {} instead of {}", nodeId, subdir,
+            defaultSubdirectory);
+        return getSchemaResources(subdir);
+    }
+
+    private synchronized @NonNull SchemaResourcesDTO getSchemaResources(final String subdir) {
+        // Fast path for unusual devices
+        final SchemaResourcesDTO existing = resources.get(subdir);
+        if (existing != null) {
+            return existing;
+        }
+
+        final SchemaResourcesDTO created = createResources(subdir);
+        resources.put(subdir, created);
+        return created;
+    }
+
+    private @NonNull SchemaResourcesDTO createResources(final String subdir) {
+        // Setup the baseline empty registry
+        // FIXME: add YangParserFactory argument
+        final SharedSchemaRepository repository = new SharedSchemaRepository(subdir);
+
+        // Teach the registry how to transform YANG text to ASTSchemaSource internally
+        repository.registerSchemaSourceListener(TextToASTTransformer.create(repository, repository));
+
+        // Attach a soft cache of ASTSchemaSource instances. This is important during convergence when we are fishing
+        // for a consistent set of modules, as it skips the need to re-parse the text sources multiple times. It also
+        // helps establishing different sets of contexts, as they can share this pre-made cache.
+        repository.registerSchemaSourceListener(
+            // FIXME: add knobs to control cache lifetime explicitly
+            InMemorySchemaSourceCache.createSoftCache(repository, ASTSchemaSource.class));
+
+        // Attach the filesystem cache, providing persistence capability, so that restarts do not require us to
+        // re-populate the cache. This also acts as a side-load capability, as anything pre-populated into that
+        // directory will not be fetched from the device.
+        repository.registerSchemaSourceListener(new FilesystemSchemaSourceCache<>(repository,
+                YangTextSchemaSource.class, new File(rootDirectory + File.separator + subdir)));
+
+        return new SchemaResourcesDTO(repository, repository,
+            repository.createEffectiveModelContextFactory(SchemaContextFactoryConfiguration.getDefault()),
+            new NetconfStateSchemasResolverImpl());
+    }
+}
index 6916c588fefc3de837991b03e5b040209e1d851d..d21a6d7291edd087590ced5b0c09cf6a26bb8c9b 100644 (file)
@@ -18,4 +18,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <service ref="deviceActionFactory"
              interface="org.opendaylight.netconf.sal.connect.api.DeviceActionFactory"
              odl:type="default"/>
+
+    <bean id="schemaResourceManager"
+          class="org.opendaylight.netconf.sal.connect.impl.DefaultSchemaResourceManager">
+    </bean>
+
+    <service ref="schemaResourceManager"
+             interface="org.opendaylight.netconf.sal.connect.api.SchemaResourceManager"/>
 </blueprint>
\ No newline at end of file