1 package org.apache.turbine.services.pull;
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.ArrayList;
58 import java.util.Iterator;
59 import java.util.List;
60 import java.util.Properties;
61 import org.apache.turbine.Turbine;
62 import org.apache.turbine.om.security.User;
63 import org.apache.turbine.services.InitializationException;
64 import org.apache.turbine.services.TurbineBaseService;
65 import org.apache.turbine.services.TurbineServices;
66 import org.apache.turbine.services.pool.PoolService;
67 import org.apache.turbine.services.resources.ResourceService;
68 import org.apache.turbine.services.resources.TurbineResources;
69 import org.apache.turbine.util.Log;
70 import org.apache.turbine.util.RunData;
71 import org.apache.velocity.VelocityContext;
72 import org.apache.velocity.context.Context;
73
74 /***
75 * <p>
76 * This is the concrete implementation of the Turbine
77 * Pull Service.
78 * </p>
79 * <p>
80 * These are tools that are placed in the context by the service
81 * These tools will be made available to all your
82 * templates. You list the tools in the following way:
83 * </p>
84 * <pre>
85 * tool.<scope>.<id> = <classname>
86 *
87 * <scope> is the tool scope: global, request, session
88 * or persistent (see below for more details)
89 * <id> is the name of the tool in the context
90 *
91 * You can configure the tools in this way:
92 * tool.<id>.<parameter> = <value>
93 *
94 * So if you find "global", "request", "session" or "persistent" as second
95 * part, it is a configuration to put a tool into the toolbox, else it is a
96 * tool specific configuration.
97 *
98 * For example:
99 *
100 * tool.global.ui = org.apache.turbine.util.pull.UIManager
101 * tool.global.mm = org.apache.turbine.util.pull.MessageManager
102 * tool.request.link = org.apache.turbine.util.template.TemplateLink
103 * tool.request.page = org.apache.turbine.util.template.TemplatePageAttributes
104 *
105 * Then:
106 *
107 * tool.ui.skin = default
108 *
109 * configures the value of "skin" for the "ui" tool.
110 *
111 * Tools are accessible in all templates by the <id> given
112 * to the tool. So for the above listings the UIManager would
113 * be available as $ui, the MessageManager as $mm, the TemplateLink
114 * as $link and the TemplatePageAttributes as $page.
115 *
116 * You should avoid using tool names called "global", "request",
117 * "session" or "persistent" because of clashes with the possible Scopes.
118 *
119 * Scopes:
120 *
121 * global: tool is instantiated once and that instance is available
122 * to all templates for all requests. Tool must be threadsafe.
123 *
124 * request: tool is instantiated once for each request (although the
125 * PoolService is used to recycle instances). Tool need not
126 * be threadsafe.
127 *
128 * session: tool is instantiated once for each user session, and is
129 * stored in the user's temporary hashtable. Tool should be
130 * threadsafe.
131 *
132 * persistent: tool is instantitated once for each use session, and
133 * is stored in the user's permanent hashtable. This means
134 * for a logged in user the tool will be persisted in the
135 * user's objectdata. Tool should be threadsafe and
136 * Serializable.
137 *
138 * Defaults: none
139 * </pre>
140 *
141 * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
142 * @author <a href="mailto:sean@informage.net">Sean Legassick</a>
143 * @version $Id: TurbinePullService.java,v 1.5 2002/07/11 16:53:25 mpoeschl Exp $
144 */
145 public class TurbinePullService extends TurbineBaseService
146 implements PullService
147 {
148 /***
149 * This is the container for the global web application
150 * tools that are used in conjunction with the
151 * Turbine Pull Model. All the global tools will be placed
152 * in this Context and be made accessible inside
153 * templates via the tool name specified in the TR.props
154 * file.
155 */
156 private Context globalContext;
157
158 /***
159 * This inner class is used in the lists below to store the
160 * tool name and class for each of request, session and persistent
161 * tools
162 */
163 private static class ToolData
164 {
165 String toolName;
166 String toolClassName;
167 Class toolClass;
168
169 public ToolData(String toolName, String toolClassName, Class toolClass)
170 {
171 this.toolName = toolName;
172 this.toolClassName = toolClassName;
173 this.toolClass = toolClass;
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 globalTools;
183 private List requestTools;
184 private List sessionTools;
185 private List persistentTools;
186
187 /***
188 * The property tags that are used in conjunction with
189 * TurbineResources.getOrderedValues(String) to get
190 * our list of tools to instantiate (one tag for each
191 * type of tool).
192 */
193 private static final String GLOBAL_TOOL = "tool.global";
194 private static final String REQUEST_TOOL = "tool.request";
195 private static final String SESSION_TOOL = "tool.session";
196 private static final String PERSISTENT_TOOL = "tool.persistent";
197
198 /***
199 * Directory where application tool resources are stored.
200 */
201 private static String resourcesDirectory;
202
203 /***
204 * The absolute path the to resources directory used
205 * by the application tools.
206 */
207 private static String absolutePathToResourcesDirectory;
208
209 /***
210 * Property tag for application tool resources directory
211 */
212 private static final String TOOL_RESOURCES_DIR
213 = "tools.resources.dir";
214
215 /***
216 * Default value for the application tool resources
217 * directory. The location for the resources directory
218 * is typically WEBAPP/resources.
219 */
220 private static final String TOOL_RESOURCES_DIR_DEFAULT
221 = "/resources";
222
223 /***
224 * Property tag for per request tool refreshing
225 * (for obvious reasons has no effect for per-request tools)
226 */
227 private static final String TOOLS_PER_REQUEST_REFRESH =
228 "tools.per.request.refresh";
229
230 /***
231 * Should we refresh the application tools on
232 * a per request basis.
233 */
234 private static boolean refreshToolsPerRequest;
235
236 /***
237 * Called the first time the Service is used.
238 */
239 public void init() throws InitializationException
240 {
241 try
242 {
243 /*
244 * Make sure to setInit(true) *inside* initPull()
245 * because Tools may make calls back to the TurbinePull
246 * static methods which may cause a recursive init
247 * thing to happen.
248 */
249 initPull();
250 }
251 catch (Exception e)
252 {
253 throw new InitializationException(
254 "TurbinePullService failed to initialize", e);
255 }
256 }
257
258 /***
259 * Initialize the pull system
260 *
261 * @exception Exception, a generic exception.
262 */
263 private void initPull() throws Exception
264 {
265 Properties props = getProperties();
266
267 /*
268 * Get the resources directory that is specificed
269 * in the TR.props or default to "/resources".
270 */
271 resourcesDirectory = TurbineResources.getString(
272 TOOL_RESOURCES_DIR,
273 TOOL_RESOURCES_DIR_DEFAULT);
274
275 /*
276 * Get absolute path to the resources directory.
277 *
278 * This should be done before the tools initialized
279 * because a tool might need to know this value
280 * for it to initialize correctly.
281 */
282 absolutePathToResourcesDirectory =
283 Turbine.getRealPath(resourcesDirectory);
284
285 /*
286 * Should we refresh the tool box on a per
287 * request basis.
288 */
289 refreshToolsPerRequest =
290 new Boolean(properties.getProperty(
291 TOOLS_PER_REQUEST_REFRESH)).booleanValue();
292
293 /*
294 * Log the fact that the application tool box will
295 * be refreshed on a per request basis.
296 */
297 if (refreshToolsPerRequest)
298 Log.info("Pull Model tools will "
299 + "be refreshed on a per request basis.");
300
301 /*
302 * Make sure to set init true because Tools may make
303 * calls back to the TurbinePull static methods which
304 * may cause a recursive init thing to happen.
305 */
306 setInit(true);
307
308 /*
309 * Grab each list of tools that are to be used (for global scope,
310 * request scope, session scope and persistent scope tools).
311 * They are specified respectively in the TR.props like this:
312 *
313 * tool.global.ui = org.apache.turbine.util.pull.UIManager
314 * tool.global.mm = org.apache.turbine.util.pull.MessageManager
315 *
316 * tool.request.link = org.apache.turbine.util.template.TemplateLink;
317 *
318 * tool.session.basket = org.sample.util.ShoppingBasket;
319 *
320 * tool.persistent.ui = org.apache.turbine.services.pull.util.PersistentUIManager
321 */
322 globalTools = getTools(GLOBAL_TOOL);
323 requestTools = getTools(REQUEST_TOOL);
324 sessionTools = getTools(SESSION_TOOL);
325 persistentTools = getTools(PERSISTENT_TOOL);
326
327 /*
328 * Create and populate the global context right now
329 */
330 globalContext = new VelocityContext();
331 populateWithGlobalTools(globalContext);
332 }
333
334 /***
335 * Retrieve the tool names and classes for the tools definied
336 * in the properties file with the prefix given.
337 *
338 * @param keyPrefix a String giving the property name prefix to look for
339 */
340 private List getTools(String keyPrefix)
341 {
342 List classes = new ArrayList();
343
344 ResourceService toolResources =
345 TurbineResources.getResources(keyPrefix);
346
347 /*
348 * There might not be any tools for this prefix
349 * so return an empty list.
350 */
351 if (toolResources == null)
352 {
353 return classes;
354 }
355
356 Iterator it = toolResources.getKeys();
357 while (it.hasNext())
358 {
359 String toolName = (String) it.next();
360 String toolClassName = toolResources.getString(toolName);
361
362 try
363 {
364 /*
365 * Create an instance of the tool class.
366 */
367 Class toolClass = Class.forName(toolClassName);
368
369 /*
370 * Add the tool to the list being built.
371 */
372 classes.add(new ToolData(toolName, toolClassName, toolClass));
373
374 Log.info("Instantiated tool class " + toolClassName
375 + " to add to the context as '$" + toolName + "'");
376 }
377 catch (Exception e)
378 {
379 Log.error("Cannot find tool class " + toolClassName
380 + ", please check the name of the class.");
381 }
382 }
383
384 return classes;
385 }
386
387 /***
388 * Return the Context which contains all global tools that
389 * are to be used in conjunction with the Turbine
390 * Pull Model.
391 */
392 public Context getGlobalContext()
393 {
394 return globalContext;
395 }
396
397 /***
398 * Populate the given context with all request, session
399 * and persistent scope tools (it is assumed that the context
400 * already wraps the global context, and thus already contains
401 * the global tools).
402 *
403 * @param context a Velocity Context to populate
404 * @param data a RunData object for request specific data
405 */
406 public void populateContext(Context context, RunData data)
407 {
408 populateWithRequestTools(context, data);
409
410 // session tools (whether session-only or persistent are
411 // very similar, so the same method is used - the
412 // boolean parameter indicates whether get/setPerm is to be used
413 // rather than get/setTemp)
414 User user = data.getUser();
415 if (user != null)
416 {
417 populateWithSessionTools(sessionTools, context, user, false);
418
419 if (user.hasLoggedIn())
420 {
421 populateWithSessionTools(persistentTools, context, user, true);
422 }
423 }
424 }
425
426 /***
427 * Populate the given context with the global tools
428 *
429 * @param context a Velocity Context to populate
430 */
431 private void populateWithGlobalTools(Context context)
432 {
433 Iterator it = globalTools.iterator();
434 while (it.hasNext())
435 {
436 ToolData toolData = (ToolData)it.next();
437 try
438 {
439 Object tool = toolData.toolClass.newInstance();
440 if (tool instanceof ApplicationTool)
441 {
442 // global tools are init'd with a null data parameter
443 ((ApplicationTool)tool).init(null);
444 }
445 // put the tool in the context
446 context.put(toolData.toolName, tool);
447 }
448 catch (Exception e)
449 {
450 Log.error(
451 "Could not instantiate tool " + toolData.toolClassName
452 + " to add to the context");
453 }
454 }
455 }
456
457 /***
458 * Populate the given context with the request-scope tools
459 *
460 * @param context a Velocity Context to populate
461 * @param data a RunData instance
462 */
463 private void populateWithRequestTools(Context context, RunData data)
464 {
465 // Get the PoolService to fetch object instances from
466 PoolService pool = (PoolService)
467 TurbineServices.getInstance().getService(PoolService.SERVICE_NAME);
468
469 // Iterate the tools
470 Iterator it = requestTools.iterator();
471 while (it.hasNext())
472 {
473 ToolData toolData = (ToolData)it.next();
474 try
475 {
476 Object tool = pool.getInstance(toolData.toolClass);
477 if (tool instanceof ApplicationTool)
478 {
479 // request tools are init'd with a RunData object
480 ((ApplicationTool)tool).init(data);
481 }
482 // put the tool in the context
483 context.put(toolData.toolName, tool);
484 }
485 catch (Exception e)
486 {
487 Log.error(
488 "Could not instantiate tool " + toolData.toolClassName
489 + " to add to the context",e);
490 }
491 }
492 }
493
494 /***
495 * Populate the given context with the session-scoped tools.
496 *
497 * @param tools The list of tools with which to populate the
498 * session.
499 * @param context The context to populate.
500 * @param user The <code>User</code> object whose storage to
501 * retrieve the tool from.
502 * @param userPerm Whether to retrieve the tools from the
503 * permanent storage (as opposed to the temporary storage).
504 */
505 private void populateWithSessionTools(List tools, Context context,
506 User user, boolean usePerm)
507 {
508 // Get the PoolService to fetch object instances from
509 PoolService pool = (PoolService)
510 TurbineServices.getInstance().getService(PoolService.SERVICE_NAME);
511
512 // Iterate the tools
513 Iterator it = tools.iterator();
514 while (it.hasNext())
515 {
516 ToolData toolData = (ToolData)it.next();
517 try
518 {
519 // ensure that tool is created only once for a user
520 // by synchronizing against the user object
521 synchronized (user)
522 {
523 // first try and fetch the tool from the user's
524 // hashtable
525 Object tool = usePerm
526 ? user.getPerm(toolData.toolClassName)
527 : user.getTemp(toolData.toolClassName);
528
529 if (tool == null)
530 {
531 // if not there, an instance must be fetched from
532 // the pool
533 tool = pool.getInstance(toolData.toolClass);
534 if (tool instanceof ApplicationTool)
535 {
536 // session tools are init'd with the User object
537 ((ApplicationTool)tool).init(user);
538 }
539 // store the newly created tool in the user's hashtable
540 if (usePerm)
541 {
542 user.setPerm(toolData.toolClassName, tool);
543 }
544 else
545 {
546 user.setTemp(toolData.toolClassName, tool);
547 }
548 }
549 else if (refreshToolsPerRequest
550 && tool instanceof ApplicationTool)
551 {
552 ((ApplicationTool)tool).refresh();
553 }
554 // put the tool in the context
555 context.put(toolData.toolName, tool);
556 }
557 }
558 catch (Exception e)
559 {
560 Log.error(
561 "Could not instantiate tool " + toolData.toolClassName
562 + " to add to the context");
563 }
564 }
565 }
566
567 /***
568 * Return the absolute path to the resources directory
569 * used by the application tools.
570 */
571 public String getAbsolutePathToResourcesDirectory()
572 {
573 return absolutePathToResourcesDirectory;
574 }
575
576 /***
577 * Return the resources directory. This is
578 * relative to the web context.
579 */
580 public String getResourcesDirectory()
581 {
582 return resourcesDirectory;
583 }
584
585 /***
586 * Refresh the global tools. We can
587 * only refresh those tools that adhere to
588 * ApplicationTool interface because we
589 * know those types of tools have a refresh
590 * method.
591 */
592 public void refreshGlobalTools()
593 {
594 Iterator i = globalTools.iterator();
595 while (i.hasNext())
596 {
597 ToolData toolData = (ToolData)i.next();
598 Object tool = globalContext.get(toolData.toolName);
599 if (tool instanceof ApplicationTool)
600 ((ApplicationTool)tool).refresh();
601 }
602 }
603
604 /***
605 * Should we refresh the ToolBox on
606 * a per request basis.
607 */
608 public boolean refreshToolsPerRequest()
609 {
610 return refreshToolsPerRequest;
611 }
612
613 /***
614 * Release the request-scope tool instances in the
615 * given Context back to the pool
616 *
617 * @param context the Velocity Context to release tools from
618 */
619 public void releaseTools(Context context)
620 {
621 // Get the PoolService to release object instances to
622 PoolService pool = (PoolService)
623 TurbineServices.getInstance().getService(PoolService.SERVICE_NAME);
624
625 // only the request tools can be released - other scoped
626 // tools will have continuing references to them
627 releaseTools(context, pool, requestTools);
628 }
629
630 /***
631 * Release the given list of tools from the context back
632 * to the pool
633 *
634 * @param context the Context containing the tools
635 * @param pool an instance of the PoolService
636 * @param tools a List of ToolData objects
637 */
638 private void releaseTools(Context context, PoolService pool, List tools)
639 {
640 Iterator it = tools.iterator();
641 while (it.hasNext())
642 {
643 ToolData toolData = (ToolData)it.next();
644 Object tool = context.remove(toolData.toolName);
645
646 if (tool != null)
647 {
648 pool.putInstance(tool);
649 }
650 }
651 }
652 }
This page was automatically generated by Maven