VirtualBox

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

Last change on this file since 22323 was 22305, checked in by vboxsync, 16 years ago

Main: generic callback wrappers mechanism

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.9 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 from win32con import DUPLICATE_SAME_ACCESS
208 from win32api import GetCurrentThread,GetCurrentThreadId,DuplicateHandle,GetCurrentProcess
209 pid = GetCurrentProcess()
210 self.tid = GetCurrentThreadId()
211 handle = DuplicateHandle(pid, GetCurrentThread(), pid, 0, 0, DUPLICATE_SAME_ACCESS)
212 self.handles = []
213 self.handles.append(handle)
214 _COMForward['getattr'] = DispatchBaseClass.__dict__['__getattr__']
215 DispatchBaseClass.__dict__['__getattr__'] = CustomGetAttr
216 _COMForward['setattr'] = DispatchBaseClass.__dict__['__setattr__']
217 DispatchBaseClass.__dict__['__setattr__'] = CustomSetAttr
218 win32com.client.gencache.EnsureDispatch('VirtualBox.Session')
219 win32com.client.gencache.EnsureDispatch('VirtualBox.VirtualBox')
220 win32com.client.gencache.EnsureDispatch('VirtualBox.VirtualBoxCallback')
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 getType(self):
233 return 'MSCOM'
234
235 def getRemote(self):
236 return False
237
238 def getArray(self, obj, field):
239 return obj.__getattr__(field)
240
241 def initPerThread(self):
242 import pythoncom
243 pythoncom.CoInitializeEx(0)
244
245 def deinitPerThread(self):
246 import pythoncom
247 pythoncom.CoUninitialize()
248
249 def createCallback(self, iface, impl, arg):
250 d = {}
251 d['BaseClass'] = impl
252 d['arg'] = arg
253 d['tlb_guid'] = PlatformMSCOM.VBOX_TLB_GUID
254 str = ""
255 str += "import win32com.server.util\n"
256 str += "import pythoncom\n"
257
258 str += "class "+iface+"Impl(BaseClass):\n"
259 str += " _com_interfaces_ = ['"+iface+"']\n"
260 str += " _typelib_guid_ = tlb_guid\n"
261 str += " _typelib_version_ = 1, 0\n"
262
263 # generate capitalized version of callbacks - that's how Python COM
264 # looks them up on Windows
265 for m in dir(impl):
266 if m.startswith("on"):
267 str += " "+ComifyName(m)+"=BaseClass."+m+"\n"
268
269 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
270 str += "result = win32com.client.Dispatch('VirtualBox.VirtualBoxCallback')\n"
271 str += "result.SetLocalObject(win32com.server.util.wrap("+iface+"Impl())\n"
272 exec (str,d,d)
273 return d['result']
274
275 def waitForEvents(self, timeout):
276 from win32api import GetCurrentThreadId
277 from win32event import MsgWaitForMultipleObjects, \
278 QS_ALLINPUT, WAIT_TIMEOUT, WAIT_OBJECT_0
279 from pythoncom import PumpWaitingMessages
280
281 if (self.tid != GetCurrentThreadId()):
282 raise Exception("wait for events from the same thread you inited!")
283
284 rc = MsgWaitForMultipleObjects(self.handles, 0, timeout, QS_ALLINPUT)
285 if rc >= WAIT_OBJECT_0 and rc < WAIT_OBJECT_0+len(self.handles):
286 # is it possible?
287 pass
288 elif rc==WAIT_OBJECT_0 + len(self.handles):
289 # Waiting messages
290 PumpWaitingMessages()
291 else:
292 # Timeout
293 pass
294
295 def deinit(self):
296 import pythoncom
297 from win32file import CloseHandle
298
299 for h in self.handles:
300 if h is not None:
301 CloseHandle(h)
302 self.handles = None
303 pythoncom.CoUninitialize()
304 pass
305
306
307class PlatformXPCOM:
308 def __init__(self, params):
309 sys.path.append(VboxSdkDir+'/bindings/xpcom/python/')
310 import xpcom.vboxxpcom
311 import xpcom
312 import xpcom.components
313
314 def getSessionObject(self, vbox):
315 import xpcom.components
316 return xpcom.components.classes["@virtualbox.org/Session;1"].createInstance()
317
318 def getVirtualBox(self):
319 import xpcom.components
320 return xpcom.components.classes["@virtualbox.org/VirtualBox;1"].createInstance()
321
322 def getType(self):
323 return 'XPCOM'
324
325 def getRemote(self):
326 return False
327
328 def getArray(self, obj, field):
329 return obj.__getattr__('get'+ComifyName(field))()
330
331 def initPerThread(self):
332 pass
333
334 def deinitPerThread(self):
335 pass
336
337 def createCallback(self, iface, impl, arg):
338 d = {}
339 d['BaseClass'] = impl
340 d['arg'] = arg
341 str = ""
342 str += "import xpcom.components\n"
343 str += "class "+iface+"Impl(BaseClass):\n"
344 str += " _com_interfaces_ = xpcom.components.interfaces."+iface+"\n"
345 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
346 str += "result = xpcom.components.classes['@virtualbox.org/VirtualBoxCallback;1'].createInstance()\n"
347 str += "result.setLocalObject("+iface+"Impl())\n"
348 exec (str,d,d)
349 return d['result']
350
351 def waitForEvents(self, timeout):
352 import xpcom
353 xpcom._xpcom.WaitForEvents(timeout)
354
355 def deinit(self):
356 import xpcom
357 xpcom._xpcom.DeinitCOM()
358
359class PlatformWEBSERVICE:
360 def __init__(self, params):
361 sys.path.append(os.path.join(VboxSdkDir,'bindings', 'webservice', 'python', 'lib'))
362 # not really needed, but just fail early if misconfigured
363 import VirtualBox_services
364 import VirtualBox_wrappers
365 from VirtualBox_wrappers import IWebsessionManager2
366
367 if params is not None:
368 self.user = params.get("user", "")
369 self.password = params.get("password", "")
370 self.url = params.get("url", "")
371 else:
372 self.user = ""
373 self.password = ""
374 self.url = None
375 self.vbox = None
376
377 def getSessionObject(self, vbox):
378 return self.wsmgr.getSessionObject(vbox)
379
380 def getVirtualBox(self):
381 return self.connect(self.url, self.user, self.password)
382
383 def connect(self, url, user, passwd):
384 if self.vbox is not None:
385 self.disconnect()
386 from VirtualBox_wrappers import IWebsessionManager2
387 if url is None:
388 url = ""
389 self.url = url
390 if user is None:
391 user = ""
392 self.user = user
393 if passwd is None:
394 passwd = ""
395 self.password = passwd
396 self.wsmgr = IWebsessionManager2(self.url)
397 self.vbox = self.wsmgr.logon(self.user, self.password)
398 if not self.vbox.handle:
399 raise Exception("cannot connect to '"+self.url+"' as '"+self.user+"'")
400 return self.vbox
401
402 def disconnect(self):
403 if self.vbox is not None and self.wsmgr is not None:
404 self.wsmgr.logoff(self.vbox)
405 self.vbox = None
406 self.wsmgr = None
407
408 def getType(self):
409 return 'WEBSERVICE'
410
411 def getRemote(self):
412 return True
413
414 def getArray(self, obj, field):
415 return obj.__getattr__(field)
416
417 def initPerThread(self):
418 pass
419
420 def deinitPerThread(self):
421 pass
422
423 def createCallback(self, iface, impl, arg):
424 raise Exception("no callbacks for webservices")
425
426 def waitForEvents(self, timeout):
427 # Webservices cannot do that yet
428 pass
429
430 def deinit(self):
431 try:
432 disconnect()
433 except:
434 pass
435
436class SessionManager:
437 def __init__(self, mgr):
438 self.mgr = mgr
439
440 def getSessionObject(self, vbox):
441 return self.mgr.platform.getSessionObject(vbox)
442
443class VirtualBoxManager:
444 def __init__(self, style, platparams):
445 if style is None:
446 if sys.platform == 'win32':
447 style = "MSCOM"
448 else:
449 style = "XPCOM"
450
451
452 exec "self.platform = Platform"+style+"(platparams)"
453 # for webservices, enums are symbolic
454 self.constants = VirtualBoxReflectionInfo(style == "WEBSERVICE")
455 self.type = self.platform.getType()
456 self.remote = self.platform.getRemote()
457 self.style = style
458 self.mgr = SessionManager(self)
459
460 try:
461 self.vbox = self.platform.getVirtualBox()
462 except NameError,ne:
463 print "Installation problem: check that appropriate libs in place"
464 traceback.print_exc()
465 raise ne
466 except Exception,e:
467 print "init exception: ",e
468 traceback.print_exc()
469 if self.remote:
470 self.vbox = None
471 else:
472 raise e
473
474 def getArray(self, obj, field):
475 return self.platform.getArray(obj, field)
476
477 def getVirtualBox(self):
478 return self.platform.getVirtualBox()
479
480 def __del__(self):
481 self.deinit()
482
483 def deinit(self):
484 if hasattr(self, "vbox"):
485 del self.vbox
486 self.vbox = None
487 if hasattr(self, "platform"):
488 self.platform.deinit()
489 self.platform = None
490
491 def initPerThread(self):
492 self.platform.initPerThread()
493
494 def openMachineSession(self, machineId):
495 session = self.mgr.getSessionObject(self.vbox)
496 self.vbox.openSession(session, machineId)
497 return session
498
499 def closeMachineSession(self, session):
500 session.close()
501
502 def deinitPerThread(self):
503 self.platform.deinitPerThread()
504
505 def createCallback(self, iface, impl, arg):
506 return self.platform.createCallback(iface, impl, arg)
507
508 def waitForEvents(self, timeout):
509 return self.platform.waitForEvents(timeout)
510
511 def getPerfCollector(self, vbox):
512 return PerfCollector(self, vbox)
Note: See TracBrowser for help on using the repository browser.

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