View Javadoc

1   /*
2    * $Id: AbstractHttpServlet.java,v 1.4 2005/06/05 08:16:08 cstein Exp $
3    * 
4    * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5    * 
6    * Redistribution and use of this software and associated documentation
7    * ("Software"), with or without modification, are permitted provided that the
8    * following conditions are met:
9    * 
10   * 1. Redistributions of source code must retain copyright statements and
11   * notices. Redistributions must also contain a copy of this document.
12   * 
13   * 2. Redistributions in binary form must reproduce the above copyright notice,
14   * this list of conditions and the following disclaimer in the documentation
15   * and/or other materials provided with the distribution.
16   * 
17   * 3. The name "groovy" must not be used to endorse or promote products derived
18   * from this Software without prior written permission of The Codehaus. For
19   * written permission, please contact info@codehaus.org.
20   * 
21   * 4. Products derived from this Software may not be called "groovy" nor may
22   * "groovy" appear in their names without prior written permission of The
23   * Codehaus. "groovy" is a registered trademark of The Codehaus.
24   * 
25   * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
26   * 
27   * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
28   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
29   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30   * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
31   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
35   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37   *  
38   */
39  package groovy.servlet;
40  
41  import groovy.lang.MetaClass;
42  import groovy.util.ResourceConnector;
43  import groovy.util.ResourceException;
44  
45  import java.io.File;
46  import java.io.IOException;
47  import java.net.URL;
48  import java.net.URLConnection;
49  
50  import javax.servlet.ServletConfig;
51  import javax.servlet.ServletContext;
52  import javax.servlet.ServletException;
53  import javax.servlet.http.HttpServlet;
54  import javax.servlet.http.HttpServletRequest;
55  
56  /***
57   * A common ground dealing with the http servlet API wrinkles.
58   *
59   * @author Christian Stein
60   */
61  public abstract class AbstractHttpServlet extends HttpServlet implements
62      ResourceConnector {
63  
64    /***
65     * Content type of the HTTP response.
66     */
67    public static final String CONTENT_TYPE_TEXT_HTML = "text/html";
68  
69    /***
70     * Servlet API include key name: path_info
71     */
72    public static final String INC_PATH_INFO = "javax.servlet.include.path_info";
73    
74    /* Not used, yet. See comments in getScriptUri(HttpServletRequest request)!
75     * Servlet API include key name: request_uri
76     */
77    // public static final String INC_REQUEST_URI = "javax.servlet.include.request_uri";
78    
79    /***
80     * Servlet API include key name: servlet_path
81     */
82    public static final String INC_SERVLET_PATH = "javax.servlet.include.servlet_path";
83  
84    /***
85     * Debug flag logging the class the class loader of the request.
86     */
87    private boolean logRequestClassAndLoaderOnce;
88    
89    /***
90     * Servlet (or the web application) context.
91     */
92    protected ServletContext servletContext;
93    
94    /***
95     * Initializes all fields.
96     * 
97     */
98    public AbstractHttpServlet() {
99      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 }