Bug 4100 - Extend sal-netconf-connector base schema context 59/33759/3
authorAndrej Mak <andmak@cisco.com>
Fri, 29 Jan 2016 10:09:35 +0000 (11:09 +0100)
committerAndrej Mak <andmak@cisco.com>
Thu, 11 Feb 2016 15:02:36 +0000 (15:02 +0000)
In case, that device supports notifications, but doesn't provide
model for them, model from BaseSchema in NetconfMessageTransformer
will be used as fallback.

Change-Id: Ib058ea07a8a457dd83ed98c6d91e21976a0d8ffb
Signed-off-by: Andrej Mak <andmak@cisco.com>
opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/NetconfDevice.java
opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/NetconfStateSchemas.java
opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java
opendaylight/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/NetconfStateSchemasTest.java
opendaylight/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTxTest.java
opendaylight/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java

index fd3399fb9e991136db5c73bfa82b3374efc4e87c..bb63554d5491d356cc13a5072a8563b1fb75a2ea 100644 (file)
@@ -43,10 +43,8 @@ import org.opendaylight.netconf.sal.connect.netconf.schema.NetconfRemoteSchemaYa
 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer;
 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.netconf.monitoring.extension.rev131210.$YangModuleInfoImpl;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability;
-import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
@@ -68,26 +66,6 @@ public class NetconfDevice implements RemoteDevice<NetconfSessionPreferences, Ne
 
     private static final Logger LOG = LoggerFactory.getLogger(NetconfDevice.class);
 
-    /**
-     * Initial schema context contains schemas for netconf monitoring and netconf notifications
-     */
-    public static final SchemaContext INIT_SCHEMA_CTX;
-
-    static {
-        try {
-            final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
-            moduleInfoBackedContext.addModuleInfos(
-                    Lists.newArrayList(
-                            $YangModuleInfoImpl.getInstance(),
-                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.$YangModuleInfoImpl.getInstance(),
-                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.$YangModuleInfoImpl.getInstance()));
-            INIT_SCHEMA_CTX = moduleInfoBackedContext.tryToCreateSchemaContext().get();
-        } catch (final RuntimeException e) {
-            LOG.error("Unable to prepare schema context for netconf initialization", e);
-            throw new ExceptionInInitializerError(e);
-        }
-    }
-
     public static final Function<QName, SourceIdentifier> QNAME_TO_SOURCE_ID_FUNCTION = new Function<QName, SourceIdentifier>() {
         @Override
         public SourceIdentifier apply(final QName input) {
@@ -117,8 +95,12 @@ public class NetconfDevice implements RemoteDevice<NetconfSessionPreferences, Ne
     /**
      * 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) {
-        return new NetconfDeviceRpc(INIT_SCHEMA_CTX, listener, new NetconfMessageTransformer(INIT_SCHEMA_CTX, false));
+    static NetconfDeviceRpc getRpcForInitialization(final NetconfDeviceCommunicator listener, final boolean notificationSupport) {
+        NetconfMessageTransformer.BaseSchema baseSchema = notificationSupport ?
+                NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS :
+                NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX;
+
+        return new NetconfDeviceRpc(baseSchema.getSchemaContext(), listener, new NetconfMessageTransformer(baseSchema.getSchemaContext(), false, baseSchema));
     }
 
 
@@ -145,7 +127,7 @@ public class NetconfDevice implements RemoteDevice<NetconfSessionPreferences, Ne
         // http://netty.io/wiki/thread-model.html
         LOG.debug("{}: Session to remote device established with {}", id, remoteSessionCapabilities);
 
-        final NetconfDeviceRpc initRpc = getRpcForInitialization(listener);
+        final NetconfDeviceRpc initRpc = getRpcForInitialization(listener, remoteSessionCapabilities.isNotificationsSupported());
         final DeviceSourcesResolver task = new DeviceSourcesResolver(remoteSessionCapabilities, id, stateSchemasResolver, initRpc);
         final ListenableFuture<DeviceSources> sourceResolverFuture = processingExecutor.submit(task);
 
@@ -215,7 +197,11 @@ public class NetconfDevice implements RemoteDevice<NetconfSessionPreferences, Ne
     }
 
     protected void handleSalInitializationSuccess(final SchemaContext result, final NetconfSessionPreferences remoteSessionCapabilities, final DOMRpcService deviceRpc) {
-        messageTransformer = new NetconfMessageTransformer(result, true);
+        NetconfMessageTransformer.BaseSchema baseSchema =
+                remoteSessionCapabilities.isNotificationsSupported() ?
+                NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS :
+                NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX;
+        messageTransformer = new NetconfMessageTransformer(result, true, baseSchema);
 
         updateTransformer(messageTransformer);
         // salFacade.onDeviceConnected has to be called before the notification handler is initialized
index 0797ab505f1856305933039a8bcad5e3a19b8e4b..ee119344ebe2f9220f91a0092ab0481fc465950b 100644 (file)
@@ -27,6 +27,7 @@ import java.util.concurrent.ExecutionException;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
 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.NetconfMessageTransformer;
 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.netconf.monitoring.rev101004.NetconfState;
@@ -79,7 +80,8 @@ public final class NetconfStateSchemas {
 
     private static final ContainerNode GET_SCHEMAS_RPC;
     static {
-        final DataContainerChild<?, ?> filter = NetconfMessageTransformUtil.toFilterStructure(STATE_SCHEMAS_IDENTIFIER, NetconfDevice.INIT_SCHEMA_CTX);
+        final DataContainerChild<?, ?> filter = NetconfMessageTransformUtil.toFilterStructure(STATE_SCHEMAS_IDENTIFIER,
+                NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS.getSchemaContext());
         GET_SCHEMAS_RPC
                 = Builders.containerBuilder().withNodeIdentifier(toId(NETCONF_GET_QNAME)).withChild(filter).build();
     }
index 2ac01caffce792270c774ab1bde8ef6ddab52268..270cdbfb188c8ce0582c9fe9634f0749eec10daf 100644 (file)
@@ -8,9 +8,11 @@
 package org.opendaylight.netconf.sal.connect.netconf.schema.mapping;
 
 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.EVENT_TIME;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.IETF_NETCONF_NOTIFICATIONS;
 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_RPC_QNAME;
 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_URI;
 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
+
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
@@ -44,7 +46,9 @@ import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
 import org.opendaylight.netconf.sal.connect.util.MessageCounter;
 import org.opendaylight.netconf.util.OrderedNormalizedNodeWriter;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.$YangModuleInfoImpl;
 import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
@@ -68,6 +72,46 @@ import org.w3c.dom.Element;
 
 public class NetconfMessageTransformer implements MessageTransformer<NetconfMessage> {
 
+    public enum BaseSchema {
+
+        BASE_NETCONF_CTX(
+                Lists.newArrayList(
+                        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.$YangModuleInfoImpl.getInstance()
+                )
+        ),
+        BASE_NETCONF_CTX_WITH_NOTIFICATIONS(
+                Lists.newArrayList(
+                        $YangModuleInfoImpl.getInstance(),
+                        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.$YangModuleInfoImpl.getInstance(),
+                        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.$YangModuleInfoImpl.getInstance(),
+                        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.$YangModuleInfoImpl.getInstance()
+                )
+        );
+
+        private final Map<QName, RpcDefinition> mappedRpcs;
+        private final SchemaContext schemaContext;
+
+        BaseSchema(List<YangModuleInfo> modules) {
+            try {
+                final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
+                moduleInfoBackedContext.addModuleInfos(modules);
+                schemaContext = moduleInfoBackedContext.tryToCreateSchemaContext().get();
+                mappedRpcs = Maps.uniqueIndex(schemaContext.getOperations(), QNAME_FUNCTION);
+            } catch (final RuntimeException e) {
+                LOG.error("Unable to prepare schema context for base netconf ops", e);
+                throw new ExceptionInInitializerError(e);
+            }
+        }
+
+        private Map<QName, RpcDefinition> getMappedRpcs() {
+            return mappedRpcs;
+        }
+
+        public SchemaContext getSchemaContext() {
+            return schemaContext;
+        }
+    }
+
     public static final String MESSAGE_ID_PREFIX = "m";
 
     private static final Logger LOG= LoggerFactory.getLogger(NetconfMessageTransformer.class);
@@ -86,34 +130,25 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
             return QNAME_FUNCTION.apply(notification).withoutRevision();
         }
     };
-    private static final SchemaContext BASE_NETCONF_CTX;
-
-    static {
-        try {
-            final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
-            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();
-        } catch (final RuntimeException e) {
-            LOG.error("Unable to prepare schema context for base netconf ops", e);
-            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 BaseSchema baseSchema;
     private final MessageCounter counter;
     private final Map<QName, RpcDefinition> mappedRpcs;
     private final Multimap<QName, NotificationDefinition> mappedNotifications;
     private final DomToNormalizedNodeParserFactory parserFactory;
 
     public NetconfMessageTransformer(final SchemaContext schemaContext, final boolean strictParsing) {
+        this(schemaContext, strictParsing, BaseSchema.BASE_NETCONF_CTX);
+    }
+
+    public NetconfMessageTransformer(final SchemaContext schemaContext, final boolean strictParsing, final BaseSchema baseSchema) {
         this.counter = new MessageCounter();
         this.schemaContext = schemaContext;
         parserFactory = DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, schemaContext, strictParsing);
-
         mappedRpcs = Maps.uniqueIndex(schemaContext.getOperations(), QNAME_FUNCTION);
         mappedNotifications = Multimaps.index(schemaContext.getNotifications(), QNAME_NOREV_FUNCTION);
+        this.baseSchema = baseSchema;
     }
 
     @Override
@@ -213,9 +248,9 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
 
         // 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);
+        final boolean needToUseBaseCtx = mappedRpcs.get(rpcQName) == null && isBaseOrNotificationRpc(rpcQName);
         if(needToUseBaseCtx) {
-            currentMappedRpcs = MAPPED_BASE_RPCS;
+            currentMappedRpcs = baseSchema.getMappedRpcs();
         }
 
         Preconditions.checkNotNull(currentMappedRpcs.get(rpcQName), "Unknown rpc %s, available rpcs: %s", rpcQName, currentMappedRpcs.keySet());
@@ -234,7 +269,8 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
         try {
             // 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(((ContainerNode) payload), result, rpc, needToUseBaseCtx ? BASE_NETCONF_CTX : schemaContext);
+            SchemaContext ctx = needToUseBaseCtx ? baseSchema.getSchemaContext() : schemaContext;
+            writeNormalizedRpc(((ContainerNode) payload), result, rpc, ctx);
         } catch (final XMLStreamException | IOException | IllegalStateException e) {
             throw new IllegalStateException("Unable to serialize " + rpc, e);
         }
@@ -244,8 +280,10 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
         return new NetconfMessage(node);
     }
 
-    private static boolean isBaseRpc(final QName rpc) {
-        return rpc.getNamespace().equals(NETCONF_URI);
+    private boolean isBaseOrNotificationRpc(final QName rpc) {
+        return rpc.getNamespace().equals(NETCONF_URI) ||
+                rpc.getNamespace().equals(IETF_NETCONF_NOTIFICATIONS.getNamespace()) ||
+                rpc.getNamespace().equals(NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_QNAME.getNamespace());
     }
 
     private DOMResult prepareDomResultForRpcRequest(final QName rpcQName) {
@@ -304,9 +342,9 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
 
             // 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);
+            final boolean needToUseBaseCtx = mappedRpcs.get(rpcQName) == null && isBaseOrNotificationRpc(rpcQName);
             if(needToUseBaseCtx) {
-                currentMappedRpcs = MAPPED_BASE_RPCS;
+                currentMappedRpcs = baseSchema.getMappedRpcs();
             }
 
             final RpcDefinition rpcDefinition = currentMappedRpcs.get(rpcQName);
index a06bd4a05cd05b96aea49ebb68953319d46127da..ac2fd3279d298f3aa81dceb2ed3fa48414db560b 100644 (file)
@@ -17,6 +17,7 @@ import java.util.Collections;
 import java.util.Set;
 import org.junit.Test;
 import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
@@ -25,6 +26,7 @@ import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNo
 import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -32,10 +34,11 @@ public class NetconfStateSchemasTest {
 
     @Test
     public void testCreate() throws Exception {
-        final DataSchemaNode schemasNode = ((ContainerSchemaNode) NetconfDevice.INIT_SCHEMA_CTX.getDataChildByName("netconf-state")).getDataChildByName("schemas");
+        final SchemaContext schemaContext = NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS.getSchemaContext();
+        final DataSchemaNode schemasNode = ((ContainerSchemaNode) schemaContext.getDataChildByName("netconf-state")).getDataChildByName("schemas");
 
         final Document schemasXml = XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/netconf-state.schemas.payload.xml"));
-        final ToNormalizedNodeParser<Element, ContainerNode, ContainerSchemaNode> containerNodeParser = DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, NetconfDevice.INIT_SCHEMA_CTX, false).getContainerNodeParser();
+        final ToNormalizedNodeParser<Element, ContainerNode, ContainerSchemaNode> containerNodeParser = DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, schemaContext, false).getContainerNodeParser();
         final ContainerNode compositeNodeSchemas = containerNodeParser.parse(Collections.singleton(schemasXml.getDocumentElement()), (ContainerSchemaNode) schemasNode);
         final NetconfStateSchemas schemas = NetconfStateSchemas.create(new RemoteDeviceId("device", new InetSocketAddress(99)), compositeNodeSchemas);
 
index c708574ce133896cbc9e09b8298a209477673da8..82fe4b23e788c64ea3c1924536c1432c118c6306 100644 (file)
@@ -33,7 +33,7 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
 import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
-import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
+import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer;
 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps;
 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
@@ -128,7 +128,7 @@ public class NetconfDeviceWriteOnlyTxTest {
                 .doReturn(Futures.immediateFailedCheckedFuture(new IllegalStateException("Failed tx")))
                 .when(rpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
 
-        final WriteRunningTx tx = new WriteRunningTx(id, new NetconfBaseOps(rpc, NetconfDevice.INIT_SCHEMA_CTX),
+        final WriteRunningTx tx = new WriteRunningTx(id, new NetconfBaseOps(rpc, NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS.getSchemaContext()),
                 false, 60000L);
         try {
             tx.delete(LogicalDatastoreType.CONFIGURATION, yangIId);
index f8bf554c1cdd282d63f6ded564c5109156c62be4..91279cc1dfca469261b4cc4ddc2da378f9f3f204 100644 (file)
@@ -13,6 +13,8 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_CONTENT;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_QNAME;
 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.GET_SCHEMA_QNAME;
 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME;
 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME;
@@ -46,7 +48,6 @@ import org.junit.Test;
 import org.opendaylight.controller.config.util.xml.XmlUtil;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
 import org.opendaylight.netconf.api.NetconfMessage;
-import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
 import org.opendaylight.netconf.sal.connect.netconf.schema.NetconfRemoteSchemaYangSourceProvider;
 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps;
 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
@@ -97,6 +98,23 @@ public class NetconfMessageTransformerTest {
         assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString("<rpc"));
     }
 
+    @Test
+    public void testCreateSubscriberNotificationSchemaNotPresent() throws Exception {
+        final SchemaContext partialSchema = getSchema(true);
+        final NetconfMessageTransformer transformer = new NetconfMessageTransformer(
+                partialSchema,
+                true,
+                NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS
+        );
+        NetconfMessage netconfMessage = transformer.toRpcRequest(
+                toPath(CREATE_SUBSCRIPTION_RPC_QNAME),
+                CREATE_SUBSCRIPTION_RPC_CONTENT
+        );
+        String documentString = XmlUtil.toString(netconfMessage.getDocument());
+        assertThat(documentString, CoreMatchers.containsString("<create-subscription"));
+        assertThat(documentString, CoreMatchers.containsString("<rpc"));
+    }
+
     @Test
     public void tesLockSchemaRequest() throws Exception {
         final SchemaContext partialSchema = getSchema(false);
@@ -228,7 +246,7 @@ public class NetconfMessageTransformerTest {
         final MapEntryNode schemaNode = Builders.mapEntryBuilder().withNodeIdentifier(identifierWithPredicates).withValue(values).build();
 
         final YangInstanceIdentifier id = YangInstanceIdentifier.builder().node(NetconfState.QNAME).node(Schemas.QNAME).node(Schema.QNAME).nodeWithKey(Schema.QNAME, keys).build();
-        final DataContainerChild<?, ?> editConfigStructure = createEditConfigStructure(NetconfDevice.INIT_SCHEMA_CTX, id, Optional.<ModifyAction>absent(), Optional.<NormalizedNode<?, ?>>fromNullable(schemaNode));
+        final DataContainerChild<?, ?> editConfigStructure = createEditConfigStructure(NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS.getSchemaContext(), id, Optional.<ModifyAction>absent(), Optional.<NormalizedNode<?, ?>>fromNullable(schemaNode));
 
         final DataContainerChild<?, ?> target = NetconfBaseOps.getTargetNode(NETCONF_CANDIDATE_QNAME);