KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fulcrum > velocity > TurbineVelocityService


1 package org.apache.fulcrum.velocity;
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.util.List JavaDoc;
58 import java.util.Vector JavaDoc;
59 import java.util.Iterator JavaDoc;
60 import java.util.Enumeration JavaDoc;
61 import java.io.IOException JavaDoc;
62 import java.io.OutputStream JavaDoc;
63 import java.io.Writer JavaDoc;
64 import java.io.OutputStreamWriter JavaDoc;
65 import java.io.ByteArrayOutputStream JavaDoc;
66 import org.apache.velocity.VelocityContext;
67 import org.apache.velocity.app.VelocityEngine;
68 import org.apache.velocity.app.event.EventCartridge;
69 import org.apache.velocity.app.event.ReferenceInsertionEventHandler;
70 import org.apache.velocity.app.event.NullSetEventHandler;
71 import org.apache.velocity.app.event.MethodExceptionEventHandler;
72 import org.apache.velocity.context.Context;
73 import org.apache.velocity.context.InternalEventContext;
74 import org.apache.velocity.exception.MethodInvocationException;
75 import org.apache.fulcrum.ServiceException;
76 import org.apache.fulcrum.InitializationException;
77 import org.apache.fulcrum.template.TemplateContext;
78 import org.apache.fulcrum.template.BaseTemplateEngineService;
79 import org.apache.commons.configuration.ConfigurationConverter;
80
81 /**
82  * This is a Service that can process Velocity templates from within a
83  * Turbine Screen. Here's an example of how you might use it from a
84  * screen:<br>
85  *
86  * <code><pre>
87  * Context context = new VelocityContext();
88  * context.put("message", "Hello from Turbine!");
89  * String results = TurbineVelocity.handleRequest(context,"HelloWorld.vm");
90  * </pre></code>
91  *
92  * Character sets map codes to glyphs, while encodings map between
93  * chars/bytes and codes.
94  * <i>bytes -> [encoding] -> charset -> [rendering] -> glyphs</i>
95  *
96  * @author <a HREF="mailto:mbryson@mont.mindspring.com">Dave Bryson</a>
97  * @author <a HREF="mailto:krzewski@e-point.pl">Rafal Krzewski</a>
98  * @author <a HREF="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
99  * @author <a HREF="mailto:sean@informage.ent">Sean Legassick</a>
100  * @author <a HREF="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
101  * @author <a HREF="mailto:jon@latchkey.com">Jon S. Stevens</a>
102  * @author <a HREF="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
103  * @author <a HREF="mailto:james@jamestaylor.org">James Taylor</a>
104  * @version $Id: TurbineVelocityService.java,v 1.1 2004/11/12 10:25:47 epugh Exp $
105  */

106 public class TurbineVelocityService
107     extends BaseTemplateEngineService
108     implements VelocityService
109 {
110     /**
111      * The generic resource loader path property in velocity.
112      */

113     private static final String JavaDoc RESOURCE_LOADER_PATH =
114         ".resource.loader.path";
115
116     /**
117      * Default character set to use if not specified by caller.
118      */

119     private static final String JavaDoc DEFAULT_CHAR_SET = "ISO-8859-1";
120
121     /**
122      * The prefix used for URIs which are of type <code>jar</code>.
123      */

124     private static final String JavaDoc JAR_PREFIX = "jar:";
125
126     /**
127      * The prefix used for URIs which are of type <code>absolute</code>.
128      */

129     private static final String JavaDoc ABSOLUTE_PREFIX = "file://";
130
131     /**
132      * The EventCartridge that is used against all contexts
133      */

134     private EventCartridge eventCartridge;
135
136     /**
137      * Whether or not to use the eventCartridge. Defaults to true.
138      * Can be used to turn off EC processing.
139      */

140     private boolean eventCartridgeEnabled = true;
141
142     /**
143      * The VelocityEngine used by the service to merge templates
144      */

145     private VelocityEngine velocityEngine = new VelocityEngine();
146
147     /**
148      * Performs early initialization of this Turbine service.
149      */

150     public void init()
151         throws InitializationException
152     {
153         try
154         {
155             initVelocity();
156             initEventCartridges();
157
158             // Register with the template service.
159
registerConfiguration("vm");
160             setInit(true);
161         }
162         catch (Exception JavaDoc e)
163         {
164             e.printStackTrace();
165             throw new InitializationException(
166                 "Failed to initialize TurbineVelocityService", e);
167         }
168     }
169
170     /**
171      * @see org.apache.fulcrum.velocity.VelocityService
172      */

173     public String JavaDoc handleRequest(TemplateContext context, String JavaDoc template)
174         throws ServiceException
175     {
176         return handleRequest(new ContextAdapter(context), template);
177     }
178
179     /**
180      * @see org.apache.fulcrum.velocity.VelocityService
181      */

182     public String JavaDoc handleRequest(Context context, String JavaDoc filename)
183         throws ServiceException
184     {
185         return handleRequest(context, filename, (String JavaDoc)null, null);
186     }
187
188     /**
189      * @see org.apache.fulcrum.velocity.VelocityService
190      */

191     public String JavaDoc handleRequest(Context context, String JavaDoc filename,
192                                 String JavaDoc charset, String JavaDoc encoding)
193         throws ServiceException
194     {
195         String JavaDoc results = null;
196         ByteArrayOutputStream JavaDoc bytes = null;
197
198         try
199         {
200             bytes = new ByteArrayOutputStream JavaDoc();
201             charset = decodeRequest(context, filename, bytes, charset,
202                                     encoding);
203             results = bytes.toString(charset);
204         }
205         catch (Exception JavaDoc e)
206         {
207             renderingError(filename, e);
208         }
209         finally
210         {
211             try
212             {
213                 if (bytes != null)
214                 {
215                     bytes.close();
216                 }
217             }
218             catch (IOException JavaDoc ignored)
219             {
220             }
221         }
222         return results;
223     }
224
225     /**
226      * @see org.apache.fulcrum.template.TemplateEngineService
227      */

228     public void handleRequest(TemplateContext context, String JavaDoc template,
229                               OutputStream JavaDoc outputStream)
230         throws ServiceException
231     {
232         handleRequest(new ContextAdapter(context), template, outputStream);
233     }
234
235     /**
236      * @see org.apache.fulcrum.velocity.VelocityService
237      */

238     public void handleRequest(Context context, String JavaDoc filename,
239                               OutputStream JavaDoc output)
240         throws ServiceException
241     {
242         handleRequest(context, filename, output, null, null);
243     }
244
245     /**
246      * @see org.apache.fulcrum.velocity.VelocityService
247      */

248     public void handleRequest(Context context, String JavaDoc filename,
249                               OutputStream JavaDoc output, String JavaDoc charset,
250                               String JavaDoc encoding)
251         throws ServiceException
252     {
253         decodeRequest(context, filename, output, charset, encoding);
254     }
255
256     /**
257      * @see BaseTemplateEngineService#handleRequest(TemplateContext, String, Writer)
258      */

259     public void handleRequest(TemplateContext context,
260                                        String JavaDoc template, Writer JavaDoc writer)
261         throws ServiceException
262     {
263         handleRequest(new ContextAdapter(context), template, writer);
264     }
265
266     /**
267      * @see VelocityService#handleRequest(Context, String, Writer)
268      */

269     public void handleRequest(Context context, String JavaDoc filename,
270                               Writer JavaDoc writer)
271         throws ServiceException
272     {
273         handleRequest(context, filename, writer, null);
274     }
275
276     /**
277      * @see VelocityService#handleRequest(Context, String, Writer, String)
278      */

279     public void handleRequest(Context context, String JavaDoc filename,
280                               Writer JavaDoc writer, String JavaDoc encoding)
281         throws ServiceException
282     {
283         try
284         {
285             // If the context is not already an instance of
286
// InternalEventContext, wrap it in a VeclocityContext so that
287
// event cartridges will work. Unfortunately there is no interface
288
// that extends both Context and InternalEventContext, so this
289
// is not as clear as it could be.
290

291             Context eventContext;
292
293             if ( context instanceof InternalEventContext )
294             {
295                 eventContext = context;
296             }
297             else
298             {
299                 eventContext = new VelocityContext( context );
300             }
301
302             // Attach the EC to the context
303
EventCartridge ec = getEventCartridge();
304             if (ec != null && eventCartridgeEnabled)
305             {
306                 ec.attachToContext(eventContext);
307             }
308
309             if (encoding != null)
310             {
311                 // Request scoped encoding first supported by Velocity 1.1.
312
velocityEngine.mergeTemplate(filename, encoding,
313                                              eventContext, writer);
314             }
315             else
316             {
317                 velocityEngine.mergeTemplate(filename, eventContext, writer);
318             }
319         }
320         catch (Exception JavaDoc e)
321         {
322             renderingError(filename, e);
323         }
324     }
325
326     /**
327      * By default, this is true if there is configured event cartridges.
328      * You can disable EC processing if you first disable it and then call
329      * handleRequest.
330      */

331     public void setEventCartridgeEnabled(boolean value)
332     {
333         this.eventCartridgeEnabled = value;
334     }
335
336     /**
337      * @return EventCartridge the event cartridge
338      */

339     public EventCartridge getEventCartridge()
340     {
341         return eventCartridge;
342     }
343
344     /**
345      * Processes the request and fill in the template with the values
346      * you set in the the supplied Context. Applies the specified
347      * character and template encodings.
348      *
349      * @param context A context to use when evaluating the specified
350      * template.
351      * @param filename The file name of the template.
352      * @param output The stream to which we will write the processed
353      * template as a String.
354      * @return The character set applied to the resulting text.
355      *
356      * @throws ServiceException Any exception trown while processing
357      * will be wrapped into a ServiceException and rethrown.
358      */

359     private String JavaDoc decodeRequest(Context context, String JavaDoc filename,
360                                  OutputStream JavaDoc output, String JavaDoc charset,
361                                  String JavaDoc encoding)
362         throws ServiceException
363     {
364         // TODO: Push this method of getting character set & encoding
365
// from RunData back into Turbine.
366
// charset = ((RunData) data).getCharSet();
367
// encoding = ((RunData) data).getTemplateEncoding();
368

369         if (charset == null)
370         {
371             charset = DEFAULT_CHAR_SET;
372         }
373
374         OutputStreamWriter JavaDoc writer = null;
375         try
376         {
377             try
378             {
379                 writer = new OutputStreamWriter JavaDoc(output, charset);
380             }
381             catch (Exception JavaDoc e)
382             {
383                 renderingError(filename, e);
384             }
385             handleRequest(context, filename, writer, encoding);
386         }
387         finally
388         {
389             try
390             {
391                 if (writer != null)
392                 {
393                     writer.flush();
394                 }
395             }
396             catch (Exception JavaDoc ignored)
397             {
398             }
399         }
400         return charset;
401     }
402
403     /**
404      * Macro to handle rendering errors.
405      *
406      * @param filename The file name of the unrenderable template.
407      * @param e The error.
408      *
409      * @exception ServiceException Thrown every time. Adds additional
410      * information to <code>e</code>.
411      */

412     private final void renderingError(String JavaDoc filename, Throwable JavaDoc e)
413         throws ServiceException
414     {
415         String JavaDoc err = "Error rendering Velocity template: " + filename;
416         getCategory().error(err + ": " + e.getMessage());
417         // if the Exception is a MethodInvocationException, the underlying
418
// Exception is likely to be more informative, so rewrap that one.
419
if (e instanceof MethodInvocationException)
420         {
421             e = ((MethodInvocationException)e).getWrappedThrowable();
422         }
423
424         throw new ServiceException(err, e);
425     }
426
427     /**
428      * This method is responsible for initializing the various Velocity
429      * EventCartridges. You just add a configuration like this:
430      * <code>
431      * services.VelocityService.eventCartridge.classes = org.tigris.scarab.util.ReferenceInsertionFilter
432      * </code>
433      * and list out (comma separated) the list of EC's that you want to
434      * initialize.
435      */

436     private void initEventCartridges()
437         throws InitializationException
438     {
439         eventCartridge = new EventCartridge();
440
441         List JavaDoc ecconfig = getConfiguration()
442             .getList("eventCartridge.classes", null);
443         if (ecconfig == null)
444         {
445             getCategory().info("No Velocity EventCartridges configured.");
446             return;
447         }
448
449         Object JavaDoc obj = null;
450         String JavaDoc className = null;
451         for (Iterator JavaDoc i = ecconfig.iterator() ; i.hasNext() ;)
452         {
453             className = (String JavaDoc) i.next();
454             try
455             {
456                 boolean result = false;
457
458                 obj = Class.forName(className).newInstance();
459
460                 if (obj instanceof ReferenceInsertionEventHandler)
461                 {
462                     result = getEventCartridge()
463                         .addEventHandler((ReferenceInsertionEventHandler)obj);
464                 }
465                 else if (obj instanceof NullSetEventHandler)
466                 {
467                     result = getEventCartridge()
468                         .addEventHandler((NullSetEventHandler)obj);
469                 }
470                 else if (obj instanceof MethodExceptionEventHandler)
471                 {
472                     result = getEventCartridge()
473                         .addEventHandler((MethodExceptionEventHandler)obj);
474                 }
475                 getCategory().info("Added EventCartridge: " +
476                     obj.getClass().getName() + " : " + result);
477             }
478             catch (Exception JavaDoc h)
479             {
480                 throw new InitializationException(
481                     "Could not initialize EventCartridge: " +
482                     className, h);
483             }
484         }
485     }
486
487     /**
488      * Setup the velocity runtime by using a subset of the
489      * Turbine configuration which relates to velocity.
490      *
491      * @exception InitializationException For any errors during initialization.
492      */

493     private void initVelocity()
494         throws InitializationException
495     {
496         // Now we have to perform a couple of path translations
497
// for our log file and template paths.
498
String JavaDoc path = getRealPath(
499             getConfiguration().getString(VelocityEngine.RUNTIME_LOG, null));
500
501         if (path != null && path.length() > 0)
502         {
503             getConfiguration().setProperty(VelocityEngine.RUNTIME_LOG, path);
504         }
505         else
506         {
507             String JavaDoc msg = VelocityService.SERVICE_NAME + " runtime log file " +
508                 "is misconfigured: '" + path + "' is not a valid log file";
509
510             throw new Error JavaDoc(msg);
511         }
512
513         // Get all the template paths where the velocity
514
// runtime should search for templates and
515
// collect them into a separate vector
516
// to avoid concurrent modification exceptions.
517
String JavaDoc key;
518         Vector JavaDoc keys = new Vector JavaDoc();
519         for (Iterator JavaDoc i = getConfiguration().getKeys(); i.hasNext();)
520         {
521             key = (String JavaDoc) i.next();
522             if (key.endsWith(RESOURCE_LOADER_PATH))
523             {
524                 keys.add(key);
525             }
526         }
527
528         // Loop through all template paths, clear the corresponding
529
// velocity properties and translate them all to the webapp space.
530
int ind;
531         List JavaDoc paths;
532         String JavaDoc entry;
533         for (Iterator JavaDoc i = keys.iterator(); i.hasNext();)
534         {
535             key = (String JavaDoc) i.next();
536             paths = getConfiguration().getList(key,null);
537             if (paths != null)
538             {
539                 velocityEngine.clearProperty(key);
540                 getConfiguration().clearProperty(key);
541
542                 for (Iterator JavaDoc j = paths.iterator(); j.hasNext();)
543                 {
544                     path = (String JavaDoc) j.next();
545                     if (path.startsWith(JAR_PREFIX + "file"))
546                     {
547                         // A local jar resource URL path is a bit more
548
// complicated, but we can translate it as well.
549
ind = path.indexOf("!/");
550                         if (ind >= 0)
551                         {
552                             entry = path.substring(ind);
553                             path = path.substring(9,ind);
554                         }
555                         else
556                         {
557                             entry = "!/";
558                             path = path.substring(9);
559                         }
560                         path = JAR_PREFIX + "file:" + getRealPath(path) +
561                             entry;
562                     }
563                     else if (path.startsWith(ABSOLUTE_PREFIX))
564                     {
565                         path = path.substring (ABSOLUTE_PREFIX.length(),
566                                                path.length());
567                     }
568                     else if (!path.startsWith(JAR_PREFIX))
569                     {
570                         // But we don't translate remote jar URLs.
571
path = getRealPath(path);
572                     }
573                     // Put the translated paths back to the configuration.
574
getConfiguration().addProperty(key,path);
575                 }
576             }
577         }
578
579         try
580         {
581             velocityEngine.setExtendedProperties(ConfigurationConverter
582                     .getExtendedProperties(getConfiguration()));
583
584             velocityEngine.init();
585         }
586         catch(Exception JavaDoc e)
587         {
588             // This will be caught and rethrown by the init() method.
589
// Oh well, that will protect us from RuntimeException folk showing
590
// up somewhere above this try/catch
591
throw new InitializationException(
592                 "Failed to set up TurbineVelocityService", e);
593         }
594     }
595
596     /**
597      * Find out if a given template exists. Velocity
598      * will do its own searching to determine whether
599      * a template exists or not.
600      *
601      * @param String template to search for
602      * @return boolean
603      */

604     public boolean templateExists(String JavaDoc template)
605     {
606         return velocityEngine.templateExists(template);
607     }
608 }
609
Popular Tags