Revision 11d9e642 ncclient/operations/listeners.py

b/ncclient/operations/listeners.py
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 Lock
16
from weakref import WeakValueDictionary
17

  
18
from . import logger
19

  
20

  
21
class RPCReplyListener(Listener):
22
    
23
    '''This is the glue between received data and the object it should be
24
    forwarded to.
25
    '''
26
    
27
    def __init__(self):
28
        # this dictionary takes care of <rpc-reply> elements received
29
        # { 'message-id': obj } dict
30
        self._id2rpc = WeakValueDictionary()
31
        # this is a more generic dict takes care of other top-level elements
32
        # that may be received, e.g. <notification>'s
33
        # {'tag': obj} dict
34
        self._tag2obj = WeakValueDictionary() 
35
        # if we receive a SessionCloseError it might not be one we want to act on
36
        self._expecting_close = False
37
        self._errback = None # error event callback
38
        self._lock = Lock()
39
    
40
    def __str__(self):
41
        return 'SessionListener'
42
    
43
    def register(self, msgid, rpc):
44
        with self._lock:
45
            self._id2rpc[msgid] = rpc
46
    
47
    def recognize(self, tag, obj):
48
        with self._lock:
49
            self._tag2obj[tag] = obj
50
    
51
    def expect_close(self):
52
        self._expecting_close = True
53
    
54
    @property
55
    def _recognized_elements(self):
56
        elems = q_rpcreply
57
        with self._lock:
58
            elems.extend(self._tag2obj.keys())
59
        return elems
60
    
61
    def set_errback(self, errback):
62
        self._errback = errback
63
    
64
    def received(self, raw):
65
        res = RootParser.parse(raw, self._recognized_elements)
66
        if res is not None:
67
            tag, attrs = res # unpack
68
        else:
69
            return
70
        logger.debug('SessionListener.reply: parsed (%r, %r)' % res)
71
        try:
72
            obj = None
73
            if tag in q_rpcreply:
74
                for key in attrs:
75
                    if __(key) == 'message-id':
76
                        id = attrs[key]
77
                        break
78
                else:
79
                    logger.warning('<rpc-reply> without message-id received: %s'
80
                                   % raw)
81
                obj = self._id2rpc.get(id, None)
82
            else:
83
                obj = self._tag2obj.get(tag, None)
84
            if obj is not None:
85
                obj.deliver(raw)
86
        except Exception as e:
87
            logger.warning('SessionListener.reply: %r' % e)
88
    
89
    def error(self, err):
90
        from ncclient.transport.errors import SessionCloseError
91
        act = True
92
        if isinstance(err, SessionCloseError):
93
            logger.debug('session closed, expecting_close=%s' %
94
                         self._expecting_close)
95
            if self._expecting_close:
96
                act = False
97
        if act:
98
            logger.error('SessionListener.error: %r' % err)
99
            if self._errback is not None:
100
                errback(err)
101

  
102

  
103
class NotificationListener(Listener):
104
    
105
    pass

Also available in: Unified diff