VirtualBox

source: vbox/trunk/src/VBox/Main/glue/vboxapi.py@ 21965

Last change on this file since 21965 was 21959, checked in by vboxsync, 15 years ago

Python shell: handle subtel COM/XPCOM difference

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.8 KB
Line 
1#
2# Copyright (C) 2009 Sun Microsystems, Inc.
3#
4# This file is part of VirtualBox Open Source Edition (OSE), as
5# available from http://www.virtualbox.org. This file is free software;
6# you can redistribute it and/or modify it under the terms of the GNU
7# General Public License (GPL) as published by the Free Software
8# Foundation, in version 2 as it comes in the "COPYING" file of the
9# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
10# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
11#
12# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
13# Clara, CA 95054 USA or visit http://www.sun.com if you need
14# additional information or have any questions.
15#
16import sys,os
17import traceback
18
19VboxBinDir = os.environ.get("VBOX_PROGRAM_PATH", None)
20VboxSdkDir = os.environ.get("VBOX_SDK_PATH", None)
21
22if VboxBinDir is None:
23 # Will be set by the installer
24 VboxBinDir = "%VBOX_INSTALL_PATH%"
25
26if VboxSdkDir is None:
27 VboxSdkDir = os.path.join(VboxBinDir,"sdk")
28
29os.environ["VBOX_PROGRAM_PATH"] = VboxBinDir
30os.environ["VBOX_SDK_PATH"] = VboxSdkDir
31sys.path.append(VboxBinDir)
32
33from VirtualBox_constants import VirtualBoxReflectionInfo
34
35class PerfCollector:
36 """ This class provides a wrapper over IPerformanceCollector in order to
37 get more 'pythonic' interface.
38
39 To begin collection of metrics use setup() method.
40
41 To get collected data use query() method.
42
43 It is possible to disable metric collection without changing collection
44 parameters with disable() method. The enable() method resumes metric
45 collection.
46 """
47
48 def __init__(self, mgr, vbox):
49 """ Initializes the instance.
50
51 """
52 self.mgr = mgr
53 self.isMscom = (mgr.type == 'MSCOM')
54 self.collector = vbox.performanceCollector
55
56 def setup(self, names, objects, period, nsamples):
57 """ Discards all previously collected values for the specified
58 metrics, sets the period of collection and the number of retained
59 samples, enables collection.
60 """
61 self.collector.setupMetrics(names, objects, period, nsamples)
62
63 def enable(self, names, objects):
64 """ Resumes metric collection for the specified metrics.
65 """
66 self.collector.enableMetrics(names, objects)
67
68 def disable(self, names, objects):
69 """ Suspends metric collection for the specified metrics.
70 """
71 self.collector.disableMetrics(names, objects)
72
73 def query(self, names, objects):
74 """ Retrieves collected metric values as well as some auxiliary
75 information. Returns an array of dictionaries, one dictionary per
76 metric. Each dictionary contains the following entries:
77 'name': metric name
78 'object': managed object this metric associated with
79 'unit': unit of measurement
80 'scale': divide 'values' by this number to get float numbers
81 'values': collected data
82 'values_as_string': pre-processed values ready for 'print' statement
83 """
84 # Get around the problem with input arrays returned in output
85 # parameters (see #3953) for MSCOM.
86 if self.isMscom:
87 (values, names, objects, names_out, objects_out, units, scales, sequence_numbers,
88 indices, lengths) = self.collector.queryMetricsData(names, objects)
89 else:
90 (values, names_out, objects_out, units, scales, sequence_numbers,
91 indices, lengths) = self.collector.queryMetricsData(names, objects)
92 out = []
93 for i in xrange(0, len(names_out)):
94 scale = int(scales[i])
95 if scale != 1:
96 fmt = '%.2f%s'
97 else:
98 fmt = '%d %s'
99 out.append({
100 'name':str(names_out[i]),
101 'object':str(objects_out[i]),
102 'unit':str(units[i]),
103 'scale':scale,
104 'values':[int(values[j]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))],
105 'values_as_string':'['+', '.join([fmt % (int(values[j])/scale, units[i]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))])+']'
106 })
107 return out
108
109def ComifyName(name):
110 return name[0].capitalize()+name[1:]
111
112_COMForward = { 'getattr' : None,
113 'setattr' : None}
114
115def CustomGetAttr(self, attr):
116 # fastpath
117 if self.__class__.__dict__.get(attr) != None:
118 return self.__class__.__dict__.get(attr)
119
120 # try case-insensitivity workaround for class attributes (COM methods)
121 for k in self.__class__.__dict__.keys():
122 if k.lower() == attr.lower():
123 self.__class__.__dict__[attr] = self.__class__.__dict__[k]
124 return getattr(self, k)
125 try:
126 return _COMForward['getattr'](self,ComifyName(attr))
127 except AttributeError:
128 return _COMForward['getattr'](self,attr)
129
130def CustomSetAttr(self, attr, value):
131 try:
132 return _COMForward['setattr'](self, ComifyName(attr), value)
133 except AttributeError:
134 return _COMForward['setattr'](self, attr, value)
135
136class PlatformMSCOM:
137 # Class to fake access to constants in style of foo.bar.boo
138 class ConstantFake:
139 def __init__(self, parent, name):
140 self.__dict__['_parent'] = parent
141 self.__dict__['_name'] = name
142 self.__dict__['_consts'] = {}
143 try:
144 self.__dict__['_depth']=parent.__dict__['_depth']+1
145 except:
146 self.__dict__['_depth']=0
147 if self.__dict__['_depth'] > 4:
148 raise AttributeError
149
150 def __getattr__(self, attr):
151 import win32com
152 from win32com.client import constants
153
154 if attr.startswith("__"):
155 raise AttributeError
156
157 consts = self.__dict__['_consts']
158
159 fake = consts.get(attr, None)
160 if fake != None:
161 return fake
162 try:
163 name = self.__dict__['_name']
164 parent = self.__dict__['_parent']
165 while parent != None:
166 if parent._name is not None:
167 name = parent._name+'_'+name
168 parent = parent._parent
169
170 if name is not None:
171 name += "_" + attr
172 else:
173 name = attr
174 return win32com.client.constants.__getattr__(name)
175 except AttributeError,e:
176 fake = PlatformMSCOM.ConstantFake(self, attr)
177 consts[attr] = fake
178 return fake
179
180
181 class InterfacesWrapper:
182 def __init__(self):
183 self.__dict__['_rootFake'] = PlatformMSCOM.ConstantFake(None, None)
184
185 def __getattr__(self, a):
186 import win32com
187 from win32com.client import constants
188 if a.startswith("__"):
189 raise AttributeError
190 try:
191 return win32com.client.constants.__getattr__(a)
192 except AttributeError,e:
193 return self.__dict__['_rootFake'].__getattr__(a)
194
195 VBOX_TLB_GUID = '{46137EEC-703B-4FE5-AFD4-7C9BBBBA0259}'
196 VBOX_TLB_LCID = 0
197 VBOX_TLB_MAJOR = 1
198 VBOX_TLB_MINOR = 0
199
200 def __init__(self, params):
201 from win32com import universal
202 from win32com.client import gencache, DispatchBaseClass
203 from win32com.client import constants, getevents
204 import win32com
205 import pythoncom
206 import win32api
207 self.constants = PlatformMSCOM.InterfacesWrapper()
208 from win32con import DUPLICATE_SAME_ACCESS
209 from win32api import GetCurrentThread,GetCurrentThreadId,DuplicateHandle,GetCurrentProcess
210 pid = GetCurrentProcess()
211 self.tid = GetCurrentThreadId()
212 handle = DuplicateHandle(pid, GetCurrentThread(), pid, 0, 0, DUPLICATE_SAME_ACCESS)
213 self.handles = []
214 self.handles.append(handle)
215 _COMForward['getattr'] = DispatchBaseClass.__dict__['__getattr__']
216 DispatchBaseClass.__dict__['__getattr__'] = CustomGetAttr
217 _COMForward['setattr'] = DispatchBaseClass.__dict__['__setattr__']
218 DispatchBaseClass.__dict__['__setattr__'] = CustomSetAttr
219 win32com.client.gencache.EnsureDispatch('VirtualBox.Session')
220 win32com.client.gencache.EnsureDispatch('VirtualBox.VirtualBox')
221
222 def getSessionObject(self, vbox):
223 import win32com
224 from win32com.client import Dispatch
225 return win32com.client.Dispatch("VirtualBox.Session")
226
227 def getVirtualBox(self):
228 import win32com
229 from win32com.client import Dispatch
230 return win32com.client.Dispatch("VirtualBox.VirtualBox")
231
232 def getConstants(self):
233 return self.constants
234
235 def getType(self):
236 return 'MSCOM'
237
238 def getRemote(self):
239 return False
240
241 def getArray(self, obj, field):
242 return obj.__getattr__(field)
243
244 def initPerThread(self):
245 import pythoncom
246 pythoncom.CoInitializeEx(0)
247
248 def deinitPerThread(self):
249 import pythoncom
250 pythoncom.CoUninitialize()
251
252 def createCallback(self, iface, impl, arg):
253 d = {}
254 d['BaseClass'] = impl
255 d['arg'] = arg
256 d['tlb_guid'] = PlatformMSCOM.VBOX_TLB_GUID
257 str = ""
258 str += "import win32com.server.util\n"
259 str += "import pythoncom\n"
260
261 str += "class "+iface+"Impl(BaseClass):\n"
262 str += " _com_interfaces_ = ['"+iface+"']\n"
263 str += " _typelib_guid_ = tlb_guid\n"
264 str += " _typelib_version_ = 1, 0\n"
265
266 # generate capitalized version of callbacks - that's how Python COM
267 # looks them up on Windows
268 for m in dir(impl):
269 if m.startswith("on"):
270 str += " "+ComifyName(m)+"=BaseClass."+m+"\n"
271
272 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
273 str += "result = win32com.server.util.wrap("+iface+"Impl())\n"
274 exec (str,d,d)
275 return d['result']
276
277 def waitForEvents(self, timeout):
278 from win32api import GetCurrentThreadId
279 from win32event import MsgWaitForMultipleObjects, \
280 QS_ALLINPUT, WAIT_TIMEOUT, WAIT_OBJECT_0
281 from pythoncom import PumpWaitingMessages
282
283 if (self.tid != GetCurrentThreadId()):
284 raise Exception("wait for events from the same thread you inited!")
285
286 rc = MsgWaitForMultipleObjects(self.handles, 0, timeout, QS_ALLINPUT)
287 if rc >= WAIT_OBJECT_0 and rc < WAIT_OBJECT_0+len(self.handles):
288 # is it possible?
289 pass
290 elif rc==WAIT_OBJECT_0 + len(self.handles):
291 # Waiting messages
292 PumpWaitingMessages()
293 else:
294 # Timeout
295 pass
296
297 def deinit(self):
298 import pythoncom
299 from win32file import CloseHandle
300
301 for h in self.handles:
302 if h is not None:
303 CloseHandle(h)
304 self.handles = None
305 pythoncom.CoUninitialize()
306 pass
307
308
309class PlatformXPCOM:
310 def __init__(self, params):
311 sys.path.append(VboxSdkDir+'/bindings/xpcom/python/')
312 import xpcom.vboxxpcom
313 import xpcom
314 import xpcom.components
315
316 def getSessionObject(self, vbox):
317 import xpcom.components
318 return xpcom.components.classes["@virtualbox.org/Session;1"].createInstance()
319
320 def getVirtualBox(self):
321 import xpcom.components
322 return xpcom.components.classes["@virtualbox.org/VirtualBox;1"].createInstance()
323
324 def getConstants(self):
325 import xpcom.components
326 return xpcom.components.interfaces
327
328 def getType(self):
329 return 'XPCOM'
330
331 def getRemote(self):
332 return False
333
334 def getArray(self, obj, field):
335 return obj.__getattr__('get'+ComifyName(field))()
336
337 def initPerThread(self):
338 pass
339
340 def deinitPerThread(self):
341 pass
342
343 def createCallback(self, iface, impl, arg):
344 d = {}
345 d['BaseClass'] = impl
346 d['arg'] = arg
347 str = ""
348 str += "import xpcom.components\n"
349 str += "class "+iface+"Impl(BaseClass):\n"
350 str += " _com_interfaces_ = xpcom.components.interfaces."+iface+"\n"
351 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
352 str += "result = "+iface+"Impl()\n"
353 exec (str,d,d)
354 return d['result']
355
356 def waitForEvents(self, timeout):
357 import xpcom
358 xpcom._xpcom.WaitForEvents(timeout)
359
360 def deinit(self):
361 import xpcom
362 xpcom._xpcom.DeinitCOM()
363
364class PlatformWEBSERVICE:
365 def __init__(self, params):
366 sys.path.append(os.path.join(VboxSdkDir,'bindings', 'webservice', 'python', 'lib'))
367 # not really needed, but just fail early if misconfigured
368 import VirtualBox_services
369 import VirtualBox_wrappers
370 from VirtualBox_wrappers import IWebsessionManager2
371
372 if params is not None:
373 self.user = params.get("user", "")
374 self.password = params.get("password", "")
375 self.url = params.get("url", "")
376 else:
377 self.user = ""
378 self.password = ""
379 self.url = None
380 self.vbox = None
381
382 def getSessionObject(self, vbox):
383 return self.wsmgr.getSessionObject(vbox)
384
385 def getVirtualBox(self):
386 return self.connect(self.url, self.user, self.password)
387
388 def connect(self, url, user, passwd):
389 if self.vbox is not None:
390 self.disconnect()
391 from VirtualBox_wrappers import IWebsessionManager2
392 if url is None:
393 url = ""
394 self.url = url
395 if user is None:
396 user = ""
397 self.user = user
398 if passwd is None:
399 passwd = ""
400 self.password = passwd
401 self.wsmgr = IWebsessionManager2(self.url)
402 self.vbox = self.wsmgr.logon(self.user, self.password)
403 if not self.vbox.handle:
404 raise Exception("cannot connect to '"+self.url+"' as '"+self.user+"'")
405 return self.vbox
406
407 def disconnect(self):
408 if self.vbox is not None and self.wsmgr is not None:
409 self.wsmgr.logoff(self.vbox)
410 self.vbox = None
411 self.wsmgr = None
412
413 def getConstants(self):
414 return None
415
416 def getType(self):
417 return 'WEBSERVICE'
418
419 def getRemote(self):
420 return True
421
422 def getArray(self, obj, field):
423 return obj.__getattr__(field)
424
425 def initPerThread(self):
426 pass
427
428 def deinitPerThread(self):
429 pass
430
431 def createCallback(self, iface, impl, arg):
432 raise Exception("no callbacks for webservices")
433
434 def waitForEvents(self, timeout):
435 # Webservices cannot do that yet
436 pass
437
438 def deinit(self):
439 try:
440 disconnect()
441 except:
442 pass
443
444class SessionManager:
445 def __init__(self, mgr):
446 self.mgr = mgr
447
448 def getSessionObject(self, vbox):
449 return self.mgr.platform.getSessionObject(vbox)
450
451class VirtualBoxManager:
452 def __init__(self, style, platparams):
453 if style is None:
454 if sys.platform == 'win32':
455 style = "MSCOM"
456 else:
457 style = "XPCOM"
458
459 exec "self.platform = Platform"+style+"(platparams)"
460
461 self.constants = VirtualBoxReflectionInfo()
462 self.type = self.platform.getType()
463 self.remote = self.platform.getRemote()
464 self.style = style
465 self.mgr = SessionManager(self)
466
467 try:
468 self.vbox = self.platform.getVirtualBox()
469 except NameError,ne:
470 print "Installation problem: check that appropriate libs in place"
471 traceback.print_exc()
472 raise ne
473 except Exception,e:
474 print "init exception: ",e
475 traceback.print_exc()
476 if self.remote:
477 self.vbox = None
478 else:
479 raise e
480
481 def getArray(self, obj, field):
482 return self.platform.getArray(obj, field)
483
484 def getVirtualBox(self):
485 return self.platform.getVirtualBox()
486
487 def __del__(self):
488 self.deinit()
489
490 def deinit(self):
491 if hasattr(self, "vbox"):
492 del self.vbox
493 self.vbox = None
494 if hasattr(self, "platform"):
495 self.platform.deinit()
496 self.platform = None
497
498 def initPerThread(self):
499 self.platform.initPerThread()
500
501 def openMachineSession(self, machineId):
502 session = self.mgr.getSessionObject(self.vbox)
503 self.vbox.openSession(session, machineId)
504 return session
505
506 def closeMachineSession(self, session):
507 session.close()
508
509 def deinitPerThread(self):
510 self.platform.deinitPerThread()
511
512 def createCallback(self, iface, impl, arg):
513 return self.platform.createCallback(iface, impl, arg)
514
515 def waitForEvents(self, timeout):
516 return self.platform.waitForEvents(timeout)
517
518 def getPerfCollector(self, vbox):
519 return PerfCollector(self, vbox)
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