VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/python/server/policy.py@ 78394

Last change on this file since 78394 was 59824, checked in by vboxsync, 9 years ago

python/server/policy.py: fix syntax incompatibility between python3 and python2

  • Property svn:eol-style set to native
File size: 17.6 KB
Line 
1# ***** BEGIN LICENSE BLOCK *****
2# Version: MPL 1.1/GPL 2.0/LGPL 2.1
3#
4# The contents of this file are subject to the Mozilla Public License Version
5# 1.1 (the "License"); you may not use this file except in compliance with
6# the License. You may obtain a copy of the License at
7# http://www.mozilla.org/MPL/
8#
9# Software distributed under the License is distributed on an "AS IS" basis,
10# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11# for the specific language governing rights and limitations under the
12# License.
13#
14# The Original Code is Python XPCOM language bindings.
15#
16# The Initial Developer of the Original Code is
17# ActiveState Tool Corp.
18# Portions created by the Initial Developer are Copyright (C) 2001
19# the Initial Developer. All Rights Reserved.
20#
21# Contributor(s):
22# Mark Hammond <[email protected]> (original author)
23#
24# Alternatively, the contents of this file may be used under the terms of
25# either the GNU General Public License Version 2 or later (the "GPL"), or
26# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27# in which case the provisions of the GPL or the LGPL are applicable instead
28# of those above. If you wish to allow use of your version of this file only
29# under the terms of either the GPL or the LGPL, and not to allow others to
30# use your version of this file under the terms of the MPL, indicate your
31# decision by deleting the provisions above and replace them with the notice
32# and other provisions required by the GPL or the LGPL. If you do not delete
33# the provisions above, a recipient may use your version of this file under
34# the terms of any one of the MPL, the GPL or the LGPL.
35#
36# ***** END LICENSE BLOCK *****
37
38from xpcom import xpcom_consts, _xpcom, client, nsError, logger
39from xpcom import ServerException, COMException
40import xpcom
41import xpcom.server
42import operator
43import types
44import logging
45import sys
46
47# Python 3 hacks:
48if sys.version_info[0] >= 3:
49 long = int # pylint: disable=W0622,C0103
50
51
52IID_nsISupports = _xpcom.IID_nsISupports
53IID_nsIVariant = _xpcom.IID_nsIVariant
54XPT_MD_IS_GETTER = xpcom_consts.XPT_MD_IS_GETTER
55XPT_MD_IS_SETTER = xpcom_consts.XPT_MD_IS_SETTER
56
57VARIANT_INT_TYPES = xpcom_consts.VTYPE_INT8, xpcom_consts.VTYPE_INT16, xpcom_consts.VTYPE_INT32, \
58 xpcom_consts.VTYPE_UINT8, xpcom_consts.VTYPE_UINT16, xpcom_consts.VTYPE_INT32
59VARIANT_LONG_TYPES = xpcom_consts.VTYPE_INT64, xpcom_consts.VTYPE_UINT64
60VARIANT_FLOAT_TYPES = xpcom_consts.VTYPE_FLOAT, xpcom_consts.VTYPE_DOUBLE
61VARIANT_STRING_TYPES = xpcom_consts.VTYPE_CHAR, xpcom_consts.VTYPE_CHAR_STR, xpcom_consts.VTYPE_STRING_SIZE_IS, \
62 xpcom_consts.VTYPE_CSTRING
63VARIANT_UNICODE_TYPES = xpcom_consts.VTYPE_WCHAR, xpcom_consts.VTYPE_DOMSTRING, xpcom_consts.VTYPE_WSTRING_SIZE_IS, \
64 xpcom_consts.VTYPE_ASTRING
65
66_supports_primitives_map_ = {} # Filled on first use.
67
68_interface_sequence_types_ = tuple, list
69if sys.version_info[0] <= 2:
70 _string_types_ = str, unicode
71else:
72 _string_types_ = bytes, str
73XPTI_GetInterfaceInfoManager = _xpcom.XPTI_GetInterfaceInfoManager
74
75def _GetNominatedInterfaces(obj):
76 ret = getattr(obj, "_com_interfaces_", None)
77 if ret is None: return None
78 # See if the user only gave one.
79 if type(ret) not in _interface_sequence_types_:
80 ret = [ret]
81 real_ret = []
82 # For each interface, walk to the root of the interface tree.
83 iim = XPTI_GetInterfaceInfoManager()
84 for interface in ret:
85 # Allow interface name or IID.
86 interface_info = None
87 if type(interface) in _string_types_:
88 try:
89 interface_info = iim.GetInfoForName(interface)
90 except COMException:
91 pass
92 if interface_info is None:
93 # Allow a real IID
94 interface_info = iim.GetInfoForIID(interface)
95 real_ret.append(interface_info.GetIID())
96 parent = interface_info.GetParent()
97 while parent is not None:
98 parent_iid = parent.GetIID()
99 if parent_iid == IID_nsISupports:
100 break
101 real_ret.append(parent_iid)
102 parent = parent.GetParent()
103 return real_ret
104
105##
106## ClassInfo support
107##
108## We cache class infos by class
109class_info_cache = {}
110
111def GetClassInfoForObject(ob):
112 if xpcom.server.tracer_unwrap is not None:
113 ob = xpcom.server.tracer_unwrap(ob)
114 klass = ob.__class__
115 ci = class_info_cache.get(klass)
116 if ci is None:
117 ci = DefaultClassInfo(klass)
118 ci = xpcom.server.WrapObject(ci, _xpcom.IID_nsIClassInfo, bWrapClient = 0)
119 class_info_cache[klass] = ci
120 return ci
121
122class DefaultClassInfo:
123 _com_interfaces_ = _xpcom.IID_nsIClassInfo
124 def __init__(self, klass):
125 self.klass = klass
126 self.contractID = getattr(klass, "_reg_contractid_", None)
127 self.classDescription = getattr(klass, "_reg_desc_", None)
128 self.classID = getattr(klass, "_reg_clsid_", None)
129 self.implementationLanguage = 3 # Python - avoid lookups just for this
130 self.flags = 0 # what to do here??
131 self.interfaces = None
132
133 def get_classID(self):
134 if self.classID is None:
135 raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED, "Class '%r' has no class ID" % (self.klass,))
136 return self.classID
137
138 def getInterfaces(self):
139 if self.interfaces is None:
140 self.interfaces = _GetNominatedInterfaces(self.klass)
141 return self.interfaces
142
143 def getHelperForLanguage(self, language):
144 return None # Not sure what to do here.
145
146class DefaultPolicy:
147 def __init__(self, instance, iid):
148 self._obj_ = instance
149 self._nominated_interfaces_ = ni = _GetNominatedInterfaces(instance)
150 self._iid_ = iid
151 if ni is None:
152 raise ValueError("The object '%r' can not be used as a COM object" % (instance,))
153 # This is really only a check for the user
154 if __debug__:
155 if iid != IID_nsISupports and iid not in ni:
156 # The object may delegate QI.
157 delegate_qi = getattr(instance, "_query_interface_", None)
158 # Perform the actual QI and throw away the result - the _real_
159 # QI performed by the framework will set things right!
160 if delegate_qi is None or not delegate_qi(iid):
161 raise ServerException(nsError.NS_ERROR_NO_INTERFACE)
162 # Stuff for the magic interface conversion.
163 self._interface_info_ = None
164 self._interface_iid_map_ = {} # Cache - Indexed by (method_index, param_index)
165
166 def _QueryInterface_(self, com_object, iid):
167 # Framework allows us to return a single boolean integer,
168 # or a COM object.
169 if iid in self._nominated_interfaces_:
170 # We return the underlying object re-wrapped
171 # in a new gateway - which is desirable, as one gateway should only support
172 # one interface (this wont affect the users of this policy - we can have as many
173 # gateways as we like pointing to the same Python objects - the users never
174 # see what object the call came in from.
175 # NOTE: We could have simply returned the instance and let the framework
176 # do the auto-wrap for us - but this way we prevent a round-trip back into Python
177 # code just for the autowrap.
178 return xpcom.server.WrapObject(self._obj_, iid, bWrapClient = 0)
179
180 # Always support nsIClassInfo
181 if iid == _xpcom.IID_nsIClassInfo:
182 return GetClassInfoForObject(self._obj_)
183
184 # See if the instance has a QI
185 # use lower-case "_query_interface_" as win32com does, and it doesnt really matter.
186 delegate = getattr(self._obj_, "_query_interface_", None)
187 if delegate is not None:
188 # The COM object itself doesnt get passed to the child
189 # (again, as win32com doesnt). It is rarely needed
190 # (in win32com, we dont even pass it to the policy, although we have identified
191 # one place where we should - for marshalling - so I figured I may as well pass it
192 # to the policy layer here, but no all the way down to the object.
193 return delegate(iid)
194 # Finally see if we are being queried for one of the "nsISupports primitives"
195 if not _supports_primitives_map_:
196 iim = _xpcom.XPTI_GetInterfaceInfoManager()
197 for (iid_name, attr, cvt) in _supports_primitives_data_:
198 special_iid = iim.GetInfoForName(iid_name).GetIID()
199 _supports_primitives_map_[special_iid] = (attr, cvt)
200 attr, cvt = _supports_primitives_map_.get(iid, (None,None))
201 if attr is not None and hasattr(self._obj_, attr):
202 return xpcom.server.WrapObject(SupportsPrimitive(iid, self._obj_, attr, cvt), iid, bWrapClient = 0)
203 # Out of clever things to try!
204 return None # We dont support this IID.
205
206 def _MakeInterfaceParam_(self, interface, iid, method_index, mi, param_index):
207 # Wrap a "raw" interface object in a nice object. The result of this
208 # function will be passed to one of the gateway methods.
209 if iid is None:
210 # look up the interface info - this will be true for all xpcom called interfaces.
211 if self._interface_info_ is None:
212 import xpcom.xpt
213 self._interface_info_ = xpcom.xpt.Interface( self._iid_ )
214 iid = self._interface_iid_map_.get( (method_index, param_index))
215 if iid is None:
216 iid = self._interface_info_.GetIIDForParam(method_index, param_index)
217 self._interface_iid_map_[(method_index, param_index)] = iid
218 # handle nsIVariant
219 if iid == IID_nsIVariant:
220 interface = interface.QueryInterface(iid)
221 dt = interface.dataType
222 if dt in VARIANT_INT_TYPES:
223 return interface.getAsInt32()
224 if dt in VARIANT_LONG_TYPES:
225 return interface.getAsInt64()
226 if dt in VARIANT_FLOAT_TYPES:
227 return interface.getAsFloat()
228 if dt in VARIANT_STRING_TYPES:
229 return interface.getAsStringWithSize()
230 if dt in VARIANT_UNICODE_TYPES:
231 return interface.getAsWStringWithSize()
232 if dt == xpcom_consts.VTYPE_BOOL:
233 return interface.getAsBool()
234 if dt == xpcom_consts.VTYPE_INTERFACE:
235 return interface.getAsISupports()
236 if dt == xpcom_consts.VTYPE_INTERFACE_IS:
237 return interface.getAsInterface()
238 if dt == xpcom_consts.VTYPE_EMPTY or dt == xpcom_consts.VTYPE_VOID:
239 return None
240 if dt == xpcom_consts.VTYPE_ARRAY:
241 return interface.getAsArray()
242 if dt == xpcom_consts.VTYPE_EMPTY_ARRAY:
243 return []
244 if dt == xpcom_consts.VTYPE_ID:
245 return interface.getAsID()
246 # all else fails...
247 logger.warning("Warning: nsIVariant type %d not supported - returning a string", dt)
248 try:
249 return interface.getAsString()
250 except COMException:
251 logger.exception("Error: failed to get Variant as a string - returning variant object")
252 return interface
253
254 return client.Component(interface, iid)
255
256 def _CallMethod_(self, com_object, index, info, params):
257 #print "_CallMethod_", index, info, params
258 flags, name, param_descs, ret = info
259 assert ret[1][0] == xpcom_consts.TD_UINT32, "Expected an nsresult (%s)" % (ret,)
260 if XPT_MD_IS_GETTER(flags):
261 # Look for a function of that name
262 func = getattr(self._obj_, "get_" + name, None)
263 if func is None:
264 assert len(param_descs)==1 and len(params)==0, "Can only handle a single [out] arg for a default getter"
265 ret = getattr(self._obj_, name) # Let attribute error go here!
266 else:
267 ret = func(*params)
268 return 0, ret
269 elif XPT_MD_IS_SETTER(flags):
270 # Look for a function of that name
271 func = getattr(self._obj_, "set_" + name, None)
272 if func is None:
273 assert len(param_descs)==1 and len(params)==1, "Can only handle a single [in] arg for a default setter"
274 setattr(self._obj_, name, params[0]) # Let attribute error go here!
275 else:
276 func(*params)
277 return 0
278 else:
279 # A regular method.
280 func = getattr(self._obj_, name)
281 return 0, func(*params)
282
283 def _doHandleException(self, func_name, exc_info):
284 exc_val = exc_info[1]
285 is_server_exception = isinstance(exc_val, ServerException)
286 if is_server_exception:
287 # When a component raised an explicit COM exception, it is
288 # considered 'normal' - however, we still write a debug log
289 # record to help track these otherwise silent exceptions.
290
291 # Note that Python 2.3 does not allow an explicit exc_info tuple
292 # and passing 'True' will not work as there is no exception pending.
293 # Trick things!
294 if logger.isEnabledFor(logging.DEBUG):
295 try:
296 if sys.version_info[0] <= 2:
297 exec('raise exc_info[0], exc_info[1], exc_info[2]')
298 else:
299 raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])
300 except:
301 logger.debug("'%s' raised COM Exception %s",
302 func_name, exc_val, exc_info = 1)
303 return exc_val.errno
304 # Unhandled exception - always print a warning and the traceback.
305 # As above, trick the logging module to handle Python 2.3
306 try:
307 if sys.version_info[0] <= 2:
308 exec('raise exc_info[0], exc_info[1], exc_info[2]')
309 else:
310 raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])
311 except:
312 logger.exception("Unhandled exception calling '%s'", func_name)
313 return nsError.NS_ERROR_FAILURE
314
315 # Called whenever an unhandled Python exception is detected as a result
316 # of _CallMethod_ - this exception may have been raised during the _CallMethod_
317 # invocation, or after its return, but when unpacking the results
318 # eg, type errors, such as a Python integer being used as a string "out" param.
319 def _CallMethodException_(self, com_object, index, info, params, exc_info):
320 # Later we may want to have some smart "am I debugging" flags?
321 # Or maybe just delegate to the actual object - it's probably got the best
322 # idea what to do with them!
323 flags, name, param_descs, ret = info
324 exc_typ, exc_val, exc_tb = exc_info
325 # use the xpt module to get a better repr for the method.
326 # But if we fail, ignore it!
327 try:
328 import xpcom.xpt
329 m = xpcom.xpt.Method(info, index, None)
330 func_repr = m.Describe().lstrip()
331 except COMException:
332 func_repr = "%s(%r)" % (name, param_descs)
333 except:
334 # any other errors are evil!? Log it
335 self._doHandleException("<building method repr>", sys.exc_info())
336 # And fall through to logging the original error.
337 return self._doHandleException(func_repr, exc_info)
338
339 # Called whenever a gateway fails due to anything other than _CallMethod_.
340 # Really only used for the component loader etc objects, so most
341 # users should never see exceptions triggered here.
342 def _GatewayException_(self, name, exc_info):
343 return self._doHandleException(name, exc_info)
344
345if sys.version_info[0] <= 2:
346 _supports_primitives_data_ = [
347 ("nsISupportsCString", "__str__", str),
348 ("nsISupportsString", "__unicode__", unicode),
349 ("nsISupportsPRUint64", "__long__", long),
350 ("nsISupportsPRInt64", "__long__", long),
351 ("nsISupportsPRUint32", "__int__", int),
352 ("nsISupportsPRInt32", "__int__", int),
353 ("nsISupportsPRUint16", "__int__", int),
354 ("nsISupportsPRInt16", "__int__", int),
355 ("nsISupportsPRUint8", "__int__", int),
356 ("nsISupportsPRBool", "__nonzero__", operator.truth),
357 ("nsISupportsDouble", "__float__", float),
358 ("nsISupportsFloat", "__float__", float),
359 ]
360else:
361 _supports_primitives_data_ = [
362 ("nsISupportsCString", "__str__", str),
363 ("nsISupportsString", "__unicode__", str),
364 ("nsISupportsPRUint64", "__long__", int),
365 ("nsISupportsPRInt64", "__long__", int),
366 ("nsISupportsPRUint32", "__int__", int),
367 ("nsISupportsPRInt32", "__int__", int),
368 ("nsISupportsPRUint16", "__int__", int),
369 ("nsISupportsPRInt16", "__int__", int),
370 ("nsISupportsPRUint8", "__int__", int),
371 ("nsISupportsPRBool", "__nonzero__", operator.truth),
372 ("nsISupportsDouble", "__float__", float),
373 ("nsISupportsFloat", "__float__", float),
374 ]
375
376# Support for the nsISupports primitives:
377class SupportsPrimitive:
378 _com_interfaces_ = ["nsISupports"]
379 def __init__(self, iid, base_ob, attr_name, converter):
380 self.iid = iid
381 self.base_ob = base_ob
382 self.attr_name = attr_name
383 self.converter = converter
384 def _query_interface_(self, iid):
385 if iid == self.iid:
386 return 1
387 return None
388 def get_data(self):
389 method = getattr(self.base_ob, self.attr_name)
390 val = method()
391 return self.converter(val)
392 def set_data(self, val):
393 raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED)
394 def toString(self):
395 return str(self.get_data())
396
397def _shutdown():
398 class_info_cache.clear()
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette