KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > opensymphony > webwork > portlet > velocity > VelocityManager


1 /*
2  * Copyright (c) 2005 Opensymphony. All Rights Reserved.
3  */

4 package com.opensymphony.webwork.portlet.velocity;
5
6 import com.opensymphony.webwork.ServletActionContext;
7 import com.opensymphony.webwork.config.Configuration;
8 import com.opensymphony.webwork.util.VelocityWebWorkUtil;
9 import com.opensymphony.webwork.util.WebWorkUtil;
10 import com.opensymphony.webwork.views.jsp.ui.OgnlTool;
11 import com.opensymphony.webwork.views.util.ContextUtil;
12 import com.opensymphony.webwork.views.velocity.BodyTagDirective;
13 import com.opensymphony.webwork.views.velocity.ParamDirective;
14 import com.opensymphony.webwork.views.velocity.TagDirective;
15 import com.opensymphony.webwork.views.velocity.WebWorkVelocityContext;
16 import com.opensymphony.webwork.views.velocity.components.*;
17 import com.opensymphony.xwork.ObjectFactory;
18 import com.opensymphony.xwork.util.OgnlValueStack;
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.apache.velocity.VelocityContext;
22 import org.apache.velocity.app.Velocity;
23 import org.apache.velocity.app.VelocityEngine;
24 import org.apache.velocity.context.Context;
25 import org.apache.velocity.tools.view.ToolboxManager;
26 import org.apache.velocity.tools.view.context.ChainedContext;
27 import org.apache.velocity.tools.view.servlet.ServletToolboxManager;
28
29 import javax.servlet.ServletContext JavaDoc;
30 import javax.servlet.http.HttpServletRequest JavaDoc;
31 import javax.servlet.http.HttpServletResponse JavaDoc;
32 import java.io.File JavaDoc;
33 import java.io.FileInputStream JavaDoc;
34 import java.io.IOException JavaDoc;
35 import java.io.InputStream JavaDoc;
36 import java.util.*;
37
38 /**
39  * * Revise the original VelocityManager for WebWork to
40  * <li>add the actionURL implement in VelocityManager for Portlet
41  * <li>init the Velocity Engine from ServletContext.
42  *
43  * @author <a HREF="mailto:hu_pengfei@yahoo.com.cn">Henry Hu </a>
44  * @since 2005-7-18
45  */

46
47 /**
48  * Manages the environment for Velocity result types
49  *
50  * @author Matt Ho <matt@indigoegg.com>
51  */

52 public class VelocityManager {
53     //~ Static fields/initializers
54
// /////////////////////////////////////////////
55

56     private static final Log log = LogFactory.getLog(VelocityManager.class);
57
58     private static VelocityManager instance;
59
60     //In order to get the Portlet actionURL in VM result, add this attribute in
61
// Context. Add for Portlet
62
public static final String JavaDoc ACTION_URL = "actionURL";
63
64     public static final String JavaDoc ACTION_XURL = "actionXURL";
65
66     public static final String JavaDoc WEBWORK = "webwork";
67
68     /**
69      * the parent JSP tag
70      */

71     public static final String JavaDoc PARENT = "parent";
72
73     /**
74      * the current JSP tag
75      */

76     public static final String JavaDoc TAG = "tag";
77
78     //~ Instance fields
79
// ////////////////////////////////////////////////////////
80
private OgnlTool ognlTool = OgnlTool.getInstance();
81
82     private VelocityEngine velocityEngine;
83
84     /**
85      * A reference to the toolbox manager.
86      */

87     protected ToolboxManager toolboxManager = null;
88
89     private String JavaDoc toolBoxLocation;
90
91     private VelocityContext[] chainedContexts;
92
93     /**
94      * Names of contexts that will be chained on every request
95      */

96     private String JavaDoc[] chainedContextNames;
97
98     //~ Constructors
99
// ///////////////////////////////////////////////////////////
100

101     protected VelocityManager() {
102         init();
103     }
104
105     //~ Methods
106
// ////////////////////////////////////////////////////////////////
107

108     /**
109      * retrieve an instance to the current VelocityManager
110      */

111     public synchronized static VelocityManager getInstance() {
112         if (instance == null) {
113             String JavaDoc classname = VelocityManager.class.getName();
114
115             if (Configuration.isSet("webwork.velocity.manager.classname")) {
116                 classname = Configuration.getString("webwork.velocity.manager.classname").trim();
117             }
118
119             if (!classname.equals(VelocityManager.class.getName())) {
120                 try {
121                     log.info("Instantiating VelocityManager!, " + classname);
122                     instance = (VelocityManager) ObjectFactory.getObjectFactory().buildBean(Class.forName(classname));
123                 } catch (Exception JavaDoc e) {
124                     log.fatal("Fatal exception occurred while trying to instantiate a VelocityManager instance, " + classname, e);
125                     instance = new VelocityManager();
126                 }
127             } else {
128                 instance = new VelocityManager();
129             }
130         }
131
132         return instance;
133     }
134
135     /**
136      * @return a reference to the VelocityEngine used by <b>all </b> webwork
137      * velocity thingies with the exception of directly accessed *.vm
138      * pages
139      */

140     public VelocityEngine getVelocityEngine() {
141         return velocityEngine;
142     }
143
144     /**
145      * This method is responsible for creating the standard VelocityContext used
146      * by all WW2 velocity views. The following context parameters are defined:
147      * <p/>
148      * <ul>
149      * <li><strong>req </strong>- the current HttpServletRequest</li>
150      * <li><strong>res </strong>- the current HttpServletResponse</li>
151      * <li><strong>stack </strong>- the current {@link OgnlValueStack}</li>
152      * <li><strong>ognl </strong>- an {@link OgnlTool}</li>
153      * <li><strong>webwork </strong>- an instance of {@link WebWorkUtil}</li>
154      * <li><strong>action </strong>- the current WebWork action</li>
155      * </ul>
156      *
157      * @return a new WebWorkVelocityContext
158      */

159     public Context createContext(OgnlValueStack stack, HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc res) {
160         ///
161
VelocityContext[] chainedContexts = prepareChainedContexts(req, res);
162         WebWorkVelocityContext context = new WebWorkVelocityContext(chainedContexts, stack);
163
164         Map standardMap = ContextUtil.getStandardContext(stack, req, res);
165         for (Iterator iterator = standardMap.entrySet().iterator(); iterator.hasNext();) {
166             Map.Entry entry = (Map.Entry) iterator.next();
167             context.put((String JavaDoc) entry.getKey(), entry.getValue());
168         }
169         context.put(WEBWORK, new VelocityWebWorkUtil(context, stack, req, res));
170
171         /*
172          * Add actiontURl/actionXURL in the OGNL context for VM result to
173          * retrieve. -- Add for Portlet
174          */

175         String JavaDoc actionURL = com.opensymphony.webwork.portlet.context.PortletContext.getContext().getActionURL();
176         String JavaDoc actionXURL = actionURL + "?wwXAction=";
177         context.put(ACTION_URL, actionURL);
178         context.put(ACTION_XURL, actionXURL);
179         ////////////////////////////////////
180

181         ServletContext JavaDoc ctx = null;
182         try {
183             ctx = ServletActionContext.getServletContext();
184         } catch (NullPointerException JavaDoc npe) {
185             // in case this was used outside the lifecycle of webwork servlet
186
log.debug("internal toolbox context ignored");
187         }
188
189         if (toolboxManager != null && ctx != null) {
190             ChainedContext chained = new ChainedContext(context, req, res, ctx);
191             chained.setToolbox(toolboxManager.getToolboxContext(null));
192             return chained;
193         } else {
194             return context;
195         }
196
197     }
198
199     /**
200      * constructs contexts for chaining on this request. This method does not
201      * perform any initialization of the contexts. All that must be done in the
202      * context itself.
203      *
204      * @param servletRequest
205      * @param servletResponse
206      * @return an VelocityContext[] of contexts to chain
207      */

208     protected VelocityContext[] prepareChainedContexts(HttpServletRequest JavaDoc servletRequest, HttpServletResponse JavaDoc servletResponse) {
209         if (this.chainedContextNames == null) {
210             return null;
211         }
212         List contextList = new ArrayList();
213         for (int i = 0; i < chainedContextNames.length; i++) {
214             String JavaDoc className = chainedContextNames[i];
215             try {
216                 VelocityContext velocityContext = (VelocityContext) ObjectFactory.getObjectFactory().buildBean(className);
217                 contextList.add(velocityContext);
218             } catch (Exception JavaDoc e) {
219                 log.warn("Warning. " + e.getClass().getName() + " caught while attempting to instantiate a chained VelocityContext, "
220                         + className + " -- skipping");
221             }
222         }
223         if (contextList.size() > 0) {
224             VelocityContext[] extraContexts = new VelocityContext[contextList.size()];
225             contextList.toArray(extraContexts);
226             return extraContexts;
227         } else {
228             return null;
229         }
230     }
231
232     /**
233      * initializes the VelocityManager. this should be called during the
234      * initialization process, say by ServletDispatcher. this may be called
235      * multiple times safely although calls beyond the first won't do anything
236      *
237      * @param context the current servlet context
238      */

239     public synchronized void init(ServletContext JavaDoc context) {
240         if (velocityEngine == null) {
241             velocityEngine = newVelocityEngine(context);
242         }
243         this.initToolbox(context);
244     }
245
246     /**
247      * load optional velocity properties using the following loading strategy
248      * <ul>
249      * <li>relative to the servlet context path</li>
250      * <li>relative to the WEB-INF directory</li>
251      * <li>on the classpath</li>
252      * </ul>
253      *
254      * @param context the current ServletContext. may <b>not </b> be null
255      * @return the optional properties if webwork.velocity.configfile was
256      * specified, an empty Properties file otherwise
257      */

258     public Properties loadConfiguration(ServletContext JavaDoc context) {
259         if (context == null) {
260             String JavaDoc gripe = "Error attempting to create a loadConfiguration from a null ServletContext!";
261             log.error(gripe);
262             throw new IllegalArgumentException JavaDoc(gripe);
263         }
264
265         Properties properties = new Properties();
266
267         // now apply our systemic defaults, then allow user to override
268
applyDefaultConfiguration(context, properties);
269
270         //fixed for velocity.properties userdirectvie property --Added by Henry Hu
271
String JavaDoc defaultUserDirective = properties.getProperty("userdirective");
272
273         /**
274          * if the user has specified an external velocity configuration file,
275          * we'll want to search for it in the following order
276          *
277          * 1. relative to the context path 2. relative to /WEB-INF 3. in the
278          * class path
279          */

280         String JavaDoc configfile;
281
282         if (Configuration.isSet("webwork.velocity.configfile")) {
283             configfile = Configuration.getString("webwork.velocity.configfile");
284         } else {
285             configfile = "velocity.properties";
286         }
287
288         configfile = configfile.trim();
289
290         InputStream JavaDoc in = null;
291         String JavaDoc resourceLocation = null;
292
293         try {
294             if (context.getRealPath(configfile) != null) {
295                 // 1. relative to context path, i.e. /velocity.properties
296
String JavaDoc filename = context.getRealPath(configfile);
297
298                 if (filename != null) {
299                     File JavaDoc file = new File JavaDoc(filename);
300
301                     if (file.isFile()) {
302                         resourceLocation = file.getCanonicalPath() + " from file system";
303                         in = new FileInputStream JavaDoc(file);
304                     }
305
306                     // 2. if nothing was found relative to the context path,
307
// search relative to the WEB-INF directory
308
if (in == null) {
309                         file = new File JavaDoc(context.getRealPath("/WEB-INF/" + configfile));
310
311                         if (file.isFile()) {
312                             resourceLocation = file.getCanonicalPath() + " from file system";
313                             in = new FileInputStream JavaDoc(file);
314                         }
315                     }
316                 }
317             }
318
319             // 3. finally, if there's no physical file, how about something in
320
// our classpath
321
if (in == null) {
322                 in = VelocityManager.class.getClassLoader().getResourceAsStream(configfile);
323                 if (in != null) {
324                     resourceLocation = configfile + " from classloader";
325                 }
326             }
327
328             // if we've got something, load 'er up
329
if (in != null) {
330                 log.info("Initializing velocity using " + resourceLocation);
331                 properties.load(in);
332             }
333         } catch (IOException JavaDoc e) {
334             log.warn("Unable to load velocity configuration " + resourceLocation, e);
335         } finally {
336             if (in != null) {
337                 try {
338                     in.close();
339                 } catch (IOException JavaDoc e) {
340                 }
341             }
342         }
343
344         //fixed for velocity.properties userdirectvie property -Added by Henry Hu
345
String JavaDoc userdirective = properties.getProperty("userdirective");
346
347         if ((userdirective == null) || userdirective.trim().equals("")) {
348             userdirective = defaultUserDirective;
349         } else {
350             userdirective = userdirective.trim() + "," + defaultUserDirective;
351         }
352
353         properties.setProperty("userdirective", userdirective);
354         ///////////////////////////////
355

356         // for debugging purposes, allows users to dump out the properties that
357
// have been configured
358
if (log.isDebugEnabled()) {
359             log.debug("Initializing Velocity with the following properties ...");
360
361             for (Iterator iter = properties.keySet().iterator(); iter.hasNext();) {
362                 String JavaDoc key = (String JavaDoc) iter.next();
363                 String JavaDoc value = properties.getProperty(key);
364
365                 if (log.isDebugEnabled()) {
366                     log.warn(" '" + key + "' = '" + value + "'");
367                 }
368             }
369         }
370
371         return properties;
372     }
373
374     /**
375      * performs one-time initializations
376      */

377     protected void init() {
378
379         // read in the names of contexts to add to each request
380
initChainedContexts();
381
382         if (Configuration.isSet("webwork.velocity.toolboxlocation")) {
383             toolBoxLocation = Configuration.get("webwork.velocity.toolboxlocation").toString();
384         }
385
386     }
387
388     /**
389      * Initializes the ServletToolboxManager for this servlet's toolbox (if
390      * any).
391      *
392      * @param config servlet configuation
393      */

394     protected void initToolbox(ServletContext JavaDoc context) {
395         /* if we have a toolbox, get a manager for it */
396         if (toolBoxLocation != null) {
397             toolboxManager = ServletToolboxManager.getInstance(context, toolBoxLocation);
398         } else {
399             Velocity.info("VelocityViewServlet: No toolbox entry in configuration.");
400         }
401     }
402
403     /**
404      * allow users to specify via the webwork.properties file a set of
405      * additional VelocityContexts to chain to the the WebWorkVelocityContext.
406      * The intent is to allow these contexts to store helper objects that the ui
407      * developer may want access to. Examples of reasonable VelocityContexts
408      * would be an IoCVelocityContext, a SpringReferenceVelocityContext, and a
409      * ToolboxVelocityContext
410      */

411     protected void initChainedContexts() {
412
413         if (Configuration.isSet("webwork.velocity.contexts")) {
414             // we expect contexts to be a comma separated list of classnames
415
String JavaDoc contexts = Configuration.get("webwork.velocity.contexts").toString();
416             StringTokenizer st = new StringTokenizer(contexts, ",");
417             List contextList = new ArrayList();
418
419             while (st.hasMoreTokens()) {
420                 String JavaDoc classname = st.nextToken();
421                 contextList.add(classname);
422             }
423             if (contextList.size() > 0) {
424                 String JavaDoc[] chainedContexts = new String JavaDoc[contextList.size()];
425                 contextList.toArray(chainedContexts);
426                 this.chainedContextNames = chainedContexts;
427             }
428
429         }
430
431     }
432
433     /**
434      * <p/>Instantiates a new VelocityEngine.
435      * </p>
436      * <p/>The following is the default Velocity configuration
437      * </p>
438      * <p/>
439      * <pre>
440      * <p/>
441      * <p/>
442      * resource.loader = file, class
443      * file.resource.loader.path = real path of webapp
444      * class.resource.loader.description = Velocity Classpath Resource Loader
445      * class.resource.loader.class = com.opensymphony.webwork.views.velocity.WebWorkResourceLoader
446      * <p/>
447      * <p/>
448      * </pre>
449      * <p/>
450      * <p/>this default configuration can be overridden by specifying a
451      * webwork.velocity.configfile property in the webwork.properties file. the
452      * specified config file will be searched for in the following order:
453      * </p>
454      * <ul>
455      * <li>relative to the servlet context path</li>
456      * <li>relative to the WEB-INF directory</li>
457      * <li>on the classpath</li>
458      * </ul>
459      *
460      * @param context the current ServletContext. may <b>not </b> be null
461      */

462     protected VelocityEngine newVelocityEngine(ServletContext JavaDoc context) {
463         if (context == null) {
464             String JavaDoc gripe = "Error attempting to create a new VelocityEngine from a null ServletContext!";
465             log.error(gripe);
466             throw new IllegalArgumentException JavaDoc(gripe);
467         }
468
469         Properties p = loadConfiguration(context);
470
471         VelocityEngine velocityEngine = new VelocityEngine();
472
473         try {
474             velocityEngine.init(p);
475         } catch (Exception JavaDoc e) {
476             String JavaDoc gripe = "Unable to instantiate VelocityEngine!";
477             log.error(gripe, e);
478             throw new RuntimeException JavaDoc(gripe);
479         }
480
481         return velocityEngine;
482     }
483
484     /**
485      * once we've loaded up the user defined configurations, we will want to
486      * apply WebWork specification configurations.
487      * <ul>
488      * <li>if Velocity.RESOURCE_LOADER has not been defined, then we will use
489      * the defaults which is a joined file, class loader for unpackaed wars and
490      * a straight class loader otherwise</li>
491      * <li>we need to define the various WebWork custom user directives such as
492      * #param, #tag, and #bodytag</li>
493      * </ul>
494      *
495      * @param context
496      * @param p
497      */

498     private void applyDefaultConfiguration(ServletContext JavaDoc context, Properties p) {
499         // ensure that caching isn't overly aggressive
500

501         /**
502          * Load a default resource loader definition if there isn't one present.
503          * Ben Hall (22/08/2003)
504          */

505         if (p.getProperty(Velocity.RESOURCE_LOADER) == null) {
506             p.setProperty(Velocity.RESOURCE_LOADER, "wwfile, wwclass");
507         }
508
509         /**
510          * If there's a "real" path add it for the wwfile resource loader. If
511          * there's no real path and they haven't configured a loader then we
512          * change resource loader property to just use the wwclass loader Ben
513          * Hall (22/08/2003)
514          */

515         if (context.getRealPath("") != null) {
516             p.setProperty("wwfile.resource.loader.description", "Velocity File Resource Loader");
517             p.setProperty("wwfile.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
518             p.setProperty("wwfile.resource.loader.path", context.getRealPath(""));
519             p.setProperty("wwfile.resource.loader.modificationCheckInterval", "2");
520             p.setProperty("wwfile.resource.loader.cache", "true");
521         } else {
522             // remove wwfile from resource loader property
523
String JavaDoc prop = p.getProperty(Velocity.RESOURCE_LOADER);
524             if (prop.indexOf("wwfile,") != -1) {
525                 prop = replace(prop, "wwfile,", "");
526             } else if (prop.indexOf(", wwfile") != -1) {
527                 prop = replace(prop, ", wwfile", "");
528             } else if (prop.indexOf("wwfile") != -1) {
529                 prop = replace(prop, "wwfile", "");
530             }
531
532             p.setProperty(Velocity.RESOURCE_LOADER, prop);
533         }
534
535         /**
536          * Refactored the Velocity templates for the WebWork taglib into the
537          * classpath from the web path. This will enable WebWork projects to
538          * have access to the templates by simply including the WebWork jar
539          * file. Unfortunately, there does not appear to be a macro for the
540          * class loader keywords Matt Ho - Mon Mar 17 00:21:46 PST 2003
541          */

542         p.setProperty("wwclass.resource.loader.description", "Velocity Classpath Resource Loader");
543         p.setProperty("wwclass.resource.loader.class", "com.opensymphony.webwork.views.velocity.WebWorkResourceLoader");
544         p.setProperty("wwclass.resource.loader.modificationCheckInterval", "2");
545         p.setProperty("wwclass.resource.loader.cache", "true");
546
547         // components
548
StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
549
550         //deprecated
551
addDirective(sb, BodyTagDirective.class);
552         addDirective(sb, TagDirective.class);
553         addDirective(sb, ParamDirective.class);
554
555         addDirective(sb, ApplyDecoratorDirective.class);
556         addDirective(sb, CheckBoxDirective.class);
557         addDirective(sb, CheckBoxListDirective.class);
558         addDirective(sb, ComboBoxDirective.class);
559         addDirective(sb, ComponentDirective.class);
560         addDirective(sb, DatePickerDirective.class);
561         addDirective(sb, DivDirective.class);
562         addDirective(sb, DoubleSelectDirective.class);
563         addDirective(sb, FileDirective.class);
564         addDirective(sb, FormDirective.class);
565         addDirective(sb, HiddenDirective.class);
566         addDirective(sb, HrefDirective.class);
567         addDirective(sb, LabelDirective.class);
568         addDirective(sb, PanelDirective.class);
569         addDirective(sb, PasswordDirective.class);
570         addDirective(sb, RadioDirective.class);
571         addDirective(sb, SelectDirective.class);
572         addDirective(sb, SubmitDirective.class);
573         addDirective(sb, TabbedPanelDirective.class);
574         addDirective(sb, TextAreaDirective.class);
575         addDirective(sb, TextFieldDirective.class);
576         addDirective(sb, TokenDirective.class);
577
578         String JavaDoc directives = sb.toString();
579
580         String JavaDoc userdirective = p.getProperty("userdirective");
581         if ((userdirective == null) || userdirective.trim().equals("")) {
582             userdirective = directives;
583         } else {
584             userdirective = userdirective.trim() + "," + directives;
585         }
586
587         p.setProperty("userdirective", userdirective);
588     }
589
590     private void addDirective(StringBuffer JavaDoc sb, Class JavaDoc clazz) {
591         sb.append(clazz.getName()).append(",");
592     }
593
594     private static final String JavaDoc replace(String JavaDoc string, String JavaDoc oldString, String JavaDoc newString) {
595         if (string == null) {
596             return null;
597         }
598         // If the newString is null, just return the string since there's
599
// nothing to replace.
600
if (newString == null) {
601             return string;
602         }
603         int i = 0;
604         // Make sure that oldString appears at least once before doing any
605
// processing.
606
if ((i = string.indexOf(oldString, i)) >= 0) {
607             // Use char []'s, as they are more efficient to deal with.
608
char[] string2 = string.toCharArray();
609             char[] newString2 = newString.toCharArray();
610             int oLength = oldString.length();
611             StringBuffer JavaDoc buf = new StringBuffer JavaDoc(string2.length);
612             buf.append(string2, 0, i).append(newString2);
613             i += oLength;
614             int j = i;
615             // Replace all remaining instances of oldString with newString.
616
while ((i = string.indexOf(oldString, i)) > 0) {
617                 buf.append(string2, j, i - j).append(newString2);
618                 i += oLength;
619                 j = i;
620             }
621             buf.append(string2, j, string2.length - j);
622             return buf.toString();
623         }
624         return string;
625     }
626 }
Popular Tags