package org.opendaylight.netconf.topology.singleton.impl.utils;
-import akka.cluster.Member;
-import akka.util.Timeout;
+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.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;
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.model.repo.util.InMemorySchemaSourceCache;
import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
-import scala.concurrent.duration.Duration;
+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 class NetconfTopologyUtils {
+public final class NetconfTopologyUtils {
+ private static Logger LOG = LoggerFactory.getLogger(NetconfTopologyUtils.class);
private static final String DEFAULT_SCHEMA_REPOSITORY_NAME = "sal-netconf-connector";
- public static final Timeout TIMEOUT = new Timeout(Duration.create(10, "seconds"));
-
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;
new FilesystemSchemaSourceCache<>(DEFAULT_SCHEMA_REPOSITORY, YangTextSchemaSource.class,
new File(QUALIFIED_DEFAULT_CACHE_DIRECTORY));
+ 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 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>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_CACHE);
+ DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(DEFAULT_AST_CACHE);
+ DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(
+ TextToASTTransformer.create(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY));
+ }
+
+ 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 SchemaContextFactory schemaContextFactory
+ = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+
+ 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) {
- IpAddress ipAddress = node.getHost().getIpAddress();
- InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null
+ final IpAddress ipAddress = node.getHost().getIpAddress();
+ final InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null
? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(),
node.getPort().getValue());
return new RemoteDeviceId(nodeId.getValue(), address);
}
- public static String createActorPath(String masterMember, String name) {
+ public static String createActorPath(final String masterMember, final String name) {
return masterMember + "/user/" + name;
}
- public static String createMasterActorName(String name, String masterAddress) {
+ public static String createMasterActorName(final String name, final String masterAddress) {
return masterAddress.replaceAll("//", "") + "_" + name;
}
public static InstanceIdentifier<Node> createTopologyNodePath(final String topologyId) {
return createTopologyListPath(topologyId).child(Node.class);
}
+
+ public static DocumentedException createMasterIsDownException(final RemoteDeviceId id, final Exception cause) {
+ return new DocumentedException(id + ":Master is down. Please try again.", cause,
+ DocumentedException.ErrorType.APPLICATION, DocumentedException.ErrorTag.OPERATION_FAILED,
+ DocumentedException.ErrorSeverity.WARNING);
+ }
}