com.xemantic.tadedon.guice.servlet.mock.FakeServletContainer.java Source code

Java tutorial

Introduction

Here is the source code for com.xemantic.tadedon.guice.servlet.mock.FakeServletContainer.java

Source

/*
 * Copyright 2010 Xemantic
 *
 * 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.xemantic.tadedon.guice.servlet.mock;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicLong;

import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.mock.web.MockFilterConfig;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.mock.web.MockServletContext;

import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Singleton;
import com.google.inject.servlet.GuiceFilter;
import com.google.inject.servlet.GuiceServletContextListener;
import com.google.inject.servlet.SessionScoped;

/**
 * Servlet container representation which does not
 * involve any HTTP stack.
 * <p>
 * Note: this class is configured using {@link FakeServletContainerModule}.
 * <p>
 * This class keeps single instance of {@link GuiceFilter}
 * and {@link GuiceServletContextListener}. This utility is
 * intended as unit testing support for the code based on
 * <a href="http://code.google.com/p/google-guice/wiki/ServletModule">guice-servlet</a>
 * library.
 * <p>
 * Typical usage in test class (junit):
 * <pre>
 * public class MyServletTest {
 * 
 *     private static FakeServletContainer servletContainer;
 * 
 *     {@literal @BeforeClass}
 *     public static void startServletContainer() throws ServletException {
 *         Injector injector = Guice.createInjector(
 *                 new FakeServletContainerModule(),
 *                 new ServletModule() {
 *                     {@literal @Override}
 *                     protected void configureServlets() {
 *                         serve("/MyServlet").with(MyServlet.class);
 *                     }
 *                 });
 *         servletContainer = injector.getInstance(FakeServletContainer.class);
 *         servletContainer.start();
 *     }
 * 
 *     {@literal @Test}
 *     public void shouldInvokeMyServlet() throws IOException, ServletException {
 *         // given
 *         MockHttpServletRequest request = servletContainer.newRequest("GET", "/MyServlet");
 *         MockHttpServletResponse response = new MockHttpServletResponse();
 * 
 *         // when
 *         servletContainer.service(request, response);
 * 
 *         // then
 *         // list of expectation ...
 *         // e.g. assertThat(response.getContentAsString(), is("My response"));
 *     }
 * 
 *     {@literal @AfterClass}
 *     public static void stopServletContainer() {
 *         if (servletContainer != null) {
 *             servletContainer.stop();
 *         }
 *     }
 * }
 * </pre>
 * Created on Jul 2, 2010
 *
 * @author hshsce
 * @see FakeServletContainerModule
 * @see ServletInterceptionModule
 */
@Singleton
public class FakeServletContainer {

    private final Injector m_injector;

    private final GuiceFilter m_filter;

    private final GuiceServletContextListener m_listener;

    private final AtomicLong m_sessionIdProvider = new AtomicLong(0);

    private ServletContext m_context;

    private HttpSession m_session;

    /**
     * Creates servlet container instance.
     *
     * @param filter the guice filter.
     * @param listener the listener instance.
     */
    @Inject
    public FakeServletContainer(Injector injector, GuiceFilter filter, GuiceServletContextListener listener) {

        m_injector = injector;
        m_filter = filter;
        m_listener = listener;
    }

    /**
     * Starts the container with {@link MockServletContext}.
     *
     * @throws ServletException if {@link GuiceFilter} cannot be initialized.
     * @see #start(ServletContext)
     */
    public void start() throws ServletException {
        start(new MockServletContext());
    }

    /**
     * Starts the container with using given {@code servletContext}.
     *
     * @param context the servlet context.
     * @throws ServletException if {@link GuiceFilter} cannot be initialized.
     * @see #start()
     */
    public void start(ServletContext context) throws ServletException {
        m_session = new MockHttpSession();
        m_context = context;
        MockFilterConfig config = new MockFilterConfig(m_context);
        m_filter.init(config);
        m_listener.contextInitialized(new ServletContextEvent(m_context));
    }

    /**
     * Stops the container.
     */
    public void stop() {
        m_filter.destroy();
        m_listener.contextDestroyed(new ServletContextEvent(m_context));
    }

    public void service(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        if (request instanceof MockHttpServletRequest) {
            MockHttpServletRequest mockRequest = (MockHttpServletRequest) request;
            mockRequest.setServletPath(mockRequest.getRequestURI());
        }
        m_filter.doFilter(request, response, new org.springframework.mock.web.MockFilterChain());
    }

    /**
     * Returns instance provided by call to {@link Injector#getInstance(Class)}, but
     * if it where returned to the servlet handling the request. Useful for initializing
     * {@link SessionScoped} components. 
     *
     * @throws ServletException 
     * @throws IOException 
     */
    @SuppressWarnings("unchecked")
    public <T> T getInstance(final Class<T> type) throws IOException, ServletException {
        MockFilterChain chain = new MockFilterChain() {
            @Override
            protected Object invoke() throws Throwable {
                return m_injector.getInstance(type);
            }
        };
        m_filter.doFilter(newRequest(), new MockHttpServletResponse(), chain);
        return (T) chain.getResult();
    }

    /**
      * Returns instance provided by call to {@link Injector#getInstance(Class)}, but
      * if it where returned to the servlet handling the request. Useful for initializing
      * {@link SessionScoped} components. 
      *
      * @throws ServletException 
      * @throws IOException 
      */
    @SuppressWarnings("unchecked")
    public <T> T getInstance(final Key<T> key) throws IOException, ServletException {
        MockFilterChain chain = new MockFilterChain() {
            @Override
            protected Object invoke() throws Throwable {
                return m_injector.getInstance(key);
            }
        };
        m_filter.doFilter(newRequest(), new MockHttpServletResponse(), chain);
        return (T) chain.getResult();
    }

    /**
     * Returns container's servlet context.
     *
     * @return the servlet context
     */
    public ServletContext getContext() {
        return m_context;
    }

    public MockHttpSession newSession() {
        MockHttpSession session = new MockHttpSession(m_context,
                String.valueOf(m_sessionIdProvider.getAndIncrement()));
        m_session = session;
        return session;
    }

    public MockHttpSession newSession(String sessionId) {
        MockHttpSession session = new MockHttpSession(m_context, sessionId);
        m_session = session;
        return session;
    }

    public void setSession(HttpSession session) {
        m_session = session;
    }

    public HttpSession getSession() {
        return m_session;
    }

    public MockHttpServletRequest newRequest() {
        MockHttpServletRequest request = new MockHttpServletRequest(m_context);
        request.setSession(m_session);
        return request;
    }

    public MockHttpServletRequest newRequest(String method, String requestUri) {
        MockHttpServletRequest request = new MockHttpServletRequest(m_context, method, requestUri);
        request.setSession(m_session);
        return request;
    }

}