1 16 17 package org.springframework.web.servlet.view.velocity; 18 19 import java.util.Enumeration ; 20 import java.util.HashMap ; 21 import java.util.Iterator ; 22 import java.util.Locale ; 23 import java.util.Map ; 24 import java.util.Properties ; 25 26 import javax.servlet.http.HttpServletRequest ; 27 import javax.servlet.http.HttpServletResponse ; 28 29 import org.apache.velocity.Template; 30 import org.apache.velocity.VelocityContext; 31 import org.apache.velocity.app.VelocityEngine; 32 import org.apache.velocity.app.tools.VelocityFormatter; 33 import org.apache.velocity.context.Context; 34 import org.apache.velocity.exception.MethodInvocationException; 35 import org.apache.velocity.exception.ResourceNotFoundException; 36 import org.apache.velocity.tools.generic.DateTool; 37 import org.apache.velocity.tools.generic.NumberTool; 38 39 import org.springframework.beans.BeansException; 40 import org.springframework.beans.factory.BeanFactoryUtils; 41 import org.springframework.beans.factory.NoSuchBeanDefinitionException; 42 import org.springframework.context.ApplicationContextException; 43 import org.springframework.util.ClassUtils; 44 import org.springframework.web.servlet.support.RequestContextUtils; 45 import org.springframework.web.servlet.view.AbstractTemplateView; 46 import org.springframework.web.util.NestedServletException; 47 48 91 public class VelocityView extends AbstractTemplateView { 92 93 private Map toolAttributes; 94 95 private String velocityFormatterAttribute; 96 97 private String dateToolAttribute; 98 99 private String numberToolAttribute; 100 101 private String encoding; 102 103 private boolean cacheTemplate = false; 104 105 private VelocityEngine velocityEngine; 106 107 private Template template; 108 109 110 138 public void setToolAttributes(Properties toolAttributes) { 139 this.toolAttributes = new HashMap (toolAttributes.size()); 140 for (Enumeration attributeNames = toolAttributes.propertyNames(); attributeNames.hasMoreElements();) { 141 String attributeName = (String ) attributeNames.nextElement(); 142 String className = toolAttributes.getProperty(attributeName); 143 Class toolClass = null; 144 try { 145 toolClass = ClassUtils.forName(className); 146 } 147 catch (ClassNotFoundException ex) { 148 throw new IllegalArgumentException ( 149 "Invalid definition for tool '" + attributeName + "' - tool class not found: " + ex.getMessage()); 150 } 151 this.toolAttributes.put(attributeName, toolClass); 152 } 153 } 154 155 161 public void setVelocityFormatterAttribute(String velocityFormatterAttribute) { 162 this.velocityFormatterAttribute = velocityFormatterAttribute; 163 } 164 165 175 public void setDateToolAttribute(String dateToolAttribute) { 176 this.dateToolAttribute = dateToolAttribute; 177 } 178 179 189 public void setNumberToolAttribute(String numberToolAttribute) { 190 this.numberToolAttribute = numberToolAttribute; 191 } 192 193 199 public void setEncoding(String encoding) { 200 this.encoding = encoding; 201 } 202 203 206 protected String getEncoding() { 207 return this.encoding; 208 } 209 210 217 public void setCacheTemplate(boolean cacheTemplate) { 218 this.cacheTemplate = cacheTemplate; 219 } 220 221 224 protected boolean isCacheTemplate() { 225 return this.cacheTemplate; 226 } 227 228 234 public void setVelocityEngine(VelocityEngine velocityEngine) { 235 this.velocityEngine = velocityEngine; 236 } 237 238 241 protected VelocityEngine getVelocityEngine() { 242 return this.velocityEngine; 243 } 244 245 246 250 protected void initApplicationContext() throws BeansException { 251 super.initApplicationContext(); 252 253 if (getVelocityEngine() == null) { 254 setVelocityEngine(autodetectVelocityEngine()); 256 } 257 258 checkTemplate(); 259 } 260 261 269 protected VelocityEngine autodetectVelocityEngine() throws BeansException { 270 try { 271 VelocityConfig velocityConfig = (VelocityConfig) 272 BeanFactoryUtils.beanOfTypeIncludingAncestors( 273 getApplicationContext(), VelocityConfig.class, true, false); 274 return velocityConfig.getVelocityEngine(); 275 } 276 catch (NoSuchBeanDefinitionException ex) { 277 throw new ApplicationContextException( 278 "Must define a single VelocityConfig bean in this web application context " + 279 "(may be inherited): VelocityConfigurer is the usual implementation. " + 280 "This bean may be given any name.", ex); 281 } 282 } 283 284 290 protected void checkTemplate() throws ApplicationContextException { 291 try { 292 this.template = getTemplate(); 294 } 295 catch (ResourceNotFoundException ex) { 296 throw new ApplicationContextException("Cannot find Velocity template for URL [" + getUrl() + 297 "]: Did you specify the correct resource loader path?", ex); 298 } 299 catch (Exception ex) { 300 throw new ApplicationContextException( 301 "Could not load Velocity template for URL [" + getUrl() + "]", ex); 302 } 303 } 304 305 306 311 protected void renderMergedTemplateModel( 312 Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { 313 314 exposeHelpers(model, request); 315 316 Context velocityContext = createVelocityContext(model, request, response); 317 exposeHelpers(velocityContext, request, response); 318 exposeToolAttributes(velocityContext, request); 319 320 doRender(velocityContext, response); 321 } 322 323 333 protected void exposeHelpers(Map model, HttpServletRequest request) throws Exception { 334 } 335 336 356 protected Context createVelocityContext( 357 Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { 358 359 return createVelocityContext(model); 360 } 361 362 373 protected Context createVelocityContext(Map model) throws Exception { 374 return new VelocityContext(model); 375 } 376 377 390 protected void exposeHelpers( 391 Context velocityContext, HttpServletRequest request, HttpServletResponse response) throws Exception { 392 393 exposeHelpers(velocityContext, request); 394 } 395 396 406 protected void exposeHelpers(Context velocityContext, HttpServletRequest request) throws Exception { 407 } 408 409 422 protected void exposeToolAttributes(Context velocityContext, HttpServletRequest request) throws Exception { 423 if (this.toolAttributes != null) { 425 for (Iterator it = this.toolAttributes.entrySet().iterator(); it.hasNext();) { 426 Map.Entry entry = (Map.Entry ) it.next(); 427 String attributeName = (String ) entry.getKey(); 428 Class toolClass = (Class ) entry.getValue(); 429 try { 430 Object tool = toolClass.newInstance(); 431 initTool(tool, velocityContext); 432 velocityContext.put(attributeName, tool); 433 } 434 catch (Exception ex) { 435 throw new NestedServletException("Could not instantiate Velocity tool '" + attributeName + "'", ex); 436 } 437 } 438 } 439 440 if (this.velocityFormatterAttribute != null) { 442 velocityContext.put(this.velocityFormatterAttribute, new VelocityFormatter(velocityContext)); 443 } 444 445 if (this.dateToolAttribute != null || this.numberToolAttribute != null) { 447 Locale locale = RequestContextUtils.getLocale(request); 448 if (this.dateToolAttribute != null) { 449 velocityContext.put(this.dateToolAttribute, new LocaleAwareDateTool(locale)); 450 } 451 if (this.numberToolAttribute != null) { 452 velocityContext.put(this.numberToolAttribute, new LocaleAwareNumberTool(locale)); 453 } 454 } 455 } 456 457 474 protected void initTool(Object tool, Context velocityContext) throws Exception { 475 } 476 477 478 494 protected void doRender(Context context, HttpServletResponse response) throws Exception { 495 if (logger.isDebugEnabled()) { 496 logger.debug("Rendering Velocity template [" + getUrl() + "] in VelocityView '" + getBeanName() + "'"); 497 } 498 mergeTemplate(getTemplate(), context, response); 499 } 500 501 512 protected Template getTemplate() throws Exception { 513 if (isCacheTemplate() && this.template != null) { 517 return this.template; 518 } 519 else { 520 return getTemplate(getUrl()); 521 } 522 } 523 524 534 protected Template getTemplate(String name) throws Exception { 535 return (getEncoding() != null ? 536 getVelocityEngine().getTemplate(name, getEncoding()) : 537 getVelocityEngine().getTemplate(name)); 538 } 539 540 549 protected void mergeTemplate( 550 Template template, Context context, HttpServletResponse response) throws Exception { 551 552 try { 553 template.merge(context, response.getWriter()); 554 } 555 catch (MethodInvocationException ex) { 556 throw new NestedServletException( 557 "Method invocation failed during rendering of Velocity view with name '" + 558 getBeanName() + "': " + ex.getMessage() + "; reference [" + ex.getReferenceName() + 559 "], method '" + ex.getMethodName() + "'", 560 ex.getWrappedThrowable()); 561 } 562 } 563 564 565 570 private static class LocaleAwareDateTool extends DateTool { 571 572 private final Locale locale; 573 574 private LocaleAwareDateTool(Locale locale) { 575 this.locale = locale; 576 } 577 578 public Locale getLocale() { 579 return this.locale; 580 } 581 } 582 583 584 589 private static class LocaleAwareNumberTool extends NumberTool { 590 591 private final Locale locale; 592 593 private LocaleAwareNumberTool(Locale locale) { 594 this.locale = locale; 595 } 596 597 public Locale getLocale() { 598 return this.locale; 599 } 600 } 601 602 } 603 | Popular Tags |