From: Jakub Morvay Date: Wed, 29 Mar 2017 08:22:16 +0000 (+0200) Subject: Bug 8086 - Cannot mount honeycomb in clustered odl on CentOS X-Git-Tag: release/carbon~30^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F17%2F54017%2F2;p=netconf.git Bug 8086 - Cannot mount honeycomb in clustered odl on CentOS Change-Id: I596cc8b7e0ed04b224bad6b7fa98555c8ef172e2 Signed-off-by: Jakub Morvay --- diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfNodeManager.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfNodeManager.java index 9e60db57a2..6ec40e5747 100644 --- a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfNodeManager.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfNodeManager.java @@ -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; } diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyContext.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyContext.java index 3d74d07d30..8b2ccf66af 100644 --- a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyContext.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyContext.java @@ -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()); diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java index 23a46aaa5a..b932cd4f44 100644 --- a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java @@ -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(); } diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java index 5a0d45c4f7..9a9ad5e357 100644 --- a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java @@ -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 SchemaResourcesDTO. The - * SchemaResourcesDTO is essentially a container that allows for the extraction of the - * SchemaRegistry and SchemaContextFactory which should be used for a particular - * Netconf mount. Access to schemaResourcesDTOs should be surrounded by appropriate - * synchronization locks. - */ - private static final Map 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> registeredYangLibSources = Lists.newArrayList(); if (node.getYangLibrary() != null) { @@ -199,7 +168,7 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector { for (final Map.Entry 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 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 deviceCache = - createDeviceFilesystemCache(moduleSchemaCacheDirectory); - repository.registerSchemaSourceListener(deviceCache); - return new NetconfDevice.SchemaResourcesDTO(repository, repository, schemaContextFactory, - new NetconfStateSchemasResolverImpl()); - } - - /** - * Creates a FilesystemSchemaSourceCache for the custom schema cache directory. - * - * @param schemaCacheDirectory The custom cache directory relative to "cache" - * @return A FilesystemSchemaSourceCache for the custom schema cache directory - */ - private FilesystemSchemaSourceCache 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 getSchemaResourcesDTOs() { - return schemaResourcesDTOs; - } - private static final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory { private final Long connectionAttempts; private final EventExecutor executor; diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java index d607f33d2b..9ee287d97d 100644 --- a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java @@ -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(); } diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtils.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtils.java index 0968ddbebd..1b59e88398 100644 --- a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtils.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtils.java @@ -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 SchemaResourcesDTO. The + * SchemaResourcesDTO is essentially a container that allows for the extraction of the + * SchemaRegistry and SchemaContextFactory which should be used for a particular + * Netconf mount. Access to schemaResourcesDTOs should be surrounded by appropriate + * synchronization locks. + */ + private static final Map 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 deviceCache = + createDeviceFilesystemCache(moduleSchemaCacheDirectory, repository); + repository.registerSchemaSourceListener(deviceCache); + return new NetconfDevice.SchemaResourcesDTO(repository, repository, schemaContextFactory, + new NetconfStateSchemasResolverImpl()); + } + + /** + * Creates a FilesystemSchemaSourceCache for the custom schema cache directory. + * + * @param schemaCacheDirectory The custom cache directory relative to "cache" + * @return A FilesystemSchemaSourceCache for the custom schema cache directory + */ + private static FilesystemSchemaSourceCache 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 diff --git a/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImplTest.java b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImplTest.java index c1036e70f7..fbdde9466d 100644 --- a/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImplTest.java +++ b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImplTest.java @@ -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")); - } - }