Bug 8086 - Cannot mount honeycomb in clustered odl on CentOS 17/54017/2
authorJakub Morvay <jmorvay@cisco.com>
Wed, 29 Mar 2017 08:22:16 +0000 (10:22 +0200)
committerJakub Morvay <jmorvay@cisco.com>
Thu, 30 Mar 2017 08:28:33 +0000 (10:28 +0200)
Change-Id: I596cc8b7e0ed04b224bad6b7fa98555c8ef172e2
Signed-off-by: Jakub Morvay <jmorvay@cisco.com>
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfNodeManager.java
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyContext.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/RemoteDeviceConnectorImpl.java
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtils.java
netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImplTest.java

index 9e60db57a2c031cf9a089fe85d3569ad81de82d3..6ec40e5747999159fd2d635216e3645305ab254a 100644 (file)
@@ -54,12 +54,11 @@ class NetconfNodeManager
     private final Timeout actorResponseWaitTime;
 
     NetconfNodeManager(final NetconfTopologySetup setup,
-                       final RemoteDeviceId id, final SchemaSourceRegistry schemaRegistry,
-                       final SchemaRepository schemaRepository, final Timeout actorResponseWaitTime) {
+                       final RemoteDeviceId id, final Timeout actorResponseWaitTime) {
         this.setup = setup;
         this.id = id;
-        this.schemaRegistry = schemaRegistry;
-        this.schemaRepository = schemaRepository;
+        this.schemaRegistry = setup.getSchemaResourcesDTO().getSchemaRegistry();
+        this.schemaRepository = setup.getSchemaResourcesDTO().getSchemaRepository();
         this.actorResponseWaitTime = actorResponseWaitTime;
     }
 
index 3d74d07d308efbf27b47c4731d4ef40842041829..8b2ccf66afb6719d21c7b0f56b8de1c0d99f13fa 100644 (file)
@@ -108,8 +108,7 @@ class NetconfTopologyContext implements ClusterSingletonService {
 
     private NetconfNodeManager createNodeDeviceManager() {
         final NetconfNodeManager ndm =
-                new NetconfNodeManager(netconfTopologyDeviceSetup, remoteDeviceId, DEFAULT_SCHEMA_REPOSITORY,
-                        DEFAULT_SCHEMA_REPOSITORY, actorResponseWaitTime);
+                new NetconfNodeManager(netconfTopologyDeviceSetup, remoteDeviceId, actorResponseWaitTime);
         ndm.registerDataTreeChangeListener(netconfTopologyDeviceSetup.getTopologyId(),
                 netconfTopologyDeviceSetup.getNode().getKey());
 
index 23a46aaa5a7a22e1bd710656ae28c2655b03d65a..b932cd4f44a73bfe8468f43f012b926b816351aa 100644 (file)
@@ -35,6 +35,7 @@ import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvid
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.netconf.client.NetconfClientDispatcher;
+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;
@@ -242,7 +243,8 @@ public class NetconfTopologyManager
                 .setKeepaliveExecutor(keepaliveExecutor)
                 .setProcessingExecutor(processingExecutor)
                 .setTopologyId(topologyId)
-                .setNetconfClientDispatcher(clientDispatcher);
+                .setNetconfClientDispatcher(clientDispatcher)
+                .setSchemaResourceDTO(NetconfTopologyUtils.setupSchemaCacheDTO(node));
 
         return builder.build();
     }
index 5a0d45c4f747bfa2c79c977639a447c850cfb7d8..9a9ad5e3572a9aca70c1a08c70b7cb0722c50a8e 100644 (file)
@@ -12,18 +12,15 @@ import akka.actor.ActorRef;
 import akka.util.Timeout;
 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 io.netty.util.concurrent.EventExecutor;
-import java.io.File;
 import java.math.BigDecimal;
 import java.net.InetSocketAddress;
 import java.net.URL;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -40,7 +37,6 @@ import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
 import org.opendaylight.netconf.sal.connect.netconf.LibraryModulesSchemas;
 import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
 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.listener.NetconfDeviceCapabilities;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
@@ -62,17 +58,10 @@ 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.connection.status.available.capabilities.AvailableCapability.CapabilityOrigin;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.Credentials;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
 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.parser.repo.SharedSchemaRepository;
-import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -80,36 +69,13 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
 
     private static final Logger LOG = LoggerFactory.getLogger(RemoteDeviceConnectorImpl.class);
 
-    /**
-     * 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>schemaResourcesDTOs</code> should be surrounded by appropriate
-     * synchronization locks.
-     */
-    private static final Map<String, NetconfDevice.SchemaResourcesDTO> schemaResourcesDTOs = new HashMap<>();
     private final Timeout actorResponseWaitTime;
 
     // Initializes default constant instances for the case when the default schema repository
     // directory cache/schema is used.
-    static {
-        schemaResourcesDTOs.put(NetconfTopologyUtils.DEFAULT_CACHE_DIRECTORY,
-                new NetconfDevice.SchemaResourcesDTO(NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY,
-                        NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY,
-                        NetconfTopologyUtils.DEFAULT_SCHEMA_CONTEXT_FACTORY,
-                        new NetconfStateSchemasResolverImpl()));
-        NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(NetconfTopologyUtils.DEFAULT_CACHE);
-        NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(
-                TextToASTTransformer.create(NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY,
-                        NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY));
-    }
 
     private final NetconfTopologySetup netconfTopologyDeviceSetup;
     private final RemoteDeviceId remoteDeviceId;
-    private SchemaSourceRegistry schemaRegistry = NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY;
-    private final SchemaRepository schemaRepository = NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY;
-    private SchemaContextFactory schemaContextFactory = NetconfTopologyUtils.DEFAULT_SCHEMA_CONTEXT_FACTORY;
     private NetconfConnectorDTO deviceCommunicatorDTO;
 
     public RemoteDeviceConnectorImpl(final NetconfTopologySetup netconfTopologyDeviceSetup,
@@ -181,6 +147,9 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
                     defaultRequestTimeoutMillis);
         }
 
+        final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = netconfTopologyDeviceSetup.getSchemaResourcesDTO();
+
+
         // pre register yang library sources as fallback schemas to schema registry
         final List<SchemaSourceRegistration<YangTextSchemaSource>> registeredYangLibSources = Lists.newArrayList();
         if (node.getYangLibrary() != null) {
@@ -199,7 +168,7 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
                 for (final Map.Entry<SourceIdentifier, URL> sourceIdentifierURLEntry :
                         libraryModulesSchemas.getAvailableModels().entrySet()) {
                     registeredYangLibSources
-                            .add(schemaRegistry.registerSchemaSource(
+                            .add(schemaResourcesDTO.getSchemaRegistry().registerSchemaSource(
                                     new YangLibrarySchemaYangSourceProvider(remoteDeviceId,
                                             libraryModulesSchemas.getAvailableModels()),
                                     PotentialSchemaSource
@@ -209,7 +178,6 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
             }
         }
 
-        final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = setupSchemaCacheDTO(nodeId, node);
         final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> device;
         if (node.isSchemaless()) {
             device = new SchemalessNetconfDevice(remoteDeviceId, salFacade);
@@ -264,82 +232,6 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
         return Optional.of(NetconfSessionPreferences.fromStrings(capabilities, CapabilityOrigin.UserDefined));
     }
 
-    private 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 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(NetconfTopologyUtils.DEFAULT_CACHE_DIRECTORY)) {
-                // Multiple modules may be created at once;  synchronize to avoid issues with data consistency among
-                // threads.
-                synchronized (schemaResourcesDTOs) {
-                    // Look for the cached DTO to reuse SchemaRegistry and SchemaContextFactory variables if
-                    // they already exist
-                    schemaResourcesDTO = schemaResourcesDTOs.get(moduleSchemaCacheDirectory);
-                    if (schemaResourcesDTO == null) {
-                        schemaResourcesDTO = createSchemaResourcesDTO(moduleSchemaCacheDirectory);
-                        schemaResourcesDTO.getSchemaRegistry().registerSchemaSourceListener(
-                                TextToASTTransformer.create((SchemaRepository) schemaResourcesDTO.getSchemaRegistry(),
-                                        schemaResourcesDTO.getSchemaRegistry())
-                        );
-                        schemaResourcesDTOs.put(moduleSchemaCacheDirectory, schemaResourcesDTO);
-                    }
-                }
-                LOG.info("{} : netconf connector will use schema cache directory {} instead of {}",
-                        remoteDeviceId, moduleSchemaCacheDirectory, NetconfTopologyUtils.DEFAULT_CACHE_DIRECTORY);
-            }
-        } else {
-            LOG.info("{} : using the default directory {}",
-                    remoteDeviceId, NetconfTopologyUtils.QUALIFIED_DEFAULT_CACHE_DIRECTORY);
-        }
-
-        if (schemaResourcesDTO == null) {
-            schemaResourcesDTO =
-                    new NetconfDevice.SchemaResourcesDTO(schemaRegistry, schemaRepository, schemaContextFactory,
-                            new NetconfStateSchemasResolverImpl());
-        }
-
-        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 NetconfDevice.SchemaResourcesDTO createSchemaResourcesDTO(final String moduleSchemaCacheDirectory) {
-        final SharedSchemaRepository repository = new SharedSchemaRepository(moduleSchemaCacheDirectory);
-        final SchemaContextFactory schemaContextFactory
-                = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
-        this.schemaRegistry = repository;
-        this.schemaContextFactory = schemaContextFactory;
-
-        final FilesystemSchemaSourceCache<YangTextSchemaSource> deviceCache =
-                createDeviceFilesystemCache(moduleSchemaCacheDirectory);
-        repository.registerSchemaSourceListener(deviceCache);
-        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 FilesystemSchemaSourceCache<YangTextSchemaSource> createDeviceFilesystemCache(
-            final String schemaCacheDirectory) {
-        final String relativeSchemaCacheDirectory =
-                NetconfTopologyUtils.CACHE_DIRECTORY + File.separator + schemaCacheDirectory;
-        return new FilesystemSchemaSourceCache<>(schemaRegistry, YangTextSchemaSource.class,
-                new File(relativeSchemaCacheDirectory));
-    }
-
     //TODO: duplicate code
     private InetSocketAddress getSocketAddress(final Host host, final int port) {
         if (host.getDomainName() != null) {
@@ -396,11 +288,6 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
                 .build();
     }
 
-    @VisibleForTesting
-    Map<String, NetconfDevice.SchemaResourcesDTO> getSchemaResourcesDTOs() {
-        return schemaResourcesDTOs;
-    }
-
     private static final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory {
         private final Long connectionAttempts;
         private final EventExecutor executor;
index d607f33d2bc4d87eda5ede5148f262dcbf6b77a4..9ee287d97dfa092a6306c88e2ad8be7502d69e04 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.controller.sal.core.api.Broker;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
 import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
@@ -36,6 +37,8 @@ public class NetconfTopologySetup {
     private final EventExecutor eventExecutor;
     private final NetconfClientDispatcher netconfClientDispatcher;
     private final String topologyId;
+    private final NetconfDevice.SchemaResourcesDTO schemaResourceDTO;
+
     private NetconfTopologySetup(final NetconfTopologySetupBuilder builder) {
         this.clusterSingletonServiceProvider = builder.getClusterSingletonServiceProvider();
         this.rpcProviderRegistry = builder.getRpcProviderRegistry();
@@ -50,6 +53,7 @@ public class NetconfTopologySetup {
         this.eventExecutor = builder.getEventExecutor();
         this.netconfClientDispatcher = builder.getNetconfClientDispatcher();
         this.topologyId = builder.getTopologyId();
+        this.schemaResourceDTO = builder.getSchemaResourceDTO();
     }
 
     public ClusterSingletonServiceProvider getClusterSingletonServiceProvider() {
@@ -104,6 +108,10 @@ public class NetconfTopologySetup {
         return netconfClientDispatcher;
     }
 
+    public NetconfDevice.SchemaResourcesDTO getSchemaResourcesDTO() {
+        return  schemaResourceDTO;
+    }
+
     public static class NetconfTopologySetupBuilder {
 
         private ClusterSingletonServiceProvider clusterSingletonServiceProvider;
@@ -119,6 +127,7 @@ public class NetconfTopologySetup {
         private EventExecutor eventExecutor;
         private String topologyId;
         private NetconfClientDispatcher netconfClientDispatcher;
+        private NetconfDevice.SchemaResourcesDTO schemaResourceDTO;
 
         public NetconfTopologySetupBuilder(){
         }
@@ -245,6 +254,16 @@ public class NetconfTopologySetup {
             return this;
         }
 
+        public NetconfTopologySetupBuilder setSchemaResourceDTO(
+                final NetconfDevice.SchemaResourcesDTO schemaResourceDTO) {
+            this.schemaResourceDTO = schemaResourceDTO;
+            return this;
+        }
+
+        private NetconfDevice.SchemaResourcesDTO getSchemaResourceDTO() {
+            return schemaResourceDTO;
+        }
+
         public static NetconfTopologySetupBuilder create() {
             return new NetconfTopologySetupBuilder();
         }
index 0968ddbebd4ec86b57c072341afcb9ca072ca099..1b59e883989c8b6d3c21e2c3529e194b9741bbe1 100644 (file)
@@ -8,9 +8,14 @@
 
 package org.opendaylight.netconf.topology.singleton.impl.utils;
 
+import com.google.common.base.Strings;
 import java.io.File;
 import java.math.BigDecimal;
 import java.net.InetSocketAddress;
+import java.util.HashMap;
+import java.util.Map;
+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;
@@ -25,12 +30,18 @@ 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.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
 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.parser.repo.SharedSchemaRepository;
+import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class NetconfTopologyUtils {
+    private static Logger LOG = LoggerFactory.getLogger(NetconfTopologyUtils.class);
 
     private static final String DEFAULT_SCHEMA_REPOSITORY_NAME = "sal-netconf-connector";
 
@@ -69,6 +80,104 @@ public class NetconfTopologyUtils {
     public static final SchemaContextFactory DEFAULT_SCHEMA_CONTEXT_FACTORY =
             DEFAULT_SCHEMA_REPOSITORY.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
 
+    /**
+     * 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>schemaResourcesDTOs</code> should be surrounded by appropriate
+     * synchronization locks.
+     */
+    private static final Map<String, NetconfDevice.SchemaResourcesDTO> schemaResourcesDTOs = new HashMap<>();
+
+    // Initializes default constant instances for the case when the default schema repository
+    // directory cache/schema is used.
+    static {
+        schemaResourcesDTOs.put(DEFAULT_CACHE_DIRECTORY,
+                new NetconfDevice.SchemaResourcesDTO(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY,
+                        DEFAULT_SCHEMA_CONTEXT_FACTORY, new NetconfStateSchemasResolverImpl()));
+        DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(DEFAULT_CACHE);
+        DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(
+                TextToASTTransformer.create(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY));
+    }
+
+    public static NetconfDevice.SchemaResourcesDTO setupSchemaCacheDTO(final Node node) {
+        final NetconfNode netconfNode = node.getAugmentation(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 (schemaResourcesDTOs) {
+                    // Look for the cached DTO to reuse SchemaRegistry and SchemaContextFactory variables if
+                    // they already exist
+                    schemaResourcesDTO = schemaResourcesDTOs.get(moduleSchemaCacheDirectory);
+                    if (schemaResourcesDTO == null) {
+                        schemaResourcesDTO = createSchemaResourcesDTO(moduleSchemaCacheDirectory);
+                        schemaResourcesDTO.getSchemaRegistry().registerSchemaSourceListener(
+                                TextToASTTransformer.create((SchemaRepository) schemaResourcesDTO.getSchemaRegistry(),
+                                        schemaResourcesDTO.getSchemaRegistry())
+                        );
+                        schemaResourcesDTOs.put(moduleSchemaCacheDirectory, schemaResourcesDTO);
+                    }
+                }
+                LOG.info("{} : netconf connector will use schema cache directory {} instead of {}",
+                        deviceId, moduleSchemaCacheDirectory, DEFAULT_CACHE_DIRECTORY);
+            }
+        }
+
+        if (schemaResourcesDTO == null) {
+            synchronized (schemaResourcesDTOs) {
+                schemaResourcesDTO = schemaResourcesDTOs.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 SchemaContextFactory schemaContextFactory
+                = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+
+        final FilesystemSchemaSourceCache<YangTextSchemaSource> deviceCache =
+                createDeviceFilesystemCache(moduleSchemaCacheDirectory, repository);
+        repository.registerSchemaSourceListener(deviceCache);
+        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 c1036e70f719112906fd54494b37a3354b51dd64..fbdde9466d0778239a8fc825cd0b5f42a08b5aaa 100644 (file)
@@ -45,6 +45,7 @@ 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;
@@ -116,7 +117,6 @@ public class RemoteDeviceConnectorImplTest {
         builder.setEventExecutor(eventExecutor);
         builder.setNetconfClientDispatcher(clientDispatcher);
         builder.setTopologyId(TOPOLOGY_ID);
-
     }
 
     @Test
@@ -171,6 +171,8 @@ public class RemoteDeviceConnectorImplTest {
                 .setCredentials(credentials)
                 .build();
 
+        final Node node = new NodeBuilder().setNodeId(NODE_ID).addAugmentation(NetconfNode.class, netconfNode).build();
+        builder.setSchemaResourceDTO(NetconfTopologyUtils.setupSchemaCacheDTO(node));
         final RemoteDeviceConnectorImpl remoteDeviceConnection =
                 new RemoteDeviceConnectorImpl(builder.build(), remoteDeviceId, TIMEOUT);
 
@@ -202,6 +204,8 @@ public class RemoteDeviceConnectorImplTest {
 
         final RemoteDeviceId remoteDeviceId = new RemoteDeviceId(TOPOLOGY_ID,
                 new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 9999));
+        final Node node = new NodeBuilder().setNodeId(NODE_ID).addAugmentation(NetconfNode.class, netconfNode).build();
+        builder.setSchemaResourceDTO(NetconfTopologyUtils.setupSchemaCacheDTO(node));
 
         final RemoteDeviceConnectorImpl remoteDeviceConnection =
                 new RemoteDeviceConnectorImpl(builder.build(), remoteDeviceId, TIMEOUT);
@@ -242,33 +246,4 @@ public class RemoteDeviceConnectorImplTest {
         assertEquals(defaultClientConfig.getAuthHandler().getUsername(), "testuser");
         assertEquals(defaultClientConfig.getProtocol(), NetconfClientConfiguration.NetconfClientProtocol.TCP);
     }
-
-    @Test
-    public void testSchemaResourceDTO() throws UnknownHostException {
-        final ExecutorService executorService = mock(ExecutorService.class);
-        doReturn(executorService).when(processingExecutor).getExecutor();
-
-        final Credentials credentials = new LoginPasswordBuilder().setPassword("admin").setUsername("admin").build();
-        final NetconfNode netconfNode = new NetconfNodeBuilder()
-                .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
-                .setPort(new PortNumber(9999))
-                .setReconnectOnChangedSchema(true)
-                .setDefaultRequestTimeoutMillis(1000L)
-                .setBetweenAttemptsTimeoutMillis(100)
-                .setSchemaless(false)
-                .setTcpOnly(false)
-                .setCredentials(credentials)
-                .setSchemaCacheDirectory("schemas-test")
-                .build();
-
-        final RemoteDeviceConnectorImpl remoteDeviceConnection =
-                new RemoteDeviceConnectorImpl(builder.build(), remoteDeviceId, TIMEOUT);
-
-        final ActorRef masterRef = mock(ActorRef.class);
-
-        remoteDeviceConnection.createDeviceCommunicator(NODE_ID, netconfNode, masterRef);
-
-        assertTrue(remoteDeviceConnection.getSchemaResourcesDTOs().containsKey("schemas-test"));
-    }
-
 }