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 }