This commit consists of:
1) Ability for the netconf client to retrieve schemas metadata from
   the netconf server
2) Ability for the netconf server to retrieve specific yang schema from
   the netconf server
3) Netconf says Happy New Year 2017

Change-Id: I6552224707607ca6cc1397f2fbf193503bb116a3
diff --git a/netconf/nc_rpc/__init__.py b/netconf/nc_rpc/__init__.py
index 7398217..e69de29 100644
--- a/netconf/nc_rpc/__init__.py
+++ b/netconf/nc_rpc/__init__.py
@@ -1,44 +0,0 @@
-# -*- coding: utf-8 -*-#
-#
-# December 23 2014, Christian Hopps <chopps@gmail.com>
-#
-# Copyright (c) 2015, Deutsche Telekom AG
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-from __future__ import absolute_import, division, unicode_literals, print_function, nested_scopes
-from lxml.etree import register_namespace
-
-MAXSSHBUF = 16 * 1024
-NSMAP = { }
-
-
-def nsmap_add (prefix, namespace):
-    "Add a prefix namespace mapping to the modules mapping dictionary"
-    NSMAP[prefix] = namespace
-    register_namespace(prefix, namespace)
-
-
-def nsmap_update (nsdict):
-    "Add a dicitonary of prefx namespace mappings to the modules mapping dictionary"
-    NSMAP.update(nsdict)
-    for key, val in nsdict.items():
-        register_namespace(key, val)
-
-
-def qmap (key):
-    return "{" + NSMAP[key] + "}"
-
-
-# Add base spec namespace
-nsmap_add('nc', "urn:ietf:params:xml:ns:netconf:base:1.0")
diff --git a/netconf/nc_rpc/base/close_session.py b/netconf/nc_rpc/base/close_session.py
index 7e76b45..45a6cc2 100644
--- a/netconf/nc_rpc/base/close_session.py
+++ b/netconf/nc_rpc/base/close_session.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -24,8 +24,10 @@
 
 class CloseSession(Rpc):
 
-    def __init__(self, request, grpc_client, session):
-        super(CloseSession, self).__init__(request, grpc_client, session)
+    def __init__(self, request, request_xml, grpc_client, session,
+                 capabilities):
+        super(CloseSession, self).__init__(request, request_xml, grpc_client,
+                                           session)
         self._validate_parameters()
 
     def execute(self):
diff --git a/netconf/nc_rpc/base/commit.py b/netconf/nc_rpc/base/commit.py
index 06c1746..22a0e6a 100644
--- a/netconf/nc_rpc/base/commit.py
+++ b/netconf/nc_rpc/base/commit.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -24,8 +24,8 @@
 
 class Commit(Rpc):
 
-	def __init__(self, request, grpc_client, session):
-		super(Commit, self).__init__(request, grpc_client, session)
+	def __init__(self, request, request_xml, grpc_client, session, capabilities):
+		super(Commit, self).__init__(request, request_xml, grpc_client, session)
 		self._validate_parameters()
 
 	def execute(self):
diff --git a/netconf/nc_rpc/base/copy_config.py b/netconf/nc_rpc/base/copy_config.py
index a59081d..1d96b76 100644
--- a/netconf/nc_rpc/base/copy_config.py
+++ b/netconf/nc_rpc/base/copy_config.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -23,8 +23,8 @@
 
 class CopyConfig(Rpc):
 
-	def __init__(self, request, grpc_client, session):
-		super(CopyConfig, self).__init__(request, grpc_client, session)
+	def __init__(self, request, request_xml, grpc_client, session, capabilities):
+		super(CopyConfig, self).__init__(request, request_xml, grpc_client, session)
 		self._validate_parameters()
 
 	def execute(self):
diff --git a/netconf/nc_rpc/base/delete_config.py b/netconf/nc_rpc/base/delete_config.py
index 8ad5ea4..e21d2d4 100644
--- a/netconf/nc_rpc/base/delete_config.py
+++ b/netconf/nc_rpc/base/delete_config.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -23,8 +23,8 @@
 
 class DeleteConfig(Rpc):
 
-	def __init__(self, request, grpc_client, session):
-		super(DeleteConfig, self).__init__(request, grpc_client, session)
+	def __init__(self, request, request_xml, grpc_client, session, capabilities):
+		super(DeleteConfig, self).__init__(request, request_xml, grpc_client, session)
 		self._validate_parameters()
 
 	def execute(self):
diff --git a/netconf/nc_rpc/base/discard_changes.py b/netconf/nc_rpc/base/discard_changes.py
index 961eea0..4b4b219 100644
--- a/netconf/nc_rpc/base/discard_changes.py
+++ b/netconf/nc_rpc/base/discard_changes.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -23,8 +23,8 @@
 
 class DiscardChanges(Rpc):
 
-	def __init__(self, request, grpc_client, session):
-		super(DiscardChanges, self).__init__(request, grpc_client, session)
+	def __init__(self, request, request_xml, grpc_client, session, capabilities):
+		super(DiscardChanges, self).__init__(request, request_xml, grpc_client, session)
 		self._validate_parameters()
 
 	def execute(self):
diff --git a/netconf/nc_rpc/base/edit_config.py b/netconf/nc_rpc/base/edit_config.py
index 92fa085..0991c67 100644
--- a/netconf/nc_rpc/base/edit_config.py
+++ b/netconf/nc_rpc/base/edit_config.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -23,8 +23,8 @@
 
 class EditConfig(Rpc):
 
-	def __init__(self, request, grpc_client, session):
-		super(EditConfig, self).__init__(request, grpc_client, session)
+	def __init__(self, request, request_xml, grpc_client, session, capabilities):
+		super(EditConfig, self).__init__(request, request_xml, grpc_client, session)
 		self._validate_parameters()
 
 	def execute(self):
diff --git a/netconf/nc_rpc/base/get.py b/netconf/nc_rpc/base/get.py
index 71449ad..d953b17 100644
--- a/netconf/nc_rpc/base/get.py
+++ b/netconf/nc_rpc/base/get.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -14,22 +14,18 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-from lxml import etree
 import structlog
 from netconf.nc_rpc.rpc import Rpc
 import netconf.nc_common.error as ncerror
-from netconf.constants import Constants as C
-from netconf.utils import filter_tag_match
 from twisted.internet.defer import inlineCallbacks, returnValue
 import dicttoxml
-from simplejson import dumps, load
 
 log = structlog.get_logger()
 
 
 class Get(Rpc):
-    def __init__(self, request, grpc_client, session):
-        super(Get, self).__init__(request, grpc_client, session)
+    def __init__(self, request, request_xml, grpc_client, session, capabilities):
+        super(Get, self).__init__(request, request_xml, grpc_client, session)
         self._validate_parameters()
 
     @inlineCallbacks
diff --git a/netconf/nc_rpc/base/get_config.py b/netconf/nc_rpc/base/get_config.py
index 2fb8ad0..e7ade72 100644
--- a/netconf/nc_rpc/base/get_config.py
+++ b/netconf/nc_rpc/base/get_config.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -14,20 +14,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-from lxml import etree
 import structlog
 from netconf.nc_rpc.rpc import Rpc
 import netconf.nc_common.error as ncerror
 from netconf.constants import Constants as C
-from netconf.utils import elm
-from netconf import NSMAP
 
 log = structlog.get_logger()
 
 class GetConfig(Rpc):
 
-	def __init__(self, request, grpc_client, session):
-		super(GetConfig, self).__init__(request, grpc_client, session)
+	def __init__(self, request, request_xml, grpc_client, session, capabilities):
+		super(GetConfig, self).__init__(request, request_xml, grpc_client, session)
 		self._validate_parameters()
 
 	def execute(self):
@@ -47,17 +44,17 @@
 			self.rpc_response.node = ncerror.BadMsg(self.rpc_request)
 			return
 
-		self.source_param = self.rpc_method.find(C.NC_SOURCE, namespaces=NSMAP)
-		if self.source_param is None:
-			self.rpc_response.is_error = True
-			self.rpc_response.node = ncerror.MissingElement(
-				self.rpc_request, elm(C.NC_SOURCE))
-			return
+		self.source_param = self.rpc_method.find(C.NC_SOURCE, namespaces=C.NS_MAP)
+		# if self.source_param is None:
+		# 	self.rpc_response.is_error = True
+		# 	self.rpc_response.node = ncerror.MissingElement(
+		# 		self.rpc_request, elm(C.NC_SOURCE))
+		# 	return
 
 		self.filter_param = None
 		if paramslen == 2:
 			self.filter_param = self.rpc_method.find(C.NC_FILTER,
-												  namespaces=NSMAP)
+												  namespaces=C.NS_MAP)
 			if self.filter_param is None:
 				unknown_elm = self.params[0] if self.params[0] != \
 												self.source_param else \
diff --git a/netconf/nc_rpc/base/kill_session.py b/netconf/nc_rpc/base/kill_session.py
index 16461cd..e10f3a5 100644
--- a/netconf/nc_rpc/base/kill_session.py
+++ b/netconf/nc_rpc/base/kill_session.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -25,8 +25,8 @@
 
 class KillSession(Rpc):
 
-    def __init__(self, request, grpc_client, session):
-        super(KillSession, self).__init__(request, grpc_client, session)
+    def __init__(self, request, request_xml, grpc_client, session, capabilities):
+        super(KillSession, self).__init__(request, request_xml, grpc_client, session)
         self._validate_parameters()
 
     def execute(self):
diff --git a/netconf/nc_rpc/base/lock.py b/netconf/nc_rpc/base/lock.py
index 2f41e24..5a59376 100644
--- a/netconf/nc_rpc/base/lock.py
+++ b/netconf/nc_rpc/base/lock.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -23,8 +23,8 @@
 
 class Lock(Rpc):
 
-	def __init__(self, request, grpc_client, session):
-		super(Lock, self).__init__(request, grpc_client, session)
+	def __init__(self, request, request_xml, grpc_client, session, capabilities):
+		super(Lock, self).__init__(request, request_xml, grpc_client, session)
 		self._validate_parameters()
 
 	def execute(self):
diff --git a/netconf/nc_rpc/base/unlock.py b/netconf/nc_rpc/base/unlock.py
index f9ef062..b5db7c1 100644
--- a/netconf/nc_rpc/base/unlock.py
+++ b/netconf/nc_rpc/base/unlock.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -23,9 +23,8 @@
 
 class UnLock(Rpc):
 
-	def __init__(self, rpc_request, rpc_method, grpc_client, session):
-		super(UnLock, self).__init__(rpc_request, rpc_method, grpc_client,
-									 session)
+	def __init__(self, request, request_xml, grpc_client, session, capabilities):
+		super(UnLock, self).__init__(request, request_xml, grpc_client, session)
 		self._validate_parameters()
 
 	def execute(self):
diff --git a/netconf/nc_rpc/base/validate.py b/netconf/nc_rpc/base/validate.py
index 8671b12..61e2f80 100644
--- a/netconf/nc_rpc/base/validate.py
+++ b/netconf/nc_rpc/base/validate.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
 
 class Validate(Rpc):
 
-	def __init__(self, request, grpc_client, session):
+	def __init__(self, request, request_xml, grpc_client, session, capabilities):
 		super(Validate, self).__init__(request, grpc_client, session)
 		self._validate_parameters()
 
diff --git a/netconf/nc_rpc/ext/get_schema.py b/netconf/nc_rpc/ext/get_schema.py
new file mode 100644
index 0000000..ec473d3
--- /dev/null
+++ b/netconf/nc_rpc/ext/get_schema.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+#
+# Copyright 2017 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+from lxml import etree
+import structlog
+from netconf.nc_rpc.rpc import Rpc
+import netconf.nc_common.error as ncerror
+from netconf.constants import Constants as C
+from netconf.nc_common.utils import qmap, ns
+
+log = structlog.get_logger()
+
+class GetSchema(Rpc):
+    def __init__(self, request, request_xml, grpc_client, session, capabilities):
+        super(GetSchema, self).__init__(request, request_xml, grpc_client, session)
+        self.capabilities = capabilities
+        # specific schema parsing required
+        self.parse_schema_request(request_xml)
+        self._validate_parameters()
+
+    def execute(self):
+        if self.rpc_response.is_error:
+            return(self.rpc_response)
+
+        log.info('get-schema-request', session=self.session.session_id,
+                 request=self.request)
+
+        # Get the yang schema content
+        # TODO: Use version as well
+        content = self.capabilities.get_schema_content(self.request['identifier'])
+        if not content:
+            self.rpc_response.is_error = True
+            self.rpc_response.node = ncerror.BadMsg('Server Error')
+            return
+
+        self.rpc_response.node = self.create_xml_response(content)
+
+        self.rpc_response.is_error = False
+
+        return(self.rpc_response)
+
+    def _validate_parameters(self):
+        log.info('validate-parameters', session=self.session.session_id)
+        # Validate the GET command
+        if self.request:
+            try:
+                if self.request['command'] != 'get-schema' or \
+                        not self.request.has_key('identifier') or \
+                        not self.request.has_key('format') or \
+                        not self.request.has_key('version'):
+                    self.rpc_response.is_error = True
+                    self.rpc_response.node = ncerror.BadMsg('Improperly '
+                                                            'formatted get '
+                                                            'schemas request')
+                    return
+
+                if self.request.has_key('filter'):
+                    if not self.request.has_key('class'):
+                        self.rpc_response.is_error = True
+                        self.rpc_response.node = ncerror.BadMsg(
+                            'Missing filter sub-element')
+                        return
+
+                # Verify that the requested schema exists
+                if not self.capabilities.is_schema_supported(self.request[
+                                                             'identifier']) \
+                        or self.request['format'] != 'yang' :
+                    self.rpc_response.is_error = True
+                    self.rpc_response.node = ncerror.BadMsg(
+                        'Unsupported request')
+                    return
+
+            except Exception as e:
+                self.rpc_response.is_error = True
+                self.rpc_response.node = ncerror.BadMsg(self.request)
+                return
+
+    # Parse context-specific parameters
+    def parse_schema_request(self, node):
+        if not len(node):
+            return
+        schema_node = node.find(''.join([qmap(C.NCM), 'get-schema']))
+        if schema_node is not None:
+            for item in ['identifier', 'version', 'format']:
+                elem = schema_node.find(''.join([qmap(C.NCM), item]))
+                if elem is not None:
+                    self.request[item] = elem.text
+
+    def create_xml_response(self, content):
+        ns = {}
+        ns['xmlns'] = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"
+
+        elem = etree.Element('data', attrib=ns)
+        elem.text = unicode(content, "utf-8")
+        return elem
diff --git a/netconf/nc_rpc/ext/get_schemas.py b/netconf/nc_rpc/ext/get_schemas.py
new file mode 100644
index 0000000..7ec4555
--- /dev/null
+++ b/netconf/nc_rpc/ext/get_schemas.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+#
+# Copyright 2017 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+from lxml import etree
+import structlog
+from netconf.nc_rpc.rpc import Rpc
+import netconf.nc_common.error as ncerror
+
+log = structlog.get_logger()
+
+
+class GetSchemas(Rpc):
+    def __init__(self, request, request_xml, grpc_client, session, capabilities):
+        super(GetSchemas, self).__init__(request, request_xml, grpc_client, session)
+        self._validate_parameters()
+        self.capabilities = capabilities
+
+    def execute(self):
+        if self.rpc_response.is_error:
+            return(self.rpc_response)
+
+        log.info('get-schemas-request', session=self.session.session_id,
+                 request=self.request)
+
+        # Get the schema definitions
+        schema_defs = self.capabilities.get_yang_schemas_definitions()
+        log.info('schema-defs', definitions=schema_defs)
+
+        # format the schemas in xml
+        top = etree.Element('yang')
+        for dict in schema_defs:
+            schema = etree.SubElement(top, 'schema')
+            node = etree.SubElement(schema, 'identifier')
+            node.text = dict['id']
+            node = etree.SubElement(schema, 'version')
+            node.text = dict['version']
+            node = etree.SubElement(schema, 'format')
+            node.text = dict['format']
+            node = etree.SubElement(schema, 'namespace')
+            node.text = dict['namespace']
+            node = etree.SubElement(schema, 'location')
+            node.text = dict['location']
+
+        # Build the yang response
+        self.rpc_response.node = self.rpc_response.build_xml_response(
+            self.request, top)
+
+        self.rpc_response.is_error = False
+
+        return(self.rpc_response)
+
+
+    def _validate_parameters(self):
+        log.info('validate-parameters', session=self.session.session_id)
+        # Validate the GET command
+        if self.request:
+            try:
+                if self.request['command'] != 'get-schemas':
+                    self.rpc_response.is_error = True
+                    self.rpc_response.node = ncerror.BadMsg('Improperly '
+                                                            'formatted get '
+                                                            'schemas request')
+
+                if self.request.has_key('filter'):
+                    if not self.request.has_key('class'):
+                        self.rpc_response.is_error = True
+                        self.rpc_response.node = ncerror.BadMsg(
+                            'Missing filter sub-element')
+
+            except Exception as e:
+                self.rpc_response.is_error = True
+                self.rpc_response.node = ncerror.BadMsg(self.request)
+                return
+
diff --git a/netconf/nc_rpc/ext/get_voltha.py b/netconf/nc_rpc/ext/get_voltha.py
index 0c51e9a..5b004e7 100644
--- a/netconf/nc_rpc/ext/get_voltha.py
+++ b/netconf/nc_rpc/ext/get_voltha.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -18,20 +18,18 @@
 import structlog
 from netconf.nc_rpc.rpc import Rpc
 import netconf.nc_common.error as ncerror
-from netconf.constants import Constants as C
-from netconf.utils import filter_tag_match
 from twisted.internet.defer import inlineCallbacks, returnValue
 import dicttoxml
-from simplejson import dumps, load
 
 log = structlog.get_logger()
 
 
 class GetVoltha(Rpc):
-    def __init__(self, request, grpc_client, session):
-        super(GetVoltha, self).__init__(request, grpc_client, session)
+    def __init__(self, request, request_xml, grpc_client, session, capabilities):
+        super(GetVoltha, self).__init__(request, request_xml, grpc_client, session)
         self._validate_parameters()
 
+
     @inlineCallbacks
     def execute(self):
         log.info('get-voltha-request', session=self.session.session_id,
@@ -64,11 +62,5 @@
             self.rpc_response.node = ncerror.BadMsg(self.rpc_request)
             return
 
-        if self.params and not filter_tag_match(self.params[0], C.NC_FILTER):
-            self.rpc_response.is_error = True
-            self.rpc_response.node = ncerror.UnknownElement(
-                self.rpc_request, self.params[0])
-            return
-
         if not self.params:
             self.params = [None]
diff --git a/netconf/nc_rpc/rpc.py b/netconf/nc_rpc/rpc.py
index bafc58e..3f1eff4 100644
--- a/netconf/nc_rpc/rpc.py
+++ b/netconf/nc_rpc/rpc.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Code adapted from https://github.com/choppsv1/netconf
 #
@@ -24,8 +24,9 @@
 
 
 class Rpc(object):
-    def __init__(self, request, grpc_client, session):
-        self.request = request
+    def __init__(self, request_dict, request_xml, grpc_client, session):
+        self.request = request_dict
+        self.request_xml = request_xml
         self.rpc_response = RpcResponse()
         self.grpc_client =  grpc_client
         self.session = session
diff --git a/netconf/nc_rpc/rpc_factory.py b/netconf/nc_rpc/rpc_factory.py
index 230c57a..3d0d678 100644
--- a/netconf/nc_rpc/rpc_factory.py
+++ b/netconf/nc_rpc/rpc_factory.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Code adapted from https://github.com/choppsv1/netconf
 #
@@ -17,10 +17,10 @@
 # limitations under the License.
 #
 import structlog
+from netconf.constants import Constants as C
 from base.commit import Commit
 from base.copy_config import CopyConfig
 from base.delete_config import DeleteConfig
-from base.discard_changes import DiscardChanges
 from base.edit_config import EditConfig
 from base.get import Get
 from base.get_config import GetConfig
@@ -28,18 +28,15 @@
 from base.unlock import UnLock
 from base.close_session import CloseSession
 from base.kill_session import KillSession
+from ext.get_schemas import GetSchemas
+from ext.get_schema import GetSchema
 from ext.get_voltha import GetVoltha
-from netconf import NSMAP, qmap
 import netconf.nc_common.error as ncerror
-
-log = structlog.get_logger()
+from netconf.nc_common.utils import qmap, ns
 from lxml import etree
 
-ns_map = {
-    'base': '{urn:ietf:params:xml:ns:netconf:base:1.0}',
-    'voltha': '{urn:opencord:params:xml:ns:voltha:ietf-voltha}'
-}
 
+log = structlog.get_logger()
 
 class RpcFactory:
     instance = None
@@ -61,6 +58,7 @@
             if tup[0] == name:
                 return tup[1]
 
+
     # Parse a request (node is an ElementTree) and return a dictionary
     # TODO:  This parser is specific to a GET request.  Need to be it more
     # generic
@@ -69,8 +67,8 @@
         if not len(node):
             return request
         for elem in node.iter():
-            if elem.tag.find(ns_map['base']) != -1:  # found
-                elem_name = elem.tag.replace(ns_map['base'], "")
+            if elem.tag.find(qmap(C.NC)) != -1:  # found
+                elem_name = elem.tag.replace(qmap(C.NC), "")
                 if elem_name == 'rpc':
                     request['type'] = 'rpc'
                     request['message_id'] = self.get_attribute_value(
@@ -81,12 +79,24 @@
                 else:
                     request[
                         'command'] = elem_name  # attribute is empty for now
-            elif elem.tag.find(ns_map['voltha']) != -1:  # found
+            elif elem.tag.find(qmap(C.VOLTHA)) != -1:  # found
+                request['namespace'] = ns(C.VOLTHA)
                 if request.has_key('class'):
-                    request['subclass'] = elem.tag.replace(ns_map['voltha'],
-                                                           "")
+                    request['subclass'] = elem.tag.replace(qmap(C.VOLTHA),"")
                 else:
-                    request['class'] = elem.tag.replace(ns_map['voltha'], "")
+                    request['class'] = elem.tag.replace(qmap(C.VOLTHA), "")
+            elif elem.tag.find(qmap(C.NCM)) != -1:  # found
+                request['namespace'] = ns(C.NCM)
+                elem_name = elem.tag.replace(qmap(C.NCM), "")
+                if elem_name == 'get-schema':
+                    request['command'] = elem_name
+                    request['class'] = elem_name
+                elif request.has_key('class'):
+                    request['subclass'] = elem_name
+                elif elem_name == 'netconf-state':
+                    request['command'] = 'get-schemas'
+                    request['class'] = elem_name
+
         return request
 
     def register_rpc(self, namespace, service, name, klass):
@@ -99,7 +109,8 @@
         if key in self.rpc_map.keys():
             return self.rpc_map[key]
 
-    def get_rpc_handler(self, rpc_node, msg, grpc_channel, session):
+    def get_rpc_handler(self, rpc_node, msg, grpc_channel, session,
+                        capabilities):
         try:
             # Parse the request into a dictionary
             log.info("rpc-node",
@@ -110,17 +121,17 @@
                 log.error("request-bad-format")
                 raise ncerror.BadMsg(rpc_node)
 
-            if not request.has_key('message_id') or \
-                    not request.has_key('command'):
+            log.info("parsed-request", request=request)
+
+            if not request.has_key('message_id'):
                 log.error("request-no-message-id")
                 raise ncerror.BadMsg(rpc_node)
 
-            log.info("parsed-request", request=request)
-
             class_handler = self.rpc_class_handlers.get(request['command'],
                                                         None)
             if class_handler is not None:
-                return class_handler(request, grpc_channel, session)
+                return class_handler(request, rpc_node, grpc_channel, session,
+                                     capabilities)
 
             log.error("rpc-not-implemented", rpc=request['command'])
 
@@ -131,6 +142,8 @@
         'getvoltha': GetVoltha,
         'get-config': GetConfig,
         'get': Get,
+        'get-schemas': GetSchemas,
+        'get-schema': GetSchema,
         'edit-config': EditConfig,
         'copy-config': CopyConfig,
         'delete-config': DeleteConfig,
diff --git a/netconf/nc_rpc/rpc_response.py b/netconf/nc_rpc/rpc_response.py
index 584e35b..150631b 100644
--- a/netconf/nc_rpc/rpc_response.py
+++ b/netconf/nc_rpc/rpc_response.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2016 the original author or authors.
+# Copyright 2017 the original author or authors.
 #
 # Code adapted from https://github.com/choppsv1/netconf
 #
@@ -36,7 +36,7 @@
             return
         voltha_xml_string = etree.tostring(voltha_response)
 
-        # Remove the leading and trailing <root> tags
+        # Remove the leading and trailing <yang> tags
         if voltha_xml_string.startswith('<yang>'):
             voltha_xml_string = voltha_xml_string[len('<yang>'):]
             if voltha_xml_string.endswith('</yang>'):
@@ -48,7 +48,9 @@
                 '<data>',
                 '<',
                 request['class'],
-                ' xmlns="urn:opencord:params:xml:ns:voltha:ietf-voltha">',
+                ' xmlns="',
+                request['namespace'],
+                '">',
                 '<',
                 request['subclass'],
                 '>',