org.ireland.jnetty.dispatch.servlet.ServletConfigImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.ireland.jnetty.dispatch.servlet.ServletConfigImpl.java

Source

/*
 * Copyright (c) 1998-2012 Caucho Technology -- all rights reserved
 *
 * This file is part of Resin(R) Open Source
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Resin Open Source is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Resin Open Source is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Resin Open Source; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Scott Ferguson
 */

package org.ireland.jnetty.dispatch.servlet;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;

import javax.servlet.FilterChain;
import javax.servlet.MultipartConfigElement;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletSecurityElement;
import javax.servlet.UnavailableException;
import javax.servlet.annotation.MultipartConfig;

import org.ireland.jnetty.dispatch.filterchain.ServletFilterChain;
import org.ireland.jnetty.webapp.WebApp;
import org.springframework.util.Assert;

/**
 * Configuration for a servlet.
 * 
 * Servlet?(web.xml<servlet>)
 * 
<servlet>
       
  <description>This is FirstServlet</description>
      
  <display-name>FirstServlet</display-name>
      
  <servlet-name>FirstServlet</servlet-name>
  <servlet-class>myServlet.FirstServlet</servlet-class>
      
  <init-param>
     <param-name>abc</param-name>
     <param-value>12</param-value>
  </init-param>
      
  <init-param>
     <param-name>addsf</param-name>
     <param-value>155</param-value>
  </init-param>
      
  <load-on-startup>2</load-on-startup>
      
  <async-supported>true</async-supported>
      
   </servlet>
 * 
 */
public class ServletConfigImpl implements ServletConfig, ServletRegistration.Dynamic {
    protected static final Log log = LogFactory.getLog(ServletConfigImpl.class.getName());
    private static final boolean debug = log.isDebugEnabled();

    private final WebApp _webApp;

    private final ServletContext _servletContext;

    private final ServletManager _servletManager;

    private final ServletMapper _servletMapper;

    // Servlet?
    private String _location;

    private String _servletName;
    private String _servletNameDefault;

    private String _servletClassName;
    private Class<? extends Servlet> _servletClass;
    private String _displayName;

    private int _loadOnStartup = Integer.MIN_VALUE;

    private boolean _asyncSupported;

    private HashMap<String, String> _initParams = new HashMap<String, String>();

    // used for params defined prior to applying fragments.
    private Set<String> _paramNames = new HashSet<String>();

    private MultipartConfigElement _multipartConfigElement;

    //Servlet(?)
    private Servlet _servlet;

    //ServletServletFilterChain
    private FilterChain _servletChain;

    /**
     * Creates a new servlet configuration object.
     */
    public ServletConfigImpl(WebApp _webApp, ServletContext _servletContext, ServletManager _servletManager,
            ServletMapper _servletMapper) {
        Assert.notNull(_webApp);
        Assert.notNull(_servletContext);
        Assert.notNull(_servletManager);
        Assert.notNull(_servletMapper);

        this._webApp = _webApp;
        this._servletContext = _servletContext;
        this._servletManager = _servletManager;
        this._servletMapper = _servletMapper;
    }

    protected void copyFrom(ServletConfigImpl source) {
        _initParams.putAll(source._initParams);
    }

    public WebApp getWebApp() {
        return _webApp;
    }

    /**
     * Sets the config location.
     */
    public void setConfigUriLocation(String location, int line) {
        _location = location + ":" + line + ": ";
    }

    /**
     * Sets the servlet name.
     */
    public void setServletName(String name) {
        _servletName = name;
    }

    /**
     * Gets the servlet name.
     */
    @Override
    public String getServletName() {
        return _servletName;
    }

    @Override
    public String getName() {
        return getServletName();
    }

    @Override
    public String getClassName() {
        return _servletClassName;
    }

    /**
     * add??
     */
    @Override
    public boolean setInitParameter(String name, String value) {
        if (_initParams.containsKey(name))
            return false;

        _initParams.put(name, value);

        return true;
    }

    @Override
    public void setMultipartConfig(MultipartConfigElement multipartConfig) {
        if (multipartConfig == null)
            throw new IllegalArgumentException();

        _multipartConfigElement = multipartConfig;
    }

    public MultipartConfigElement getMultipartConfig() {
        if (_multipartConfigElement == null) {
            Class<?> servletClass = null;

            try {
                servletClass = getServletClass();
            } catch (Exception e) {
                log.debug(e.toString(), e);
            }

            if (servletClass != null) {
                MultipartConfig config = (MultipartConfig) servletClass.getAnnotation(MultipartConfig.class);

                if (config != null)
                    _multipartConfigElement = new MultipartConfigElement(config);
            }
        }

        return _multipartConfigElement;
    }

    /**
     * Maps or exists if any of the patterns in urlPatterns already map to a different servlet
     * 
     * @param urlPatterns
     * @return a Set of patterns previously mapped to a different servlet
     */
    @Override
    public Set<String> addMapping(String... urlPatterns) {

        try {
            Set<String> conflictPattern = new HashSet<String>();

            // server/12t8 vs server/12uc
            for (String urlPattern : urlPatterns) {
                ServletMapping mapping = _servletMapper.getServletMapping(urlPattern);

                if (mapping == null) {
                    continue;
                }

                String servletName = mapping.getServletConfig().getServletName();

                if (!_servletName.equals(servletName) && servletName != null) //urlPattern?(?urlPatternServlet)
                {
                    if (debug) {
                        log.debug("programmatic addMapping for '" + urlPattern
                                + "' ignored because of existing servlet-mapping to '" + servletName + "'");
                    }

                    conflictPattern.add(urlPattern);
                }
            }

            if (conflictPattern.size() > 0) {
                return conflictPattern;
            }

            //ServletMappingServletContext
            ServletMapping mapping = _webApp.createNewServletMapping(this);

            for (String urlPattern : urlPatterns) {
                mapping.addURLPattern(urlPattern);
            }

            _webApp.addServletMapping(mapping);

            return Collections.unmodifiableSet(conflictPattern);
        } catch (ServletException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    @Override
    public Collection<String> getMappings() {
        Set<String> patterns = _servletMapper.getUrlPatterns(_servletName);

        if (patterns != null)
            return Collections.unmodifiableSet(new LinkedHashSet<String>(patterns));
        else
            return new LinkedHashSet<String>();
    }

    /**
     * ??
     */
    @Override
    public Set<String> setInitParameters(Map<String, String> initParameters) {

        Set<String> conflicting = new HashSet<String>();

        for (Map.Entry<String, String> param : initParameters.entrySet()) {
            if (_initParams.containsKey(param.getKey()))
                conflicting.add(param.getKey());
            else
                _initParams.put(param.getKey(), param.getValue());
        }

        return Collections.unmodifiableSet(conflicting);
    }

    public Map<String, String> getInitParameters() {
        return _initParams;
    }

    public void setAsyncSupported(boolean asyncSupported) {
        _asyncSupported = asyncSupported;
    }

    public boolean isAsyncSupported() {
        return _asyncSupported;
    }

    /**
     * Sets the servlet name default when not specified
     */
    public void setServletNameDefault(String name) {
        _servletNameDefault = name;
    }

    /**
     * Gets the servlet name default.
     */
    public String getServletNameDefault() {
        return _servletNameDefault;
    }

    /**
     * Gets the servlet name.
     */
    public String getServletClassName() {
        return _servletClassName;
    }

    /**
     * 
     * @return true:Servlet??
     */
    public boolean isServletConfig() {
        return _servletClassName != null;
    }

    /**
     * Sets the servlet class. Servlet Class 
     */
    public void setServletClass(String servletClassName) {
        _servletClassName = servletClassName;

        ClassLoader loader = _webApp.getClassLoader();

        try {
            _servletClass = (Class<? extends Servlet>) Class.forName(servletClassName, false, loader);

        } catch (ClassNotFoundException e) {
            log.debug(e.toString(), e);
        }
    }

    public void setServletClass(Class<? extends Servlet> servletClass) {
        if (servletClass == null) {
            throw new NullPointerException();
        }

        _servletClass = servletClass;
        _servletClassName = servletClass.getName();
    }

    /**
     * Gets the servlet class. ServletClass
     */
    public Class<? extends Servlet> getServletClass() {

        if (_servletClassName == null)
            return null;

        if (_servletClass == null) {
            try {
                ClassLoader loader = _webApp.getClassLoader();

                _servletClass = (Class<? extends Servlet>) Class.forName(calculateServletClassName(), false,
                        loader);
            } catch (Exception e) {
                error(_servletClassName
                        + " | is not a known servlet class.  Servlets belong in the classpath, for example WEB-INF/classes.",
                        e);
            }
        }

        return _servletClass;
    }

    protected String calculateServletClassName() {
        return getServletClassName();
    }

    public void setServlet(Servlet servlet) {
        _servlet = servlet;
    }

    /**
     * Sets an init-param
     */
    public void setInitParam(String param, String value) {
        _initParams.put(param, value);
    }

    /**
     * Gets the init params
     */
    public Map getInitParamMap() {
        return _initParams;
    }

    /**
     * Gets the init params
     */
    public String getInitParameter(String name) {
        return _initParams.get(name);
    }

    /**
     * Gets the init params
     */
    @Override
    public Enumeration<String> getInitParameterNames() {
        return Collections.enumeration(_initParams.keySet());
    }

    /**
     * Returns the servlet context.
     */
    public ServletContext getServletContext() {
        return _servletContext;
    }

    /**
     * Returns the servlet manager.
     */
    public ServletManager getServletManager() {
        return _servletManager;
    }

    /**
     * Sets the load-on-startup
     */
    public void setLoadOnStartup(int loadOnStartup) {
        _loadOnStartup = loadOnStartup;
    }

    /**
     * Gets the load-on-startup value.
     */
    public int getLoadOnStartup() {
        if (_loadOnStartup > Integer.MIN_VALUE)
            return _loadOnStartup;
        else
            return Integer.MIN_VALUE;
    }

    /**
     * Sets the display name
     */
    public void setDisplayName(String displayName) {
        _displayName = displayName;
    }

    /**
     * Gets the display name
     */
    public String getDisplayName() {
        return _displayName;
    }

    /**
     * Sets the description
     */
    public void setDescription(String description) {
    }

    /**
     * Returns the servlet.
     */
    public Servlet getServlet() {
        return _servlet;
    }

    public void merge(ServletConfigImpl config) {
        if (_loadOnStartup == Integer.MIN_VALUE)
            _loadOnStartup = config._loadOnStartup;

        if (!getClassName().equals(config.getClassName()))
            throw new RuntimeException("Illegal attempt to specify different servlet-class ["
                    + config.getClassName() + "] for servlet '" + _servletName + "'. Servlet '" + _servletName
                    + " has already been defined with servlet-class '" + _servletClassName
                    + "'. Consider using <absolute-ordering> to exclude conflicting web-fragment.");

        for (Map.Entry<String, String> param : config._initParams.entrySet()) {
            if (_paramNames.contains(param.getKey())) {
            } else if (!_initParams.containsKey(param.getKey()))
                _initParams.put(param.getKey(), param.getValue());
            else if (!_initParams.get(param.getKey()).equals(param.getValue())) {
                throw new RuntimeException("Illegal attempt to specify different param-value of ["
                        + param.getValue() + "] for parameter [" + param.getKey()
                        + "]. This error indicates that two web-fragments use different values. Consider defining the parameter in web.xml to override definitions in web-fragment.");
            }
        }
    }

    /**
     * Initialize the servlet config. ?Servlet?
     */
    public void init() throws ServletException {

        if (_servletName == null) {
            if (getServletNameDefault() != null)
                _servletName = getServletNameDefault();
            else
                setServletName(_servletClassName);
        }
    }

    /**
     * ?ServletClass?,?javax.servlet.Servlet?
     * 
     * @param requireClass
     * @throws ServletException
     */
    protected void validateClass(boolean requireClass) throws ServletException {

        if (_loadOnStartup >= 0)
            requireClass = true;

        if (_servletClassName == null) {
        } else {
            if (_servletClass == null) {
                try {
                    _servletClass = (Class<? extends Servlet>) Class.forName(_servletClassName, false,
                            _webApp.getClassLoader());
                } catch (ClassNotFoundException e) {
                    log.debug(e.toString(), e);
                }
            }

            if (_servletClass != null) {
            } else if (requireClass) {
                throw error(_servletClassName
                        + " | is not a known servlet class.  Servlets belong in the classpath, for example WEB-INF/classes.");
            } else {
                String location = _location != null ? _location : "";

                log.warn(location + _servletClassName
                        + " | is not a known servlet.  Servlets belong in the classpath, often in WEB-INF/classes.");
                return;
            }

            if (!Servlet.class.isAssignableFrom(_servletClass)) {
                throw error(_servletClassName
                        + " | must implement javax.servlet.Servlet  All servlets must implement the Servlet interface.");
            }

        }
    }

    /**
     * Checks the class constructor for the public-zero arg. Class??public
     */
    public void checkConstructor() throws ServletException {
        Constructor[] constructors = _servletClass.getDeclaredConstructors();

        Constructor zeroArg = null;
        for (int i = 0; i < constructors.length; i++) {
            if (constructors[i].getParameterTypes().length == 0) {
                zeroArg = constructors[i];
                break;
            }
        }

        if (zeroArg == null)
            throw error(_servletClassName
                    + " | must have a zero arg constructor.  Servlets must have public zero-arg constructors.\n"
                    + (constructors != null ? constructors[0] : null) + " is not a valid constructor.");

        if (!Modifier.isPublic(zeroArg.getModifiers()))
            throw error(zeroArg + " | must be public.  '" + _servletClassName
                    + "' must have a public, zero-arg constructor.");
    }

    public FilterChain createServletChain() throws ServletException {
        synchronized (this) {
            if (_servletChain == null)
                _servletChain = createServletChainImpl();

            return _servletChain; //Servlet?,ServletFilterChain??,??ServletFilterChain
        }
    }

    /**
     * 
     * 
     * @return
     * @throws ServletException
     */
    private FilterChain createServletChainImpl() throws ServletException {
        FilterChain servletChain = null;

        if (_servlet != null) {
            servletChain = new ServletFilterChain(this);

            return servletChain;
        }

        validateClass(true);

        Class<?> servletClass = getServletClass();

        if (servletClass == null) {
            throw new IllegalStateException("servlet class for '" + getServletName() + "' can't be null");
        } else {
            servletChain = new ServletFilterChain(this);
        }

        return servletChain;
    }

    /**
     * Instantiates a servlet given its configuration.
     * 
     * Servlet(?,?)
     * 
     * 1:Servlet?,Servlet,
     *   ?(javax.servlet.Servlet#init(ServletConfig config)
     * 
     * 2:?Servlet.
     * 
     * 
     * @return the initialized servlet.
     */
    public Servlet getInstance() throws ServletException {
        // server/102e
        if (_servlet != null)
            return _servlet;

        _servlet = createServletAndInit();

        return _servlet;
    }

    /*
     * 
     * 
     * Servlet,?
     * 
     * servlet.init(this);
     */
    private Servlet createServletAndInit() throws ServletException {

        Class<? extends Servlet> servletClass = getServletClass();

        Servlet servlet;

        if (servletClass == null)
            throw new ServletException("Null servlet class for " + _servletName);

        try {
            servlet = servletClass.newInstance();
        } catch (Exception e) {
            throw new ServletException(e);
        }

        // ?Servlet
        configureServlet(servlet);

        //?
        servlet.init(this);

        if (debug)
            log.debug("Servlet[" + _servletName + "] instantiated and inited");

        return servlet;
    }

    /**
     * Configure the servlet (everything that is done after instantiation but before servlet.init()
     */
    void configureServlet(Object servlet) {

    }

    /**
     * @see javax.servlet.Servlet#destroy()
     */
    public void destroyServlet() {
        Object servlet = _servlet;
        _servlet = null;

        if (servlet instanceof Servlet) {
            ((Servlet) servlet).destroy();
        }
    }

    /**
     * ?Servlet
     */
    public void close() {
        destroyServlet();
    }

    protected ServletException error(String msg) {
        ServletException e;

        if (_location != null)
            e = new ServletException(_location + msg);
        else
            e = new ServletException(msg);

        log.warn(e.getMessage());

        return e;
    }

    protected ServletException error(String msg, Throwable e) {
        ServletException e1;

        if (_location != null)
            e1 = new ServletException(_location + msg, e);
        else
            e1 = new ServletException(msg, e);

        log.warn(e1.getMessage());

        return e1;
    }

    protected RuntimeException error(Throwable e) {
        RuntimeException e1;

        if (_location != null)
            e1 = new RuntimeException(_location + e.getMessage(), e);
        else
            e1 = new RuntimeException(e);

        log.warn(e1.toString());

        return e1;
    }

    /**
     * Returns a printable representation of the servlet config object.
     */
    public String toString() {
        return getClass().getSimpleName() + "[name=" + _servletName + ",class=" + _servletClass + "]";
    }

    //unused-------------------------------------------------
    @Override
    public String getRunAsRole() {
        return null;
    }

    @Override
    public void setRunAsRole(String roleName) {
    }

    @Override
    public Set<String> setServletSecurity(ServletSecurityElement constraint) {
        return null;
    }

    public ServletMapper getServletMapper() {
        return _servletMapper;
    }

}