Statistics
| Branch: | Tag: | Revision:

root / ncclient / operations / rpc / rpc.py @ cc9af1c3

History | View | Annotate | Download (3.3 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 WeakValueDictionary
18

    
19
from ncclient.content import XMLConverter
20
from ncclient.content import qualify as _
21
from ncclient.content import unqualify as __
22
from ncclient.glue import Listener
23

    
24
from listener import RPCReplyListener
25
from reply import RPCReply
26

    
27
import logging
28
logger = logging.getLogger('ncclient.rpc')
29

    
30
class RPC(object):
31
    
32
    DEPENDS = []
33
    REPLY_CLS = RPCReply
34
    
35
    def __init__(self, session, async=False, timeout=None):
36
        if not session.can_pipeline:
37
            raise UserWarning('Asynchronous mode not supported for this device/session')
38
        self._session = session
39
        try:
40
            for cap in self.DEPENDS:
41
                self._assert(cap)
42
        except AttributeError:
43
            pass        
44
        self._async = async
45
        self._timeout = timeout
46
        self._id = uuid1().urn
47
        self._listener = RPCReplyListener(session)
48
        self._listener.register(self._id, self)
49
        self._reply = None
50
        self._reply_event = Event()
51
    
52
    def _build(self, opspec, encoding='utf-8'):
53
        "TODO: docstring"
54
        spec = {
55
            'tag': _('rpc'),
56
            'attributes': {'message-id': self._id},
57
            'subtree': opspec
58
            }
59
        return XMLConverter(spec).to_string(encoding)
60
    
61
    def _request(self, op):
62
        req = self._build(op)
63
        self._session.send(req)
64
        if self._async:
65
            return self._reply_event
66
        else:
67
            self._reply_event.wait(self._timeout)
68
            if self._reply_event.isSet():
69
                self._reply.parse()
70
                return self._reply
71
            else:
72
                raise ReplyTimeoutError
73
    
74
    def request(self):
75
        return self._request(self.SPEC)
76
    
77
    def _delivery_hook(self):
78
        'For subclasses'
79
        pass
80
    
81
    def _assert(self, capability):
82
        if capability not in self._session.server_capabilities:
83
            raise MissingCapabilityError('Server does not support [%s]' % cap)
84
    
85
    def deliver(self, raw):
86
        self._reply = self.REPLY_CLS(raw)
87
        self._delivery_hook()
88
        self._reply_event.set()
89
    
90
    @property
91
    def has_reply(self):
92
        return self._reply_event.isSet()
93
    
94
    @property
95
    def reply(self):
96
        return self._reply
97
    
98
    @property
99
    def id(self):
100
        return self._id
101
    
102
    @property
103
    def session(self):
104
        return self._session
105
    
106
    @property
107
    def reply_event(self):
108
        return self._reply_event
109
    
110
    def set_async(self, bool): self._async = bool
111
    async = property(fget=lambda self: self._async, fset=set_async)
112
    
113
    def set_timeout(self, timeout): self._timeout = timeout
114
    timeout = property(fget=lambda self: self._timeout, fset=set_timeout)