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.NetconfStateSchemas;
+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;
schemaResourcesDTOs.put(DEFAULT_CACHE_DIRECTORY,
new NetconfDevice.SchemaResourcesDTO(DEFAULT_SCHEMA_REPOSITORY,
DEFAULT_SCHEMA_CONTEXT_FACTORY,
- new NetconfStateSchemas.NetconfStateSchemasResolverImpl()));
+ new NetconfStateSchemasResolverImpl()));
DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(DEFAULT_CACHE);
DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(
TextToASTTransformer.create(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY));
if (schemaResourcesDTO == null) {
schemaResourcesDTO = new NetconfDevice.SchemaResourcesDTO(schemaRegistry, schemaContextFactory,
- new NetconfStateSchemas.NetconfStateSchemasResolverImpl());
+ new NetconfStateSchemasResolverImpl());
}
return schemaResourcesDTO;
createDeviceFilesystemCache(moduleSchemaCacheDirectory);
repository.registerSchemaSourceListener(deviceCache);
return new NetconfDevice.SchemaResourcesDTO(repository, schemaContextFactory,
- new NetconfStateSchemas.NetconfStateSchemasResolverImpl());
+ new NetconfStateSchemasResolverImpl());
}
/**
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.NetconfStateSchemas;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfStateSchemasResolverImpl;
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.listener.UserPreferences;
schemaResourcesDTOs.put(DEFAULT_CACHE_DIRECTORY,
new NetconfDevice.SchemaResourcesDTO(DEFAULT_SCHEMA_REPOSITORY,
DEFAULT_SCHEMA_CONTEXT_FACTORY,
- new NetconfStateSchemas.NetconfStateSchemasResolverImpl()));
+ new NetconfStateSchemasResolverImpl()));
DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(DEFAULT_CACHE);
DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(
TextToASTTransformer.create(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY));
if (schemaResourcesDTO == null) {
schemaResourcesDTO = new NetconfDevice.SchemaResourcesDTO(schemaRegistry, schemaContextFactory,
- new NetconfStateSchemas.NetconfStateSchemasResolverImpl());
+ new NetconfStateSchemasResolverImpl());
}
final NetconfDevice device = new NetconfDeviceBuilder()
createDeviceFilesystemCache(moduleSchemaCacheDirectory);
repository.registerSchemaSourceListener(deviceCache);
return new NetconfDevice.SchemaResourcesDTO(repository, schemaContextFactory,
- new NetconfStateSchemas.NetconfStateSchemasResolverImpl());
+ new NetconfStateSchemasResolverImpl());
}
/**
--- /dev/null
+/*
+ * Copyright (c) 2016 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.sal.connect.api;
+
+import java.util.Set;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfStateSchemas;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
+
+public interface NetconfDeviceSchemas {
+
+ Set<QName> getAvailableYangSchemasQNames();
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.sal.connect.api;
+
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+
+/**
+ * Factory for netconf device schemas
+ */
+public interface NetconfDeviceSchemasResolver {
+ NetconfDeviceSchemas resolve(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id);
+}
package org.opendaylight.netconf.sal.connect.netconf;
import static javax.xml.bind.DatatypeConverter.printBase64Binary;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DATA_QNAME;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_QNAME;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toId;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
import com.google.gson.stream.JsonReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
+import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemas;
+import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc;
+import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160409.ModulesState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160409.module.list.Module;
import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
* Holds URLs with YANG schema resources for all yang modules reported in
* ietf-netconf-yang-library/modules-state/modules node
*/
-public class LibraryModulesSchemas {
+public class LibraryModulesSchemas implements NetconfDeviceSchemas {
private static final Logger LOG = LoggerFactory.getLogger(LibraryModulesSchemas.class);
- private static SchemaContext libraryContext;
-
- private final Map<SourceIdentifier, URL> availableModels;
+ private static final SchemaContext LIBRARY_CONTEXT;
static {
final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
moduleInfoBackedContext.registerModuleInfo(
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160409.
$YangModuleInfoImpl.getInstance());
- libraryContext = moduleInfoBackedContext.tryToCreateSchemaContext().get();
+ LIBRARY_CONTEXT = moduleInfoBackedContext.tryToCreateSchemaContext().get();
+ }
+
+ private final Map<QName, URL> availableModels;
+
+ private static final YangInstanceIdentifier MODULES_STATE_MODULE_LIST =
+ YangInstanceIdentifier.builder().node(ModulesState.QNAME).node(Module.QNAME).build();
+
+ private static final ContainerNode GET_MODULES_STATE_MODULE_LIST_RPC;
+
+ static {
+ final DataContainerChild<?, ?> filter =
+ NetconfMessageTransformUtil.toFilterStructure(MODULES_STATE_MODULE_LIST, LIBRARY_CONTEXT);
+ GET_MODULES_STATE_MODULE_LIST_RPC =
+ Builders.containerBuilder().withNodeIdentifier(toId(NETCONF_GET_QNAME)).withChild(filter).build();
}
- private LibraryModulesSchemas(final Map<SourceIdentifier, URL> availableModels) {
+ private LibraryModulesSchemas(final Map<QName, URL> availableModels) {
this.availableModels = availableModels;
}
public Map<SourceIdentifier, URL> getAvailableModels() {
- return availableModels;
+ final Map<SourceIdentifier, URL> result = Maps.newHashMap();
+ for (final Map.Entry<QName, URL> entry : availableModels.entrySet()) {
+ final SourceIdentifier sId = RevisionSourceIdentifier
+ .create(entry.getKey().getLocalName(), Optional.fromNullable(entry.getKey().getFormattedRevision()));
+ result.put(sId, entry.getValue());
+ }
+
+ return result;
}
if(connection instanceof HttpURLConnection) {
connection.setRequestProperty("Accept", "application/xml");
- String userpass = username + ":" + password;
- String basicAuth = "Basic " + printBase64Binary(userpass.getBytes());
+ final String userpass = username + ":" + password;
+ final String basicAuth = "Basic " + printBase64Binary(userpass.getBytes());
connection.setRequestProperty("Authorization", basicAuth);
}
return createFromURLConnection(connection);
- } catch (IOException e) {
+ } catch (final IOException e) {
LOG.warn("Unable to download yang library from {}", url, e);
- return new LibraryModulesSchemas(Collections.<SourceIdentifier, URL>emptyMap());
+ return new LibraryModulesSchemas(Collections.<QName, URL>emptyMap());
}
}
- private static LibraryModulesSchemas createFromURLConnection(URLConnection connection) {
+ public static LibraryModulesSchemas create(final NetconfDeviceRpc deviceRpc, final RemoteDeviceId deviceId) {
+ final DOMRpcResult moduleListNodeResult;
+ try {
+ moduleListNodeResult =
+ deviceRpc.invokeRpc(toPath(NETCONF_GET_QNAME), GET_MODULES_STATE_MODULE_LIST_RPC).get();
+ } catch (final InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new RuntimeException(deviceId + ": Interrupted while waiting for response to "
+ + MODULES_STATE_MODULE_LIST, e);
+ } catch (final ExecutionException e) {
+ LOG.warn("{}: Unable to detect available schemas, get to {} failed", deviceId, MODULES_STATE_MODULE_LIST, e);
+ return new LibraryModulesSchemas(Collections.<QName, URL>emptyMap());
+ }
+
+ if(moduleListNodeResult.getErrors().isEmpty() == false) {
+ LOG.warn("{}: Unable to detect available schemas, get to {} failed, {}",
+ deviceId, MODULES_STATE_MODULE_LIST, moduleListNodeResult.getErrors());
+ return new LibraryModulesSchemas(Collections.<QName, URL>emptyMap());
+ }
+
+
+ final Optional<? extends NormalizedNode<?, ?>> modulesStateNode =
+ findModulesStateNode(moduleListNodeResult.getResult());
+ if(modulesStateNode.isPresent()) {
+ Preconditions.checkState(modulesStateNode.get() instanceof ContainerNode,
+ "Expecting container containing schemas, but was %s", modulesStateNode.get());
+ return create(((ContainerNode) modulesStateNode.get()));
+ } else {
+ LOG.warn("{}: Unable to detect available schemas, get to {} was empty", deviceId, toId(ModulesState.QNAME));
+ return new LibraryModulesSchemas(Collections.<QName, URL>emptyMap());
+ }
+ }
+
+ private static Optional<? extends NormalizedNode<?, ?>> findModulesStateNode(final NormalizedNode<?, ?> result) {
+ if(result == null) {
+ return Optional.absent();
+ }
+ final Optional<DataContainerChild<?, ?>> dataNode = ((DataContainerNode<?>) result).getChild(toId(NETCONF_DATA_QNAME));
+ if(dataNode.isPresent() == false) {
+ return Optional.absent();
+ }
+
+ return ((DataContainerNode<?>) dataNode.get()).getChild(toId(ModulesState.QNAME));
+ }
+
+ private static LibraryModulesSchemas create(final ContainerNode modulesStateNode) {
+ final YangInstanceIdentifier.NodeIdentifier moduleListNodeId =
+ new YangInstanceIdentifier.NodeIdentifier(Module.QNAME);
+ final Optional<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>> moduleListNode =
+ modulesStateNode.getChild(moduleListNodeId);
+ Preconditions.checkState(moduleListNode.isPresent(),
+ "Unable to find list: %s in %s", moduleListNodeId, modulesStateNode);
+ Preconditions.checkState(moduleListNode.get() instanceof MapNode,
+ "Unexpected structure for container: %s in : %s. Expecting a list",
+ moduleListNodeId, modulesStateNode);
+
+ final ImmutableMap.Builder<QName, URL> schemasMapping = new ImmutableMap.Builder<>();
+ for (final MapEntryNode moduleNode : ((MapNode) moduleListNode.get()).getValue()) {
+ final Optional<Map.Entry<QName, URL>> schemaMappingEntry = createFromEntry(moduleNode);
+ if (schemaMappingEntry.isPresent()) {
+ schemasMapping.put(createFromEntry(moduleNode).get());
+ }
+ }
+
+ return new LibraryModulesSchemas(schemasMapping.build());
+ }
+
+ private static LibraryModulesSchemas createFromURLConnection(final URLConnection connection) {
String contentType = connection.getContentType();
contentType.equals("application/json") ? readJson(in) : readXml(in);
if (!optionalModulesStateNode.isPresent()) {
- return new LibraryModulesSchemas(Collections.<SourceIdentifier, URL>emptyMap());
+ return new LibraryModulesSchemas(Collections.<QName, URL>emptyMap());
}
final NormalizedNode<?, ?> modulesStateNode = optionalModulesStateNode.get();
"Unexpected structure for container: %s in : %s. Expecting a list",
moduleListNodeId, modulesStateNode);
- final ImmutableMap.Builder<SourceIdentifier, URL> schemasMapping = new ImmutableMap.Builder<>();
+ final ImmutableMap.Builder<QName, URL> schemasMapping = new ImmutableMap.Builder<>();
for (final MapEntryNode moduleNode : ((MapNode) moduleListNode.get()).getValue()) {
- final Optional<Map.Entry<SourceIdentifier, URL>> schemaMappingEntry = createFromEntry(moduleNode);
+ final Optional<Map.Entry<QName, URL>> schemaMappingEntry = createFromEntry(moduleNode);
if (schemaMappingEntry.isPresent()) {
schemasMapping.put(createFromEntry(moduleNode).get());
}
}
return new LibraryModulesSchemas(schemasMapping.build());
- } catch (IOException e) {
+ } catch (final IOException e) {
LOG.warn("Unable to download yang library from {}", connection.getURL(), e);
- return new LibraryModulesSchemas(Collections.<SourceIdentifier, URL>emptyMap());
+ return new LibraryModulesSchemas(Collections.<QName, URL>emptyMap());
}
}
return createFromURLConnection(connection);
- } catch (IOException e) {
+ } catch (final IOException e) {
LOG.warn("Unable to download yang library from {}", url, e);
- return new LibraryModulesSchemas(Collections.<SourceIdentifier, URL>emptyMap());
+ return new LibraryModulesSchemas(Collections.<QName, URL>emptyMap());
}
}
final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
- final JsonParserStream jsonParser = JsonParserStream.create(writer, libraryContext);
+ final JsonParserStream jsonParser = JsonParserStream.create(writer, LIBRARY_CONTEXT);
final JsonReader reader = new JsonReader(new InputStreamReader(in));
jsonParser.parse(reader);
private static Optional<NormalizedNode<?, ?>> readXml(final InputStream in) {
final DomToNormalizedNodeParserFactory parserFactory =
- DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, libraryContext);
+ DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, LIBRARY_CONTEXT);
try {
final NormalizedNode<?, ?> parsed =
parserFactory.getContainerNodeParser().parse(Collections.singleton(XmlUtil.readXmlToElement(in)),
- (ContainerSchemaNode) libraryContext.getDataChildByName(ModulesState.QNAME));
+ (ContainerSchemaNode) LIBRARY_CONTEXT.getDataChildByName(ModulesState.QNAME));
return Optional.of(parsed);
} catch (IOException|SAXException e) {
LOG.warn("Unable to parse yang library xml content", e);
return Optional.<NormalizedNode<?, ?>>absent();
}
- private static Optional<Map.Entry<SourceIdentifier, URL>> createFromEntry(final MapEntryNode moduleNode) {
+ private static Optional<Map.Entry<QName, URL>> createFromEntry(final MapEntryNode moduleNode) {
Preconditions.checkArgument(
moduleNode.getNodeType().equals(Module.QNAME), "Wrong QName %s", moduleNode.getNodeType());
if(revision.isPresent()) {
if(!SourceIdentifier.REVISION_PATTERN.matcher(revision.get()).matches()) {
LOG.warn("Skipping library schema for {}. Revision {} is in wrong format.", moduleNode, revision.get());
- return Optional.<Map.Entry<SourceIdentifier, URL>>absent();
+ return Optional.<Map.Entry<QName, URL>>absent();
}
}
childNodeId = new YangInstanceIdentifier.NodeIdentifier(QName.create(Module.QNAME, "schema"));
final Optional<String> schemaUriAsString = getSingleChildNodeValue(moduleNode, childNodeId);
+ childNodeId = new YangInstanceIdentifier.NodeIdentifier(QName.create(Module.QNAME, "namespace"));
+ final String moduleNameSpace = getSingleChildNodeValue(moduleNode, childNodeId).get();
- final SourceIdentifier sourceId = revision.isPresent()
- ? RevisionSourceIdentifier.create(moduleName, revision.get())
- : RevisionSourceIdentifier.create(moduleName);
+ final QName moduleQName = revision.isPresent()
+ ? QName.create(moduleNameSpace, revision.get(), moduleName)
+ : QName.create(URI.create(moduleNameSpace), null, moduleName);
try {
- return Optional.<Map.Entry<SourceIdentifier, URL>>of(new AbstractMap.SimpleImmutableEntry<>(
- sourceId, new URL(schemaUriAsString.get())));
- } catch (MalformedURLException e) {
+ return Optional.<Map.Entry<QName, URL>>of(new AbstractMap.SimpleImmutableEntry<>(
+ moduleQName, new URL(schemaUriAsString.get())));
+ } catch (final MalformedURLException e) {
LOG.warn("Skipping library schema for {}. URL {} representing yang schema resource is not valid",
moduleNode, schemaUriAsString.get());
- return Optional.<Map.Entry<SourceIdentifier, URL>>absent();
+ return Optional.<Map.Entry<QName, URL>>absent();
}
}
? Optional.<String>absent() : Optional.of(value.toString().trim());
}
+ @Override
+ public Set<QName> getAvailableYangSchemasQNames() {
+ return null;
+ }
}
import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
+import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemas;
+import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemasResolver;
import org.opendaylight.netconf.sal.connect.api.RemoteDevice;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceCommunicator;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc;
import org.opendaylight.netconf.sal.connect.netconf.schema.NetconfRemoteSchemaYangSourceProvider;
+import org.opendaylight.netconf.sal.connect.netconf.schema.YangLibrarySchemaYangSourceProvider;
import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseSchema;
import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
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.SchemaSourceProvider;
import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
import org.slf4j.Logger;
private final RemoteDeviceHandler<NetconfSessionPreferences> salFacade;
private final ListeningExecutorService processingExecutor;
protected final SchemaSourceRegistry schemaRegistry;
- private final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver;
+ private final NetconfDeviceSchemasResolver stateSchemasResolver;
private final NotificationHandler notificationHandler;
protected final List<SchemaSourceRegistration<? extends SchemaSourceRepresentation>> sourceRegistrations = Lists.newArrayList();
* Create rpc implementation capable of handling RPC for monitoring and notifications even before the schemas of remote device are downloaded
*/
static NetconfDeviceRpc getRpcForInitialization(final NetconfDeviceCommunicator listener, final boolean notificationSupport) {
- BaseSchema baseSchema = notificationSupport ?
+ final BaseSchema baseSchema = notificationSupport ?
BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS :
BaseSchema.BASE_NETCONF_CTX;
final FutureCallback<DeviceSources> resolvedSourceCallback = new FutureCallback<DeviceSources>() {
@Override
public void onSuccess(final DeviceSources result) {
- addProvidedSourcesToSchemaRegistry(initRpc, result);
+ addProvidedSourcesToSchemaRegistry(result);
setUpSchema(result);
}
}
protected void handleSalInitializationSuccess(final SchemaContext result, final NetconfSessionPreferences remoteSessionCapabilities, final DOMRpcService deviceRpc) {
- BaseSchema baseSchema =
+ final BaseSchema baseSchema =
remoteSessionCapabilities.isNotificationsSupported() ?
BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS :
BaseSchema.BASE_NETCONF_CTX;
messageTransformer = transformer;
}
- private void addProvidedSourcesToSchemaRegistry(final NetconfDeviceRpc deviceRpc, final DeviceSources deviceSources) {
- final NetconfRemoteSchemaYangSourceProvider yangProvider = new NetconfRemoteSchemaYangSourceProvider(id, deviceRpc);
+ private void addProvidedSourcesToSchemaRegistry(final DeviceSources deviceSources) {
+ final SchemaSourceProvider<YangTextSchemaSource> yangProvider = deviceSources.getSourceProvider();
for (final SourceIdentifier sourceId : deviceSources.getProvidedSources()) {
sourceRegistrations.add(schemaRegistry.registerSchemaSource(yangProvider,
PotentialSchemaSource.create(sourceId, YangTextSchemaSource.class, PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
public static class SchemaResourcesDTO {
private final SchemaSourceRegistry schemaRegistry;
private final SchemaContextFactory schemaContextFactory;
- private final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver;
+ private final NetconfDeviceSchemasResolver stateSchemasResolver;
- public SchemaResourcesDTO(final SchemaSourceRegistry schemaRegistry, final SchemaContextFactory schemaContextFactory, final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver) {
+ public SchemaResourcesDTO(final SchemaSourceRegistry schemaRegistry,
+ final SchemaContextFactory schemaContextFactory,
+ final NetconfDeviceSchemasResolver deviceSchemasResolver) {
this.schemaRegistry = Preconditions.checkNotNull(schemaRegistry);
this.schemaContextFactory = Preconditions.checkNotNull(schemaContextFactory);
- this.stateSchemasResolver = Preconditions.checkNotNull(stateSchemasResolver);
+ this.stateSchemasResolver = Preconditions.checkNotNull(deviceSchemasResolver);
}
public SchemaSourceRegistry getSchemaRegistry() {
return schemaContextFactory;
}
- public NetconfStateSchemas.NetconfStateSchemasResolver getStateSchemasResolver() {
+ public NetconfDeviceSchemasResolver getStateSchemasResolver() {
return stateSchemasResolver;
}
}
private final NetconfDeviceRpc deviceRpc;
private final NetconfSessionPreferences remoteSessionCapabilities;
private final RemoteDeviceId id;
- private final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver;
+ private final NetconfDeviceSchemasResolver stateSchemasResolver;
DeviceSourcesResolver(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities,
- final RemoteDeviceId id, final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver) {
+ final RemoteDeviceId id, final NetconfDeviceSchemasResolver stateSchemasResolver) {
this.deviceRpc = deviceRpc;
this.remoteSessionCapabilities = remoteSessionCapabilities;
this.id = id;
this.stateSchemasResolver = stateSchemasResolver;
}
- public DeviceSourcesResolver(final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id, final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver, final NetconfDeviceRpc rpcForMonitoring) {
+ public DeviceSourcesResolver(final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id, final NetconfDeviceSchemasResolver stateSchemasResolver, final NetconfDeviceRpc rpcForMonitoring) {
this(rpcForMonitoring, remoteSessionCapabilities, id, stateSchemasResolver);
}
@Override
public DeviceSources call() throws Exception {
- final NetconfStateSchemas availableSchemas = stateSchemasResolver.resolve(deviceRpc, remoteSessionCapabilities, id);
+ final NetconfDeviceSchemas availableSchemas = stateSchemasResolver.resolve(deviceRpc, remoteSessionCapabilities, id);
LOG.debug("{}: Schemas exposed by ietf-netconf-monitoring: {}", id, availableSchemas.getAvailableYangSchemasQNames());
final Set<QName> requiredSources = Sets.newHashSet(remoteSessionCapabilities.getModuleBasedCaps());
requiredSources.addAll(providedSourcesNotRequired);
}
- return new DeviceSources(requiredSources, providedSources);
+ final SchemaSourceProvider<YangTextSchemaSource> sourceProvider;
+ if(availableSchemas instanceof LibraryModulesSchemas) {
+ sourceProvider = new YangLibrarySchemaYangSourceProvider(id,
+ ((LibraryModulesSchemas) availableSchemas).getAvailableModels());
+ } else {
+ sourceProvider = new NetconfRemoteSchemaYangSourceProvider(id, deviceRpc);
+ }
+
+ return new DeviceSources(requiredSources, providedSources, sourceProvider);
}
}
private static final class DeviceSources {
private final Set<QName> requiredSources;
private final Set<QName> providedSources;
+ private final SchemaSourceProvider<YangTextSchemaSource> sourceProvider;
- public DeviceSources(final Set<QName> requiredSources, final Set<QName> providedSources) {
+ public DeviceSources(final Set<QName> requiredSources, final Set<QName> providedSources,
+ final SchemaSourceProvider<YangTextSchemaSource> sourceProvider) {
this.requiredSources = requiredSources;
this.providedSources = providedSources;
+ this.sourceProvider = sourceProvider;
}
public Set<QName> getRequiredSourcesQName() {
return Collections2.transform(providedSources, QNAME_TO_SOURCE_ID_FUNCTION);
}
+ public SchemaSourceProvider<YangTextSchemaSource> getSourceProvider() {
+ return sourceProvider;
+ }
}
/**
capabilities.addNonModuleBasedCapabilities(remoteSessionCapabilities.getNonModuleCaps());
handleSalInitializationSuccess(result, remoteSessionCapabilities, getDeviceSpecificRpc(result));
return;
- } catch (Throwable t) {
+ } catch (final Throwable t) {
if (t instanceof MissingSchemaSourceException){
requiredSources = handleMissingSchemaSourceException(requiredSources, (MissingSchemaSourceException) t);
} else if (t instanceof SchemaResolutionException) {
salFacade.onDeviceFailed(cause);
}
- private Collection<SourceIdentifier> handleMissingSchemaSourceException(Collection<SourceIdentifier> requiredSources, final MissingSchemaSourceException t) {
+ private Collection<SourceIdentifier> handleMissingSchemaSourceException(final Collection<SourceIdentifier> requiredSources, final MissingSchemaSourceException t) {
// In case source missing, try without it
final SourceIdentifier missingSource = t.getSourceId();
LOG.warn("{}: Unable to build schema context, missing source {}, will reattempt without it", id, missingSource);
return stripMissingSource(requiredSources, missingSource);
}
- private Collection<SourceIdentifier> handleSchemaResolutionException(Collection<SourceIdentifier> requiredSources, final SchemaResolutionException resolutionException) {
+ private Collection<SourceIdentifier> handleSchemaResolutionException(final Collection<SourceIdentifier> requiredSources, final SchemaResolutionException resolutionException) {
// In case resolution error, try only with resolved sources
final Set<SourceIdentifier> unresolvedSources = resolutionException.getUnsatisfiedImports().keySet();
capabilities.addUnresolvedCapabilities(getQNameFromSourceIdentifiers(unresolvedSources), UnavailableCapability.FailureReason.UnableToResolve);
import java.util.Set;
import java.util.concurrent.ExecutionException;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemas;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc;
import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseSchema;
/**
* Holds QNames for all yang modules reported by ietf-netconf-monitoring/state/schemas
*/
-public final class NetconfStateSchemas {
+public final class NetconfStateSchemas implements NetconfDeviceSchemas {
private static final Logger LOG = LoggerFactory.getLogger(NetconfStateSchemas.class);
- /**
- * Factory for NetconfStateSchemas
- */
- public interface NetconfStateSchemasResolver {
- NetconfStateSchemas resolve(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id);
- }
-
- /**
- * Default implementation resolving schemas QNames from netconf-state
- */
- public static final class NetconfStateSchemasResolverImpl implements NetconfStateSchemasResolver {
-
- @Override
- public NetconfStateSchemas resolve(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
- return NetconfStateSchemas.create(deviceRpc, remoteSessionCapabilities, id);
- }
- }
-
public static final NetconfStateSchemas EMPTY = new NetconfStateSchemas(Collections.<RemoteYangSchema>emptySet());
private static final YangInstanceIdentifier STATE_SCHEMAS_IDENTIFIER =
return availableYangSchemas;
}
+ @Override
public Set<QName> getAvailableYangSchemasQNames() {
return Sets.newHashSet(Collections2.transform(getAvailableYangSchemas(), new Function<RemoteYangSchema, QName>() {
@Override
/**
* Issue get request to remote device and parse response to find all schemas under netconf-state/schemas
*/
- private static NetconfStateSchemas create(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
+ static NetconfStateSchemas create(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
if(remoteSessionCapabilities.isMonitoringSupported() == false) {
// TODO - need to search for get-schema support, not just ietf-netconf-monitoring support
// issue might be a deviation to ietf-netconf-monitoring where get-schema is unsupported...
QName childNode = NetconfMessageTransformUtil.IETF_NETCONF_MONITORING_SCHEMA_FORMAT;
- String formatAsString = getSingleChildNodeValue(schemaNode, childNode).get();
+ final String formatAsString = getSingleChildNodeValue(schemaNode, childNode).get();
if(formatAsString.equals(Yang.QNAME.toString()) == false) {
LOG.debug("{}: Ignoring schema due to unsupported format: {}", id, formatAsString);
--- /dev/null
+/*
+ * Copyright (c) 2016 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.sal.connect.netconf;
+
+import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemas;
+import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemasResolver;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160409.ModulesState;
+import org.opendaylight.yangtools.yang.common.QName;
+
+/**
+ * Default implementation resolving schemas QNames from netconf-state or from modules-state
+ */
+public final class NetconfStateSchemasResolverImpl implements NetconfDeviceSchemasResolver {
+
+ @Override
+ public NetconfDeviceSchemas resolve(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
+ if (remoteSessionCapabilities.isMonitoringSupported()) {
+ return NetconfStateSchemas.create(deviceRpc, remoteSessionCapabilities, id);
+ } else if (remoteSessionCapabilities.containsModuleCapability(QName.create(ModulesState.QNAME, "ietf-yang-library"))) {
+ return LibraryModulesSchemas.create(deviceRpc, id);
+ }
+ return NetconfStateSchemas.EMPTY;
+ }
+}
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
+import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemas;
+import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemasResolver;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
RevisionSourceIdentifier.create(TEST_MODULE + "2", Optional.of(TEST_REVISION));
public static final String TEST_CAPABILITY2 = TEST_NAMESPACE + "?module=" + TEST_MODULE + "2" + "&revision=" + TEST_REVISION;
- private static final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver = new NetconfStateSchemas.NetconfStateSchemasResolver() {
+ private static final NetconfDeviceSchemasResolver stateSchemasResolver = new NetconfDeviceSchemasResolver() {
@Override
- public NetconfStateSchemas resolve(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
+ public NetconfDeviceSchemas resolve(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
return NetconfStateSchemas.EMPTY;
}
};
}
}).when(schemaFactory).createSchemaContext(anyCollectionOf(SourceIdentifier.class));
- final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver = new NetconfStateSchemas.NetconfStateSchemasResolver() {
+ final NetconfDeviceSchemasResolver stateSchemasResolver = new NetconfDeviceSchemasResolver() {
@Override
- public NetconfStateSchemas resolve(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
+ public NetconfDeviceSchemas resolve(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
final Module first = Iterables.getFirst(schema.getModules(), null);
final QName qName = QName.create(first.getQNameModule(), first.getName());
final NetconfStateSchemas.RemoteYangSchema source1 = new NetconfStateSchemas.RemoteYangSchema(qName);
<module>
<name>module-with-bad-url</name>
<revision></revision>
+ <namespace>b</namespace>
<schema>
badurl
</schema>
<module>
<name>module-bad-revision</name>
<revision>bad-revision</revision>
+ <namespace>bbb</namespace>
</module>
<module>
<name>good-ol-module</name>
<revision></revision>
<schema>http://www.example.com</schema>
+ <namespace>bbbds</namespace>
</module>
</modules>
\ No newline at end of file
{
"name": "module-with-revision",
"revision": "2014-04-08",
- "schema": "http://localhost:8181/yanglib/schemas/module-with-revision/2014-04-08"
+ "schema": "http://localhost:8181/yanglib/schemas/module-with-revision/2014-04-08",
+ "namespace": "bla"
},
{
"name": "another-module-with-revision",
"revision": "2014-06-08",
+ "namespace": "test",
"schema": "http://localhost:8181/yanglib/schemas/another-module-with-revision/2013-10-21"
},
{
"name": "module-without-revision",
"revision": "",
+ "namespace": "namespace:module-without-revision",
"schema": "http://localhost:8181/yanglib/schemas/module-without-revision/2013-10-21"
}
]
<module>
<name>module-with-revision</name>
<revision>2014-04-08</revision>
+ <namespace>namespace</namespace>
<schema>
http://localhost:8181/yanglib/schemas/module-with-revision/2014-04-08
</schema>
<module>
<name>another-module-with-revision</name>
<revision>2013-10-21</revision>
+ <namespace>another-module-with-revision:namespace</namespace>
<schema>
http://localhost:8181/yanglib/schemas/another-module-with-revision/2013-10-21
</schema>
</module>
<module>
<name>module-without-revision</name>
+ <namespace>module-without-revision:namespace</namespace>
<revision></revision>
<schema>
http://localhost:8181/yanglib/schemas/module-without-revision/
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.NetconfStateSchemas.NetconfStateSchemasResolverImpl;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfStateSchemasResolverImpl;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;