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 }