View Javadoc
1 package org.apache.turbine.services.webmacro; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache Turbine" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * "Apache Turbine", nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>;. 55 */ 56 57 import java.io.ByteArrayOutputStream; 58 import java.io.OutputStream; 59 import javax.servlet.ServletConfig; 60 import org.apache.commons.configuration.Configuration; 61 import org.apache.turbine.services.InitializationException; 62 import org.apache.turbine.services.servlet.TurbineServlet; 63 import org.apache.turbine.services.template.BaseTemplateEngineService; 64 import org.apache.turbine.services.template.TurbineTemplate; 65 import org.apache.turbine.util.ContentURI; 66 import org.apache.turbine.util.Log; 67 import org.apache.turbine.util.RunData; 68 import org.apache.turbine.util.TurbineException; 69 import org.apache.turbine.util.template.TemplateLink; 70 import org.apache.turbine.util.template.TemplatePageAttributes; 71 import org.apache.turbine.util.webmacro.WebMacroFormatter; 72 import org.webmacro.Broker; 73 import org.webmacro.FastWriter; 74 import org.webmacro.InitException; 75 import org.webmacro.NotFoundException; 76 import org.webmacro.Template; 77 import org.webmacro.WM; 78 import org.webmacro.WebMacro; 79 import org.webmacro.broker.ResourceBroker; 80 import org.webmacro.broker.ResourceProvider; 81 import org.webmacro.servlet.WebContext; 82 83 /*** 84 * This is a Service that can process WebMacro templates from within a 85 * Turbine Screen. Here's an example of how you might use it from a 86 * screen: 87 * <br> 88 * <code> 89 * WebContext context = WebMacro.getContext(data);<br> 90 * context.put("message", "Hello from Turbine!");<br> 91 * String results = WebMacro.handleRequest(context,"helloWorld.wm");<br> 92 * data.getPage().getBody().addElement(results);<br> 93 * </code> 94 * <p> 95 * Multiple template paths are specified via the 96 * <code>services.TurbineWebMacroService.templates</code> property in the 97 * <code>TurbineResources.properties</code> file, specified as a single string 98 * delimited by the value of the System property <code>path.separator</code> 99 * (this is <code>:</code> on UNIX and <code>;</code> on Windows). 100 * <p> 101 * Turbine does not use the default <code>ResourceProvider</code> for WebMacro 102 * ResourceEvents of type <code>template</code>. Instead, Turbine uses its own 103 * <code>TurbineTemplateProvider</code> implementation. 104 * 105 * @author <a href="mailto:mbryson@mont.mindspring.com">Dave Bryson</a> 106 * @author <a href="mailto:krzewski@e-point.pl">Rafal Krzewski</a> 107 * @author <a href="mailto:dlr@collab.net">Daniel Rall</a> 108 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> 109 * @version $Id: TurbineWebMacroService.java,v 1.4 2002/07/11 16:53:23 mpoeschl Exp $ 110 * @deprecated 111 */ 112 public class TurbineWebMacroService extends BaseTemplateEngineService 113 implements WebMacroService 114 { 115 /*** 116 * The default encoding used by the WebMacro <code>FastWriter</code>. 117 * <p> 118 * We should encode the ouput byte stream as <code>UTF-16</code> to 119 * achieve the fastest conversion back to Java characters, but for some 120 * reason this does not work (bug in FastWriter?). <code>UTF-8</code> 121 * seems to work and is used as a fallback option. 122 */ 123 protected static final String DEFAULT_ENCODING = "UTF-8"; 124 125 /*** 126 * The WebMacro engine. 127 */ 128 private WebMacro wm = null; 129 130 /*** 131 * The context used as a factory. 132 */ 133 private WebContext wcPrototype = null; 134 135 /*** 136 * The broker used by WebMacro to retrieve resources. 137 */ 138 private Broker broker = null; 139 140 /*** 141 * Paths where templates can be located. 142 */ 143 private String[] templatePaths = null; 144 145 /*** 146 * Webmacro properties file. 147 */ 148 private String WMProperties = null; 149 150 /*** 151 * WebMacro template provider. 152 */ 153 private String WMTemplateProvider = null; 154 155 /*** 156 * Performs early initialization of this service. 157 * 158 * @exception InitializationException Caused by any initialization error. 159 */ 160 public void init(ServletConfig unused) throws InitializationException 161 { 162 try 163 { 164 initWebMacro(); 165 initWebContext(); 166 registerConfiguration("wm"); 167 setInit(true); 168 } 169 catch (Exception e) 170 { 171 throw new InitializationException 172 (WebMacroService.SERVICE_NAME + " failed to initialize", e); 173 } 174 } 175 176 /*** 177 * Shuts down the service, including its 178 * <a href="http://webmacro.org/">WebMacro</a> engine. 179 */ 180 public void shutdown() 181 { 182 wm.destroy(); 183 /* 184 * WebMacro leaves an active thread after shutdown (which is probably 185 * a bug). We shut it down manually here. 186 */ 187 org.webmacro.util.ThreadScheduler.stop(); 188 } 189 190 /*** 191 * Create an empty WebContext object. 192 * 193 * @return A new, empty context. 194 */ 195 public WebContext getContext() 196 { 197 return new WebContext(broker); 198 } 199 200 /*** 201 * Create a <code>WebContext</code> from the <code>RunData</code> 202 * object. Adds a pointer to the <code>RunData</code> object to 203 * the WC so that RunData is available in the templates. 204 * 205 * @param data The Turbine RunData object. 206 * @return A clone of the WebContext needed by WebMacro. 207 */ 208 public WebContext getContext(RunData data) 209 { 210 WebContext newWC = wcPrototype.newInstance(data.getRequest(), 211 data.getResponse()); 212 newWC.put( "data", data ); 213 newWC.put( "link", new TemplateLink(data) ); 214 newWC.put( "page", new TemplatePageAttributes(data) ); 215 newWC.put( "formatter", new WebMacroFormatter(newWC) ); 216 newWC.put( "content", new ContentURI(data) ); 217 return newWC; 218 } 219 220 /*** 221 * Process the request and fill in the template with the values 222 * you set in the WebContext. 223 * 224 * @param wc The populated context. 225 * @param filename The file name of the template. 226 * @return The process template as a String. 227 * @throws TurbineException Any exception trown while processing will be 228 * wrapped into a TurbineException and rethrown. 229 */ 230 public String handleRequest(WebContext wc, 231 String filename) 232 throws TurbineException 233 { 234 String results = null; 235 try 236 { 237 ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 238 FastWriter fw = new FastWriter(bytes, DEFAULT_ENCODING); 239 handleRequest(wc, filename, fw); 240 fw.flush(); 241 results = bytes.toString(DEFAULT_ENCODING); 242 } 243 catch( Exception e ) 244 { 245 throw new TurbineException 246 ("An error occurred while rendering template: " + filename, e); 247 } 248 249 return results; 250 } 251 252 /*** 253 * Process the request and fill in the template with the values 254 * you set in the WebContext. 255 * 256 * @param wc The populated context. 257 * @param filename The file name of the template. 258 * @param out A stream to write the processed template to. 259 * @throws TurbineException Any exception trown while processing will be 260 * wrapped into a TurbineException and rethrown. 261 */ 262 public void handleRequest(WebContext wc, 263 String filename, 264 OutputStream out) 265 throws Exception 266 { 267 handleRequest(wc, filename, new FastWriter(out, DEFAULT_ENCODING)); 268 } 269 270 /*** 271 * Process the request and fill in the template with the values 272 * you set in the WebContext. 273 * 274 * @param wc The populated context. 275 * @param filename The file name of the template. 276 * @param writer A writer to write the processed template with. 277 * @throws TurbineException Any exception trown while processing will be 278 * wrapped into a TurbineException and rethrown. 279 */ 280 public void handleRequest(WebContext wc, 281 String filename, 282 FastWriter writer) 283 throws Exception 284 { 285 Template template = getTemplate(filename); 286 template.write(writer, wc); 287 } 288 289 /*** 290 * Return a template from WebMacro. 291 * 292 * @param filename A String with the name of the template. 293 * @return A Template. 294 * @exception NotFoundException The template could not be found. 295 */ 296 public Template getTemplate(String filename) 297 throws NotFoundException 298 { 299 return wm.getTemplate(filename); 300 } 301 302 /*** 303 * This method returns the WebMacro object which will be used to 304 * load, access, and manage the Broker. The WM first tries to 305 * locate the WebMacro properties file in the location specified 306 * by the 'services.WebmacroService.properties' key in the 307 * TurbineResource file. If the key is not set, it will search 308 * the classpath looking for the file. 309 * 310 * @param config A ServletConfig. 311 * @exception InitException Thrown by WebMacro. 312 * @exception InitializationException Thrown by Turbine. 313 */ 314 private void initWebMacro() 315 throws InitException, InitializationException 316 { 317 Configuration config = getConfiguration(); 318 319 /* 320 * We retrieve the template paths here and translate 321 * them so that we have a functional templateExists(name) 322 * method in this service. This happens again in 323 * the provider so that we don't have to store the 324 * converted configuration, and we don't want to 325 * store them because the initialization of this 326 * service is done in one pass. This means that 327 * the provider trying to retrieve the converted 328 * properties via this service we get a recursion 329 * problem. What would be idea is if the service 330 * broker could store the properties for each of 331 * the services, even if they are converted. Just 332 * trying to explain what's going on. 333 */ 334 templatePaths = config.getStringArray("templates"); 335 templatePaths = TurbineTemplate.translateTemplatePaths(templatePaths); 336 337 WMTemplateProvider = config.getString("templates.provider", null); 338 WMProperties = config.getString("properties"); 339 340 if (WMProperties != null) 341 { 342 /* 343 * If possible, transform paths to be webapp 344 * root relative. 345 */ 346 WMProperties = TurbineServlet.getRealPath(WMProperties); 347 wm = new WM(WMProperties); 348 } 349 else 350 { 351 /* 352 * Not specified: fallback to WM style properties search 353 * through the classpath. 354 */ 355 wm = new WM(); 356 } 357 broker = wm.getBroker(); 358 359 try 360 { 361 ResourceBroker resourceBroker = (ResourceBroker)broker; 362 363 /* 364 * Replace WM's TemplateProvider with Turbine's. 365 */ 366 try 367 { 368 /* 369 * Instantiate Turbine's TemplateProvider. 370 */ 371 Log.debug("Loading TurbineTemplateProvider"); 372 Class c = Class.forName(WMTemplateProvider); 373 ResourceProvider provider = (ResourceProvider)c.newInstance(); 374 375 /* 376 * Register the provider with the broker. 377 */ 378 Log.debug("Registering TurbineTemplateProvider with WebMacro"); 379 resourceBroker.join(provider); 380 // TODO: Find WM template provider instance and remove it. 381 // ResourceProvider wmProvier = null; 382 // resourceBroker.leave(wmProvider); 383 } 384 catch (Exception e) 385 { 386 throw new TurbineException 387 ("Unable to register TurbineTemplateProvider", e); 388 } 389 390 // Note that WebMacro.properties shouldn't contain 391 // org.webmacro.resource.TemplateProvider in the Providers 392 // entry, because then we would have two TemplateProviders 393 // in the system, one of wich would be non functional and 394 // would waste cycles during every request. 395 // 396 // It seems reasonable to me, that there should be a 397 // possibility to ask the broker if it knows any providers 398 // of a specified type of resource. This would allow us 399 // to notify the user that there is a non-functional 400 // provider in the system, that should be removed from the 401 // config file. Better yet, if the browser supported 402 // enumerating providers of a specified type of resource, 403 // we could locate such provider, and ask it to terminate. 404 // 405 // The broker class in the WM snapshot I have doesn't 406 // support either of these options, and I don't feel 407 // competent enough to implement it. 408 // 409 // Rafal 410 } 411 catch (Exception e) 412 { 413 throw new InitializationException 414 ("Failed to set up WebMacro templates", e); 415 } 416 } 417 418 /*** 419 * This method must return a cloneable WebContext which can be 420 * cloned for use in responding to individual requests. Each 421 * incoming request will receive a clone of the returned object as 422 * its context. The default implementation is to return a new 423 * WebContext. 424 * 425 * @exception InitException. 426 */ 427 private void initWebContext() 428 throws InitException 429 { 430 wcPrototype = getContext(); 431 if (wcPrototype == null) 432 { 433 throw new InitException 434 ("Unable to create WebContext prototype"); 435 } 436 } 437 438 /*** 439 * Determine whether a given template exists. This service 440 * currently only supports file base template hierarchies 441 * so we will use the utility methods provided by 442 * the template service to do the searching. 443 * 444 * @param String template 445 * @return boolean 446 */ 447 public boolean templateExists(String template) 448 { 449 return TurbineTemplate.templateExists(template, templatePaths); 450 } 451 }

This page was automatically generated by Maven