Java tutorial
/* * Copyright 2012 Romain Gilles * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ops4j.pax.web.service.tomcat.internal; import java.util.ArrayList; import java.util.Collection; import java.util.Dictionary; import java.util.EnumSet; import java.util.EventListener; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.DispatcherType; import javax.servlet.FilterRegistration; import javax.servlet.FilterRegistration.Dynamic; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletContextAttributeListener; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletRequestListener; import javax.servlet.UnavailableException; import javax.servlet.descriptor.JspConfigDescriptor; import javax.servlet.descriptor.JspPropertyGroupDescriptor; import javax.servlet.descriptor.TaglibDescriptor; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionListener; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.InstanceEvent; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.LifecycleState; import org.apache.catalina.Wrapper; import org.apache.catalina.core.ContainerBase; import org.apache.catalina.security.SecurityUtil; import org.apache.catalina.startup.Tomcat.ExistingStandardWrapper; import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.descriptor.web.ErrorPage; import org.apache.tomcat.util.descriptor.web.FilterDef; import org.apache.tomcat.util.descriptor.web.FilterMap; import org.apache.tomcat.util.descriptor.web.JspConfigDescriptorImpl; import org.apache.tomcat.util.descriptor.web.JspPropertyGroup; import org.apache.tomcat.util.descriptor.web.JspPropertyGroupDescriptorImpl; import org.apache.tomcat.util.descriptor.web.SecurityCollection; import org.apache.tomcat.util.descriptor.web.SecurityConstraint; import org.apache.tomcat.util.descriptor.web.TaglibDescriptorImpl; import org.ops4j.lang.NullArgumentException; import org.ops4j.pax.swissbox.core.BundleUtils; import org.ops4j.pax.swissbox.core.ContextClassLoaderUtils; import org.ops4j.pax.web.service.WebContainerConstants; import org.ops4j.pax.web.service.spi.LifeCycle; import org.ops4j.pax.web.service.spi.model.ContextModel; import org.ops4j.pax.web.service.spi.model.ErrorPageModel; import org.ops4j.pax.web.service.spi.model.EventListenerModel; import org.ops4j.pax.web.service.spi.model.FilterModel; import org.ops4j.pax.web.service.spi.model.Model; import org.ops4j.pax.web.service.spi.model.SecurityConstraintMappingModel; import org.ops4j.pax.web.service.spi.model.ServletModel; import org.ops4j.pax.web.service.spi.model.WelcomeFileModel; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceRegistration; import org.osgi.service.http.HttpContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Romain Gilles */ class TomcatServerWrapper implements ServerWrapper { private final class OsgiExistingStandardWrapper extends ExistingStandardWrapper { private final ServletModel model; private OsgiExistingStandardWrapper(Servlet existing, ServletModel model) { super(existing); this.model = model; } @Override public synchronized void load() throws ServletException { try { instance = ContextClassLoaderUtils.doWithClassLoader(model.getContextModel().getClassLoader(), new Callable<Servlet>() { @Override public Servlet call() { try { return loadServlet(); } catch (final ServletException e) { LOG.warn("Caucht exception while loading Servlet with classloader {}", e); return null; } } }); } catch (Exception e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } LOG.error("Ignored exception during servlet registration", e); } if (!instanceInitialized) { initServlet(instance); } // skip the JMX part not needed here! } private synchronized void initServlet(Servlet servlet) throws ServletException { if (instanceInitialized && !singleThreadModel) return; // Call the initialization method of this servlet try { instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT, servlet); if (Globals.IS_SECURITY_ENABLED) { Object[] args = new Object[] { (facade) }; SecurityUtil.doAsPrivilege("init", servlet, classType, args); args = null; } else { servlet.init(facade); } instanceInitialized = true; instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet); } catch (UnavailableException f) { instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet, f); unavailable(f); throw f; } catch (ServletException f) { instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet, f); // If the servlet wanted to be unavailable it would have // said so, so do not call unavailable(null). throw f; } catch (Throwable f) { ExceptionUtils.handleThrowable(f); getServletContext().log("StandardWrapper.Throwable", f); instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet, f); // If the servlet wanted to be unavailable it would have // said so, so do not call unavailable(null). throw new ServletException(sm.getString("standardWrapper.initException", getName()), f); } } } private static final Logger LOG = LoggerFactory.getLogger(TomcatServerWrapper.class); private static final String WEB_CONTEXT_PATH = "Web-ContextPath"; private final EmbeddedTomcat server; private final Map<HttpContext, Context> contextMap = new ConcurrentHashMap<HttpContext, Context>(); private ServiceRegistration<ServletContext> servletContextService; private Map<String, Object> contextAttributes; private TomcatServerWrapper(final EmbeddedTomcat server) { NullArgumentException.validateNotNull(server, "server"); this.server = server; ((ContainerBase) server.getHost()).setStartChildren(false); TomcatURLStreamHandlerFactory.disable(); } static ServerWrapper getInstance(final EmbeddedTomcat server) { return new TomcatServerWrapper(server); } @Override public void start() { LOG.debug("start server"); try { final long t1 = System.nanoTime(); server.getHost(); server.start(); final long t2 = System.nanoTime(); if (LOG.isInfoEnabled()) { LOG.info("TomCat server startup in " + ((t2 - t1) / 1000000) + " ms"); } } catch (final LifecycleException e) { throw new ServerStartException(server.getServer().toString(), e); } } @Override public void stop() { LOG.debug("stop server"); final LifecycleState state = server.getServer().getState(); if (LifecycleState.STOPPING_PREP.compareTo(state) <= 0 && LifecycleState.DESTROYED.compareTo(state) >= 0) { throw new IllegalStateException("stop already called!"); } else { //CHECKSTYLE:OFF try { server.stop(); server.destroy(); } catch (final Throwable e) { LOG.error("LifecycleException caught {}", e); } //CHECKSTYLE:ON } } @Override public void addServlet(final ServletModel model) { LOG.debug("add servlet [{}]", model); final Context context = findOrCreateContext(model.getContextModel()); final String servletName = model.getName(); if (model.getServlet() == null) { // will do class for name and set init params try { final Servlet servlet = model.getServletFromName(); if (servlet != null) { createServletWrapper(model, context, servletName, servlet); if (!model.getContextModel().isWebBundle()) { context.addLifecycleListener(new LifecycleListener() { @Override public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.AFTER_START_EVENT.equalsIgnoreCase(event.getType())) { Map<String, ? extends ServletRegistration> servletRegistrations = context .getServletContext().getServletRegistrations(); //CHECKSTYLE:OFF if (!servletRegistrations.containsKey(servletName)) { LOG.debug("need to re-register the servlet ..."); createServletWrapper(model, context, servletName, servlet); } //CHECKSTYLE:ON } } }); } } else { final Wrapper sw = context.createWrapper(); sw.setServletClass(model.getServletClass().getName()); addServletWrapper(sw, servletName, context, model); if (!model.getContextModel().isWebBundle()) { context.addLifecycleListener(new LifecycleListener() { @Override public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.AFTER_START_EVENT.equalsIgnoreCase(event.getType())) { Map<String, ? extends ServletRegistration> servletRegistrations = context .getServletContext().getServletRegistrations(); //CHECKSTYLE:OFF if (!servletRegistrations.containsKey(servletName)) { LOG.debug("need to re-register the servlet ..."); sw.setServletClass(model.getServletClass().getName()); addServletWrapper(sw, servletName, context, model); } //CHECKSTYLE:ON } } }); } } } catch (InstantiationException e) { LOG.error("failed to create Servlet", e); } catch (IllegalAccessException e) { LOG.error("failed to create Servlet", e); } catch (ClassNotFoundException e) { LOG.error("failed to create Servlet", e); } catch (SecurityException e) { LOG.error("failed to create Servlet", e); } } else { createServletWrapper(model, context, servletName, null); if (!model.getContextModel().isWebBundle()) { context.addLifecycleListener(new LifecycleListener() { @Override public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.BEFORE_START_EVENT.equalsIgnoreCase(event.getType())) { Map<String, ? extends ServletRegistration> servletRegistrations = context .getServletContext().getServletRegistrations(); if (!servletRegistrations.containsKey(servletName)) { LOG.debug("need to re-register the servlet ..."); createServletWrapper(model, context, servletName, null); } } } }); } } } private void createServletWrapper(final ServletModel model, final Context context, final String servletName, Servlet servlet) { if (servlet != null) { Wrapper sw = new OsgiExistingStandardWrapper(model.getServlet(), model); addServletWrapper(sw, servletName, context, model); } else { Wrapper sw = new OsgiExistingStandardWrapper(model.getServlet(), model); addServletWrapper(sw, servletName, context, model); } } private void addServletWrapper(final Wrapper sw, final String servletName, final Context context, final ServletModel model) { sw.setName(servletName); context.addChild(sw); addServletMappings(context, servletName, model.getUrlPatterns()); addInitParameters(sw, model.getInitParams()); if (model.getAsyncSupported() != null) { sw.setAsyncSupported(model.getAsyncSupported()); } if (model.getLoadOnStartup() != null) { sw.setLoadOnStartup(model.getLoadOnStartup()); } if (model.getMultipartConfig() != null) { sw.setMultipartConfigElement(model.getMultipartConfig()); } } @Override public void removeServlet(final ServletModel model) { LOG.debug("remove servlet [{}]", model); final Context context = findContext(model); if (context == null) { throw new TomcatRemoveServletException( "cannot remove servlet cannot find the associated container: " + model); } final Container servlet = context.findChild(model.getName()); if (servlet == null) { throw new TomcatRemoveServletException("cannot find the servlet to remove: " + model); } context.removeChild(servlet); } @Override public void removeContext(final HttpContext httpContext) { LOG.debug("remove context [{}]", httpContext); try { if (servletContextService != null) { servletContextService.unregister(); } } catch (final IllegalStateException e) { LOG.info("ServletContext service already removed"); } final Context context = contextMap.remove(httpContext); this.server.getHost().removeChild(context); if (context == null) { throw new RemoveContextException("cannot remove the context because it does not exist: " + httpContext); } try { final LifecycleState state = context.getState(); if (LifecycleState.DESTROYED != state || LifecycleState.DESTROYING != state) { context.destroy(); } } catch (final LifecycleException e) { throw new RemoveContextException("cannot destroy the context: " + httpContext, e); } } @Override public void addEventListener(final EventListenerModel eventListenerModel) { LOG.debug("add event listener: [{}]", eventListenerModel); final Context context = findOrCreateContext(eventListenerModel); LifecycleState state = ((HttpServiceContext) context).getState(); boolean restartContext = false; if ((LifecycleState.STARTING.equals(state) || LifecycleState.STARTED.equals(state)) && !eventListenerModel.getContextModel().isWebBundle()) { try { restartContext = true; ((HttpServiceContext) context).stop(); } catch (LifecycleException e) { LOG.warn("Can't reset the Lifecycle ... ", e); } } context.addLifecycleListener(new LifecycleListener() { @Override public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.BEFORE_START_EVENT.equalsIgnoreCase(event.getType())) { context.getServletContext().addListener(eventListenerModel.getEventListener()); } } }); if (restartContext) { try { ((HttpServiceContext) context).start(); } catch (LifecycleException e) { LOG.warn("Can't reset the Lifecycle ... ", e); } } } @Override public void removeEventListener(final EventListenerModel eventListenerModel) { LOG.debug("remove event listener: [{}]", eventListenerModel); NullArgumentException.validateNotNull(eventListenerModel, "eventListenerModel"); NullArgumentException.validateNotNull(eventListenerModel.getEventListener(), "eventListenerModel#weventListener"); final Context context = findOrCreateContext(eventListenerModel); // TODO open a bug in tomcat if (!removeApplicationEventListener(context, eventListenerModel.getEventListener())) { if (!removeApplicationLifecycleListener(context, eventListenerModel.getEventListener())) { throw new RemoveEventListenerException( "cannot remove the event lister it is a not support class : " + eventListenerModel); } } } private boolean removeApplicationLifecycleListener(final Context context, final EventListener eventListener) { if (!isApplicationLifecycleListener(eventListener)) { return false; } Object[] applicationLifecycleListeners = context.getApplicationLifecycleListeners(); List<EventListener> listeners = new ArrayList<>(); boolean found = filterEventListener(listeners, applicationLifecycleListeners, eventListener); if (found) { context.setApplicationLifecycleListeners(listeners.toArray()); } return found; } private boolean isApplicationLifecycleListener(final EventListener eventListener) { return (eventListener instanceof HttpSessionListener || eventListener instanceof ServletContextListener); } private boolean removeApplicationEventListener(final Context context, final EventListener eventListener) { if (!isApplicationEventListener(eventListener)) { return false; } Object[] applicationEventListeners = context.getApplicationEventListeners(); List<EventListener> newEventListeners = new ArrayList<>(); boolean found = filterEventListener(newEventListeners, applicationEventListeners, eventListener); if (found) { context.setApplicationEventListeners(newEventListeners.toArray()); } return found; } private boolean filterEventListener(List<EventListener> listeners, Object[] applicationEventListeners, EventListener eventListener) { boolean found = false; for (Object object : applicationEventListeners) { EventListener listener = (EventListener) object; if (listener != eventListener) { listeners.add(listener); } else { found = true; } } return found; } private boolean isApplicationEventListener(final EventListener eventListener) { return (eventListener instanceof ServletContextAttributeListener || eventListener instanceof ServletRequestListener || eventListener instanceof ServletRequestAttributeListener || eventListener instanceof HttpSessionAttributeListener); } @Override public void addFilter(final FilterModel filterModel) { LOG.debug("add filter [{}]", filterModel); final Context context = findOrCreateContext(filterModel); LifecycleState state = ((HttpServiceContext) context).getState(); boolean restartContext = false; if ((LifecycleState.STARTING.equals(state) || LifecycleState.STARTED.equals(state)) && !filterModel.getContextModel().isWebBundle()) { try { restartContext = true; ((HttpServiceContext) context).stop(); } catch (LifecycleException e) { LOG.warn("Can't reset the Lifecycle ... ", e); } } context.addLifecycleListener(new LifecycleListener() { @Override public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.BEFORE_START_EVENT.equalsIgnoreCase(event.getType())) { FilterRegistration.Dynamic filterRegistration = null; if (filterModel.getFilter() != null) { filterRegistration = context.getServletContext().addFilter(filterModel.getName(), filterModel.getFilter()); } else if (filterModel.getFilterClass() != null) { filterRegistration = context.getServletContext().addFilter(filterModel.getName(), filterModel.getFilterClass()); } if (filterRegistration == null) { filterRegistration = (Dynamic) context.getServletContext() .getFilterRegistration(filterModel.getName()); if (filterRegistration == null) { LOG.error("Can't register Filter due to unknown reason!"); } } filterRegistration.setAsyncSupported(filterModel.isAsyncSupported()); if (filterModel.getServletNames() != null && filterModel.getServletNames().length > 0) { filterRegistration.addMappingForServletNames(getDispatcherTypes(filterModel), /* * TODO get * asynch * supported? */false, filterModel.getServletNames()); } else if (filterModel.getUrlPatterns() != null && filterModel.getUrlPatterns().length > 0) { filterRegistration.addMappingForUrlPatterns(getDispatcherTypes(filterModel), /* * TODO get * asynch * supported? */false, filterModel.getUrlPatterns()); } else { throw new AddFilterException( "cannot add filter to the context; at least a not empty list of servlet names or URL patterns in exclusive mode must be provided: " + filterModel); } filterRegistration.setInitParameters(filterModel.getInitParams()); } } }); if (restartContext) { try { ((HttpServiceContext) context).start(); } catch (LifecycleException e) { LOG.warn("Can't reset the Lifecycle ... ", e); } } } private EnumSet<DispatcherType> getDispatcherTypes(final FilterModel filterModel) { final ArrayList<DispatcherType> dispatcherTypes = new ArrayList<DispatcherType>( DispatcherType.values().length); for (final String dispatcherType : filterModel.getDispatcher()) { dispatcherTypes.add(DispatcherType.valueOf(dispatcherType.toUpperCase())); } EnumSet<DispatcherType> result = EnumSet.noneOf(DispatcherType.class); if (dispatcherTypes != null && dispatcherTypes.size() > 0) { result = EnumSet.copyOf(dispatcherTypes); } return result; } @Override public void removeFilter(final FilterModel filterModel) { final Context context = findOrCreateContext(filterModel); FilterDef findFilterDef = context.findFilterDef(filterModel.getName()); context.removeFilterDef(findFilterDef); FilterMap[] filterMaps = context.findFilterMaps(); for (FilterMap filterMap : filterMaps) { if (filterMap.getFilterName().equalsIgnoreCase(filterModel.getName())) { context.removeFilterMap(filterMap); } } } @Override public void addErrorPage(final ErrorPageModel model) { final Context context = findContext(model); if (context == null) { throw new AddErrorPageException("cannot retrieve the associated context: " + model); } final ErrorPage errorPage = createErrorPage(model); context.addErrorPage(errorPage); } private ErrorPage createErrorPage(final ErrorPageModel model) { NullArgumentException.validateNotNull(model, "model"); NullArgumentException.validateNotNull(model.getLocation(), "model#location"); NullArgumentException.validateNotNull(model.getError(), "model#error"); final ErrorPage errorPage = new ErrorPage(); errorPage.setLocation(model.getLocation()); final Integer errorCode = parseErrorCode(model.getError()); if (errorCode != null) { errorPage.setErrorCode(errorCode); } else { if (!ErrorPageModel.ERROR_PAGE.equalsIgnoreCase(model.getError())) { errorPage.setExceptionType(model.getError()); } } return errorPage; } private Integer parseErrorCode(final String errorCode) { try { return Integer.parseInt(errorCode); } catch (final NumberFormatException e) { return null; } } @Override public void removeErrorPage(final ErrorPageModel model) { final Context context = findContext(model); if (context == null) { throw new RemoveErrorPageException("cannot retrieve the associated context: " + model); } final ErrorPage errorPage = createErrorPage(model); context.removeErrorPage(errorPage); } @Override public Servlet createResourceServlet(final ContextModel contextModel, final String alias, final String name) { LOG.debug("createResourceServlet( contextModel: {}, alias: {}, name: {})"); return new TomcatResourceServlet(contextModel.getHttpContext(), contextModel.getContextName(), alias, name); } @Override public void addSecurityConstraintMapping(final SecurityConstraintMappingModel secMapModel) { LOG.debug("add security contstraint mapping [{}]", secMapModel); final Context context = findOrCreateContext(secMapModel.getContextModel()); String mappingMethod = secMapModel.getMapping(); String constraintName = secMapModel.getConstraintName(); String url = secMapModel.getUrl(); String dataConstraint = secMapModel.getDataConstraint(); List<String> roles = secMapModel.getRoles(); boolean authentication = secMapModel.isAuthentication(); SecurityConstraint[] constraints = context.findConstraints(); SecurityConstraint secConstraint = new SecurityConstraint(); boolean foundExisting = false; for (SecurityConstraint securityConstraint : constraints) { if (securityConstraint.getDisplayName().equalsIgnoreCase(constraintName)) { secConstraint = securityConstraint; foundExisting = true; continue; } } if (!foundExisting) { secConstraint.setDisplayName(secMapModel.getConstraintName()); secConstraint.setAuthConstraint(authentication); for (String authRole : roles) { secConstraint.addAuthRole(authRole); } secConstraint.setUserConstraint(dataConstraint); context.addConstraint(secConstraint); } SecurityCollection collection = new SecurityCollection(); collection.addMethod(mappingMethod); collection.addPattern(url); secConstraint.addCollection(collection); } @Override public LifeCycle getContext(final ContextModel model) { final Context context = findOrCreateContext(model); if (context == null) { throw new RemoveErrorPageException("cannot retrieve the associated context: " + model); } return new LifeCycle() { @Override public void start() throws Exception { ContainerBase host = (ContainerBase) TomcatServerWrapper.this.server.getHost(); host.setStartChildren(true); if (!context.getState().isAvailable()) { LOG.info("server is available, in state {}", context.getState()); ContextClassLoaderUtils.doWithClassLoader(context.getParentClassLoader(), new Callable<Void>() { @Override public Void call() throws LifecycleException { context.start(); return null; } }); } } @Override public void stop() throws Exception { context.stop(); } }; } private void addServletMappings(final Context context, final String servletName, final String[] urlPatterns) { NullArgumentException.validateNotNull(urlPatterns, "urlPatterns"); for (final String urlPattern : urlPatterns) { // TODO add a enhancement // to tomcat it is in // the specification so // tomcat should provide // it out of the box context.addServletMapping(urlPattern, servletName); } } private void addInitParameters(final Wrapper wrapper, final Map<String, String> initParameters) { NullArgumentException.validateNotNull(initParameters, "initParameters"); NullArgumentException.validateNotNull(wrapper, "wrapper"); for (final Map.Entry<String, String> initParam : initParameters.entrySet()) { wrapper.addInitParameter(initParam.getKey(), initParam.getValue()); } } private Context findOrCreateContext(final Model model) { NullArgumentException.validateNotNull(model, "model"); return findOrCreateContext(model.getContextModel()); } private Context findOrCreateContext(final ContextModel contextModel) { HttpContext httpContext = contextModel.getHttpContext(); Context context = contextMap.get(httpContext); if (context == null) { context = createContext(contextModel); } return context; } private Context createContext(final ContextModel contextModel) { final Bundle bundle = contextModel.getBundle(); final BundleContext bundleContext = BundleUtils.getBundleContext(bundle); final Context context = server.addContext(contextModel.getContextParams(), getContextAttributes(bundleContext), contextModel.getContextName(), contextModel.getHttpContext(), contextModel.getAccessControllerContext(), contextModel.getContainerInitializers(), contextModel.getJettyWebXmlURL(), contextModel.getVirtualHosts(), null /*contextModel.getConnectors() */, server.getBasedir()); context.setParentClassLoader(contextModel.getClassLoader()); // TODO: is the context already configured? // TODO: how about security, classloader? // TODO: compare with JettyServerWrapper.addContext // TODO: what about the init parameters? configureJspConfigDescriptor(context, contextModel); final LifecycleState state = context.getState(); if (state != LifecycleState.STARTED && state != LifecycleState.STARTING && state != LifecycleState.STARTING_PREP) { LOG.debug("Registering ServletContext as service. "); final Dictionary<String, String> properties = new Hashtable<String, String>(); properties.put("osgi.web.symbolicname", bundle.getSymbolicName()); final Dictionary<String, String> headers = bundle.getHeaders(); final String version = (String) headers.get(Constants.BUNDLE_VERSION); if (version != null && version.length() > 0) { properties.put("osgi.web.version", version); } String webContextPath = (String) headers.get(WEB_CONTEXT_PATH); final String webappContext = (String) headers.get("Webapp-Context"); final ServletContext servletContext = context.getServletContext(); // This is the default context, but shouldn't it be called default? // See PAXWEB-209 if ("/".equalsIgnoreCase(context.getPath()) && (webContextPath == null || webappContext == null)) { webContextPath = context.getPath(); } // makes sure the servlet context contains a leading slash webContextPath = webContextPath != null ? webContextPath : webappContext; if (webContextPath != null && !webContextPath.startsWith("/")) { webContextPath = "/" + webContextPath; } if (webContextPath == null) { LOG.warn("osgi.web.contextpath couldn't be set, it's not configured"); } properties.put("osgi.web.contextpath", webContextPath); servletContextService = bundleContext.registerService(ServletContext.class, servletContext, properties); LOG.debug("ServletContext registered as service. "); } contextMap.put(contextModel.getHttpContext(), context); return context; } private void configureJspConfigDescriptor(Context context, ContextModel model) { Boolean elIgnored = model.getJspElIgnored(); Boolean isXml = model.getJspIsXml(); Boolean scriptingInvalid = model.getJspScriptingInvalid(); Collection<JspPropertyGroupDescriptor> jspPropertyGroupDescriptors = null; Collection<TaglibDescriptor> taglibs = null; if (elIgnored != null || isXml != null || scriptingInvalid != null || model.getJspIncludeCodes() != null || model.getJspUrlPatterns() != null || model.getJspIncludePreludes() != null) { JspPropertyGroup jspPropertyGroup = new JspPropertyGroup(); JspPropertyGroupDescriptorImpl jspPropertyGroupDescriptor = new JspPropertyGroupDescriptorImpl( jspPropertyGroup); if (jspPropertyGroupDescriptors == null) jspPropertyGroupDescriptors = new ArrayList<>(); jspPropertyGroupDescriptors.add(jspPropertyGroupDescriptor); if (model.getJspIncludeCodes() != null) { for (String includeCoda : model.getJspIncludeCodes()) { jspPropertyGroup.addIncludeCoda(includeCoda); } } if (model.getJspUrlPatterns() != null) { for (String urlPattern : model.getJspUrlPatterns()) { jspPropertyGroup.addUrlPattern(urlPattern); } } if (model.getJspIncludePreludes() != null) { for (String prelude : model.getJspIncludePreludes()) { jspPropertyGroup.addIncludePrelude(prelude); } } if (elIgnored != null) jspPropertyGroup.setElIgnored(elIgnored.toString()); if (isXml != null) jspPropertyGroup.setIsXml(isXml.toString()); if (scriptingInvalid != null) jspPropertyGroup.setScriptingInvalid(scriptingInvalid.toString()); } if (model.getTagLibLocation() != null || model.getTagLibUri() != null) { TaglibDescriptorImpl tagLibDescriptor = new TaglibDescriptorImpl(model.getTagLibLocation(), model.getTagLibUri()); if (taglibs == null) taglibs = new ArrayList<>(); taglibs.add(tagLibDescriptor); } if (jspPropertyGroupDescriptors != null || taglibs != null) { JspConfigDescriptor jspConfig = new JspConfigDescriptorImpl(jspPropertyGroupDescriptors, taglibs); ((Context) context.getServletContext()).setJspConfigDescriptor(jspConfig); } } private Context findContext(final ContextModel contextModel) { return server.findContext(contextModel); } private Context findContext(final Model model) { return findContext(model.getContextModel()); } /** * Returns a list of servlet context attributes out of configured properties * and attribues containing the bundle context associated with the bundle * that created the model (web element). * * @param bundleContext * bundle context to be set as attribute * * @return context attributes map */ private Map<String, Object> getContextAttributes(final BundleContext bundleContext) { final Map<String, Object> attributes = new HashMap<String, Object>(); if (contextAttributes != null) { attributes.putAll(contextAttributes); } attributes.put(WebContainerConstants.BUNDLE_CONTEXT_ATTRIBUTE, bundleContext); attributes.put("org.springframework.osgi.web.org.osgi.framework.BundleContext", bundleContext); return attributes; } @Override public void addWelcomeFiles(WelcomeFileModel model) { final Context context = findOrCreateContext(model.getContextModel()); for (String welcomeFile : model.getWelcomeFiles()) { context.addWelcomeFile(welcomeFile); } } @Override public void removeWelcomeFiles(WelcomeFileModel model) { final Context context = findOrCreateContext(model.getContextModel()); for (String welcomeFile : model.getWelcomeFiles()) { context.removeWelcomeFile(welcomeFile); } } }