Statistics
| Branch: | Tag: | Revision:

root / ncclient / operations / rpc.py @ f0271461

History | View | Annotate | Download (4 kB)

1
# Copyright 2009 Shikhar Bhushan
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License");
4
# you may not use this file except in compliance with the License.
5
# You may obtain a copy of the License at
6
#
7
#    http://www.apache.org/licenses/LICENSE-2.0
8
#
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS,
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
# See the License for the specific language governing permissions and
13
# limitations under the License.
14

    
15
from threading import Event, Lock
16
from uuid import uuid1
17
from weakref import WeakKeyDictionary
18

    
19
from listener import SessionListener
20
from ncclient.content.builders import RPCBuilder
21
from ncclient.content.parsers import RPCReplyParser
22

    
23
class RPC:
24
    
25
    _listeners = WeakKeyDictionary()
26
    _lock = Lock()
27
    
28
    def __init__(self, session):
29
        self._session = session
30
        self._id = None
31
        self._reply = None # RPCReply
32
        self._reply_event = None
33
    
34
    @property
35
    def _listener(self):
36
        with self._lock:
37
            return self._listeners.setdefault(self._session, SessionListener())
38
    
39
    def deliver(self, raw):
40
        self._reply = RPCReply(raw)
41
        self._reply_event.set()
42
    
43
    def _do_request(self, op, reply_event=None):
44
        self._id = uuid1().urn
45
        # get the listener instance for this session
46
        # <rpc-reply> with message id will reach response_cb
47
        self._listener.register(self._id, self)
48
        # only effective the first time, transport.session.Subject internally
49
        # uses a set type for listeners
50
        self._session.add_listener(self._listener)
51
        req = RPCBuilder.build(self._id, op)
52
        self._session.send(req)
53
        if reply_event is not None: # if we were provided an Event to use
54
            self._reply_event = reply_event
55
        else: # otherwise, block till response received and return it
56
            self._reply_event = Event()
57
            self._reply_event.wait()
58
            self._reply.parse()
59
            return self._reply
60
    
61
    def request(self, *args, **kwds):
62
        raise NotImplementedError
63
    
64
    @property
65
    def has_reply(self):
66
        try:
67
            return self._reply_event.isSet()
68
        except TypeError: # reply_event is None
69
            return False
70
    
71
    @property
72
    def reply(self):
73
        return self._reply
74
    
75
    @property
76
    def id(self):
77
        return self._id
78
    
79
    @property
80
    def session(self):
81
        return self._session
82

    
83
class RPCReply:
84
    
85
    def __init__(self, raw):
86
        self._raw = raw
87
        self._parsed = False
88
        self._errs = []
89
    
90
    def __str__(self):
91
        return self._raw
92
    
93
    def parse(self):
94
        if not self._parsed:
95
            errs = RPCReplyParser.parse(self._raw)
96
            for raw, err_dict in errs:
97
                self._errs.append(RPCError(raw, err_dict))
98
            self._parsed = True
99
    
100
    @property
101
    def raw(self):
102
        return self._raw
103
    
104
    @property
105
    def parsed(self):
106
        return self._parsed
107
    
108
    @property
109
    def ok(self):
110
        return True if self._parsed and not self._errs else False
111
    
112
    @property
113
    def errors(self):
114
        return self._errs
115

    
116
class RPCError(Exception): # raise it if you like
117
    
118
    def __init__(self, raw, err_dict):
119
        self._raw = raw
120
        self._dict = err_dict
121

    
122
    def __str__(self):
123
        # TODO
124
        return self._raw
125
    
126
    def __dict__(self):
127
        return self._dict
128
    
129
    @property
130
    def raw(self):
131
        return self._raw
132
    
133
    @property
134
    def type(self):
135
        return self._dict.get('type', None)
136
    
137
    @property
138
    def severity(self):
139
        return self._dict.get('severity', None)
140
    
141
    @property
142
    def tag(self):
143
        return self._dict.get('tag', None)
144
    
145
    @property
146
    def path(self):
147
        return self._dict.get('path', None)
148
    
149
    @property
150
    def message(self):
151
        return self._dict.get('message', None)
152
    
153
    @property
154
    def info(self):
155
        return self._dict.get('info', None)