001: /*
002: * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
003: *
004: * Redistribution and use of this software and associated documentation
005: * ("Software"), with or without modification, are permitted provided that the
006: * following conditions are met: 1. Redistributions of source code must retain
007: * copyright statements and notices. Redistributions must also contain a copy
008: * of this document. 2. Redistributions in binary form must reproduce the above
009: * copyright notice, this list of conditions and the following disclaimer in
010: * the documentation and/or other materials provided with the distribution. 3.
011: * The name "groovy" must not be used to endorse or promote products derived
012: * from this Software without prior written permission of The Codehaus. For
013: * written permission, please contact info@codehaus.org. 4. Products derived
014: * from this Software may not be called "groovy" nor may "groovy" appear in
015: * their names without prior written permission of The Codehaus. "groovy" is a
016: * registered trademark of The Codehaus. 5. Due credit should be given to The
017: * Codehaus - http://groovy.codehaus.org/
018: *
019: * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
020: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022: * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
023: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
024: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
025: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
026: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
027: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
028: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
029: * DAMAGE.
030: *
031: */
032: package groovy.servlet;
033:
034: import groovy.lang.Binding;
035: import groovy.lang.Closure;
036: import groovy.util.GroovyScriptEngine;
037: import groovy.util.ResourceException;
038: import groovy.util.ScriptException;
039:
040: import java.io.IOException;
041:
042: import javax.servlet.ServletConfig;
043: import javax.servlet.ServletException;
044: import javax.servlet.http.HttpServletRequest;
045: import javax.servlet.http.HttpServletResponse;
046:
047: import org.codehaus.groovy.runtime.GroovyCategorySupport;
048:
049: /**
050: * This servlet will run Groovy scripts as Groovlets. Groovlets are scripts
051: * with these objects implicit in their scope:
052: *
053: * <ul>
054: * <li>request - the HttpServletRequest</li>
055: * <li>response - the HttpServletResponse</li>
056: * <li>application - the ServletContext associated with the servlet</li>
057: * <li>session - the HttpSession associated with the HttpServletRequest</li>
058: * <li>out - the PrintWriter associated with the ServletRequest</li>
059: * </ul>
060: *
061: * <p>Your script sources can be placed either in your web application's normal
062: * web root (allows for subdirectories) or in /WEB-INF/groovy/* (also allows
063: * subdirectories).
064: *
065: * <p>To make your web application more groovy, you must add the GroovyServlet
066: * to your application's web.xml configuration using any mapping you like, so
067: * long as it follows the pattern *.* (more on this below). Here is the
068: * web.xml entry:
069: *
070: * <pre>
071: * <servlet>
072: * <servlet-name>Groovy</servlet-name>
073: * <servlet-class>groovy.servlet.GroovyServlet</servlet-class>
074: * </servlet>
075: *
076: * <servlet-mapping>
077: * <servlet-name>Groovy</servlet-name>
078: * <url-pattern>*.groovy</url-pattern>
079: * <url-pattern>*.gdo</url-pattern>
080: * </servlet-mapping>
081: * </pre>
082: *
083: * <p>The URL pattern does not require the "*.groovy" mapping. You can, for
084: * example, make it more Struts-like but groovy by making your mapping "*.gdo".
085: *
086: * @author Sam Pullara
087: * @author Mark Turansky (markturansky at hotmail.com)
088: * @author Guillaume Laforge
089: * @author Christian Stein
090: *
091: * @see groovy.servlet.ServletBinding
092: */
093: public class GroovyServlet extends AbstractHttpServlet {
094:
095: /**
096: * The script engine executing the Groovy scripts for this servlet
097: */
098: private static GroovyScriptEngine gse;
099:
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
113: .log("Groovy servlet initialized on " + gse + ".");
114: }
115:
116: /**
117: * Handle web requests to the GroovyServlet
118: */
119: public void service(HttpServletRequest request,
120: HttpServletResponse response) throws IOException {
121:
122: // Get the script path from the request - include aware (GROOVY-815)
123: final String scriptUri = getScriptUri(request);
124:
125: // Set it to HTML by default
126: response.setContentType("text/html");
127:
128: // Set up the script context
129: final Binding binding = new ServletBinding(request, response,
130: servletContext);
131:
132: // Run the script
133: try {
134: Closure closure = new Closure(gse) {
135:
136: public Object call() {
137: try {
138: return ((GroovyScriptEngine) getDelegate())
139: .run(scriptUri, binding);
140: } catch (ResourceException e) {
141: throw new RuntimeException(e);
142: } catch (ScriptException e) {
143: throw new RuntimeException(e);
144: }
145: }
146:
147: };
148: GroovyCategorySupport.use(ServletCategory.class, closure);
149: /*
150: * Set reponse code 200.
151: */
152: response.setStatus(HttpServletResponse.SC_OK);
153: } catch (RuntimeException runtimeException) {
154: StringBuffer error = new StringBuffer(
155: "GroovyServlet Error: ");
156: error.append(" script: '");
157: error.append(scriptUri);
158: error.append("': ");
159: Throwable e = runtimeException.getCause();
160: /*
161: * Null cause?!
162: */
163: if (e == null) {
164: error.append(" Script processing failed.");
165: error.append(runtimeException.getMessage());
166: error.append(runtimeException.getStackTrace()[0]
167: .toString());
168: servletContext.log(error.toString());
169: System.err.println(error.toString());
170: runtimeException.printStackTrace(System.err);
171: response.sendError(
172: HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
173: error.toString());
174: return;
175: }
176: /*
177: * Resource not found.
178: */
179: if (e instanceof ResourceException) {
180: error.append(" Script not found, sending 404.");
181: servletContext.log(error.toString());
182: System.err.println(error.toString());
183: response.sendError(HttpServletResponse.SC_NOT_FOUND);
184: return;
185: }
186: /*
187: * Other internal error. Perhaps syntax?!
188: */
189: servletContext.log(
190: "An error occurred processing the request",
191: runtimeException);
192: error.append(e.getMessage());
193: error.append(e.getStackTrace()[0].toString());
194: servletContext.log(e.toString());
195: System.err.println(e.toString());
196: runtimeException.printStackTrace(System.err);
197: response.sendError(
198: HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e
199: .toString());
200: } finally {
201: /*
202: * Finally, flush the response buffer.
203: */
204: response.flushBuffer();
205: // servletContext.log("Flushed response buffer.");
206: }
207: }
208:
209: }
|