KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > turbine > services > pull > TurbinePullService


1 package org.apache.turbine.services.pull;
2
3 /* ====================================================================
4  * The Apache Software License, Version 1.1
5  *
6  * Copyright (c) 2001-2002 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.ArrayList JavaDoc;
58 import java.util.Iterator JavaDoc;
59 import java.util.List JavaDoc;
60
61 import org.apache.commons.configuration.Configuration;
62 import org.apache.fulcrum.BaseService;
63 import org.apache.fulcrum.InitializationException;
64 import org.apache.fulcrum.TurbineServices;
65 import org.apache.fulcrum.factory.FactoryService;
66 import org.apache.fulcrum.pool.PoolService;
67 import org.apache.fulcrum.security.entity.User;
68 import org.apache.turbine.RunData;
69 import org.apache.turbine.TemplateContext;
70 import org.apache.turbine.modules.DefaultTemplateContext;
71 import org.apache.turbine.services.yaaficomponent.YaafiComponentService;
72
73 /**
74  * <p>
75  * This is the concrete implementation of the Turbine
76  * Pull Service.
77  * </p>
78  * <p>
79  * These are tools that are placed in the context by the service
80  * These tools will be made available to all your
81  * templates. You list the tools in the following way:
82  * </p>
83  * <pre>
84  * services.PullService.tool.<scope>.<id> = <classname>
85  *
86  * <scope> is the tool scope: global, request, session
87  * or persistent (see below for more details)
88  * <id> is the name of the tool in the context
89  *
90  * You can configure the tools in this way:
91  * tool.<id>.<parameter> = <value>
92  *
93  * So if you find "global", "request", "session" or "persistent" as second
94  * part, it is a configuration to put a tool into the toolbox, else it is a
95  * tool specific configuration.
96  *
97  * For example:
98  *
99  * services.PullService.tool.global.ui = org.apache.turbine.util.pull.UIManager
100  * services.PullService.tool.global.mm = org.apache.turbine.util.pull.MessageManager
101  * services.PullService.tool.request.link = org.apache.turbine.util.template.TemplateLink
102  * services.PullService.tool.request.page = org.apache.turbine.util.template.TemplatePageAttributes
103  *
104  * Then:
105  *
106  * tool.ui.skin = default
107  *
108  * configures the value of "skin" for the "ui" tool.
109  *
110  * Tools are accessible in all templates by the <id> given
111  * to the tool. So for the above listings the UIManager would
112  * be available as $ui, the MessageManager as $mm, the TemplateLink
113  * as $link and the TemplatePageAttributes as $page.
114  *
115  * You should avoid using tool names called "global", "request",
116  * "session" or "persistent" because of clashes with the possible Scopes.
117  *
118  * Scopes:
119  *
120  * global: tool is instantiated once and that instance is available
121  * to all templates for all requests. Tool must be threadsafe.
122  *
123  * request: tool is instantiated once for each request (although the
124  * PoolService is used to recycle instances). Tool need not
125  * be threadsafe. See
126  * <code>org.apache.fulcrum.pool.RecyclableSupport</code>
127  * for pre-packaged recyclable implementation.
128  *
129  * session: tool is instantiated once for each user session, and is
130  * stored in the user's temporary hashtable. Tool should be
131  * threadsafe.
132  *
133  * persistent: tool is instantitated once for each use session, and
134  * is stored in the user's permanent hashtable. This means
135  * for a logged in user the tool will be persisted in the
136  * user's objectdata. Tool should be threadsafe and
137  * Serializable.
138  *
139  * Defaults: none
140  * </pre>
141  *
142  * @author <a HREF="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
143  * @author <a HREF="mailto:sean@informage.net">Sean Legassick</a>
144  * @author <a HREF="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
145  * @version $Id: TurbinePullService.java,v 1.17 2004/11/12 10:26:00 epugh Exp $
146  */

147 public class TurbinePullService
148     extends BaseService
149     implements PullService
150 {
151     /**
152      * This is the container for the global web application
153      * tools that are used in conjunction with the
154      * Turbine Pull Model. All the global tools will be placed
155      * in this Context and be made accessible inside
156      * templates via the tool name specified in the TR.props
157      * file.
158      */

159     private TemplateContext globalContext;
160
161     /**
162      * This inner class is used to store lists of tool and class
163      * name pairs.
164      */

165     protected static class ToolData
166     {
167         protected String JavaDoc toolName;
168         protected String JavaDoc toolClassName;
169
170         public ToolData(String JavaDoc toolName, String JavaDoc toolClassName)
171         {
172             this.toolName = toolName;
173             this.toolClassName = toolClassName;
174         }
175     }
176
177     /**
178      * The lists that store tool data (name and class) for each
179      * of the different type of tool. The Lists contain ToolData
180      * objects.
181      */

182     private List JavaDoc globalTools;
183     private List JavaDoc requestTools;
184     private List JavaDoc sessionTools;
185     private List JavaDoc persistentTools;
186
187     /**
188      * The property tags that are used in to get
189      * our list of tools to instantiate (one tag for each
190      * type of tool).
191      */

192     private static final String JavaDoc GLOBAL_TOOL = "tool.global";
193     private static final String JavaDoc REQUEST_TOOL = "tool.request";
194     private static final String JavaDoc SESSION_TOOL = "tool.session";
195     private static final String JavaDoc PERSISTENT_TOOL = "tool.persistent";
196
197     /**
198      * Directory where application tool resources are stored.
199      */

200     private static String JavaDoc resourcesDirectory;
201
202     /**
203      * The absolute path the to resources directory used
204      * by the application tools.
205      */

206     private static String JavaDoc absolutePathToResourcesDirectory;
207
208     /**
209      * Property tag for application tool resources directory
210      */

211     private static final String JavaDoc TOOL_RESOURCES_DIR
212         = "tools.resources.dir";
213
214     /**
215      * Default value for the application tool resources
216      * directory. The location for the resources directory
217      * is typically WEBAPP/resources.
218      */

219     private static final String JavaDoc TOOL_RESOURCES_DIR_DEFAULT
220         = "/resources";
221
222     /**
223      * Property tag for per request tool refreshing
224      * (for obvious reasons has no effect for per-request tools)
225      */

226     private static final String JavaDoc TOOLS_PER_REQUEST_REFRESH =
227         "toolsPerRequestRefresh";
228
229     /**
230      * Should we refresh the application tools on
231      * a per request basis.
232      */

233     private static boolean refreshToolsPerRequest;
234
235     /**
236      * Called the first time the Service is used.
237      */

238     public void init()
239         throws InitializationException
240     {
241         try
242         {
243             // Get the resources directory that is specificed
244
// in the TR.props or default to "/resources".
245
resourcesDirectory = getConfiguration().getString(
246                 TOOL_RESOURCES_DIR,
247                     TOOL_RESOURCES_DIR_DEFAULT);
248
249             // Get absolute path to the resources directory.
250
//
251
// This should be done before the tools initialized
252
// because a tool might need to know this value
253
// for it to initialize correctly.
254
absolutePathToResourcesDirectory = getRealPath(resourcesDirectory);
255
256             // Should we refresh the tool box on a per
257
// request basis.
258
refreshToolsPerRequest = getConfiguration()
259                 .getBoolean(TOOLS_PER_REQUEST_REFRESH);
260
261             // Log the fact that the application tool box will
262
// be refreshed on a per request basis.
263
if (refreshToolsPerRequest)
264             {
265                 getCategory().info("Pull Model tools will "
266                     + "be refreshed on a per request basis.");
267             }
268
269             // Make sure to set init true because Tools may make
270
// calls back to the TurbinePull static methods which
271
// may cause a recursive init thing to happen.
272
setInit(true);
273
274             // Grab each list of tools that are to be used (for global scope,
275
// request scope, session scope and persistent scope tools).
276
globalTools = getTools(GLOBAL_TOOL);
277             requestTools = getTools(REQUEST_TOOL);
278             sessionTools = getTools(SESSION_TOOL);
279             persistentTools = getTools(PERSISTENT_TOOL);
280
281             // Create and populate the global context right now
282
globalContext = new DefaultTemplateContext();
283             populateWithGlobalTools(globalContext);
284         }
285         catch (Exception JavaDoc e)
286         {
287             throw new InitializationException(
288                 "TurbinePullService failed to initialize", e);
289         }
290     }
291
292     /**
293      * Retrieve the tool names and classes for the tools definied
294      * in the properties file with the prefix given.
295      *
296      * @param keyPrefix a String giving the property name prefix to look for
297      */

298     protected List JavaDoc getTools(String JavaDoc keyPrefix)
299     {
300         List JavaDoc classes = new ArrayList JavaDoc();
301
302         Configuration toolResources = getConfiguration().subset(keyPrefix);
303
304         // There might not be any tools for this prefix
305
// so return an empty list.
306
if (toolResources == null)
307         {
308             return classes;
309         }
310
311         Iterator JavaDoc it = toolResources.getKeys();
312         while (it.hasNext())
313         {
314             String JavaDoc toolName = (String JavaDoc) it.next();
315             String JavaDoc toolClassName = toolResources.getString(toolName);
316
317             try
318             {
319                 // Add the tool to the list being built.
320
classes.add(new ToolData(toolName, toolClassName));
321
322                 getCategory().info("Setup tool class " + toolClassName
323                     + " to add to the context as '$" + toolName + "'");
324             }
325             catch (Exception JavaDoc e)
326             {
327                 getCategory().error("Cannot find tool class " + toolClassName
328                         + ", please check the name of the class.");
329             }
330         }
331
332         return classes;
333     }
334
335     /**
336      * Return the Context which contains all global tools that
337      * are to be used in conjunction with the Turbine
338      * Pull Model.
339      */

340     public TemplateContext getGlobalContext()
341     {
342         return globalContext;
343     }
344
345     /**
346      * This is used to populate a TemplateContext with all of the
347      * various tools. The order of population is:
348      * Request, Session, Persistent, Global
349      *
350      * @param data Turbine information.
351      */

352     public TemplateContext getRuntimeContext(RunData data)
353     {
354         TemplateContext tc = new DefaultTemplateContext();
355         populateContext(tc, data);
356
357         // copy global context values into tc
358
// FIXME: this could probably be optimized with the use of
359
// chained contexts, but that is currently not implemented
360
// in TemplateContext
361
Iterator JavaDoc i = getGlobalContext().keySet().iterator();
362         while (i.hasNext())
363         {
364             String JavaDoc key = (String JavaDoc)i.next();
365             tc.put (key, getGlobalContext().get(key));
366         }
367         return tc;
368     }
369
370     /**
371      * Populate the given context with all request, session
372      * and persistent scope tools (it is assumed that the context
373      * already wraps the global context, and thus already contains
374      * the global tools).
375      *
376      * @param context a TemplateContext to populate
377      * @param data a RunData object for request specific data
378      */

379     public void populateContext(TemplateContext context, RunData data)
380     {
381         populateWithRequestTools(context, data);
382
383         // session tools (whether session-only or persistent are
384
// very similar, so the same method is used - the
385
// boolean parameter indicates whether get/setPerm is to be used
386
// rather than get/setTemp)
387
User user = data.getUser();
388         if (user != null)
389         {
390             populateWithSessionTools(sessionTools, context, user, false);
391
392             if (user.hasLoggedIn())
393             {
394                 populateWithSessionTools(persistentTools, context, user, true);
395             }
396         }
397     }
398
399     /**
400      * Populate the given context with the global tools.
401      * Globally-scoped tools are initialized with a <code>null</code>
402      * reference.
403      *
404      * @param context The <code>TemplateContext</code> to populate.
405      */

406     private void populateWithGlobalTools(TemplateContext context)
407     {
408         // Use the FactoryService to get instances for much more flexibility
409
FactoryService factoryService = getFactoryService();
410         Iterator JavaDoc it = globalTools.iterator();
411         while (it.hasNext())
412         {
413             ToolData toolData = (ToolData)it.next();
414             try
415             {
416                 Object JavaDoc tool =
417                     factoryService.getInstance(toolData.toolClassName);
418                 if (tool instanceof ApplicationTool)
419                 {
420                     ((ApplicationTool)tool).init(null);
421                 }
422                 // put the tool in the context
423
context.put(toolData.toolName, tool);
424             }
425             catch (Exception JavaDoc e)
426             {
427                 getCategory().error(
428                     "Could not instantiate tool " + toolData.toolClassName
429                         + " to add to the context" , e );
430             }
431         }
432     }
433
434     /**
435      * Populate the given context with the request-scope tools
436      *
437      * @param context a TemplateContext to populate
438      * @param data a RunData instance
439      */

440     private void populateWithRequestTools(TemplateContext context, RunData data)
441     {
442         // Get the PoolService to fetch object instances from
443
PoolService pool = getPoolService();
444
445         // Iterate the tools
446
Iterator JavaDoc it = requestTools.iterator();
447         while (it.hasNext())
448         {
449             ToolData toolData = (ToolData)it.next();
450             try
451             {
452                 Object JavaDoc tool = pool.getInstance(Class.forName(toolData.toolClassName));
453                 if (tool instanceof ApplicationTool)
454                 {
455                     // request tools are init'd with a RunData object
456
((ApplicationTool)tool).init(data);
457                 }
458                 // put the tool in the context
459
context.put(toolData.toolName, tool);
460             }
461             catch (Exception JavaDoc e)
462             {
463                 getCategory().error(
464                     "Could not instantiate tool " + toolData.toolClassName
465                         + " to add to the context",e);
466             }
467         }
468     }
469
470     /**
471      * Populate the given context with the session-scope tools
472      *
473      * @param tools The list of tools with which to populate the
474      * session.
475      * @param context A TemplateContext to populate.
476      * @param user The <code>User</code> object whose storage to
477      * retrieve the tool from.
478      * @param usePerm Whether to retrieve the tools from the
479      * permanent storage (as opposed to the temporary storage).
480      */

481     private void populateWithSessionTools(List JavaDoc tools,
482                                           TemplateContext context,
483                                           User user,
484                                           boolean usePerm)
485     {
486         // Get the PoolService to fetch object instances from
487
PoolService pool = getPoolService();
488
489         // Iterate the tools
490
Iterator JavaDoc it = tools.iterator();
491         while (it.hasNext())
492         {
493             ToolData toolData = (ToolData)it.next();
494             try
495             {
496                 // ensure that tool is created only once for a user
497
// by synchronizing against the user object
498
synchronized (user)
499                 {
500                     // first try and fetch the tool from the user's
501
// hashtable
502
Object JavaDoc tool = usePerm
503                         ? user.getPerm(toolData.toolClassName)
504                         : user.getTemp(toolData.toolClassName);
505
506                     if (tool == null)
507                     {
508                         // if not there, an instance must be fetched from
509
// the pool
510
tool = pool.getInstance(Class.forName(toolData.toolClassName));
511                         if (tool instanceof ApplicationTool)
512                         {
513                             // session tools are init'd with the User object
514
((ApplicationTool)tool).init(user);
515                         }
516                         // store the newly created tool in the user's hashtable
517
if (usePerm)
518                         {
519                             user.setPerm(toolData.toolClassName, tool);
520                         }
521                         else
522                         {
523                             user.setTemp(toolData.toolClassName, tool);
524                         }
525                     }
526                     else if (refreshToolsPerRequest
527                             && tool instanceof ApplicationTool)
528                     {
529                         ((ApplicationTool)tool).refresh();
530                     }
531                     // put the tool in the context
532
context.put(toolData.toolName, tool);
533                 }
534             }
535             catch (Exception JavaDoc e)
536             {
537                 getCategory().error("Could not instantiate tool " +
538                     toolData.toolClassName + " to add to the context");
539             }
540         }
541     }
542
543     /**
544      * Return the absolute path to the resources directory
545      * used by the application tools.
546      */

547     public String JavaDoc getAbsolutePathToResourcesDirectory()
548     {
549         return absolutePathToResourcesDirectory;
550     }
551
552     /**
553      * Return the resources directory. This is
554      * relative to the web context.
555      */

556     public String JavaDoc getResourcesDirectory()
557     {
558         return resourcesDirectory;
559     }
560
561     /**
562      * Refresh the global tools. We can
563      * only refresh those tools that adhere to
564      * ApplicationTool interface because we
565      * know those types of tools have a refresh
566      * method.
567      */

568     public void refreshGlobalTools()
569     {
570         Iterator JavaDoc i = globalTools.iterator();
571         while (i.hasNext())
572         {
573             ToolData toolData = (ToolData)i.next();
574             Object JavaDoc tool = globalContext.get(toolData.toolName);
575             if (tool instanceof ApplicationTool)
576             {
577                 ((ApplicationTool)tool).refresh();
578             }
579         }
580     }
581
582     /**
583      * Should we refresh the ToolBox on
584      * a per request basis.
585      */

586     public boolean refreshToolsPerRequest()
587     {
588         return refreshToolsPerRequest;
589     }
590
591     /**
592      * Release the request-scope tool instances in the
593      * given Context back to the pool
594      *
595      * @param context the TemplateContext to release tools from
596      */

597     public void releaseTools(TemplateContext context)
598     {
599         // Get the PoolService to release object instances to
600
PoolService pool = getPoolService();
601
602         // only the request tools can be released - other scoped
603
// tools will have continuing references to them
604
releaseTools(context, pool, requestTools);
605     }
606
607     /**
608      * Release the given list of tools from the context back
609      * to the pool
610      *
611      * @param context the Context containing the tools
612      * @param pool an instance of the PoolService
613      * @param tools a List of ToolData objects
614      */

615     private void releaseTools(TemplateContext context, PoolService pool,
616                               List JavaDoc tools)
617     {
618         Iterator JavaDoc it = tools.iterator();
619         while (it.hasNext())
620         {
621             ToolData toolData = (ToolData)it.next();
622             // FIXME! context.remove(key) is returning key, though this is not
623
// what the TemplateContext interface specifies.
624
// UPDATE: As of Feb 18, 2003, Fulcrum's
625
// DefaultTemplateContext uses HashMap.remove(Object),
626
// which should return the value.
627
//Object tool = context.remove(toolData.toolName);
628
Object JavaDoc tool = context.get(toolData.toolName);
629             context.remove(toolData.toolName);
630             if (tool != null)
631             {
632                 pool.putInstance(tool);
633             }
634         }
635     }
636       
637     
638     /**
639      * Utility method for accessing the service implementation
640      *
641      * @return a PoolService implementation instance
642      */

643     protected static PoolService getPoolService() {
644         try {
645         YaafiComponentService yaafi = (YaafiComponentService) TurbineServices.getInstance().getService(
646                 YaafiComponentService.SERVICE_NAME);
647         return (PoolService) yaafi.lookup(PoolService.class.getName());
648         } catch (Exception JavaDoc e) {
649             throw new RuntimeException JavaDoc("Problem looking up pool service", e);
650         }
651     }
652
653     /**
654      * Utility method for accessing the service implementation
655      *
656      * @return a FactoryService implementation instance
657      */

658     protected static FactoryService getFactoryService() {
659         try {
660         YaafiComponentService yaafi = (YaafiComponentService) TurbineServices.getInstance().getService(
661                 YaafiComponentService.SERVICE_NAME);
662         return (FactoryService) yaafi.lookup(FactoryService.class.getName());
663         } catch (Exception JavaDoc e) {
664             throw new RuntimeException JavaDoc("Problem looking up Factory service", e);
665         }
666     }
667 }
668
Popular Tags