View Javadoc

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.Closure;
36  import groovy.util.GroovyScriptEngine;
37  import groovy.util.ResourceException;
38  import groovy.util.ScriptException;
39  
40  import java.io.IOException;
41  
42  import javax.servlet.ServletConfig;
43  import javax.servlet.ServletException;
44  import javax.servlet.http.HttpServletRequest;
45  import javax.servlet.http.HttpServletResponse;
46  
47  import org.codehaus.groovy.runtime.GroovyCategorySupport;
48  
49  /***
50   * This servlet will run Groovy scripts as Groovlets.  Groovlets are scripts
51   * with these objects implicit in their scope:
52   *
53   * <ul>
54   * 	<li>request - the HttpServletRequest</li>
55   *  <li>response - the HttpServletResponse</li>
56   *  <li>application - the ServletContext associated with the servlet</li>
57   *  <li>session - the HttpSession associated with the HttpServletRequest</li>
58   *  <li>out - the PrintWriter associated with the ServletRequest</li>
59   * </ul>
60   *
61   * <p>Your script sources can be placed either in your web application's normal
62   * web root (allows for subdirectories) or in /WEB-INF/groovy/* (also allows
63   * subdirectories).
64   *
65   * <p>To make your web application more groovy, you must add the GroovyServlet
66   * to your application's web.xml configuration using any mapping you like, so
67   * long as it follows the pattern *.* (more on this below).  Here is the
68   * web.xml entry:
69   *
70   * <pre>
71   *    <servlet>
72   *      <servlet-name>Groovy</servlet-name>
73   *      <servlet-class>groovy.servlet.GroovyServlet</servlet-class>
74   *    </servlet>
75   *
76   *    <servlet-mapping>
77   *      <servlet-name>Groovy</servlet-name>
78   *      <url-pattern>*.groovy</url-pattern>
79   *      <url-pattern>*.gdo</url-pattern>
80   *    </servlet-mapping>
81   * </pre>
82   *
83   * <p>The URL pattern does not require the "*.groovy" mapping.  You can, for
84   * example, make it more Struts-like but groovy by making your mapping "*.gdo".
85   *
86   * @author Sam Pullara
87   * @author Mark Turansky (markturansky at hotmail.com)
88   * @author Guillaume Laforge
89   * @author Christian Stein
90   * 
91   * @see groovy.servlet.ServletBinding
92   */
93  public class GroovyServlet extends AbstractHttpServlet {
94  
95      /***
96       * The script engine executing the Groovy scripts for this servlet
97       */
98      private static GroovyScriptEngine gse;
99  
100     /***
101      * Initialize the GroovyServlet.
102      *
103      * @throws ServletException
104      *  if this method encountered difficulties
105      */
106     public void init(ServletConfig config) throws ServletException {
107         super.init(config);
108 
109         // Set up the scripting engine
110         gse = new GroovyScriptEngine(this);
111 
112         servletContext.log("Groovy servlet initialized on " + gse + ".");
113     }
114 
115     /***
116      * Handle web requests to the GroovyServlet
117      */
118     public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
119 
120         // Get the script path from the request - include aware (GROOVY-815)
121         final String scriptUri = getScriptUri(request);
122 
123         // Set it to HTML by default
124         response.setContentType("text/html");
125 
126         // Set up the script context
127         final Binding binding = new ServletBinding(request, response, servletContext);
128 
129         // Run the script
130         try {
131             Closure closure = new Closure(gse) {
132 
133                 public Object call() {
134                     try {
135                         return ((GroovyScriptEngine) getDelegate()).run(scriptUri, binding);
136                     } catch (ResourceException e) {
137                         throw new RuntimeException(e);
138                     } catch (ScriptException e) {
139                         throw new RuntimeException(e);
140                     }
141                 }
142 
143             };
144             GroovyCategorySupport.use(ServletCategory.class, closure);
145             /*
146              * Set reponse code 200.
147              */
148             response.setStatus(HttpServletResponse.SC_OK);
149         } catch (RuntimeException runtimeException) {
150             StringBuffer error = new StringBuffer("GroovyServlet Error: ");
151             error.append(" script: '");
152             error.append(scriptUri);
153             error.append("': ");
154             Throwable e = runtimeException.getCause();
155             /*
156              * Null cause?!
157              */
158             if (e == null) {
159                 error.append(" Script processing failed.");
160                 error.append(runtimeException.getMessage());
161                 error.append(runtimeException.getStackTrace()[0].toString());
162                 servletContext.log(error.toString());
163                 System.err.println(error.toString());
164                 runtimeException.printStackTrace(System.err);
165                 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error.toString());
166                 return;
167             }
168             /*
169              * Resource not found.
170              */
171             if (e instanceof ResourceException) {
172                 error.append(" Script not found, sending 404.");
173                 servletContext.log(error.toString());
174                 System.err.println(error.toString());
175                 response.sendError(HttpServletResponse.SC_NOT_FOUND);
176                 return;
177             }
178             /*
179              * Other internal error. Perhaps syntax?! 
180              */
181             servletContext.log("An error occurred processing the request", runtimeException);
182             error.append(e.getMessage());
183             error.append(e.getStackTrace()[0].toString());
184             servletContext.log(e.toString());
185             System.err.println(e.toString());
186             runtimeException.printStackTrace(System.err);
187             response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
188         } finally {
189             /*
190              * Finally, flush the response buffer.
191              */
192             response.flushBuffer();
193             // servletContext.log("Flushed response buffer.");
194         }
195     }
196 
197 }