org.seasar.wicket.S2WicketFilter.java Source code

Java tutorial

Introduction

Here is the source code for org.seasar.wicket.S2WicketFilter.java

Source

/*-
 * Copyright 2011 TAKEUCHI Hideyuki (chimerast)
 *
 * 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 org.seasar.wicket;

import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.wicket.Application;
import org.apache.wicket.RuntimeConfigurationType;
import org.apache.wicket.application.ReloadingClassLoader;
import org.apache.wicket.protocol.http.ReloadingWicketFilter;
import org.apache.wicket.protocol.http.WebApplication;
import org.seasar.framework.container.ExternalContext;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.deployer.ComponentDeployerFactory;
import org.seasar.framework.container.deployer.ExternalComponentDeployerProvider;
import org.seasar.framework.container.external.servlet.HttpServletExternalContext;
import org.seasar.framework.container.external.servlet.HttpServletExternalContextComponentDefRegister;
import org.seasar.framework.container.factory.S2ContainerFactory;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;
import org.seasar.framework.container.filter.S2ContainerFilter;
import org.seasar.framework.container.util.SmartDeployUtil;
import org.seasar.framework.exception.EmptyRuntimeException;
import org.seasar.wicket.debug.S2DebugPage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * S2Container????WicketFilter
 * <p>
 * web.xml???????Wicket??S2Container??????????
 * WicketFilter??S2ContainerFilter??????????
 * </p>
 * <p>
 * Wicket?<b>development????</b>??????
 * </p>
 * <dl>
 * <dt>?(HotDeploy)</dt>
 * <dd>web.xml???reloadingClassPattern????????</dd>
 * <dt>?</dt>
 * <dd>?????????
 * ?????????????</dd>
 * </dl>
 * <h4>?</h4>
 * <dl>
 * <dt>applicationClassName</dt>
 * <dd>Wicket?WebApplication????</dd>
 * <dt>configuration</dt>
 * <dd>Wicket?deployment??????development?????
 * ?????development()????</dd>
 * <dt>debug</dt>
 * <dd>S2Container??????</dd>
 * <dt>reloadingClassPattern</dt>
 * <dd>Wicket??development???????
 * ?????????????","???
 * ??"*"??????????"-"??????
 * ???????????convention.dicon???rootPackageName???</dd>
 * <dl>
 * <h4>web.xml</h4>
 * 
 * <pre>
 * &lt;filter&gt;
 *   &lt;filter-name&gt;s2wicketfilter&lt;/filter-name&gt;
 *   &lt;filter-class&gt;org.seasar.wicket.S2WicketFilter&lt;/filter-class&gt;
 *   &lt;init-param&gt;
 *     &lt;!-- Wicket? --&gt;
 *     &lt;param-name&gt;applicationClassName&lt;/param-name&gt;
 *     &lt;param-value&gt;org.seasar.wicket.example.ExampleApplication&lt;/param-value&gt;
 *   &lt;/init-param&gt;
 *   &lt;init-param&gt;
 *     &lt;!-- Wicket???development --&gt;
 *     &lt;!-- development????? --&gt;
 *     &lt;param-name&gt;configuration&lt;/param-name&gt;
 *     &lt;param-value&gt;deployment&lt;/param-value&gt;
 *   &lt;/init-param&gt;
 *   &lt;init-param&gt;
 *     &lt;!-- S2Container??? --&gt;
 *     &lt;param-name&gt;debug&lt;/param-name&gt;
 *     &lt;param-value&gt;/debug&lt;/param-value&gt;
 *   &lt;/init-param&gt;
 *   &lt;init-param&gt;
 *     &lt;!-- ???development?? --&gt;
 *     &lt;param-name&gt;reloadingClassPattern&lt;/param-name&gt;
 *     &lt;param-value&gt;org.seasar.wicket.example.*&lt;/param-value&gt;
 *   &lt;/init-param&gt;
 * &lt;/filter&gt;
 * &lt;filter-mapping&gt;
 *   &lt;filter-name&gt;s2wicketfilter&lt;/filter-name&gt;
 *   &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
 * &lt;/filter-mapping&gt;
 * </pre>
 * 
 * @author TAKEUCHI Hideyuki (chimerast)
 */
public class S2WicketFilter extends ReloadingWicketFilter {
    protected final Logger logger = LoggerFactory.getLogger(getClass());

    // ?
    private static final String SESSION_LOADER = "s2wicket$loader";

    /** Wicket? */
    private String configuration;

    /** S2Container??dicon?(: app.dicon) */
    private String configPath;
    /** S2Container??URL */
    private String debug;
    /** Hot Deploy ??(Wicket?Matcher??) */
    private String reloadingClassPattern;
    /** ReloadingClassLoader????? */
    private boolean useReloadingClassLoader;

    /** ?(DEPLOYMENT, DEVELOPMENT) */
    private RuntimeConfigurationType applicationConfigType;
    /** ? */
    private String applicationEncoding;

    @Override
    public void init(final boolean isServlet, FilterConfig filterConfig) throws ServletException {
        try {
            initInternal(isServlet, filterConfig);
        } catch (RuntimeException e) {
            logger.error("[init] error on initializing filter.", e);
            throw e;
        } catch (Error e) {
            logger.error("[init] error on initializing filter.", e);
            throw e;
        } catch (ServletException e) {
            logger.error("[init] error on initializing filter.", e);
            throw e;
        }
    }

    private void initInternal(final boolean isServlet, FilterConfig filterConfig) throws ServletException {
        // ????????????
        destroy();

        // ???
        configuration = getInitParameter(filterConfig, "configuration", "development").toUpperCase();
        configPath = getInitParameter(filterConfig, "configPath", "app.dicon");
        debug = getInitParameter(filterConfig, "debug", null);
        reloadingClassPattern = getInitParameter(filterConfig, "reloadingClassPattern", null);
        useReloadingClassLoader = RuntimeConfigurationType.DEVELOPMENT.name().equalsIgnoreCase(configuration)
                && reloadingClassPattern != null;

        if (logger.isInfoEnabled()) {
            logger.info("[config] configuration='{}'", configuration);
            logger.info("[config] configPath='{}'", configPath);
            logger.info("[config] debug='{}'", debug);
            logger.info("[config] reloadingClassPattern='{}'", reloadingClassPattern);
        }

        if (RuntimeConfigurationType.DEVELOPMENT == RuntimeConfigurationType.valueOf(configuration)
                && reloadingClassPattern != null) {
            ReloadingClassLoader.getPatterns().clear();
            // ??????????
            // ???????????
            for (String classPattern : reloadingClassPattern.split(",")) {
                if (!classPattern.startsWith("-")) {
                    ReloadingClassLoader.includePattern(classPattern);
                } else {
                    ReloadingClassLoader.excludePattern(classPattern.substring(1));
                }
            }
            for (URL str : ReloadingClassLoader.getLocations()) {
                logger.info("[classpath] {}", str);
            }
            for (String str : ReloadingClassLoader.getPatterns()) {
                logger.info("[pattern] {}", str);
            }
        }

        ComponentDeployerFactory.setProvider(new ExternalComponentDeployerProvider());
        S2Container s2container = S2ContainerFactory.create(configPath, getClassLoader());
        s2container.setExternalContext(new HttpServletExternalContext());
        s2container.setExternalContextComponentDefRegister(new HttpServletExternalContextComponentDefRegister());
        s2container.getExternalContext().setApplication(filterConfig.getServletContext());
        s2container.init();
        SingletonS2ContainerFactory.setContainer(s2container);

        if (SmartDeployUtil.isHotdeployMode(SingletonS2ContainerFactory.getContainer())) {
            throw new ServletException("S2Wicket does not support HOT deploy mode.");
        }

        // Application???getHomePage()??????
        // ????????????

        super.init(isServlet, filterConfig);

        // ???WebApplication?????????
        WebApplication webApplication = (WebApplication) Application.get(filterConfig.getFilterName());
        webApplication.getComponentInstantiationListeners().add(new ComponentInjectionListener());
        applicationConfigType = webApplication.getConfigurationType();
        applicationEncoding = webApplication.getRequestCycleSettings().getResponseRequestEncoding();

        if (RuntimeConfigurationType.DEVELOPMENT == RuntimeConfigurationType.valueOf(configuration)) {
            webApplication.getFrameworkSettings()
                    .setSerializer(new ReloadingJavaSerializer(webApplication.getApplicationKey()));
            if (debug != null) {
                webApplication.mountPage(debug, S2DebugPage.class);
            }
        }
    }

    @Override
    public void destroy() {
        if (SingletonS2ContainerFactory.hasContainer()) {
            SingletonS2ContainerFactory.destroy();
        }
        super.destroy();
    }

    @Override
    protected ClassLoader getClassLoader() {
        if (useReloadingClassLoader) {
            return super.getClassLoader();
        } else {
            return Thread.currentThread().getContextClassLoader();
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        if (RuntimeConfigurationType.DEVELOPMENT == applicationConfigType) {
            if (request instanceof HttpServletRequest) {
                // ???????
                HttpSession session = ((HttpServletRequest) request).getSession();
                ClassLoader previousLoader = (ClassLoader) session.getAttribute(SESSION_LOADER);
                if (previousLoader != getClassLoader()) {
                    logger.info("[reload] invalidate old session attributes ...");
                    Enumeration<String> names = session.getAttributeNames();
                    while (names.hasMoreElements()) {
                        String name = names.nextElement();
                        Object obj = session.getAttribute(name);
                        ClassLoader objectLoader = obj != null ? obj.getClass().getClassLoader() : null;
                        if (previousLoader == null || objectLoader == previousLoader) {
                            session.removeAttribute(name);
                        }
                    }
                }
                session.setAttribute(SESSION_LOADER, getClassLoader());
            }
        }

        if (request.getCharacterEncoding() == null) {
            request.setCharacterEncoding(applicationEncoding);
        }

        // S2ContainerFilter?????
        S2Container container = SingletonS2ContainerFactory.getContainer();
        ExternalContext externalContext = container.getExternalContext();
        if (externalContext == null) {
            throw new EmptyRuntimeException("externalContext");
        }

        final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
        final Object originalRequest = externalContext.getRequest();
        final Object originalResponse = externalContext.getResponse();
        try {
            Thread.currentThread().setContextClassLoader(getClassLoader());
            externalContext.setRequest(request);
            externalContext.setResponse(response);
            super.doFilter(request, response, chain);
        } finally {
            externalContext.setRequest(originalRequest);
            externalContext.setResponse(originalResponse);
            Thread.currentThread().setContextClassLoader(originalClassLoader);
            invalidateSession(request);
        }
    }

    /*
     * ????????
     */
    private String getInitParameter(FilterConfig filterConfig, String key, String def) {
        String value = filterConfig.getInitParameter(key);
        return value != null ? value : def;
    }

    /*
     * ??#INVALIDATE_SESSION?Boolean#TRUE???????
     * HttpSession???
     */
    private void invalidateSession(final ServletRequest request) {
        final Object invalidateSession = request.getAttribute(S2ContainerFilter.INVALIDATE_SESSION);
        if (Boolean.TRUE.equals(invalidateSession)) {
            final HttpSession session = ((HttpServletRequest) request).getSession(false);
            if (session != null) {
                session.invalidate();
            }
        }
    }
}