You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by jm...@apache.org on 2016/03/29 06:20:31 UTC

[22/51] [abbrv] incubator-guacamole-client git commit: GUACAMOLE-1: Rename Basic* classes sensibly. Refactor tunnel classes into own packages.

GUACAMOLE-1: Rename Basic* classes sensibly. Refactor tunnel classes into own packages.


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/713fc7f8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/713fc7f8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/713fc7f8

Branch: refs/heads/master
Commit: 713fc7f89fd70ee59778966b2f9de2216cb9bb8d
Parents: c7a5f0b
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Mar 22 15:29:04 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Mar 28 20:50:07 2016 -0700

----------------------------------------------------------------------
 .../guacamole/BasicGuacamoleTunnelServlet.java  |  67 ----
 .../guacamole/BasicServletContextListener.java  | 103 -----
 .../GuacamoleServletContextListener.java        | 103 +++++
 .../org/apache/guacamole/HTTPTunnelRequest.java |  90 -----
 .../java/org/apache/guacamole/TunnelLoader.java |  44 ---
 .../java/org/apache/guacamole/TunnelModule.java | 113 ------
 .../org/apache/guacamole/TunnelRequest.java     | 372 ------------------
 .../apache/guacamole/TunnelRequestService.java  | 359 ------------------
 .../rest/auth/BasicTokenSessionMap.java         | 200 ----------
 .../rest/auth/HashTokenSessionMap.java          | 200 ++++++++++
 .../apache/guacamole/tunnel/TunnelLoader.java   |  44 +++
 .../apache/guacamole/tunnel/TunnelModule.java   | 114 ++++++
 .../apache/guacamole/tunnel/TunnelRequest.java  | 374 +++++++++++++++++++
 .../guacamole/tunnel/TunnelRequestService.java  | 363 ++++++++++++++++++
 .../tunnel/http/HTTPTunnelRequest.java          |  91 +++++
 .../RestrictedGuacamoleHTTPTunnelServlet.java   |  69 ++++
 .../guacamole/tunnel/http/package-info.java     |  27 ++
 .../apache/guacamole/tunnel/package-info.java   |  27 ++
 ...trictedGuacamoleWebSocketTunnelEndpoint.java | 121 ++++++
 .../tunnel/websocket/WebSocketTunnelModule.java | 104 ++++++
 .../websocket/WebSocketTunnelRequest.java       |  70 ++++
 .../jetty8/GuacamoleWebSocketTunnelServlet.java | 232 ++++++++++++
 ...strictedGuacamoleWebSocketTunnelServlet.java |  52 +++
 .../websocket/jetty8/WebSocketTunnelModule.java |  73 ++++
 .../tunnel/websocket/jetty8/package-info.java   |  27 ++
 .../GuacamoleWebSocketTunnelListener.java       | 243 ++++++++++++
 .../RestrictedGuacamoleWebSocketCreator.java    |  72 ++++
 ...trictedGuacamoleWebSocketTunnelListener.java |  59 +++
 ...strictedGuacamoleWebSocketTunnelServlet.java |  54 +++
 .../websocket/jetty9/WebSocketTunnelModule.java |  73 ++++
 .../jetty9/WebSocketTunnelRequest.java          |  76 ++++
 .../tunnel/websocket/jetty9/package-info.java   |  28 ++
 .../tunnel/websocket/package-info.java          |  28 ++
 .../tomcat/GuacamoleWebSocketTunnelServlet.java | 265 +++++++++++++
 ...strictedGuacamoleWebSocketTunnelServlet.java |  52 +++
 .../websocket/tomcat/WebSocketTunnelModule.java |  73 ++++
 .../tunnel/websocket/tomcat/package-info.java   |  29 ++
 .../BasicGuacamoleWebSocketTunnelEndpoint.java  | 120 ------
 .../websocket/WebSocketTunnelModule.java        | 104 ------
 .../websocket/WebSocketTunnelRequest.java       |  70 ----
 .../BasicGuacamoleWebSocketTunnelServlet.java   |  52 ---
 .../jetty8/GuacamoleWebSocketTunnelServlet.java | 232 ------------
 .../websocket/jetty8/WebSocketTunnelModule.java |  73 ----
 .../websocket/jetty8/package-info.java          |  27 --
 .../jetty9/BasicGuacamoleWebSocketCreator.java  |  72 ----
 .../BasicGuacamoleWebSocketTunnelListener.java  |  59 ---
 .../BasicGuacamoleWebSocketTunnelServlet.java   |  54 ---
 .../GuacamoleWebSocketTunnelListener.java       | 243 ------------
 .../websocket/jetty9/WebSocketTunnelModule.java |  73 ----
 .../jetty9/WebSocketTunnelRequest.java          |  76 ----
 .../websocket/jetty9/package-info.java          |  28 --
 .../guacamole/websocket/package-info.java       |  28 --
 .../BasicGuacamoleWebSocketTunnelServlet.java   |  52 ---
 .../tomcat/GuacamoleWebSocketTunnelServlet.java | 265 -------------
 .../websocket/tomcat/WebSocketTunnelModule.java |  73 ----
 .../websocket/tomcat/package-info.java          |  29 --
 guacamole/src/main/webapp/WEB-INF/web.xml       |   2 +-
 57 files changed, 3144 insertions(+), 3079 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/713fc7f8/guacamole/src/main/java/org/apache/guacamole/BasicGuacamoleTunnelServlet.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/BasicGuacamoleTunnelServlet.java b/guacamole/src/main/java/org/apache/guacamole/BasicGuacamoleTunnelServlet.java
deleted file mode 100644
index 7ebbd7f..0000000
--- a/guacamole/src/main/java/org/apache/guacamole/BasicGuacamoleTunnelServlet.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2013 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-package org.apache.guacamole;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import javax.servlet.http.HttpServletRequest;
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.net.GuacamoleTunnel;
-import org.apache.guacamole.servlet.GuacamoleHTTPTunnelServlet;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Connects users to a tunnel associated with the authorized connection
- * having the given ID.
- *
- * @author Michael Jumper
- */
-@Singleton
-public class BasicGuacamoleTunnelServlet extends GuacamoleHTTPTunnelServlet {
-
-    /**
-     * Service for handling tunnel requests.
-     */
-    @Inject
-    private TunnelRequestService tunnelRequestService;
-    
-    /**
-     * Logger for this class.
-     */
-    private static final Logger logger = LoggerFactory.getLogger(BasicGuacamoleTunnelServlet.class);
-
-    @Override
-    protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException {
-
-        // Attempt to create HTTP tunnel
-        GuacamoleTunnel tunnel = tunnelRequestService.createTunnel(new HTTPTunnelRequest(request));
-
-        // If successful, warn of lack of WebSocket
-        logger.info("Using HTTP tunnel (not WebSocket). Performance may be sub-optimal.");
-
-        return tunnel;
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/713fc7f8/guacamole/src/main/java/org/apache/guacamole/BasicServletContextListener.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/BasicServletContextListener.java b/guacamole/src/main/java/org/apache/guacamole/BasicServletContextListener.java
deleted file mode 100644
index 96fab85..0000000
--- a/guacamole/src/main/java/org/apache/guacamole/BasicServletContextListener.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2015 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-package org.apache.guacamole;
-
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Stage;
-import com.google.inject.servlet.GuiceServletContextListener;
-import javax.servlet.ServletContextEvent;
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.environment.Environment;
-import org.apache.guacamole.environment.LocalEnvironment;
-import org.apache.guacamole.extension.ExtensionModule;
-import org.apache.guacamole.log.LogModule;
-import org.apache.guacamole.rest.RESTServiceModule;
-import org.apache.guacamole.rest.auth.BasicTokenSessionMap;
-import org.apache.guacamole.rest.auth.TokenSessionMap;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A ServletContextListener to listen for initialization of the servlet context
- * in order to set up dependency injection.
- *
- * @author James Muehlner
- */
-public class BasicServletContextListener extends GuiceServletContextListener {
-
-    /**
-     * Logger for this class.
-     */
-    private final Logger logger = LoggerFactory.getLogger(BasicServletContextListener.class);
-
-    /**
-     * The Guacamole server environment.
-     */
-    private Environment environment;
-
-    /**
-     * Singleton instance of a TokenSessionMap.
-     */
-    private TokenSessionMap sessionMap;
-
-    @Override
-    public void contextInitialized(ServletContextEvent servletContextEvent) {
-
-        try {
-            environment = new LocalEnvironment();
-            sessionMap = new BasicTokenSessionMap(environment);
-        }
-        catch (GuacamoleException e) {
-            logger.error("Unable to read guacamole.properties: {}", e.getMessage());
-            logger.debug("Error reading guacamole.properties.", e);
-            throw new RuntimeException(e);
-        }
-
-        super.contextInitialized(servletContextEvent);
-
-    }
-
-    @Override
-    protected Injector getInjector() {
-        return Guice.createInjector(Stage.PRODUCTION,
-            new EnvironmentModule(environment),
-            new LogModule(environment),
-            new ExtensionModule(environment),
-            new RESTServiceModule(sessionMap),
-            new TunnelModule()
-        );
-    }
-
-    @Override
-    public void contextDestroyed(ServletContextEvent servletContextEvent) {
-
-        super.contextDestroyed(servletContextEvent);
-
-        // Shutdown TokenSessionMap
-        if (sessionMap != null)
-            sessionMap.shutdown();
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/713fc7f8/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java b/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java
new file mode 100644
index 0000000..ea5f61a
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole;
+
+import org.apache.guacamole.tunnel.TunnelModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Stage;
+import com.google.inject.servlet.GuiceServletContextListener;
+import javax.servlet.ServletContextEvent;
+import org.apache.guacamole.environment.Environment;
+import org.apache.guacamole.environment.LocalEnvironment;
+import org.apache.guacamole.extension.ExtensionModule;
+import org.apache.guacamole.log.LogModule;
+import org.apache.guacamole.rest.RESTServiceModule;
+import org.apache.guacamole.rest.auth.HashTokenSessionMap;
+import org.apache.guacamole.rest.auth.TokenSessionMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A ServletContextListener to listen for initialization of the servlet context
+ * in order to set up dependency injection.
+ *
+ * @author James Muehlner
+ */
+public class GuacamoleServletContextListener extends GuiceServletContextListener {
+
+    /**
+     * Logger for this class.
+     */
+    private final Logger logger = LoggerFactory.getLogger(GuacamoleServletContextListener.class);
+
+    /**
+     * The Guacamole server environment.
+     */
+    private Environment environment;
+
+    /**
+     * Singleton instance of a TokenSessionMap.
+     */
+    private TokenSessionMap sessionMap;
+
+    @Override
+    public void contextInitialized(ServletContextEvent servletContextEvent) {
+
+        try {
+            environment = new LocalEnvironment();
+            sessionMap = new HashTokenSessionMap(environment);
+        }
+        catch (GuacamoleException e) {
+            logger.error("Unable to read guacamole.properties: {}", e.getMessage());
+            logger.debug("Error reading guacamole.properties.", e);
+            throw new RuntimeException(e);
+        }
+
+        super.contextInitialized(servletContextEvent);
+
+    }
+
+    @Override
+    protected Injector getInjector() {
+        return Guice.createInjector(Stage.PRODUCTION,
+            new EnvironmentModule(environment),
+            new LogModule(environment),
+            new ExtensionModule(environment),
+            new RESTServiceModule(sessionMap),
+            new TunnelModule()
+        );
+    }
+
+    @Override
+    public void contextDestroyed(ServletContextEvent servletContextEvent) {
+
+        super.contextDestroyed(servletContextEvent);
+
+        // Shutdown TokenSessionMap
+        if (sessionMap != null)
+            sessionMap.shutdown();
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/713fc7f8/guacamole/src/main/java/org/apache/guacamole/HTTPTunnelRequest.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/HTTPTunnelRequest.java b/guacamole/src/main/java/org/apache/guacamole/HTTPTunnelRequest.java
deleted file mode 100644
index 9edc45a..0000000
--- a/guacamole/src/main/java/org/apache/guacamole/HTTPTunnelRequest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2014 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-package org.apache.guacamole;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * HTTP-specific implementation of TunnelRequest.
- *
- * @author Michael Jumper
- */
-public class HTTPTunnelRequest extends TunnelRequest {
-
-    /**
-     * A copy of the parameters obtained from the HttpServletRequest used to
-     * construct the HTTPTunnelRequest.
-     */
-    private final Map<String, List<String>> parameterMap =
-            new HashMap<String, List<String>>();
-
-    /**
-     * Creates a HTTPTunnelRequest which copies and exposes the parameters
-     * from the given HttpServletRequest.
-     *
-     * @param request
-     *     The HttpServletRequest to copy parameter values from.
-     */
-    @SuppressWarnings("unchecked") // getParameterMap() is defined as returning Map<String, String[]>
-    public HTTPTunnelRequest(HttpServletRequest request) {
-
-        // For each parameter
-        for (Map.Entry<String, String[]> mapEntry : ((Map<String, String[]>)
-                request.getParameterMap()).entrySet()) {
-
-            // Get parameter name and corresponding values
-            String parameterName = mapEntry.getKey();
-            List<String> parameterValues = Arrays.asList(mapEntry.getValue());
-
-            // Store copy of all values in our own map
-            parameterMap.put(
-                parameterName,
-                new ArrayList<String>(parameterValues)
-            );
-
-        }
-
-    }
-
-    @Override
-    public String getParameter(String name) {
-        List<String> values = getParameterValues(name);
-
-        // Return the first value from the list if available
-        if (values != null && !values.isEmpty())
-            return values.get(0);
-
-        return null;
-    }
-
-    @Override
-    public List<String> getParameterValues(String name) {
-        return parameterMap.get(name);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/713fc7f8/guacamole/src/main/java/org/apache/guacamole/TunnelLoader.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/TunnelLoader.java b/guacamole/src/main/java/org/apache/guacamole/TunnelLoader.java
deleted file mode 100644
index 756c6dd..0000000
--- a/guacamole/src/main/java/org/apache/guacamole/TunnelLoader.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2014 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-package org.apache.guacamole;
-
-import com.google.inject.Module;
-
-/**
- * Generic means of loading a tunnel without adding explicit dependencies within
- * the main ServletModule, as not all servlet containers may have the classes
- * required by all tunnel implementations.
- *
- * @author Michael Jumper
- */
-public interface TunnelLoader extends Module {
-
-    /**
-     * Checks whether this type of tunnel is supported by the servlet container.
-     * 
-     * @return true if this type of tunnel is supported and can be loaded
-     *         without errors, false otherwise.
-     */
-    public boolean isSupported();
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/713fc7f8/guacamole/src/main/java/org/apache/guacamole/TunnelModule.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/TunnelModule.java b/guacamole/src/main/java/org/apache/guacamole/TunnelModule.java
deleted file mode 100644
index e7c105c..0000000
--- a/guacamole/src/main/java/org/apache/guacamole/TunnelModule.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2015 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-package org.apache.guacamole;
-
-import com.google.inject.servlet.ServletModule;
-import java.lang.reflect.InvocationTargetException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Module which loads tunnel implementations.
- *
- * @author Michael Jumper
- */
-public class TunnelModule extends ServletModule {
-
-    /**
-     * Logger for this class.
-     */
-    private final Logger logger = LoggerFactory.getLogger(TunnelModule.class);
-
-    /**
-     * Classnames of all implementation-specific WebSocket tunnel modules.
-     */
-    private static final String[] WEBSOCKET_MODULES = {
-        "org.apache.guacamole.websocket.WebSocketTunnelModule",
-        "org.apache.guacamole.websocket.jetty8.WebSocketTunnelModule",
-        "org.apache.guacamole.websocket.jetty9.WebSocketTunnelModule",
-        "org.apache.guacamole.websocket.tomcat.WebSocketTunnelModule"
-    };
-
-    private boolean loadWebSocketModule(String classname) {
-
-        try {
-
-            // Attempt to find WebSocket module
-            Class<?> module = Class.forName(classname);
-
-            // Create loader
-            TunnelLoader loader = (TunnelLoader) module.getConstructor().newInstance();
-
-            // Install module, if supported
-            if (loader.isSupported()) {
-                install(loader);
-                return true;
-            }
-
-        }
-
-        // If no such class or constructor, etc., then this particular
-        // WebSocket support is not present
-        catch (ClassNotFoundException e) {}
-        catch (NoClassDefFoundError e) {}
-        catch (NoSuchMethodException e) {}
-
-        // Log errors which indicate bugs
-        catch (InstantiationException e) {
-            logger.debug("Error instantiating WebSocket module.", e);
-        }
-        catch (IllegalAccessException e) {
-            logger.debug("Error instantiating WebSocket module.", e);
-        }
-        catch (InvocationTargetException e) {
-            logger.debug("Error instantiating WebSocket module.", e);
-        }
-
-        // Load attempt failed
-        return false;
-
-    }
-
-    @Override
-    protected void configureServlets() {
-
-        bind(TunnelRequestService.class);
-
-        // Set up HTTP tunnel
-        serve("/tunnel").with(BasicGuacamoleTunnelServlet.class);
-
-        // Try to load each WebSocket tunnel in sequence
-        for (String classname : WEBSOCKET_MODULES) {
-            if (loadWebSocketModule(classname)) {
-                logger.debug("WebSocket module loaded: {}", classname);
-                return;
-            }
-        }
-
-        // Warn of lack of WebSocket
-        logger.info("WebSocket support NOT present. Only HTTP will be used.");
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/713fc7f8/guacamole/src/main/java/org/apache/guacamole/TunnelRequest.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/TunnelRequest.java b/guacamole/src/main/java/org/apache/guacamole/TunnelRequest.java
deleted file mode 100644
index 622e2f0..0000000
--- a/guacamole/src/main/java/org/apache/guacamole/TunnelRequest.java
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright (C) 2015 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-package org.apache.guacamole;
-
-import java.util.List;
-import org.apache.guacamole.GuacamoleClientException;
-import org.apache.guacamole.GuacamoleException;
-
-/**
- * A request object which provides only the functions absolutely required to
- * retrieve and connect to a tunnel.
- *
- * @author Michael Jumper
- */
-public abstract class TunnelRequest {
-
-    /**
-     * The name of the request parameter containing the user's authentication
-     * token.
-     */
-    public static final String AUTH_TOKEN_PARAMETER = "token";
-
-    /**
-     * The name of the parameter containing the identifier of the
-     * AuthenticationProvider associated with the UserContext containing the
-     * object to which a tunnel is being requested.
-     */
-    public static final String AUTH_PROVIDER_IDENTIFIER_PARAMETER = "GUAC_DATA_SOURCE";
-
-    /**
-     * The name of the parameter specifying the type of object to which a
-     * tunnel is being requested. Currently, this may be "c" for a Guacamole
-     * connection, or "g" for a Guacamole connection group.
-     */
-    public static final String TYPE_PARAMETER = "GUAC_TYPE";
-
-    /**
-     * The name of the parameter containing the unique identifier of the object
-     * to which a tunnel is being requested.
-     */
-    public static final String IDENTIFIER_PARAMETER = "GUAC_ID";
-
-    /**
-     * The name of the parameter containing the desired display width, in
-     * pixels.
-     */
-    public static final String WIDTH_PARAMETER = "GUAC_WIDTH";
-
-    /**
-     * The name of the parameter containing the desired display height, in
-     * pixels.
-     */
-    public static final String HEIGHT_PARAMETER = "GUAC_HEIGHT";
-
-    /**
-     * The name of the parameter containing the desired display resolution, in
-     * DPI.
-     */
-    public static final String DPI_PARAMETER = "GUAC_DPI";
-
-    /**
-     * The name of the parameter specifying one supported audio mimetype. This
-     * will normally appear multiple times within a single tunnel request -
-     * once for each mimetype.
-     */
-    public static final String AUDIO_PARAMETER = "GUAC_AUDIO";
-
-    /**
-     * The name of the parameter specifying one supported video mimetype. This
-     * will normally appear multiple times within a single tunnel request -
-     * once for each mimetype.
-     */
-    public static final String VIDEO_PARAMETER = "GUAC_VIDEO";
-
-    /**
-     * The name of the parameter specifying one supported image mimetype. This
-     * will normally appear multiple times within a single tunnel request -
-     * once for each mimetype.
-     */
-    public static final String IMAGE_PARAMETER = "GUAC_IMAGE";
-
-    /**
-     * All supported object types that can be used as the destination of a
-     * tunnel.
-     */
-    public static enum Type {
-
-        /**
-         * A Guacamole connection.
-         */
-        CONNECTION("c"),
-
-        /**
-         * A Guacamole connection group.
-         */
-        CONNECTION_GROUP("g");
-
-        /**
-         * The parameter value which denotes a destination object of this type.
-         */
-        final String PARAMETER_VALUE;
-        
-        /**
-         * Defines a Type having the given corresponding parameter value.
-         *
-         * @param value
-         *     The parameter value which denotes a destination object of this
-         *     type.
-         */
-        Type(String value) {
-            PARAMETER_VALUE = value;
-        }
-
-    };
-
-    /**
-     * Returns the value of the parameter having the given name.
-     *
-     * @param name
-     *     The name of the parameter to return.
-     *
-     * @return
-     *     The value of the parameter having the given name, or null if no such
-     *     parameter was specified.
-     */
-    public abstract String getParameter(String name);
-
-    /**
-     * Returns a list of all values specified for the given parameter.
-     *
-     * @param name
-     *     The name of the parameter to return.
-     *
-     * @return
-     *     All values of the parameter having the given name , or null if no
-     *     such parameter was specified.
-     */
-    public abstract List<String> getParameterValues(String name);
-
-    /**
-     * Returns the value of the parameter having the given name, throwing an
-     * exception if the parameter is missing.
-     *
-     * @param name
-     *     The name of the parameter to return.
-     *
-     * @return
-     *     The value of the parameter having the given name.
-     *
-     * @throws GuacamoleException
-     *     If the parameter is not present in the request.
-     */
-    public String getRequiredParameter(String name) throws GuacamoleException {
-
-        // Pull requested parameter, aborting if absent
-        String value = getParameter(name);
-        if (value == null)
-            throw new GuacamoleClientException("Parameter \"" + name + "\" is required.");
-
-        return value;
-
-    }
-
-    /**
-     * Returns the integer value of the parameter having the given name,
-     * throwing an exception if the parameter cannot be parsed.
-     *
-     * @param name
-     *     The name of the parameter to return.
-     *
-     * @return
-     *     The integer value of the parameter having the given name, or null if
-     *     the parameter is missing.
-     *
-     * @throws GuacamoleException
-     *     If the parameter is not a valid integer.
-     */
-    public Integer getIntegerParameter(String name) throws GuacamoleException {
-
-        // Pull requested parameter
-        String value = getParameter(name);
-        if (value == null)
-            return null;
-
-        // Attempt to parse as an integer
-        try {
-            return Integer.parseInt(value);
-        }
-
-        // Rethrow any parsing error as a GuacamoleClientException
-        catch (NumberFormatException e) {
-            throw new GuacamoleClientException("Parameter \"" + name + "\" must be a valid integer.", e);
-        }
-
-    }
-
-    /**
-     * Returns the authentication token associated with this tunnel request.
-     *
-     * @return
-     *     The authentication token associated with this tunnel request, or
-     *     null if no authentication token is present.
-     */
-    public String getAuthenticationToken() {
-        return getParameter(AUTH_TOKEN_PARAMETER);
-    }
-
-    /**
-     * Returns the identifier of the AuthenticationProvider associated with the
-     * UserContext from which the connection or connection group is to be
-     * retrieved when the tunnel is created. In the context of the REST API and
-     * the JavaScript side of the web application, this is referred to as the
-     * data source identifier.
-     *
-     * @return
-     *     The identifier of the AuthenticationProvider associated with the
-     *     UserContext from which the connection or connection group is to be
-     *     retrieved when the tunnel is created.
-     *
-     * @throws GuacamoleException
-     *     If the identifier was not present in the request.
-     */
-    public String getAuthenticationProviderIdentifier()
-            throws GuacamoleException {
-        return getRequiredParameter(AUTH_PROVIDER_IDENTIFIER_PARAMETER);
-    }
-
-    /**
-     * Returns the type of object for which the tunnel is being requested.
-     *
-     * @return
-     *     The type of object for which the tunnel is being requested.
-     *
-     * @throws GuacamoleException
-     *     If the type was not present in the request, or if the type requested
-     *     is in the wrong format.
-     */
-    public Type getType() throws GuacamoleException {
-
-        String type = getRequiredParameter(TYPE_PARAMETER);
-
-        // For each possible object type
-        for (Type possibleType : Type.values()) {
-
-            // Match against defined parameter value
-            if (type.equals(possibleType.PARAMETER_VALUE))
-                return possibleType;
-
-        }
-
-        throw new GuacamoleClientException("Illegal identifier - unknown type.");
-
-    }
-
-    /**
-     * Returns the identifier of the destination of the tunnel being requested.
-     * As there are multiple types of destination objects available, and within
-     * multiple data sources, the associated object type and data source are
-     * also necessary to determine what this identifier refers to.
-     *
-     * @return
-     *     The identifier of the destination of the tunnel being requested.
-     *
-     * @throws GuacamoleException
-     *     If the identifier was not present in the request.
-     */
-    public String getIdentifier() throws GuacamoleException {
-        return getRequiredParameter(IDENTIFIER_PARAMETER);
-    }
-
-    /**
-     * Returns the display width desired for the Guacamole session over the
-     * tunnel being requested.
-     *
-     * @return
-     *     The display width desired for the Guacamole session over the tunnel
-     *     being requested, or null if no width was given.
-     *
-     * @throws GuacamoleException
-     *     If the width specified was not a valid integer.
-     */
-    public Integer getWidth() throws GuacamoleException {
-        return getIntegerParameter(WIDTH_PARAMETER);
-    }
-
-    /**
-     * Returns the display height desired for the Guacamole session over the
-     * tunnel being requested.
-     *
-     * @return
-     *     The display height desired for the Guacamole session over the tunnel
-     *     being requested, or null if no width was given.
-     *
-     * @throws GuacamoleException
-     *     If the height specified was not a valid integer.
-     */
-    public Integer getHeight() throws GuacamoleException {
-        return getIntegerParameter(HEIGHT_PARAMETER);
-    }
-
-    /**
-     * Returns the display resolution desired for the Guacamole session over
-     * the tunnel being requested, in DPI.
-     *
-     * @return
-     *     The display resolution desired for the Guacamole session over the
-     *     tunnel being requested, or null if no resolution was given.
-     *
-     * @throws GuacamoleException
-     *     If the resolution specified was not a valid integer.
-     */
-    public Integer getDPI() throws GuacamoleException {
-        return getIntegerParameter(DPI_PARAMETER);
-    }
-
-    /**
-     * Returns a list of all audio mimetypes declared as supported within the
-     * tunnel request.
-     *
-     * @return
-     *     A list of all audio mimetypes declared as supported within the
-     *     tunnel request, or null if no mimetypes were specified.
-     */
-    public List<String> getAudioMimetypes() {
-        return getParameterValues(AUDIO_PARAMETER);
-    }
-
-    /**
-     * Returns a list of all video mimetypes declared as supported within the
-     * tunnel request.
-     *
-     * @return
-     *     A list of all video mimetypes declared as supported within the
-     *     tunnel request, or null if no mimetypes were specified.
-     */
-    public List<String> getVideoMimetypes() {
-        return getParameterValues(VIDEO_PARAMETER);
-    }
-
-    /**
-     * Returns a list of all image mimetypes declared as supported within the
-     * tunnel request.
-     *
-     * @return
-     *     A list of all image mimetypes declared as supported within the
-     *     tunnel request, or null if no mimetypes were specified.
-     */
-    public List<String> getImageMimetypes() {
-        return getParameterValues(IMAGE_PARAMETER);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/713fc7f8/guacamole/src/main/java/org/apache/guacamole/TunnelRequestService.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/TunnelRequestService.java b/guacamole/src/main/java/org/apache/guacamole/TunnelRequestService.java
deleted file mode 100644
index d78fdde..0000000
--- a/guacamole/src/main/java/org/apache/guacamole/TunnelRequestService.java
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Copyright (C) 2013 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-package org.apache.guacamole;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import java.util.List;
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.GuacamoleSecurityException;
-import org.apache.guacamole.GuacamoleUnauthorizedException;
-import org.apache.guacamole.net.DelegatingGuacamoleTunnel;
-import org.apache.guacamole.net.GuacamoleTunnel;
-import org.apache.guacamole.net.auth.Connection;
-import org.apache.guacamole.net.auth.ConnectionGroup;
-import org.apache.guacamole.net.auth.Directory;
-import org.apache.guacamole.net.auth.UserContext;
-import org.apache.guacamole.rest.ObjectRetrievalService;
-import org.apache.guacamole.rest.auth.AuthenticationService;
-import org.apache.guacamole.protocol.GuacamoleClientInformation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Utility class that takes a standard request from the Guacamole JavaScript
- * client and produces the corresponding GuacamoleTunnel. The implementation
- * of this utility is specific to the form of request used by the upstream
- * Guacamole web application, and is not necessarily useful to applications
- * that use purely the Guacamole API.
- *
- * @author Michael Jumper
- * @author Vasily Loginov
- */
-@Singleton
-public class TunnelRequestService {
-
-    /**
-     * Logger for this class.
-     */
-    private final Logger logger = LoggerFactory.getLogger(TunnelRequestService.class);
-
-    /**
-     * A service for authenticating users from auth tokens.
-     */
-    @Inject
-    private AuthenticationService authenticationService;
-
-    /**
-     * Service for convenient retrieval of objects.
-     */
-    @Inject
-    private ObjectRetrievalService retrievalService;
-
-    /**
-     * Reads and returns the client information provided within the given
-     * request.
-     *
-     * @param request
-     *     The request describing tunnel to create.
-     *
-     * @return GuacamoleClientInformation
-     *     An object containing information about the client sending the tunnel
-     *     request.
-     *
-     * @throws GuacamoleException
-     *     If the parameters of the tunnel request are invalid.
-     */
-    protected GuacamoleClientInformation getClientInformation(TunnelRequest request)
-        throws GuacamoleException {
-
-        // Get client information
-        GuacamoleClientInformation info = new GuacamoleClientInformation();
-
-        // Set width if provided
-        Integer width = request.getWidth();
-        if (width != null)
-            info.setOptimalScreenWidth(width);
-
-        // Set height if provided
-        Integer height = request.getHeight();
-        if (height != null)
-            info.setOptimalScreenHeight(height);
-
-        // Set resolution if provided
-        Integer dpi = request.getDPI();
-        if (dpi != null)
-            info.setOptimalResolution(dpi);
-
-        // Add audio mimetypes
-        List<String> audioMimetypes = request.getAudioMimetypes();
-        if (audioMimetypes != null)
-            info.getAudioMimetypes().addAll(audioMimetypes);
-
-        // Add video mimetypes
-        List<String> videoMimetypes = request.getVideoMimetypes();
-        if (videoMimetypes != null)
-            info.getVideoMimetypes().addAll(videoMimetypes);
-
-        // Add image mimetypes
-        List<String> imageMimetypes = request.getImageMimetypes();
-        if (imageMimetypes != null)
-            info.getImageMimetypes().addAll(imageMimetypes);
-
-        return info;
-    }
-
-    /**
-     * Creates a new tunnel using which is connected to the connection or
-     * connection group identifier by the given ID. Client information
-     * is specified in the {@code info} parameter.
-     *
-     * @param context
-     *     The UserContext associated with the user for whom the tunnel is
-     *     being created.
-     *
-     * @param type
-     *     The type of object being connected to (connection or group).
-     *
-     * @param id
-     *     The id of the connection or group being connected to.
-     *
-     * @param info
-     *     Information describing the connected Guacamole client.
-     *
-     * @return
-     *     A new tunnel, connected as required by the request.
-     *
-     * @throws GuacamoleException
-     *     If an error occurs while creating the tunnel.
-     */
-    protected GuacamoleTunnel createConnectedTunnel(UserContext context,
-            final TunnelRequest.Type type, String id,
-            GuacamoleClientInformation info)
-            throws GuacamoleException {
-
-        // Create connected tunnel from identifier
-        GuacamoleTunnel tunnel = null;
-        switch (type) {
-
-            // Connection identifiers
-            case CONNECTION: {
-
-                // Get connection directory
-                Directory<Connection> directory = context.getConnectionDirectory();
-
-                // Get authorized connection
-                Connection connection = directory.get(id);
-                if (connection == null) {
-                    logger.info("Connection \"{}\" does not exist for user \"{}\".", id, context.self().getIdentifier());
-                    throw new GuacamoleSecurityException("Requested connection is not authorized.");
-                }
-
-                // Connect tunnel
-                tunnel = connection.connect(info);
-                logger.info("User \"{}\" connected to connection \"{}\".", context.self().getIdentifier(), id);
-                break;
-            }
-
-            // Connection group identifiers
-            case CONNECTION_GROUP: {
-
-                // Get connection group directory
-                Directory<ConnectionGroup> directory = context.getConnectionGroupDirectory();
-
-                // Get authorized connection group
-                ConnectionGroup group = directory.get(id);
-                if (group == null) {
-                    logger.info("Connection group \"{}\" does not exist for user \"{}\".", id, context.self().getIdentifier());
-                    throw new GuacamoleSecurityException("Requested connection group is not authorized.");
-                }
-
-                // Connect tunnel
-                tunnel = group.connect(info);
-                logger.info("User \"{}\" connected to group \"{}\".", context.self().getIdentifier(), id);
-                break;
-            }
-
-            // Type is guaranteed to be one of the above
-            default:
-                assert(false);
-
-        }
-
-        return tunnel;
-
-    }
-
-    /**
-     * Associates the given tunnel with the given session, returning a wrapped
-     * version of the same tunnel which automatically handles closure and
-     * removal from the session.
-     *
-     * @param tunnel
-     *     The connected tunnel to wrap and monitor.
-     *
-     * @param authToken
-     *     The authentication token associated with the given session. If
-     *     provided, this token will be automatically invalidated (and the
-     *     corresponding session destroyed) if tunnel errors imply that the
-     *     user is no longer authorized.
-     *
-     * @param session
-     *     The Guacamole session to associate the tunnel with.
-     *
-     * @param type
-     *     The type of object being connected to (connection or group).
-     *
-     * @param id
-     *     The id of the connection or group being connected to.
-     *
-     * @return
-     *     A new tunnel, associated with the given session, which delegates all
-     *     functionality to the given tunnel while monitoring and automatically
-     *     handling closure.
-     *
-     * @throws GuacamoleException
-     *     If an error occurs while obtaining the tunnel.
-     */
-    protected GuacamoleTunnel createAssociatedTunnel(GuacamoleTunnel tunnel,
-            final String authToken,  final GuacamoleSession session,
-            final TunnelRequest.Type type, final String id)
-            throws GuacamoleException {
-
-        // Monitor tunnel closure and data
-        GuacamoleTunnel monitoredTunnel = new DelegatingGuacamoleTunnel(tunnel) {
-
-            /**
-             * The time the connection began, measured in milliseconds since
-             * midnight, January 1, 1970 UTC.
-             */
-            private final long connectionStartTime = System.currentTimeMillis();
-
-            @Override
-            public void close() throws GuacamoleException {
-
-                long connectionEndTime = System.currentTimeMillis();
-                long duration = connectionEndTime - connectionStartTime;
-
-                // Log closure
-                switch (type) {
-
-                    // Connection identifiers
-                    case CONNECTION:
-                        logger.info("User \"{}\" disconnected from connection \"{}\". Duration: {} milliseconds",
-                                session.getAuthenticatedUser().getIdentifier(), id, duration);
-                        break;
-
-                    // Connection group identifiers
-                    case CONNECTION_GROUP:
-                        logger.info("User \"{}\" disconnected from connection group \"{}\". Duration: {} milliseconds",
-                                session.getAuthenticatedUser().getIdentifier(), id, duration);
-                        break;
-
-                    // Type is guaranteed to be one of the above
-                    default:
-                        assert(false);
-
-                }
-
-                try {
-
-                    // Close and clean up tunnel
-                    session.removeTunnel(getUUID().toString());
-                    super.close();
-
-                }
-
-                // Ensure any associated session is invalidated if unauthorized
-                catch (GuacamoleUnauthorizedException e) {
-
-                    // If there is an associated auth token, invalidate it
-                    if (authenticationService.destroyGuacamoleSession(authToken))
-                        logger.debug("Implicitly invalidated session for token \"{}\".", authToken);
-
-                    // Continue with exception processing
-                    throw e;
-
-                }
-
-            }
-
-        };
-
-        // Associate tunnel with session
-        session.addTunnel(monitoredTunnel);
-        return monitoredTunnel;
-        
-    }
-
-    /**
-     * Creates a new tunnel using the parameters and credentials present in
-     * the given request.
-     *
-     * @param request
-     *     The request describing the tunnel to create.
-     *
-     * @return
-     *     The created tunnel, or null if the tunnel could not be created.
-     *
-     * @throws GuacamoleException
-     *     If an error occurs while creating the tunnel.
-     */
-    public GuacamoleTunnel createTunnel(TunnelRequest request)
-            throws GuacamoleException {
-
-        // Parse request parameters
-        String authToken                = request.getAuthenticationToken();
-        String id                       = request.getIdentifier();
-        TunnelRequest.Type type         = request.getType();
-        String authProviderIdentifier   = request.getAuthenticationProviderIdentifier();
-        GuacamoleClientInformation info = getClientInformation(request);
-
-        GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
-        UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
-
-        try {
-
-            // Create connected tunnel using provided connection ID and client information
-            GuacamoleTunnel tunnel = createConnectedTunnel(userContext, type, id, info);
-
-            // Associate tunnel with session
-            return createAssociatedTunnel(tunnel, authToken, session, type, id);
-
-        }
-
-        // Ensure any associated session is invalidated if unauthorized
-        catch (GuacamoleUnauthorizedException e) {
-
-            // If there is an associated auth token, invalidate it
-            if (authenticationService.destroyGuacamoleSession(authToken))
-                logger.debug("Implicitly invalidated session for token \"{}\".", authToken);
-
-            // Continue with exception processing
-            throw e;
-
-        }
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/713fc7f8/guacamole/src/main/java/org/apache/guacamole/rest/auth/BasicTokenSessionMap.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/auth/BasicTokenSessionMap.java b/guacamole/src/main/java/org/apache/guacamole/rest/auth/BasicTokenSessionMap.java
deleted file mode 100644
index 9486122..0000000
--- a/guacamole/src/main/java/org/apache/guacamole/rest/auth/BasicTokenSessionMap.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2014 Glyptodon LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-package org.apache.guacamole.rest.auth;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.environment.Environment;
-import org.apache.guacamole.GuacamoleSession;
-import org.apache.guacamole.properties.IntegerGuacamoleProperty;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A HashMap-based implementation of the TokenSessionMap with support for
- * session timeouts.
- *
- * @author James Muehlner
- */
-public class BasicTokenSessionMap implements TokenSessionMap {
-
-    /**
-     * Logger for this class.
-     */
-    private static final Logger logger = LoggerFactory.getLogger(BasicTokenSessionMap.class);
-
-    /**
-     * Executor service which runs the period session eviction task.
-     */
-    private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
-    
-    /**
-     * Keeps track of the authToken to GuacamoleSession mapping.
-     */
-    private final ConcurrentMap<String, GuacamoleSession> sessionMap =
-            new ConcurrentHashMap<String, GuacamoleSession>();
-
-    /**
-     * The session timeout for the Guacamole REST API, in minutes.
-     */
-    private final IntegerGuacamoleProperty API_SESSION_TIMEOUT =
-            new IntegerGuacamoleProperty() {
-
-        @Override
-        public String getName() { return "api-session-timeout"; }
-
-    };
-
-    /**
-     * Create a new BasicTokenGuacamoleSessionMap configured using the given
-     * environment.
-     *
-     * @param environment
-     *     The environment to use when configuring the token session map.
-     */
-    public BasicTokenSessionMap(Environment environment) {
-        
-        int sessionTimeoutValue;
-
-        // Read session timeout from guacamole.properties
-        try {
-            sessionTimeoutValue = environment.getProperty(API_SESSION_TIMEOUT, 60);
-        }
-        catch (GuacamoleException e) {
-            logger.error("Unable to read guacamole.properties: {}", e.getMessage());
-            logger.debug("Error while reading session timeout value.", e);
-            sessionTimeoutValue = 60;
-        }
-        
-        // Check for expired sessions every minute
-        logger.info("Sessions will expire after {} minutes of inactivity.", sessionTimeoutValue);
-        executor.scheduleAtFixedRate(new SessionEvictionTask(sessionTimeoutValue * 60000l), 1, 1, TimeUnit.MINUTES);
-        
-    }
-
-    /**
-     * Task which iterates through all active sessions, evicting those sessions
-     * which are beyond the session timeout.
-     */
-    private class SessionEvictionTask implements Runnable {
-
-        /**
-         * The maximum allowed age of any session, in milliseconds.
-         */
-        private final long sessionTimeout;
-
-        /**
-         * Creates a new task which automatically evicts sessions which are
-         * older than the specified timeout.
-         * 
-         * @param sessionTimeout The maximum age of any session, in
-         *                       milliseconds.
-         */
-        public SessionEvictionTask(long sessionTimeout) {
-            this.sessionTimeout = sessionTimeout;
-        }
-        
-        @Override
-        public void run() {
-
-            // Get start time of session check time
-            long sessionCheckStart = System.currentTimeMillis();
-
-            logger.debug("Checking for expired sessions...");
-
-            // For each session, remove sesions which have expired
-            Iterator<Map.Entry<String, GuacamoleSession>> entries = sessionMap.entrySet().iterator();
-            while (entries.hasNext()) {
-
-                Map.Entry<String, GuacamoleSession> entry = entries.next();
-                GuacamoleSession session = entry.getValue();
-
-                // Do not expire sessions which are active
-                if (session.hasTunnels())
-                    continue;
-
-                // Get elapsed time since last access
-                long age = sessionCheckStart - session.getLastAccessedTime();
-
-                // If session is too old, evict it and check the next one
-                if (age >= sessionTimeout) {
-                    logger.debug("Session \"{}\" has timed out.", entry.getKey());
-                    entries.remove();
-                    session.invalidate();
-                }
-
-            }
-
-            // Log completion and duration
-            logger.debug("Session check completed in {} ms.",
-                    System.currentTimeMillis() - sessionCheckStart);
-            
-        }
-
-    }
-
-    @Override
-    public GuacamoleSession get(String authToken) {
-        
-        // There are no null auth tokens
-        if (authToken == null)
-            return null;
-
-        // Update the last access time and return the GuacamoleSession
-        GuacamoleSession session = sessionMap.get(authToken);
-        if (session != null)
-            session.access();
-
-        return session;
-
-    }
-
-    @Override
-    public void put(String authToken, GuacamoleSession session) {
-        sessionMap.put(authToken, session);
-    }
-
-    @Override
-    public GuacamoleSession remove(String authToken) {
-
-        // There are no null auth tokens
-        if (authToken == null)
-            return null;
-
-        // Attempt to retrieve only if non-null
-        return sessionMap.remove(authToken);
-
-    }
-
-    @Override
-    public void shutdown() {
-        executor.shutdownNow();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/713fc7f8/guacamole/src/main/java/org/apache/guacamole/rest/auth/HashTokenSessionMap.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/auth/HashTokenSessionMap.java b/guacamole/src/main/java/org/apache/guacamole/rest/auth/HashTokenSessionMap.java
new file mode 100644
index 0000000..a362c69
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/auth/HashTokenSessionMap.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2014 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest.auth;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.environment.Environment;
+import org.apache.guacamole.GuacamoleSession;
+import org.apache.guacamole.properties.IntegerGuacamoleProperty;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A HashMap-based implementation of the TokenSessionMap with support for
+ * session timeouts.
+ *
+ * @author James Muehlner
+ */
+public class HashTokenSessionMap implements TokenSessionMap {
+
+    /**
+     * Logger for this class.
+     */
+    private static final Logger logger = LoggerFactory.getLogger(HashTokenSessionMap.class);
+
+    /**
+     * Executor service which runs the period session eviction task.
+     */
+    private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
+    
+    /**
+     * Keeps track of the authToken to GuacamoleSession mapping.
+     */
+    private final ConcurrentMap<String, GuacamoleSession> sessionMap =
+            new ConcurrentHashMap<String, GuacamoleSession>();
+
+    /**
+     * The session timeout for the Guacamole REST API, in minutes.
+     */
+    private final IntegerGuacamoleProperty API_SESSION_TIMEOUT =
+            new IntegerGuacamoleProperty() {
+
+        @Override
+        public String getName() { return "api-session-timeout"; }
+
+    };
+
+    /**
+     * Create a new BasicTokenGuacamoleSessionMap configured using the given
+     * environment.
+     *
+     * @param environment
+     *     The environment to use when configuring the token session map.
+     */
+    public HashTokenSessionMap(Environment environment) {
+        
+        int sessionTimeoutValue;
+
+        // Read session timeout from guacamole.properties
+        try {
+            sessionTimeoutValue = environment.getProperty(API_SESSION_TIMEOUT, 60);
+        }
+        catch (GuacamoleException e) {
+            logger.error("Unable to read guacamole.properties: {}", e.getMessage());
+            logger.debug("Error while reading session timeout value.", e);
+            sessionTimeoutValue = 60;
+        }
+        
+        // Check for expired sessions every minute
+        logger.info("Sessions will expire after {} minutes of inactivity.", sessionTimeoutValue);
+        executor.scheduleAtFixedRate(new SessionEvictionTask(sessionTimeoutValue * 60000l), 1, 1, TimeUnit.MINUTES);
+        
+    }
+
+    /**
+     * Task which iterates through all active sessions, evicting those sessions
+     * which are beyond the session timeout.
+     */
+    private class SessionEvictionTask implements Runnable {
+
+        /**
+         * The maximum allowed age of any session, in milliseconds.
+         */
+        private final long sessionTimeout;
+
+        /**
+         * Creates a new task which automatically evicts sessions which are
+         * older than the specified timeout.
+         * 
+         * @param sessionTimeout The maximum age of any session, in
+         *                       milliseconds.
+         */
+        public SessionEvictionTask(long sessionTimeout) {
+            this.sessionTimeout = sessionTimeout;
+        }
+        
+        @Override
+        public void run() {
+
+            // Get start time of session check time
+            long sessionCheckStart = System.currentTimeMillis();
+
+            logger.debug("Checking for expired sessions...");
+
+            // For each session, remove sesions which have expired
+            Iterator<Map.Entry<String, GuacamoleSession>> entries = sessionMap.entrySet().iterator();
+            while (entries.hasNext()) {
+
+                Map.Entry<String, GuacamoleSession> entry = entries.next();
+                GuacamoleSession session = entry.getValue();
+
+                // Do not expire sessions which are active
+                if (session.hasTunnels())
+                    continue;
+
+                // Get elapsed time since last access
+                long age = sessionCheckStart - session.getLastAccessedTime();
+
+                // If session is too old, evict it and check the next one
+                if (age >= sessionTimeout) {
+                    logger.debug("Session \"{}\" has timed out.", entry.getKey());
+                    entries.remove();
+                    session.invalidate();
+                }
+
+            }
+
+            // Log completion and duration
+            logger.debug("Session check completed in {} ms.",
+                    System.currentTimeMillis() - sessionCheckStart);
+            
+        }
+
+    }
+
+    @Override
+    public GuacamoleSession get(String authToken) {
+        
+        // There are no null auth tokens
+        if (authToken == null)
+            return null;
+
+        // Update the last access time and return the GuacamoleSession
+        GuacamoleSession session = sessionMap.get(authToken);
+        if (session != null)
+            session.access();
+
+        return session;
+
+    }
+
+    @Override
+    public void put(String authToken, GuacamoleSession session) {
+        sessionMap.put(authToken, session);
+    }
+
+    @Override
+    public GuacamoleSession remove(String authToken) {
+
+        // There are no null auth tokens
+        if (authToken == null)
+            return null;
+
+        // Attempt to retrieve only if non-null
+        return sessionMap.remove(authToken);
+
+    }
+
+    @Override
+    public void shutdown() {
+        executor.shutdownNow();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/713fc7f8/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelLoader.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelLoader.java b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelLoader.java
new file mode 100644
index 0000000..2e58d95
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelLoader.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.tunnel;
+
+import com.google.inject.Module;
+
+/**
+ * Generic means of loading a tunnel without adding explicit dependencies within
+ * the main ServletModule, as not all servlet containers may have the classes
+ * required by all tunnel implementations.
+ *
+ * @author Michael Jumper
+ */
+public interface TunnelLoader extends Module {
+
+    /**
+     * Checks whether this type of tunnel is supported by the servlet container.
+     * 
+     * @return true if this type of tunnel is supported and can be loaded
+     *         without errors, false otherwise.
+     */
+    public boolean isSupported();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/713fc7f8/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelModule.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelModule.java b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelModule.java
new file mode 100644
index 0000000..331184f
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelModule.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.tunnel;
+
+import org.apache.guacamole.tunnel.http.RestrictedGuacamoleHTTPTunnelServlet;
+import com.google.inject.servlet.ServletModule;
+import java.lang.reflect.InvocationTargetException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Module which loads tunnel implementations.
+ *
+ * @author Michael Jumper
+ */
+public class TunnelModule extends ServletModule {
+
+    /**
+     * Logger for this class.
+     */
+    private final Logger logger = LoggerFactory.getLogger(TunnelModule.class);
+
+    /**
+     * Classnames of all implementation-specific WebSocket tunnel modules.
+     */
+    private static final String[] WEBSOCKET_MODULES = {
+        "org.apache.guacamole.websocket.WebSocketTunnelModule",
+        "org.apache.guacamole.websocket.jetty8.WebSocketTunnelModule",
+        "org.apache.guacamole.websocket.jetty9.WebSocketTunnelModule",
+        "org.apache.guacamole.websocket.tomcat.WebSocketTunnelModule"
+    };
+
+    private boolean loadWebSocketModule(String classname) {
+
+        try {
+
+            // Attempt to find WebSocket module
+            Class<?> module = Class.forName(classname);
+
+            // Create loader
+            TunnelLoader loader = (TunnelLoader) module.getConstructor().newInstance();
+
+            // Install module, if supported
+            if (loader.isSupported()) {
+                install(loader);
+                return true;
+            }
+
+        }
+
+        // If no such class or constructor, etc., then this particular
+        // WebSocket support is not present
+        catch (ClassNotFoundException e) {}
+        catch (NoClassDefFoundError e) {}
+        catch (NoSuchMethodException e) {}
+
+        // Log errors which indicate bugs
+        catch (InstantiationException e) {
+            logger.debug("Error instantiating WebSocket module.", e);
+        }
+        catch (IllegalAccessException e) {
+            logger.debug("Error instantiating WebSocket module.", e);
+        }
+        catch (InvocationTargetException e) {
+            logger.debug("Error instantiating WebSocket module.", e);
+        }
+
+        // Load attempt failed
+        return false;
+
+    }
+
+    @Override
+    protected void configureServlets() {
+
+        bind(TunnelRequestService.class);
+
+        // Set up HTTP tunnel
+        serve("/tunnel").with(RestrictedGuacamoleHTTPTunnelServlet.class);
+
+        // Try to load each WebSocket tunnel in sequence
+        for (String classname : WEBSOCKET_MODULES) {
+            if (loadWebSocketModule(classname)) {
+                logger.debug("WebSocket module loaded: {}", classname);
+                return;
+            }
+        }
+
+        // Warn of lack of WebSocket
+        logger.info("WebSocket support NOT present. Only HTTP will be used.");
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/713fc7f8/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java
new file mode 100644
index 0000000..e210ded
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2015 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.tunnel;
+
+import java.util.List;
+import org.apache.guacamole.GuacamoleClientException;
+import org.apache.guacamole.GuacamoleClientException;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleException;
+
+/**
+ * A request object which provides only the functions absolutely required to
+ * retrieve and connect to a tunnel.
+ *
+ * @author Michael Jumper
+ */
+public abstract class TunnelRequest {
+
+    /**
+     * The name of the request parameter containing the user's authentication
+     * token.
+     */
+    public static final String AUTH_TOKEN_PARAMETER = "token";
+
+    /**
+     * The name of the parameter containing the identifier of the
+     * AuthenticationProvider associated with the UserContext containing the
+     * object to which a tunnel is being requested.
+     */
+    public static final String AUTH_PROVIDER_IDENTIFIER_PARAMETER = "GUAC_DATA_SOURCE";
+
+    /**
+     * The name of the parameter specifying the type of object to which a
+     * tunnel is being requested. Currently, this may be "c" for a Guacamole
+     * connection, or "g" for a Guacamole connection group.
+     */
+    public static final String TYPE_PARAMETER = "GUAC_TYPE";
+
+    /**
+     * The name of the parameter containing the unique identifier of the object
+     * to which a tunnel is being requested.
+     */
+    public static final String IDENTIFIER_PARAMETER = "GUAC_ID";
+
+    /**
+     * The name of the parameter containing the desired display width, in
+     * pixels.
+     */
+    public static final String WIDTH_PARAMETER = "GUAC_WIDTH";
+
+    /**
+     * The name of the parameter containing the desired display height, in
+     * pixels.
+     */
+    public static final String HEIGHT_PARAMETER = "GUAC_HEIGHT";
+
+    /**
+     * The name of the parameter containing the desired display resolution, in
+     * DPI.
+     */
+    public static final String DPI_PARAMETER = "GUAC_DPI";
+
+    /**
+     * The name of the parameter specifying one supported audio mimetype. This
+     * will normally appear multiple times within a single tunnel request -
+     * once for each mimetype.
+     */
+    public static final String AUDIO_PARAMETER = "GUAC_AUDIO";
+
+    /**
+     * The name of the parameter specifying one supported video mimetype. This
+     * will normally appear multiple times within a single tunnel request -
+     * once for each mimetype.
+     */
+    public static final String VIDEO_PARAMETER = "GUAC_VIDEO";
+
+    /**
+     * The name of the parameter specifying one supported image mimetype. This
+     * will normally appear multiple times within a single tunnel request -
+     * once for each mimetype.
+     */
+    public static final String IMAGE_PARAMETER = "GUAC_IMAGE";
+
+    /**
+     * All supported object types that can be used as the destination of a
+     * tunnel.
+     */
+    public static enum Type {
+
+        /**
+         * A Guacamole connection.
+         */
+        CONNECTION("c"),
+
+        /**
+         * A Guacamole connection group.
+         */
+        CONNECTION_GROUP("g");
+
+        /**
+         * The parameter value which denotes a destination object of this type.
+         */
+        final String PARAMETER_VALUE;
+        
+        /**
+         * Defines a Type having the given corresponding parameter value.
+         *
+         * @param value
+         *     The parameter value which denotes a destination object of this
+         *     type.
+         */
+        Type(String value) {
+            PARAMETER_VALUE = value;
+        }
+
+    };
+
+    /**
+     * Returns the value of the parameter having the given name.
+     *
+     * @param name
+     *     The name of the parameter to return.
+     *
+     * @return
+     *     The value of the parameter having the given name, or null if no such
+     *     parameter was specified.
+     */
+    public abstract String getParameter(String name);
+
+    /**
+     * Returns a list of all values specified for the given parameter.
+     *
+     * @param name
+     *     The name of the parameter to return.
+     *
+     * @return
+     *     All values of the parameter having the given name , or null if no
+     *     such parameter was specified.
+     */
+    public abstract List<String> getParameterValues(String name);
+
+    /**
+     * Returns the value of the parameter having the given name, throwing an
+     * exception if the parameter is missing.
+     *
+     * @param name
+     *     The name of the parameter to return.
+     *
+     * @return
+     *     The value of the parameter having the given name.
+     *
+     * @throws GuacamoleException
+     *     If the parameter is not present in the request.
+     */
+    public String getRequiredParameter(String name) throws GuacamoleException {
+
+        // Pull requested parameter, aborting if absent
+        String value = getParameter(name);
+        if (value == null)
+            throw new GuacamoleClientException("Parameter \"" + name + "\" is required.");
+
+        return value;
+
+    }
+
+    /**
+     * Returns the integer value of the parameter having the given name,
+     * throwing an exception if the parameter cannot be parsed.
+     *
+     * @param name
+     *     The name of the parameter to return.
+     *
+     * @return
+     *     The integer value of the parameter having the given name, or null if
+     *     the parameter is missing.
+     *
+     * @throws GuacamoleException
+     *     If the parameter is not a valid integer.
+     */
+    public Integer getIntegerParameter(String name) throws GuacamoleException {
+
+        // Pull requested parameter
+        String value = getParameter(name);
+        if (value == null)
+            return null;
+
+        // Attempt to parse as an integer
+        try {
+            return Integer.parseInt(value);
+        }
+
+        // Rethrow any parsing error as a GuacamoleClientException
+        catch (NumberFormatException e) {
+            throw new GuacamoleClientException("Parameter \"" + name + "\" must be a valid integer.", e);
+        }
+
+    }
+
+    /**
+     * Returns the authentication token associated with this tunnel request.
+     *
+     * @return
+     *     The authentication token associated with this tunnel request, or
+     *     null if no authentication token is present.
+     */
+    public String getAuthenticationToken() {
+        return getParameter(AUTH_TOKEN_PARAMETER);
+    }
+
+    /**
+     * Returns the identifier of the AuthenticationProvider associated with the
+     * UserContext from which the connection or connection group is to be
+     * retrieved when the tunnel is created. In the context of the REST API and
+     * the JavaScript side of the web application, this is referred to as the
+     * data source identifier.
+     *
+     * @return
+     *     The identifier of the AuthenticationProvider associated with the
+     *     UserContext from which the connection or connection group is to be
+     *     retrieved when the tunnel is created.
+     *
+     * @throws GuacamoleException
+     *     If the identifier was not present in the request.
+     */
+    public String getAuthenticationProviderIdentifier()
+            throws GuacamoleException {
+        return getRequiredParameter(AUTH_PROVIDER_IDENTIFIER_PARAMETER);
+    }
+
+    /**
+     * Returns the type of object for which the tunnel is being requested.
+     *
+     * @return
+     *     The type of object for which the tunnel is being requested.
+     *
+     * @throws GuacamoleException
+     *     If the type was not present in the request, or if the type requested
+     *     is in the wrong format.
+     */
+    public Type getType() throws GuacamoleException {
+
+        String type = getRequiredParameter(TYPE_PARAMETER);
+
+        // For each possible object type
+        for (Type possibleType : Type.values()) {
+
+            // Match against defined parameter value
+            if (type.equals(possibleType.PARAMETER_VALUE))
+                return possibleType;
+
+        }
+
+        throw new GuacamoleClientException("Illegal identifier - unknown type.");
+
+    }
+
+    /**
+     * Returns the identifier of the destination of the tunnel being requested.
+     * As there are multiple types of destination objects available, and within
+     * multiple data sources, the associated object type and data source are
+     * also necessary to determine what this identifier refers to.
+     *
+     * @return
+     *     The identifier of the destination of the tunnel being requested.
+     *
+     * @throws GuacamoleException
+     *     If the identifier was not present in the request.
+     */
+    public String getIdentifier() throws GuacamoleException {
+        return getRequiredParameter(IDENTIFIER_PARAMETER);
+    }
+
+    /**
+     * Returns the display width desired for the Guacamole session over the
+     * tunnel being requested.
+     *
+     * @return
+     *     The display width desired for the Guacamole session over the tunnel
+     *     being requested, or null if no width was given.
+     *
+     * @throws GuacamoleException
+     *     If the width specified was not a valid integer.
+     */
+    public Integer getWidth() throws GuacamoleException {
+        return getIntegerParameter(WIDTH_PARAMETER);
+    }
+
+    /**
+     * Returns the display height desired for the Guacamole session over the
+     * tunnel being requested.
+     *
+     * @return
+     *     The display height desired for the Guacamole session over the tunnel
+     *     being requested, or null if no width was given.
+     *
+     * @throws GuacamoleException
+     *     If the height specified was not a valid integer.
+     */
+    public Integer getHeight() throws GuacamoleException {
+        return getIntegerParameter(HEIGHT_PARAMETER);
+    }
+
+    /**
+     * Returns the display resolution desired for the Guacamole session over
+     * the tunnel being requested, in DPI.
+     *
+     * @return
+     *     The display resolution desired for the Guacamole session over the
+     *     tunnel being requested, or null if no resolution was given.
+     *
+     * @throws GuacamoleException
+     *     If the resolution specified was not a valid integer.
+     */
+    public Integer getDPI() throws GuacamoleException {
+        return getIntegerParameter(DPI_PARAMETER);
+    }
+
+    /**
+     * Returns a list of all audio mimetypes declared as supported within the
+     * tunnel request.
+     *
+     * @return
+     *     A list of all audio mimetypes declared as supported within the
+     *     tunnel request, or null if no mimetypes were specified.
+     */
+    public List<String> getAudioMimetypes() {
+        return getParameterValues(AUDIO_PARAMETER);
+    }
+
+    /**
+     * Returns a list of all video mimetypes declared as supported within the
+     * tunnel request.
+     *
+     * @return
+     *     A list of all video mimetypes declared as supported within the
+     *     tunnel request, or null if no mimetypes were specified.
+     */
+    public List<String> getVideoMimetypes() {
+        return getParameterValues(VIDEO_PARAMETER);
+    }
+
+    /**
+     * Returns a list of all image mimetypes declared as supported within the
+     * tunnel request.
+     *
+     * @return
+     *     A list of all image mimetypes declared as supported within the
+     *     tunnel request, or null if no mimetypes were specified.
+     */
+    public List<String> getImageMimetypes() {
+        return getParameterValues(IMAGE_PARAMETER);
+    }
+
+}