diff --git a/guacamole/pom.xml b/guacamole/pom.xml
index 0693e6aae..3e8941da7 100644
--- a/guacamole/pom.xml
+++ b/guacamole/pom.xml
@@ -254,6 +254,11 @@
slf4j-api
1.7.7
+
+ org.slf4j
+ jul-to-slf4j
+ 1.7.7
+
ch.qos.logback
logback-classic
@@ -435,34 +440,39 @@
com.google.inject
guice
- 3.0
+ 4.2.3
com.google.inject.extensions
guice-assistedinject
- 3.0
+ 4.2.3
com.google.inject.extensions
guice-servlet
- 3.0
+ 4.2.3
- com.sun.jersey
- jersey-server
- 1.17.1
+ org.glassfish.jersey.containers
+ jersey-container-servlet-core
+ 2.31
+
+
+ org.glassfish.jersey.inject
+ jersey-hk2
+ 2.31
-
+
- com.sun.jersey.contribs
- jersey-guice
- 1.17.1
-
+ org.glassfish.hk2
+ guice-bridge
+ 2.6.1
+
@@ -473,9 +483,9 @@
- com.sun.jersey
- jersey-json
- 1.17.1
+ org.glassfish.jersey.media
+ jersey-media-json-jackson
+ 2.31
diff --git a/guacamole/src/main/java/org/apache/guacamole/GuacamoleApplication.java b/guacamole/src/main/java/org/apache/guacamole/GuacamoleApplication.java
new file mode 100644
index 000000000..7f3e4603c
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/GuacamoleApplication.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole;
+
+import com.google.inject.Injector;
+import javax.inject.Inject;
+import javax.servlet.ServletContext;
+import javax.ws.rs.ApplicationPath;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.jersey.jackson.JacksonFeature;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.jvnet.hk2.guice.bridge.api.GuiceBridge;
+import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge;
+import org.slf4j.bridge.SLF4JBridgeHandler;
+
+/**
+ * JAX-RS Application which serves as the root definition of the Guacamole
+ * REST API. The HK2 dependency injection used by Jersey is automatically
+ * bridged to Guice, allowing injections managed by Guice to be injected within
+ * classes served by Jersey.
+ */
+@ApplicationPath("/*")
+public class GuacamoleApplication extends ResourceConfig {
+
+ /**
+ * Creates a new GuacamoleApplication which defines the Guacamole REST API,
+ * automatically configuring Jersey's HK2 dependency injection to
+ * additionally pull services from a Guice injector.
+ *
+ * @param servletContext
+ * The ServletContext which has already associated with a Guice
+ * injector via a GuacamoleServletContextListener.
+ *
+ * @param serviceLocator
+ * The HK2 service locator (injector).
+ */
+ @Inject
+ public GuacamoleApplication(ServletContext servletContext,
+ ServiceLocator serviceLocator) {
+
+ // Bridge Jersey logging (java.util.logging) to SLF4J
+ SLF4JBridgeHandler.removeHandlersForRootLogger();
+ SLF4JBridgeHandler.install();
+
+ // Bridge HK2 service locator with Guice injector
+ Injector guiceInjector = (Injector) servletContext.getAttribute(GuacamoleServletContextListener.GUICE_INJECTOR);
+ GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
+ GuiceIntoHK2Bridge bridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
+ bridge.bridgeGuiceInjector(guiceInjector);
+
+ // Automatically scan for REST resources
+ packages("org.apache.guacamole.rest");
+
+ // Use Jackson for JSON
+ register(JacksonFeature.class);
+
+ }
+
+}
diff --git a/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java b/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java
index 38d5b7c01..f793575e6 100644
--- a/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java
+++ b/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java
@@ -25,6 +25,7 @@ import com.google.inject.Injector;
import com.google.inject.Stage;
import com.google.inject.servlet.GuiceServletContextListener;
import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject;
import javax.servlet.ServletContextEvent;
import org.apache.guacamole.environment.Environment;
@@ -41,9 +42,45 @@ import org.slf4j.LoggerFactory;
/**
* A ServletContextListener to listen for initialization of the servlet context
* in order to set up dependency injection.
+ *
+ * NOTE: Guacamole's REST API uses Jersey 2.x which does not natively support
+ * dependency injection using Guice. It DOES support dependency injection using
+ * HK2, which supports bi-directional bridging with Guice.
+ *
+ * The overall process is thus:
+ *
+ * 1. Application initialization proceeds using GuacamoleServletContextListener,
+ * a subclass of GuiceServletContextListener, with all HTTP requests being
+ * routed through GuiceFilter which serves as the absolute root.
+ *
+ * 2. GuacamoleServletContextListener prepares the Guice injector, storing the
+ * injector within the ServletContext such that it can later be bridged with
+ * HK2.
+ *
+ * 3. Several of the modules used to prepare the Guice injector are
+ * ServletModule subclasses, which define HTTP request paths that GuiceFilter
+ * should route to specific servlets. One of these paths is "/api/*" (the
+ * root of the REST API) which is routed to Jersey's ServletContainer servlet
+ * (the root of Jersey's JAX-RS implementation).
+ *
+ * 4. Configuration information passed to Jersey's ServletContainer tells Jersey
+ * to use the GuacamoleApplication class (a subclass of ResourceConfig) to
+ * define the rest of the resources and any other configuration.
+ *
+ * 5. When Jersey creates its instance of GuacamoleApplication, the
+ * initialization process of GuacamoleApplication pulls the Guice injector
+ * from the ServletContext, completes the HK2 bridging, and configures Jersey
+ * to automatically locate and inject all REST services.
*/
public class GuacamoleServletContextListener extends GuiceServletContextListener {
+ /**
+ * The name of the ServletContext attribute which will contain a reference
+ * to the Guice injector once the contextInitialized() event has been
+ * handled.
+ */
+ public static final String GUICE_INJECTOR = "GUAC_GUICE_INJECTOR";
+
/**
* Logger for this class.
*/
@@ -65,6 +102,12 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener
@Inject
private List authProviders;
+ /**
+ * Internal reference to the Guice injector that was lazily created when
+ * getInjector() was first invoked.
+ */
+ private final AtomicReference guiceInjector = new AtomicReference<>();
+
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
@@ -78,33 +121,47 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener
throw new RuntimeException(e);
}
+ // NOTE: The superclass implementation of contextInitialized() is
+ // expected to invoke getInjector(), hence the need to call AFTER
+ // setting up the environment and session map
super.contextInitialized(servletContextEvent);
+ // Inject any annotated members of this class
+ Injector injector = getInjector();
+ injector.injectMembers(this);
+
+ // Store reference to injector for use by Jersey and HK2 bridge
+ servletContextEvent.getServletContext().setAttribute(GUICE_INJECTOR, injector);
+
}
@Override
protected Injector getInjector() {
+ return guiceInjector.updateAndGet((current) -> {
- // Create injector
- Injector injector = Guice.createInjector(Stage.PRODUCTION,
- new EnvironmentModule(environment),
- new LogModule(environment),
- new ExtensionModule(environment),
- new RESTServiceModule(sessionMap),
- new TunnelModule()
- );
+ // Use existing injector if already created
+ if (current != null)
+ return current;
- // Inject any annotated members of this class
- injector.injectMembers(this);
+ // Create new injector if necessary
+ Injector injector = Guice.createInjector(Stage.PRODUCTION,
+ new EnvironmentModule(environment),
+ new LogModule(environment),
+ new ExtensionModule(environment),
+ new RESTServiceModule(sessionMap),
+ new TunnelModule()
+ );
- return injector;
+ return injector;
+ });
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
- super.contextDestroyed(servletContextEvent);
+ // Clean up reference to Guice injector
+ servletContextEvent.getServletContext().removeAttribute(GUICE_INJECTOR);
// Shutdown TokenSessionMap
if (sessionMap != null)
@@ -116,6 +173,9 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener
authProvider.shutdown();
}
+ // Continue any Guice-specific cleanup
+ super.contextDestroyed(servletContextEvent);
+
}
}
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/PATCH.java b/guacamole/src/main/java/org/apache/guacamole/rest/PATCH.java
deleted file mode 100644
index 171719eed..000000000
--- a/guacamole/src/main/java/org/apache/guacamole/rest/PATCH.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-package org.apache.guacamole.rest;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import javax.ws.rs.HttpMethod;
-
-/**
- * An annotation for using the HTTP PATCH method in the REST endpoints.
- */
-@Target({ElementType.METHOD})
-@Retention(RetentionPolicy.RUNTIME)
-@HttpMethod("PATCH")
-public @interface PATCH {}
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTMethodMatcher.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTMethodMatcher.java
deleted file mode 100644
index 875f4161c..000000000
--- a/guacamole/src/main/java/org/apache/guacamole/rest/RESTMethodMatcher.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.guacamole.rest;
-
-import com.google.inject.matcher.AbstractMatcher;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import javax.ws.rs.HttpMethod;
-import javax.ws.rs.Path;
-import org.apache.guacamole.GuacamoleException;
-
-/**
- * A Guice Matcher which matches only methods which throw GuacamoleException
- * (or a subclass thereof) and are explicitly annotated as with an HTTP method
- * annotation like @GET
or @POST
. Any method which
- * throws GuacamoleException and is annotated with an annotation that is
- * annotated with @HttpMethod
will match.
- */
-public class RESTMethodMatcher extends AbstractMatcher {
-
- /**
- * Returns whether the given method throws the specified exception type,
- * including any subclasses of that type.
- *
- * @param method
- * The method to test.
- *
- * @param exceptionType
- * The exception type to test for.
- *
- * @return
- * true if the given method throws an exception of the specified type,
- * false otherwise.
- */
- private boolean methodThrowsException(Method method,
- Class extends Exception> exceptionType) {
-
- // Check whether the method throws an exception of the specified type
- for (Class> thrownType : method.getExceptionTypes()) {
- if (exceptionType.isAssignableFrom(thrownType))
- return true;
- }
-
- // No such exception is declared to be thrown
- return false;
-
- }
-
- /**
- * Returns whether the given method is annotated as a REST method. A REST
- * method is annotated with an annotation which is annotated with
- * @HttpMethod
or @Path
.
- *
- * @param method
- * The method to test.
- *
- * @return
- * true if the given method is annotated as a REST method, false
- * otherwise.
- */
- private boolean isRESTMethod(Method method) {
-
- // Check whether the required REST annotations are present
- for (Annotation annotation : method.getAnnotations()) {
-
- // A method is a REST method if it is annotated with @HttpMethod
- Class extends Annotation> annotationType = annotation.annotationType();
- if (annotationType.isAnnotationPresent(HttpMethod.class))
- return true;
-
- // A method is a REST method if it is annotated with @Path
- if (Path.class.isAssignableFrom(annotationType))
- return true;
-
- }
-
- // A method is also REST method if it overrides a REST method within
- // the superclass
- Class> superclass = method.getDeclaringClass().getSuperclass();
- if (superclass != null) {
-
- // Recheck against identical method within superclass
- try {
- return isRESTMethod(superclass.getMethod(method.getName(),
- method.getParameterTypes()));
- }
-
- // If there is no such method, then this method cannot possibly be
- // a REST method
- catch (NoSuchMethodException e) {
- return false;
- }
-
- }
-
- // Lacking a superclass, the search stops here - it's not a REST method
- return false;
-
- }
-
- @Override
- public boolean matches(Method method) {
-
- // Guacamole REST methods are REST methods which throw
- // GuacamoleExceptions
- return isRESTMethod(method)
- && methodThrowsException(method, GuacamoleException.class);
-
- }
-
-}
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java
index 9fc1045b2..32878b1ee 100644
--- a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java
@@ -19,19 +19,14 @@
package org.apache.guacamole.rest;
-import org.apache.guacamole.rest.event.ListenerService;
-import org.apache.guacamole.rest.session.UserContextResourceFactory;
-import org.apache.guacamole.rest.session.SessionRESTService;
import com.google.inject.Scopes;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.servlet.ServletModule;
-import com.sun.jersey.api.core.ResourceConfig;
-import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Collections;
+import org.apache.guacamole.rest.event.ListenerService;
+import org.apache.guacamole.rest.session.UserContextResourceFactory;
+import org.apache.guacamole.GuacamoleApplication;
import org.apache.guacamole.rest.activeconnection.ActiveConnectionModule;
-import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
-import org.apache.guacamole.rest.auth.TokenRESTService;
import org.apache.guacamole.rest.auth.AuthTokenGenerator;
import org.apache.guacamole.rest.auth.AuthenticationService;
import org.apache.guacamole.rest.auth.DecorationService;
@@ -39,15 +34,14 @@ import org.apache.guacamole.rest.auth.SecureRandomAuthTokenGenerator;
import org.apache.guacamole.rest.auth.TokenSessionMap;
import org.apache.guacamole.rest.connection.ConnectionModule;
import org.apache.guacamole.rest.connectiongroup.ConnectionGroupModule;
-import org.apache.guacamole.rest.extension.ExtensionRESTService;
-import org.apache.guacamole.rest.language.LanguageRESTService;
-import org.apache.guacamole.rest.patch.PatchRESTService;
import org.apache.guacamole.rest.session.SessionResourceFactory;
import org.apache.guacamole.rest.sharingprofile.SharingProfileModule;
import org.apache.guacamole.rest.tunnel.TunnelCollectionResourceFactory;
import org.apache.guacamole.rest.tunnel.TunnelResourceFactory;
import org.apache.guacamole.rest.user.UserModule;
import org.apache.guacamole.rest.usergroup.UserGroupModule;
+import org.glassfish.jersey.servlet.ServletContainer;
+import org.glassfish.jersey.servlet.ServletProperties;
import org.webjars.servlet.WebjarsServlet;
/**
@@ -76,8 +70,6 @@ public class RESTServiceModule extends ServletModule {
@Override
protected void configureServlets() {
- Map containerParams = new HashMap<>();
-
// Bind session map
bind(TokenSessionMap.class).toInstance(tokenSessionMap);
@@ -87,21 +79,7 @@ public class RESTServiceModule extends ServletModule {
bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class);
bind(DecorationService.class);
- // Automatically translate GuacamoleExceptions for REST methods
- bind(RESTExceptionMapper.class);
-
- // Restrict API requests by entity size
- containerParams.put(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS, RequestSizeFilter.class.getName());
- bind(RequestSizeFilter.class).in(Scopes.SINGLETON);
-
- // Set up the API endpoints
- bind(ExtensionRESTService.class);
- bind(LanguageRESTService.class);
- bind(PatchRESTService.class);
- bind(TokenRESTService.class);
-
// Root-level resources
- bind(SessionRESTService.class);
install(new FactoryModuleBuilder().build(SessionResourceFactory.class));
install(new FactoryModuleBuilder().build(TunnelCollectionResourceFactory.class));
install(new FactoryModuleBuilder().build(TunnelResourceFactory.class));
@@ -115,10 +93,12 @@ public class RESTServiceModule extends ServletModule {
install(new UserModule());
install(new UserGroupModule());
- // Set up the servlet and JSON mappings
- bind(GuiceContainer.class);
- bind(JacksonJsonProvider.class).in(Scopes.SINGLETON);
- serve("/api/*").with(GuiceContainer.class, containerParams);
+ // Serve REST services using Jersey 2.x
+ bind(ServletContainer.class).in(Scopes.SINGLETON);
+ serve("/api/*").with(ServletContainer.class, Collections.singletonMap(
+ ServletProperties.JAXRS_APPLICATION_CLASS,
+ GuacamoleApplication.class.getName()
+ ));
// Serve Webjar JavaScript dependencies
bind(WebjarsServlet.class).in(Scopes.SINGLETON);
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RequestSizeFilter.java b/guacamole/src/main/java/org/apache/guacamole/rest/RequestSizeFilter.java
index 10f0a1cb0..cce8a2970 100644
--- a/guacamole/src/main/java/org/apache/guacamole/rest/RequestSizeFilter.java
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/RequestSizeFilter.java
@@ -19,11 +19,12 @@
package org.apache.guacamole.rest;
-import com.sun.jersey.spi.container.ContainerRequest;
-import com.sun.jersey.spi.container.ContainerRequestFilter;
-import com.sun.jersey.spi.resource.Singleton;
+import java.io.IOException;
import java.io.InputStream;
import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.ext.Provider;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.environment.Environment;
@@ -61,7 +62,7 @@ public class RequestSizeFilter implements ContainerRequestFilter {
private Environment environment;
@Override
- public ContainerRequest filter(ContainerRequest request) {
+ public void filter(ContainerRequestContext context) throws IOException {
// Retrieve configured request size limits
final long maxRequestSize;
@@ -74,15 +75,13 @@ public class RequestSizeFilter implements ContainerRequestFilter {
// Ignore request size if limit is disabled
if (maxRequestSize == 0)
- return request;
+ return;
// Restrict maximum size of requests which have an input stream
// available to be limited
- InputStream stream = request.getEntityInputStream();
+ InputStream stream = context.getEntityStream();
if (stream != null)
- request.setEntityInputStream(new LimitedRequestInputStream(stream, maxRequestSize));
-
- return request;
+ context.setEntityStream(new LimitedRequestInputStream(stream, maxRequestSize));
}
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResource.java
index ce9cb8371..e9b4b225b 100644
--- a/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResource.java
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResource.java
@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
+import javax.ws.rs.PATCH;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@@ -44,7 +45,6 @@ import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermission;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
import org.apache.guacamole.rest.APIPatch;
-import org.apache.guacamole.rest.PATCH;
/**
* A REST resource which abstracts the operations available on all Guacamole
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/identifier/RelatedObjectSetResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/identifier/RelatedObjectSetResource.java
index 446b0453e..77b0b4091 100644
--- a/guacamole/src/main/java/org/apache/guacamole/rest/identifier/RelatedObjectSetResource.java
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/identifier/RelatedObjectSetResource.java
@@ -23,13 +23,13 @@ import java.util.List;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
+import javax.ws.rs.PATCH;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.RelatedObjectSet;
import org.apache.guacamole.rest.APIPatch;
-import org.apache.guacamole.rest.PATCH;
/**
* A REST resource which abstracts the operations available on arbitrary sets
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/permission/PermissionSetResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/permission/PermissionSetResource.java
index 739a39c5e..38b337e0e 100644
--- a/guacamole/src/main/java/org/apache/guacamole/rest/permission/PermissionSetResource.java
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/permission/PermissionSetResource.java
@@ -22,6 +22,7 @@ package org.apache.guacamole.rest.permission;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
+import javax.ws.rs.PATCH;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleClientException;
@@ -31,7 +32,6 @@ import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.Permission;
import org.apache.guacamole.net.auth.permission.SystemPermission;
import org.apache.guacamole.rest.APIPatch;
-import org.apache.guacamole.rest.PATCH;
/**
* A REST resource which abstracts the operations available on the permissions
diff --git a/guacamole/src/main/webapp/WEB-INF/web.xml b/guacamole/src/main/webapp/WEB-INF/web.xml
index bc067c704..52a52a624 100644
--- a/guacamole/src/main/webapp/WEB-INF/web.xml
+++ b/guacamole/src/main/webapp/WEB-INF/web.xml
@@ -28,7 +28,7 @@
index.html
-
+
guiceFilter
com.google.inject.servlet.GuiceFilter
@@ -37,7 +37,6 @@
guiceFilter
/*
-
org.apache.guacamole.GuacamoleServletContextListener