mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUACAMOLE-364: add extension module support for event listeners
This commit is contained in:
@@ -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;
|
||||
@@ -109,6 +111,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.
|
||||
@@ -265,6 +272,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());
|
||||
@@ -488,6 +572,17 @@ public class Extension {
|
||||
return authenticationProviderClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@@ -87,6 +87,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.
|
||||
@@ -355,6 +360,32 @@ public class ExtensionManifest {
|
||||
this.authProviders = authProviders;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@@ -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;
|
||||
@@ -91,6 +92,12 @@ public class ExtensionModule extends ServletModule {
|
||||
private final List<AuthenticationProvider> boundAuthenticationProviders =
|
||||
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.
|
||||
*/
|
||||
@@ -187,6 +194,49 @@ public class ExtensionModule extends ServletModule {
|
||||
return Collections.unmodifiableList(boundAuthenticationProviders);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -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());
|
||||
|
||||
|
Reference in New Issue
Block a user