Java tutorial
/* * 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; } }