blob: 39e44c8fd7ccaea40908072b303cde74a4466400 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006-2007 Cognos Incorporated, IBM Corporation and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cognos Incorporated - initial API and implementation
* IBM Corporation - bug fixes and enhancements
*******************************************************************************/
package org.eclipse.equinox.jsp.jasper;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.equinox.internal.jsp.jasper.JspClassLoader;
import org.osgi.framework.Bundle;
/**
* <p>
* JSPServlet wraps the Apache Jasper Servlet making it appropriate for running in an OSGi environment under the Http Service.
* The Jasper JSPServlet makes use of the Thread Context Classloader to support compile and runtime of JSPs and to accommodate running
* in an OSGi environment, a Bundle is used to provide the similar context normally provided by the webapp.
* </p>
* <p>
* The Jasper Servlet will search the ServletContext to find JSPs, tag library descriptors, and additional information in the web.xml
* as per the JSP 2.0 specification. In addition to the ServletContext this implementation will search the bundle (but not attached
* fragments) for matching resources in a manner consistent with the Http Service's notion of a resource. By using alias and bundleResourcePath the JSP lookup should be in
* line with the resource mapping specified in {102.4} of the OSGi HttpService.
* </p>
* <p>
* TLD discovery is slightly different, to clarify it occurs in one of three ways:
* <ol>
* <li> declarations found in /WEB-INF/web.xml (found either on the bundleResourcePath in the bundle or in the ServletContext)</li>
* <li> tld files found under /WEB-INF (found either on the bundleResourcePath in the bundle or in the ServletContext)</li>
* <li> tld files found in jars on the Bundle-Classpath (see org.eclipse.equinox.internal.jsp.jasper.JSPClassLoader)</li>
* </ol>
* </p>
* <p>
* Other than the setting and resetting of the thread context classloader and additional resource lookups in the bundle the JSPServlet
* is behaviourally consistent with the JSP 2.0 specification and regular Jasper operation.
* </p>
*/
public class JspServlet extends HttpServlet {
private static final long serialVersionUID = -4110476909131707652L;
private Servlet jspServlet = new org.apache.jasper.servlet.JspServlet();
Bundle bundle;
private URLClassLoader jspLoader;
String bundleResourcePath;
String alias;
public JspServlet(Bundle bundle, String bundleResourcePath, String alias) {
this.bundle = bundle;
this.bundleResourcePath = (bundleResourcePath == null || bundleResourcePath.equals("/")) ? "" : bundleResourcePath; //$NON-NLS-1$ //$NON-NLS-2$
this.alias = (alias == null || alias.equals("/")) ? null : alias; //$NON-NLS-1$
jspLoader = new JspClassLoader(bundle);
}
public JspServlet(Bundle bundle, String bundleResourcePath) {
this(bundle, bundleResourcePath, null);
}
public void init(ServletConfig config) throws ServletException {
ClassLoader original = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(jspLoader);
jspServlet.init(new ServletConfigAdaptor(config));
} finally {
Thread.currentThread().setContextClassLoader(original);
}
}
public void destroy() {
ClassLoader original = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(jspLoader);
jspServlet.destroy();
} finally {
Thread.currentThread().setContextClassLoader(original);
}
}
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pathInfo = request.getPathInfo();
if (pathInfo != null && pathInfo.startsWith("/WEB-INF/")) { //$NON-NLS-1$
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
ClassLoader original = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(jspLoader);
jspServlet.service(request, response);
} finally {
Thread.currentThread().setContextClassLoader(original);
}
}
public ServletConfig getServletConfig() {
return jspServlet.getServletConfig();
}
public String getServletInfo() {
return jspServlet.getServletInfo();
}
private class ServletConfigAdaptor implements ServletConfig {
private ServletConfig config;
private ServletContext context;
public ServletConfigAdaptor(ServletConfig config) {
this.config = config;
this.context = new ServletContextAdaptor(config.getServletContext());
}
public String getInitParameter(String arg0) {
return config.getInitParameter(arg0);
}
public Enumeration getInitParameterNames() {
return config.getInitParameterNames();
}
public ServletContext getServletContext() {
return context;
}
public String getServletName() {
return config.getServletName();
}
}
private class ServletContextAdaptor implements ServletContext {
private ServletContext delegate;
public ServletContextAdaptor(ServletContext delegate) {
this.delegate = delegate;
}
public URL getResource(String name) throws MalformedURLException {
if (alias != null && name.startsWith(alias))
name = name.substring(alias.length());
String resourceName = bundleResourcePath + name;
int lastSlash = resourceName.lastIndexOf('/');
if (lastSlash == -1)
return null;
String path = resourceName.substring(0, lastSlash);
if (path.length() == 0)
path = "/"; //$NON-NLS-1$
String file = resourceName.substring(lastSlash + 1);
Enumeration entryPaths = bundle.findEntries(path, file, false);
if (entryPaths != null && entryPaths.hasMoreElements())
return (URL) entryPaths.nextElement();
return delegate.getResource(name);
}
public InputStream getResourceAsStream(String name) {
try {
URL resourceURL = getResource(name);
if (resourceURL != null)
return resourceURL.openStream();
} catch (IOException e) {
log("Error opening stream for resource '" + name + "'", e); //$NON-NLS-1$ //$NON-NLS-2$
}
return null;
}
public Set getResourcePaths(String name) {
Set result = delegate.getResourcePaths(name);
Enumeration e = bundle.findEntries(bundleResourcePath + name, null, false);
if (e != null) {
if (result == null)
result = new HashSet();
while (e.hasMoreElements()) {
URL entryURL = (URL) e.nextElement();
result.add(entryURL.getFile().substring(bundleResourcePath.length()));
}
}
return result;
}
public RequestDispatcher getRequestDispatcher(String arg0) {
return delegate.getRequestDispatcher(arg0);
}
public Object getAttribute(String arg0) {
return delegate.getAttribute(arg0);
}
public Enumeration getAttributeNames() {
return delegate.getAttributeNames();
}
public ServletContext getContext(String arg0) {
return delegate.getContext(arg0);
}
public String getInitParameter(String arg0) {
return delegate.getInitParameter(arg0);
}
public Enumeration getInitParameterNames() {
return delegate.getInitParameterNames();
}
public int getMajorVersion() {
return delegate.getMajorVersion();
}
public String getMimeType(String arg0) {
return delegate.getMimeType(arg0);
}
public int getMinorVersion() {
return delegate.getMinorVersion();
}
public RequestDispatcher getNamedDispatcher(String arg0) {
return delegate.getNamedDispatcher(arg0);
}
public String getRealPath(String arg0) {
return delegate.getRealPath(arg0);
}
public String getServerInfo() {
return delegate.getServerInfo();
}
/** @deprecated **/
public Servlet getServlet(String arg0) throws ServletException {
return delegate.getServlet(arg0);
}
public String getServletContextName() {
return delegate.getServletContextName();
}
/** @deprecated **/
public Enumeration getServletNames() {
return delegate.getServletNames();
}
/** @deprecated **/
public Enumeration getServlets() {
return delegate.getServlets();
}
/** @deprecated **/
public void log(Exception arg0, String arg1) {
delegate.log(arg0, arg1);
}
public void log(String arg0, Throwable arg1) {
delegate.log(arg0, arg1);
}
public void log(String arg0) {
delegate.log(arg0);
}
public void removeAttribute(String arg0) {
delegate.removeAttribute(arg0);
}
public void setAttribute(String arg0, Object arg1) {
delegate.setAttribute(arg0, arg1);
}
// Added in Servlet 2.5
public String getContextPath() {
try {
Method getContextPathMethod = delegate.getClass().getMethod("getContextPath", null); //$NON-NLS-1$
return (String) getContextPathMethod.invoke(delegate, null);
} catch (Exception e) {
// ignore
}
return null;
}
}
}