001 /*
002 * $Id: AbstractHttpServlet.java,v 1.4 2005/06/05 08:16:08 cstein Exp $
003 *
004 * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005 *
006 * Redistribution and use of this software and associated documentation
007 * ("Software"), with or without modification, are permitted provided that the
008 * following conditions are met:
009 *
010 * 1. Redistributions of source code must retain copyright statements and
011 * notices. Redistributions must also contain a copy of this document.
012 *
013 * 2. Redistributions in binary form must reproduce the above copyright notice,
014 * this list of conditions and the following disclaimer in the documentation
015 * and/or other materials provided with the distribution.
016 *
017 * 3. The name "groovy" must not be used to endorse or promote products derived
018 * from this Software without prior written permission of The Codehaus. For
019 * written permission, please contact info@codehaus.org.
020 *
021 * 4. Products derived from this Software may not be called "groovy" nor may
022 * "groovy" appear in their names without prior written permission of The
023 * Codehaus. "groovy" is a registered trademark of The Codehaus.
024 *
025 * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
026 *
027 * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
028 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
029 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
030 * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
031 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
032 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
033 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
034 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
035 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
036 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037 *
038 */
039 package groovy.servlet;
040
041 import groovy.lang.MetaClass;
042 import groovy.util.ResourceConnector;
043 import groovy.util.ResourceException;
044
045 import java.io.File;
046 import java.io.IOException;
047 import java.net.URL;
048 import java.net.URLConnection;
049
050 import javax.servlet.ServletConfig;
051 import javax.servlet.ServletContext;
052 import javax.servlet.ServletException;
053 import javax.servlet.http.HttpServlet;
054 import javax.servlet.http.HttpServletRequest;
055
056 /**
057 * A common ground dealing with the http servlet API wrinkles.
058 *
059 * @author Christian Stein
060 */
061 public abstract class AbstractHttpServlet extends HttpServlet implements
062 ResourceConnector {
063
064 /**
065 * Content type of the HTTP response.
066 */
067 public static final String CONTENT_TYPE_TEXT_HTML = "text/html";
068
069 /**
070 * Servlet API include key name: path_info
071 */
072 public static final String INC_PATH_INFO = "javax.servlet.include.path_info";
073
074 /* Not used, yet. See comments in getScriptUri(HttpServletRequest request)!
075 * Servlet API include key name: request_uri
076 */
077 // public static final String INC_REQUEST_URI = "javax.servlet.include.request_uri";
078
079 /**
080 * Servlet API include key name: servlet_path
081 */
082 public static final String INC_SERVLET_PATH = "javax.servlet.include.servlet_path";
083
084 /**
085 * Debug flag logging the class the class loader of the request.
086 */
087 private boolean logRequestClassAndLoaderOnce;
088
089 /**
090 * Servlet (or the web application) context.
091 */
092 protected ServletContext servletContext;
093
094 /**
095 * Initializes all fields.
096 *
097 */
098 public AbstractHttpServlet() {
099 this.logRequestClassAndLoaderOnce = true;
100 this.servletContext = null;
101 }
102
103 /**
104 * Interface method for ResourceContainer. This is used by the GroovyScriptEngine.
105 */
106 public URLConnection getResourceConnection(String name)
107 throws ResourceException {
108 try {
109 URL url = servletContext.getResource("/" + name);
110 if (url == null) {
111 url = servletContext.getResource("/WEB-INF/groovy/" + name);
112 if (url == null) {
113 throw new ResourceException("Resource " + name + " not found");
114 }
115 }
116 return url.openConnection();
117 }
118 catch (IOException ioe) {
119 throw new ResourceException("Problem reading resource " + name);
120 }
121 }
122
123 /**
124 * Returns the include-aware uri of the script or template file.
125 *
126 * @param request
127 * the http request to analyze
128 * @return the include-aware uri either parsed from request attributes or
129 * hints provided by the servlet container
130 */
131 protected String getScriptUri(HttpServletRequest request) {
132 //
133 if (logRequestClassAndLoaderOnce) {
134 log("Logging request class and its class loader:");
135 log(" c = request.getClass() :\"" + request.getClass()+ "\"");
136 log(" l = c.getClassLoader() :\"" + request.getClass().getClassLoader()+ "\"");
137 log(" l.getClass() :\"" + request.getClass().getClassLoader().getClass()+ "\"");
138 logRequestClassAndLoaderOnce = false;
139 }
140
141 //
142 // NOTE: This piece of code is heavily inspired by Apaches Jasper2!
143 //
144 // http://cvs.apache.org/viewcvs.cgi/jakarta-tomcat-jasper/jasper2/ \
145 // src/share/org/apache/jasper/servlet/JspServlet.java?view=markup
146 //
147 // Why doesn't it use request.getRequestURI() or INC_REQUEST_URI?
148 //
149
150 String uri = null;
151 String info = null;
152
153 //
154 // Check to see if the requested script/template source file has been the
155 // target of a RequestDispatcher.include().
156 //
157 uri = (String) request.getAttribute(INC_SERVLET_PATH);
158 if (uri != null) {
159 //
160 // Requested script/template file has been target of
161 // RequestDispatcher.include(). Its path is assembled from the relevant
162 // javax.servlet.include.* request attributes and returned!
163 //
164 info = (String) request.getAttribute(INC_PATH_INFO);
165 if (info != null) {
166 uri += info;
167 }
168 return uri;
169 }
170
171 //
172 // Requested script/template file has not been the target of a
173 // RequestDispatcher.include(). Reconstruct its path from the request's
174 // getServletPath() and getPathInfo() results.
175 //
176 uri = request.getServletPath();
177 info = request.getPathInfo();
178 if (info != null) {
179 uri += info;
180 }
181
182 return uri;
183 }
184
185 /**
186 * Parses the http request for the real script or template source file.
187 *
188 * @param request
189 * the http request to analyze
190 * @param context
191 * the context of this servlet used to get the real path string
192 * @return a file object using an absolute file path name
193 */
194 protected File getScriptUriAsFile(HttpServletRequest request) {
195 String uri = getScriptUri(request);
196 String real = servletContext.getRealPath(uri);
197 File file = new File(real).getAbsoluteFile();
198
199 // log("\tInclude-aware URI: " + uri);
200 // log("\tContext real path: " + real); // context.getRealPath(uri)
201 // log("\t File: " + file);
202 // log("\t File exists? " + file.exists());
203 // log("\t File can read? " + file.canRead());
204 // log("\t ServletPath: " + request.getServletPath());
205 // log("\t PathInfo: " + request.getPathInfo());
206 // log("\t RequestURI: " + request.getRequestURI());
207 // log("\t QueryString: " + request.getQueryString());
208
209 // //log("\t Request Params: ");
210 // //Enumeration e = request.getParameterNames();
211 // //while (e.hasMoreElements()) {
212 // // String name = (String) e.nextElement();
213 // // log("\t\t " + name + " = " + request.getParameter(name));
214 // //}
215
216 return file;
217 }
218
219 /**
220 * Overrides the generic init method.
221 *
222 * Enables a fix, that tells Groovy to use (slower) reflection than compiling
223 * metaclass proxies. This is needed due to some container implementation hide
224 * their classes from the servlet by using different class loaders. See
225 * {@link http://jira.codehaus.org/browse/GROOVY-861} for details.
226 *
227 * @param config
228 * the servlet coniguration provided by the container
229 * @throws ServletException if init() method defined in super class
230 * javax.servlet.GenericServlet throws it
231 */
232 public void init(ServletConfig config) throws ServletException {
233 super.init(config);
234 this.servletContext = config.getServletContext();
235
236 // FIXME http://jira.codehaus.org/browse/GROOVY-861
237 MetaClass.setUseReflection(true);
238 String value = config.getInitParameter("logRequestClassAndLoaderOnce");
239 if (value != null) {
240 this.logRequestClassAndLoaderOnce = Boolean.valueOf(value).booleanValue();
241 }
242
243 }
244
245 }