You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by mj...@apache.org on 2017/10/06 16:51:29 UTC

[12/17] incubator-guacamole-client git commit: GUACAMOLE-364: declare and implement new listener API

GUACAMOLE-364: declare and implement new listener API

This commit also deprecates the existing listener API and
includes support for adapting existing listener implementations
to the new API.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/commit/f63c8b43
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/f63c8b43
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/f63c8b43

Branch: refs/heads/master
Commit: f63c8b43a8277f9d38ada78f4acac72e02fcbed6
Parents: 2062f1c
Author: Carl Harris <ce...@vt.edu>
Authored: Thu Sep 7 16:58:44 2017 -0400
Committer: Carl Harris <ce...@vt.edu>
Committed: Thu Sep 7 16:58:44 2017 -0400

----------------------------------------------------------------------
 ...uacamoleAuthenticationRejectedException.java |  33 ---
 .../GuacamoleTunnelConnectedException.java      |  32 ---
 .../GuacamoleTunnelRejectedException.java       |  32 ---
 .../net/event/AuthenticationSuccessEvent.java   |   5 +
 .../guacamole/net/event/TunnelCloseEvent.java   |   4 +
 .../guacamole/net/event/TunnelConnectEvent.java |   4 +
 .../listener/AuthenticationFailureListener.java |   6 +-
 .../listener/AuthenticationSuccessListener.java |   6 +-
 .../guacamole/net/event/listener/Listener.java  |  29 ++-
 .../net/event/listener/TunnelCloseListener.java |   6 +-
 .../event/listener/TunnelConnectListener.java   |   6 +-
 .../apache/guacamole/extension/Extension.java   |  10 +-
 .../guacamole/extension/ExtensionModule.java    |  42 +--
 .../guacamole/extension/ListenerFacade.java     | 134 ----------
 .../guacamole/extension/ListenerFactory.java    | 256 +++++++++++++++++++
 .../rest/auth/AuthenticationService.java        |  35 +--
 .../guacamole/rest/event/ListenerService.java   | 108 +-------
 .../guacamole/tunnel/TunnelRequestService.java  |  41 +--
 18 files changed, 378 insertions(+), 411 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole-common/src/main/java/org/apache/guacamole/GuacamoleAuthenticationRejectedException.java
----------------------------------------------------------------------
diff --git a/guacamole-common/src/main/java/org/apache/guacamole/GuacamoleAuthenticationRejectedException.java b/guacamole-common/src/main/java/org/apache/guacamole/GuacamoleAuthenticationRejectedException.java
deleted file mode 100644
index 907e0c9..0000000
--- a/guacamole-common/src/main/java/org/apache/guacamole/GuacamoleAuthenticationRejectedException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.guacamole;
-
-/**
- * An exception thrown when a successful authentication is rejected by a
- * AuthenticationSuccessListener in an extension.
- */
-public class GuacamoleAuthenticationRejectedException
-    extends GuacamoleSecurityException {
-
-    public GuacamoleAuthenticationRejectedException() {
-        super("authentication rejected by listener extension");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole-common/src/main/java/org/apache/guacamole/GuacamoleTunnelConnectedException.java
----------------------------------------------------------------------
diff --git a/guacamole-common/src/main/java/org/apache/guacamole/GuacamoleTunnelConnectedException.java b/guacamole-common/src/main/java/org/apache/guacamole/GuacamoleTunnelConnectedException.java
deleted file mode 100644
index c7d21cf..0000000
--- a/guacamole-common/src/main/java/org/apache/guacamole/GuacamoleTunnelConnectedException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.guacamole;
-
-/**
- * An exception thrown when a request to close a tunnel is vetoed by a
- * TunnelCloseListener in an extension.
- */
-public class GuacamoleTunnelConnectedException extends GuacamoleClientException {
-
-    public GuacamoleTunnelConnectedException() {
-        super("tunnel close vetoed by listener extension");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole-common/src/main/java/org/apache/guacamole/GuacamoleTunnelRejectedException.java
----------------------------------------------------------------------
diff --git a/guacamole-common/src/main/java/org/apache/guacamole/GuacamoleTunnelRejectedException.java b/guacamole-common/src/main/java/org/apache/guacamole/GuacamoleTunnelRejectedException.java
deleted file mode 100644
index b9367c1..0000000
--- a/guacamole-common/src/main/java/org/apache/guacamole/GuacamoleTunnelRejectedException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.guacamole;
-
-/**
- * An exception thrown when a successful tunnel connection is rejected by a
- * TunnelConnectListener in an extension.
- */
-public class GuacamoleTunnelRejectedException extends GuacamoleClientException {
-
-    public GuacamoleTunnelRejectedException() {
-        super("tunnel connection rejected by listener extension");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole-ext/src/main/java/org/apache/guacamole/net/event/AuthenticationSuccessEvent.java
----------------------------------------------------------------------
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/AuthenticationSuccessEvent.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/AuthenticationSuccessEvent.java
index 2e5ae3a..c72d669 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/AuthenticationSuccessEvent.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/AuthenticationSuccessEvent.java
@@ -26,6 +26,11 @@ import org.apache.guacamole.net.auth.UserContext;
  * An event which is triggered whenever a user's credentials pass
  * authentication. The credentials that passed authentication are included
  * within this event, and can be retrieved using getCredentials().
+ * <p>
+ * If a {@link org.apache.guacamole.net.event.listener.Listener} throws
+ * a GuacamoleException when handling an event of this type, successful authentication
+ * is effectively <em>vetoed</em> and will be subsequently processed as though the
+ * authentication failed.
  */
 public class AuthenticationSuccessEvent implements UserEvent, CredentialEvent {
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole-ext/src/main/java/org/apache/guacamole/net/event/TunnelCloseEvent.java
----------------------------------------------------------------------
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/TunnelCloseEvent.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/TunnelCloseEvent.java
index ab453e8..c0e2a62 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/TunnelCloseEvent.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/TunnelCloseEvent.java
@@ -28,6 +28,10 @@ import org.apache.guacamole.net.auth.UserContext;
  * being closed can be accessed through getTunnel(), and the UserContext
  * associated with the request which is closing the tunnel can be retrieved
  * with getUserContext().
+ * <p>
+ * If a {@link org.apache.guacamole.net.event.listener.Listener} throws
+ * a GuacamoleException when handling an event of this type, the request to close
+ * the tunnel is effectively <em>vetoed</em> and will remain connected.
  */
 public class TunnelCloseEvent implements UserEvent, CredentialEvent, TunnelEvent {
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole-ext/src/main/java/org/apache/guacamole/net/event/TunnelConnectEvent.java
----------------------------------------------------------------------
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/TunnelConnectEvent.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/TunnelConnectEvent.java
index acf5e89..62828db 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/TunnelConnectEvent.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/TunnelConnectEvent.java
@@ -28,6 +28,10 @@ import org.apache.guacamole.net.auth.UserContext;
  * being connected can be accessed through getTunnel(), and the UserContext
  * associated with the request which is connecting the tunnel can be retrieved
  * with getUserContext().
+ * <p>
+ * If a {@link org.apache.guacamole.net.event.listener.Listener} throws
+ * a GuacamoleException when handling an event of this type, the tunnel connection
+ * is effectively <em>vetoed</em> and will be subsequently closed.
  */
 public class TunnelConnectEvent implements UserEvent, CredentialEvent, TunnelEvent {
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/AuthenticationFailureListener.java
----------------------------------------------------------------------
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/AuthenticationFailureListener.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/AuthenticationFailureListener.java
index 86122ba..1971af8 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/AuthenticationFailureListener.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/AuthenticationFailureListener.java
@@ -26,8 +26,12 @@ import org.apache.guacamole.net.event.AuthenticationFailureEvent;
  * A listener whose authenticationFailed() hook will fire immediately
  * after a user's authentication attempt fails. Note that this hook cannot
  * be used to cancel the authentication failure.
+ *
+ * @deprecated
+ *      Listeners should instead implement the {@link Listener} interface
  */
-public interface AuthenticationFailureListener extends Listener {
+@Deprecated
+public interface AuthenticationFailureListener {
 
     /**
      * Event hook which fires immediately after a user's authentication attempt

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/AuthenticationSuccessListener.java
----------------------------------------------------------------------
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/AuthenticationSuccessListener.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/AuthenticationSuccessListener.java
index cc5e01d..77a6ed1 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/AuthenticationSuccessListener.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/AuthenticationSuccessListener.java
@@ -27,8 +27,12 @@ import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
  * authentication attempt succeeds. If a user successfully authenticates,
  * the authenticationSucceeded() hook has the opportunity to cancel the
  * authentication and force it to fail.
+ *
+ * @deprecated
+ *      Listeners should instead implement the {@link Listener} interface
  */
-public interface AuthenticationSuccessListener extends Listener {
+@Deprecated
+public interface AuthenticationSuccessListener {
 
     /**
      * Event hook which fires immediately after a user's authentication attempt

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/Listener.java
----------------------------------------------------------------------
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/Listener.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/Listener.java
index 5849993..d21f686 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/Listener.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/Listener.java
@@ -19,10 +19,33 @@
 
 package org.apache.guacamole.net.event.listener;
 
+import org.apache.guacamole.GuacamoleException;
+
 /**
- * A marker interface extended by all listener types. This interface is used
- * simply to validate that a listener class identified in an extension
- * actually implements some listener interface.
+ * A listener for events that occur in handing various Guacamole requests
+ * such as authentication, tunnel connect/close, etc. Listeners are registered
+ * through the extension manifest mechanism. When an event occurs, listeners
+ * are notified in the order in which they are declared in the manifest and
+ * continues until either all listeners have been notified or with the first
+ * listener that throws a GuacamoleException or other runtime exception.
  */
 public interface Listener {
+
+    /**
+     * Notifies the recipient that an event has occurred.
+     * <p>
+     * Throwing an exception from an event listener can act to veto an action in
+     * progress for some event types. See the Javadoc for specific event types for
+     * details.
+     *
+     * @param event
+     *     an object that describes the subject event
+     *
+     * @throws GuacamoleException
+     *     If the listener wishes to stop notification of the event to subsequent
+     *     listeners. For some event types, this acts to veto an action in progress;
+     *     e.g. treating a successful authentication as though it failed
+     */
+    void handleEvent(Object event) throws GuacamoleException;
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/TunnelCloseListener.java
----------------------------------------------------------------------
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/TunnelCloseListener.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/TunnelCloseListener.java
index 99f2c04..70677b3 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/TunnelCloseListener.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/TunnelCloseListener.java
@@ -25,8 +25,12 @@ import org.apache.guacamole.net.event.TunnelCloseEvent;
 /**
  * A listener whose tunnelClosed() hook will fire immediately after an
  * existing tunnel is closed.
+ *
+ * @deprecated
+ *      Listeners should instead implement the {@link Listener} interface
  */
-public interface TunnelCloseListener extends Listener {
+@Deprecated
+public interface TunnelCloseListener {
 
     /**
      * Event hook which fires immediately before an existing tunnel is closed.

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/TunnelConnectListener.java
----------------------------------------------------------------------
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/TunnelConnectListener.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/TunnelConnectListener.java
index 7ac47e1..edc144e 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/TunnelConnectListener.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/listener/TunnelConnectListener.java
@@ -25,8 +25,12 @@ import org.apache.guacamole.net.event.TunnelConnectEvent;
 /**
  * A listener whose tunnelConnected() hook will fire immediately after a new
  * tunnel is connected.
+ *
+ * @deprecated
+ *      Listeners should instead implement the {@link Listener} interface
  */
-public interface TunnelConnectListener extends Listener {
+@Deprecated
+public interface TunnelConnectListener {
 
    /**
      * Event hook which fires immediately after a new tunnel is connected.

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole/src/main/java/org/apache/guacamole/extension/Extension.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/Extension.java b/guacamole/src/main/java/org/apache/guacamole/extension/Extension.java
index 697002d..dc43b8f 100644
--- a/guacamole/src/main/java/org/apache/guacamole/extension/Extension.java
+++ b/guacamole/src/main/java/org/apache/guacamole/extension/Extension.java
@@ -113,7 +113,7 @@ public class Extension {
     /**
      * The collection of all Listener classes defined within the extension.
      */
-    private final Collection<Class<Listener>> listenerClasses;
+    private final Collection<Class<?>> listenerClasses;
 
     /**
      * The resource for the small favicon for the extension. If provided, this
@@ -328,15 +328,15 @@ public class Extension {
      *     If any given class does not exist, or if any given class is not a
      *     subclass of AuthenticationProvider.
      */
-    private Collection<Class<Listener>> getListenerClasses(Collection<String> names)
+    private Collection<Class<?>> getListenerClasses(Collection<String> names)
             throws GuacamoleException {
 
         // If no classnames are provided, just return an empty list
         if (names == null)
-            return Collections.<Class<Listener>>emptyList();
+            return Collections.<Class<?>>emptyList();
 
         // Define all auth provider classes
-        Collection<Class<Listener>> classes = new ArrayList<Class<Listener>>(names.size());
+        Collection<Class<?>> classes = new ArrayList<Class<?>>(names.size());
         for (String name : names)
             classes.add(getListenerClass(name));
 
@@ -578,7 +578,7 @@ public class Extension {
      * @return
      *     All declared listener classes with this extension.
      */
-    public Collection<Class<Listener>> getListenerClasses() {
+    public Collection<Class<?>> getListenerClasses() {
         return listenerClasses;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java
index 1e1a854..f3ca700 100644
--- a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java
+++ b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java
@@ -95,8 +95,8 @@ public class ExtensionModule extends ServletModule {
     /**
      * All currently-bound authentication providers, if any.
      */
-    private final List<ListenerProvider> boundListenerProviders =
-            new ArrayList<ListenerProvider>();
+    private final List<Listener> boundListners =
+            new ArrayList<Listener>();
 
     /**
      * Service for adding and retrieving language resources.
@@ -195,19 +195,19 @@ public class ExtensionModule extends ServletModule {
     }
 
     /**
-     * Binds the given Listener class such that any service
-     * requiring access to the Listener can obtain it via
-     * injection, along with any other bound Listener.
-     *
-     * @param listenerClass
-     *     The Listener class to bind.
+     * Binds the given provider class such that a listener is bound for each
+     * listener interface implemented by the provider and such that all bound
+     * listener instances can be obtained via injection.
+     * *
+     * @param providerClass
+     *     The listener provider class to bind
      */
-    private void bindListenerProvider(Class<? extends Listener> listenerClass) {
+    private void bindListeners(Class<?> providerClass) {
+
+        logger.debug("[{}] Binding listeners \"{}\".",
+                boundListners.size(), providerClass.getName());
+        boundListners.addAll(ListenerFactory.createListeners(providerClass));
 
-        // Bind listener
-        logger.debug("[{}] Binding Listener \"{}\".",
-                boundListenerProviders.size(), listenerClass.getName());
-        boundListenerProviders.add(new ListenerFacade(listenerClass));
     }
 
     /**
@@ -218,23 +218,23 @@ public class ExtensionModule extends ServletModule {
      * @param listeners
      *     The Listener classes to bind.
      */
-    private void bindListenerProviders(Collection<Class<Listener>> listeners) {
+    private void bindListeners(Collection<Class<?>> listeners) {
 
         // Bind each listener within extension
-        for (Class<Listener> listener : listeners)
-            bindListenerProvider(listener);
+        for (Class<?> listener : listeners)
+            bindListeners(listener);
     }
 
     /**
-     * Returns a list of all currently-bound ListenerProvider instances.
+     * Returns a list of all currently-bound Listener instances.
      *
      * @return
-     *     A List of all currently-bound ListenerProvider instances. The List is
+     *     A List of all currently-bound Listener instances. The List is
      *     not modifiable.
      */
     @Provides
-    public List<ListenerProvider> getListenerProviders() {
-        return Collections.unmodifiableList(boundListenerProviders);
+    public List<Listener> getListeners() {
+        return Collections.unmodifiableList(boundListners);
     }
 
     /**
@@ -378,7 +378,7 @@ public class ExtensionModule extends ServletModule {
                 bindAuthenticationProviders(extension.getAuthenticationProviderClasses());
 
                 // Attempt to load all listeners
-                bindListenerProviders(extension.getListenerClasses());
+                bindListeners(extension.getListenerClasses());
 
                 // Add any translation resources
                 serveLanguageResources(extension.getTranslationResources());

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFacade.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFacade.java b/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFacade.java
deleted file mode 100644
index ab0b7c8..0000000
--- a/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFacade.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.guacamole.extension;
-
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.net.event.AuthenticationFailureEvent;
-import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
-import org.apache.guacamole.net.event.TunnelCloseEvent;
-import org.apache.guacamole.net.event.TunnelConnectEvent;
-import org.apache.guacamole.net.event.listener.*;
-
-/**
- * Provides a wrapper around a Listener subclass, allowing listener
- * extensions to be bound without regard for which specific listener interfaces
- * are implemented.
- */
-class ListenerFacade implements ListenerProvider {
-
-    private final Listener delegate;
-
-    /**
-     * Creates a new ListenerFacade which delegates all listener methods
-     * calls to an instance of the given Listener subclass. If
-     * an instance of the given class cannot be created, creation of this
-     * facade will still succeed. Errors will be logged at the time listener
-     * creation fails, but subsequent events directed to the listener will be
-     * silently dropped.
-     *
-     * @param listenerClass
-     *     The Listener subclass to instantiate.
-     */
-    public ListenerFacade(Class<? extends Listener> listenerClass) {
-        delegate = ProviderFactory.newInstance("listener", listenerClass);
-    }
-
-    /**
-     * Notifies the delegate listener of an authentication success event, if the
-     * listener implements the AuthenticationSuccessListener interface.
-     *
-     * @param
-     *      event The AuthenticationSuccessEvent describing the authentication
-     *        success that just occurred.
-     * @return
-     *      false if the delegate listener rejects the successful authentication,
-     *      else true
-     *
-     * @throws GuacamoleException
-     *      if the delegate listener throws this exception
-     */
-    @Override
-    public boolean authenticationSucceeded(AuthenticationSuccessEvent event)
-            throws GuacamoleException {
-        return !(delegate instanceof AuthenticationSuccessListener)
-                || ((AuthenticationSuccessListener) delegate).authenticationSucceeded(event);
-    }
-
-    /**
-     * Notifies the delegate listener of an authentication failure event, if the
-     * listener implements the AuthenticationSuccessListener interface.
-     *
-     * @param
-     *      event The AuthenticationFailureEvent describing the authentication
-     *        failure that just occurred.
-     *
-     * @throws GuacamoleException
-     *      if the delegate listener throws this exception
-     */
-    @Override
-    public void authenticationFailed(AuthenticationFailureEvent event)
-            throws GuacamoleException {
-        if (delegate instanceof AuthenticationFailureListener) {
-            ((AuthenticationFailureListener) delegate).authenticationFailed(event);
-        }
-    }
-
-    /**
-     * Notifies the delegate listener of a tunnel connected event, if the
-     * listener implements the TunnelConnectListener interface.
-     *
-     * @param
-     *      event The TunnelConnectEvent describing the tunnel that was just connected
-
-     * @return
-     *      false if the delegate listener rejects the tunnel connection,
-     *      else true
-     *
-     * @throws GuacamoleException
-     *      if the delegate listener throws this exception
-     */
-    @Override
-    public boolean tunnelConnected(TunnelConnectEvent event)
-            throws GuacamoleException {
-        return !(delegate instanceof TunnelConnectListener)
-                || ((TunnelConnectListener) delegate).tunnelConnected(event);
-    }
-
-    /**
-     * Notifies the delegate listener of a tunnel close event, if the
-     * listener implements the TunnelCloseListener interface.
-     *
-     * @param
-     *      event The TunnelCloseEvent describing the tunnel that is to be close
-
-     * @return
-     *      false if the delegate listener rejects the tunnel close request,
-     *      else true
-     *
-     * @throws GuacamoleException
-     *      if the delegate listener throws this exception
-     */
-    @Override
-    public boolean tunnelClosed(TunnelCloseEvent event) throws GuacamoleException {
-        return !(delegate instanceof TunnelCloseListener)
-                || ((TunnelCloseListener) delegate).tunnelClosed(event);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFactory.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFactory.java b/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFactory.java
new file mode 100644
index 0000000..c11f00f
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFactory.java
@@ -0,0 +1,256 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.guacamole.extension;
+
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleSecurityException;
+import org.apache.guacamole.net.event.AuthenticationFailureEvent;
+import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
+import org.apache.guacamole.net.event.TunnelCloseEvent;
+import org.apache.guacamole.net.event.TunnelConnectEvent;
+import org.apache.guacamole.net.event.listener.*;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A factory that reflectively instantiates Listener objects for a given
+ * provider class.
+ */
+class ListenerFactory {
+
+    /**
+     * Creates all listeners represented by an instance of the given provider class.
+     * <p>
+     * If a provider class implements the simple Listener interface, that is the
+     * only listener type that will be returned. Otherwise, a list of Listener
+     * objects that adapt the legacy listener interfaces will be returned.
+     *
+     * @param providerClass
+     *      a class that represents a listener provider
+     *
+     * @return
+     *      list of listeners represented by the given provider class
+     */
+    static List<Listener> createListeners(Class<?> providerClass) {
+
+        Object provider = ProviderFactory.newInstance("listener", providerClass);
+
+        if (provider instanceof Listener) {
+            return Collections.singletonList((Listener) provider);
+        }
+
+        return createListenerAdapters(provider);
+
+    }
+
+    @SuppressWarnings("deprecation")
+    private static List<Listener> createListenerAdapters(Object provider) {
+
+        final List<Listener> listeners = new ArrayList<Listener>();
+
+        if (provider instanceof AuthenticationSuccessListener) {
+            listeners.add(new AuthenticationSuccessListenerAdapter(
+                    (AuthenticationSuccessListener) provider));
+        }
+
+        if (provider instanceof AuthenticationFailureListener) {
+            listeners.add(new AuthenticationFailureListenerAdapter(
+                    (AuthenticationFailureListener) provider));
+        }
+
+        if (provider instanceof TunnelConnectListener) {
+            listeners.add(new TunnelConnectListenerAdapter(
+                    (TunnelConnectListener) provider));
+        }
+
+        if (provider instanceof TunnelCloseListener) {
+            listeners.add(new TunnelCloseListenerAdapter(
+                    (TunnelCloseListener) provider));
+        }
+
+        return listeners;
+
+    }
+
+    /**
+     * An adapter the allows an AuthenticationSuccessListener to be used
+     * as an ordinary Listener.
+     */
+    @SuppressWarnings("deprecation")
+    private static class AuthenticationSuccessListenerAdapter implements Listener {
+
+        private final AuthenticationSuccessListener delegate;
+
+        /**
+         * Constructs a new adapter.
+         *
+         * @param delegate
+         *      the delegate listener
+         */
+        AuthenticationSuccessListenerAdapter(AuthenticationSuccessListener delegate) {
+            this.delegate = delegate;
+        }
+
+        /**
+         * Handles an AuthenticationSuccessEvent by passing the event to the delegate
+         * listener. If the delegate returns false, the adapter throws a GuacamoleException
+         * to veto the authentication success event. All other event types are ignored.
+         *
+         * @param event
+         *     an object that describes the subject event
+         *
+         * @throws GuacamoleException
+         *      if thrown by the delegate listener
+         */
+        @Override
+        public void handleEvent(Object event) throws GuacamoleException {
+            if (event instanceof AuthenticationSuccessEvent) {
+                if (!delegate.authenticationSucceeded((AuthenticationSuccessEvent) event)) {
+                    throw new GuacamoleSecurityException(
+                        "listener vetoed successful authentication");
+                }
+            }
+        }
+
+    }
+
+    /**
+     * An adapter the allows an AuthenticationFailureListener to be used
+     * as an ordinary Listener.
+     */
+    @SuppressWarnings("deprecation")
+    private static class AuthenticationFailureListenerAdapter implements Listener {
+
+        private final AuthenticationFailureListener delegate;
+
+        /**
+         * Constructs a new adapter.
+         *
+         * @param delegate
+         *      the delegate listener
+         */
+        AuthenticationFailureListenerAdapter(AuthenticationFailureListener delegate) {
+            this.delegate = delegate;
+        }
+
+        /**
+         * Handles an AuthenticationFailureEvent by passing the event to the delegate
+         * listener. All other event types are ignored.
+         *
+         * @param event
+         *     an object that describes the subject event
+         *
+         * @throws GuacamoleException
+         *      if thrown by the delegate listener
+         */
+        @Override
+        public void handleEvent(Object event) throws GuacamoleException {
+            if (event instanceof AuthenticationFailureEvent) {
+                delegate.authenticationFailed((AuthenticationFailureEvent) event);
+            }
+        }
+
+    }
+
+    /**
+     * An adapter the allows a TunnelConnectListener to be used as an ordinary
+     * Listener.
+     */
+    @SuppressWarnings("deprecation")
+    private static class TunnelConnectListenerAdapter implements Listener {
+
+        private final TunnelConnectListener delegate;
+
+        /**
+         * Constructs a new adapter.
+         *
+         * @param delegate
+         *      the delegate listener
+         */
+        TunnelConnectListenerAdapter(TunnelConnectListener delegate) {
+            this.delegate = delegate;
+        }
+
+        /**
+         * Handles a TunnelConnectEvent by passing the event to the delegate listener.
+         * If the delegate returns false, the adapter throws a GuacamoleException
+         * to veto the tunnel connect event. All other event types are ignored.
+         *
+         * @param event
+         *     an object that describes the subject event
+         *
+         * @throws GuacamoleException
+         *      if thrown by the delegate listener
+         */
+        @Override
+        public void handleEvent(Object event) throws GuacamoleException {
+            if (event instanceof TunnelConnectEvent) {
+                if (!delegate.tunnelConnected((TunnelConnectEvent) event)) {
+                    throw new GuacamoleException("listener vetoed tunnel connection");
+                }
+            }
+        }
+
+    }
+
+    /**
+     * An adapter the allows a TunnelCloseListener to be used as an ordinary
+     * Listener.
+     */
+    @SuppressWarnings("deprecation")
+    private static class TunnelCloseListenerAdapter implements Listener {
+
+        private final TunnelCloseListener delegate;
+
+        /**
+         * Constructs a new adapter.
+         *
+         * @param delegate
+         *      the delegate listener
+         */
+        TunnelCloseListenerAdapter(TunnelCloseListener delegate) {
+            this.delegate = delegate;
+        }
+
+        /**
+         * Handles a TunnelCloseEvent by passing the event to the delegate listener.
+         * If the delegate returns false, the adapter throws a GuacamoleException
+         * to veto the tunnel connect event. All other event types are ignored.
+         *
+         * @param event
+         *     an object that describes the subject event
+         *
+         * @throws GuacamoleException
+         *      if thrown by the delegate listener
+         */
+        @Override
+        public void handleEvent(Object event) throws GuacamoleException {
+            if (event instanceof TunnelCloseEvent) {
+                if (!delegate.tunnelClosed((TunnelCloseEvent) event)) {
+                    throw new GuacamoleException("listener vetoed tunnel close request");
+                }
+            }
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole/src/main/java/org/apache/guacamole/rest/auth/AuthenticationService.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/auth/AuthenticationService.java b/guacamole/src/main/java/org/apache/guacamole/rest/auth/AuthenticationService.java
index cca2845..bdefc3e 100644
--- a/guacamole/src/main/java/org/apache/guacamole/rest/auth/AuthenticationService.java
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/auth/AuthenticationService.java
@@ -24,7 +24,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.regex.Pattern;
 import javax.servlet.http.HttpServletRequest;
-import org.apache.guacamole.GuacamoleAuthenticationRejectedException;
+
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.GuacamoleSecurityException;
 import org.apache.guacamole.GuacamoleUnauthorizedException;
@@ -218,19 +218,17 @@ public class AuthenticationService {
     }
 
     /**
-     * Notify all bound AuthenticationSuccessListeners that a successful authentication
-     * has occurred. If any of the bound listeners returns false (indicating that the
-     * authentication should be rejected) a GuacamoleRejectedAuthenticationException is
-     * thrown.
+     * Notify all bound listeners that a successful authentication
+     * has occurred.
      *
      * @param authenticatedUser
      *      The user that was successfully authenticated
      * @param session
      *      Existing session for the user (if any)
      * @throws GuacamoleException
-     *      If a filter throws an exception or if any filter rejects the authentication
+     *      If thrown by a listener
      */
-    private void notifyAuthenticationSuccessListeners(
+    private void fireAuthenticationSuccessEvent(
             AuthenticatedUser authenticatedUser, GuacamoleSession session)
             throws GuacamoleException {
 
@@ -240,26 +238,21 @@ public class AuthenticationService {
                 authenticatedUser.getAuthenticationProvider().getIdentifier());
         }
 
-        AuthenticationSuccessEvent event = new AuthenticationSuccessEvent(
-            userContext, authenticatedUser.getCredentials());
-
-        if (!listenerService.authenticationSucceeded(event)) {
-            throw new GuacamoleAuthenticationRejectedException();
-        }
+        listenerService.handleEvent(new AuthenticationSuccessEvent(
+            userContext, authenticatedUser.getCredentials()));
     }
 
     /**
-     * Notify all bound AuthenticationFailureListeners that an authentication has failed.
+     * Notify all bound listeners that an authentication attempt has failed.
      *
      * @param credentials
      *      The credentials that failed to authenticate
      * @throws GuacamoleException
-     *      If a filter throws an exception
+     *      If thrown by a listener
      */
-    private void notifyAuthenticationFailureListeners(Credentials credentials)
+    private void fireAuthenticationFailedEvent(Credentials credentials)
             throws GuacamoleException {
-
-        listenerService.authenticationFailed(new AuthenticationFailureEvent(credentials));
+        listenerService.handleEvent(new AuthenticationFailureEvent(credentials));
     }
 
     /**
@@ -290,13 +283,13 @@ public class AuthenticationService {
             if (existingSession != null) {
                 AuthenticatedUser updatedUser = updateAuthenticatedUser(
                         existingSession.getAuthenticatedUser(), credentials);
-                notifyAuthenticationSuccessListeners(updatedUser, existingSession);
+                fireAuthenticationSuccessEvent(updatedUser, existingSession);
                 return updatedUser;
             }
 
             // Otherwise, attempt authentication as a new user
             AuthenticatedUser authenticatedUser = AuthenticationService.this.authenticateUser(credentials);
-            notifyAuthenticationSuccessListeners(authenticatedUser, null);
+            fireAuthenticationSuccessEvent(authenticatedUser, null);
 
             if (logger.isInfoEnabled())
                 logger.info("User \"{}\" successfully authenticated from {}.",
@@ -310,7 +303,7 @@ public class AuthenticationService {
         // Log and rethrow any authentication errors
         catch (GuacamoleException e) {
 
-            notifyAuthenticationFailureListeners(credentials);
+            fireAuthenticationFailedEvent(credentials);
 
             // Get request and username for sake of logging
             HttpServletRequest request = credentials.getRequest();

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole/src/main/java/org/apache/guacamole/rest/event/ListenerService.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/event/ListenerService.java b/guacamole/src/main/java/org/apache/guacamole/rest/event/ListenerService.java
index 30c4357..bbff8ee 100644
--- a/guacamole/src/main/java/org/apache/guacamole/rest/event/ListenerService.java
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/event/ListenerService.java
@@ -22,118 +22,32 @@ package org.apache.guacamole.rest.event;
 import java.util.List;
 import com.google.inject.Inject;
 import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.extension.ListenerProvider;
-import org.apache.guacamole.net.event.AuthenticationFailureEvent;
-import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
-import org.apache.guacamole.net.event.TunnelConnectEvent;
-import org.apache.guacamole.net.event.TunnelCloseEvent;
-import org.apache.guacamole.net.event.listener.AuthenticationFailureListener;
-import org.apache.guacamole.net.event.listener.AuthenticationSuccessListener;
-import org.apache.guacamole.net.event.listener.TunnelCloseListener;
-import org.apache.guacamole.net.event.listener.TunnelConnectListener;
+import org.apache.guacamole.net.event.listener.Listener;
 
 /**
  * A service used to notify listeners registered by extensions when events of
  * interest occur.
  */
-public class ListenerService implements ListenerProvider {
+public class ListenerService implements Listener {
 
     @Inject
-    private List<ListenerProvider> listeners;
+    private List<Listener> listeners;
 
     /**
-     * Notifies all bound listeners of an authentication success event. Listeners
-     * are allowed to veto a successful authentication by returning false from the
-     * listener method. Regardless of whether a particular listener rejects the
-     * successful authentication, all listeners are notified.
+     * Notifies registered listeners than an event has occurred. Notification continues
+     * until a given listener throws a GuacamoleException or other runtime exception, or
+     * until all listeners have been notified.
      *
      * @param event
-     *      The AuthenticationSuccessEvent describing the successful authentication
-     *      that just occurred.
+     *     an object that describes the subject event
      *
-     * @return
-     *      false if any bound listener returns false, else true
-     *
-     * @throws GuacamoleException
-     *      If any bound listener throws this exception. If a listener throws an exception
-     *      some listeners may not receive the authentication success event notification.
-     */
-    @Override
-    public boolean authenticationSucceeded(AuthenticationSuccessEvent event)
-            throws GuacamoleException {
-        boolean result = true;
-        for (AuthenticationSuccessListener listener : listeners) {
-            result = result && listener.authenticationSucceeded(event);
-        }
-        return result;
-    }
-
-    /**
-     * Notifies all bound listeners of an authentication failure event.
-     *
-     * @param event
-     *      The AuthenticationSuccessEvent describing the authentication failure
-     *      that just occurred.
-     *
-     * @throws GuacamoleException
-     *      If any bound listener throws this exception. If a listener throws an exception
-     *      some listeners may not receive the authentication failure event notification.
-     */
-    @Override
-    public void authenticationFailed(AuthenticationFailureEvent event)
-            throws GuacamoleException {
-        for (AuthenticationFailureListener listener : listeners) {
-            listener.authenticationFailed(event);
-        }
-    }
-
-    /**
-     * Notifies all bound listeners of an tunnel connected event. Listeners
-     * are allowed to veto a tunnel connection by returning false from the
-     * listener method. Regardless of whether a particular listener rejects the
-     * tunnel connection, all listeners are notified.
-     * @param event
-     *      The TunnelConnectedEvent describing the tunnel that was just connected
-     *
-     * @return
-     *      false if any bound listener returns false, else true
-     *
-     * @throws GuacamoleException
-     *      If any bound listener throws this exception. If a listener throws an exception
-     *      some listeners may not receive the tunnel connected event notification.
-     */
-    @Override
-    public boolean tunnelConnected(TunnelConnectEvent event)
-            throws GuacamoleException {
-        boolean result = true;
-        for (TunnelConnectListener listener : listeners) {
-            result = result && listener.tunnelConnected(event);
-        }
-        return result;
-    }
-
-    /**
-     * Notifies all bound listeners of an tunnel close event. Listeners
-     * are allowed to veto the request to close a tunnel by returning false from
-     * the listener method. Regardless of whether a particular listener rejects the
-     * tunnel close request, all listeners are notified.
-     * @param event
-     *      The TunnelCloseEvent describing the tunnel that is to be closed
-     *
-     * @return
-     *      false if any bound listener returns false, else true
-     *
-     * @throws GuacamoleException
-     *      If any bound listener throws this exception. If a listener throws an exception
-     *      some listeners may not receive the tunnel close event notification.
+     * @throws GuacamoleException if a registered listener throws a GuacamoleException
      */
     @Override
-    public boolean tunnelClosed(TunnelCloseEvent event) throws GuacamoleException {
-        boolean result = true;
-        for (TunnelCloseListener listener : listeners) {
-            result = result && listener.tunnelClosed(event);
+    public void handleEvent(Object event) throws GuacamoleException {
+        for (final Listener listener : listeners) {
+            listener.handleEvent(event);
         }
-        return result;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f63c8b43/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java
index 56cf82a..d3543d7 100644
--- a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java
+++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java
@@ -25,8 +25,6 @@ import java.util.List;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.GuacamoleSecurityException;
 import org.apache.guacamole.GuacamoleSession;
-import org.apache.guacamole.GuacamoleTunnelConnectedException;
-import org.apache.guacamole.GuacamoleTunnelRejectedException;
 import org.apache.guacamole.GuacamoleUnauthorizedException;
 import org.apache.guacamole.net.GuacamoleTunnel;
 import org.apache.guacamole.net.auth.Connection;
@@ -70,10 +68,8 @@ public class TunnelRequestService {
     private ListenerService listenerService;
 
     /**
-     * Notifies bound TunnelConnectListeners that a new tunnel has been connected.
-     * Listeners are allowed to veto a connected tunnel by returning false from the
-     * listener method. If the ListenerService indicates that any listener rejected
-     * the tunnel, the tunnel is closed an GuacamoleTunnelRejectedException is thrown.
+     * Notifies bound listeners that a new tunnel has been connected.
+     * Listeners may veto a connected tunnel by throwing any GuacamoleException.
      *
      * @param userContext
      *      The UserContext associated with the user for whom the tunnel is
@@ -88,25 +84,15 @@ public class TunnelRequestService {
      * @throws GuacamoleException
      *     If thrown by a listener or if any listener vetoes the connected tunnel
      */
-    private void notifyTunnelConnectListeners(UserContext userContext,
+    private void fireTunnelConnectEvent(UserContext userContext,
             Credentials credentials, GuacamoleTunnel tunnel) throws GuacamoleException {
-        TunnelConnectEvent event = new TunnelConnectEvent(userContext, credentials, tunnel);
-        if (!listenerService.tunnelConnected(event)) {
-            try {
-                tunnel.close();
-            }
-            catch (GuacamoleException closeEx) {
-                logger.warn("Error closing rejected tunnel connection: {}", closeEx.getMessage());
-            }
-            throw new GuacamoleTunnelRejectedException();
-        }
+        listenerService.handleEvent(new TunnelConnectEvent(userContext, credentials, tunnel));
     }
 
     /**
-     * Notifies bound TunnelCloseListeners that a tunnel is to be closed.
-     * Listeners are allowed to veto a request to close a tunnel by returning false from
-     * the listener method. If the ListenerService indicates that any listener vetoed the
-     * request to the close the tunnel, a GuacamoleTunnelConnectedException is thrown.
+     * Notifies bound listeners that a tunnel is to be closed.
+     * Listeners are allowed to veto a request to close a tunnel by throwing any
+     * GuacamoleException.
      *
      * @param userContext
      *      The UserContext associated with the user for whom the tunnel is
@@ -119,15 +105,12 @@ public class TunnelRequestService {
      *      The tunnel that was connected
      *
      * @throws GuacamoleException
-     *     If thrown by a listener or if any listener vetoes the request to close the tunnel
+     *     If thrown by a listener.
      */
-    private void notifyTunnelCloseListeners(UserContext userContext,
+    private void fireTunnelClosedEvent(UserContext userContext,
             Credentials credentials, GuacamoleTunnel tunnel)
             throws GuacamoleException {
-        TunnelCloseEvent event = new TunnelCloseEvent(userContext, credentials, tunnel);
-        if (listenerService.tunnelClosed(event)) {
-            throw new GuacamoleTunnelConnectedException();
-        }
+        listenerService.handleEvent(new TunnelCloseEvent(userContext, credentials, tunnel));
     }
 
     /**
@@ -317,7 +300,7 @@ public class TunnelRequestService {
             public void close() throws GuacamoleException {
 
                 // notify listeners to allow close request to be vetoed
-                notifyTunnelCloseListeners(context,
+                fireTunnelClosedEvent(context,
                     session.getAuthenticatedUser().getCredentials(), tunnel);
 
                 long connectionEndTime = System.currentTimeMillis();
@@ -406,7 +389,7 @@ public class TunnelRequestService {
             GuacamoleTunnel tunnel = createConnectedTunnel(userContext, type, id, info);
 
             // Notify listeners to allow connection to be vetoed
-            notifyTunnelConnectListeners(userContext,
+            fireTunnelConnectEvent(userContext,
                     session.getAuthenticatedUser().getCredentials(), tunnel);
 
             // Associate tunnel with session