001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.servlet;
018:
019: import java.io.File;
020: import java.io.InputStream;
021: import java.net.MalformedURLException;
022: import java.net.URL;
023: import java.util.Enumeration;
024: import java.util.Set;
025:
026: import javax.servlet.RequestDispatcher;
027: import javax.servlet.Servlet;
028: import javax.servlet.ServletConfig;
029: import javax.servlet.ServletContext;
030: import javax.servlet.ServletException;
031:
032: /**
033: * A bootstrap servlet to allow Cocoon to run in servlet engines that aren't fully
034: * compliant with the servlet 2.2 spec.
035: * <p>
036: * This servlet adds a mandatory "context-dir" parameter to those accepted by {@link CocoonServlet},
037: * which should point to Cocoon's context directory (e.g. "<code>/path-to-webapp/cocoon</code>").
038: * This directory is used to :
039: * <ul>
040: * <li>build a classloader with the correct class path with the contents of
041: * <code>WEB-INF/classes</code> and <code>WEB-INF/lib</code> (see
042: * {@link ParanoidClassLoader}),</li>
043: * <li>resolve paths for context resources.
044: * </ul>
045: *
046: * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
047: * @version CVS $Id: BootstrapServlet.java 433543 2006-08-22 06:22:54Z crossley $
048: */
049:
050: public class BootstrapServlet extends ParanoidCocoonServlet {
051:
052: protected File contextDir;
053:
054: protected File getContextDir() throws ServletException {
055:
056: ServletContext context = getServletContext();
057: ServletConfig config = getServletConfig();
058:
059: log("getRealPath(\"/\") = " + context.getRealPath("/"));
060:
061: String contextDirParam = config
062: .getInitParameter("context-directory");
063:
064: if (contextDirParam == null) {
065: throw new ServletException(
066: "The 'context-directory' parameter must be set to the root of the servlet context");
067: }
068:
069: // Ensure context dir doesn't end with a "/" (servlet spec says that paths for
070: // getResource() should start by a "/")
071: if (contextDirParam.endsWith("/")) {
072: contextDirParam = contextDirParam.substring(0,
073: contextDirParam.length() - 1);
074: }
075:
076: // Ensure context dir exists and is a directory
077: this .contextDir = new File(contextDirParam);
078: if (!this .contextDir.exists()) {
079: String msg = "Context dir '" + this .contextDir
080: + "' doesn't exist";
081: log(msg);
082: throw new ServletException(msg);
083: }
084:
085: if (!this .contextDir.isDirectory()) {
086: String msg = "Context dir '" + this .contextDir
087: + "' should be a directory";
088: log(msg);
089: throw new ServletException(msg);
090: }
091:
092: context.log("Context dir set to " + this .contextDir);
093:
094: return this .contextDir;
095: }
096:
097: protected void initServlet() throws ServletException {
098:
099: ServletContext newContext = new ContextWrapper(
100: getServletContext(), this .contextDir);
101: ServletConfig newConfig = new ConfigWrapper(getServletConfig(),
102: newContext);
103:
104: this .servlet.init(newConfig);
105: }
106:
107: //-------------------------------------------------------------------------
108: /**
109: * Implementation of <code>ServletConfig</code> passed to the actual servlet.
110: * It wraps the original config object and returns the new context.
111: */
112: public static class ConfigWrapper implements ServletConfig {
113: ServletConfig config;
114: ServletContext context;
115:
116: /**
117: * Builds a <code>ServletConfig</code> using a servlet name and
118: * a <code>ServletContext</code>.
119: */
120: public ConfigWrapper(ServletConfig config,
121: ServletContext context) {
122: this .config = config;
123: this .context = context;
124: }
125:
126: public String getServletName() {
127: return config.getServletName();
128: }
129:
130: public Enumeration getInitParameterNames() {
131: return this .config.getInitParameterNames();
132: }
133:
134: public ServletContext getServletContext() {
135: return this .context;
136: }
137:
138: public String getInitParameter(String name) {
139: return config.getInitParameter(name);
140: }
141: }
142:
143: //-------------------------------------------------------------------------
144: /**
145: * Wrapper for the <code>ServletContext</code> passed to the actual servlet.
146: * It implements all resource-related methods using the provided context
147: * root directory. Other calls are delegated to the wrapped context.
148: */
149: public static class ContextWrapper implements ServletContext {
150: ServletContext context;
151: File contextRoot;
152:
153: /**
154: * Builds a wrapper around an existing context, and handle all
155: * resource resolution relatively to <code>contextRoot</code>
156: */
157: public ContextWrapper(ServletContext context, File contextRoot) {
158: this .context = context;
159: this .contextRoot = contextRoot;
160: }
161:
162: public ServletContext getContext(String param) {
163: return this .context.getContext(param);
164: }
165:
166: public int getMajorVersion() {
167: return this .context.getMajorVersion();
168: }
169:
170: public int getMinorVersion() {
171: return this .context.getMinorVersion();
172: }
173:
174: public String getMimeType(String param) {
175: return this .context.getMimeType(param);
176: }
177:
178: /**
179: * Returns the resource URL by appending <code>path</code> to the context
180: * root. If this doesn't point to an existing file, <code>null</code> is
181: * returned.
182: */
183: public URL getResource(String path)
184: throws MalformedURLException {
185: File file = new File(this .contextRoot, path);
186: if (file.exists()) {
187: URL result = file.toURL();
188: //this.context.log("getResource(" + path + ") = " + result);
189: return result;
190: } else {
191: //this.context.log("getResource(" + path + ") = null");
192: return null;
193: }
194: }
195:
196: /**
197: * Returns the stream for the result of <code>getResource()</code>, or
198: * <code>null</code> if the resource doesn't exist.
199: */
200: public InputStream getResourceAsStream(String path) {
201: try {
202: URL url = getResource(path);
203: return (url == null) ? null : url.openStream();
204: } catch (Exception e) {
205: this .context.log("getResourceAsStream(" + path
206: + ") failed", e);
207: return null;
208: }
209: }
210:
211: public RequestDispatcher getRequestDispatcher(String param) {
212: return this .context.getRequestDispatcher(param);
213: }
214:
215: public RequestDispatcher getNamedDispatcher(String param) {
216: return this .context.getNamedDispatcher(param);
217: }
218:
219: /**
220: * @deprecated The method BootstrapServlet.ContextWrapper.getServlet(String)
221: * overrides a deprecated method from ServletContext.
222: * @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>
223: */
224: public Servlet getServlet(String param) throws ServletException {
225: return this .context.getServlet(param);
226: }
227:
228: /**
229: * @deprecated The method BootstrapServlet.ContextWrapper.getServlets()
230: * overrides a deprecated method from ServletContext.
231: * @see <a href="http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/ServletContext.html#getServlets()">ServletContext#getServlets()</a>
232: */
233: public Enumeration getServlets() {
234: return this .context.getServlets();
235: }
236:
237: /**
238: * @deprecated The method BootstrapServlet.ContextWrapper.getServletNames()
239: * overrides a deprecated method from ServletContext.
240: * @see <a href="http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/ServletContext.html#getServletNames()">ServletContext#getServletNames()</a>
241: */
242: public Enumeration getServletNames() {
243: return this .context.getServletNames();
244: }
245:
246: public void log(String msg) {
247: this .context.log(msg);
248: }
249:
250: /** @deprecated use {@link #log(String message, Throwable throwable)} instead. */
251: public void log(Exception ex, String msg) {
252: this .context.log(ex, msg);
253: }
254:
255: public void log(String msg, Throwable thr) {
256: this .context.log(msg, thr);
257: }
258:
259: /**
260: * Appends <code>path</code> to the context root.
261: */
262: public String getRealPath(String path) {
263: String result = this .contextRoot + path;
264: //this.context.log("getRealPath(" + path + ") = " + result);
265: return result;
266: }
267:
268: public String getServerInfo() {
269: return this .context.getServerInfo();
270: }
271:
272: public String getInitParameter(String param) {
273: return this .context.getInitParameter(param);
274: }
275:
276: public Enumeration getInitParameterNames() {
277: return this .context.getInitParameterNames();
278: }
279:
280: public Object getAttribute(String param) {
281: Object result = this .context.getAttribute(param);
282: //this.context.log("getAttribute(" + param + ") = " + result);
283: return result;
284: }
285:
286: public Enumeration getAttributeNames() {
287: return this .context.getAttributeNames();
288: }
289:
290: public void setAttribute(String name, Object value) {
291: this .context.setAttribute(name, value);
292: }
293:
294: public void removeAttribute(String name) {
295: this .context.removeAttribute(name);
296: }
297:
298: // Implementation of Servlet 2.3 methods. This is not absolutely required
299: // for real usage since this servlet is targeted at 2.2, but is needed
300: // for successful compilation
301: public Set getResourcePaths(String param) {
302: return null;
303: }
304:
305: public String getServletContextName() {
306: return "Cocoon context";
307: }
308: }
309: }
|