google-nomulus/javatests/google/registry/server/ServletWrapperDelegatorServlet.java
cgoldfeder 0859cde790 Fix the TestServer filter support added in []
In the previous CL I added filter support for the test server, but
even though I could verify that filters were being run when debugging,
in practice the side effects of the filters (notably, ObjectifyFilter
clearing the session cache) were somehow not present in tests (and
therefore causing new as-yet unsubmitted tests that rely on proper
session caching to break).

Investigating further, the way TestServer works is that it creates
a wrapper Servlet for each route, and in that wrapper just pushes
a future onto a queue and waits on it. The actual target servlet
is run within the queue, not within the wrapper servlet's context.
I had added filters to the *wrapper* servlet, which meant that even
though they were invoked before adding the task to the queue, they
were not invoked in the process of actually running the task.

In this CL I pushed the filters into the task itself, just like the
target servlet.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=144123637
2017-01-12 14:02:55 -05:00

94 lines
3.6 KiB
Java

// Copyright 2016 The Nomulus Authors. All Rights Reserved.
//
// Licensed 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 google.registry.server;
import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.util.TypeUtils.instantiate;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Uninterruptibles;
import java.io.IOException;
import java.util.Iterator;
import java.util.Queue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import javax.annotation.Nullable;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet that wraps a servlet and delegates request execution to a queue.
*
* <p>The actual invocation of the delegate does not happen within this servlet's lifecycle.
* Therefore, the task on the queue must manually invoke filters within the queue task.
*
* @see TestServer
*/
public final class ServletWrapperDelegatorServlet extends HttpServlet {
private final Queue<FutureTask<Void>> requestQueue;
private final Class<? extends HttpServlet> servletClass;
private final ImmutableList<Class<? extends Filter>> filterClasses;
ServletWrapperDelegatorServlet(
Class<? extends HttpServlet> servletClass,
ImmutableList<Class<? extends Filter>> filterClasses,
Queue<FutureTask<Void>> requestQueue) {
this.servletClass = servletClass;
this.filterClasses = filterClasses;
this.requestQueue = checkNotNull(requestQueue, "requestQueue");
}
@Override
public void service(final HttpServletRequest req, final HttpServletResponse rsp)
throws ServletException, IOException {
FutureTask<Void> task = new FutureTask<>(new Callable<Void>() {
@Nullable
@Override
public Void call() throws ServletException, IOException {
// Simulate the full filter chain with the servlet at the end.
final Iterator<Class<? extends Filter>> filtersIter = filterClasses.iterator();
FilterChain filterChain =
new FilterChain() {
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
if (filtersIter.hasNext()) {
instantiate(filtersIter.next()).doFilter(request, response, this);
} else {
instantiate(servletClass).service(request, response);
}
}};
filterChain.doFilter(req, rsp);
return null;
}});
requestQueue.add(task);
try {
Uninterruptibles.getUninterruptibly(task);
} catch (ExecutionException e) {
Throwables.propagateIfInstanceOf(e.getCause(), ServletException.class);
Throwables.propagateIfInstanceOf(e.getCause(), IOException.class);
throw Throwables.propagate(e.getCause());
}
}
}