1 package org.apache.turbine.services.velocity; 2 3 18 19 import java.io.ByteArrayOutputStream ; 20 import java.io.IOException ; 21 import java.io.OutputStream ; 22 import java.io.OutputStreamWriter ; 23 import java.io.Writer ; 24 25 import java.util.Iterator ; 26 import java.util.List ; 27 import java.util.Vector ; 28 29 import javax.servlet.ServletConfig ; 30 31 import org.apache.commons.collections.ExtendedProperties; 32 import org.apache.commons.configuration.Configuration; 33 import org.apache.commons.lang.StringUtils; 34 import org.apache.commons.logging.Log; 35 import org.apache.commons.logging.LogFactory; 36 37 import org.apache.velocity.VelocityContext; 38 import org.apache.velocity.app.Velocity; 39 import org.apache.velocity.app.event.EventCartridge; 40 import org.apache.velocity.app.event.MethodExceptionEventHandler; 41 import org.apache.velocity.context.Context; 42 import org.apache.velocity.runtime.log.SimpleLog4JLogSystem; 43 44 import org.apache.turbine.Turbine; 45 import org.apache.turbine.services.InitializationException; 46 import org.apache.turbine.services.pull.PullService; 47 import org.apache.turbine.services.pull.TurbinePull; 48 import org.apache.turbine.services.template.BaseTemplateEngineService; 49 import org.apache.turbine.util.RunData; 50 import org.apache.turbine.util.TurbineException; 51 52 78 public class TurbineVelocityService 79 extends BaseTemplateEngineService 80 implements VelocityService, 81 MethodExceptionEventHandler 82 { 83 84 private static final String RESOURCE_LOADER_PATH = ".resource.loader.path"; 85 86 87 private static final String DEFAULT_CHAR_SET = "ISO-8859-1"; 88 89 90 private static final String JAR_PREFIX = "jar:"; 91 92 93 private static final String ABSOLUTE_PREFIX = "file://"; 94 95 96 private static Log log = LogFactory.getLog(TurbineVelocityService.class); 97 98 99 private boolean pullModelActive = false; 100 101 102 private boolean catchErrors = true; 103 104 105 private PullService pullService = null; 106 107 108 116 public void init() 117 throws InitializationException 118 { 119 try 120 { 121 initVelocity(); 122 123 if (TurbinePull.isRegistered()) 127 { 128 pullModelActive = true; 129 130 pullService = TurbinePull.getService(); 131 132 log.debug("Activated Pull Tools"); 133 } 134 135 registerConfiguration(VelocityService.VELOCITY_EXTENSION); 137 138 setInit(true); 139 } 140 catch (Exception e) 141 { 142 throw new InitializationException( 143 "Failed to initialize TurbineVelocityService", e); 144 } 145 } 146 147 148 157 public void init(ServletConfig config) 158 throws InitializationException 159 { 160 init(); 161 } 162 163 164 169 public Context getContext() 170 { 171 Context globalContext = 172 pullModelActive ? pullService.getGlobalContext() : null; 173 174 Context ctx = new VelocityContext(globalContext); 175 return ctx; 176 } 177 178 183 public Context getNewContext() 184 { 185 Context ctx = new VelocityContext(); 186 187 EventCartridge ec = new EventCartridge(); 190 ec.addEventHandler(this); 191 ec.attachToContext(ctx); 192 return ctx; 193 } 194 195 208 public Object methodException(Class clazz, String method, Exception e) 209 throws Exception 210 { 211 log.error("Class " + clazz.getName() + "." + method + " threw Exception", e); 212 213 if (!catchErrors) 214 { 215 throw e; 216 } 217 218 return "[Turbine caught an Error here. Look into the turbine.log for further information]"; 219 } 220 221 229 public Context getContext(RunData data) 230 { 231 Context context = (Context) 234 data.getTemplateInfo().getTemplateContext(VelocityService.CONTEXT); 235 236 if (context == null) 237 { 238 context = getContext(); 239 context.put(VelocityService.RUNDATA_KEY, data); 240 241 if (pullModelActive) 242 { 243 pullService.populateContext(context, data); 248 } 249 250 data.getTemplateInfo().setTemplateContext( 251 VelocityService.CONTEXT, context); 252 } 253 return context; 254 } 255 256 267 public String handleRequest(Context context, String filename) 268 throws TurbineException 269 { 270 String results = null; 271 ByteArrayOutputStream bytes = null; 272 OutputStreamWriter writer = null; 273 String charset = getCharSet(context); 274 275 try 276 { 277 bytes = new ByteArrayOutputStream (); 278 279 writer = new OutputStreamWriter (bytes, charset); 280 281 executeRequest(context, filename, writer); 282 writer.flush(); 283 results = bytes.toString(charset); 284 } 285 catch (Exception e) 286 { 287 renderingError(filename, e); 288 } 289 finally 290 { 291 try 292 { 293 if (bytes != null) 294 { 295 bytes.close(); 296 } 297 } 298 catch (IOException ignored) 299 { 300 } 302 } 303 return results; 304 } 305 306 318 public void handleRequest(Context context, String filename, 319 OutputStream output) 320 throws TurbineException 321 { 322 String charset = getCharSet(context); 323 OutputStreamWriter writer = null; 324 325 try 326 { 327 writer = new OutputStreamWriter (output, charset); 328 executeRequest(context, filename, writer); 329 } 330 catch (Exception e) 331 { 332 renderingError(filename, e); 333 } 334 finally 335 { 336 try 337 { 338 if (writer != null) 339 { 340 writer.flush(); 341 } 342 } 343 catch (Exception ignored) 344 { 345 } 347 } 348 } 349 350 351 363 public void handleRequest(Context context, String filename, Writer writer) 364 throws TurbineException 365 { 366 try 367 { 368 executeRequest(context, filename, writer); 369 } 370 catch (Exception e) 371 { 372 renderingError(filename, e); 373 } 374 finally 375 { 376 try 377 { 378 if (writer != null) 379 { 380 writer.flush(); 381 } 382 } 383 catch (Exception ignored) 384 { 385 } 387 } 388 } 389 390 391 403 private void executeRequest(Context context, String filename, 404 Writer writer) 405 throws Exception 406 { 407 String encoding = getEncoding(context); 408 409 if (encoding != null) 410 { 411 Velocity.mergeTemplate(filename, encoding, context, writer); 412 } 413 else 414 { 415 Velocity.mergeTemplate(filename, context, writer); 416 } 417 } 418 419 425 private String getCharSet(Context context) 426 { 427 String charset = null; 428 429 Object data = context.get(VelocityService.RUNDATA_KEY); 430 if ((data != null) && (data instanceof RunData)) 431 { 432 charset = ((RunData) data).getCharSet(); 433 } 434 435 return (StringUtils.isEmpty(charset)) ? DEFAULT_CHAR_SET : charset; 436 } 437 438 444 private String getEncoding(Context context) 445 { 446 String encoding = null; 447 448 Object data = context.get(VelocityService.RUNDATA_KEY); 449 if ((data != null) && (data instanceof RunData)) 450 { 451 encoding = ((RunData) data).getTemplateEncoding(); 452 } 453 454 return encoding; 455 } 456 457 466 private static final void renderingError(String filename, Exception e) 467 throws TurbineException 468 { 469 String err = "Error rendering Velocity template: " + filename; 470 log.error(err, e); 471 throw new TurbineException(err, e); 472 } 473 474 480 private synchronized void initVelocity() 481 throws Exception 482 { 483 Configuration conf = getConfiguration(); 485 486 catchErrors = conf.getBoolean(CATCH_ERRORS_KEY, CATCH_ERRORS_DEFAULT); 487 488 conf.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM_CLASS, 489 SimpleLog4JLogSystem.class.getName()); 490 conf.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM 491 + ".log4j.category", "velocity"); 492 493 Velocity.setExtendedProperties(createVelocityProperties(conf)); 494 Velocity.init(); 495 } 496 497 498 509 510 public ExtendedProperties createVelocityProperties(Configuration conf) 511 throws Exception 512 { 513 516 ExtendedProperties veloConfig = new ExtendedProperties(); 517 518 522 for (Iterator i = conf.getKeys(); i.hasNext();) 523 { 524 String key = (String ) i.next(); 525 if (!key.endsWith(RESOURCE_LOADER_PATH)) 526 { 527 Object value = conf.getProperty(key); 528 529 if (value instanceof List ) 536 { 537 List srcValue = (List ) value; 538 Vector targetValue = new Vector (srcValue.size()); 539 540 for (Iterator it = srcValue.iterator(); it.hasNext(); ) 541 { 542 targetValue.add(it.next()); 543 } 544 545 veloConfig.addProperty(key, targetValue); 546 } 547 else 548 { 549 veloConfig.addProperty(key, value); 550 } 551 552 continue; } 554 555 List paths = conf.getList(key, null); 556 if (paths == null) 557 { 558 continue; } 562 563 Velocity.clearProperty(key); 564 565 573 for (Iterator j = paths.iterator(); j.hasNext();) 574 { 575 String path = (String ) j.next(); 576 577 log.debug("Translating " + path); 578 579 if (path.startsWith(JAR_PREFIX)) 580 { 581 if (path.substring(4).startsWith(ABSOLUTE_PREFIX)) 583 { 584 int jarSepIndex = path.indexOf("!/"); 586 587 path = (jarSepIndex < 0) 589 ? Turbine.getRealPath(path.substring(11)) 590 : (Turbine.getRealPath(path.substring(11, jarSepIndex)) + path.substring(jarSepIndex)); 592 593 log.debug("Result (absolute jar path): " + path); 594 } 595 } 596 else if(path.startsWith(ABSOLUTE_PREFIX)) 597 { 598 path = Turbine.getRealPath(path.substring(7)); 600 601 log.debug("Result (absolute URL Path): " + path); 602 } 603 else if(path.indexOf("://") < 0) 605 { 606 path = Turbine.getRealPath(path); 607 608 log.debug("Result (normal fs reference): " + path); 609 } 610 611 log.debug("Adding " + key + " -> " + path); 612 veloConfig.addProperty(key, path); 614 } 615 } 616 return veloConfig; 617 } 618 619 627 public boolean templateExists(String template) 628 { 629 return Velocity.templateExists(template); 630 } 631 632 638 public void requestFinished(Context context) 639 { 640 if (pullModelActive) 641 { 642 pullService.releaseTools(context); 643 } 644 } 645 } 646 | Popular Tags |