Statistics
| Branch: | Tag: | Revision:

root / ncclient / operations / rpc.py @ 41e2ed46

History | View | Annotate | Download (4.6 kB)

1 589b23e4 Shikhar Bhushan
# Copyright 2009 Shikhar Bhushan
2 589b23e4 Shikhar Bhushan
#
3 589b23e4 Shikhar Bhushan
# Licensed under the Apache License, Version 2.0 (the "License");
4 589b23e4 Shikhar Bhushan
# you may not use this file except in compliance with the License.
5 589b23e4 Shikhar Bhushan
# You may obtain a copy of the License at
6 589b23e4 Shikhar Bhushan
#
7 589b23e4 Shikhar Bhushan
#    http://www.apache.org/licenses/LICENSE-2.0
8 589b23e4 Shikhar Bhushan
#
9 589b23e4 Shikhar Bhushan
# Unless required by applicable law or agreed to in writing, software
10 589b23e4 Shikhar Bhushan
# distributed under the License is distributed on an "AS IS" BASIS,
11 589b23e4 Shikhar Bhushan
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 589b23e4 Shikhar Bhushan
# See the License for the specific language governing permissions and
13 589b23e4 Shikhar Bhushan
# limitations under the License.
14 589b23e4 Shikhar Bhushan
15 38a9b062 Shikhar Bhushan
from threading import Event, Lock
16 38a9b062 Shikhar Bhushan
from uuid import uuid1
17 1d540e60 Shikhar Bhushan
from weakref import WeakValueDictionary
18 38a9b062 Shikhar Bhushan
19 1d540e60 Shikhar Bhushan
from ncclient.content import TreeBuilder
20 1d540e60 Shikhar Bhushan
from ncclient.content import qualify as _
21 1d540e60 Shikhar Bhushan
from ncclient.content import unqualify as __
22 3e022b7b Shikhar Bhushan
from ncclient.glue import Listener
23 3e022b7b Shikhar Bhushan
24 3e022b7b Shikhar Bhushan
from . import logger
25 3e022b7b Shikhar Bhushan
from reply import RPCReply
26 3e022b7b Shikhar Bhushan
27 e91a5349 Shikhar Bhushan
28 5858a82c Shikhar Bhushan
class RPC(object):
29 5858a82c Shikhar Bhushan
    
30 11d9e642 Shikhar Bhushan
    def __init__(self, session, async=False):
31 38a9b062 Shikhar Bhushan
        self._session = session
32 1d540e60 Shikhar Bhushan
        self._async = async
33 11d9e642 Shikhar Bhushan
        self._id = uuid1().urn
34 5858a82c Shikhar Bhushan
        self._listener = RPCReplyListener(session)
35 5858a82c Shikhar Bhushan
        self._listener.register(self._id, self)
36 3e022b7b Shikhar Bhushan
        self._reply = None
37 11d9e642 Shikhar Bhushan
        self._reply_event = Event()
38 efed7d4c Shikhar Bhushan
    
39 11d9e642 Shikhar Bhushan
    def _build(self, op, encoding='utf-8'):
40 5858a82c Shikhar Bhushan
        if isinstance(op, dict):
41 5858a82c Shikhar Bhushan
            return self.build_from_spec(self._id, op, encoding)
42 11d9e642 Shikhar Bhushan
        else:
43 3e022b7b Shikhar Bhushan
            return self.build_from_string(self._id, op, encoding)
44 efed7d4c Shikhar Bhushan
    
45 e91a5349 Shikhar Bhushan
    def _request(self, op):
46 5858a82c Shikhar Bhushan
        req = self._build(op)
47 efed7d4c Shikhar Bhushan
        self._session.send(req)
48 1d540e60 Shikhar Bhushan
        if self._async:
49 41e2ed46 Shikhar Bhushan
            return self._reply_event
50 41e2ed46 Shikhar Bhushan
        else:
51 ee4bb099 Shikhar Bhushan
            self._reply_event.wait()
52 efed7d4c Shikhar Bhushan
            self._reply.parse()
53 3e022b7b Shikhar Bhushan
            return self._reply
54 ee4bb099 Shikhar Bhushan
    
55 41e2ed46 Shikhar Bhushan
    def _set_reply(self, raw):
56 3e022b7b Shikhar Bhushan
        self._reply = RPCReply(raw)
57 41e2ed46 Shikhar Bhushan
    
58 41e2ed46 Shikhar Bhushan
    def _set_reply_event(self):
59 3e022b7b Shikhar Bhushan
        self._reply_event.set()
60 ee4bb099 Shikhar Bhushan
    
61 41e2ed46 Shikhar Bhushan
    def _delivery_hook(self):
62 41e2ed46 Shikhar Bhushan
        'For subclasses'
63 41e2ed46 Shikhar Bhushan
        pass
64 41e2ed46 Shikhar Bhushan
    
65 41e2ed46 Shikhar Bhushan
    def deliver(self, raw):
66 41e2ed46 Shikhar Bhushan
        self._set_reply(raw)
67 41e2ed46 Shikhar Bhushan
        self._delivery_hook()
68 41e2ed46 Shikhar Bhushan
        self._set_reply_event()
69 41e2ed46 Shikhar Bhushan
    
70 589b23e4 Shikhar Bhushan
    @property
71 35ad9d81 Shikhar Bhushan
    def has_reply(self):
72 3e022b7b Shikhar Bhushan
        return self._reply_event.isSet()
73 589b23e4 Shikhar Bhushan
    
74 589b23e4 Shikhar Bhushan
    @property
75 ee4bb099 Shikhar Bhushan
    def reply(self):
76 ee4bb099 Shikhar Bhushan
        return self._reply
77 ee4bb099 Shikhar Bhushan
    
78 ee4bb099 Shikhar Bhushan
    @property
79 41e2ed46 Shikhar Bhushan
    def is_async(self):
80 41e2ed46 Shikhar Bhushan
        return self._async
81 41e2ed46 Shikhar Bhushan
    
82 41e2ed46 Shikhar Bhushan
    @property
83 38a9b062 Shikhar Bhushan
    def id(self):
84 ee4bb099 Shikhar Bhushan
        return self._id
85 ee4bb099 Shikhar Bhushan
    
86 ee4bb099 Shikhar Bhushan
    @property
87 ee4bb099 Shikhar Bhushan
    def session(self):
88 ee4bb099 Shikhar Bhushan
        return self._session
89 efed7d4c Shikhar Bhushan
    
90 3e022b7b Shikhar Bhushan
    @property
91 3e022b7b Shikhar Bhushan
    def reply_event(self):
92 3e022b7b Shikhar Bhushan
        return self._reply_event
93 3e022b7b Shikhar Bhushan
    
94 11d9e642 Shikhar Bhushan
    @staticmethod
95 11d9e642 Shikhar Bhushan
    def build_from_spec(msgid, opspec, encoding='utf-8'):
96 11d9e642 Shikhar Bhushan
        "TODO: docstring"
97 11d9e642 Shikhar Bhushan
        spec = {
98 1d540e60 Shikhar Bhushan
            'tag': _('rpc'),
99 11d9e642 Shikhar Bhushan
            'attributes': {'message-id': msgid},
100 11d9e642 Shikhar Bhushan
            'children': opspec
101 11d9e642 Shikhar Bhushan
            }
102 11d9e642 Shikhar Bhushan
        return TreeBuilder(spec).to_string(encoding)
103 11d9e642 Shikhar Bhushan
    
104 11d9e642 Shikhar Bhushan
    @staticmethod
105 11d9e642 Shikhar Bhushan
    def build_from_string(msgid, opstr, encoding='utf-8'):
106 11d9e642 Shikhar Bhushan
        "TODO: docstring"
107 11d9e642 Shikhar Bhushan
        decl = '<?xml version="1.0" encoding="%s"?>' % encoding
108 5858a82c Shikhar Bhushan
        doc = (u'<rpc message-id="%s" xmlns="%s">%s</rpc>' %
109 11d9e642 Shikhar Bhushan
               (msgid, BASE_NS, opstr)).encode(encoding)
110 5858a82c Shikhar Bhushan
        return '%s%s' % (decl, doc)
111 3e022b7b Shikhar Bhushan
112 3e022b7b Shikhar Bhushan
113 3e022b7b Shikhar Bhushan
class RPCReplyListener(Listener):
114 3e022b7b Shikhar Bhushan
    
115 3e022b7b Shikhar Bhushan
    # TODO - determine if need locking
116 3e022b7b Shikhar Bhushan
    
117 3e022b7b Shikhar Bhushan
    # one instance per subject    
118 3e022b7b Shikhar Bhushan
    def __new__(cls, subject):
119 3e022b7b Shikhar Bhushan
        instance = subject.get_listener_instance(cls)
120 3e022b7b Shikhar Bhushan
        if instance is None:
121 3e022b7b Shikhar Bhushan
            instance = object.__new__(cls)
122 3e022b7b Shikhar Bhushan
            instance._id2rpc = WeakValueDictionary()
123 3e022b7b Shikhar Bhushan
            instance._errback = None
124 3e022b7b Shikhar Bhushan
            subject.add_listener(instance)
125 3e022b7b Shikhar Bhushan
        return instance
126 3e022b7b Shikhar Bhushan
    
127 3e022b7b Shikhar Bhushan
    def __str__(self):
128 3e022b7b Shikhar Bhushan
        return 'RPCReplyListener'
129 3e022b7b Shikhar Bhushan
    
130 3e022b7b Shikhar Bhushan
    def set_errback(self, errback):
131 3e022b7b Shikhar Bhushan
        self._errback = errback
132 3e022b7b Shikhar Bhushan
133 41e2ed46 Shikhar Bhushan
    def register(self, id, rpc):
134 41e2ed46 Shikhar Bhushan
        self._id2rpc[id] = rpc
135 3e022b7b Shikhar Bhushan
    
136 3e022b7b Shikhar Bhushan
    def callback(self, root, raw):
137 3e022b7b Shikhar Bhushan
        tag, attrs = root
138 3e022b7b Shikhar Bhushan
        if __(tag) != 'rpc-reply':
139 3e022b7b Shikhar Bhushan
            return
140 3e022b7b Shikhar Bhushan
        for key in attrs:
141 3e022b7b Shikhar Bhushan
            if __(key) == 'message-id':
142 3e022b7b Shikhar Bhushan
                id = attrs[key]
143 3e022b7b Shikhar Bhushan
                try:
144 3e022b7b Shikhar Bhushan
                    rpc = self._id2rpc[id]
145 3e022b7b Shikhar Bhushan
                    rpc.deliver(raw)
146 41e2ed46 Shikhar Bhushan
                except KeyError:
147 41e2ed46 Shikhar Bhushan
                    logger.warning('[RPCReplyListener.callback] no RPC '
148 3e022b7b Shikhar Bhushan
                                   + 'registered for message-id: [%s]' % id)
149 41e2ed46 Shikhar Bhushan
                    logger.debug('[RPCReplyListener.callback] registered: %r '
150 41e2ed46 Shikhar Bhushan
                                 % dict(self._id2rpc))
151 41e2ed46 Shikhar Bhushan
                except Exception as e:
152 41e2ed46 Shikhar Bhushan
                    logger.debug('[RPCReplyListener.callback] error - %r' % e)
153 3e022b7b Shikhar Bhushan
                break
154 3e022b7b Shikhar Bhushan
        else:
155 3e022b7b Shikhar Bhushan
            logger.warning('<rpc-reply> without message-id received: %s' % raw)
156 3e022b7b Shikhar Bhushan
    
157 3e022b7b Shikhar Bhushan
    def errback(self, err):
158 3e022b7b Shikhar Bhushan
        if self._errback is not None:
159 1d540e60 Shikhar Bhushan
            self._errback(err)