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