package example.domain.web.nodriver;

import org.springframework.core.io.FileSystemResourceLoader;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletConfig;
import org.springframework.mock.web.MockServletContext;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class SpringDispatcherServlet {

    private static SpringDispatcherServlet instance;

    private final XmlWebApplicationContext applicationContext = new XmlWebApplicationContext();
    private final XmlWebApplicationContext servletContext = new XmlWebApplicationContext();
    private final DispatcherServlet servlet = new DispatcherServlet();

    public static SpringDispatcherServlet create() throws Exception {
        if (instance == null) {
            instance = new SpringDispatcherServlet();
            instance.registerShutdownHook();
            instance.startup();
        }
        return instance;
    }

    public MockHttpServletResponse process(MockHttpServletRequest request) throws Exception {
        MockHttpServletResponse response = new MockHttpServletResponse();
        servlet.service(withVersionFilterAttributes(request), response);
        return response;
    }

    private MockHttpServletRequest withVersionFilterAttributes(MockHttpServletRequest request) {
        request.setAttribute("servletPath", "");
        request.setAttribute("contextPath", "");
        request.setAttribute("version", "");
        return request;
    }

    private void startup() throws Exception {
        MockServletContext ctx = createServletContext();
        initApplicationContext(ctx);
        initServletContext(ctx);
        initServlet(ctx);
    }

    private MockServletContext createServletContext() {
        MockServletContext context = new MockServletContext("src/webapp", new FileSystemResourceLoader());
        context.addInitParameter("database.driver.class", "org.hsqldb.jdbcDriver");
        context.addInitParameter("database.driver.url", "jdbc:hsqldb:mem:webapp-template");
        context.addInitParameter("database.driver.username", "sa");
        context.addInitParameter("database.driver.password", "");
        context.addInitParameter("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
        context.addInitParameter("hibernate.cache.provider_class", "org.hibernate.cache.NoCacheProvider");
        context.addInitParameter("hibernate.hbm2ddl.auto", "create");
        return context;
    }

    private void initApplicationContext(MockServletContext ctx) {
        applicationContext.setConfigLocation("WEB-INF/applicationContext.xml");
        applicationContext.setServletContext(ctx);
        applicationContext.refresh();
    }

    private void initServletContext(MockServletContext ctx) {
        servletContext.setConfigLocation("/WEB-INF/spring-servlet.xml");
        servletContext.setParent(applicationContext);
        servletContext.setServletContext(ctx);
        servletContext.refresh();
    }

    private void initServlet(MockServletContext ctx) throws Exception {
        String contextName = getClass().getName() + ".CONTEXT";
        ctx.setAttribute(contextName, servletContext);

        servlet.setContextAttribute(contextName);
        servlet.init(new MockServletConfig(ctx, "test"));
    }

    private void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            public void run() {
                shutdown();
            }
        }));
    }

    private void shutdown() {
        try {
            servlet.destroy();
        } catch (Exception e) {
            // ignore
        }
        try {
            servletContext.destroy();
        } catch (Exception e) {
            // ignore
        }
        try {
            applicationContext.destroy();
        } catch (Exception e) {
            // ignore
        }
    }
}

@@ -2720,16 +2720,17 @@
 cation(%22
+/
 WEB-INF/

fix bad path name to /WEB-INF