VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/python/components.py@ 93585

Last change on this file since 93585 was 90618, checked in by vboxsync, 3 years ago

libs/XPCOM: Implemented _query_interface_ for our ShutdownObserver object (based on nsIObserver) so that the interface check in the DefaultPolicy initialization will pass. bugref:10079

  • Property svn:eol-style set to native
File size: 9.8 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 the 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) 2000, 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
38# This module provides the JavaScript "components" interface
39from . import xpt
40import xpcom
41import xpcom._xpcom as _xpcom
42import xpcom.client
43import xpcom.server
44
45StringTypes = [bytes, str]
46
47def _get_good_iid(iid):
48 if iid is None:
49 iid = _xpcom.IID_nsISupports
50 elif type(iid) in StringTypes and len(iid)>0 and iid[0] != "{":
51 iid = getattr(interfaces, iid)
52 return iid
53
54# The "manager" object.
55manager = xpcom.client.Component(_xpcom.GetComponentManager(), _xpcom.IID_nsIComponentManager)
56
57# The component registrar
58registrar = xpcom.client.Component(_xpcom.GetComponentManager(), _xpcom.IID_nsIComponentRegistrar)
59
60# The "interfaceInfoManager" object - JS doesnt have this.
61interfaceInfoManager = _xpcom.XPTI_GetInterfaceInfoManager()
62
63# The serviceManager - JS doesnt have this either!
64serviceManager = _xpcom.GetServiceManager()
65
66# The "Exception" object
67Exception = xpcom.COMException
68
69# Base class for our collections.
70# It appears that all objects supports "." and "[]" notation.
71# eg, "interface.nsISupports" or interfaces["nsISupports"]
72class _ComponentCollection:
73 # Bases are to over-ride 2 methods.
74 # _get_one(self, name) - to return one object by name
75 # _build_dict - to return a dictionary which provide access into
76 def __init__(self):
77 self._dict_data = None
78 def keys(self):
79 if self._dict_data is None:
80 self._dict_data = self._build_dict()
81 return list(self._dict_data.keys())
82 def items(self):
83 if self._dict_data is None:
84 self._dict_data = self._build_dict()
85 return list(self._dict_data.items())
86 def values(self):
87 if self._dict_data is None:
88 self._dict_data = self._build_dict()
89 return list(self._dict_data.values())
90# def has_key(self, key):
91# if self._dict_data is None:
92# self._dict_data = self._build_dict()
93# return self._dict_data.has_key(key)
94
95 def __len__(self):
96 if self._dict_data is None:
97 self._dict_data = self._build_dict()
98 return len(self._dict_data)
99
100 def __getattr__(self, attr):
101 if self._dict_data is not None and attr in self._dict_data:
102 return self._dict_data[attr]
103 return self._get_one(attr)
104 def __getitem__(self, item):
105 if self._dict_data is not None and item in self._dict_data:
106 return self._dict_data[item]
107 return self._get_one(item)
108
109_constants_by_iid_map = {}
110
111class _Interface:
112 # An interface object.
113 def __init__(self, name, iid):
114 # Bypass self.__setattr__ when initializing attributes.
115 d = self.__dict__
116 d['_iidobj_'] = iid # Allows the C++ framework to treat this as a native IID.
117 d['name'] = name
118 def __cmp__(self, other):
119 this_iid = self._iidobj_
120 other_iid = getattr(other, "_iidobj_", other)
121 return cmp(this_iid, other_iid)
122 def __eq__(self, other):
123 this_iid = self._iidobj_
124 other_iid = getattr(other, "_iidobj_", other)
125 return this_iid == other_iid
126 def __hash__(self):
127 return hash(self._iidobj_)
128 def __str__(self):
129 return str(self._iidobj_)
130 def __getitem__(self, item):
131 raise TypeError("components.interface objects are not subscriptable")
132 def __setitem__(self, item, value):
133 raise TypeError("components.interface objects are not subscriptable")
134 def __setattr__(self, attr, value):
135 raise AttributeError("Can not set attributes on components.Interface objects")
136 def __getattr__(self, attr):
137 # Support constants as attributes.
138 c = _constants_by_iid_map.get(self._iidobj_)
139 if c is None:
140 c = {}
141 i = xpt.Interface(self._iidobj_)
142 for c_ob in i.constants:
143 c[c_ob.name] = c_ob.value
144 _constants_by_iid_map[self._iidobj_] = c
145 if attr in c:
146 return c[attr]
147 raise AttributeError("'%s' interfaces do not define a constant '%s'" % (self.name, attr))
148
149
150class _Interfaces(_ComponentCollection):
151 def _get_one(self, name):
152 try:
153 item = interfaceInfoManager.GetInfoForName(name)
154 except xpcom.COMException as why:
155 # Present a better exception message, and give a more useful error code.
156 from . import nsError
157 raise xpcom.COMException(nsError.NS_ERROR_NO_INTERFACE, "The interface '%s' does not exist" % (name,))
158 return _Interface(item.GetName(), item.GetIID())
159
160 def _build_dict(self):
161 ret = {}
162 enum = interfaceInfoManager.EnumerateInterfaces()
163 while not enum.IsDone():
164 # Call the Python-specific FetchBlock, to keep the loop in C.
165 items = enum.FetchBlock(500, _xpcom.IID_nsIInterfaceInfo)
166 # This shouldnt be necessary, but appears to be so!
167 for item in items:
168 ret[item.GetName()] = _Interface(item.GetName(), item.GetIID())
169 return ret
170
171# And the actual object people use.
172interfaces = _Interfaces()
173
174del _Interfaces # Keep our namespace clean.
175
176#################################################
177class _Class:
178 def __init__(self, contractid):
179 self.contractid = contractid
180 def __getattr__(self, attr):
181 if attr == "clsid":
182 rc = registrar.contractIDToCID(self.contractid)
183 # stash it away - it can never change!
184 self.clsid = rc
185 return rc
186 raise AttributeError("%s class has no attribute '%s'" % (self.contractid, attr))
187 def createInstance(self, iid = None):
188 import xpcom.client
189 try:
190 return xpcom.client.Component(self.contractid, _get_good_iid(iid))
191 except xpcom.COMException as details:
192 from . import nsError
193 # Handle "no such component" in a cleaner way for the user.
194 if details.errno == nsError.NS_ERROR_FACTORY_NOT_REGISTERED:
195 raise xpcom.COMException(details.errno, "No such component '%s'" % (self.contractid,))
196 raise # Any other exception reraise.
197 def getService(self, iid = None):
198 return serviceManager.getServiceByContractID(self.contractid, _get_good_iid(iid))
199
200class _Classes(_ComponentCollection):
201 def __init__(self):
202 _ComponentCollection.__init__(self)
203 def _get_one(self, name):
204 # XXX - Need to check the contractid is valid!
205 return _Class(name)
206
207 def _build_dict(self):
208 ret = {}
209 enum = registrar.enumerateContractIDs()
210 while enum.hasMoreElements():
211 # Call the Python-specific FetchBlock, to keep the loop in C.
212 items = enum.fetchBlock(2000, _xpcom.IID_nsISupportsCString)
213 for item in items:
214 name = str(item.data)
215 ret[name] = _Class(name)
216 return ret
217
218classes = _Classes()
219
220del _Classes
221
222del _ComponentCollection
223
224# The ID function
225ID = _xpcom.ID
226
227# A helper to cleanup our namespace as xpcom shuts down.
228class _ShutdownObserver:
229 _com_interfaces_ = interfaces.nsIObserver
230 def observe(self, service, topic, extra):
231 global manager, registrar, classes, interfaces, interfaceInfoManager, _shutdownObserver, serviceManager, _constants_by_iid_map
232 manager = registrar = classes = interfaces = interfaceInfoManager = _shutdownObserver = serviceManager = _constants_by_iid_map = None
233 xpcom.client._shutdown()
234 xpcom.server._shutdown()
235 def _query_interface_(self, iid): # VBox: Needed so that the interface check in the DefaultPolicy initialization will pass; @bugref{10079}.
236 if iid == interfaces.nsIObserver:
237 return 1
238 return None
239
240svc = _xpcom.GetServiceManager().getServiceByContractID("@mozilla.org/observer-service;1", interfaces.nsIObserverService)
241# Observers will be QI'd for a weak-reference, so we must keep the
242# observer alive ourself, and must keep the COM object alive,
243# _not_ just the Python instance!!!
244_shutdownObserver = xpcom.server.WrapObject(_ShutdownObserver(), interfaces.nsIObserver)
245# Say we want a weak ref due to an assertion failing. If this is fixed, we can pass 0,
246# and remove the lifetime hacks above! See http://bugzilla.mozilla.org/show_bug.cgi?id=99163
247svc.addObserver(_shutdownObserver, "xpcom-shutdown", 1)
248del svc, _ShutdownObserver
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