Statistics
| Branch: | Tag: | Revision:

root / ncclient / transport / session.py @ 2c3d3e27

History | View | Annotate | Download (4.7 kB)

1 d095a59e Shikhar Bhushan
# Copyright 2009 Shikhar Bhushan
2 d095a59e Shikhar Bhushan
#
3 d095a59e Shikhar Bhushan
# Licensed under the Apache License, Version 2.0 (the "License");
4 d095a59e Shikhar Bhushan
# you may not use this file except in compliance with the License.
5 d095a59e Shikhar Bhushan
# You may obtain a copy of the License at
6 d095a59e Shikhar Bhushan
#
7 d095a59e Shikhar Bhushan
#    http://www.apache.org/licenses/LICENSE-2.0
8 d095a59e Shikhar Bhushan
#
9 d095a59e Shikhar Bhushan
# Unless required by applicable law or agreed to in writing, software
10 d095a59e Shikhar Bhushan
# distributed under the License is distributed on an "AS IS" BASIS,
11 d095a59e Shikhar Bhushan
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 d095a59e Shikhar Bhushan
# See the License for the specific language governing permissions and
13 d095a59e Shikhar Bhushan
# limitations under the License.
14 d095a59e Shikhar Bhushan
15 d6688264 Shikhar Bhushan
from Queue import Queue
16 4de03d63 Shikhar Bhushan
from threading import Thread, Lock, Event
17 e91a5349 Shikhar Bhushan
18 2f8bc438 Shikhar Bhushan
from ncclient.capabilities import Capabilities
19 4de03d63 Shikhar Bhushan
from ncclient.content import parse_root
20 d095a59e Shikhar Bhushan
21 c35cebbf Shikhar Bhushan
from hello import HelloHandler
22 d095a59e Shikhar Bhushan
23 41e2ed46 Shikhar Bhushan
import logging
24 41e2ed46 Shikhar Bhushan
logger = logging.getLogger('ncclient.transport.session')
25 41e2ed46 Shikhar Bhushan
26 4de03d63 Shikhar Bhushan
27 a14c36f9 Shikhar Bhushan
class Session(Thread):
28 d095a59e Shikhar Bhushan
    
29 68006767 Shikhar Bhushan
    "TODO: docstring"
30 68006767 Shikhar Bhushan
    
31 2f8bc438 Shikhar Bhushan
    def __init__(self, capabilities):
32 41e2ed46 Shikhar Bhushan
        "Subclass constructor should call this"
33 a14c36f9 Shikhar Bhushan
        Thread.__init__(self)
34 a14c36f9 Shikhar Bhushan
        self.setDaemon(True)
35 a14c36f9 Shikhar Bhushan
        self._listeners = set() # TODO(?) weakref
36 a14c36f9 Shikhar Bhushan
        self._lock = Lock()
37 1d540e60 Shikhar Bhushan
        self.setName('session')
38 d6688264 Shikhar Bhushan
        self._q = Queue()
39 2f8bc438 Shikhar Bhushan
        self._client_capabilities = capabilities
40 d095a59e Shikhar Bhushan
        self._server_capabilities = None # yet
41 d095a59e Shikhar Bhushan
        self._id = None # session-id
42 d095a59e Shikhar Bhushan
        self._connected = False # to be set/cleared by subclass implementation
43 41e2ed46 Shikhar Bhushan
        logger.debug('%r created: client_capabilities=%r' %
44 41e2ed46 Shikhar Bhushan
                     (self, self._client_capabilities))
45 d095a59e Shikhar Bhushan
    
46 a14c36f9 Shikhar Bhushan
    def _dispatch_message(self, raw):
47 a14c36f9 Shikhar Bhushan
        "TODO: docstring"
48 a14c36f9 Shikhar Bhushan
        try:
49 a14c36f9 Shikhar Bhushan
            root = parse_root(raw)
50 a14c36f9 Shikhar Bhushan
        except Exception as e:
51 a14c36f9 Shikhar Bhushan
            logger.error('error parsing dispatch message: %s' % e)
52 a14c36f9 Shikhar Bhushan
            return
53 a14c36f9 Shikhar Bhushan
        with self._lock:
54 a14c36f9 Shikhar Bhushan
            listeners = list(self._listeners)
55 a14c36f9 Shikhar Bhushan
        for l in listeners:
56 a14c36f9 Shikhar Bhushan
            logger.debug('dispatching message to %r' % l)
57 a14c36f9 Shikhar Bhushan
            try:
58 a14c36f9 Shikhar Bhushan
                l.callback(root, raw)
59 a14c36f9 Shikhar Bhushan
            except Exception as e:
60 a14c36f9 Shikhar Bhushan
                logger.warning('[error] %r' % e)
61 a14c36f9 Shikhar Bhushan
    
62 a14c36f9 Shikhar Bhushan
    def _dispatch_error(self, err):
63 a14c36f9 Shikhar Bhushan
        "TODO: docstring"
64 a14c36f9 Shikhar Bhushan
        with self._lock:
65 a14c36f9 Shikhar Bhushan
            listeners = list(self._listeners)
66 a14c36f9 Shikhar Bhushan
        for l in listeners:
67 a14c36f9 Shikhar Bhushan
            logger.debug('dispatching error to %r' % l)
68 a14c36f9 Shikhar Bhushan
            try:
69 a14c36f9 Shikhar Bhushan
                l.errback(err)
70 a14c36f9 Shikhar Bhushan
            except Exception as e:
71 a14c36f9 Shikhar Bhushan
                logger.warning('error %r' % e)
72 a14c36f9 Shikhar Bhushan
    
73 65c6a607 Shikhar Bhushan
    def _post_connect(self):
74 65c6a607 Shikhar Bhushan
        "Greeting stuff"
75 65c6a607 Shikhar Bhushan
        init_event = Event()
76 65c6a607 Shikhar Bhushan
        error = [None] # so that err_cb can bind error[0]. just how it is.
77 65c6a607 Shikhar Bhushan
        # callbacks
78 65c6a607 Shikhar Bhushan
        def ok_cb(id, capabilities):
79 65c6a607 Shikhar Bhushan
            self._id = id
80 65c6a607 Shikhar Bhushan
            self._server_capabilities = Capabilities(capabilities)
81 65c6a607 Shikhar Bhushan
            init_event.set()
82 65c6a607 Shikhar Bhushan
        def err_cb(err):
83 65c6a607 Shikhar Bhushan
            error[0] = err
84 65c6a607 Shikhar Bhushan
            init_event.set()
85 65c6a607 Shikhar Bhushan
        listener = HelloHandler(ok_cb, err_cb)
86 65c6a607 Shikhar Bhushan
        self.add_listener(listener)
87 65c6a607 Shikhar Bhushan
        self.send(HelloHandler.build(self._client_capabilities))
88 65c6a607 Shikhar Bhushan
        logger.debug('starting main loop')
89 65c6a607 Shikhar Bhushan
        self.start()
90 65c6a607 Shikhar Bhushan
        # we expect server's hello message
91 65c6a607 Shikhar Bhushan
        init_event.wait()
92 65c6a607 Shikhar Bhushan
        # received hello message or an error happened
93 65c6a607 Shikhar Bhushan
        self.remove_listener(listener)
94 65c6a607 Shikhar Bhushan
        if error[0]:
95 65c6a607 Shikhar Bhushan
            raise error[0]
96 65c6a607 Shikhar Bhushan
        logger.info('initialized: session-id=%s | server_capabilities=%s' %
97 65c6a607 Shikhar Bhushan
                     (self._id, self._server_capabilities))
98 65c6a607 Shikhar Bhushan
    
99 a14c36f9 Shikhar Bhushan
    def add_listener(self, listener):
100 a14c36f9 Shikhar Bhushan
        "TODO: docstring"
101 a14c36f9 Shikhar Bhushan
        logger.debug('installing listener %r' % listener)
102 a14c36f9 Shikhar Bhushan
        with self._lock:
103 a14c36f9 Shikhar Bhushan
            self._listeners.add(listener)
104 a14c36f9 Shikhar Bhushan
    
105 a14c36f9 Shikhar Bhushan
    def remove_listener(self, listener):
106 a14c36f9 Shikhar Bhushan
        "TODO: docstring"
107 a14c36f9 Shikhar Bhushan
        logger.debug('discarding listener %r' % listener)
108 a14c36f9 Shikhar Bhushan
        with self._lock:
109 a14c36f9 Shikhar Bhushan
            self._listeners.discard(listener)
110 a14c36f9 Shikhar Bhushan
    
111 a14c36f9 Shikhar Bhushan
    def get_listener_instance(self, cls):
112 a14c36f9 Shikhar Bhushan
        '''This is useful when we want to maintain one listener of a particular
113 a14c36f9 Shikhar Bhushan
        type per subject i.e. a multiton.
114 a14c36f9 Shikhar Bhushan
        '''
115 a14c36f9 Shikhar Bhushan
        with self._lock:
116 a14c36f9 Shikhar Bhushan
            for listener in self._listeners:
117 a14c36f9 Shikhar Bhushan
                if isinstance(listener, cls):
118 a14c36f9 Shikhar Bhushan
                    return listener
119 a14c36f9 Shikhar Bhushan
    
120 6625258b Shikhar Bhushan
    def connect(self, *args, **kwds):
121 41e2ed46 Shikhar Bhushan
        "Subclass implements"
122 d095a59e Shikhar Bhushan
        raise NotImplementedError
123 d095a59e Shikhar Bhushan
124 d095a59e Shikhar Bhushan
    def run(self):
125 41e2ed46 Shikhar Bhushan
        "Subclass implements"
126 d095a59e Shikhar Bhushan
        raise NotImplementedError
127 d095a59e Shikhar Bhushan
    
128 d6688264 Shikhar Bhushan
    def send(self, message):
129 d6688264 Shikhar Bhushan
        "TODO: docstring"
130 d6688264 Shikhar Bhushan
        logger.debug('queueing %s' % message)
131 d6688264 Shikhar Bhushan
        self._q.put(message)
132 d6688264 Shikhar Bhushan
    
133 d095a59e Shikhar Bhushan
    ### Properties
134 d095a59e Shikhar Bhushan
    
135 d095a59e Shikhar Bhushan
    @property
136 d095a59e Shikhar Bhushan
    def client_capabilities(self):
137 d095a59e Shikhar Bhushan
        return self._client_capabilities
138 d095a59e Shikhar Bhushan
    
139 d095a59e Shikhar Bhushan
    @property
140 d095a59e Shikhar Bhushan
    def server_capabilities(self):
141 d095a59e Shikhar Bhushan
        return self._server_capabilities
142 d095a59e Shikhar Bhushan
    
143 d095a59e Shikhar Bhushan
    @property
144 d095a59e Shikhar Bhushan
    def connected(self):
145 d095a59e Shikhar Bhushan
        return self._connected
146 d095a59e Shikhar Bhushan
    
147 d095a59e Shikhar Bhushan
    @property
148 d095a59e Shikhar Bhushan
    def id(self):
149 d095a59e Shikhar Bhushan
        return self._id
150 94803aaf Shikhar Bhushan
    
151 94803aaf Shikhar Bhushan
    @property
152 94803aaf Shikhar Bhushan
    def can_pipeline(self):
153 94803aaf Shikhar Bhushan
        return True