blob: 6bdfab05e42ca097c9900a52c0d1b02ffafa2366 [file] [log] [blame]
/*
* 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.cocoon.servlet;
import java.io.File;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Set;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
/**
* A bootstrap servlet to allow Cocoon to run in servlet engines that aren't fully
* compliant with the servlet 2.2 spec.
* <p>
* This servlet adds a mandatory "context-dir" parameter to those accepted by {@link CocoonServlet},
* which should point to Cocoon's context directory (e.g. "<code>/path-to-webapp/cocoon</code>").
* This directory is used to :
* <ul>
* <li>build a classloader with the correct class path with the contents of
* <code>WEB-INF/classes</code> and <code>WEB-INF/lib</code> (see
* {@link ParanoidClassLoader}),</li>
* <li>resolve paths for context resources.
* </ul>
*
* @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
* @version CVS $Id$
*/
public class BootstrapServlet extends ParanoidCocoonServlet {
protected File contextDir;
protected File getContextDir() throws ServletException {
ServletContext context = getServletContext();
ServletConfig config = getServletConfig();
log("getRealPath(\"/\") = " + context.getRealPath("/"));
String contextDirParam = config.getInitParameter("context-directory");
if (contextDirParam == null) {
throw new ServletException("The 'context-directory' parameter must be set to the root of the servlet context");
}
// Ensure context dir doesn't end with a "/" (servlet spec says that paths for
// getResource() should start by a "/")
if (contextDirParam.endsWith("/")) {
contextDirParam = contextDirParam.substring(0, contextDirParam.length() - 1);
}
// Ensure context dir exists and is a directory
this.contextDir = new File(contextDirParam);
if (!this.contextDir.exists()) {
String msg = "Context dir '" + this.contextDir + "' doesn't exist";
log(msg);
throw new ServletException(msg);
}
if (!this.contextDir.isDirectory()) {
String msg = "Context dir '" + this.contextDir + "' should be a directory";
log(msg);
throw new ServletException(msg);
}
context.log("Context dir set to " + this.contextDir);
return this.contextDir;
}
protected void initServlet() throws ServletException {
ServletContext newContext = new ContextWrapper(getServletContext(), this.contextDir);
ServletConfig newConfig = new ConfigWrapper(getServletConfig(), newContext);
this.servlet.init(newConfig);
}
//-------------------------------------------------------------------------
/**
* Implementation of <code>ServletConfig</code> passed to the actual servlet.
* It wraps the original config object and returns the new context.
*/
public static class ConfigWrapper implements ServletConfig {
ServletConfig config;
ServletContext context;
/**
* Builds a <code>ServletConfig</code> using a servlet name and
* a <code>ServletContext</code>.
*/
public ConfigWrapper(ServletConfig config, ServletContext context) {
this.config = config;
this.context = context;
}
public String getServletName() {
return config.getServletName();
}
public Enumeration getInitParameterNames() {
return this.config.getInitParameterNames();
}
public ServletContext getServletContext() {
return this.context;
}
public String getInitParameter(String name) {
return config.getInitParameter(name);
}
}
//-------------------------------------------------------------------------
/**
* Wrapper for the <code>ServletContext</code> passed to the actual servlet.
* It implements all resource-related methods using the provided context
* root directory. Other calls are delegated to the wrapped context.
*/
public static class ContextWrapper implements ServletContext {
ServletContext context;
File contextRoot;
/**
* Builds a wrapper around an existing context, and handle all
* resource resolution relatively to <code>contextRoot</code>
*/
public ContextWrapper(ServletContext context, File contextRoot) {
this.context = context;
this.contextRoot = contextRoot;
}
public ServletContext getContext(String param) {
return this.context.getContext(param);
}
public int getMajorVersion() {
return this.context.getMajorVersion();
}
public int getMinorVersion() {
return this.context.getMinorVersion();
}
public String getMimeType(String param) {
return this.context.getMimeType(param);
}
/**
* Returns the resource URL by appending <code>path</code> to the context
* root. If this doesn't point to an existing file, <code>null</code> is
* returned.
*/
public URL getResource(String path) throws MalformedURLException {
File file = new File(this.contextRoot, path);
if (file.exists()) {
URL result = file.toURL();
//this.context.log("getResource(" + path + ") = " + result);
return result;
} else {
//this.context.log("getResource(" + path + ") = null");
return null;
}
}
/**
* Returns the stream for the result of <code>getResource()</code>, or
* <code>null</code> if the resource doesn't exist.
*/
public InputStream getResourceAsStream(String path) {
try {
URL url = getResource(path);
return (url == null) ? null : url.openStream();
} catch(Exception e) {
this.context.log("getResourceAsStream(" + path + ") failed", e);
return null;
}
}
public RequestDispatcher getRequestDispatcher(String param) {
return this.context.getRequestDispatcher(param);
}
public RequestDispatcher getNamedDispatcher(String param) {
return this.context.getNamedDispatcher(param);
}
/**
* @deprecated The method BootstrapServlet.ContextWrapper.getServlet(String)
* overrides a deprecated method from ServletContext.
* @see <a href="http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/ServletContext.html#getServlet(java.lang.String)">ServletContext#getServlet(java.lang.String)</a>
*/
public Servlet getServlet(String param) throws ServletException {
return this.context.getServlet(param);
}
/**
* @deprecated The method BootstrapServlet.ContextWrapper.getServlets()
* overrides a deprecated method from ServletContext.
* @see <a href="http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/ServletContext.html#getServlets()">ServletContext#getServlets()</a>
*/
public Enumeration getServlets() {
return this.context.getServlets();
}
/**
* @deprecated The method BootstrapServlet.ContextWrapper.getServletNames()
* overrides a deprecated method from ServletContext.
* @see <a href="http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/ServletContext.html#getServletNames()">ServletContext#getServletNames()</a>
*/
public Enumeration getServletNames() {
return this.context.getServletNames();
}
public void log(String msg) {
this.context.log(msg);
}
/** @deprecated use {@link #log(String message, Throwable throwable)} instead. */
public void log(Exception ex, String msg) {
this.context.log(ex, msg);
}
public void log(String msg, Throwable thr) {
this.context.log(msg, thr);
}
/**
* Appends <code>path</code> to the context root.
*/
public String getRealPath(String path) {
String result = this.contextRoot + path;
//this.context.log("getRealPath(" + path + ") = " + result);
return result;
}
public String getServerInfo() {
return this.context.getServerInfo();
}
public String getInitParameter(String param) {
return this.context.getInitParameter(param);
}
public Enumeration getInitParameterNames() {
return this.context.getInitParameterNames();
}
public Object getAttribute(String param) {
Object result = this.context.getAttribute(param);
//this.context.log("getAttribute(" + param + ") = " + result);
return result;
}
public Enumeration getAttributeNames() {
return this.context.getAttributeNames();
}
public void setAttribute(String name, Object value) {
this.context.setAttribute(name, value);
}
public void removeAttribute(String name) {
this.context.removeAttribute(name);
}
// Implementation of Servlet 2.3 methods. This is not absolutely required
// for real usage since this servlet is targeted at 2.2, but is needed
// for successful compilation
public Set getResourcePaths(String param) {
return null;
}
public String getServletContextName() {
return "Cocoon context";
}
}
}