Skip to content

Instantly share code, notes, and snippets.

@maxidorius
Last active May 24, 2022 09:12
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxidorius/8e1d09f831a3b75fb3043b5737d0014d to your computer and use it in GitHub Desktop.
Save maxidorius/8e1d09f831a3b75fb3043b5737d0014d to your computer and use it in GitHub Desktop.
VirtualBox - 5.1 API - Sample code to illustrate event management with Java bindings
/*
* Copyright (c) 2017 Maxime Dor
*
* https://max.kamax.io/
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
import org.virtualbox_5_1.*;
import java.util.Arrays;
import java.util.List;
public class CatchEvents_5_1 {
static VirtualBoxManager mgr;
static Thread listener;
public static void main(String args[]) {
String vmName = Long.toString(System.currentTimeMillis()); // get a random VM name to use later
System.out.println("Creating VirtualBox client instance");
mgr = VirtualBoxManager.createInstance(null);
try {
/*
* This line is only required if you are using the WebServices to connect.
* Also, change "user" and "password" to local credentials on the machine running the web services, or set authentication to null.
* To do so, you can start vboxwevsrv with "-A null" argument or use vboxmanage to make it permanent.
*/
System.out.println("Connecting to VirtualBox using Web Services");
mgr.connect("http://localhost:18083", "user", "password"); // only if you are using WebServices Bindings
System.out.println("Connected to VirtualBox using Web Services");
/*
* We will run the event worker in a separate thread like it would normally be done.
*/
listener = new EventWorker();
listener.start();
try {
/*
* We create an empty machine, we save its settings to disk (to actually make it really exist) than we register it.
* This will trigger IMachineRegisteredEvent.
*/
IMachine vm = mgr.getVBox().createMachine(null, vmName, null, "Other", null);
vm.saveSettings();
mgr.getVBox().registerMachine(vm);
vm = mgr.getVBox().findMachine(vmName); // we fetch the machine object again just to be safe
ISession session = mgr.getSessionObject();
IProgress p = vm.launchVMProcess(session, "headless", null);
p.waitForCompletion(-1); // we wait until the starting process has finished
try {
if (p.getResultCode() != 0) { // error when starting the VM, we don't continue further
throw new RuntimeException(p.getErrorInfo().getText());
} else { // VM got started, OnMachineStateChanged triggered two times at this point
// let's now power down the VM
p = session.getConsole().powerDown();
p.waitForCompletion(-1);
if (p.getResultCode() != 0) { // we failed to stop the VM
throw new RuntimeException(p.getErrorInfo().getText());
} else {
// VM got stopped, OnMachineStateChanged triggered several times at this point
}
}
} finally {
// we do not need the lock any further and is required for for IMachine::unregister()
session.unlockMachine();
// since unlock is not instant, we need to wait until the unlock is done or unregister() will fail.
while (!SessionState.Unlocked.equals(vm.getSessionState())) {
try {
System.out.println("Waiting for session unlock...");
Thread.sleep(1000L);
} catch (InterruptedException e) {
System.err.println("Interrupted while waiting for session to be unlocked");
}
}
// vm.unregister() will trigger IMachineRegisteredEvent.
System.out.println("Deleting machine");
vm.deleteConfig(vm.unregister(CleanupMode.DetachAllReturnHardDisksOnly));
}
} finally { // we instruct the Event Worker to stop and wait 5 sec for it to do so
listener.interrupt();
try {
listener.join(5000); // we wait on the thread
} catch (InterruptedException e) {
System.err.println("Interrupted while waiting for EventWorker to stop");
}
if (listener.isAlive()) {
System.err.println("Event worked did not stop in a timely fashion");
} else {
System.out.println("Event worked stopped");
}
}
} finally {
mgr.disconnect(); // only if you are using WebServices Bindings
mgr.cleanup();
System.out.println("Disconnected from VirtualBox - bye bye!");
}
}
static class EventWorker extends Thread {
IEventListener el;
@Override
public void run() {
System.out.println("EventWorker started");
el = mgr.getVBox().getEventSource().createListener(); // we create the object that will fetch and queue the events for us
/*
* We register for the events that we are interested in.
* If we wanted all of them, we would use VBoxEventType.Any
*
* Not all events will be visible here. If we want events for a specific machine (like Clipboard mode change),
* we need to use the event source of that specific machine - see IMachine::getEventSource()
*/
List<VBoxEventType> types = Arrays.asList(VBoxEventType.OnSessionStateChanged, VBoxEventType.OnMachineStateChanged,
VBoxEventType.OnMachineRegistered);
mgr.getVBox().getEventSource().registerListener(el, types, false);
try {
while (!isInterrupted()) {
mgr.waitForEvents(0); // Needed to clear the internal event queue, see https://www.virtualbox.org/ticket/13647
IEvent rawEvent = mgr.getVBox().getEventSource().getEvent(el, 1000);
if (rawEvent == null) { // we waited but no event came
continue; // we loop again and skip the code below
}
try {
System.out.println("Got event of type " + rawEvent.getType());
if (VBoxEventType.OnSessionStateChanged.equals(rawEvent.getType())) {
// It is important to use the queryInterface() on the expected class, simple casting will not work.
ISessionStateChangedEvent event = ISessionStateChangedEvent.queryInterface(rawEvent);
System.out.println("Session state changed to " + event.getState() + " for machine " + event.getMachineId());
}
if (VBoxEventType.OnMachineRegistered.equals(rawEvent.getType())) { // we check the event type
// It is important to use the queryInterface() on the expected class, simple casting will not work.
IMachineRegisteredEvent event = IMachineRegisteredEvent.queryInterface(rawEvent);
System.out.println("Machine " + event.getMachineId() + " has been " + (event.getRegistered() ? "registered" : "unregistered"));
}
if (VBoxEventType.OnMachineStateChanged.equals(rawEvent.getType())) {
// It is important to use the queryInterface() on the expected class, simple casting will not work.
IMachineStateChangedEvent event = IMachineStateChangedEvent.queryInterface(rawEvent);
System.out.println("Machine " + event.getMachineId() + " state changed to " + event.getState());
}
} finally {
// We mark the event as processed so ressources can be released. We do this in a finally block to ensure it is done no matter what.
mgr.getVBox().getEventSource().eventProcessed(el, rawEvent);
}
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
mgr.getVBox().getEventSource().unregisterListener(el); // we are done fetching events, so we free the listener
System.out.println("EventWorker finished");
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment