/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.felix.http.base.internal.service; import static org.apache.felix.http.base.internal.util.UriUtils.decodePath; import static org.apache.felix.http.base.internal.util.UriUtils.removeDotSegments; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Collections; import java.util.Enumeration; import java.util.EventListener; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.Filter; import javax.servlet.FilterRegistration; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletRequestListener; import javax.servlet.SessionCookieConfig; import javax.servlet.SessionTrackingMode; import javax.servlet.descriptor.JspConfigDescriptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionListener; import org.apache.felix.http.base.internal.context.ExtServletContext; import org.apache.felix.http.base.internal.dispatch.RequestDispatcherImpl; import org.apache.felix.http.base.internal.dispatch.RequestInfo; import org.apache.felix.http.base.internal.handler.ServletHandler; import org.apache.felix.http.base.internal.logger.SystemLogger; import org.apache.felix.http.base.internal.registry.PathResolution; import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry; import org.apache.felix.http.base.internal.registry.ServletResolution; import org.apache.felix.http.base.internal.util.MimeTypes; import org.apache.felix.http.base.internal.util.UriUtils; import org.osgi.framework.Bundle; import org.osgi.service.http.HttpContext; @SuppressWarnings("deprecation") public class ServletContextImpl implements ExtServletContext { private final Bundle bundle; private final ServletContext context; private final HttpContext httpContext; private final Map<String, Object> attributes; private final PerContextHandlerRegistry handlerRegistry; public ServletContextImpl(final Bundle bundle, final ServletContext context, final HttpContext httpContext, final boolean sharedAttributes, final PerContextHandlerRegistry registry) { this.bundle = bundle; this.context = context; this.httpContext = httpContext; this.attributes = sharedAttributes ? null : new ConcurrentHashMap<String, Object>(); this.handlerRegistry = registry; } @Override public FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> type) { throw new UnsupportedOperationException(); } @Override public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { throw new UnsupportedOperationException(); } @Override public FilterRegistration.Dynamic addFilter(String filterName, String className) { throw new UnsupportedOperationException(); } @Override public void addListener(Class<? extends EventListener> type) { throw new UnsupportedOperationException(); } @Override public void addListener(String className) { throw new UnsupportedOperationException(); } @Override public <T extends EventListener> void addListener(T listener) { throw new UnsupportedOperationException(); } @Override public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> type) { throw new UnsupportedOperationException(); } @Override public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { throw new UnsupportedOperationException(); } @Override public ServletRegistration.Dynamic addServlet(String servletName, String className) { throw new UnsupportedOperationException(); } @Override public <T extends Filter> T createFilter(Class<T> type) throws ServletException { throw new UnsupportedOperationException(); } @Override public <T extends EventListener> T createListener(Class<T> type) throws ServletException { throw new UnsupportedOperationException(); } @Override public <T extends Servlet> T createServlet(Class<T> type) throws ServletException { throw new UnsupportedOperationException(); } @Override public void declareRoles(String... roleNames) { this.context.declareRoles(roleNames); } @Override public String getVirtualServerName() { return context.getVirtualServerName(); } @Override public Object getAttribute(String name) { return (this.attributes != null) ? this.attributes.get(name) : this.context.getAttribute(name); } @Override public Enumeration<String> getAttributeNames() { return (this.attributes != null) ? Collections.enumeration(this.attributes.keySet()) : this.context.getAttributeNames(); } @Override public ClassLoader getClassLoader() { return bundle.getClass().getClassLoader(); } @Override public ServletContext getContext(String uri) { return this.context.getContext(uri); } @Override public String getContextPath() { return this.context.getContextPath(); } @Override public Set<SessionTrackingMode> getDefaultSessionTrackingModes() { return this.context.getDefaultSessionTrackingModes(); } @Override public int getEffectiveMajorVersion() { return this.context.getEffectiveMajorVersion(); } @Override public int getEffectiveMinorVersion() { return this.context.getEffectiveMinorVersion(); } @Override public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() { return this.context.getEffectiveSessionTrackingModes(); } @Override public FilterRegistration getFilterRegistration(String filterName) { return this.context.getFilterRegistration(filterName); } @Override public Map<String, ? extends FilterRegistration> getFilterRegistrations() { return this.context.getFilterRegistrations(); } @Override public String getInitParameter(String name) { return this.context.getInitParameter(name); } @Override public Enumeration<String> getInitParameterNames() { return this.context.getInitParameterNames(); } @Override public JspConfigDescriptor getJspConfigDescriptor() { throw new UnsupportedOperationException(); } @Override public int getMajorVersion() { return this.context.getMajorVersion(); } @Override public String getMimeType(String file) { String type = this.httpContext.getMimeType(file); if (type != null) { return type; } return MimeTypes.get().getByFile(file); } @Override public int getMinorVersion() { return this.context.getMinorVersion(); } @Override public String getRealPath(String name) { URL url = getResource(name); if (url == null) { return null; } return url.toExternalForm(); } @Override public URL getResource(String path) { return this.httpContext.getResource(normalizeResourcePath(path)); } @Override public InputStream getResourceAsStream(String path) { URL res = getResource(path); if (res != null) { try { return res.openStream(); } catch (IOException e) { // Do nothing } } return null; } @Override public Set<String> getResourcePaths(String path) { Enumeration<String> paths = this.bundle.getEntryPaths(normalizePath(path)); if ((paths == null) || !paths.hasMoreElements()) { return null; } Set<String> set = new HashSet<String>(); while (paths.hasMoreElements()) { set.add(paths.nextElement()); } return set; } @Override public String getServerInfo() { return this.context.getServerInfo(); } @Override public Servlet getServlet(String name) throws ServletException { return this.context.getServlet(name); } @Override public String getServletContextName() { return this.context.getServletContextName(); } @Override public Enumeration<String> getServletNames() { return this.context.getServletNames(); } @Override public ServletRegistration getServletRegistration(String servletName) { return this.context.getServletRegistration(servletName); } @Override public Map<String, ? extends ServletRegistration> getServletRegistrations() { return this.context.getServletRegistrations(); } @Override public Enumeration<Servlet> getServlets() { return this.context.getServlets(); } @Override public SessionCookieConfig getSessionCookieConfig() { return this.context.getSessionCookieConfig(); } @Override public HttpSessionListener getHttpSessionListener() { return this.handlerRegistry.getEventListenerRegistry(); } @Override public HttpSessionAttributeListener getHttpSessionAttributeListener() { return this.handlerRegistry.getEventListenerRegistry(); } @Override public ServletRequestListener getServletRequestListener() { return this.handlerRegistry.getEventListenerRegistry(); } @Override public ServletRequestAttributeListener getServletRequestAttributeListener() { return this.handlerRegistry.getEventListenerRegistry(); } @Override public boolean handleSecurity(HttpServletRequest req, HttpServletResponse res) throws IOException { return this.httpContext.handleSecurity(req, res); } @Override public void log(Exception cause, String message) { SystemLogger.error(message, cause); } @Override public void log(String message) { SystemLogger.info(message); } @Override public void log(String message, Throwable cause) { SystemLogger.error(message, cause); } @Override public void removeAttribute(String name) { Object oldValue; if (this.attributes != null) { oldValue = this.attributes.remove(name); } else { oldValue = this.context.getAttribute(name); this.context.removeAttribute(name); } if (oldValue != null) { this.handlerRegistry.getEventListenerRegistry().attributeRemoved(new ServletContextAttributeEvent(this, name, oldValue)); } } @Override public void setAttribute(String name, Object value) { if (value == null) { this.removeAttribute(name); } else if (name != null) { Object oldValue; if (this.attributes != null) { oldValue = this.attributes.put(name, value); } else { oldValue = this.context.getAttribute(name); this.context.setAttribute(name, value); } if (oldValue == null) { this.handlerRegistry.getEventListenerRegistry().attributeAdded(new ServletContextAttributeEvent(this, name, value)); } else { this.handlerRegistry.getEventListenerRegistry().attributeReplaced(new ServletContextAttributeEvent(this, name, oldValue)); } } } @Override public boolean setInitParameter(String name, String value) { return this.context.setInitParameter(name, value); } @Override public void setSessionTrackingModes(Set<SessionTrackingMode> modes) { this.context.setSessionTrackingModes(modes); } @Override public RequestDispatcher getNamedDispatcher(final String name) { if (name == null) { return null; } final RequestDispatcher dispatcher; final ServletHandler servletHandler = this.handlerRegistry.resolveServletByName(name); if ( servletHandler != null ) { final ServletResolution resolution = new ServletResolution(); resolution.handler = servletHandler; resolution.handlerRegistry = this.handlerRegistry; // TODO - what is the path of a named servlet? final RequestInfo requestInfo = new RequestInfo("", null, null, null); dispatcher = new RequestDispatcherImpl(resolution, requestInfo); } else { dispatcher = null; } return dispatcher; } @Override public RequestDispatcher getRequestDispatcher(String path) { // See section 9.1 of Servlet 3.x specification... if (path == null || (!path.startsWith("/") && !"".equals(path))) { return null; } String query = null; int q = 0; if ((q = path.indexOf('?')) > 0) { query = path.substring(q + 1); path = path.substring(0, q); } // TODO remove path parameters... final String encodedRequestURI = path == null ? "" : removeDotSegments(path); final String requestURI = decodePath(encodedRequestURI); final RequestDispatcher dispatcher; final PathResolution pathResolution = this.handlerRegistry.resolve(requestURI); if ( pathResolution != null ) { final ServletResolution resolution = new ServletResolution(); resolution.handler = pathResolution.handler; resolution.handlerRegistry = this.handlerRegistry; final RequestInfo requestInfo = new RequestInfo(pathResolution.servletPath, pathResolution.pathInfo, query, UriUtils.concat(this.getContextPath(), encodedRequestURI)); dispatcher = new RequestDispatcherImpl(resolution, requestInfo); } else { dispatcher = null; } return dispatcher; } private String normalizePath(String path) { if (path == null) { return null; } String normalizedPath = normalizeResourcePath(path); if (normalizedPath.startsWith("/") && (normalizedPath.length() > 1)) { normalizedPath = normalizedPath.substring(1); } return normalizedPath; } private String normalizeResourcePath(String path) { if ( path == null) { return null; } String normalizedPath = path.trim().replaceAll("/+", "/"); return normalizedPath; } }