1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """
16 Provides RMI dispatcher classes.
17 """
18
19 import sys
20 import traceback as tb
21 from pulp.messaging import *
22 from pulp.messaging.decorators import mayinvoke
23 from logging import getLogger
24
25
26 log = getLogger(__name__)
30 """
31 Target class not found.
32 """
33
36
39 """
40 Target method not found.
41 """
42
44 message = 'method %s.%s(), not found' % (classname, method)
45 Exception.__init__(self, message)
46
49 """
50 Permission denied or not visible.
51 """
52
54 message = 'method %s.%s(), not permitted' % (classname, method)
55 Exception.__init__(self, message)
56
59 """
60 Return envelope.
61 """
62
63 @classmethod
65 """
66 Return successful
67 @param x: The returned value.
68 @type x: any
69 @return: A return envelope.
70 @rtype: L{Return}
71 """
72 return Return(retval=x)
73
74 @classmethod
76 """
77 Return raised exception.
78 @return: A return envelope.
79 @rtype: L{Return}
80 """
81 info = sys.exc_info()
82 ex = '\n'.join(tb.format_exception(*info))
83 return Return(exval=ex)
84
86 """
87 Test whether the return indicates success.
88 @return: True when indicates success.
89 @rtype: bool
90 """
91 return ( 'retval' in self )
92
94 """
95 Test whether the return indicates failure.
96 @return: True when indicates failure.
97 @rtype: bool
98 """
99 return ( not self.succeeded() )
100
103 """
104 An RMI request envelope.
105 """
106 pass
107
108
109 -class RMI(object):
110 """
111 The RMI object performs the invocation.
112 @ivar request: The request envelope.
113 @type request: L{Request}
114 @ivar catalog: A dict of class mappings.
115 @type catalog: dict
116 """
117
119 """
120 @param request: The request envelope.
121 @type request: L{Request}
122 @param catalog: A dict of class mappings.
123 @type catalog: dict
124 """
125 self.request = request
126 self.catalog = catalog
127
129 """
130 Resolve the class/method in the request.
131 @return: A tuple (inst, method)
132 @rtype: tuple
133 """
134 inst = self.getclass()
135 method = self.getmethod(inst)
136 return (inst, method)
137
139 """
140 Get an instance of the class specified in
141 the request using the catalog.
142 @return: An instance of the class.
143 @rtype: object
144 """
145 key = self.request.classname
146 inst = self.catalog.get(key, None)
147 if inst is None:
148 raise ClassNotFound(key)
149 return inst()
150
152 """
153 Get method of the class specified in the request.
154 Ensures that remote invocation is permitted.
155 @return: The requested method.
156 @rtype: instancemethod
157 """
158 cn, fn = \
159 (self.request.classname,
160 self.request.method)
161 if hasattr(inst, fn):
162 method = getattr(inst, fn)
163 if not mayinvoke(method):
164 raise NotPermitted(cn, fn)
165 return method
166 else:
167 raise MethodNotFound(cn, fn)
168
170 """
171 Invoke the method.
172 @return: The invocation result.
173 @rtype: L{Return}
174 """
175 args, keywords = \
176 (self.request.args,
177 self.request.kws)
178 try:
179 inst, method = self.resolve()
180 retval = method(*args, **keywords)
181 return Return.succeed(retval)
182 except:
183 return Return.exception()
184
186 return str(self.request)
187
190
193 """
194 The remote invocation dispatcher.
195 @ivar classes: The (catalog) of target classes.
196 @type classes: list
197 """
198
200 """
201 """
202 self.classes = {}
203
205 """
206 Dispatch the requested RMI.
207 @param request: A request.
208 @type request: L{Request}
209 @return: The result.
210 @rtype: any
211 """
212 request = Request(request)
213 rmi = RMI(request, self.classes)
214 log.info('dispatching:%s', rmi)
215 return rmi()
216
218 """
219 Register classes exposed as RMI targets.
220 @param classes: A list of classes
221 @type classes: [cls,..]
222 @return self
223 @rtype: L{Dispatcher}
224 """
225 for cls in classes:
226 self.classes[cls.__name__] = cls
227 return self
228