org.eclipse.jetty.ee8.servlet.ServletContextHandler Maven / Gradle / Ivy
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.ee8.servlet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.ServletSecurityElement;
import javax.servlet.SessionCookieConfig;
import javax.servlet.SessionTrackingMode;
import javax.servlet.descriptor.JspConfigDescriptor;
import javax.servlet.descriptor.JspPropertyGroupDescriptor;
import javax.servlet.descriptor.TaglibDescriptor;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionIdListener;
import javax.servlet.http.HttpSessionListener;
import org.eclipse.jetty.ee8.nested.ContextHandler;
import org.eclipse.jetty.ee8.nested.Dispatcher;
import org.eclipse.jetty.ee8.nested.ErrorHandler;
import org.eclipse.jetty.ee8.nested.Handler;
import org.eclipse.jetty.ee8.nested.HandlerWrapper;
import org.eclipse.jetty.ee8.nested.SessionHandler;
import org.eclipse.jetty.ee8.security.ConstraintAware;
import org.eclipse.jetty.ee8.security.ConstraintMapping;
import org.eclipse.jetty.ee8.security.ConstraintSecurityHandler;
import org.eclipse.jetty.ee8.security.SecurityHandler;
import org.eclipse.jetty.server.Handler.Container;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.DeprecationWarning;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.LifeCycle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Servlet Context.
*
* This extension to the ContextHandler allows for
* simple construction of a context with ServletHandler and optionally
* session and security handlers, et.
*
* new ServletContext("/context",Context.SESSIONS|Context.NO_SECURITY);
*
*
* This class should have been called ServletContext, but this would have
* cause confusion with {@link ServletContext}.
*/
@ManagedObject("Servlet Context Handler")
public class ServletContextHandler extends ContextHandler {
private static final Logger LOG = LoggerFactory.getLogger(ServletContextHandler.class);
public static final int SESSIONS = 1;
public static final int SECURITY = 2;
public static final int NO_SESSIONS = 0;
public static final int NO_SECURITY = 0;
public static ServletContextHandler getServletContextHandler(ServletContext servletContext, String purpose) {
ContextHandler contextHandler = ContextHandler.getContextHandler(servletContext);
if (contextHandler == null)
throw new IllegalStateException("No Jetty ContextHandler, " + purpose + " unavailable");
if (!(contextHandler instanceof ServletContextHandler))
throw new IllegalStateException("No Jetty ServletContextHandler, " + purpose + " unavailable");
return (ServletContextHandler) contextHandler;
}
public static ServletContextHandler getServletContextHandler(ServletContext context) {
ContextHandler handler = getContextHandler(context);
if (handler == null)
return null;
if (handler instanceof ServletContextHandler)
return (ServletContextHandler) handler;
return null;
}
public interface ServletContainerInitializerCaller extends LifeCycle {
}
protected final DecoratedObjectFactory _objFactory;
protected Class extends SecurityHandler> _defaultSecurityHandlerClass = ConstraintSecurityHandler.class;
protected SessionHandler _sessionHandler;
protected SecurityHandler _securityHandler;
protected ServletHandler _servletHandler;
protected int _options;
protected JspConfigDescriptor _jspConfig;
private boolean _startListeners;
public ServletContextHandler() {
this(null, null, null, null, null);
}
public ServletContextHandler(int options) {
this(null, null, options);
}
public ServletContextHandler(Container parent, String contextPath) {
this(parent, contextPath, null, null, null, null);
}
public ServletContextHandler(Container parent, String contextPath, int options) {
this(parent, contextPath, null, null, null, null, options);
}
public ServletContextHandler(Container parent, String contextPath, boolean sessions, boolean security) {
this(parent, contextPath, (sessions ? SESSIONS : 0) | (security ? SECURITY : 0));
}
public ServletContextHandler(Container parent, SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler) {
this(parent, null, sessionHandler, securityHandler, servletHandler, errorHandler);
}
public ServletContextHandler(Container parent, String contextPath, SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler) {
this(parent, contextPath, sessionHandler, securityHandler, servletHandler, errorHandler, 0);
}
public ServletContextHandler(Container parent, String contextPath, SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler, int options) {
super(null, parent, contextPath);
_options = options;
_apiContext = new ServletAPIContext();
_sessionHandler = sessionHandler;
_securityHandler = securityHandler;
_servletHandler = servletHandler;
_objFactory = new DecoratedObjectFactory();
installBean(_objFactory, true);
// Link the handlers
relinkHandlers();
if (errorHandler != null)
setErrorHandler(errorHandler);
}
/**
* Add EventListener
*
* @param listener the listener to add
* @return true if the listener was added
* @see HttpSessionAttributeListener
* @see HttpSessionActivationListener
* @see HttpSessionBindingListener
* @see HttpSessionListener
* @see HttpSessionIdListener
* @see ContextHandler#addEventListener(EventListener)
*/
@Override
public boolean addEventListener(EventListener listener) {
if (super.addEventListener(listener)) {
if ((listener instanceof HttpSessionActivationListener) || (listener instanceof HttpSessionAttributeListener) || (listener instanceof HttpSessionBindingListener) || (listener instanceof HttpSessionListener) || (listener instanceof HttpSessionIdListener)) {
if (_sessionHandler != null)
_sessionHandler.addEventListener(listener);
}
return true;
}
return false;
}
private void doSetHandler(HandlerWrapper wrapper, Handler handler) {
if (wrapper == this)
super.setHandler(handler);
else
wrapper.setHandler(handler);
}
private void relinkHandlers() {
HandlerWrapper handler = this;
// link session handler
if (getSessionHandler() != null) {
while (!(handler.getHandler() instanceof SessionHandler) && !(handler.getHandler() instanceof SecurityHandler) && !(handler.getHandler() instanceof ServletHandler) && handler.getHandler() instanceof HandlerWrapper) {
handler = (HandlerWrapper) handler.getHandler();
}
if (handler.getHandler() != _sessionHandler)
doSetHandler(handler, _sessionHandler);
handler = _sessionHandler;
}
// link security handler
if (getSecurityHandler() != null) {
while (!(handler.getHandler() instanceof SecurityHandler) && !(handler.getHandler() instanceof ServletHandler) && handler.getHandler() instanceof HandlerWrapper) {
handler = (HandlerWrapper) handler.getHandler();
}
if (handler.getHandler() != _securityHandler)
doSetHandler(handler, _securityHandler);
handler = _securityHandler;
}
// link servlet handler
if (getServletHandler() != null) {
while (!(handler.getHandler() instanceof ServletHandler) && handler.getHandler() instanceof HandlerWrapper) {
handler = (HandlerWrapper) handler.getHandler();
}
if (handler.getHandler() != _servletHandler)
doSetHandler(handler, _servletHandler);
}
}
@Override
protected void doStart() throws Exception {
_objFactory.addDecorator(new DeprecationWarning());
getServletContext().setAttribute(DecoratedObjectFactory.ATTR, _objFactory);
super.doStart();
}
@Override
protected void doStop() throws Exception {
super.doStop();
_objFactory.clear();
getServletContext().removeAttribute(DecoratedObjectFactory.ATTR);
}
/**
* Get the defaultSecurityHandlerClass.
*
* @return the defaultSecurityHandlerClass
*/
public Class extends SecurityHandler> getDefaultSecurityHandlerClass() {
return _defaultSecurityHandlerClass;
}
/**
* Set the defaultSecurityHandlerClass.
*
* @param defaultSecurityHandlerClass the defaultSecurityHandlerClass to set
*/
public void setDefaultSecurityHandlerClass(Class extends SecurityHandler> defaultSecurityHandlerClass) {
_defaultSecurityHandlerClass = defaultSecurityHandlerClass;
}
protected SessionHandler newSessionHandler() {
return new SessionHandler();
}
protected SecurityHandler newSecurityHandler() {
try {
return getDefaultSecurityHandlerClass().getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
protected ServletHandler newServletHandler() {
return new ServletHandler();
}
/**
* Finish constructing handlers and link them together.
*/
@Override
protected void startContext() throws Exception {
for (ServletContainerInitializerCaller sci : getBeans(ServletContainerInitializerCaller.class)) {
if (sci.isStopped()) {
sci.start();
if (isAuto(sci))
manage(sci);
}
}
if (_servletHandler != null) {
//Ensure listener instances are created, added to ContextHandler
if (_servletHandler.getListeners() != null) {
for (ListenerHolder holder : _servletHandler.getListeners()) {
holder.start();
}
}
}
_startListeners = true;
super.startContext();
// OK to Initialize servlet handler now that all relevant object trees have been started
if (_servletHandler != null)
_servletHandler.initialize();
}
@Override
protected void stopContext() throws Exception {
_startListeners = false;
super.stopContext();
}
/**
* @return Returns the securityHandler.
*/
@ManagedAttribute(value = "context security handler", readonly = true)
public SecurityHandler getSecurityHandler() {
if (_securityHandler == null && (_options & SECURITY) != 0 && !isStarted())
_securityHandler = newSecurityHandler();
return _securityHandler;
}
/**
* @return Returns the servletHandler.
*/
@ManagedAttribute(value = "context servlet handler", readonly = true)
public ServletHandler getServletHandler() {
if (_servletHandler == null && !isStarted())
_servletHandler = newServletHandler();
return _servletHandler;
}
/**
* @return Returns the sessionHandler.
*/
@ManagedAttribute(value = "context session handler", readonly = true)
public SessionHandler getSessionHandler() {
if (_sessionHandler == null && (_options & SESSIONS) != 0 && !isStarted())
_sessionHandler = newSessionHandler();
return _sessionHandler;
}
/**
* Convenience method to add a servlet.
*
* @param className the servlet class name
* @param pathSpec the path spec to map servlet to
* @return the ServletHolder for the added servlet
*/
public ServletHolder addServlet(String className, String pathSpec) {
return getServletHandler().addServletWithMapping(className, pathSpec);
}
/**
* Convenience method to add a servlet.
*
* @param servlet the servlet class
* @param pathSpec the path spec to map servlet to
* @return the ServletHolder for the added servlet
*/
public ServletHolder addServlet(Class extends Servlet> servlet, String pathSpec) {
return getServletHandler().addServletWithMapping(servlet, pathSpec);
}
/**
* Convenience method to add a servlet.
*
* @param servlet the servlet holder
* @param pathSpec the path spec
*/
public void addServlet(ServletHolder servlet, String pathSpec) {
getServletHandler().addServletWithMapping(servlet, pathSpec);
}
/**
* Convenience method to add a filter
*
* @param holder the filter holder
* @param pathSpec the path spec
* @param dispatches the dispatcher types for this filter
*/
public void addFilter(FilterHolder holder, String pathSpec, EnumSet dispatches) {
getServletHandler().addFilterWithMapping(holder, pathSpec, dispatches);
}
/**
* Convenience method to add a filter
*
* @param filterClass the filter class
* @param pathSpec the path spec
* @param dispatches the dispatcher types for this filter
* @return the FilterHolder that was created
*/
public FilterHolder addFilter(Class extends Filter> filterClass, String pathSpec, EnumSet dispatches) {
return getServletHandler().addFilterWithMapping(filterClass, pathSpec, dispatches);
}
/**
* Convenience method to add a filter
*
* @param filterClass the filter class name
* @param pathSpec the path spec
* @param dispatches the dispatcher types for this filter
* @return the FilterHolder that was created
*/
public FilterHolder addFilter(String filterClass, String pathSpec, EnumSet dispatches) {
return getServletHandler().addFilterWithMapping(filterClass, pathSpec, dispatches);
}
/**
* Convenience method to programmatically add a {@link ServletContainerInitializer}.
* @param sci the ServletContainerInitializer to register.
* @return the ServletContainerInitializerHolder that was created
*/
public ServletContainerInitializerHolder addServletContainerInitializer(ServletContainerInitializer sci) {
if (!isStopped())
throw new IllegalStateException("ServletContainerInitializers should be added before starting");
ServletContainerInitializerHolder holder = new ServletContainerInitializerHolder(sci);
addServletContainerInitializer(holder);
return holder;
}
/**
* Convenience method to programmatically add a {@link ServletContainerInitializer}.
* @param sci the ServletContainerInitializer to register.
* @param classes the Set of application classes.
* @return the ServletContainerInitializerHolder that was created
*/
public ServletContainerInitializerHolder addServletContainerInitializer(ServletContainerInitializer sci, Class>... classes) {
if (!isStopped())
throw new IllegalStateException("ServletContainerInitializers should be added before starting");
ServletContainerInitializerHolder holder = new ServletContainerInitializerHolder(sci, classes);
addServletContainerInitializer(holder);
return holder;
}
/**
* Convenience method to programmatically add a list of {@link ServletContainerInitializer}.
* The initializers are guaranteed to be called in the order they are passed into this method.
* @param sciHolders the ServletContainerInitializerHolders
*/
public void addServletContainerInitializer(ServletContainerInitializerHolder... sciHolders) {
ServletContainerInitializerStarter starter = getBean(ServletContainerInitializerStarter.class);
if (starter == null) {
//add the starter as bean which will start when the context is started
//NOTE: do not use addManaged(starter) because this will start the
//starter immediately, which may not be before we have parsed web.xml
starter = new ServletContainerInitializerStarter();
addBean(starter, true);
}
starter.addServletContainerInitializerHolders(sciHolders);
}
/**
* notification that a ServletRegistration has been created so we can track the annotations
*
* @param holder new holder created through the api.
* @return the ServletRegistration.Dynamic
*/
protected ServletRegistration.Dynamic dynamicHolderAdded(ServletHolder holder) {
return holder.getRegistration();
}
/**
* delegate for ServletContext.declareRole method
*
* @param roleNames role names to add
*/
protected void addRoles(String... roleNames) {
//Get a reference to the SecurityHandler, which must be ConstraintAware
if (_securityHandler != null && _securityHandler instanceof ConstraintAware) {
HashSet union = new HashSet<>();
Set existing = ((ConstraintAware) _securityHandler).getRoles();
if (existing != null)
union.addAll(existing);
union.addAll(Arrays.asList(roleNames));
((ConstraintSecurityHandler) _securityHandler).setRoles(union);
}
}
/**
* Delegate for ServletRegistration.Dynamic.setServletSecurity method
*
* @param registration ServletRegistration.Dynamic instance that setServletSecurity was called on
* @param servletSecurityElement new security info
* @return the set of exact URL mappings currently associated with the registration that are also present in the web.xml
* security constraints and thus will be unaffected by this call.
*/
public Set setServletSecurity(ServletRegistration.Dynamic registration, ServletSecurityElement servletSecurityElement) {
//Default implementation is to just accept them all. If using a webapp, then this behaviour is overridden in WebAppContext.setServletSecurity
Collection pathSpecs = registration.getMappings();
if (pathSpecs != null) {
for (String pathSpec : pathSpecs) {
List mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath(registration.getName(), pathSpec, servletSecurityElement);
for (ConstraintMapping m : mappings) {
((ConstraintAware) getSecurityHandler()).addConstraintMapping(m);
}
}
}
return Collections.emptySet();
}
@Override
public void callContextInitialized(ServletContextListener l, ServletContextEvent e) {
try {
//toggle state of the dynamic API so that the listener cannot use it
if (isProgrammaticListener(l))
this.getServletContext().setEnabled(false);
super.callContextInitialized(l, e);
} finally {
//untoggle the state of the dynamic API
this.getServletContext().setEnabled(true);
}
}
@Override
public void callContextDestroyed(ServletContextListener l, ServletContextEvent e) {
super.callContextDestroyed(l, e);
}
private void replaceHandler(HandlerWrapper handler, HandlerWrapper replacement) {
if (isStarted())
throw new IllegalStateException("STARTED");
Handler next = null;
if (handler != null) {
next = handler.getHandler();
handler.setHandler(null);
HandlerWrapper wrapper = this;
while (wrapper != null) {
if (wrapper.getHandler() == handler) {
doSetHandler(wrapper, replacement);
break;
}
wrapper = (wrapper.getHandler() instanceof HandlerWrapper) ? (HandlerWrapper) wrapper.getHandler() : null;
}
}
if (next != null && replacement.getHandler() == null)
replacement.setHandler(next);
}
/**
* @param sessionHandler The sessionHandler to set.
*/
public void setSessionHandler(SessionHandler sessionHandler) {
replaceHandler(_sessionHandler, sessionHandler);
_sessionHandler = sessionHandler;
relinkHandlers();
}
/**
* @param securityHandler The {@link SecurityHandler} to set on this context.
*/
public void setSecurityHandler(SecurityHandler securityHandler) {
replaceHandler(_securityHandler, securityHandler);
_securityHandler = securityHandler;
relinkHandlers();
}
/**
* @param servletHandler The servletHandler to set.
*/
public void setServletHandler(ServletHandler servletHandler) {
replaceHandler(_servletHandler, servletHandler);
_servletHandler = servletHandler;
relinkHandlers();
}
@Override
public void setHandler(Handler handler) {
if (handler instanceof SessionHandler)
setSessionHandler((SessionHandler) handler);
else if (handler instanceof SecurityHandler)
setSecurityHandler((SecurityHandler) handler);
else if (handler instanceof ServletHandler)
setServletHandler((ServletHandler) handler);
else
getServletHandler().setHandler(handler);
}
/**
* Insert a HandlerWrapper before the first Session, Security or ServletHandler
* but after any other HandlerWrappers.
*/
@Override
public void insertHandler(HandlerWrapper handler) {
if (handler instanceof SessionHandler)
setSessionHandler((SessionHandler) handler);
else if (handler instanceof SecurityHandler)
setSecurityHandler((SecurityHandler) handler);
else if (handler instanceof ServletHandler)
setServletHandler((ServletHandler) handler);
else {
HandlerWrapper tail = handler;
while (tail.getHandler() instanceof HandlerWrapper) {
tail = (HandlerWrapper) tail.getHandler();
}
if (tail.getHandler() != null)
throw new IllegalArgumentException("bad tail of inserted wrapper chain");
// Skip any injected handlers
// This is not the best behavior, but is retained here for jetty-10/11 compatibility
// but is changed in ee10 and beyond
HandlerWrapper h = this;
while (h.getHandler() instanceof HandlerWrapper) {
HandlerWrapper wrapper = (HandlerWrapper) h.getHandler();
if (wrapper instanceof SessionHandler || wrapper instanceof SecurityHandler || wrapper instanceof ServletHandler)
break;
h = wrapper;
}
Handler next = h.getHandler();
doSetHandler(h, handler);
doSetHandler(tail, next);
}
relinkHandlers();
}
/**
* The DecoratedObjectFactory for use by IoC containers (weld / spring / etc)
*
* @return The DecoratedObjectFactory
*/
public DecoratedObjectFactory getObjectFactory() {
return _objFactory;
}
void destroyServlet(Servlet servlet) {
_objFactory.destroy(servlet);
}
void destroyFilter(Filter filter) {
_objFactory.destroy(filter);
}
void destroyListener(EventListener listener) {
_objFactory.destroy(listener);
}
public static class JspPropertyGroup implements JspPropertyGroupDescriptor {
private final List _urlPatterns = new ArrayList<>();
private String _elIgnored;
private String _pageEncoding;
private String _scriptingInvalid;
private String _isXml;
private final List _includePreludes = new ArrayList<>();
private final List _includeCodas = new ArrayList<>();
private String _deferredSyntaxAllowedAsLiteral;
private String _trimDirectiveWhitespaces;
private String _defaultContentType;
private String _buffer;
private String _errorOnUndeclaredNamespace;
@Override
public Collection getUrlPatterns() {
// spec says must be a copy
return new ArrayList<>(_urlPatterns);
}
public void addUrlPattern(String s) {
if (!_urlPatterns.contains(s))
_urlPatterns.add(s);
}
@Override
public String getElIgnored() {
return _elIgnored;
}
public void setElIgnored(String s) {
_elIgnored = s;
}
@Override
public String getPageEncoding() {
return _pageEncoding;
}
public void setPageEncoding(String pageEncoding) {
_pageEncoding = pageEncoding;
}
public void setScriptingInvalid(String scriptingInvalid) {
_scriptingInvalid = scriptingInvalid;
}
public void setIsXml(String isXml) {
_isXml = isXml;
}
public void setDeferredSyntaxAllowedAsLiteral(String deferredSyntaxAllowedAsLiteral) {
_deferredSyntaxAllowedAsLiteral = deferredSyntaxAllowedAsLiteral;
}
public void setTrimDirectiveWhitespaces(String trimDirectiveWhitespaces) {
_trimDirectiveWhitespaces = trimDirectiveWhitespaces;
}
public void setDefaultContentType(String defaultContentType) {
_defaultContentType = defaultContentType;
}
public void setBuffer(String buffer) {
_buffer = buffer;
}
public void setErrorOnUndeclaredNamespace(String errorOnUndeclaredNamespace) {
_errorOnUndeclaredNamespace = errorOnUndeclaredNamespace;
}
@Override
public String getScriptingInvalid() {
return _scriptingInvalid;
}
@Override
public String getIsXml() {
return _isXml;
}
@Override
public Collection getIncludePreludes() {
//must be a copy
return new ArrayList<>(_includePreludes);
}
public void addIncludePrelude(String prelude) {
if (!_includePreludes.contains(prelude))
_includePreludes.add(prelude);
}
@Override
public Collection getIncludeCodas() {
//must be a copy
return new ArrayList<>(_includeCodas);
}
public void addIncludeCoda(String coda) {
if (!_includeCodas.contains(coda))
_includeCodas.add(coda);
}
@Override
public String getDeferredSyntaxAllowedAsLiteral() {
return _deferredSyntaxAllowedAsLiteral;
}
@Override
public String getTrimDirectiveWhitespaces() {
return _trimDirectiveWhitespaces;
}
@Override
public String getDefaultContentType() {
return _defaultContentType;
}
@Override
public String getBuffer() {
return _buffer;
}
@Override
public String getErrorOnUndeclaredNamespace() {
return _errorOnUndeclaredNamespace;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("JspPropertyGroupDescriptor:");
sb.append(" el-ignored=").append(_elIgnored);
sb.append(" is-xml=").append(_isXml);
sb.append(" page-encoding=").append(_pageEncoding);
sb.append(" scripting-invalid=").append(_scriptingInvalid);
sb.append(" deferred-syntax-allowed-as-literal=").append(_deferredSyntaxAllowedAsLiteral);
sb.append(" trim-directive-whitespaces").append(_trimDirectiveWhitespaces);
sb.append(" default-content-type=").append(_defaultContentType);
sb.append(" buffer=").append(_buffer);
sb.append(" error-on-undeclared-namespace=").append(_errorOnUndeclaredNamespace);
for (String prelude : _includePreludes) {
sb.append(" include-prelude=").append(prelude);
}
for (String coda : _includeCodas) {
sb.append(" include-coda=").append(coda);
}
return sb.toString();
}
}
public static class TagLib implements TaglibDescriptor {
private String _uri;
private String _location;
@Override
public String getTaglibURI() {
return _uri;
}
public void setTaglibURI(String uri) {
_uri = uri;
}
@Override
public String getTaglibLocation() {
return _location;
}
public void setTaglibLocation(String location) {
_location = location;
}
@Override
public String toString() {
return ("TagLibDescriptor: taglib-uri=" + _uri + " location=" + _location);
}
}
public static class JspConfig implements JspConfigDescriptor {
private final List _taglibs = new ArrayList<>();
private final List _jspPropertyGroups = new ArrayList<>();
public JspConfig() {
}
@Override
public Collection getTaglibs() {
return new ArrayList<>(_taglibs);
}
public void addTaglibDescriptor(TaglibDescriptor d) {
_taglibs.add(d);
}
@Override
public Collection getJspPropertyGroups() {
return new ArrayList<>(_jspPropertyGroups);
}
public void addJspPropertyGroup(JspPropertyGroupDescriptor g) {
_jspPropertyGroups.add(g);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("JspConfigDescriptor: \n");
for (TaglibDescriptor taglib : _taglibs) {
sb.append(taglib).append("\n");
}
for (JspPropertyGroupDescriptor jpg : _jspPropertyGroups) {
sb.append(jpg).append("\n");
}
return sb.toString();
}
}
public class ServletAPIContext extends APIContext {
@Override
public RequestDispatcher getNamedDispatcher(String name) {
ContextHandler context = ServletContextHandler.this;
if (_servletHandler == null)
return null;
ServletHolder holder = _servletHandler.getServlet(name);
if (holder == null || !holder.isEnabled())
return null;
return new Dispatcher(context, name);
}
private void checkDynamic(String name) {
if (isStarted())
throw new IllegalStateException();
if (ServletContextHandler.this.getServletHandler().isInitialized())
throw new IllegalStateException();
if (StringUtil.isBlank(name))
throw new IllegalArgumentException("Missing name");
if (!_enabled)
throw new UnsupportedOperationException();
}
/**
* @since servlet-api-3.0
*/
@Override
public FilterRegistration.Dynamic addFilter(String filterName, Class extends Filter> filterClass) {
checkDynamic(filterName);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
FilterHolder holder = handler.getFilter(filterName);
if (holder == null) {
//new filter
holder = handler.newFilterHolder(Source.JAKARTA_API);
holder.setName(filterName);
holder.setHeldClass(filterClass);
handler.addFilter(holder);
return holder.getRegistration();
}
if (holder.getClassName() == null && holder.getHeldClass() == null) {
//preliminary filter registration completion
holder.setHeldClass(filterClass);
return holder.getRegistration();
} else
//existing filter
return null;
}
/**
* @since servlet-api-3.0
*/
@Override
public FilterRegistration.Dynamic addFilter(String filterName, String className) {
checkDynamic(filterName);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
FilterHolder holder = handler.getFilter(filterName);
if (holder == null) {
//new filter
holder = handler.newFilterHolder(Source.JAKARTA_API);
holder.setName(filterName);
holder.setClassName(className);
handler.addFilter(holder);
return holder.getRegistration();
}
if (holder.getClassName() == null && holder.getHeldClass() == null) {
//preliminary filter registration completion
holder.setClassName(className);
return holder.getRegistration();
} else
//existing filter
return null;
}
/**
* @since servlet-api-3.0
*/
@Override
public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) {
checkDynamic(filterName);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
FilterHolder holder = handler.getFilter(filterName);
if (holder == null) {
//new filter
holder = handler.newFilterHolder(Source.JAKARTA_API);
holder.setName(filterName);
holder.setFilter(filter);
handler.addFilter(holder);
return holder.getRegistration();
}
if (holder.getClassName() == null && holder.getHeldClass() == null) {
//preliminary filter registration completion
holder.setFilter(filter);
return holder.getRegistration();
} else
//existing filter
return null;
}
/**
* @since servlet-api-3.0
*/
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Class extends Servlet> servletClass) {
checkDynamic(servletName);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
ServletHolder holder = handler.getServlet(servletName);
if (holder == null) {
//new servlet
holder = handler.newServletHolder(Source.JAKARTA_API);
holder.setName(servletName);
holder.setHeldClass(servletClass);
handler.addServlet(holder);
return dynamicHolderAdded(holder);
}
//complete a partial registration
if (holder.getClassName() == null && holder.getHeldClass() == null) {
holder.setHeldClass(servletClass);
return holder.getRegistration();
} else
//existing completed registration for servlet name
return null;
}
/**
* @since servlet-api-3.0
*/
@Override
public ServletRegistration.Dynamic addServlet(String servletName, String className) {
checkDynamic(servletName);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
ServletHolder holder = handler.getServlet(servletName);
if (holder == null) {
//new servlet
holder = handler.newServletHolder(Source.JAKARTA_API);
holder.setName(servletName);
holder.setClassName(className);
handler.addServlet(holder);
return dynamicHolderAdded(holder);
}
//complete a partial registration
if (holder.getClassName() == null && holder.getHeldClass() == null) {
holder.setClassName(className);
return holder.getRegistration();
} else
//existing completed registration for servlet name
return null;
}
/**
* @since servlet-api-3.0
*/
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
checkDynamic(servletName);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
ServletHolder holder = handler.getServlet(servletName);
if (holder == null) {
holder = handler.newServletHolder(Source.JAKARTA_API);
holder.setName(servletName);
holder.setServlet(servlet);
handler.addServlet(holder);
return dynamicHolderAdded(holder);
}
//complete a partial registration
if (holder.getClassName() == null && holder.getHeldClass() == null) {
holder.setServlet(servlet);
return holder.getRegistration();
} else
//existing completed registration for servlet name
return null;
}
@Override
public ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) {
checkDynamic(servletName);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
ServletHolder holder = handler.getServlet(servletName);
if (holder == null) {
//new servlet
holder = handler.newServletHolder(Source.JAKARTA_API);
holder.setName(servletName);
holder.setForcedPath(jspFile);
handler.addServlet(holder);
return dynamicHolderAdded(holder);
}
//complete a partial registration
if (holder.getClassName() == null && holder.getHeldClass() == null && holder.getForcedPath() == null) {
holder.setForcedPath(jspFile);
return holder.getRegistration();
} else
//existing completed registration for servlet name
return null;
}
@Override
public String getInitParameter(String name) {
//since servlet spec 4.0
Objects.requireNonNull(name);
return super.getInitParameter(name);
}
@Override
public boolean setInitParameter(String name, String value) {
//since servlet spec 4.0
Objects.requireNonNull(name);
if (!isStarting())
throw new IllegalStateException();
if (!_enabled)
throw new UnsupportedOperationException();
return super.setInitParameter(name, value);
}
@Override
public T createInstance(Class clazz) throws ServletException {
return _objFactory.decorate(super.createInstance(clazz));
}
public T createInstance(BaseHolder holder) throws ServletException {
try {
//set a thread local
DecoratedObjectFactory.associateInfo(holder);
return createInstance(holder.getHeldClass());
} finally {
//unset the thread local
DecoratedObjectFactory.disassociateInfo();
}
}
public void destroyFilter(T f) {
_objFactory.destroy(f);
}
public void destroyServlet(T s) {
_objFactory.destroy(s);
}
@Override
public Set getDefaultSessionTrackingModes() {
if (!_enabled)
throw new UnsupportedOperationException();
if (_sessionHandler != null)
return _sessionHandler.getDefaultSessionTrackingModes();
return null;
}
@Override
public Set getEffectiveSessionTrackingModes() {
if (!_enabled)
throw new UnsupportedOperationException();
if (_sessionHandler != null)
return _sessionHandler.getEffectiveSessionTrackingModes();
return null;
}
@Override
public FilterRegistration getFilterRegistration(String filterName) {
if (!_enabled)
throw new UnsupportedOperationException();
final FilterHolder holder = ServletContextHandler.this.getServletHandler().getFilter(filterName);
return (holder == null) ? null : holder.getRegistration();
}
@Override
public Map getFilterRegistrations() {
if (!_enabled)
throw new UnsupportedOperationException();
HashMap registrations = new HashMap<>();
ServletHandler handler = ServletContextHandler.this.getServletHandler();
FilterHolder[] holders = handler.getFilters();
if (holders != null) {
for (FilterHolder holder : holders) {
registrations.put(holder.getName(), holder.getRegistration());
}
}
return registrations;
}
@Override
public ServletRegistration getServletRegistration(String servletName) {
if (!_enabled)
throw new UnsupportedOperationException();
final ServletHolder holder = ServletContextHandler.this.getServletHandler().getServlet(servletName);
return (holder == null) ? null : holder.getRegistration();
}
@Override
public Map getServletRegistrations() {
if (!_enabled)
throw new UnsupportedOperationException();
HashMap registrations = new HashMap<>();
ServletHandler handler = ServletContextHandler.this.getServletHandler();
ServletHolder[] holders = handler.getServlets();
if (holders != null) {
for (ServletHolder holder : holders) {
registrations.put(holder.getName(), holder.getRegistration());
}
}
return registrations;
}
@Override
public SessionCookieConfig getSessionCookieConfig() {
if (!_enabled)
throw new UnsupportedOperationException();
if (_sessionHandler != null)
return _sessionHandler.getSessionCookieConfig();
return null;
}
@Override
public void setSessionTrackingModes(Set sessionTrackingModes) {
if (!isStarting())
throw new IllegalStateException();
if (!_enabled)
throw new UnsupportedOperationException();
if (_sessionHandler != null)
_sessionHandler.setSessionTrackingModes(sessionTrackingModes);
}
@Override
public int getSessionTimeout() {
if (!_enabled)
throw new UnsupportedOperationException();
int timeout = -1;
if (_sessionHandler != null) {
timeout = _sessionHandler.getMaxInactiveInterval();
}
return (int) TimeUnit.SECONDS.toMinutes(timeout);
}
@Override
public void setSessionTimeout(int sessionTimeout) {
if (!isStarting())
throw new IllegalStateException();
if (!_enabled)
throw new UnsupportedOperationException();
if (_sessionHandler != null) {
long tmp = TimeUnit.MINUTES.toSeconds(sessionTimeout);
if (tmp > Integer.MAX_VALUE)
tmp = Integer.MAX_VALUE;
if (tmp < Integer.MIN_VALUE)
tmp = Integer.MIN_VALUE;
_sessionHandler.setMaxInactiveInterval((int) tmp);
}
}
@Override
public T createServlet(Class clazz) throws ServletException {
if (!_enabled)
throw new UnsupportedOperationException();
return super.createServlet(clazz);
}
@Override
public T createFilter(Class clazz) throws ServletException {
if (!_enabled)
throw new UnsupportedOperationException();
return super.createFilter(clazz);
}
@Override
public T createListener(Class clazz) throws ServletException {
if (!_enabled)
throw new UnsupportedOperationException();
try {
checkListener(clazz);
} catch (IllegalArgumentException e) {
//Bizarrely, according to the spec, it is NOT an error to create an instance of
//a ServletContextListener from inside a ServletContextListener, but it IS an error
//to call addListener with one!
if (!ServletContextListener.class.isAssignableFrom(clazz))
throw e;
}
return super.createListener(clazz);
}
@Override
public void addListener(String className) {
if (!isStarting())
throw new IllegalStateException();
if (!_enabled)
throw new UnsupportedOperationException();
super.addListener(className);
}
@Override
public void addListener(T t) {
if (!isStarting())
throw new IllegalStateException();
if (!_enabled)
throw new UnsupportedOperationException();
checkListener(t.getClass());
ListenerHolder holder = getServletHandler().newListenerHolder(Source.JAKARTA_API);
holder.setListener(t);
addProgrammaticListener(t);
getServletHandler().addListener(holder);
if (_startListeners) {
try {
holder.start();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}
@Override
public void addListener(Class extends EventListener> listenerClass) {
if (!isStarting())
throw new IllegalStateException();
if (!_enabled)
throw new UnsupportedOperationException();
super.addListener(listenerClass);
}
@Override
public JspConfigDescriptor getJspConfigDescriptor() {
return _jspConfig;
}
@Override
public void setJspConfigDescriptor(JspConfigDescriptor d) {
_jspConfig = d;
}
@Override
public void declareRoles(String... roleNames) {
if (!isStarting())
throw new IllegalStateException();
if (!_enabled)
throw new UnsupportedOperationException();
addRoles(roleNames);
}
@Override
public String getRequestCharacterEncoding() {
return getDefaultRequestCharacterEncoding();
}
@Override
public void setRequestCharacterEncoding(String encoding) {
if (!isStarting())
throw new IllegalStateException();
setDefaultRequestCharacterEncoding(encoding);
}
@Override
public String getResponseCharacterEncoding() {
return getDefaultResponseCharacterEncoding();
}
@Override
public void setResponseCharacterEncoding(String encoding) {
if (!isStarting())
throw new IllegalStateException();
setDefaultResponseCharacterEncoding(encoding);
}
}
/**
* A utility class to hold a {@link ServletContainerInitializer} and implement the
* {@link ServletContainerInitializerCaller} interface so that the SCI is correctly
* started if an instance of this class is added as a bean to a {@link ServletContextHandler}.
* @deprecated
*/
@Deprecated
public static class Initializer extends AbstractLifeCycle implements ServletContainerInitializerCaller {
private final ServletContextHandler _context;
private final ServletContainerInitializer _sci;
private final Set> _classes;
public Initializer(ServletContextHandler context, ServletContainerInitializer sci, Set> classes) {
_context = context;
_sci = sci;
_classes = classes;
}
public Initializer(ServletContextHandler context, ServletContainerInitializer sci) {
this(context, sci, Collections.emptySet());
}
@Override
protected void doStart() throws Exception {
boolean oldExtended = _context.getServletContext().isExtendedListenerTypes();
try {
_context.getServletContext().setExtendedListenerTypes(true);
_sci.onStartup(_classes, _context.getServletContext());
} finally {
_context.getServletContext().setExtendedListenerTypes(oldExtended);
}
}
}
/**
* Bean that is added to the ServletContextHandler to start all of the
* ServletContainerInitializers by starting their corresponding
* ServletContainerInitializerHolders when this bean is itself started.
* Note that the SCIs will be started in order of addition.
*/
public static class ServletContainerInitializerStarter extends ContainerLifeCycle implements ServletContainerInitializerCaller {
public void addServletContainerInitializerHolders(ServletContainerInitializerHolder... holders) {
for (ServletContainerInitializerHolder holder : holders) addBean(holder, true);
}
public Collection getServletContainerInitializerHolders() {
return getContainedBeans(ServletContainerInitializerHolder.class);
}
@Override
protected void doStart() throws Exception {
if (LOG.isDebugEnabled())
LOG.debug("Starting SCIs");
super.doStart();
}
@Override
protected void doStop() throws Exception {
//remove all of the non-programmatic holders
Collection holders = getServletContainerInitializerHolders();
for (ServletContainerInitializerHolder h : holders) {
if (h.getSource().getOrigin() != Source.Origin.EMBEDDED)
removeBean(h);
}
super.doStop();
}
}
}