Remove the public domainEventRegisterAny and domainEventDeregisterAny
methods. These methods basically were of no use since the only thing you
could register was a "generic" callback.
At runtime, you would have to provide a real callback function matching
the prototype of the native callback type.
Trying to use a generic callback instead quickly leads to failures or
JVM crashes.
For convenience and the sake of type safety we don't let the
user deal with Libvirt.VirDomainEventCallback interfaces directly.
Instead, there will be a specific interface definition for each type
of callback as we soon shall see.
To prevent the garbage collector from reaping registered callback objects
every event callback will be stored along with its eventID and
corresponding listener instance.
This will provide a natural, idiomatic interface using
addListener/removeListener methods.
Signed-off-by: Claudio Bley <cbley(a)av-test.de>
---
src/main/java/org/libvirt/Connect.java | 79 ++++++++++++--------
src/main/java/org/libvirt/event/EventListener.java | 7 ++
src/main/java/org/libvirt/jna/Libvirt.java | 22 ++++--
3 files changed, 73 insertions(+), 35 deletions(-)
create mode 100644 src/main/java/org/libvirt/event/EventListener.java
diff --git a/src/main/java/org/libvirt/Connect.java
b/src/main/java/org/libvirt/Connect.java
index 8ba9691..14668ef 100644
--- a/src/main/java/org/libvirt/Connect.java
+++ b/src/main/java/org/libvirt/Connect.java
@@ -1,7 +1,10 @@
package org.libvirt;
+import java.util.HashMap;
+import java.util.Map;
import java.util.UUID;
+import org.libvirt.event.*;
import org.libvirt.jna.ConnectionPointer;
import org.libvirt.jna.DevicePointer;
import org.libvirt.jna.DomainPointer;
@@ -33,6 +36,14 @@ import com.sun.jna.ptr.LongByReference;
*/
public class Connect {
+ // registered event listeners by DomainEventID
+ private Map<EventListener, Integer>[] eventListeners =
makeHashMapArray(DomainEventID.LAST);
+
+ @SuppressWarnings("unchecked")
+ private static <K, V> HashMap<K, V>[] makeHashMapArray(int size) {
+ return new HashMap[size];
+ }
+
/**
* Event IDs.
*/
@@ -354,42 +365,50 @@ public class Connect {
}
/**
- * Removes an event callback.
+ * Removes the event listener for the given eventID parameter so
+ * that it no longer receives events.
+ *
+ * @param eventID the domain event identifier
+ * @param l the event listener
+ * @throws LibvirtException
*
* @see <a
- *
href="http://www.libvirt.org/html/libvirt-libvirt.html#virConnectDom...
- * Documentation</a>
- * @param callbackID
- * the callback to deregister
- * @return <em>ignore</em> (always 0)
- * @throws LibvirtException
+ *
href="http://www.libvirt.org/html/libvirt-libvirt.html#virConnectDom...
+ * >virConnectDomainEventDeregisterAny</a>
*/
- public int domainEventDeregisterAny(int callbackID) throws LibvirtException {
- return processError(libvirt.virConnectDomainEventDeregisterAny(VCP,
callbackID));
+ private void domainEventDeregister(int eventID, EventListener l) throws
LibvirtException {
+ if (l == null)
+ return;
+
+ Map<EventListener, Integer> handlers = eventListeners[eventID];
+
+ if (handlers == null) return;
+
+ Integer listenerID = handlers.remove(l);
+
+ if (listenerID != null)
+ processError(libvirt.virConnectDomainEventDeregisterAny(VCP, listenerID));
}
- /**
- * Adds a callback to receive notifications of arbitrary domain events
- * occurring on a domain.
- *
- * @see <a
- *
href="http://www.libvirt.org/html/libvirt-libvirt.html#virConnectDom...
- * Documentation</a>
- * @param domain
- * option domain to limit the events monitored
- * @param eventId
- * the events to monitor
- * @param cb
- * the callback function to use.
- * @return The return value from this method is a positive integer
- * identifier for the callback.
- * @throws LibvirtException on failure
- */
- public int domainEventRegisterAny(Domain domain, int eventId,
Libvirt.VirConnectDomainEventGenericCallback cb)
- throws LibvirtException {
+ private void domainEventRegister(Domain domain, int eventID,
Libvirt.VirDomainEventCallback cb, EventListener l)
+ throws LibvirtException
+ {
+ Map<EventListener, Integer> handlers = eventListeners[eventID];
+
+ if (handlers == null) {
+ handlers = new HashMap<EventListener, Integer>();
+ eventListeners[eventID] = handlers;
+ } else if (handlers.containsKey(l)) {
+ return;
+ }
+
DomainPointer ptr = domain == null ? null : domain.VDP;
- int returnValue = libvirt.virConnectDomainEventRegisterAny(VCP, ptr, eventId, cb,
null, null);
- return processError(returnValue);
+
+ int ret = processError(libvirt.virConnectDomainEventRegisterAny(VCP, ptr,
+ eventID, cb,
+ null, null));
+
+ handlers.put(l, ret);
}
/**
diff --git a/src/main/java/org/libvirt/event/EventListener.java
b/src/main/java/org/libvirt/event/EventListener.java
new file mode 100644
index 0000000..fe7e127
--- /dev/null
+++ b/src/main/java/org/libvirt/event/EventListener.java
@@ -0,0 +1,7 @@
+package org.libvirt.event;
+
+/**
+ * Base interface implemented by every event listener.
+ */
+public interface EventListener {
+}
diff --git a/src/main/java/org/libvirt/jna/Libvirt.java
b/src/main/java/org/libvirt/jna/Libvirt.java
index ed52bd3..9eb9e86 100644
--- a/src/main/java/org/libvirt/jna/Libvirt.java
+++ b/src/main/java/org/libvirt/jna/Libvirt.java
@@ -66,6 +66,19 @@ public interface Libvirt extends Library {
}
/**
+ * Domain Event Callbacks
+ */
+
+ /**
+ * Common Event Callback super interface.
+ *
+ * All domain event callbacks extend this interface.
+ *
+ * @see #virConnectDomainEventRegisterAny
+ */
+ interface VirDomainEventCallback extends Callback {}
+
+ /**
* Error callback
*/
interface VirErrorCallback extends Callback {
@@ -94,10 +107,6 @@ public interface Libvirt extends Library {
void freeCallback(Pointer opaque) ;
}
- interface VirConnectDomainEventGenericCallback extends Callback {
- void eventCallback(ConnectionPointer virConnectPtr, DomainPointer
virDomainPointer, Pointer opaque) ;
- }
-
/*
* Timeout Callback
*/
@@ -125,7 +134,10 @@ public interface Libvirt extends Library {
int virConnCopyLastError(ConnectionPointer virConnectPtr, virError to);
int virConnectClose(ConnectionPointer virConnectPtr);
int virConnectCompareCPU(ConnectionPointer virConnectPtr, String xmlDesc, int
flags);
- int virConnectDomainEventRegisterAny(ConnectionPointer virConnectPtr, DomainPointer
virDomainPtr, int eventID, Libvirt.VirConnectDomainEventGenericCallback cb, Pointer
opaque, Libvirt.VirFreeCallback freecb);
+
+ // Register Domain Event Callbacks
+ int virConnectDomainEventRegisterAny(ConnectionPointer virConnectPtr, DomainPointer
virDomainPtr, int eventID, VirDomainEventCallback cb, Pointer opaque,
Libvirt.VirFreeCallback freecb);
+
int virConnectDomainEventDeregisterAny(ConnectionPointer virConnectPtr, int
callbackID) ;
void virConnSetErrorFunc(ConnectionPointer virConnectPtr, Pointer userData,
VirErrorCallback callback);
int virConnectIsAlive(ConnectionPointer virConnectPtr);
--
1.7.9.5