/*
* Copyright 2010 Google Inc.
*
* 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 com.google.jstestdriver.server.handlers;
import static com.google.inject.multibindings.MapBinder.newMapBinder;
import static com.google.jstestdriver.requesthandlers.HttpMethod.GET;
import static com.google.jstestdriver.requesthandlers.HttpMethod.POST;
import static com.google.jstestdriver.server.handlers.CaptureHandler.RUNNER_TYPE;
import static com.google.jstestdriver.server.handlers.pages.PageType.CONSOLE;
import static com.google.jstestdriver.server.handlers.pages.PageType.HEARTBEAT;
import static com.google.jstestdriver.server.handlers.pages.PageType.RUNNER;
import static com.google.jstestdriver.server.handlers.pages.PageType.STANDALONE_RUNNER;
import static com.google.jstestdriver.server.handlers.pages.PageType.VISUAL_STANDALONE_RUNNER;
import static com.google.jstestdriver.server.handlers.pages.SlavePageRequest.LOAD_TYPE;
import static com.google.jstestdriver.server.handlers.pages.SlavePageRequest.REFRESH;
import static com.google.jstestdriver.server.handlers.pages.SlavePageRequest.TESTCASE_ID;
import static com.google.jstestdriver.server.handlers.pages.SlavePageRequest.UPLOAD_SIZE;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Key;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.MapBinder;
import com.google.inject.name.Names;
import com.google.inject.servlet.RequestScoped;
import com.google.jstestdriver.CapturedBrowsers;
import com.google.jstestdriver.FileInfo;
import com.google.jstestdriver.ForwardingServlet;
import com.google.jstestdriver.SlaveBrowser;
import com.google.jstestdriver.SlaveResourceService;
import com.google.jstestdriver.Time;
import com.google.jstestdriver.TimeImpl;
import com.google.jstestdriver.annotations.BaseResourceLocation;
import com.google.jstestdriver.annotations.BrowserTimeout;
import com.google.jstestdriver.annotations.Port;
import com.google.jstestdriver.config.ExecutionType;
import com.google.jstestdriver.hooks.FileInfoScheme;
import com.google.jstestdriver.model.HandlerPathPrefix;
import com.google.jstestdriver.requesthandlers.HttpMethod;
import com.google.jstestdriver.requesthandlers.RequestHandler;
import com.google.jstestdriver.requesthandlers.RequestHandlersModule;
import com.google.jstestdriver.server.JstdTestCaseStore;
import com.google.jstestdriver.server.gateway.SimpleServletConfig;
import com.google.jstestdriver.server.handlers.pages.BrowserControlledRunnerPage;
import com.google.jstestdriver.server.handlers.pages.ConsolePage;
import com.google.jstestdriver.server.handlers.pages.HeartbeatPage;
import com.google.jstestdriver.server.handlers.pages.Page;
import com.google.jstestdriver.server.handlers.pages.PageType;
import com.google.jstestdriver.server.handlers.pages.RunnerPage;
import com.google.jstestdriver.server.handlers.pages.SlavePageRequest;
import com.google.jstestdriver.server.handlers.pages.StandaloneRunnerPage;
import com.google.jstestdriver.servlet.fileset.BrowserFileCheck;
import com.google.jstestdriver.servlet.fileset.DeltaUpload;
import com.google.jstestdriver.servlet.fileset.FileSetRequestHandler;
import com.google.jstestdriver.servlet.fileset.ListTestCases;
import com.google.jstestdriver.servlet.fileset.TestCaseUpload;
import com.google.jstestdriver.util.ParameterParser;
/**
* Defines {@link RequestHandler} bindings for the JSTD server.
*
* @author rdionne@google.com (Robert Dionne)
*/
public class JstdHandlersModule extends RequestHandlersModule {
private static final String PAGE = "page";
private static final String MODE = "mode";
private static final String ID = "id";
private static final String TIMEOUT = "timeout";
private static final String JSTD = "jstd";
private final CapturedBrowsers capturedBrowsers;
private final JstdTestCaseStore testCaseStore;
private final long browserTimeout;
private final HandlerPathPrefix handlerPrefix;
private final Set<FileInfoScheme> schemes;
private final ExecutionType executionType;
private final Boolean debug;
/**
* TODO(rdionne): Refactor so we don't depend upon manually instantiated
* classes from other object graphs.
* @param handlerPrefix TODO
* @param schemes
* @param debug
*/
public JstdHandlersModule(
CapturedBrowsers capturedBrowsers,
JstdTestCaseStore testCaseStore,
long browserTimeout,
HandlerPathPrefix handlerPrefix,
Set<FileInfoScheme> schemes,
ExecutionType executionType,
Boolean debug) {
super();
this.capturedBrowsers = capturedBrowsers;
this.testCaseStore = testCaseStore;
this.browserTimeout = browserTimeout;
this.handlerPrefix = handlerPrefix;
this.schemes = schemes;
this.executionType = executionType;
this.debug = debug;
}
@Override
protected void configureHandlers() {
// Handler bindings in alphabetical order
serve( GET, handlerPrefix.prefixPath("/"), HomeHandler.class);
serve(POST, handlerPrefix.prefixPath("/cache"), FileCacheHandler.class);
serve( GET, handlerPrefix.prefixPath("/capture"), CaptureHandler.class);
serve( GET, handlerPrefix.prefixPath("/capture/*"), CaptureHandler.class);
serve( GET, handlerPrefix.prefixPath("/cmd"), CommandGetHandler.class);
serve(POST, handlerPrefix.prefixPath("/cmd"), CommandPostHandler.class);
serve( GET, handlerPrefix.prefixPath("/favicon.ico"), FaviconHandler.class);
serve( GET, handlerPrefix.prefixPath("/fileSet"), FileSetGetHandler.class);
serve(POST, handlerPrefix.prefixPath("/fileSet"), FileSetPostHandler.class);
for (HttpMethod method : HttpMethod.values()) {
serve(method, handlerPrefix.prefixPath("/forward/*"), ForwardingHandler.class);
}
serve( GET, handlerPrefix.prefixPath("/heartbeat"), HeartbeatGetHandler.class);
serve(POST, handlerPrefix.prefixPath("/heartbeat"), HeartbeatPostHandler.class);
serve( GET, handlerPrefix.prefixPath("/proxy", JSTD), GatewayConfigurationHandler.class);
serve(POST, handlerPrefix.prefixPath("/proxy", JSTD), GatewayConfigurationHandler.class);
serve( GET, handlerPrefix.prefixPath("/gateway", JSTD), GatewayConfigurationHandler.class);
serve(POST, handlerPrefix.prefixPath("/gateway", JSTD), GatewayConfigurationHandler.class);
serve( GET, handlerPrefix.prefixPath("/hello"), HelloHandler.class);
serve(POST, handlerPrefix.prefixPath("/log"), BrowserLoggingHandler.class);
serve(POST, handlerPrefix.prefixPath("/query/*"), BrowserQueryResponseHandler.class);
serve( GET, handlerPrefix.prefixPath("/runner/*"), StandaloneRunnerHandler.class);
serve( GET, handlerPrefix.prefixPath("/slave/*"), SlaveResourceHandler.class);
if (executionType == ExecutionType.STANDALONE) {
serve( GET, handlerPrefix.prefixPath("/test/*"), CachingTestResourceHandler.class);
} else {
serve( GET, handlerPrefix.prefixPath("/test/*"), NonCachingTestResourceHandler.class);
}
serve( GET, handlerPrefix.prefixPath("/quit"), QuitHandler.class);
serve( GET, handlerPrefix.prefixPath("/quit/*"), QuitHandler.class);
serve( GET, handlerPrefix.prefixPath("/static/*"), StaticResourceHandler.class);
serve( GET, handlerPrefix.prefixPath("/bcr"), BrowserControlledRunnerHandler.class);
serve( GET, handlerPrefix.prefixPath("/bcr/*"), BrowserControlledRunnerHandler.class);
// Constant bindings
bindConstant().annotatedWith(BaseResourceLocation.class)
.to(SlaveResourceService.RESOURCE_LOCATION);
bindConstant().annotatedWith(BrowserTimeout.class).to(browserTimeout);
// Miscellaneous bindings
bind(CapturedBrowsers.class).toInstance(capturedBrowsers);
bind(JstdTestCaseStore.class).toInstance(testCaseStore);
bind(new Key<ConcurrentMap<SlaveBrowser, List<String>>>() {})
.toInstance(new ConcurrentHashMap<SlaveBrowser, List<String>>());
bind(new Key<ConcurrentMap<SlaveBrowser, Thread>>() {})
.toInstance(new ConcurrentHashMap<SlaveBrowser, Thread>());
bind(new Key<Set<FileInfo>>() {}).toInstance(new HashSet<FileInfo>());
bind(HandlerPathPrefix.class).toInstance(handlerPrefix);
bind(Time.class).to(TimeImpl.class);
bind(Boolean.class).annotatedWith(Names.named("debug")).toInstance(debug);
bind(new TypeLiteral<Set<FileInfoScheme>>(){}).toInstance(schemes);
bind(ExecutionType.class).toInstance(executionType);
MapBinder<PageType, Page> pageBinder = newMapBinder(binder(), PageType.class, Page.class);
pageBinder.addBinding(CONSOLE).to(ConsolePage.class).in(RequestScoped.class);
pageBinder.addBinding(HEARTBEAT).to(HeartbeatPage.class).in(RequestScoped.class);
pageBinder.addBinding(RUNNER).to(RunnerPage.class).in(RequestScoped.class);
pageBinder.addBinding(STANDALONE_RUNNER).to(StandaloneRunnerPage.class).in(RequestScoped.class);
pageBinder.addBinding(VISUAL_STANDALONE_RUNNER).to(BrowserControlledRunnerPage.class).in(RequestScoped.class);
}
private static final Map<String, Integer> PARAMETERS = ImmutableMap.<String, Integer>builder()
.put(JSTD, 0)
.put(RUNNER_TYPE, 1)
.put(TIMEOUT, 1)
.put(ID, 1)
.put(MODE, 1)
.put(PAGE, 1)
.put(UPLOAD_SIZE, 1)
.put(LOAD_TYPE, 1)
.put(REFRESH, 1)
.put(TESTCASE_ID, 1)
.build();
private static final Set<String> BLACKLIST = ImmutableSet.<String>builder().build();
@Provides SlavePageRequest providePageRequest(
ParameterParser parser,
HttpServletRequest request,
HandlerPathPrefix prefix,
CapturedBrowsers browsers) {
return new SlavePageRequest(
parser.getParameterMap(PARAMETERS, BLACKLIST),
request,
prefix,
browsers);
}
@Provides @Singleton List<FileSetRequestHandler<?>> provideFileSetRequestHandlers(
BrowserFileCheck browserFileCheck, TestCaseUpload serverFileUpload, DeltaUpload deltaUpload,
ListTestCases listTestCases) {
return ImmutableList.of(browserFileCheck, serverFileUpload, deltaUpload, listTestCases);
}
@Provides @Singleton
ForwardingServlet provideForwardingServlet(@Port Integer port, ServletContext context)
throws ServletException {
ForwardingServlet servlet = new ForwardingServlet("localhost", port);
// Need to init the ForwardingServlet because it is a ProxyServlet.Transparent, a class
// that relies upon ServletContext#log().
servlet.init(new SimpleServletConfig(
"forward", context, ImmutableMap.<String, String>of()));
return servlet;
}
}