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:21 UTC
[04/17] incubator-guacamole-client git commit: GUACAMOLE-364: add
extension module support for event listeners
GUACAMOLE-364: add extension module support for event listeners
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/109d57ec
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/109d57ec
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/109d57ec
Branch: refs/heads/master
Commit: 109d57ecb372c3fc8114792086f339e9269eaf98
Parents: dca7862
Author: Carl Harris <ce...@vt.edu>
Authored: Wed Aug 16 06:55:28 2017 -0400
Committer: Carl Harris <ce...@vt.edu>
Committed: Wed Aug 16 06:55:28 2017 -0400
----------------------------------------------------------------------
.../apache/guacamole/extension/Extension.java | 95 ++++++++++++++++++++
.../guacamole/extension/ExtensionManifest.java | 31 +++++++
.../guacamole/extension/ExtensionModule.java | 53 +++++++++++
3 files changed, 179 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/109d57ec/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 3183fa2..ac58676 100644
--- a/guacamole/src/main/java/org/apache/guacamole/extension/Extension.java
+++ b/guacamole/src/main/java/org/apache/guacamole/extension/Extension.java
@@ -35,6 +35,8 @@ import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
+
+import org.apache.guacamole.net.event.listener.Listener;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.ObjectMapper;
import org.apache.guacamole.GuacamoleException;
@@ -110,6 +112,11 @@ public class Extension {
private final Collection<Class<AuthenticationProvider>> authenticationProviderClasses;
/**
+ * The collection of all Listener classes defined within the extension.
+ */
+ private final Collection<Class<Listener>> listenerClasses;
+
+ /**
* The resource for the small favicon for the extension. If provided, this
* will replace the default Guacamole icon.
*/
@@ -266,6 +273,80 @@ public class Extension {
}
/**
+ * Retrieve the Listener subclass having the given name. If
+ * the class having the given name does not exist or isn't actually a
+ * subclass of Listener, an exception will be thrown.
+ *
+ * @param name
+ * The name of the Listener class to retrieve.
+ *
+ * @return
+ * The subclass of Listener having the given name.
+ *
+ * @throws GuacamoleException
+ * If no such class exists, or if the class with the given name is not
+ * a subclass of Listener.
+ */
+ @SuppressWarnings("unchecked") // We check this ourselves with isAssignableFrom()
+ private Class<Listener> getListenerClass(String name)
+ throws GuacamoleException {
+
+ try {
+
+ // Get listener class
+ Class<?> listenerClass = classLoader.loadClass(name);
+
+ // Verify the located class is actually a subclass of Listener
+ if (!Listener.class.isAssignableFrom(listenerClass))
+ throw new GuacamoleServerException("Listeners MUST implement a Listener subclass.");
+
+ // Return located class
+ return (Class<Listener>) listenerClass;
+
+ }
+ catch (ClassNotFoundException e) {
+ throw new GuacamoleException("Listener class not found.", e);
+ }
+ catch (LinkageError e) {
+ throw new GuacamoleException("Listener class cannot be loaded (wrong version of API?).", e);
+ }
+
+ }
+
+ /**
+ * Returns a new collection of all Listener subclasses having the given names.
+ * If any class does not exist or isn't actually subclass of Listener, an
+ * exception will be thrown, an no further Listener classes will be loaded.
+ *
+ * @param names
+ * The names of the AuthenticationProvider classes to retrieve.
+ *
+ * @return
+ * A new collection of all AuthenticationProvider subclasses having the
+ * given names.
+ *
+ * @throws GuacamoleException
+ * 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)
+ throws GuacamoleException {
+
+ // If no classnames are provided, just return an empty list
+ if (names == null)
+ return Collections.<Class<Listener>>emptyList();
+
+ // Define all auth provider classes
+ Collection<Class<Listener>> classes = new ArrayList<Class<Listener>>(names.size());
+ for (String name : names)
+ classes.add(getListenerClass(name));
+
+ // Callers should not rely on modifying the result
+ return Collections.unmodifiableCollection(classes);
+ }
+
+
+ /**
* Loads the given file as an extension, which must be a .jar containing
* a guac-manifest.json file describing its contents.
*
@@ -363,6 +444,9 @@ public class Extension {
// Define authentication providers
authenticationProviderClasses = getAuthenticationProviderClasses(manifest.getAuthProviders());
+ // Define listeners
+ listenerClasses = getListenerClasses(manifest.getListeners());
+
// Get small icon resource if provided
if (manifest.getSmallIcon() != null)
smallIcon = new ClassPathResource(classLoader, "image/png", manifest.getSmallIcon());
@@ -489,6 +573,17 @@ public class Extension {
}
/**
+ * Returns all declared listener classes associated wit this extension. Listeners are
+ * declared within the extension manifest.
+ *
+ * @return
+ * All declared listener classes with this extension.
+ */
+ public Collection<Class<Listener>> getListenerClasses() {
+ return listenerClasses;
+ }
+
+ /**
* Returns the resource for the small favicon for the extension. If
* provided, this will replace the default Guacamole icon.
*
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/109d57ec/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionManifest.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionManifest.java b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionManifest.java
index 9b9bd9b..1636b03 100644
--- a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionManifest.java
+++ b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionManifest.java
@@ -88,6 +88,11 @@ public class ExtensionManifest {
private Collection<String> authProviders;
/**
+ * The names of all listener classes within this extension, if any.
+ */
+ private Collection<String> listeners;
+
+ /**
* The path to the small favicon. If provided, this will replace the default
* Guacamole icon.
*/
@@ -356,6 +361,32 @@ public class ExtensionManifest {
}
/**
+ * Returns the classnames of all listener classes within the extension.
+ * These classnames are defined within the manifest by the "listeners"
+ * property as an array of strings, where each string is a listener
+ * class name.
+ *
+ * @return
+ * a collection of classnames for all listeners within the extension
+ */
+ public Collection<String> getListeners() {
+ return listeners;
+ }
+
+ /**
+ * Sets the classnames of all listener classes within the extension.
+ * These classnames are defined within the manifest by the "listeners"
+ * property as an array of strings, where each string is a listener
+ * class name.
+ *
+ * @param listeners
+ * a collection of classnames for all listeners within the extension
+ */
+ public void setListeners(Collection<String> listeners) {
+ this.listeners = listeners;
+ }
+
+ /**
* Returns the path to the small favicon, relative to the root of the
* extension.
*
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/109d57ec/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 792066c..1e1a854 100644
--- a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java
+++ b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java
@@ -34,6 +34,7 @@ import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.net.auth.AuthenticationProvider;
+import org.apache.guacamole.net.event.listener.Listener;
import org.apache.guacamole.resource.Resource;
import org.apache.guacamole.resource.ResourceServlet;
import org.apache.guacamole.resource.SequenceResource;
@@ -92,6 +93,12 @@ public class ExtensionModule extends ServletModule {
new ArrayList<AuthenticationProvider>();
/**
+ * All currently-bound authentication providers, if any.
+ */
+ private final List<ListenerProvider> boundListenerProviders =
+ new ArrayList<ListenerProvider>();
+
+ /**
* Service for adding and retrieving language resources.
*/
private final LanguageResourceService languageResourceService;
@@ -188,6 +195,49 @@ 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.
+ */
+ private void bindListenerProvider(Class<? extends Listener> listenerClass) {
+
+ // Bind listener
+ logger.debug("[{}] Binding Listener \"{}\".",
+ boundListenerProviders.size(), listenerClass.getName());
+ boundListenerProviders.add(new ListenerFacade(listenerClass));
+ }
+
+ /**
+ * Binds each of the the given Listener classes such that any
+ * service requiring access to the Listener can obtain it via
+ * injection.
+ *
+ * @param listeners
+ * The Listener classes to bind.
+ */
+ private void bindListenerProviders(Collection<Class<Listener>> listeners) {
+
+ // Bind each listener within extension
+ for (Class<Listener> listener : listeners)
+ bindListenerProvider(listener);
+ }
+
+ /**
+ * Returns a list of all currently-bound ListenerProvider instances.
+ *
+ * @return
+ * A List of all currently-bound ListenerProvider instances. The List is
+ * not modifiable.
+ */
+ @Provides
+ public List<ListenerProvider> getListenerProviders() {
+ return Collections.unmodifiableList(boundListenerProviders);
+ }
+
+ /**
* Serves each of the given resources as a language resource. Language
* resources are served from within the "/translations" directory as JSON
* files, where the name of each JSON file is the language key.
@@ -327,6 +377,9 @@ public class ExtensionModule extends ServletModule {
// Attempt to load all authentication providers
bindAuthenticationProviders(extension.getAuthenticationProviderClasses());
+ // Attempt to load all listeners
+ bindListenerProviders(extension.getListenerClasses());
+
// Add any translation resources
serveLanguageResources(extension.getTranslationResources());