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@xxxxxxxxxx> --- 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#virConnectDomainEventDeregisterAny">Libvirt - * 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#virConnectDomainEventDeregisterAny" + * >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#virConnectDomainEventRegisterAny">Libvirt - * 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list