| 1 | package org.apache.velocity.servlet; |
| 2 | |
| 3 | /* |
| 4 | * Copyright 2000-2001,2004 The Apache Software Foundation. |
| 5 | * |
| 6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 | * you may not use this file except in compliance with the License. |
| 8 | * You may obtain a copy of the License at |
| 9 | * |
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, software |
| 13 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | * See the License for the specific language governing permissions and |
| 16 | * limitations under the License. |
| 17 | */ |
| 18 | |
| 19 | import java.io.IOException; |
| 20 | import java.io.PrintWriter; |
| 21 | import java.io.StringWriter; |
| 22 | import java.io.OutputStreamWriter; |
| 23 | import java.io.FileInputStream; |
| 24 | import java.io.FileNotFoundException; |
| 25 | import java.io.UnsupportedEncodingException; |
| 26 | |
| 27 | import java.util.Properties; |
| 28 | |
| 29 | import javax.servlet.ServletConfig; |
| 30 | import javax.servlet.ServletContext; |
| 31 | import javax.servlet.ServletException; |
| 32 | import javax.servlet.ServletOutputStream; |
| 33 | |
| 34 | import javax.servlet.http.HttpServlet; |
| 35 | import javax.servlet.http.HttpServletRequest; |
| 36 | import javax.servlet.http.HttpServletResponse; |
| 37 | |
| 38 | import org.apache.velocity.Template; |
| 39 | import org.apache.velocity.runtime.RuntimeConstants; |
| 40 | import org.apache.velocity.runtime.RuntimeSingleton; |
| 41 | import org.apache.velocity.io.VelocityWriter; |
| 42 | import org.apache.velocity.util.SimplePool; |
| 43 | |
| 44 | import org.apache.velocity.context.Context; |
| 45 | import org.apache.velocity.VelocityContext; |
| 46 | |
| 47 | import org.apache.velocity.app.Velocity; |
| 48 | |
| 49 | import org.apache.velocity.exception.ResourceNotFoundException; |
| 50 | import org.apache.velocity.exception.ParseErrorException; |
| 51 | import org.apache.velocity.exception.MethodInvocationException; |
| 52 | |
| 53 | /** |
| 54 | * Base class which simplifies the use of Velocity with Servlets. |
| 55 | * Extend this class, implement the <code>handleRequest()</code> method, |
| 56 | * and add your data to the context. Then call |
| 57 | * <code>getTemplate("myTemplate.wm")</code>. |
| 58 | * |
| 59 | * This class puts some things into the context object that you should |
| 60 | * be aware of: |
| 61 | * <pre> |
| 62 | * "req" - The HttpServletRequest object |
| 63 | * "res" - The HttpServletResponse object |
| 64 | * </pre> |
| 65 | * |
| 66 | * There are other methods you can override to access, alter or control |
| 67 | * any part of the request processing chain. Please see the javadocs for |
| 68 | * more information on : |
| 69 | * <ul> |
| 70 | * <li> loadConfiguration() : for setting up the Velocity runtime |
| 71 | * <li> createContext() : for creating and loading the Context |
| 72 | * <li> setContentType() : for changing the content type on a request |
| 73 | * by request basis |
| 74 | * <li> handleRequest() : you <b>must</b> implement this |
| 75 | * <li> mergeTemplate() : the template rendering process |
| 76 | * <li> requestCleanup() : post rendering resource or other cleanup |
| 77 | * <li> error() : error handling |
| 78 | * </ul> |
| 79 | * <br> |
| 80 | * If you put a contentType object into the context within either your |
| 81 | * serlvet or within your template, then that will be used to override |
| 82 | * the default content type specified in the properties file. |
| 83 | * |
| 84 | * "contentType" - The value for the Content-Type: header |
| 85 | * |
| 86 | * @author Dave Bryson |
| 87 | * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> |
| 88 | * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> |
| 89 | * @author <a href="kjohnson@transparent.com">Kent Johnson</a> |
| 90 | * @author <a href="dlr@finemaltcoding.com">Daniel Rall</a> |
| 91 | * $Id: VelocityServlet.java,v 1.52.4.1 2004/03/03 23:23:03 geirm Exp $ |
| 92 | */ |
| 93 | public abstract class VelocityServlet extends HttpServlet |
| 94 | { |
| 95 | /** |
| 96 | * The context key for the HTTP request object. |
| 97 | */ |
| 98 | public static final String REQUEST = "req"; |
| 99 | |
| 100 | /** |
| 101 | * The context key for the HTTP response object. |
| 102 | */ |
| 103 | public static final String RESPONSE = "res"; |
| 104 | |
| 105 | /** |
| 106 | * The HTTP content type context key. |
| 107 | */ |
| 108 | public static final String CONTENT_TYPE = "default.contentType"; |
| 109 | |
| 110 | /** |
| 111 | * The default content type for the response |
| 112 | */ |
| 113 | public static final String DEFAULT_CONTENT_TYPE = "text/html"; |
| 114 | |
| 115 | |
| 116 | /** |
| 117 | * Encoding for the output stream |
| 118 | */ |
| 119 | public static final String DEFAULT_OUTPUT_ENCODING = "ISO-8859-1"; |
| 120 | |
| 121 | /** |
| 122 | * The default content type, itself defaulting to {@link |
| 123 | * #DEFAULT_CONTENT_TYPE} if not configured. |
| 124 | */ |
| 125 | private static String defaultContentType; |
| 126 | |
| 127 | /** |
| 128 | * This is the string that is looked for when getInitParameter is |
| 129 | * called (<code>org.apache.velocity.properties</code>). |
| 130 | */ |
| 131 | protected static final String INIT_PROPS_KEY = |
| 132 | "org.apache.velocity.properties"; |
| 133 | |
| 134 | /** |
| 135 | * Use of this properties key has been deprecated, and will be |
| 136 | * removed in Velocity version 1.5. |
| 137 | */ |
| 138 | private static final String OLD_INIT_PROPS_KEY = "properties"; |
| 139 | |
| 140 | /** |
| 141 | * Cache of writers |
| 142 | */ |
| 143 | |
| 144 | private static SimplePool writerPool = new SimplePool(40); |
| 145 | |
| 146 | /** |
| 147 | * Performs initialization of this servlet. Called by the servlet |
| 148 | * container on loading. |
| 149 | * |
| 150 | * @param config The servlet configuration to apply. |
| 151 | * |
| 152 | * @exception ServletException |
| 153 | */ |
| 154 | public void init( ServletConfig config ) |
| 155 | throws ServletException |
| 156 | { |
| 157 | super.init( config ); |
| 158 | |
| 159 | /* |
| 160 | * do whatever we have to do to init Velocity |
| 161 | */ |
| 162 | initVelocity( config ); |
| 163 | |
| 164 | /* |
| 165 | * Now that Velocity is initialized, cache some config. |
| 166 | */ |
| 167 | defaultContentType = RuntimeSingleton.getString(CONTENT_TYPE, |
| 168 | DEFAULT_CONTENT_TYPE); |
| 169 | } |
| 170 | |
| 171 | /** |
| 172 | * Initializes the Velocity runtime, first calling |
| 173 | * loadConfiguration(ServletConvig) to get a |
| 174 | * java.util.Properties of configuration information |
| 175 | * and then calling Velocity.init(). Override this |
| 176 | * to do anything to the environment before the |
| 177 | * initialization of the singelton takes place, or to |
| 178 | * initialize the singleton in other ways. |
| 179 | */ |
| 180 | protected void initVelocity( ServletConfig config ) |
| 181 | throws ServletException |
| 182 | { |
| 183 | try |
| 184 | { |
| 185 | /* |
| 186 | * call the overridable method to allow the |
| 187 | * derived classes a shot at altering the configuration |
| 188 | * before initializing Runtime |
| 189 | */ |
| 190 | |
| 191 | Properties props = loadConfiguration( config ); |
| 192 | |
| 193 | Velocity.init( props ); |
| 194 | } |
| 195 | catch( Exception e ) |
| 196 | { |
| 197 | throw new ServletException("Error initializing Velocity: " + e, e); |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | /** |
| 202 | * Loads the configuration information and returns that |
| 203 | * information as a Properties, which will be used to |
| 204 | * initialize the Velocity runtime. |
| 205 | * <br><br> |
| 206 | * Currently, this method gets the initialization parameter |
| 207 | * VelocityServlet.INIT_PROPS_KEY, which should be a file containing |
| 208 | * the configuration information. |
| 209 | * <br><br> |
| 210 | * To configure your Servlet Spec 2.2 compliant servlet runner to pass |
| 211 | * this to you, put the following in your WEB-INF/web.xml file |
| 212 | * <br> |
| 213 | * <pre> |
| 214 | * <servlet> |
| 215 | * <servlet-name> YourServlet </servlet-name> |
| 216 | * <servlet-class> your.package.YourServlet </servlet-class> |
| 217 | * <init-param> |
| 218 | * <param-name> org.apache.velocity.properties </param-name> |
| 219 | * <param-value> velocity.properties </param-value> |
| 220 | * </init-param> |
| 221 | * </servlet> |
| 222 | * </pre> |
| 223 | * |
| 224 | * Alternately, if you wish to configure an entire context in this |
| 225 | * fashion, you may use the following: |
| 226 | * <br> |
| 227 | * <pre> |
| 228 | * <context-param> |
| 229 | * <param-name> org.apache.velocity.properties </param-name> |
| 230 | * <param-value> velocity.properties </param-value> |
| 231 | * <description> Path to Velocity configuration </description> |
| 232 | * </context-param> |
| 233 | * </pre> |
| 234 | * |
| 235 | * Derived classes may do the same, or take advantage of this code to do the loading for them via : |
| 236 | * <pre> |
| 237 | * Properties p = super.loadConfiguration( config ); |
| 238 | * </pre> |
| 239 | * and then add or modify the configuration values from the file. |
| 240 | * <br> |
| 241 | * |
| 242 | * @param config ServletConfig passed to the servlets init() function |
| 243 | * Can be used to access the real path via ServletContext (hint) |
| 244 | * @return java.util.Properties loaded with configuration values to be used |
| 245 | * to initialize the Velocity runtime. |
| 246 | * @throws FileNotFoundException if a specified file is not found. |
| 247 | * @throws IOException I/O problem accessing the specified file, if specified. |
| 248 | */ |
| 249 | protected Properties loadConfiguration(ServletConfig config) |
| 250 | throws IOException, FileNotFoundException |
| 251 | { |
| 252 | // This is a little overly complex because of legacy support |
| 253 | // for the initialization properties key "properties". |
| 254 | // References to OLD_INIT_PROPS_KEY should be removed at |
| 255 | // Velocity version 1.5. |
| 256 | String propsFile = config.getInitParameter(INIT_PROPS_KEY); |
| 257 | if (propsFile == null || propsFile.length() == 0) |
| 258 | { |
| 259 | ServletContext sc = config.getServletContext(); |
| 260 | propsFile = config.getInitParameter(OLD_INIT_PROPS_KEY); |
| 261 | if (propsFile == null || propsFile.length() == 0) |
| 262 | { |
| 263 | propsFile = sc.getInitParameter(INIT_PROPS_KEY); |
| 264 | if (propsFile == null || propsFile.length() == 0) |
| 265 | { |
| 266 | propsFile = sc.getInitParameter(OLD_INIT_PROPS_KEY); |
| 267 | if (propsFile != null && propsFile.length() > 0) |
| 268 | { |
| 269 | sc.log("Use of the properties initialization " + |
| 270 | "parameter '" + OLD_INIT_PROPS_KEY + "' has " + |
| 271 | "been deprecated by '" + INIT_PROPS_KEY + '\''); |
| 272 | } |
| 273 | } |
| 274 | } |
| 275 | else |
| 276 | { |
| 277 | sc.log("Use of the properties initialization parameter '" + |
| 278 | OLD_INIT_PROPS_KEY + "' has been deprecated by '" + |
| 279 | INIT_PROPS_KEY + '\''); |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | /* |
| 284 | * This will attempt to find the location of the properties |
| 285 | * file from the relative path to the WAR archive (ie: |
| 286 | * docroot). Since JServ returns null for getRealPath() |
| 287 | * because it was never implemented correctly, then we know we |
| 288 | * will not have an issue with using it this way. I don't know |
| 289 | * if this will break other servlet engines, but it probably |
| 290 | * shouldn't since WAR files are the future anyways. |
| 291 | */ |
| 292 | |
| 293 | Properties p = new Properties(); |
| 294 | |
| 295 | if ( propsFile != null ) |
| 296 | { |
| 297 | String realPath = getServletContext().getRealPath(propsFile); |
| 298 | |
| 299 | if ( realPath != null ) |
| 300 | { |
| 301 | propsFile = realPath; |
| 302 | } |
| 303 | |
| 304 | p.load( new FileInputStream(propsFile) ); |
| 305 | } |
| 306 | |
| 307 | return p; |
| 308 | } |
| 309 | |
| 310 | /** |
| 311 | * Handles HTTP <code>GET</code> requests by calling {@link |
| 312 | * #doRequest()}. |
| 313 | */ |
| 314 | public void doGet( HttpServletRequest request, HttpServletResponse response ) |
| 315 | throws ServletException, IOException |
| 316 | { |
| 317 | doRequest(request, response); |
| 318 | } |
| 319 | |
| 320 | /** |
| 321 | * Handles HTTP <code>POST</code> requests by calling {@link |
| 322 | * #doRequest()}. |
| 323 | */ |
| 324 | public void doPost( HttpServletRequest request, HttpServletResponse response ) |
| 325 | throws ServletException, IOException |
| 326 | { |
| 327 | doRequest(request, response); |
| 328 | } |
| 329 | |
| 330 | /** |
| 331 | * Handles all requests (by default). |
| 332 | * |
| 333 | * @param request HttpServletRequest object containing client request |
| 334 | * @param response HttpServletResponse object for the response |
| 335 | */ |
| 336 | protected void doRequest(HttpServletRequest request, HttpServletResponse response ) |
| 337 | throws ServletException, IOException |
| 338 | { |
| 339 | Context context = null; |
| 340 | try |
| 341 | { |
| 342 | /* |
| 343 | * first, get a context |
| 344 | */ |
| 345 | |
| 346 | context = createContext( request, response ); |
| 347 | |
| 348 | /* |
| 349 | * set the content type |
| 350 | */ |
| 351 | |
| 352 | setContentType( request, response ); |
| 353 | |
| 354 | /* |
| 355 | * let someone handle the request |
| 356 | */ |
| 357 | |
| 358 | Template template = handleRequest( request, response, context ); |
| 359 | /* |
| 360 | * bail if we can't find the template |
| 361 | */ |
| 362 | |
| 363 | if ( template == null ) |
| 364 | { |
| 365 | return; |
| 366 | } |
| 367 | |
| 368 | /* |
| 369 | * now merge it |
| 370 | */ |
| 371 | |
| 372 | mergeTemplate( template, context, response ); |
| 373 | } |
| 374 | catch (Exception e) |
| 375 | { |
| 376 | /* |
| 377 | * call the error handler to let the derived class |
| 378 | * do something useful with this failure. |
| 379 | */ |
| 380 | |
| 381 | error( request, response, e); |
| 382 | } |
| 383 | finally |
| 384 | { |
| 385 | /* |
| 386 | * call cleanup routine to let a derived class do some cleanup |
| 387 | */ |
| 388 | |
| 389 | requestCleanup( request, response, context ); |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | /** |
| 394 | * A cleanup routine which is called at the end of the {@link |
| 395 | * #doRequest(HttpServletRequest, HttpServletResponse)} |
| 396 | * processing sequence, allowing a derived class to do resource |
| 397 | * cleanup or other end of process cycle tasks. |
| 398 | * |
| 399 | * @param request servlet request from client |
| 400 | * @param response servlet reponse |
| 401 | * @param context context created by the createContext() method |
| 402 | */ |
| 403 | protected void requestCleanup( HttpServletRequest request, HttpServletResponse response, Context context ) |
| 404 | { |
| 405 | return; |
| 406 | } |
| 407 | |
| 408 | /** |
| 409 | * merges the template with the context. Only override this if you really, really |
| 410 | * really need to. (And don't call us with questions if it breaks :) |
| 411 | * |
| 412 | * @param template template object returned by the handleRequest() method |
| 413 | * @param context context created by the createContext() method |
| 414 | * @param response servlet reponse (use this to get the output stream or Writer |
| 415 | */ |
| 416 | protected void mergeTemplate( Template template, Context context, HttpServletResponse response ) |
| 417 | throws ResourceNotFoundException, ParseErrorException, |
| 418 | MethodInvocationException, IOException, UnsupportedEncodingException, Exception |
| 419 | { |
| 420 | ServletOutputStream output = response.getOutputStream(); |
| 421 | VelocityWriter vw = null; |
| 422 | // ASSUMPTION: response.setContentType() has been called. |
| 423 | String encoding = response.getCharacterEncoding(); |
| 424 | |
| 425 | try |
| 426 | { |
| 427 | vw = (VelocityWriter) writerPool.get(); |
| 428 | |
| 429 | if (vw == null) |
| 430 | { |
| 431 | vw = new VelocityWriter(new OutputStreamWriter(output, |
| 432 | encoding), |
| 433 | 4 * 1024, true); |
| 434 | } |
| 435 | else |
| 436 | { |
| 437 | vw.recycle(new OutputStreamWriter(output, encoding)); |
| 438 | } |
| 439 | |
| 440 | template.merge(context, vw); |
| 441 | } |
| 442 | finally |
| 443 | { |
| 444 | try |
| 445 | { |
| 446 | if (vw != null) |
| 447 | { |
| 448 | /* |
| 449 | * flush and put back into the pool |
| 450 | * don't close to allow us to play |
| 451 | * nicely with others. |
| 452 | */ |
| 453 | vw.flush(); |
| 454 | |
| 455 | /* |
| 456 | * Clear the VelocityWriter's reference to its |
| 457 | * internal OutputStreamWriter to allow the latter |
| 458 | * to be GC'd while vw is pooled. |
| 459 | */ |
| 460 | vw.recycle(null); |
| 461 | |
| 462 | writerPool.put(vw); |
| 463 | } |
| 464 | } |
| 465 | catch (Exception e) |
| 466 | { |
| 467 | // do nothing |
| 468 | } |
| 469 | } |
| 470 | } |
| 471 | |
| 472 | /** |
| 473 | * Sets the content type of the response, defaulting to {@link |
| 474 | * #defaultContentType} if not overriden. Delegates to {@link |
| 475 | * #chooseCharacterEncoding(HttpServletRequest)} to select the |
| 476 | * appropriate character encoding. |
| 477 | * |
| 478 | * @param request The servlet request from the client. |
| 479 | * @param response The servlet reponse to the client. |
| 480 | */ |
| 481 | protected void setContentType(HttpServletRequest request, |
| 482 | HttpServletResponse response) |
| 483 | { |
| 484 | String contentType = defaultContentType; |
| 485 | int index = contentType.lastIndexOf(';') + 1; |
| 486 | if (index <= 0 || (index < contentType.length() && |
| 487 | contentType.indexOf("charset", index) == -1)) |
| 488 | { |
| 489 | // Append the character encoding which we'd like to use. |
| 490 | String encoding = chooseCharacterEncoding(request); |
| 491 | //System.out.println("Chose output encoding of '" + |
| 492 | // encoding + '\''); |
| 493 | if (!DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding)) |
| 494 | { |
| 495 | contentType += "; charset=" + encoding; |
| 496 | } |
| 497 | } |
| 498 | response.setContentType(contentType); |
| 499 | //System.out.println("Response Content-Type set to '" + |
| 500 | // contentType + '\''); |
| 501 | } |
| 502 | |
| 503 | /** |
| 504 | * Chooses the output character encoding to be used as the value |
| 505 | * for the "charset=" portion of the HTTP Content-Type header (and |
| 506 | * thus returned by <code>response.getCharacterEncoding()</code>). |
| 507 | * Called by {@link #setContentType(HttpServletRequest, |
| 508 | * HttpServletResponse)} if an encoding isn't already specified by |
| 509 | * Content-Type. By default, chooses the value of |
| 510 | * RuntimeSingleton's <code>output.encoding</code> property. |
| 511 | * |
| 512 | * @param request The servlet request from the client. |
| 513 | */ |
| 514 | protected String chooseCharacterEncoding(HttpServletRequest request) |
| 515 | { |
| 516 | return RuntimeSingleton.getString(RuntimeConstants.OUTPUT_ENCODING, |
| 517 | DEFAULT_OUTPUT_ENCODING); |
| 518 | } |
| 519 | |
| 520 | /** |
| 521 | * Returns a context suitable to pass to the handleRequest() method |
| 522 | * <br><br> |
| 523 | * Default implementation will create a VelocityContext object, |
| 524 | * put the HttpServletRequest and HttpServletResponse |
| 525 | * into the context accessable via the keys VelocityServlet.REQUEST and |
| 526 | * VelocityServlet.RESPONSE, respectively. |
| 527 | * |
| 528 | * @param request servlet request from client |
| 529 | * @param response servlet reponse to client |
| 530 | * |
| 531 | * @return context |
| 532 | */ |
| 533 | protected Context createContext(HttpServletRequest request, HttpServletResponse response ) |
| 534 | { |
| 535 | /* |
| 536 | * create a new context |
| 537 | */ |
| 538 | |
| 539 | VelocityContext context = new VelocityContext(); |
| 540 | |
| 541 | /* |
| 542 | * put the request/response objects into the context |
| 543 | * wrap the HttpServletRequest to solve the introspection |
| 544 | * problems |
| 545 | */ |
| 546 | |
| 547 | context.put( REQUEST, request ); |
| 548 | context.put( RESPONSE, response ); |
| 549 | |
| 550 | return context; |
| 551 | } |
| 552 | |
| 553 | /** |
| 554 | * Retrieves the requested template. |
| 555 | * |
| 556 | * @param name The file name of the template to retrieve relative to the |
| 557 | * template root. |
| 558 | * @return The requested template. |
| 559 | * @throws ResourceNotFoundException if template not found |
| 560 | * from any available source. |
| 561 | * @throws ParseErrorException if template cannot be parsed due |
| 562 | * to syntax (or other) error. |
| 563 | * @throws Exception if an error occurs in template initialization |
| 564 | */ |
| 565 | public Template getTemplate( String name ) |
| 566 | throws ResourceNotFoundException, ParseErrorException, Exception |
| 567 | { |
| 568 | return RuntimeSingleton.getTemplate(name); |
| 569 | } |
| 570 | |
| 571 | /** |
| 572 | * Retrieves the requested template with the specified |
| 573 | * character encoding. |
| 574 | * |
| 575 | * @param name The file name of the template to retrieve relative to the |
| 576 | * template root. |
| 577 | * @param encoding the character encoding of the template |
| 578 | * |
| 579 | * @return The requested template. |
| 580 | * @throws ResourceNotFoundException if template not found |
| 581 | * from any available source. |
| 582 | * @throws ParseErrorException if template cannot be parsed due |
| 583 | * to syntax (or other) error. |
| 584 | * @throws Exception if an error occurs in template initialization |
| 585 | * |
| 586 | * @since Velocity v1.1 |
| 587 | */ |
| 588 | public Template getTemplate( String name, String encoding ) |
| 589 | throws ResourceNotFoundException, ParseErrorException, Exception |
| 590 | { |
| 591 | return RuntimeSingleton.getTemplate( name, encoding ); |
| 592 | } |
| 593 | |
| 594 | /** |
| 595 | * Implement this method to add your application data to the context, |
| 596 | * calling the <code>getTemplate()</code> method to produce your return |
| 597 | * value. |
| 598 | * <br><br> |
| 599 | * In the event of a problem, you may handle the request directly |
| 600 | * and return <code>null</code> or throw a more meaningful exception |
| 601 | * for the error handler to catch. |
| 602 | * |
| 603 | * @param request servlet request from client |
| 604 | * @param response servlet reponse |
| 605 | * @param ctx The context to add your data to. |
| 606 | * @return The template to merge with your context or null, indicating |
| 607 | * that you handled the processing. |
| 608 | * |
| 609 | * @since Velocity v1.1 |
| 610 | */ |
| 611 | protected Template handleRequest( HttpServletRequest request, HttpServletResponse response, Context ctx ) |
| 612 | throws Exception |
| 613 | { |
| 614 | /* |
| 615 | * invoke handleRequest |
| 616 | */ |
| 617 | |
| 618 | Template t = handleRequest( ctx ); |
| 619 | |
| 620 | /* |
| 621 | * if it returns null, this is the 'old' deprecated |
| 622 | * way, and we want to mimic the behavior for a little |
| 623 | * while anyway |
| 624 | */ |
| 625 | |
| 626 | if (t == null) |
| 627 | { |
| 628 | throw new Exception ("handleRequest(Context) returned null - no template selected!" ); |
| 629 | } |
| 630 | |
| 631 | return t; |
| 632 | } |
| 633 | |
| 634 | /** |
| 635 | * Implement this method to add your application data to the context, |
| 636 | * calling the <code>getTemplate()</code> method to produce your return |
| 637 | * value. |
| 638 | * <br><br> |
| 639 | * In the event of a problem, you may simple return <code>null</code> |
| 640 | * or throw a more meaningful exception. |
| 641 | * |
| 642 | * @deprecated Use |
| 643 | * {@link #handleRequest( HttpServletRequest request, |
| 644 | * HttpServletResponse response, Context ctx )} |
| 645 | * |
| 646 | * @param ctx The context to add your data to. |
| 647 | * @return The template to merge with your context. |
| 648 | */ |
| 649 | protected Template handleRequest( Context ctx ) |
| 650 | throws Exception |
| 651 | { |
| 652 | throw new Exception ("You must override VelocityServlet.handleRequest( Context) " |
| 653 | + " or VelocityServlet.handleRequest( HttpServletRequest, " |
| 654 | + " HttpServletResponse, Context)" ); |
| 655 | } |
| 656 | |
| 657 | /** |
| 658 | * Invoked when there is an error thrown in any part of doRequest() processing. |
| 659 | * <br><br> |
| 660 | * Default will send a simple HTML response indicating there was a problem. |
| 661 | * |
| 662 | * @param request original HttpServletRequest from servlet container. |
| 663 | * @param response HttpServletResponse object from servlet container. |
| 664 | * @param cause Exception that was thrown by some other part of process. |
| 665 | */ |
| 666 | protected void error( HttpServletRequest request, HttpServletResponse response, Exception cause ) |
| 667 | throws ServletException, IOException |
| 668 | { |
| 669 | StringBuffer html = new StringBuffer(); |
| 670 | html.append("<html>"); |
| 671 | html.append("<title>Error</title>"); |
| 672 | html.append("<body bgcolor=\"#ffffff\">"); |
| 673 | html.append("<h2>VelocityServlet: Error processing the template</h2>"); |
| 674 | html.append("<pre>"); |
| 675 | String why = cause.getMessage(); |
| 676 | if (why != null && why.trim().length() > 0) |
| 677 | { |
| 678 | html.append(why); |
| 679 | html.append("<br>"); |
| 680 | } |
| 681 | |
| 682 | StringWriter sw = new StringWriter(); |
| 683 | cause.printStackTrace( new PrintWriter( sw ) ); |
| 684 | |
| 685 | html.append( sw.toString() ); |
| 686 | html.append("</pre>"); |
| 687 | html.append("</body>"); |
| 688 | html.append("</html>"); |
| 689 | response.getOutputStream().print( html.toString() ); |
| 690 | } |
| 691 | } |