KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > velocity > tools > view > servlet > ServletToolboxManager


1 /*
2  * Copyright 2003-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17
18 package org.apache.velocity.tools.view.servlet;
19
20
21 import java.io.InputStream JavaDoc;
22 import java.io.PrintWriter JavaDoc;
23 import java.io.StringWriter JavaDoc;
24
25 import java.util.List JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.ArrayList JavaDoc;
30
31 import javax.servlet.http.HttpSession JavaDoc;
32 import javax.servlet.ServletContext JavaDoc;
33
34 import org.apache.commons.digester.Digester;
35 import org.apache.commons.digester.RuleSet;
36 import org.apache.velocity.app.Velocity;
37 import org.apache.velocity.tools.view.DataInfo;
38 import org.apache.velocity.tools.view.ToolInfo;
39 import org.apache.velocity.tools.view.XMLToolboxManager;
40 import org.apache.velocity.tools.view.context.ToolboxContext;
41 import org.apache.velocity.tools.view.context.ViewContext;
42 import org.apache.velocity.tools.view.servlet.ServletToolboxRuleSet;
43
44
45 /**
46  * <p>A toolbox manager for the servlet environment.</p>
47  *
48  * <p>A toolbox manager is responsible for automatically filling the Velocity
49  * context with a set of view tools. This class provides the following
50  * features:</p>
51  * <ul>
52  * <li>configurable through an XML-based configuration file</li>
53  * <li>assembles a set of view tools (the toolbox) on request</li>
54  * <li>handles different tool scopes (request, session, application)</li>
55  * <li>supports any class with a public constructor without parameters
56  * to be used as a view tool</li>
57  * <li>supports adding primitive data values to the context(String,Number,Boolean)</li>
58  * </ul>
59  *
60  *
61  * <p><strong>Configuration</strong></p>
62  * <p>The toolbox manager is configured through an XML-based configuration
63  * file. The configuration file is passed to the {@link #load(java.io.InputStream input)}
64  * method. The format is shown in the following example:</p>
65  * <pre>
66  * &lt;?xml version="1.0"?&gt;
67  *
68  * &lt;toolbox&gt;
69  * &lt;tool&gt;
70  * &lt;key&gt;link&lt;/key&gt;
71  * &lt;scope&gt;request&lt;/scope&gt;
72  * &lt;class&gt;org.apache.velocity.tools.view.tools.LinkTool&lt;/class&gt;
73  * &lt;/tool&gt;
74  * &lt;tool&gt;
75  * &lt;key&gt;date&lt;/key&gt;
76  * &lt;scope&gt;application&lt;/scope&gt;
77  * &lt;class&gt;org.apache.velocity.tools.generic.DateTool&lt;/class&gt;
78  * &lt;/tool&gt;
79  * &lt;data type="number"&gt;
80  * &lt;key&gt;luckynumber&lt;/key&gt;
81  * &lt;value&gt;1.37&lt;/value&gt;
82  * &lt;/data&gt;
83  * &lt;data type="string"&gt;
84  * &lt;key&gt;greeting&lt;/key&gt;
85  * &lt;value&gt;Hello World!&lt;/value&gt;
86  * &lt;/data&gt;
87  * &lt;xhtml&gt;true&lt;/xhtml&gt;
88  * &lt;/toolbox&gt;
89  * </pre>
90  * <p>The recommended location for the configuration file is the WEB-INF directory of the
91  * web application.</p>
92  *
93  * @author <a HREF="mailto:sidler@teamup.com">Gabriel Sidler</a>
94  * @author <a HREF="mailto:nathan@esha.com">Nathan Bubna</a>
95  * @author <a HREF="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
96  *
97  * @version $Id: ServletToolboxManager.java,v 1.12 2004/02/18 20:07:02 nbubna Exp $
98  */

99 public class ServletToolboxManager extends XMLToolboxManager
100 {
101
102     // --------------------------------------------------- Properties ---------
103

104     public static final String JavaDoc SESSION_TOOLS_KEY =
105         ServletToolboxManager.class.getName() + ":session-tools";
106
107     private ServletContext JavaDoc servletContext;
108     private Map JavaDoc appTools;
109     private ArrayList JavaDoc sessionToolInfo;
110     private ArrayList JavaDoc requestToolInfo;
111     private boolean createSession;
112
113     private static HashMap JavaDoc managersMap = new HashMap JavaDoc();
114     private static RuleSet servletRuleSet = new ServletToolboxRuleSet();
115
116
117     // --------------------------------------------------- Constructor --------
118

119     /**
120      * Use getInstance(ServletContext,String) instead
121      * to ensure there is exactly one ServletToolboxManager
122      * per xml toolbox configuration file.
123      */

124     private ServletToolboxManager(ServletContext JavaDoc servletContext)
125     {
126         this.servletContext = servletContext;
127         appTools = new HashMap JavaDoc();
128         sessionToolInfo = new ArrayList JavaDoc();
129         requestToolInfo = new ArrayList JavaDoc();
130         createSession = true;
131     }
132
133
134     // -------------------------------------------- Public Methods ------------
135

136     /**
137      * ServletToolboxManager factory method.
138      * This method will ensure there is exactly one ServletToolboxManager
139      * per xml toolbox configuration file.
140      */

141     public static synchronized ServletToolboxManager getInstance(ServletContext JavaDoc servletContext,
142                                                                  String JavaDoc toolboxFile)
143     {
144         // little fix up
145
if (!toolboxFile.startsWith("/"))
146         {
147             toolboxFile = "/" + toolboxFile;
148         }
149
150         // get config file pathname
151
String JavaDoc pathname = servletContext.getRealPath(toolboxFile);
152
153         // check if a previous instance exists
154
ServletToolboxManager toolboxManager =
155             (ServletToolboxManager)managersMap.get(pathname);
156
157         if (toolboxManager == null)
158         {
159             // if not, build one
160
InputStream JavaDoc is = null;
161             try
162             {
163                 // get the bits
164
is = servletContext.getResourceAsStream(toolboxFile);
165
166                 if (is != null)
167                 {
168                     Velocity.info("ServletToolboxManager: Using config file '" +
169                                   toolboxFile +"'");
170
171                     toolboxManager = new ServletToolboxManager(servletContext);
172                     toolboxManager.load(is);
173
174                     // remember it
175
managersMap.put(pathname, toolboxManager);
176
177                     Velocity.info("ServletToolboxManager: Toolbox setup complete.");
178                 }
179             }
180             catch(Exception JavaDoc e)
181             {
182                 Velocity.error("Problem loading toolbox '" + toolboxFile +"' : " + e);
183
184                 // if this happens, it probably deserves
185
// to have the stack trace logged
186
StringWriter JavaDoc sw = new StringWriter JavaDoc();
187                 e.printStackTrace(new PrintWriter JavaDoc(sw));
188                 Velocity.error(sw.toString());
189             }
190             finally
191             {
192                 try
193                 {
194                     if (is != null)
195                     {
196                         is.close();
197                     }
198                 }
199                 catch(Exception JavaDoc ee) {}
200             }
201         }
202         return toolboxManager;
203     }
204
205
206     /**
207      * <p>Sets whether or not to create a new session when none exists for the
208      * current request and session-scoped tools have been defined for this
209      * toolbox.</p>
210      *
211      * <p>If true, then a call to {@link #getToolboxContext(Object)} will
212      * create a new session if none currently exists for this request and
213      * the toolbox has one or more session-scoped tools designed.</p>
214      *
215      * <p>If false, then a call to getToolboxContext(Object) will never
216      * create a new session for the current request.
217      * This effectively means that no session-scoped tools will be added to
218      * the ToolboxContext for a request that does not have a session object.
219      * </p>
220      *
221      * The default value is true.
222      */

223     public void setCreateSession(boolean b)
224     {
225         createSession = b;
226         Velocity.debug("ServletToolboxManager: create-session is set to " + b);
227     }
228
229
230     /**
231      * <p>Sets an application attribute to tell velocimacros and tools
232      * (especially the LinkTool) whether they should output XHTML or HTML.</p>
233      *
234      * @see ViewContext#XHTML
235      * @since VelocityTools 1.1
236      */

237     public void setXhtml(Boolean JavaDoc value)
238     {
239         servletContext.setAttribute(ViewContext.XHTML, value);
240         Velocity.info("ServletToolboxManager: " + ViewContext.XHTML +
241                       " is set to " + value);
242     }
243
244
245     // ------------------------------ XMLToolboxManager Overrides -------------
246

247     /**
248      * For subclassing convienence.
249      * @since VelocityTools 1.1
250      */

251     protected RuleSet getRuleSet()
252     {
253         return servletRuleSet;
254     }
255
256
257     /**
258      * Overrides XMLToolboxManager to separate tools by scope.
259      * For this to work, we obviously override getToolboxContext(Object) as well.
260      */

261     public void addTool(ToolInfo info)
262     {
263         if (info instanceof DataInfo)
264         {
265             //add static data to the appTools map
266
appTools.put(info.getKey(), info.getInstance(null));
267         }
268         else if (info instanceof ServletToolInfo)
269         {
270             ServletToolInfo sti = (ServletToolInfo)info;
271             
272             if (ViewContext.REQUEST.equalsIgnoreCase(sti.getScope()))
273             {
274                 requestToolInfo.add(sti);
275             }
276             else if (ViewContext.SESSION.equalsIgnoreCase(sti.getScope()))
277             {
278                 sessionToolInfo.add(sti);
279             }
280             else if (ViewContext.APPLICATION.equalsIgnoreCase(sti.getScope()))
281             {
282                 /* add application scoped tools to appTools and
283                  * initialize them with the ServletContext */

284                 appTools.put(sti.getKey(), sti.getInstance(servletContext));
285             }
286             else
287             {
288                 Velocity.warn("ServletToolboxManager: Unknown scope '" +
289                               sti.getScope() + "' - " + sti.getKey() +
290                               " will be request scoped.");
291                 requestToolInfo.add(sti);
292             }
293         }
294         else
295         {
296             //default is request scope
297
requestToolInfo.add(info);
298         }
299     }
300
301
302     /**
303      * Overrides XMLToolboxManager to handle the separate
304      * scopes.
305      *
306      * Application scope tools were initialized when the toolbox was loaded.
307      * Session scope tools are initialized once per session and stored in a
308      * map in the session attributes.
309      * Request scope tools are initialized on every request.
310      *
311      * @param initData the {@link ViewContext} for the current servlet request
312      */

313     public ToolboxContext getToolboxContext(Object JavaDoc initData)
314     {
315         //we know the initData is a ViewContext
316
ViewContext ctx = (ViewContext)initData;
317         
318         //create the toolbox map with the application tools in it
319
Map JavaDoc toolbox = new HashMap JavaDoc(appTools);
320
321         if (!sessionToolInfo.isEmpty())
322         {
323             HttpSession JavaDoc session = ctx.getRequest().getSession(createSession);
324             if (session != null)
325             {
326                 // allow only one thread per session at a time
327
synchronized(getMutex(session))
328                 {
329                     // get the session tools
330
Map JavaDoc stmap = (Map JavaDoc)session.getAttribute(SESSION_TOOLS_KEY);
331                     if (stmap == null)
332                     {
333                         // init and store session tools map
334
stmap = new HashMap JavaDoc(sessionToolInfo.size());
335                         Iterator JavaDoc i = sessionToolInfo.iterator();
336                         while(i.hasNext())
337                         {
338                             ToolInfo ti = (ToolInfo)i.next();
339                             stmap.put(ti.getKey(), ti.getInstance(ctx));
340                         }
341                         session.setAttribute(SESSION_TOOLS_KEY, stmap);
342                     }
343                     // add them to the toolbox
344
toolbox.putAll(stmap);
345                 }
346             }
347         }
348
349         //add and initialize request tools
350
Iterator JavaDoc i = requestToolInfo.iterator();
351         while(i.hasNext())
352         {
353             ToolInfo info = (ToolInfo)i.next();
354             toolbox.put(info.getKey(), info.getInstance(ctx));
355         }
356
357         return new ToolboxContext(toolbox);
358     }
359
360
361     /**
362      * Returns a mutex (lock object) unique to the specified session
363      * to allow for reliable synchronization on the session.
364      */

365     protected Object JavaDoc getMutex(HttpSession JavaDoc session)
366     {
367         // yes, this uses double-checked locking, but it is safe here
368
// since partial initialization of the lock is not an issue
369
Object JavaDoc lock = session.getAttribute("session.mutex");
370         if (lock == null)
371         {
372             // one thread per toolbox manager at a time
373
synchronized(this)
374             {
375                 // in case another thread already came thru
376
lock = session.getAttribute("session.mutex");
377                 if (lock == null)
378                 {
379                     lock = new Object JavaDoc();
380                     session.setAttribute("session.mutex", lock);
381                 }
382             }
383         }
384         return lock;
385     }
386
387 }
388
Popular Tags