operations
authorShikhar Bhushan <shikhar@schmizz.net>
Wed, 29 Apr 2009 03:30:39 +0000 (03:30 +0000)
committerShikhar Bhushan <shikhar@schmizz.net>
Wed, 29 Apr 2009 03:30:39 +0000 (03:30 +0000)
git-svn-id: http://ncclient.googlecode.com/svn/trunk@81 6dbcf712-26ac-11de-a2f3-1373824ab735

ncclient/operations/listeners.py [deleted file]
ncclient/operations/notification.py [new file with mode: 0644]
ncclient/operations/reply.py [new file with mode: 0644]
ncclient/operations/rpc.py
ncclient/operations/subscribe.py [new file with mode: 0644]

diff --git a/ncclient/operations/listeners.py b/ncclient/operations/listeners.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/ncclient/operations/notification.py b/ncclient/operations/notification.py
new file mode 100644 (file)
index 0000000..94b71c5
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2009 Shikhar Bhushan
+#
+# 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 glue import Listener
+
+class Notification:
+    
+    pass
+
+class NotificationListener(Listener):
+    
+    pass
diff --git a/ncclient/operations/reply.py b/ncclient/operations/reply.py
new file mode 100644 (file)
index 0000000..e052acb
--- /dev/null
@@ -0,0 +1,138 @@
+# Copyright 2009 Shikhar Bhushan
+#
+# 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.
+
+def parse():
+    
+    pass
+
+
+class RPCReply:
+    
+    def __init__(self, event):
+        self._raw = None
+        self._errs = None
+    
+    def __str__(self):
+        return self._raw
+    
+    def parse(self):
+        if not self._parsed:
+            ok = RPCReplyParser.parse(self._raw)
+            for err in errs:
+                self._errs.append(RPCError(*err))
+            self._parsed = True
+    
+    @property
+    def raw(self):
+        return self._raw
+    
+    @property
+    def parsed(self):
+        return self._parsed
+    
+    @property
+    def ok(self):
+        return True if self._parsed and not self._errs else False
+    
+    @property
+    def errors(self):
+        return self._errs
+
+
+class RPCError(Exception): # raise it if you like
+    
+    def __init__(self, raw, err_dict):
+        self._raw = raw
+        self._dict = err_dict
+    
+    def __str__(self):
+        # TODO
+        return self._raw
+    
+    def __dict__(self):
+        return self._dict
+    
+    @property
+    def raw(self):
+        return self._raw
+    
+    @property
+    def type(self):
+        return self._dict.get('type', None)
+    
+    @property
+    def severity(self):
+        return self._dict.get('severity', None)
+    
+    @property
+    def tag(self):
+        return self._dict.get('tag', None)
+    
+    @property
+    def path(self):
+        return self._dict.get('path', None)
+    
+    @property
+    def message(self):
+        return self._dict.get('message', None)
+    
+    @property
+    def info(self):
+        return self._dict.get('info', None)
+
+
+class RPCReplyListener(Listener):
+    
+    # TODO - determine if need locking
+    
+    # one instance per subject    
+    def __new__(cls, subject):
+        instance = subject.get_listener_instance(cls)
+        if instance is None:
+            instance = object.__new__(cls)
+            instance._id2rpc = WeakValueDictionary()
+            instance._errback = None
+            subject.add_listener(instance)
+        return instance
+    
+    def __str__(self):
+        return 'RPCReplyListener'
+    
+    def set_errback(self, errback):
+        self._errback = errback
+
+    def register(self, msgid, rpc):
+        self._id2rpc[msgid] = rpc
+    
+    def callback(self, root, raw):
+        tag, attrs = root
+        if __(tag) != 'rpc-reply':
+            return
+        for key in attrs:
+            if __(key) == 'message-id':
+                id = attrs[key]
+                try:
+                    rpc = self._id2rpc[id]
+                    rpc.deliver(raw)
+                except:
+                    logger.warning('RPCReplyListener.callback: no RPC '
+                                   + 'registered for message-id: [%s]' % id)
+                break
+        else:
+            logger.warning('<rpc-reply> without message-id received: %s' % raw)
+    
+    def errback(self, err):
+        logger.error('RPCReplyListener.errback: %r' % err)
+        if self._errback is not None:
+            self._errback(err)
index dc65b10..131f704 100644 (file)
@@ -16,30 +16,29 @@ from threading import Event, Lock
 from uuid import uuid1
 
 from . import logger
+from ncclient.content import TreeBuilder, BASE_NS
+from reply import RPCReply, RPCReplyListener
 
-class RPC:
-        
+class RPC(object):
+    
     def __init__(self, session, async=False):
         self._session = session
         self._id = uuid1().urn
+        self._listener = RPCReplyListener(session)
+        self._listener.register(self._id, self)
         self._reply = RPCReply()
         self._reply_event = Event()
     
     def _build(self, op, encoding='utf-8'):
-        if isinstance(op, basestring):
-            return RPCBuilder.build_from_string(self._id, op, encoding)
+        if isinstance(op, dict):
+            return self.build_from_spec(self._id, op, encoding)
+        elif isinstance(op, basestring): 
+            return self.build_from_string(self._id, op, encoding)
         else:
-            return RPCBuilder.build_from_spec(self._id, op, encoding)
+            raise ValueError('Inappropriate value of tree spec.')
     
     def _request(self, op):
-        self._reply = RPCReply()
-        # get the listener instance for this session
-        # <rpc-reply> with message id will reach response_cb
-        self._listener.register(self._id, self)
-        # only effective the first time, transport.session.Subject internally
-        # uses a set type for listeners
-        self._session.add_listener(self._listener)
-        req = RPCBuilder.build(self._id, op)
+        req = self._build(op)
         self._session.send(req)
         if reply_event is not None: # if we were provided an Event to use
             self._reply_event = reply_event
@@ -85,6 +84,6 @@ class RPC:
     def build_from_string(msgid, opstr, encoding='utf-8'):
         "TODO: docstring"
         decl = '<?xml version="1.0" encoding="%s"?>' % encoding
-        doc = (u'''<rpc message-id="%s" xmlns="%s">%s</rpc>''' %
+        doc = (u'<rpc message-id="%s" xmlns="%s">%s</rpc>' %
                (msgid, BASE_NS, opstr)).encode(encoding)
-        return (decl + doc)
+        return '%s%s' % (decl, doc)
diff --git a/ncclient/operations/subscribe.py b/ncclient/operations/subscribe.py
new file mode 100644 (file)
index 0000000..f06309b
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright 2009 Shikhar Bhushan
+#
+# 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 rpc import RPC
+
+class CreateSubscription(RPC):    
+    pass
+