X-Git-Url: https://code.wpia.club/?p=gigi.git;a=blobdiff_plain;f=lib%2Fjetty%2Forg%2Feclipse%2Fjetty%2Fservlet%2FServletHolder.java;fp=lib%2Fjetty%2Forg%2Feclipse%2Fjetty%2Fservlet%2FServletHolder.java;h=1df08b33dc6d793e558a4bc736fe88d8dcad780b;hp=0000000000000000000000000000000000000000;hb=73ef54a38e3930a1a789cdc6b5fa23cdd4c9d086;hpb=515007c7c1351045420669d65b59c08fa46850f2 diff --git a/lib/jetty/org/eclipse/jetty/servlet/ServletHolder.java b/lib/jetty/org/eclipse/jetty/servlet/ServletHolder.java new file mode 100644 index 00000000..1df08b33 --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/servlet/ServletHolder.java @@ -0,0 +1,1124 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.servlet; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +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.SingleThreadModel; +import javax.servlet.UnavailableException; + +import org.eclipse.jetty.security.IdentityService; +import org.eclipse.jetty.security.RunAsToken; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.UserIdentity; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + + + + +/* --------------------------------------------------------------------- */ +/** Servlet Instance and Context Holder. + * Holds the name, params and some state of a javax.servlet.Servlet + * instance. It implements the ServletConfig interface. + * This class will organise the loading of the servlet when needed or + * requested. + * + * + */ +@ManagedObject("Servlet Holder") +public class ServletHolder extends Holder implements UserIdentity.Scope, Comparable +{ + private static final Logger LOG = Log.getLogger(ServletHolder.class); + + /* ---------------------------------------------------------------- */ + private int _initOrder = -1; + private boolean _initOnStartup=false; + private Map _roleMap; + private String _forcedPath; + private String _runAsRole; + private RunAsToken _runAsToken; + private IdentityService _identityService; + private ServletRegistration.Dynamic _registration; + + + private transient Servlet _servlet; + private transient Config _config; + private transient long _unavailable; + private transient boolean _enabled = true; + private transient UnavailableException _unavailableEx; + + public static final String JSP_GENERATED_PACKAGE_NAME = "org.eclipse.jetty.servlet.jspPackagePrefix"; + public static final Map NO_MAPPED_ROLES = Collections.emptyMap(); + + /* ---------------------------------------------------------------- */ + /** Constructor . + */ + public ServletHolder() + { + this(Source.EMBEDDED); + } + + /* ---------------------------------------------------------------- */ + /** Constructor . + */ + public ServletHolder(Holder.Source creator) + { + super(creator); + } + + /* ---------------------------------------------------------------- */ + /** Constructor for existing servlet. + */ + public ServletHolder(Servlet servlet) + { + this(Source.EMBEDDED); + setServlet(servlet); + } + + /* ---------------------------------------------------------------- */ + /** Constructor for servlet class. + */ + public ServletHolder(String name, Class servlet) + { + this(Source.EMBEDDED); + setName(name); + setHeldClass(servlet); + } + + /* ---------------------------------------------------------------- */ + /** Constructor for servlet class. + */ + public ServletHolder(String name, Servlet servlet) + { + this(Source.EMBEDDED); + setName(name); + setServlet(servlet); + } + + /* ---------------------------------------------------------------- */ + /** Constructor for servlet class. + */ + public ServletHolder(Class servlet) + { + this(Source.EMBEDDED); + setHeldClass(servlet); + } + + /* ---------------------------------------------------------------- */ + /** + * @return The unavailable exception or null if not unavailable + */ + public UnavailableException getUnavailableException() + { + return _unavailableEx; + } + + /* ------------------------------------------------------------ */ + public synchronized void setServlet(Servlet servlet) + { + if (servlet==null || servlet instanceof SingleThreadModel) + throw new IllegalArgumentException(); + + _extInstance=true; + _servlet=servlet; + setHeldClass(servlet.getClass()); + if (getName()==null) + setName(servlet.getClass().getName()+"-"+super.hashCode()); + } + + /* ------------------------------------------------------------ */ + @ManagedAttribute(value="initialization order", readonly=true) + public int getInitOrder() + { + return _initOrder; + } + + /* ------------------------------------------------------------ */ + /** Set the initialize order. + * Holders with order<0, are initialized on use. Those with + * order>=0 are initialized in increasing order when the handler + * is started. + */ + public void setInitOrder(int order) + { + _initOnStartup=order>=0; + _initOrder = order; + } + + /* ------------------------------------------------------------ */ + /** Comparitor by init order. + */ + @Override + public int compareTo(ServletHolder sh) + { + if (sh==this) + return 0; + if (sh._initOrder<_initOrder) + return 1; + if (sh._initOrder>_initOrder) + return -1; + + int c=(_className!=null && sh._className!=null)?_className.compareTo(sh._className):0; + if (c==0) + c=_name.compareTo(sh._name); + return c; + } + + /* ------------------------------------------------------------ */ + public boolean equals(Object o) + { + return o instanceof ServletHolder && compareTo((ServletHolder)o)==0; + } + + /* ------------------------------------------------------------ */ + public int hashCode() + { + return _name==null?System.identityHashCode(this):_name.hashCode(); + } + + /* ------------------------------------------------------------ */ + /** Link a user role. + * Translate the role name used by a servlet, to the link name + * used by the container. + * @param name The role name as used by the servlet + * @param link The role name as used by the container. + */ + public synchronized void setUserRoleLink(String name,String link) + { + if (_roleMap==null) + _roleMap=new HashMap(); + _roleMap.put(name,link); + } + + /* ------------------------------------------------------------ */ + /** get a user role link. + * @param name The name of the role + * @return The name as translated by the link. If no link exists, + * the name is returned. + */ + public String getUserRoleLink(String name) + { + if (_roleMap==null) + return name; + String link= _roleMap.get(name); + return (link==null)?name:link; + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the forcedPath. + */ + @ManagedAttribute(value="forced servlet path", readonly=true) + public String getForcedPath() + { + return _forcedPath; + } + + /* ------------------------------------------------------------ */ + /** + * @param forcedPath The forcedPath to set. + */ + public void setForcedPath(String forcedPath) + { + _forcedPath = forcedPath; + } + + public boolean isEnabled() + { + return _enabled; + } + + + public void setEnabled(boolean enabled) + { + _enabled = enabled; + } + + + /* ------------------------------------------------------------ */ + public void doStart() + throws Exception + { + _unavailable=0; + if (!_enabled) + return; + + // Handle JSP file forced paths + if (_forcedPath != null) + { + // Look for a precompiled JSP Servlet + String precompiled=getClassNameForJsp(_forcedPath); + LOG.debug("Checking for precompiled servlet {} for jsp {}", precompiled, _forcedPath); + ServletHolder jsp=getServletHandler().getServlet(precompiled); + if (jsp!=null) + { + LOG.debug("JSP file {} for {} mapped to Servlet {}",_forcedPath, getName(),jsp.getClassName()); + // set the className for this servlet to the precompiled one + setClassName(jsp.getClassName()); + } + else + { + if (getClassName() == null) + { + // Look for normal JSP servlet + jsp=getServletHandler().getServlet("jsp"); + if (jsp!=null) + { + LOG.debug("JSP file {} for {} mapped to Servlet {}",_forcedPath, getName(),jsp.getClassName()); + setClassName(jsp.getClassName()); + //copy jsp init params that don't exist for this servlet + for (Map.Entry entry:jsp.getInitParameters().entrySet()) + { + if (!_initParams.containsKey(entry.getKey())) + setInitParameter(entry.getKey(), entry.getValue()); + } + //jsp specific: set up the jsp-file on the JspServlet so it can precompile iff load-on-startup is >=0 + if (_initOnStartup) + setInitParameter("jspFile", _forcedPath); + } + } + } + } + + + //check servlet has a class (ie is not a preliminary registration). If preliminary, fail startup. + try + { + super.doStart(); + } + catch (UnavailableException ue) + { + makeUnavailable(ue); + if (_servletHandler.isStartWithUnavailable()) + { + LOG.ignore(ue); + return; + } + else + throw ue; + } + + + //servlet is not an instance of javax.servlet.Servlet + try + { + checkServletType(); + } + catch (UnavailableException ue) + { + makeUnavailable(ue); + if (_servletHandler.isStartWithUnavailable()) + { + LOG.ignore(ue); + return; + } + else + throw ue; + } + + //check if we need to forcibly set load-on-startup + checkInitOnStartup(); + + _identityService = _servletHandler.getIdentityService(); + if (_identityService!=null && _runAsRole!=null) + _runAsToken=_identityService.newRunAsToken(_runAsRole); + + _config=new Config(); + + if (_class!=null && javax.servlet.SingleThreadModel.class.isAssignableFrom(_class)) + _servlet = new SingleThreadedWrapper(); + + } + + + /* ------------------------------------------------------------ */ + @Override + public void initialize () + throws Exception + { + super.initialize(); + if (_extInstance || _initOnStartup) + { + try + { + initServlet(); + } + catch(Exception e) + { + if (_servletHandler.isStartWithUnavailable()) + LOG.ignore(e); + else + throw e; + } + } + } + + + /* ------------------------------------------------------------ */ + public void doStop() + throws Exception + { + Object old_run_as = null; + if (_servlet!=null) + { + try + { + if (_identityService!=null) + old_run_as=_identityService.setRunAs(_identityService.getSystemUserIdentity(),_runAsToken); + + destroyInstance(_servlet); + } + catch (Exception e) + { + LOG.warn(e); + } + finally + { + if (_identityService!=null) + _identityService.unsetRunAs(old_run_as); + } + } + + if (!_extInstance) + _servlet=null; + + _config=null; + } + + /* ------------------------------------------------------------ */ + @Override + public void destroyInstance (Object o) + throws Exception + { + if (o==null) + return; + Servlet servlet = ((Servlet)o); + getServletHandler().destroyServlet(servlet); + servlet.destroy(); + } + + /* ------------------------------------------------------------ */ + /** Get the servlet. + * @return The servlet + */ + public synchronized Servlet getServlet() + throws ServletException + { + // Handle previous unavailability + if (_unavailable!=0) + { + if (_unavailable<0 || _unavailable>0 && System.currentTimeMillis()<_unavailable) + throw _unavailableEx; + _unavailable=0; + _unavailableEx=null; + } + + if (_servlet==null) + initServlet(); + return _servlet; + } + + /* ------------------------------------------------------------ */ + /** Get the servlet instance (no initialization done). + * @return The servlet or null + */ + public Servlet getServletInstance() + { + return _servlet; + } + + /* ------------------------------------------------------------ */ + /** + * Check to ensure class of servlet is acceptable. + * @throws UnavailableException + */ + public void checkServletType () + throws UnavailableException + { + if (_class==null || !javax.servlet.Servlet.class.isAssignableFrom(_class)) + { + throw new UnavailableException("Servlet "+_class+" is not a javax.servlet.Servlet"); + } + } + + /* ------------------------------------------------------------ */ + /** + * @return true if the holder is started and is not unavailable + */ + public boolean isAvailable() + { + if (isStarted()&& _unavailable==0) + return true; + try + { + getServlet(); + } + catch(Exception e) + { + LOG.ignore(e); + } + + return isStarted()&& _unavailable==0; + } + + /* ------------------------------------------------------------ */ + /** + * Check if there is a javax.servlet.annotation.ServletSecurity + * annotation on the servlet class. If there is, then we force + * it to be loaded on startup, because all of the security + * constraints must be calculated as the container starts. + * + */ + private void checkInitOnStartup() + { + if (_class==null) + return; + + if ((_class.getAnnotation(javax.servlet.annotation.ServletSecurity.class) != null) && !_initOnStartup) + setInitOrder(Integer.MAX_VALUE); + } + + /* ------------------------------------------------------------ */ + private void makeUnavailable(UnavailableException e) + { + if (_unavailableEx==e && _unavailable!=0) + return; + + _servletHandler.getServletContext().log("unavailable",e); + + _unavailableEx=e; + _unavailable=-1; + if (e.isPermanent()) + _unavailable=-1; + else + { + if (_unavailableEx.getUnavailableSeconds()>0) + _unavailable=System.currentTimeMillis()+1000*_unavailableEx.getUnavailableSeconds(); + else + _unavailable=System.currentTimeMillis()+5000; // TODO configure + } + } + + /* ------------------------------------------------------------ */ + + private void makeUnavailable(final Throwable e) + { + if (e instanceof UnavailableException) + makeUnavailable((UnavailableException)e); + else + { + ServletContext ctx = _servletHandler.getServletContext(); + if (ctx==null) + LOG.info("unavailable",e); + else + ctx.log("unavailable",e); + _unavailableEx=new UnavailableException(String.valueOf(e),-1) + { + { + initCause(e); + } + }; + _unavailable=-1; + } + } + + /* ------------------------------------------------------------ */ + private void initServlet() + throws ServletException + { + Object old_run_as = null; + try + { + if (_servlet==null) + _servlet=newInstance(); + if (_config==null) + _config=new Config(); + + + + // Handle run as + if (_identityService!=null) + { + old_run_as=_identityService.setRunAs(_identityService.getSystemUserIdentity(),_runAsToken); + } + + // Handle configuring servlets that implement org.apache.jasper.servlet.JspServlet + if (isJspServlet()) + { + initJspServlet(); + } + + initMultiPart(); + + LOG.debug("Filter.init {}",_servlet); + _servlet.init(_config); + } + catch (UnavailableException e) + { + makeUnavailable(e); + _servlet=null; + _config=null; + throw e; + } + catch (ServletException e) + { + makeUnavailable(e.getCause()==null?e:e.getCause()); + _servlet=null; + _config=null; + throw e; + } + catch (Exception e) + { + makeUnavailable(e); + _servlet=null; + _config=null; + throw new ServletException(this.toString(),e); + } + finally + { + // pop run-as role + if (_identityService!=null) + _identityService.unsetRunAs(old_run_as); + } + } + + + /* ------------------------------------------------------------ */ + /** + * @throws Exception + */ + protected void initJspServlet () throws Exception + { + ContextHandler ch = ContextHandler.getContextHandler(getServletHandler().getServletContext()); + + /* Set the webapp's classpath for Jasper */ + ch.setAttribute("org.apache.catalina.jsp_classpath", ch.getClassPath()); + + /* Set the system classpath for Jasper */ + setInitParameter("com.sun.appserv.jsp.classpath", Loader.getClassPath(ch.getClassLoader().getParent())); + + /* Set up other classpath attribute */ + if ("?".equals(getInitParameter("classpath"))) + { + String classpath = ch.getClassPath(); + LOG.debug("classpath=" + classpath); + if (classpath != null) + setInitParameter("classpath", classpath); + } + } + + /* ------------------------------------------------------------ */ + /** + * Register a ServletRequestListener that will ensure tmp multipart + * files are deleted when the request goes out of scope. + * + * @throws Exception + */ + protected void initMultiPart () throws Exception + { + //if this servlet can handle multipart requests, ensure tmp files will be + //cleaned up correctly + if (((Registration)getRegistration()).getMultipartConfig() != null) + { + //Register a listener to delete tmp files that are created as a result of this + //servlet calling Request.getPart() or Request.getParts() + + ContextHandler ch = ContextHandler.getContextHandler(getServletHandler().getServletContext()); + ch.addEventListener(new Request.MultiPartCleanerListener()); + } + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.server.UserIdentity.Scope#getContextPath() + */ + @Override + public String getContextPath() + { + return _config.getServletContext().getContextPath(); + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.server.UserIdentity.Scope#getRoleRefMap() + */ + @Override + public Map getRoleRefMap() + { + return _roleMap; + } + + /* ------------------------------------------------------------ */ + @ManagedAttribute(value="role to run servlet as", readonly=true) + public String getRunAsRole() + { + return _runAsRole; + } + + /* ------------------------------------------------------------ */ + public void setRunAsRole(String role) + { + _runAsRole = role; + } + + /* ------------------------------------------------------------ */ + /** Service a request with this servlet. + */ + public void handle(Request baseRequest, + ServletRequest request, + ServletResponse response) + throws ServletException, + UnavailableException, + IOException + { + if (_class==null) + throw new UnavailableException("Servlet Not Initialized"); + + Servlet servlet=_servlet; + synchronized(this) + { + if (!isStarted()) + throw new UnavailableException("Servlet not initialized", -1); + if (_unavailable!=0 || (!_initOnStartup && servlet==null)) + servlet=getServlet(); + if (servlet==null) + throw new UnavailableException("Could not instantiate "+_class); + } + + // Service the request + boolean servlet_error=true; + Object old_run_as = null; + boolean suspendable = baseRequest.isAsyncSupported(); + try + { + // Handle aliased path + if (_forcedPath!=null) + // TODO complain about poor naming to the Jasper folks + request.setAttribute("org.apache.catalina.jsp_file",_forcedPath); + + // Handle run as + if (_identityService!=null) + old_run_as=_identityService.setRunAs(baseRequest.getResolvedUserIdentity(),_runAsToken); + + if (!isAsyncSupported()) + baseRequest.setAsyncSupported(false); + + MultipartConfigElement mpce = ((Registration)getRegistration()).getMultipartConfig(); + if (mpce != null) + request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, mpce); + + servlet.service(request,response); + servlet_error=false; + } + catch(UnavailableException e) + { + makeUnavailable(e); + throw _unavailableEx; + } + finally + { + baseRequest.setAsyncSupported(suspendable); + + // pop run-as role + if (_identityService!=null) + _identityService.unsetRunAs(old_run_as); + + // Handle error params. + if (servlet_error) + request.setAttribute("javax.servlet.error.servlet_name",getName()); + } + } + + + /* ------------------------------------------------------------ */ + private boolean isJspServlet () + { + if (_servlet == null) + return false; + + Class c = _servlet.getClass(); + + boolean result = false; + while (c != null && !result) + { + result = isJspServlet(c.getName()); + c = c.getSuperclass(); + } + + return result; + } + + + /* ------------------------------------------------------------ */ + private boolean isJspServlet (String classname) + { + if (classname == null) + return false; + return ("org.apache.jasper.servlet.JspServlet".equals(classname)); + } + + + /* ------------------------------------------------------------ */ + private String getNameOfJspClass (String jsp) + { + if (jsp == null) + return ""; + + int i = jsp.lastIndexOf('/') + 1; + jsp = jsp.substring(i); + try + { + Class jspUtil = Loader.loadClass(Holder.class, "org.apache.jasper.compiler.JspUtil"); + Method makeJavaIdentifier = jspUtil.getMethod("makeJavaIdentifier", String.class); + return (String)makeJavaIdentifier.invoke(null, jsp); + } + catch (Exception e) + { + String tmp = jsp.replace('.','_'); + LOG.warn("Unable to make identifier for jsp "+jsp +" trying "+tmp+" instead"); + if (LOG.isDebugEnabled()) + LOG.warn(e); + return tmp; + } + } + + + /* ------------------------------------------------------------ */ + private String getPackageOfJspClass (String jsp) + { + if (jsp == null) + return ""; + + int i = jsp.lastIndexOf('/'); + if (i <= 0) + return ""; + try + { + Class jspUtil = Loader.loadClass(Holder.class, "org.apache.jasper.compiler.JspUtil"); + Method makeJavaPackage = jspUtil.getMethod("makeJavaPackage", String.class); + return (String)makeJavaPackage.invoke(null, jsp.substring(0,i)); + } + catch (Exception e) + { + String tmp = jsp.substring(1).replace('/','.'); + LOG.warn("Unable to make package for jsp "+jsp +" trying "+tmp+" instead"); + if (LOG.isDebugEnabled()) + LOG.warn(e); + return tmp; + } + } + + + /* ------------------------------------------------------------ */ + private String getJspPackagePrefix () + { + String jspPackageName = (String)getServletHandler().getServletContext().getInitParameter(JSP_GENERATED_PACKAGE_NAME ); + if (jspPackageName == null) + jspPackageName = "org.apache.jsp"; + + return jspPackageName; + } + + + /* ------------------------------------------------------------ */ + private String getClassNameForJsp (String jsp) + { + if (jsp == null) + return null; + + return getJspPackagePrefix() + "." +getPackageOfJspClass(jsp) + "." + getNameOfJspClass(jsp); + } + + + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + protected class Config extends HolderConfig implements ServletConfig + { + /* -------------------------------------------------------- */ + @Override + public String getServletName() + { + return getName(); + } + + } + + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + public class Registration extends HolderRegistration implements ServletRegistration.Dynamic + { + protected MultipartConfigElement _multipartConfig; + + @Override + public Set addMapping(String... urlPatterns) + { + illegalStateIfContextStarted(); + Set clash=null; + for (String pattern : urlPatterns) + { + ServletMapping mapping = _servletHandler.getServletMapping(pattern); + if (mapping!=null) + { + //if the servlet mapping was from a default descriptor, then allow it to be overridden + if (!mapping.isDefault()) + { + if (clash==null) + clash=new HashSet(); + clash.add(pattern); + } + } + } + + //if there were any clashes amongst the urls, return them + if (clash!=null) + return clash; + + //otherwise apply all of them + ServletMapping mapping = new ServletMapping(); + mapping.setServletName(ServletHolder.this.getName()); + mapping.setPathSpecs(urlPatterns); + _servletHandler.addServletMapping(mapping); + + return Collections.emptySet(); + } + + @Override + public Collection getMappings() + { + ServletMapping[] mappings =_servletHandler.getServletMappings(); + List patterns=new ArrayList(); + if (mappings!=null) + { + for (ServletMapping mapping : mappings) + { + if (!mapping.getServletName().equals(getName())) + continue; + String[] specs=mapping.getPathSpecs(); + if (specs!=null && specs.length>0) + patterns.addAll(Arrays.asList(specs)); + } + } + return patterns; + } + + @Override + public String getRunAsRole() + { + return _runAsRole; + } + + @Override + public void setLoadOnStartup(int loadOnStartup) + { + illegalStateIfContextStarted(); + ServletHolder.this.setInitOrder(loadOnStartup); + } + + public int getInitOrder() + { + return ServletHolder.this.getInitOrder(); + } + + @Override + public void setMultipartConfig(MultipartConfigElement element) + { + _multipartConfig = element; + } + + public MultipartConfigElement getMultipartConfig() + { + return _multipartConfig; + } + + @Override + public void setRunAsRole(String role) + { + _runAsRole = role; + } + + @Override + public Set setServletSecurity(ServletSecurityElement securityElement) + { + return _servletHandler.setServletSecurity(this, securityElement); + } + } + + public ServletRegistration.Dynamic getRegistration() + { + if (_registration == null) + _registration = new Registration(); + return _registration; + } + + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + /* -------------------------------------------------------- */ + private class SingleThreadedWrapper implements Servlet + { + Stack _stack=new Stack(); + + @Override + public void destroy() + { + synchronized(this) + { + while(_stack.size()>0) + try { (_stack.pop()).destroy(); } catch (Exception e) { LOG.warn(e); } + } + } + + @Override + public ServletConfig getServletConfig() + { + return _config; + } + + @Override + public String getServletInfo() + { + return null; + } + + @Override + public void init(ServletConfig config) throws ServletException + { + synchronized(this) + { + if(_stack.size()==0) + { + try + { + Servlet s = newInstance(); + s.init(config); + _stack.push(s); + } + catch (ServletException e) + { + throw e; + } + catch (Exception e) + { + throw new ServletException(e); + } + } + } + } + + @Override + public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException + { + Servlet s; + synchronized(this) + { + if(_stack.size()>0) + s=(Servlet)_stack.pop(); + else + { + try + { + s = newInstance(); + s.init(_config); + } + catch (ServletException e) + { + throw e; + } + catch (Exception e) + { + throw new ServletException(e); + } + } + } + + try + { + s.service(req,res); + } + finally + { + synchronized(this) + { + _stack.push(s); + } + } + } + } + + /* ------------------------------------------------------------ */ + /** + * @return the newly created Servlet instance + * @throws ServletException + * @throws IllegalAccessException + * @throws InstantiationException + */ + protected Servlet newInstance() throws ServletException, IllegalAccessException, InstantiationException + { + try + { + ServletContext ctx = getServletHandler().getServletContext(); + if (ctx instanceof ServletContextHandler.Context) + return ((ServletContextHandler.Context)ctx).createServlet(getHeldClass()); + return getHeldClass().newInstance(); + } + catch (ServletException se) + { + Throwable cause = se.getRootCause(); + if (cause instanceof InstantiationException) + throw (InstantiationException)cause; + if (cause instanceof IllegalAccessException) + throw (IllegalAccessException)cause; + throw se; + } + } + + + /* ------------------------------------------------------------ */ + @Override + public String toString() + { + return String.format("%s@%x==%s,%d,%b",_name,hashCode(),_className,_initOrder,_servlet!=null); + } +}