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.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 }