KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > groovy > servlet > GroovyServlet


1 /*
2  * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
3  *
4  * Redistribution and use of this software and associated documentation
5  * ("Software"), with or without modification, are permitted provided that the
6  * following conditions are met: 1. Redistributions of source code must retain
7  * copyright statements and notices. Redistributions must also contain a copy
8  * of this document. 2. Redistributions in binary form must reproduce the above
9  * copyright notice, this list of conditions and the following disclaimer in
10  * the documentation and/or other materials provided with the distribution. 3.
11  * The name "groovy" must not be used to endorse or promote products derived
12  * from this Software without prior written permission of The Codehaus. For
13  * written permission, please contact info@codehaus.org. 4. Products derived
14  * from this Software may not be called "groovy" nor may "groovy" appear in
15  * their names without prior written permission of The Codehaus. "groovy" is a
16  * registered trademark of The Codehaus. 5. Due credit should be given to The
17  * Codehaus - http://groovy.codehaus.org/
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
20  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29  * DAMAGE.
30  *
31  */

32 package groovy.servlet;
33
34 import groovy.lang.Binding;
35 import groovy.lang.MetaClass;
36 import groovy.lang.Closure;
37 import groovy.util.GroovyScriptEngine;
38 import groovy.util.ResourceConnector;
39 import groovy.util.ResourceException;
40 import groovy.util.ScriptException;
41
42 import java.io.IOException JavaDoc;
43 import java.net.URL JavaDoc;
44 import java.net.URLConnection JavaDoc;
45 import java.util.Collections JavaDoc;
46 import java.util.Enumeration JavaDoc;
47 import java.util.HashMap JavaDoc;
48 import java.util.Map JavaDoc;
49
50 import javax.servlet.ServletConfig JavaDoc;
51 import javax.servlet.ServletContext JavaDoc;
52 import javax.servlet.ServletException JavaDoc;
53 import javax.servlet.ServletRequest JavaDoc;
54 import javax.servlet.ServletResponse JavaDoc;
55 import javax.servlet.http.HttpServlet JavaDoc;
56 import javax.servlet.http.HttpServletRequest JavaDoc;
57 import javax.servlet.http.HttpServletResponse JavaDoc;
58
59 import org.codehaus.groovy.runtime.GroovyCategorySupport;
60
61 /**
62  * This servlet will run Groovy scripts as Groovlets. Groovlets are scripts
63  * with these objects implicit in their scope:
64  *
65  * <ul>
66  * <li>request - the HttpServletRequest</li>
67  * <li>response - the HttpServletResponse</li>
68  * <li>application - the ServletContext associated with the servlet</li>
69  * <li>session - the HttpSession associated with the HttpServletRequest</li>
70  * <li>out - the PrintWriter associated with the ServletRequest</li>
71  * </ul>
72  *
73  * <p>Your script sources can be placed either in your web application's normal
74  * web root (allows for subdirectories) or in /WEB-INF/groovy/* (also allows
75  * subdirectories).
76  *
77  * <p>To make your web application more groovy, you must add the GroovyServlet
78  * to your application's web.xml configuration using any mapping you like, so
79  * long as it follows the pattern *.* (more on this below). Here is the
80  * web.xml entry:
81  *
82  * <pre>
83  * <servlet>
84  * <servlet-name>Groovy</servlet-name>
85  * <servlet-class>groovy.servlet.GroovyServlet</servlet-class>
86  * </servlet>
87  *
88  * <servlet-mapping>
89  * <servlet-name>Groovy</servlet-name>
90  * <url-pattern>*.groovy</url-pattern>
91  * </servlet-mapping>
92  * </pre>
93  *
94  * <p>The URL pattern does not require the "*.groovy" mapping. You can, for
95  * example, make it more Struts-like but groovy by making your mapping "*.gdo".
96  *
97  * <p>Whatever your mapping, the GroovyServlet will check to see if your
98  * URL ends with ".groovy" and, if it does not, it will strip your mapping
99  * and append ".groovy".
100  *
101  * <p>NOTE! The GroovyServlet only handles mappings of the *.* type, not the
102  * path-like type of /groovy/*</p>
103  *
104  * @author Sam Pullara
105  * @author Mark Turansky (markturansky at hotmail.com)
106  * @author Guillaume Laforge
107  */

108 public class GroovyServlet extends HttpServlet JavaDoc implements ResourceConnector {
109
110     // ------------------------------------------------------ instance variables
111

112     /**
113      * A constant for ".groovy" which gets appended to script paths as needed.
114      */

115     public static final String JavaDoc GROOVY_EXTENSION = ".groovy";
116
117     /**
118      * The context in which this servlet is executing
119      */

120     private ServletContext JavaDoc sc;
121
122     /**
123      * The classloader associated with this servlet
124      */

125     private static ClassLoader JavaDoc parent;
126
127     /**
128      * The script engine executing the Groovy scripts for this servlet
129      */

130     private static GroovyScriptEngine gse;
131
132     // ---------------------------------------------------------- public methods
133

134     /**
135      * Returns the ServletContext for this servlet
136      */

137     public ServletContext JavaDoc getServletContext() {
138         return sc;
139     }
140
141     /**
142      * Initialize the GroovyServlet.
143      */

144     public void init(ServletConfig JavaDoc config) {
145
146         // Use reflection, some containers don't load classes properly
147
MetaClass.setUseReflection(true);
148
149         // Get the servlet context
150
sc = config.getServletContext();
151         sc.log("Groovy servlet initialized");
152
153         // Ensure that we use the correct classloader so that we can find
154
// classes in an application server.
155
parent = Thread.currentThread().getContextClassLoader();
156         if (parent == null)
157             parent = GroovyServlet.class.getClassLoader();
158
159         // Set up the scripting engine
160
gse = new GroovyScriptEngine(this);
161     }
162
163     /**
164      * Interface method for ResourceContainer. This is used by the GroovyScriptEngine.
165      */

166     public URLConnection JavaDoc getResourceConnection(String JavaDoc name) throws ResourceException {
167         try {
168             URL JavaDoc url = sc.getResource("/" + name);
169             if (url == null) {
170                 url = sc.getResource("/WEB-INF/groovy/" + name);
171                 if (url == null) {
172                     throw new ResourceException("Resource " + name + " not found");
173                 }
174             }
175             return url.openConnection();
176         } catch (IOException JavaDoc ioe) {
177             throw new ResourceException("Problem reading resource " + name);
178         }
179     }
180
181     /**
182      * Handle web requests to the GroovyServlet
183      */

184     public void service(ServletRequest JavaDoc request, ServletResponse JavaDoc response)
185         throws ServletException JavaDoc, IOException JavaDoc {
186
187         // Convert the generic servlet request and response to their Http versions
188
final HttpServletRequest JavaDoc httpRequest = (HttpServletRequest JavaDoc) request;
189         final HttpServletResponse JavaDoc httpResponse = (HttpServletResponse JavaDoc) response;
190
191         // get the script path from the request
192
final String JavaDoc scriptFilename = getGroovyScriptPath(httpRequest);
193
194         // Set it to HTML by default
195
response.setContentType("text/html");
196
197         // Set up the script context
198
final Binding binding = new ServletBinding((HttpServletRequest JavaDoc) request, response, sc);
199
200         // Run the script
201
try {
202             Closure closure = new Closure(gse) {
203                 public Object JavaDoc call() {
204                     try {
205                         return ((GroovyScriptEngine)getDelegate()).run(scriptFilename, binding);
206                     } catch (ResourceException e) {
207                         throw new RuntimeException JavaDoc(e);
208                     } catch (ScriptException e) {
209                         throw new RuntimeException JavaDoc(e);
210                     }
211                 }
212             };
213             GroovyCategorySupport.use(ServletCategory.class, closure);
214         } catch (RuntimeException JavaDoc re) {
215
216             StringBuffer JavaDoc error = new StringBuffer JavaDoc("GroovyServlet Error: ");
217             error.append(" script: '");
218             error.append(scriptFilename);
219             error.append("': ");
220
221             Throwable JavaDoc e = re.getCause();
222             if (e instanceof ResourceException) {
223                 error.append(" Script not found, sending 404.");
224                 sc.log(error.toString());
225                 System.out.println(error.toString());
226                 httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
227             } else {
228
229                 // write the script errors (if any) to the servlet context's log
230
if (re.getMessage() != null)
231                     error.append(re.getMessage());
232
233                 if (e != null) {
234                     sc.log("An error occurred processing the request", e);
235                 } else {
236                     sc.log("An error occurred processing the request", re);
237                 }
238                 sc.log(error.toString());
239                 System.out.println(error.toString());
240
241                 httpResponse.sendError(
242                     HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
243             }
244         }
245     }
246
247     // --------------------------------------------------------- private methods
248

249     /**
250      * From the HttpServletRequest, parse the groovy script path using the URL,
251      * adding the extension ".groovy" as needed.
252      */

253     private String JavaDoc getGroovyScriptPath(HttpServletRequest JavaDoc request) {
254
255         // Get the name of the Groovy script
256
int contextLength = request.getContextPath().length();
257         String JavaDoc scriptFilename = request.getRequestURI()
258             .substring(contextLength).substring(1);
259
260         // if the servlet mapping is .groovy, we don't need to strip the mapping from the filename.
261
// if the mapping is anything else, we need to strip it and append .groovy
262
if (scriptFilename.endsWith(GROOVY_EXTENSION))
263             return scriptFilename;
264
265         // strip the servlet mapping (from the last ".") and append .groovy
266
int lastDot = scriptFilename.lastIndexOf(".");
267         scriptFilename = scriptFilename.substring(0, lastDot)
268             + GROOVY_EXTENSION;
269         return scriptFilename;
270
271     }
272 }
273
Popular Tags