VirtualBox

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

Last change on this file since 53517 was 51415, checked in by vboxsync, 11 years ago

Python API bindings: eliminate dead code, unused for years (since the unification of COM/XPCOM/WSDL)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.6 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: vboxapi.py 51415 2014-05-27 08:30:29Z vboxsync $
3"""
4VirtualBox Python API Glue.
5"""
6
7__copyright__ = \
8"""
9Copyright (C) 2009-2013 Oracle Corporation
10
11This file is part of VirtualBox Open Source Edition (OSE), as
12available from http://www.virtualbox.org. This file is free software;
13you can redistribute it and/or modify it under the terms of the GNU
14General Public License (GPL) as published by the Free Software
15Foundation, in version 2 as it comes in the "COPYING" file of the
16VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18"""
19__version__ = "$Revision: 51415 $"
20
21
22# Note! To set Python bitness on OSX use 'export VERSIONER_PYTHON_PREFER_32_BIT=yes'
23
24
25# Standard Python imports.
26import sys, os
27import traceback
28
29
30#
31# Globals, environment and sys.path changes.
32#
33VBoxBinDir = os.environ.get("VBOX_PROGRAM_PATH", None)
34VBoxSdkDir = os.environ.get("VBOX_SDK_PATH", None)
35
36if VBoxBinDir is None:
37 # Will be set by the installer
38 VBoxBinDir = "%VBOX_INSTALL_PATH%"
39else:
40 VBoxBinDir = os.path.abspath(VBoxBinDir);
41
42if VBoxSdkDir is None:
43 # Will be set by the installer
44 VBoxSdkDir = "%VBOX_SDK_PATH%"
45else:
46 VBoxSdkDir = os.path.abspath(VBoxSdkDir);
47
48os.environ["VBOX_PROGRAM_PATH"] = VBoxBinDir
49os.environ["VBOX_SDK_PATH"] = VBoxSdkDir
50sys.path.append(VBoxBinDir)
51
52
53#
54# Import the generated VirtualBox constants.
55#
56from VirtualBox_constants import VirtualBoxReflectionInfo
57
58
59class PerfCollector(object):
60 """ This class provides a wrapper over IPerformanceCollector in order to
61 get more 'pythonic' interface.
62
63 To begin collection of metrics use setup() method.
64
65 To get collected data use query() method.
66
67 It is possible to disable metric collection without changing collection
68 parameters with disable() method. The enable() method resumes metric
69 collection.
70 """
71
72 def __init__(self, mgr, vbox):
73 """ Initializes the instance.
74
75 """
76 self.mgr = mgr
77 self.isMscom = (mgr.type == 'MSCOM')
78 self.collector = vbox.performanceCollector
79
80 def setup(self, names, objects, period, nsamples):
81 """ Discards all previously collected values for the specified
82 metrics, sets the period of collection and the number of retained
83 samples, enables collection.
84 """
85 self.collector.setupMetrics(names, objects, period, nsamples)
86
87 def enable(self, names, objects):
88 """ Resumes metric collection for the specified metrics.
89 """
90 self.collector.enableMetrics(names, objects)
91
92 def disable(self, names, objects):
93 """ Suspends metric collection for the specified metrics.
94 """
95 self.collector.disableMetrics(names, objects)
96
97 def query(self, names, objects):
98 """ Retrieves collected metric values as well as some auxiliary
99 information. Returns an array of dictionaries, one dictionary per
100 metric. Each dictionary contains the following entries:
101 'name': metric name
102 'object': managed object this metric associated with
103 'unit': unit of measurement
104 'scale': divide 'values' by this number to get float numbers
105 'values': collected data
106 'values_as_string': pre-processed values ready for 'print' statement
107 """
108 # Get around the problem with input arrays returned in output
109 # parameters (see #3953) for MSCOM.
110 if self.isMscom:
111 (values, names, objects, names_out, objects_out, units, scales, sequence_numbers,
112 indices, lengths) = self.collector.queryMetricsData(names, objects)
113 else:
114 (values, names_out, objects_out, units, scales, sequence_numbers,
115 indices, lengths) = self.collector.queryMetricsData(names, objects)
116 out = []
117 for i in xrange(0, len(names_out)):
118 scale = int(scales[i])
119 if scale != 1:
120 fmt = '%.2f%s'
121 else:
122 fmt = '%d %s'
123 out.append({
124 'name':str(names_out[i]),
125 'object':str(objects_out[i]),
126 'unit':str(units[i]),
127 'scale':scale,
128 'values':[int(values[j]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))],
129 'values_as_string':'['+', '.join([fmt % (int(values[j])/scale, units[i]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))])+']'
130 })
131 return out
132
133#
134# Attribute hacks.
135#
136def ComifyName(name):
137 return name[0].capitalize() + name[1:]
138
139
140## This is for saving the original DispatchBaseClass __getattr__ and __setattr__
141# method references.
142_g_dCOMForward = {
143 'getattr': None,
144 'setattr': None,
145}
146
147def _CustomGetAttr(self, sAttr):
148 """ Our getattr replacement for DispatchBaseClass. """
149 # Fastpath.
150 oRet = self.__class__.__dict__.get(sAttr);
151 if oRet != None:
152 return oRet;
153
154 # Try case-insensitivity workaround for class attributes (COM methods).
155 sAttrLower = sAttr.lower();
156 for sKey in self.__class__.__dict__.keys():
157 if sKey.lower() == sAttrLower:
158 self.__class__.__dict__[sAttr] = self.__class__.__dict__[sKey]
159 return getattr(self, sKey)
160
161 # Slow path.
162 try:
163 return _g_dCOMForward['getattr'](self, ComifyName(sAttr))
164 except AttributeError:
165 return _g_dCOMForward['getattr'](self, sAttr)
166
167def _CustomSetAttr(self, sAttr, oValue):
168 """ Our setattr replacement for DispatchBaseClass. """
169 try:
170 return _g_dCOMForward['setattr'](self, ComifyName(sAttr), oValue)
171 except AttributeError:
172 return _g_dCOMForward['setattr'](self, sAttr, oValue)
173
174
175
176class PlatformBase(object):
177 """
178 Base class for the platform specific code.
179 """
180
181 def __init__(self, aoParams):
182 _ = aoParams;
183
184 def getVirtualBox(self):
185 """
186 Gets a the IVirtualBox singleton.
187 """
188 return None;
189
190 def getSessionObject(self, oIVBox):
191 """
192 Get a session object that can be used for opening machine sessions.
193
194 The oIVBox parameter is an getVirtualBox() return value, i.e. an
195 IVirtualBox reference.
196
197 See also openMachineSession.
198 """
199 _ = oIVBox;
200 return None;
201
202 def getType(self):
203 """ Returns the platform type (class name sans 'Platform'). """
204 return None;
205
206 def isRemote(self):
207 """
208 Returns True if remote (web services) and False if local (COM/XPCOM).
209 """
210 return False
211
212 def getArray(self, oInterface, sAttrib):
213 """
214 Retrives the value of the array attribute 'sAttrib' from
215 interface 'oInterface'.
216
217 This is for hiding platform specific differences in attributes
218 returning arrays.
219 """
220 _ = oInterface;
221 _ = sAttrib;
222 return None;
223
224 def initPerThread(self):
225 """
226 Does backend specific initialization for the calling thread.
227 """
228 return True;
229
230 def deinitPerThread(self):
231 """
232 Does backend specific uninitialization for the calling thread.
233 """
234 return True;
235
236 def createListener(self, oImplClass, dArgs):
237 """
238 Instantiates and wraps an active event listener class so it can be
239 passed to an event source for registration.
240
241 oImplClass is a class (type, not instance) which implements
242 IEventListener.
243
244 dArgs is a dictionary with string indexed variables. This may be
245 modified by the method to pass platform specific parameters. Can
246 be None.
247
248 This currently only works on XPCOM. COM support is not possible due to
249 shortcuts taken in the COM bridge code, which is not under our control.
250 Use passive listeners for COM and web services.
251 """
252 _ = oImplClass;
253 _ = dArgs;
254 raise Exception("No active listeners for this platform");
255 return None;
256
257 def waitForEvents(self, cMsTimeout):
258 """
259 Wait for events to arrive and process them.
260
261 The timeout (cMsTimeout) is in milliseconds for how long to wait for
262 events to arrive. A negative value means waiting for ever, while 0
263 does not wait at all.
264
265 Returns 0 if events was processed.
266 Returns 1 if timed out or interrupted in some way.
267 Returns 2 on error (like not supported for web services).
268
269 Raises an exception if the calling thread is not the main thread (the one
270 that initialized VirtualBoxManager) or if the time isn't an integer.
271 """
272 _ = cMsTimeout;
273 return 2;
274
275 def interruptWaitEvents(self):
276 """
277 Interrupt a waitForEvents call.
278 This is normally called from a worker thread to wake up the main thread.
279
280 Returns True on success, False on failure.
281 """
282 return False;
283
284 def deinit(self):
285 """
286 Unitializes the platform specific backend.
287 """
288 return None;
289
290 def queryInterface(self, oIUnknown, sClassName):
291 """
292 IUnknown::QueryInterface wrapper.
293
294 oIUnknown is who to ask.
295 sClassName is the name of the interface we're asking for.
296 """
297 return None;
298
299 #
300 # Error (exception) access methods.
301 #
302
303 def xcptGetStatus(self, oXcpt):
304 """
305 Returns the COM status code from the VBox API given exception.
306 """
307 return None;
308
309 def xcptIsDeadInterface(self, oXcpt):
310 """
311 Returns True if the exception indicates that the interface is dead, False if not.
312 """
313 return False;
314
315 def xcptIsEqual(self, oXcpt, hrStatus):
316 """
317 Checks if the exception oXcpt is equal to the COM/XPCOM status code
318 hrStatus.
319
320 The oXcpt parameter can be any kind of object, we'll just return True
321 if it doesn't behave like a our exception class.
322
323 Will not raise any exception as long as hrStatus and self are not bad.
324 """
325 try:
326 hrXcpt = self.xcptGetStatus(oXcpt);
327 except AttributeError:
328 return False;
329 if hrXcpt == hrStatus:
330 return True;
331
332 # Fudge for 32-bit signed int conversion.
333 if hrStatus > 0x7fffffff and hrStatus <= 0xffffffff and hrXcpt < 0:
334 if (hrStatus - 0x100000000) == hrXcpt:
335 return True;
336 return False;
337
338 def xcptGetMessage(self, oXcpt):
339 """
340 Returns the best error message found in the COM-like exception.
341 Returns None to fall back on xcptToString.
342 Raises exception if oXcpt isn't our kind of exception object.
343 """
344 return None;
345
346 def xcptGetBaseXcpt(self):
347 """
348 Returns the base exception class.
349 """
350 return None;
351
352 def xcptSetupConstants(self, oDst):
353 """
354 Copy/whatever all error constants onto oDst.
355 """
356 return oDst;
357
358 @staticmethod
359 def xcptCopyErrorConstants(oDst, oSrc):
360 """
361 Copy everything that looks like error constants from oDst to oSrc.
362 """
363 for sAttr in dir(oSrc):
364 if sAttr[0].isupper() and (sAttr[1].isupper() or sAttr[1] == '_'):
365 oAttr = getattr(oSrc, sAttr);
366 if type(oAttr) is int:
367 setattr(oDst, sAttr, oAttr);
368 return oDst;
369
370
371
372class PlatformMSCOM(PlatformBase):
373 """
374 Platform specific code for MS COM.
375 """
376
377 ## @name VirtualBox COM Typelib definitions (should be generate)
378 #
379 # @remarks Must be updated when the corresponding VirtualBox.xidl bits
380 # are changed. Fortunately this isn't very often.
381 # @{
382 VBOX_TLB_GUID = '{D7569351-1750-46F0-936E-BD127D5BC264}'
383 VBOX_TLB_LCID = 0
384 VBOX_TLB_MAJOR = 1
385 VBOX_TLB_MINOR = 3
386 ## @}
387
388 def __init__(self, dParams):
389 PlatformBase.__init__(self, dParams);
390
391 #
392 # Since the code runs on all platforms, we have to do a lot of
393 # importing here instead of at the top of the file where it's normally located.
394 #
395 from win32com import universal
396 from win32com.client import gencache, DispatchBaseClass
397 from win32com.client import constants, getevents
398 import win32com
399 import pythoncom
400 import win32api
401 import winerror
402 from win32con import DUPLICATE_SAME_ACCESS
403 from win32api import GetCurrentThread, GetCurrentThreadId, DuplicateHandle, GetCurrentProcess
404 import threading
405
406 self.winerror = winerror;
407
408 pid = GetCurrentProcess()
409 self.tid = GetCurrentThreadId()
410 handle = DuplicateHandle(pid, GetCurrentThread(), pid, 0, 0, DUPLICATE_SAME_ACCESS)
411 self.handles = []
412 self.handles.append(handle)
413
414 # Hack the COM dispatcher base class so we can modify method and
415 # attribute names to match those in xpcom.
416 if _g_dCOMForward['setattr'] is None:
417 _g_dCOMForward['getattr'] = DispatchBaseClass.__dict__['__getattr__']
418 DispatchBaseClass.__dict__['__getattr__'] = _CustomGetAttr
419 _g_dCOMForward['setattr'] = DispatchBaseClass.__dict__['__setattr__']
420 DispatchBaseClass.__dict__['__setattr__'] = _CustomSetAttr
421
422 # Hack the exception base class so the users doesn't need to check for
423 # XPCOM or COM and do different things.
424 ## @todo
425
426 #
427 # Make sure the gencache is correct (we don't quite follow the COM
428 # versioning rules).
429 #
430 self.flushGenPyCache(win32com.client.gencache);
431 win32com.client.gencache.EnsureDispatch('VirtualBox.Session');
432 win32com.client.gencache.EnsureDispatch('VirtualBox.VirtualBox');
433
434 self.oIntCv = threading.Condition()
435 self.fInterrupted = False;
436
437 _ = dParams;
438
439 def flushGenPyCache(self, oGenCache):
440 """
441 Flushes VBox related files in the win32com gen_py cache.
442
443 This is necessary since we don't follow the typelib versioning rules
444 that everyeone else seems to subscribe to.
445 """
446 #
447 # The EnsureModule method have broken validation code, it doesn't take
448 # typelib module directories into account. So we brute force them here.
449 # (It's possible the directory approach is from some older pywin
450 # version or the result of runnig makepy or gencache manually, but we
451 # need to cover it as well.)
452 #
453 sName = oGenCache.GetGeneratedFileName(self.VBOX_TLB_GUID, self.VBOX_TLB_LCID,
454 self.VBOX_TLB_MAJOR, self.VBOX_TLB_MINOR);
455 sGenPath = oGenCache.GetGeneratePath();
456 if len(sName) > 36 and len(sGenPath) > 5:
457 sTypelibPath = os.path.join(sGenPath, sName);
458 if os.path.isdir(sTypelibPath):
459 import shutil;
460 shutil.rmtree(sTypelibPath, ignore_errors = True);
461
462 #
463 # Ensure that our typelib is valid.
464 #
465 return oGenCache.EnsureModule(self.VBOX_TLB_GUID, self.VBOX_TLB_LCID, self.VBOX_TLB_MAJOR, self.VBOX_TLB_MINOR);
466
467 def getSessionObject(self, oIVBox):
468 _ = oIVBox
469 import win32com
470 from win32com.client import Dispatch
471 return win32com.client.Dispatch("VirtualBox.Session")
472
473 def getVirtualBox(self):
474 import win32com
475 from win32com.client import Dispatch
476 return win32com.client.Dispatch("VirtualBox.VirtualBox")
477
478 def getType(self):
479 return 'MSCOM'
480
481 def getArray(self, oInterface, sAttrib):
482 return oInterface.__getattr__(sAttrib)
483
484 def initPerThread(self):
485 import pythoncom
486 pythoncom.CoInitializeEx(0)
487
488 def deinitPerThread(self):
489 import pythoncom
490 pythoncom.CoUninitialize()
491
492 def createListener(self, oImplClass, dArgs):
493 if True:
494 raise Exception('no active listeners on Windows as PyGatewayBase::QueryInterface() '
495 'returns new gateway objects all the time, thus breaking EventQueue '
496 'assumptions about the listener interface pointer being constants between calls ');
497 # Did this code ever really work?
498 d = {}
499 d['BaseClass'] = oImplClass
500 d['dArgs'] = dArgs
501 d['tlb_guid'] = PlatformMSCOM.VBOX_TLB_GUID
502 d['tlb_major'] = PlatformMSCOM.VBOX_TLB_MAJOR
503 d['tlb_minor'] = PlatformMSCOM.VBOX_TLB_MINOR
504 str = ""
505 str += "import win32com.server.util\n"
506 str += "import pythoncom\n"
507
508 str += "class ListenerImpl(BaseClass):\n"
509 str += " _com_interfaces_ = ['IEventListener']\n"
510 str += " _typelib_guid_ = tlb_guid\n"
511 str += " _typelib_version_ = tlb_major, tlb_minor\n"
512 str += " _reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER\n"
513 # Maybe we'd better implement Dynamic invoke policy, to be more flexible here
514 str += " _reg_policy_spec_ = 'win32com.server.policy.EventHandlerPolicy'\n"
515
516 # capitalized version of listener method
517 str += " HandleEvent=BaseClass.handleEvent\n"
518 str += " def __init__(self): BaseClass.__init__(self, dArgs)\n"
519 str += "result = win32com.server.util.wrap(ListenerImpl())\n"
520 exec(str, d, d)
521 return d['result']
522
523 def waitForEvents(self, timeout):
524 from win32api import GetCurrentThreadId
525 from win32event import INFINITE
526 from win32event import MsgWaitForMultipleObjects, \
527 QS_ALLINPUT, WAIT_TIMEOUT, WAIT_OBJECT_0
528 from pythoncom import PumpWaitingMessages
529 import types
530
531 if not isinstance(timeout, types.IntType):
532 raise TypeError("The timeout argument is not an integer")
533 if (self.tid != GetCurrentThreadId()):
534 raise Exception("wait for events from the same thread you inited!")
535
536 if timeout < 0:
537 cMsTimeout = INFINITE
538 else:
539 cMsTimeout = timeout
540 rc = MsgWaitForMultipleObjects(self.handles, 0, cMsTimeout, QS_ALLINPUT)
541 if rc >= WAIT_OBJECT_0 and rc < WAIT_OBJECT_0+len(self.handles):
542 # is it possible?
543 rc = 2;
544 elif rc==WAIT_OBJECT_0 + len(self.handles):
545 # Waiting messages
546 PumpWaitingMessages()
547 rc = 0;
548 else:
549 # Timeout
550 rc = 1;
551
552 # check for interruption
553 self.oIntCv.acquire()
554 if self.fInterrupted:
555 self.fInterrupted = False
556 rc = 1;
557 self.oIntCv.release()
558
559 return rc;
560
561 def interruptWaitEvents(self):
562 """
563 Basically a python implementation of NativeEventQueue::postEvent().
564
565 The magic value must be in sync with the C++ implementation or this
566 won't work.
567
568 Note that because of this method we cannot easily make use of a
569 non-visible Window to handle the message like we would like to do.
570 """
571 from win32api import PostThreadMessage
572 from win32con import WM_USER
573 self.oIntCv.acquire()
574 self.fInterrupted = True
575 self.oIntCv.release()
576 try:
577 PostThreadMessage(self.tid, WM_USER, None, 0xf241b819)
578 except:
579 return False;
580 return True;
581
582 def deinit(self):
583 import pythoncom
584 from win32file import CloseHandle
585
586 for h in self.handles:
587 if h is not None:
588 CloseHandle(h)
589 self.handles = None
590 pythoncom.CoUninitialize()
591 pass
592
593 def queryInterface(self, oIUnknown, sClassName):
594 from win32com.client import CastTo
595 return CastTo(oIUnknown, sClassName)
596
597 def xcptGetStatus(self, oXcpt):
598 # The DISP_E_EXCEPTION + excptinfo fun needs checking up, only
599 # empirical info on it so far.
600 hrXcpt = oXcpt.hresult
601 if hrXcpt == self.winerror.DISP_E_EXCEPTION:
602 try: hrXcpt = oXcpt.excepinfo[5];
603 except: pass;
604 return hrXcpt;
605
606 def xcptIsDeadInterface(self, oXcpt):
607 return self.xcptGetStatus(oXcpt) in [
608 0x800706ba, -2147023174, # RPC_S_SERVER_UNAVAILABLE.
609 0x800706be, -2147023170, # RPC_S_CALL_FAILED.
610 0x800706bf, -2147023169, # RPC_S_CALL_FAILED_DNE.
611 0x80010108, -2147417848, # RPC_E_DISCONNECTED.
612 0x800706b5, -2147023179, # RPC_S_UNKNOWN_IF
613 ];
614
615
616 def xcptGetMessage(self, oXcpt):
617 if hasattr(oXcpt, 'excepinfo'):
618 try:
619 if len(oXcpt.excepinfo) >= 3:
620 sRet = oXcpt.excepinfo[2];
621 if len(sRet) > 0:
622 return sRet[0:];
623 except:
624 pass;
625 if hasattr(oXcpt, 'strerror'):
626 try:
627 sRet = oXcpt.strerror;
628 if len(sRet) > 0:
629 return sRet;
630 except:
631 pass;
632 return None;
633
634 def xcptGetBaseXcpt(self):
635 import pythoncom;
636 return pythoncom.com_error;
637
638 def xcptSetupConstants(self, oDst):
639 import winerror;
640 oDst = self.xcptCopyErrorConstants(oDst, winerror);
641
642 # XPCOM compatability constants.
643 oDst.NS_OK = oDst.S_OK;
644 oDst.NS_ERROR_FAILURE = oDst.E_FAIL;
645 oDst.NS_ERROR_ABORT = oDst.E_ABORT;
646 oDst.NS_ERROR_NULL_POINTER = oDst.E_POINTER;
647 oDst.NS_ERROR_NO_INTERFACE = oDst.E_NOINTERFACE;
648 oDst.NS_ERROR_INVALID_ARG = oDst.E_INVALIDARG;
649 oDst.NS_ERROR_OUT_OF_MEMORY = oDst.E_OUTOFMEMORY;
650 oDst.NS_ERROR_NOT_IMPLEMENTED = oDst.E_NOTIMPL;
651 oDst.NS_ERROR_UNEXPECTED = oDst.E_UNEXPECTED;
652 return oDst;
653
654
655class PlatformXPCOM(PlatformBase):
656 """
657 Platform specific code for XPCOM.
658 """
659
660 def __init__(self, dParams):
661 PlatformBase.__init__(self, dParams);
662 sys.path.append(VBoxSdkDir+'/bindings/xpcom/python/')
663 import xpcom.vboxxpcom
664 import xpcom
665 import xpcom.components
666 _ = dParams;
667
668 def getSessionObject(self, oIVBox):
669 _ = oIVBox;
670 import xpcom.components
671 return xpcom.components.classes["@virtualbox.org/Session;1"].createInstance()
672
673 def getVirtualBox(self):
674 import xpcom.components
675 return xpcom.components.classes["@virtualbox.org/VirtualBox;1"].createInstance()
676
677 def getType(self):
678 return 'XPCOM'
679
680 def getArray(self, oInterface, sAttrib):
681 return oInterface.__getattr__('get'+ComifyName(sAttrib))()
682
683 def initPerThread(self):
684 import xpcom
685 xpcom._xpcom.AttachThread()
686
687 def deinitPerThread(self):
688 import xpcom
689 xpcom._xpcom.DetachThread()
690
691 def createListener(self, oImplClass, dArgs):
692 d = {}
693 d['BaseClass'] = oImplClass
694 d['dArgs'] = dArgs
695 str = ""
696 str += "import xpcom.components\n"
697 str += "class ListenerImpl(BaseClass):\n"
698 str += " _com_interfaces_ = xpcom.components.interfaces.IEventListener\n"
699 str += " def __init__(self): BaseClass.__init__(self, dArgs)\n"
700 str += "result = ListenerImpl()\n"
701 exec (str, d, d)
702 return d['result']
703
704 def waitForEvents(self, timeout):
705 import xpcom
706 return xpcom._xpcom.WaitForEvents(timeout)
707
708 def interruptWaitEvents(self):
709 import xpcom
710 return xpcom._xpcom.InterruptWait()
711
712 def deinit(self):
713 import xpcom
714 xpcom._xpcom.DeinitCOM()
715
716 def queryInterface(self, oIUnknown, sClassName):
717 import xpcom.components
718 return oIUnknown.queryInterface(getattr(xpcom.components.interfaces, sClassName))
719
720 def xcptGetStatus(self, oXcpt):
721 return oXcpt.errno;
722
723 def xcptIsDeadInterface(self, oXcpt):
724 return self.xcptGetStatus(oXcpt) in [
725 0x80004004, -2147467260, # NS_ERROR_ABORT
726 0x800706be, -2147023170, # NS_ERROR_CALL_FAILED (RPC_S_CALL_FAILED)
727 ];
728
729 def xcptGetMessage(self, oXcpt):
730 if hasattr(oXcpt, 'msg'):
731 try:
732 sRet = oXcpt.msg;
733 if len(sRet) > 0:
734 return sRet;
735 except:
736 pass;
737 return None;
738
739 def xcptGetBaseXcpt(self):
740 import xpcom;
741 return xpcom.Exception;
742
743 def xcptSetupConstants(self, oDst):
744 import xpcom;
745 oDst = self.xcptCopyErrorConstants(oDst, xpcom.nsError);
746
747 # COM compatability constants.
748 oDst.E_ACCESSDENIED = -2147024891; # see VBox/com/defs.h
749 oDst.S_OK = oDst.NS_OK;
750 oDst.E_FAIL = oDst.NS_ERROR_FAILURE;
751 oDst.E_ABORT = oDst.NS_ERROR_ABORT;
752 oDst.E_POINTER = oDst.NS_ERROR_NULL_POINTER;
753 oDst.E_NOINTERFACE = oDst.NS_ERROR_NO_INTERFACE;
754 oDst.E_INVALIDARG = oDst.NS_ERROR_INVALID_ARG;
755 oDst.E_OUTOFMEMORY = oDst.NS_ERROR_OUT_OF_MEMORY;
756 oDst.E_NOTIMPL = oDst.NS_ERROR_NOT_IMPLEMENTED;
757 oDst.E_UNEXPECTED = oDst.NS_ERROR_UNEXPECTED;
758 oDst.DISP_E_EXCEPTION = -2147352567; # For COM compatability only.
759 return oDst;
760
761
762class PlatformWEBSERVICE(PlatformBase):
763 """
764 VirtualBox Web Services API specific code.
765 """
766
767 def __init__(self, dParams):
768 PlatformBase.__init__(self, dParams);
769 # Import web services stuff. Fix the sys.path the first time.
770 sWebServLib = os.path.join(VBoxSdkDir, 'bindings', 'webservice', 'python', 'lib');
771 if sWebServLib not in sys.path:
772 sys.path.append(sWebServLib);
773 import VirtualBox_wrappers
774 from VirtualBox_wrappers import IWebsessionManager2
775
776 # Initialize instance variables from parameters.
777 if dParams is not None:
778 self.user = dParams.get("user", "")
779 self.password = dParams.get("password", "")
780 self.url = dParams.get("url", "")
781 else:
782 self.user = ""
783 self.password = ""
784 self.url = None
785 self.vbox = None
786 self.wsmgr = None;
787
788 #
789 # Base class overrides.
790 #
791
792 def getSessionObject(self, oIVBox):
793 return self.wsmgr.getSessionObject(oIVBox)
794
795 def getVirtualBox(self):
796 return self.connect(self.url, self.user, self.password)
797
798 def getType(self):
799 return 'WEBSERVICE'
800
801 def isRemote(self):
802 """ Returns True if remote VBox host, False if local. """
803 return True
804
805 def getArray(self, oInterface, sAttrib):
806 return oInterface.__getattr__(sAttrib)
807
808 def waitForEvents(self, timeout):
809 # Webservices cannot do that yet
810 return 2;
811
812 def interruptWaitEvents(self, timeout):
813 # Webservices cannot do that yet
814 return False;
815
816 def deinit(self):
817 try:
818 disconnect()
819 except:
820 pass
821
822 def queryInterface(self, oIUnknown, sClassName):
823 d = {}
824 d['oIUnknown'] = oIUnknown
825 str = ""
826 str += "from VirtualBox_wrappers import "+sClassName+"\n"
827 str += "result = "+sClassName+"(oIUnknown.mgr, oIUnknown.handle)\n"
828 # wrong, need to test if class indeed implements this interface
829 exec (str, d, d)
830 return d['result']
831
832 #
833 # Web service specific methods.
834 #
835
836 def connect(self, url, user, passwd):
837 if self.vbox is not None:
838 self.disconnect()
839 from VirtualBox_wrappers import IWebsessionManager2
840 if url is None:
841 url = ""
842 self.url = url
843 if user is None:
844 user = ""
845 self.user = user
846 if passwd is None:
847 passwd = ""
848 self.password = passwd
849 self.wsmgr = IWebsessionManager2(self.url)
850 self.vbox = self.wsmgr.logon(self.user, self.password)
851 if not self.vbox.handle:
852 raise Exception("cannot connect to '"+self.url+"' as '"+self.user+"'")
853 return self.vbox
854
855 def disconnect(self):
856 if self.vbox is not None and self.wsmgr is not None:
857 self.wsmgr.logoff(self.vbox)
858 self.vbox = None
859 self.wsmgr = None
860
861
862## The current (last) exception class.
863# This is reinitalized whenever VirtualBoxManager is called, so it will hold
864# the reference to the error exception class for the last platform/style that
865# was used. Most clients does talk to multiple VBox instance on different
866# platforms at the same time, so this should be sufficent for most uses and
867# be way simpler to use than VirtualBoxManager::oXcptClass.
868CurXctpClass = None;
869
870
871class VirtualBoxManager(object):
872 """
873 VirtualBox API manager class.
874
875 The API users will have to instantiate this. If no parameters are given,
876 it will default to interface with the VirtualBox running on the local
877 machine. sStyle can be None (default), MSCOM, XPCOM or WEBSERVICES. Most
878 users will either be specifying None or WEBSERVICES.
879
880 The dPlatformParams is an optional dictionary for passing parameters to the
881 WEBSERVICE backend.
882 """
883
884 class Statuses(object):
885 def __init__(self):
886 pass;
887
888 def __init__(self, sStyle = None, dPlatformParams = None):
889 if sStyle is None:
890 if sys.platform == 'win32':
891 sStyle = "MSCOM"
892 else:
893 sStyle = "XPCOM"
894 if sStyle == 'XPCOM':
895 self.platform = PlatformXPCOM(dPlatformParams);
896 elif sStyle == 'MSCOM':
897 self.platform = PlatformMSCOM(dPlatformParams);
898 elif sStyle == 'WEBSERVICE':
899 self.platform = PlatformWEBSERVICE(dPlatformParams);
900 else:
901 raise Exception('Unknown sStyle=%s' % (sStyle,));
902 self.style = sStyle
903 self.type = self.platform.getType()
904 self.remote = self.platform.isRemote()
905 ## VirtualBox API constants (for webservices, enums are symbolic).
906 self.constants = VirtualBoxReflectionInfo(sStyle == "WEBSERVICE")
907
908 ## Status constants.
909 self.statuses = self.platform.xcptSetupConstants(VirtualBoxManager.Statuses());
910 ## @todo Add VBOX_E_XXX to statuses? They're already in constants...
911 ## Dictionary for errToString, built on demand.
912 self._dErrorValToName = None;
913
914 ## The exception class for the selected platform.
915 self.oXcptClass = self.platform.xcptGetBaseXcpt();
916 global CurXcptClass;
917 CurXcptClass = self.oXcptClass;
918
919 # Get the virtualbox singleton.
920 try:
921 self.vbox = self.platform.getVirtualBox()
922 except NameError, ne:
923 print "Installation problem: check that appropriate libs in place"
924 traceback.print_exc()
925 raise ne
926 except Exception, e:
927 print "init exception: ", e
928 traceback.print_exc()
929 if self.remote:
930 self.vbox = None
931 else:
932 raise e
933 ## @deprecated
934 # This used to refer to a session manager class with only one method
935 # called getSessionObject. The method has moved into this call.
936 self.mgr = self;
937
938 def __del__(self):
939 self.deinit()
940
941 def getPythonApiRevision(self):
942 """
943 Returns a Python API revision number.
944 This will be incremented when features are added to this file.
945 """
946 return 3;
947
948
949 #
950 # Wrappers for self.platform methods.
951 #
952
953 def getVirtualBox(self):
954 """ See PlatformBase::getVirtualBox(). """
955 return self.platform.getVirtualBox()
956
957 def getSessionObject(self, oIVBox):
958 """ See PlatformBase::getSessionObject(). """
959 return self.platform.getSessionObject(oIVBox);
960
961 def getArray(self, oInterface, sAttrib):
962 """ See PlatformBase::getArray(). """
963 return self.platform.getArray(oInterface, sAttrib)
964
965 def createListener(self, oImplClass, dArgs = None):
966 """ See PlatformBase::createListener(). """
967 return self.platform.createListener(oImplClass, dArgs)
968
969 def waitForEvents(self, cMsTimeout):
970 """ See PlatformBase::waitForEvents(). """
971 return self.platform.waitForEvents(cMsTimeout)
972
973 def interruptWaitEvents(self):
974 """ See PlatformBase::interruptWaitEvents(). """
975 return self.platform.interruptWaitEvents()
976
977 def queryInterface(self, oIUnknown, sClassName):
978 """ See PlatformBase::queryInterface(). """
979 return self.platform.queryInterface(oIUnknown, sClassName)
980
981
982 #
983 # Init and uninit.
984 #
985
986 def initPerThread(self):
987 """ See PlatformBase::deinitPerThread(). """
988 self.platform.initPerThread()
989
990 def deinitPerThread(self):
991 """ See PlatformBase::deinitPerThread(). """
992 return self.platform.deinitPerThread()
993
994 def deinit(self):
995 """
996 For unitializing the manager.
997 Do not access it after calling this method.
998 """
999 if hasattr(self, "vbox"):
1000 del self.vbox
1001 self.vbox = None
1002 if hasattr(self, "platform"):
1003 self.platform.deinit()
1004 self.platform = None
1005 return True;
1006
1007
1008 #
1009 # Utility methods.
1010 #
1011
1012 def openMachineSession(self, oIMachine, fPermitSharing = True):
1013 """
1014 Attemts to open the a session to the machine.
1015 Returns a session object on success.
1016 Raises exception on failure.
1017 """
1018 oSession = self.mgr.getSessionObject(self.vbox);
1019 if fPermitSharing:
1020 type = self.constants.LockType_Shared;
1021 else:
1022 type = self.constants.LockType_Write;
1023 oIMachine.lockMachine(oSession, type);
1024 return oSession;
1025
1026 def closeMachineSession(self, oSession):
1027 """
1028 Closes a session opened by openMachineSession.
1029 Ignores None parameters.
1030 """
1031 if oSession is not None:
1032 oSession.unlockMachine()
1033 return True;
1034
1035 def getPerfCollector(self, oIVBox):
1036 """
1037 Returns a helper class (PerfCollector) for accessing performance
1038 collector goodies. See PerfCollector for details.
1039 """
1040 return PerfCollector(self, oIVBox)
1041
1042 def getBinDir(self):
1043 """
1044 Returns the VirtualBox binary directory.
1045 """
1046 global VBoxBinDir
1047 return VBoxBinDir
1048
1049 def getSdkDir(self):
1050 """
1051 Returns the VirtualBox SDK directory.
1052 """
1053 global VBoxSdkDir
1054 return VBoxSdkDir
1055
1056
1057 #
1058 # Error code utilities.
1059 #
1060
1061 ## @todo port to webservices!
1062
1063 def xcptGetStatus(self, oXcpt = None):
1064 """
1065 Gets the status code from an exception. If the exception parameter
1066 isn't specified, the current exception is examined.
1067 """
1068 if oXcpt is None:
1069 oXcpt = sys.exc_info()[1];
1070 return self.platform.xcptGetStatus(oXcpt);
1071
1072 def xcptIsDeadInterface(self, oXcpt = None):
1073 """
1074 Returns True if the exception indicates that the interface is dead,
1075 False if not. If the exception parameter isn't specified, the current
1076 exception is examined.
1077 """
1078 if oXcpt is None:
1079 oXcpt = sys.exc_info()[1];
1080 return self.platform.xcptIsDeadInterface(oXcpt);
1081
1082 def xcptIsOurXcptKind(self, oXcpt = None):
1083 """
1084 Checks if the exception is one that could come from the VBox API. If
1085 the exception parameter isn't specified, the current exception is
1086 examined.
1087 """
1088 if self.oXcptClass is None: ## @todo find the exception class for web services!
1089 return False;
1090 if oXcpt is None:
1091 oXcpt = sys.exc_info()[1];
1092 return isinstance(oXcpt, self.oXcptClass);
1093
1094 def xcptIsEqual(self, oXcpt, hrStatus):
1095 """
1096 Checks if the exception oXcpt is equal to the COM/XPCOM status code
1097 hrStatus.
1098
1099 The oXcpt parameter can be any kind of object, we'll just return True
1100 if it doesn't behave like a our exception class. If it's None, we'll
1101 query the current exception and examine that.
1102
1103 Will not raise any exception as long as hrStatus and self are not bad.
1104 """
1105 if oXcpt is None:
1106 oXcpt = sys.exc_info()[1];
1107 return self.platform.xcptIsEqual(oXcpt, hrStatus);
1108
1109 def xcptIsNotEqual(self, oXcpt, hrStatus):
1110 """
1111 Negated xcptIsEqual.
1112 """
1113 return not self.xcptIsEqual(oXcpt, hrStatus);
1114
1115 def xcptToString(self, hrStatusOrXcpt = None):
1116 """
1117 Converts the specified COM status code, or the status code of the
1118 specified exception, to a C constant string. If the parameter isn't
1119 specified (is None), the current exception is examined.
1120 """
1121
1122 # Deal with exceptions.
1123 if hrStatusOrXcpt is None or self.xcptIsOurXcptKind(hrStatusOrXcpt):
1124 hrStatus = self.xcptGetStatus(hrStatusOrXcpt);
1125 else:
1126 hrStatus = hrStatusOrXcpt;
1127
1128 # Build the dictionary on demand.
1129 if self._dErrorValToName is None:
1130 dErrorValToName = dict();
1131 for sKey in dir(self.statuses):
1132 if sKey[0].isupper():
1133 oValue = getattr(self.statuses, sKey);
1134 if type(oValue) is int:
1135 dErrorValToName[oValue] = sKey;
1136 self._dErrorValToName = dErrorValToName;
1137
1138 # Do the lookup, falling back on formatting the status number.
1139 try:
1140 sStr = self._dErrorValToName[int(hrStatus)];
1141 except KeyError:
1142 hrLong = long(hrStatus);
1143 sStr = '%#x (%d)' % (hrLong, hrLong);
1144 return sStr;
1145
1146 def xcptGetMessage(self, oXcpt = None):
1147 """
1148 Returns the best error message found in the COM-like exception. If the
1149 exception parameter isn't specified, the current exception is examined.
1150 """
1151 if oXcpt is None:
1152 oXcpt = sys.exc_info()[1];
1153 sRet = self.platform.xcptGetMessage(oXcpt);
1154 if sRet is None:
1155 sRet = self.xcptToString(oXcpt);
1156 return sRet;
1157
1158 # Legacy, remove in a day or two.
1159 errGetStatus = xcptGetStatus
1160 errIsDeadInterface = xcptIsDeadInterface
1161 errIsOurXcptKind = xcptIsOurXcptKind
1162 errGetMessage = xcptGetMessage
1163
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