Statistics
| Branch: | Tag: | Revision:

root / ncclient / operations / rpc.py @ 1d540e60

History | View | Annotate | Download (4.1 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 ee4bb099 Shikhar Bhushan
            self._reply_event.wait()
50 efed7d4c Shikhar Bhushan
            self._reply.parse()
51 3e022b7b Shikhar Bhushan
            return self._reply
52 ee4bb099 Shikhar Bhushan
    
53 3e022b7b Shikhar Bhushan
    def deliver(self, raw):
54 3e022b7b Shikhar Bhushan
        self._reply = RPCReply(raw)
55 3e022b7b Shikhar Bhushan
        self._reply_event.set()
56 ee4bb099 Shikhar Bhushan
    
57 589b23e4 Shikhar Bhushan
    @property
58 35ad9d81 Shikhar Bhushan
    def has_reply(self):
59 3e022b7b Shikhar Bhushan
        return self._reply_event.isSet()
60 589b23e4 Shikhar Bhushan
    
61 589b23e4 Shikhar Bhushan
    @property
62 ee4bb099 Shikhar Bhushan
    def reply(self):
63 ee4bb099 Shikhar Bhushan
        return self._reply
64 ee4bb099 Shikhar Bhushan
    
65 ee4bb099 Shikhar Bhushan
    @property
66 38a9b062 Shikhar Bhushan
    def id(self):
67 ee4bb099 Shikhar Bhushan
        return self._id
68 ee4bb099 Shikhar Bhushan
    
69 ee4bb099 Shikhar Bhushan
    @property
70 ee4bb099 Shikhar Bhushan
    def session(self):
71 ee4bb099 Shikhar Bhushan
        return self._session
72 efed7d4c Shikhar Bhushan
    
73 3e022b7b Shikhar Bhushan
    @property
74 3e022b7b Shikhar Bhushan
    def reply_event(self):
75 3e022b7b Shikhar Bhushan
        return self._reply_event
76 3e022b7b Shikhar Bhushan
    
77 11d9e642 Shikhar Bhushan
    @staticmethod
78 11d9e642 Shikhar Bhushan
    def build_from_spec(msgid, opspec, encoding='utf-8'):
79 11d9e642 Shikhar Bhushan
        "TODO: docstring"
80 11d9e642 Shikhar Bhushan
        spec = {
81 1d540e60 Shikhar Bhushan
            'tag': _('rpc'),
82 11d9e642 Shikhar Bhushan
            'attributes': {'message-id': msgid},
83 11d9e642 Shikhar Bhushan
            'children': opspec
84 11d9e642 Shikhar Bhushan
            }
85 11d9e642 Shikhar Bhushan
        return TreeBuilder(spec).to_string(encoding)
86 11d9e642 Shikhar Bhushan
    
87 11d9e642 Shikhar Bhushan
    @staticmethod
88 11d9e642 Shikhar Bhushan
    def build_from_string(msgid, opstr, encoding='utf-8'):
89 11d9e642 Shikhar Bhushan
        "TODO: docstring"
90 11d9e642 Shikhar Bhushan
        decl = '<?xml version="1.0" encoding="%s"?>' % encoding
91 5858a82c Shikhar Bhushan
        doc = (u'<rpc message-id="%s" xmlns="%s">%s</rpc>' %
92 11d9e642 Shikhar Bhushan
               (msgid, BASE_NS, opstr)).encode(encoding)
93 5858a82c Shikhar Bhushan
        return '%s%s' % (decl, doc)
94 3e022b7b Shikhar Bhushan
95 3e022b7b Shikhar Bhushan
96 3e022b7b Shikhar Bhushan
class RPCReplyListener(Listener):
97 3e022b7b Shikhar Bhushan
    
98 3e022b7b Shikhar Bhushan
    # TODO - determine if need locking
99 3e022b7b Shikhar Bhushan
    
100 3e022b7b Shikhar Bhushan
    # one instance per subject    
101 3e022b7b Shikhar Bhushan
    def __new__(cls, subject):
102 3e022b7b Shikhar Bhushan
        instance = subject.get_listener_instance(cls)
103 3e022b7b Shikhar Bhushan
        if instance is None:
104 3e022b7b Shikhar Bhushan
            instance = object.__new__(cls)
105 3e022b7b Shikhar Bhushan
            instance._id2rpc = WeakValueDictionary()
106 3e022b7b Shikhar Bhushan
            instance._errback = None
107 3e022b7b Shikhar Bhushan
            subject.add_listener(instance)
108 3e022b7b Shikhar Bhushan
        return instance
109 3e022b7b Shikhar Bhushan
    
110 3e022b7b Shikhar Bhushan
    def __str__(self):
111 3e022b7b Shikhar Bhushan
        return 'RPCReplyListener'
112 3e022b7b Shikhar Bhushan
    
113 3e022b7b Shikhar Bhushan
    def set_errback(self, errback):
114 3e022b7b Shikhar Bhushan
        self._errback = errback
115 3e022b7b Shikhar Bhushan
116 3e022b7b Shikhar Bhushan
    def register(self, msgid, rpc):
117 3e022b7b Shikhar Bhushan
        self._id2rpc[msgid] = rpc
118 3e022b7b Shikhar Bhushan
    
119 3e022b7b Shikhar Bhushan
    def callback(self, root, raw):
120 3e022b7b Shikhar Bhushan
        tag, attrs = root
121 3e022b7b Shikhar Bhushan
        if __(tag) != 'rpc-reply':
122 3e022b7b Shikhar Bhushan
            return
123 3e022b7b Shikhar Bhushan
        for key in attrs:
124 3e022b7b Shikhar Bhushan
            if __(key) == 'message-id':
125 3e022b7b Shikhar Bhushan
                id = attrs[key]
126 3e022b7b Shikhar Bhushan
                try:
127 3e022b7b Shikhar Bhushan
                    rpc = self._id2rpc[id]
128 3e022b7b Shikhar Bhushan
                    rpc.deliver(raw)
129 3e022b7b Shikhar Bhushan
                except:
130 3e022b7b Shikhar Bhushan
                    logger.warning('RPCReplyListener.callback: no RPC '
131 3e022b7b Shikhar Bhushan
                                   + 'registered for message-id: [%s]' % id)
132 3e022b7b Shikhar Bhushan
                break
133 3e022b7b Shikhar Bhushan
        else:
134 3e022b7b Shikhar Bhushan
            logger.warning('<rpc-reply> without message-id received: %s' % raw)
135 3e022b7b Shikhar Bhushan
    
136 3e022b7b Shikhar Bhushan
    def errback(self, err):
137 3e022b7b Shikhar Bhushan
        logger.error('RPCReplyListener.errback: %r' % err)
138 3e022b7b Shikhar Bhushan
        if self._errback is not None:
139 1d540e60 Shikhar Bhushan
            self._errback(err)