package org.opendaylight.controller.sal.connect.netconf.schema.mapping;
import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_RPC_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_URI;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
static {
try {
final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
- // TODO this should be used only if the base is not present
moduleInfoBackedContext.addModuleInfos(
Lists.newArrayList(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.$YangModuleInfoImpl.getInstance()));
BASE_NETCONF_CTX = moduleInfoBackedContext.tryToCreateSchemaContext().get();
throw new ExceptionInInitializerError(e);
}
}
+ private static final Map<QName, RpcDefinition> MAPPED_BASE_RPCS = Maps.uniqueIndex(BASE_NETCONF_CTX.getOperations(), QNAME_FUNCTION);
private final SchemaContext schemaContext;
private final MessageCounter counter;
public NetconfMessage toRpcRequest(SchemaPath rpc, final ContainerNode payload) {
// In case no input for rpc is defined, we can simply construct the payload here
final QName rpcQName = rpc.getLastComponent();
- Preconditions.checkNotNull(mappedRpcs.get(rpcQName), "Unknown rpc %s, available rpcs: %s", rpcQName, mappedRpcs.keySet());
- if(mappedRpcs.get(rpcQName).getInput() == null) {
+ Map<QName, RpcDefinition> currentMappedRpcs = mappedRpcs;
+
+ // Determine whether a base netconf operation is being invoked and also check if the device exposed model for base netconf
+ // If no, use pre built base netconf operations model
+ final boolean needToUseBaseCtx = mappedRpcs.get(rpcQName) == null && isBaseRpc(rpcQName);
+ if(needToUseBaseCtx) {
+ currentMappedRpcs = MAPPED_BASE_RPCS;
+ }
+
+ Preconditions.checkNotNull(currentMappedRpcs.get(rpcQName), "Unknown rpc %s, available rpcs: %s", rpcQName, currentMappedRpcs.keySet());
+ if(currentMappedRpcs.get(rpcQName).getInput() == null) {
final Document document = XmlUtil.newDocument();
final Element elementNS = document.createElementNS(rpcQName.getNamespace().toString(), rpcQName.getLocalName());
document.appendChild(elementNS);
final DOMResult result = prepareDomResultForRpcRequest(rpcQName);
try {
- writeNormalizedRpc(payload, result, rpc, schemaContext);
+ // If the schema context for netconf device does not contain model for base netconf operations, use default pre build context with just the base model
+ // This way operations like lock/unlock are supported even if the source for base model was not provided
+ writeNormalizedRpc(payload, result, rpc, needToUseBaseCtx ? BASE_NETCONF_CTX : schemaContext);
} catch (final XMLStreamException | IOException | IllegalStateException e) {
throw new IllegalStateException("Unable to serialize " + rpc, e);
}
return new NetconfMessage(node);
}
+ private static boolean isBaseRpc(final QName rpc) {
+ return rpc.getNamespace().equals(NETCONF_URI);
+ }
+
private DOMResult prepareDomResultForRpcRequest(final QName rpcQName) {
final Document document = XmlUtil.newDocument();
final Element rpcNS = document.createElementNS(NETCONF_RPC_QNAME.getNamespace().toString(), NETCONF_RPC_QNAME.getLocalName());
@Override
public synchronized DOMRpcResult toRpcResult(final NetconfMessage message, final SchemaPath rpc) {
final NormalizedNode<?, ?> normalizedNode;
- if (NetconfMessageTransformUtil.isDataRetrievalOperation(rpc.getLastComponent())) {
+ final QName rpcQName = rpc.getLastComponent();
+ if (NetconfMessageTransformUtil.isDataRetrievalOperation(rpcQName)) {
final Element xmlData = NetconfMessageTransformUtil.getDataSubtree(message.getDocument());
final ContainerSchemaNode schemaForDataRead = NetconfMessageTransformUtil.createSchemaForDataRead(schemaContext);
final ContainerNode dataNode = parserFactory.getContainerNodeParser().parse(Collections.singleton(xmlData), schemaForDataRead);
.withChild(dataNode).build();
} else {
final Set<Element> documentElement = Collections.singleton(message.getDocument().getDocumentElement());
- final RpcDefinition rpcDefinition = mappedRpcs.get(rpc.getLastComponent());
- Preconditions.checkArgument(rpcDefinition != null, "Unable to parse response of %s, the rpc is unknown", rpc.getLastComponent());
+
+ Map<QName, RpcDefinition> currentMappedRpcs = mappedRpcs;
+
+ // Determine whether a base netconf operation is being invoked and also check if the device exposed model for base netconf
+ // If no, use pre built base netconf operations model
+ final boolean needToUseBaseCtx = mappedRpcs.get(rpcQName) == null && isBaseRpc(rpcQName);
+ if(needToUseBaseCtx) {
+ currentMappedRpcs = MAPPED_BASE_RPCS;
+ }
+
+ final RpcDefinition rpcDefinition = currentMappedRpcs.get(rpcQName);
+ Preconditions.checkArgument(rpcDefinition != null, "Unable to parse response of %s, the rpc is unknown", rpcQName);
// In case no input for rpc is defined, we can simply construct the payload here
if (rpcDefinition.getOutput() == null) {
import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME;
import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME;
import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_LOCK_QNAME;
import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME;
import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.createEditConfigStructure;
import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toFilterStructure;
XMLUnit.setIgnoreAttributeOrder(true);
XMLUnit.setIgnoreComments(true);
- schema = getSchema();
+ schema = getSchema(true);
netconfMessageTransformer = getTransformer(schema);
}
+ @Test
+ public void testLockRequestBaseSchemaNotPresent() throws Exception {
+ final SchemaContext partialSchema = getSchema(false);
+ final NetconfMessageTransformer transformer = getTransformer(partialSchema);
+ final NetconfMessage netconfMessage = transformer.toRpcRequest(toPath(NETCONF_LOCK_QNAME),
+ NetconfBaseOps.getLockContent(NETCONF_CANDIDATE_QNAME));
+
+ assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<lock"));
+ }
+
+ @Test
+ public void tesLockSchemaRequest() throws Exception {
+ final SchemaContext partialSchema = getSchema(false);
+ final NetconfMessageTransformer transformer = getTransformer(partialSchema);
+ final String result = "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><ok/></rpc-reply>";
+
+ transformer.toRpcResult(new NetconfMessage(XmlUtil.readXmlToDocument(result)), toPath(NETCONF_LOCK_QNAME));
+ }
+
@Test
public void testDiscardChangesRequest() throws Exception {
final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(toPath(NETCONF_DISCARD_CHANGES_QNAME),
"</rpc>");
}
+
@Test
public void tesGetSchemaResponse() throws Exception {
- final NetconfMessageTransformer netconfMessageTransformer = getTransformer(getSchema());
+ final NetconfMessageTransformer netconfMessageTransformer = getTransformer(getSchema(true));
final NetconfMessage response = new NetconfMessage(XmlUtil.readXmlToDocument(
"<rpc-reply message-id=\"101\"\n" +
"xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
"</data>\n" +
"</rpc-reply>"));
- final NetconfMessageTransformer netconfMessageTransformer = getTransformer(getSchema());
+ final NetconfMessageTransformer netconfMessageTransformer = getTransformer(getSchema(true));
final DOMRpcResult compositeNodeRpcResult = netconfMessageTransformer.toRpcResult(response, toPath(NETCONF_GET_CONFIG_QNAME));
assertTrue(compositeNodeRpcResult.getErrors().isEmpty());
assertNotNull(compositeNodeRpcResult.getResult());
assertNull(compositeNodeRpcResult.getResult());
}
- public SchemaContext getSchema() {
+ public SchemaContext getSchema(boolean addBase) {
final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
- moduleInfoBackedContext.addModuleInfos(Collections.singleton($YangModuleInfoImpl.getInstance()));
+ if(addBase) {
+ moduleInfoBackedContext.addModuleInfos(Collections.singleton($YangModuleInfoImpl.getInstance()));
+ }
moduleInfoBackedContext.addModuleInfos(Collections.singleton(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.$YangModuleInfoImpl.getInstance()));
return moduleInfoBackedContext.tryToCreateSchemaContext().get();
}