Clover coverage report - groovy - 1.0-beta-6
Coverage timestamp: Thu Jul 15 2004 13:18:22 BST
file stats: LOC: 557   Methods: 15
NCLOC: 157   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
TemplateServlet.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  * $Id: TemplateServlet.java,v 1.8 2004/05/22 06:11:00 spullara Exp $
 3   
  * 
 4   
  * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
 5   
  * 
 6   
  * Redistribution and use of this software and associated documentation
 7   
  * ("Software"), with or without modification, are permitted provided that the
 8   
  * following conditions are met:
 9   
  * 
 10   
  * 1. Redistributions of source code must retain copyright statements and
 11   
  * notices. Redistributions must also contain a copy of this document.
 12   
  * 
 13   
  * 2. Redistributions in binary form must reproduce the above copyright notice,
 14   
  * this list of conditions and the following disclaimer in the documentation
 15   
  * and/or other materials provided with the distribution.
 16   
  * 
 17   
  * 3. The name "groovy" must not be used to endorse or promote products derived
 18   
  * from this Software without prior written permission of The Codehaus. For
 19   
  * written permission, please contact info@codehaus.org.
 20   
  * 
 21   
  * 4. Products derived from this Software may not be called "groovy" nor may
 22   
  * "groovy" appear in their names without prior written permission of The
 23   
  * Codehaus. "groovy" is a registered trademark of The Codehaus.
 24   
  * 
 25   
  * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
 26   
  * 
 27   
  * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
 28   
  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 29   
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 30   
  * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
 31   
  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 32   
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 33   
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 34   
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 35   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 36   
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 37   
  *  
 38   
  */
 39   
 package groovy.servlet;
 40   
 
 41   
 import groovy.lang.Binding;
 42   
 import groovy.text.SimpleTemplateEngine;
 43   
 import groovy.text.Template;
 44   
 import groovy.text.TemplateEngine;
 45   
 
 46   
 import java.io.FileNotFoundException;
 47   
 import java.io.IOException;
 48   
 import java.net.URL;
 49   
 import java.util.Enumeration;
 50   
 import java.util.HashMap;
 51   
 import java.util.Map;
 52   
 
 53   
 import javax.servlet.ServletConfig;
 54   
 import javax.servlet.ServletContext;
 55   
 import javax.servlet.ServletException;
 56   
 import javax.servlet.http.HttpServlet;
 57   
 import javax.servlet.http.HttpServletRequest;
 58   
 import javax.servlet.http.HttpServletResponse;
 59   
 
 60   
 /**
 61   
  * A generic servlet for templates.
 62   
  * 
 63   
  * It wraps a <code>groovy.text.TemplateEngine</code> to process HTTP
 64   
  * requests. By default, it uses the
 65   
  * <code>groovy.text.SimpleTemplateEngine</code> which interprets JSP-like (or
 66   
  * Canvas-like) templates. <br>
 67   
  * <br>
 68   
  * 
 69   
  * Example <code>HelloWorld.template</code>:
 70   
  * 
 71   
  * <pre><code>
 72   
  * 
 73   
  *  &lt;html&gt;
 74   
  *  &lt;body&gt;
 75   
  *  &lt;% 3.times { %&gt;
 76   
  *  Hello World!
 77   
  * <br>
 78   
  * 
 79   
  *  &lt;% } %&gt;
 80   
  *  &lt;/body&gt;
 81   
  *  &lt;/html&gt; 
 82   
  *  
 83   
  * </code></pre>
 84   
  * 
 85   
  * <br>
 86   
  * <br>
 87   
  * 
 88   
  * Note: <br>
 89   
  * Automatic binding of context variables and request (form) parameters is
 90   
  * disabled by default. You can enable it by setting the servlet config init
 91   
  * parameters to <code>true</code>.
 92   
  * 
 93   
  * <pre><code>
 94   
  * bindDefaultVariables = init(&quot;bindDefaultVariables&quot;, false);
 95   
  * bindRequestParameters = init(&quot;bindRequestParameters&quot;, false);
 96   
  * </code></pre>
 97   
  * 
 98   
  * @author <a mailto:sormuras@web.de>Christian Stein </a>
 99   
  * @version 1.3
 100   
  */
 101   
 public class TemplateServlet extends HttpServlet {
 102   
 
 103   
     public static final String DEFAULT_CONTENT_TYPE = "text/html";
 104   
 
 105   
     private ServletContext servletContext;
 106   
 
 107   
     protected TemplateEngine templateEngine;
 108   
 
 109   
     protected boolean bindDefaultVariables;
 110   
 
 111   
     protected boolean bindRequestParameters;
 112   
 
 113   
     /**
 114   
      * Initializes the servlet.
 115   
      * 
 116   
      * @param config
 117   
      *            Passed by the servlet container.
 118   
      */
 119  0
     public void init(ServletConfig config) {
 120   
 
 121   
         /*
 122   
          * Save the context.
 123   
          */
 124  0
         this.servletContext = config.getServletContext();
 125   
 
 126   
         /*
 127   
          * BEGIN
 128   
          */
 129  0
         String className = getClass().getName();
 130  0
         servletContext.log("Initializing on " + className + "...");
 131   
 
 132   
         /*
 133   
          * Configure from servlet config.
 134   
          */
 135  0
         this.bindDefaultVariables = init(config, "bindDefaultVariables", false);
 136  0
         this.bindRequestParameters = init(config, "bindRequestParameters", false);
 137   
 
 138   
         /*
 139   
          * Get TemplateEngine instance.
 140   
          */
 141  0
         this.templateEngine = createTemplateEngine(config);
 142  0
         if (templateEngine == null) { throw new RuntimeException("Template engine not instantiated."); }
 143   
 
 144   
         /*
 145   
          * END;
 146   
          */
 147  0
         String engineName = templateEngine.getClass().getName();
 148  0
         servletContext.log(className + " initialized on " + engineName + ".");
 149   
     }
 150   
 
 151   
     /**
 152   
      * Convient evaluation of boolean configuration parameters.
 153   
      * 
 154   
      * @return <code>true</code> or <code>false</code>.
 155   
      * @param config
 156   
      *            Servlet configuration passed by the servlet container.
 157   
      * @param param
 158   
      *            Name of the paramter to look up.
 159   
      * @param value
 160   
      *            Default value if parameter name is not set.
 161   
      */
 162  0
     protected boolean init(ServletConfig config, String param, boolean value) {
 163  0
         String string = config.getInitParameter(param);
 164  0
         if (string == null) { return value; }
 165  0
         return Boolean.valueOf(string).booleanValue();
 166   
     }
 167   
 
 168   
     /**
 169   
      * Creates the template engine.
 170   
      * 
 171   
      * Called by {@link #init(ServletConfig)} and returns just <code>
 172   
      * SimpleTemplateEngine()</code> if the init parameter <code>templateEngine</code>
 173   
      * is not set.
 174   
      * 
 175   
      * @return The underlying template engine.
 176   
      * @param config
 177   
      *            This serlvet configuration passed by the container.
 178   
      * @see #createTemplateEngine()
 179   
      */
 180  0
     protected TemplateEngine createTemplateEngine(ServletConfig config) {
 181  0
         String templateEngineClassName = config.getInitParameter("templateEngine");
 182  0
         if (templateEngineClassName == null) {
 183  0
             return new SimpleTemplateEngine();
 184   
         }
 185  0
         try {
 186  0
             return (TemplateEngine) Class.forName(templateEngineClassName).newInstance();
 187   
         } catch (InstantiationException e) {
 188  0
             servletContext.log("Could not instantiate template engine: " + templateEngineClassName, e);
 189   
         } catch (IllegalAccessException e) {
 190  0
             servletContext.log("Could not access template engine class: " + templateEngineClassName, e);
 191   
         } catch (ClassNotFoundException e) {
 192  0
             servletContext.log("Could not find template engine class: " + templateEngineClassName, e);
 193   
        }
 194  0
         return null;
 195   
     }
 196   
 
 197   
     /**
 198   
      * Delegates to {@link #doRequest(HttpServletRequest, HttpServletResponse)}.
 199   
      */
 200  0
     public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 201  0
         doRequest(request, response);
 202   
     }
 203   
 
 204   
     /**
 205   
      * Delegates to {@link #doRequest(HttpServletRequest, HttpServletResponse)}.
 206   
      */
 207  0
     public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 208  0
         doRequest(request, response);
 209   
     }
 210   
 
 211   
     /**
 212   
      * Processes all requests by dispatching to helper methods.
 213   
      * 
 214   
      * TODO Outline the algorithm. Although the method names are well-chosen. :)
 215   
      * 
 216   
      * @param request
 217   
      *            The http request.
 218   
      * @param response
 219   
      *            The http response.
 220   
      * @throws ServletException
 221   
      *             ...
 222   
      * @throws IOException
 223   
      *             ...
 224   
      */
 225  0
     protected void doRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException {
 226   
 
 227  0
         Binding binding = null;
 228   
 
 229  0
         try {
 230   
 
 231   
             /*
 232   
              * Create binding.
 233   
              */
 234  0
             binding = createBinding(request, response);
 235   
 
 236   
             /*
 237   
              * Set default content type.
 238   
              */
 239  0
             setContentType(request, response);
 240   
 
 241   
             /*
 242   
              * Create the template by its engine.
 243   
              */
 244  0
             Template template = handleRequest(request, response, binding);
 245   
 
 246   
             /*
 247   
              * Let the template, that is groovy, do the merge.
 248   
              */
 249  0
             merge(template, binding, response);
 250   
 
 251   
         }
 252   
         catch (Exception exception) {
 253   
 
 254   
             /*
 255   
              * Call exception handling hook.
 256   
              */
 257  0
             error(request, response, exception);
 258   
 
 259   
         }
 260   
         finally {
 261   
 
 262   
             /*
 263   
              * Indicate we are finally done with this request.
 264   
              */
 265  0
             requestDone(request, response, binding);
 266   
 
 267   
         }
 268   
 
 269   
     }
 270   
 
 271   
     /**
 272   
      * Creates the application context.
 273   
      * 
 274   
      * Sets 5 variables if and only if <code>bindDefaultParameters</code> is
 275   
      * <code>true</code>:
 276   
      * 
 277   
      * <pre><code>
 278   
      * binding.setVariable(&quot;request&quot;, request);
 279   
      * binding.setVariable(&quot;response&quot;, response);
 280   
      * binding.setVariable(&quot;context&quot;, servletContext);
 281   
      * binding.setVariable(&quot;session&quot;, request.getSession(true));
 282   
      * binding.setVariable(&quot;out&quot;, response.getWriter());
 283   
      * </code></pre>
 284   
      * 
 285   
      * Binds all form parameters, too. This is, where we leave the clean MVC
 286   
      * pattern and Velocity behind. (...) Nobody told you to quit Velocity
 287   
      * anyway. :)
 288   
      * 
 289   
      * @return Groovy Binding also known as application context.
 290   
      * @param request
 291   
      *            The HTTP request.
 292   
      * @param response
 293   
      *            The HTTP response.
 294   
      * @throws Exception
 295   
      *             Any exception.
 296   
      */
 297  0
     protected Binding createBinding(HttpServletRequest request, HttpServletResponse response) throws Exception {
 298   
 
 299   
         /*
 300   
          * Create empty binding.
 301   
          */
 302  0
         Binding binding = new Binding();
 303   
 
 304   
         /*
 305   
          * Bind default variables.
 306   
          */
 307  0
         if (bindDefaultVariables) {
 308  0
             binding.setVariable("request", request);
 309  0
             binding.setVariable("response", response);
 310  0
             binding.setVariable("context", servletContext);
 311  0
             binding.setVariable("session", request.getSession(true));
 312  0
             binding.setVariable("out", response.getWriter());
 313   
         }
 314   
 
 315   
         /*
 316   
          * Bind form (aka request) parameters.
 317   
          */
 318  0
         if (bindRequestParameters) {
 319  0
             Enumeration parameterNames = request.getParameterNames();
 320  0
             while (parameterNames.hasMoreElements()) {
 321  0
                 String key = (String) parameterNames.nextElement();
 322  0
                 if (binding.getVariables().containsKey(key)) {
 323  0
                     servletContext.log("Key \"" + key + "\" already bound.");
 324  0
                     continue;
 325   
                 }
 326  0
                 String[] values = request.getParameterValues(key);
 327  0
                 if (values.length == 1) {
 328  0
                     binding.setVariable(key, values[0]);
 329   
                 }
 330   
                 else {
 331  0
                     binding.setVariable(key, values);
 332   
                 }
 333   
             }
 334   
         }
 335   
 
 336  0
         return binding;
 337   
 
 338   
     }
 339   
 
 340   
     /**
 341   
      * Sets {@link #DEFAULT_CONTENT_TYPE}.
 342   
      * 
 343   
      * @param request
 344   
      *            The HTTP request.
 345   
      * @param response
 346   
      *            The HTTP response.
 347   
      */
 348  0
     protected void setContentType(HttpServletRequest request, HttpServletResponse response) {
 349   
 
 350  0
         response.setContentType(DEFAULT_CONTENT_TYPE);
 351   
 
 352   
     }
 353   
 
 354   
     /**
 355   
      * Default request handling. <br>
 356   
      * 
 357   
      * Leaving Velocity behind again. The template, actually the Groovy code in
 358   
      * it, could handle/process the entire request. Good or not? This depends on
 359   
      * you! :)<br>
 360   
      * 
 361   
      * Anyway, here no exception is thrown -- but it's strongly recommended to
 362   
      * override this method in derived class and do the real processing against
 363   
      * the model inside it. The template should be used, like Velocity
 364   
      * templates, to produce the view, the html page. Again, it's up to you!
 365   
      * 
 366   
      * @return The template that will be merged.
 367   
      * @param request
 368   
      *            The HTTP request.
 369   
      * @param response
 370   
      *            The HTTP response.
 371   
      * @param binding
 372   
      *            The application context.
 373   
      * @throws Exception
 374   
      */
 375  0
     protected Template handleRequest(
 376   
             HttpServletRequest request,
 377   
             HttpServletResponse response,
 378   
             Binding binding)
 379   
     throws Exception {
 380   
         /*
 381   
          * Delegate to getTemplate(String).
 382   
          */
 383  0
         return getTemplate(request);
 384   
     }
 385   
 
 386   
     /**
 387   
      * Gets the template by its name.
 388   
      * 
 389   
      * @return The template that will be merged.
 390   
      * @param templateName
 391   
      *            The name of the template.
 392   
      * @throws Exception
 393   
      *             Any exception.
 394   
      */
 395  0
     protected Template getTemplate(HttpServletRequest request) throws Exception {
 396   
 
 397   
         /*
 398   
          * If its an include we need to get the included path, not the main request path.
 399   
          */
 400  0
         String path = (String) request.getAttribute("javax.servlet.include.servlet_path");
 401  0
         if (path == null) {
 402  0
             path = request.getServletPath();
 403   
         }
 404   
 
 405   
         /*
 406   
          * Delegate to resolveTemplateName(String). Twice if necessary.
 407   
          */
 408  0
         URL url = resolveTemplateName(path);
 409  0
         if (url == null) {
 410  0
             url = resolveTemplateName(request.getRequestURI());
 411   
         }
 412   
 
 413   
         /*
 414   
          * Template not found?
 415   
          */
 416  0
         if (url == null) {
 417  0
             String uri = request.getRequestURI();
 418  0
             servletContext.log("Resource \"" + uri + "\" not found.");
 419  0
             throw new FileNotFoundException(uri);
 420   
         }
 421   
 
 422   
         /*
 423   
          * Delegate to getTemplate(URL).
 424   
          */
 425  0
         return getTemplate(url);
 426   
 
 427   
     }
 428   
 
 429   
     /**
 430   
      * Locate template and convert its location to an URL.
 431   
      * 
 432   
      * @return The URL pointing to the resource... the template.
 433   
      * @param templateName
 434   
      *            The name of the template.
 435   
      * @throws Exception
 436   
      *             Any exception.
 437   
      */
 438  0
     protected URL resolveTemplateName(String templateName) throws Exception {
 439   
 
 440   
         /*
 441   
          * Try servlet context resource facility.
 442   
          * 
 443   
          * Good for names pointing to templates relatively to the servlet
 444   
          * context.
 445   
          */
 446  0
         URL url = servletContext.getResource(templateName);
 447  0
         if (url != null) { return url; }
 448   
 
 449   
         /*
 450   
          * Precedence: Context classloader, Class classloader
 451   
          * (those classloaders will delegate to the system classloader)
 452   
          */
 453  0
         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 454  0
         url = classLoader.getResource(templateName);
 455  0
         if (url != null) { return url; }
 456   
 
 457   
         /*
 458   
          * Try the class loader, that loaded this class.
 459   
          * 
 460   
          * Good for templates located within the class path.
 461   
          * 
 462   
          */
 463  0
         url = getClass().getResource(templateName);
 464  0
         if (url != null) { return url; }
 465   
 
 466   
         /*
 467   
          * Still, still here? Just return null.
 468   
          */
 469  0
         return null;
 470   
 
 471   
     }
 472   
 
 473   
     /**
 474   
      * Gets the template by its url.
 475   
      * 
 476   
      * @return The template that will be merged.
 477   
      * @param templateURL
 478   
      *            The url of the template.
 479   
      * @throws Exception
 480   
      *             Any exception.
 481   
      */
 482  0
     protected Template getTemplate(URL templateURL) throws Exception {
 483   
 
 484   
         /*
 485   
          * Let the engine create the template from given URL.
 486   
          * 
 487   
          * TODO Is createTemplate(Reader); faster? Fail safer?
 488   
          */
 489  0
         return templateEngine.createTemplate(templateURL);
 490   
 
 491   
     }
 492   
 
 493   
     /**
 494   
      * Merges the template and writes response.
 495   
      * 
 496   
      * @param template
 497   
      *            The template that will be merged... now!
 498   
      * @param binding
 499   
      *            The application context.
 500   
      * @param response
 501   
      *            The HTTP response.
 502   
      * @throws Exception
 503   
      *             Any exception.
 504   
      */
 505  0
     protected void merge(Template template, Binding binding, HttpServletResponse response) throws Exception {
 506   
 
 507   
         /*
 508   
          * Set binding and write response.
 509   
          */
 510  0
         template.make(binding.getVariables()).writeTo(response.getWriter());
 511   
 
 512   
     }
 513   
 
 514   
     /**
 515   
      * Simply sends an internal server error page (code 500).
 516   
      * 
 517   
      * @param request
 518   
      *            The HTTP request.
 519   
      * @param response
 520   
      *            The HTTP response.
 521   
      * @param exception
 522   
      *            The cause.
 523   
      */
 524  0
     protected void error(HttpServletRequest request, HttpServletResponse response, Exception exception) {
 525   
 
 526  0
         try {
 527  0
             response.sendError(500, exception.getMessage());
 528   
         }
 529   
         catch (IOException ioException) {
 530  0
             servletContext.log("Should not happen.", ioException);
 531   
         }
 532   
 
 533   
     }
 534   
 
 535   
     /**
 536   
      * Called one request is processed.
 537   
      * 
 538   
      * This clean-up hook is always called, even if there was an exception
 539   
      * flying around and the error method was executed.
 540   
      * 
 541   
      * @param request
 542   
      *            The HTTP request.
 543   
      * @param response
 544   
      *            The HTTP response.
 545   
      * @param binding
 546   
      *            The application context.
 547   
      */
 548  0
     protected void requestDone(HttpServletRequest request, HttpServletResponse response, Binding binding) {
 549   
 
 550   
         /*
 551   
          * Nothing to clean up.
 552   
          */
 553  0
         return;
 554   
 
 555   
     }
 556   
 
 557   
 }