001 package org.apache.turbine.services.pull;
002
003
004 /*
005 * Licensed to the Apache Software Foundation (ASF) under one
006 * or more contributor license agreements. See the NOTICE file
007 * distributed with this work for additional information
008 * regarding copyright ownership. The ASF licenses this file
009 * to you under the Apache License, Version 2.0 (the
010 * "License"); you may not use this file except in compliance
011 * with the License. You may obtain a copy of the License at
012 *
013 * http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing,
016 * software distributed under the License is distributed on an
017 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
018 * KIND, either express or implied. See the License for the
019 * specific language governing permissions and limitations
020 * under the License.
021 */
022
023
024 import java.util.ArrayList;
025 import java.util.Iterator;
026 import java.util.List;
027
028 import org.apache.commons.configuration.Configuration;
029 import org.apache.commons.logging.Log;
030 import org.apache.commons.logging.LogFactory;
031 import org.apache.fulcrum.pool.PoolService;
032 import org.apache.turbine.Turbine;
033 import org.apache.turbine.om.security.User;
034 import org.apache.turbine.pipeline.PipelineData;
035 import org.apache.turbine.services.InitializationException;
036 import org.apache.turbine.services.TurbineBaseService;
037 import org.apache.turbine.services.TurbineServices;
038 import org.apache.turbine.services.security.TurbineSecurity;
039 import org.apache.turbine.services.velocity.TurbineVelocity;
040 import org.apache.turbine.services.velocity.VelocityService;
041 import org.apache.turbine.util.RunData;
042 import org.apache.velocity.context.Context;
043
044 /**
045 * This is the concrete implementation of the Turbine
046 * Pull Service.
047 * <p>
048 * These are tools that are placed in the context by the service
049 * These tools will be made available to all your
050 * templates. You list the tools in the following way:
051 * <p>
052 * <pre>
053 * tool.<scope>.<id> = <classname>
054 *
055 * <scope> is the tool scope: global, request, session,
056 * authorized or persistent (see below for more details)
057 * <id> is the name of the tool in the context
058 *
059 * You can configure the tools in this way:
060 * tool.<id>.<parameter> = <value>
061 *
062 * So if you find "global", "request", "session" or "persistent" as second
063 * part, it is a configuration to put a tool into the toolbox, else it is a
064 * tool specific configuration.
065 *
066 * For example:
067 *
068 * tool.global.ui = org.apache.turbine.util.pull.UIManager
069 * tool.global.mm = org.apache.turbine.util.pull.MessageManager
070 * tool.request.link = org.apache.turbine.services.pull.tools.TemplateLink
071 * tool.request.page = org.apache.turbine.util.template.TemplatePageAttributes
072 *
073 * Then:
074 *
075 * tool.ui.skin = default
076 *
077 * configures the value of "skin" for the "ui" tool.
078 *
079 * Tools are accessible in all templates by the <id> given
080 * to the tool. So for the above listings the UIManager would
081 * be available as $ui, the MessageManager as $mm, the TemplateLink
082 * as $link and the TemplatePageAttributes as $page.
083 *
084 * You should avoid using tool names called "global", "request",
085 * "session" or "persistent" because of clashes with the possible Scopes.
086 *
087 * Scopes:
088 *
089 * global: tool is instantiated once and that instance is available
090 * to all templates for all requests. Tool must be threadsafe.
091 *
092 * request: tool is instantiated once for each request (although the
093 * PoolService is used to recycle instances). Tool need not
094 * be threadsafe.
095 *
096 * session: tool is instantiated once for each user session, and is
097 * stored in the session. These tools do not need to be
098 * threadsafe.
099 *
100 * authorized: tool is instantiated once for each user session once the
101 * user logs in. After this, it is a normal session tool.
102 *
103 * persistent: tool is instantitated once for each user session once
104 * the user logs in and is is stored in the user's permanent
105 * hashtable.
106 * This means for a logged in user the tool will be persisted
107 * in the user's objectdata. Tool should be Serializable. These
108 * tools do not need to be threadsafe.
109 * <b>persistent scope tools are deprecated in 2.3</b>
110 *
111 * Defaults: none
112 * </pre>
113 *
114 * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
115 * @author <a href="mailto:sean@informage.net">Sean Legassick</a>
116 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
117 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
118 * @author <a href="mailto:peter@courcoux.biz">Peter Courcoux</a>
119 * @version $Id: TurbinePullService.java 1078552 2011-03-06 19:58:46Z tv $
120 */
121 public class TurbinePullService
122 extends TurbineBaseService
123 implements PullService
124 {
125 /** Logging */
126 private static Log log = LogFactory.getLog(TurbinePullService.class);
127
128 /** Reference to the pool service */
129 private PoolService pool = null;
130
131 /** Reference to the templating (nee Velocity) service */
132 private VelocityService velocity = null;
133
134 /**
135 * This is the container for the global web application
136 * tools that are used in conjunction with the
137 * Turbine Pull Model. All the global tools will be placed
138 * in this Context and be made accessible inside
139 * templates via the tool name specified in the TR.props
140 * file.
141 */
142 private Context globalContext;
143
144 /**
145 * This inner class is used in the lists below to store the
146 * tool name and class for each of request, session and persistent
147 * tools
148 */
149 private static class ToolData
150 {
151 String toolName;
152 String toolClassName;
153 Class<ApplicationTool> toolClass;
154
155 public ToolData(String toolName, String toolClassName, Class<ApplicationTool> toolClass)
156 {
157 this.toolName = toolName;
158 this.toolClassName = toolClassName;
159 this.toolClass = toolClass;
160 }
161 }
162
163 /** Internal list of global tools */
164 private List<ToolData> globalTools;
165
166 /** Internal list of request tools */
167 private List<ToolData> requestTools;
168
169 /** Internal list of session tools */
170 private List<ToolData> sessionTools;
171
172 /** Internal list of authorized tools */
173 private List<ToolData> authorizedTools;
174
175 /** Internal list of persistent tools */
176 private List<ToolData> persistentTools;
177
178 /** Directory where application tool resources are stored.*/
179 private String resourcesDirectory;
180
181 /** Should we refresh the application tools on a per request basis? */
182 private boolean refreshToolsPerRequest = false;
183
184 /**
185 * Called the first time the Service is used.
186 */
187 @Override
188 public void init()
189 throws InitializationException
190 {
191 try
192 {
193 pool = (PoolService)TurbineServices.getInstance().getService(PoolService.ROLE);
194
195 if (pool == null)
196 {
197 throw new InitializationException("Pull Service requires"
198 + " configured Pool Service!");
199 }
200
201 initPullService();
202 // Make sure to setInit(true) because Tools may
203 // make calls back to the TurbinePull static methods
204 // which causes an init loop.
205 setInit(true);
206
207 // Do _NOT_ move this before the setInit(true)
208 velocity = TurbineVelocity.getService();
209
210 if (velocity != null)
211 {
212 initPullTools();
213 }
214 else
215 {
216 log.info("Velocity Service not configured, skipping pull tools!");
217 }
218 }
219 catch (Exception e)
220 {
221 throw new InitializationException(
222 "TurbinePullService failed to initialize", e);
223 }
224 }
225
226 /**
227 * Initialize the pull service
228 *
229 * @exception Exception A problem happened when starting up
230 */
231 private void initPullService()
232 throws Exception
233 {
234 // This is the per-service configuration, prefixed with services.PullService
235 Configuration conf = getConfiguration();
236
237 // Get the resources directory that is specificed
238 // in the TR.props or default to "resources", relative to the webapp.
239 resourcesDirectory = conf.getString(
240 TOOL_RESOURCES_DIR_KEY,
241 TOOL_RESOURCES_DIR_DEFAULT);
242
243 // Should we refresh the tool box on a per
244 // request basis.
245 refreshToolsPerRequest =
246 conf.getBoolean(
247 TOOLS_PER_REQUEST_REFRESH_KEY,
248 TOOLS_PER_REQUEST_REFRESH_DEFAULT);
249
250 // Log the fact that the application tool box will
251 // be refreshed on a per request basis.
252 if (refreshToolsPerRequest)
253 {
254 log.info("Pull Model tools will "
255 + "be refreshed on a per request basis.");
256 }
257 }
258
259 /**
260 * Initialize the pull tools. At this point, the
261 * service must be marked as initialized, because the
262 * tools may call the methods of this service via the
263 * static facade class TurbinePull.
264 *
265 * @exception Exception A problem happened when starting up
266 */
267 private void initPullTools()
268 throws Exception
269 {
270 // And for reasons I never really fully understood,
271 // the tools directive is toplevel without the service
272 // prefix. This is brain-damaged but for legacy reasons we
273 // keep this. So this is the global turbine configuration:
274 Configuration conf = Turbine.getConfiguration();
275
276 // Grab each list of tools that are to be used (for global scope,
277 // request scope, authorized scope, session scope and persistent
278 // scope tools). They are specified respectively in the TR.props
279 // like this:
280 //
281 // tool.global.ui = org.apache.turbine.util.pull.UIManager
282 // tool.global.mm = org.apache.turbine.util.pull.MessageManager
283 //
284 // tool.request.link = org.apache.turbine.services.pull.tools.TemplateLink
285 //
286 // tool.session.basket = org.sample.util.ShoppingBasket;
287 //
288 // tool.persistent.ui = org.apache.turbine.services.pull.util.PersistentUIManager
289
290 log.debug("Global Tools:");
291 globalTools = getTools(conf.subset(GLOBAL_TOOL));
292 log.debug("Request Tools:");
293 requestTools = getTools(conf.subset(REQUEST_TOOL));
294 log.debug("Session Tools:");
295 sessionTools = getTools(conf.subset(SESSION_TOOL));
296 log.debug("Authorized Tools:");
297 authorizedTools = getTools(conf.subset(AUTHORIZED_TOOL));
298 log.debug("Persistent Tools:");
299 persistentTools = getTools(conf.subset(PERSISTENT_TOOL));
300
301 // Create and populate the global context right now
302
303 // This is unholy, because it entwines the VelocityService and
304 // the Pull Service even further. However, there isn't much we can
305 // do for the 2.3 release. Expect this to go post-2.3
306 globalContext = velocity.getNewContext();
307
308 populateWithGlobalTools(globalContext);
309 }
310
311 /**
312 * Retrieve the tool names and classes for the tools definied
313 * in the configuration file with the prefix given.
314 *
315 * @param toolConfig The part of the configuration describing some tools
316 */
317 @SuppressWarnings("unchecked")
318 private List<ToolData> getTools(Configuration toolConfig)
319 {
320 List<ToolData> tools = new ArrayList<ToolData>();
321
322 // There might not be any tools for this prefix
323 // so return an empty list.
324 if (toolConfig == null)
325 {
326 return tools;
327 }
328
329 for (Iterator<String> it = toolConfig.getKeys(); it.hasNext();)
330 {
331 String toolName = it.next();
332 String toolClassName = toolConfig.getString(toolName);
333
334 try
335 {
336 // Create an instance of the tool class.
337 Class<ApplicationTool> toolClass = (Class<ApplicationTool>) Class.forName(toolClassName);
338
339 // Add the tool to the list being built.
340 tools.add(new ToolData(toolName, toolClassName, toolClass));
341
342 log.info("Tool " + toolClassName
343 + " to add to the context as '$" + toolName + "'");
344 }
345 catch (Exception e)
346 {
347 log.error("Cannot instantiate tool class "
348 + toolClassName + ": ", e);
349 }
350 }
351
352 return tools;
353 }
354
355 /**
356 * Return the Context which contains all global tools that
357 * are to be used in conjunction with the Turbine
358 * Pull Model. The tools are refreshed every time the
359 * global Context is pulled.
360 */
361 public Context getGlobalContext()
362 {
363 if (refreshToolsPerRequest)
364 {
365 refreshGlobalTools();
366 }
367 return globalContext;
368 }
369
370 /**
371 * Populate the given context with all request, session, authorized
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 Velocity Context to populate
377 * @param data a RunData object for request specific data
378 */
379 public void populateContext(Context 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
388 //
389 // Session Tool start right at the session once the user has been set
390 // while persistent and authorized Tools are started when the user has
391 // logged in
392 //
393 User user = data.getUser();
394
395 // Note: Session tools are currently lost after the login action
396 // because the anonymous user is replaced the the real user object.
397 // We should either store the session pull tools in the session or
398 // make Turbine.loginAction() copy the session pull tools into the
399 // new user object.
400 populateWithSessionTools(sessionTools, context, data, user);
401
402 if (!TurbineSecurity.isAnonymousUser(user))
403 {
404 if (user.hasLoggedIn())
405 {
406 populateWithSessionTools(authorizedTools, context, data, user);
407 populateWithPermTools(persistentTools, context, data, user);
408 }
409 }
410 }
411
412 /**
413 * Populate the given context with all request, session, authorized
414 * and persistent scope tools (it is assumed that the context
415 * already wraps the global context, and thus already contains
416 * the global tools).
417 *
418 * @param context a Velocity Context to populate
419 * @param data a PipelineData object for request specific data
420 */
421 public void populateContext(Context context, PipelineData pipelineData)
422 {
423 // Map runDataMap = (Map) pipelineData.get(RunData.class);
424 // RunData data = (RunData)runDataMap.get(RunData.class);
425 RunData data = (RunData)pipelineData;
426
427 populateWithRequestTools(context, pipelineData);
428 // session tools (whether session-only or persistent are
429 // very similar, so the same method is used - the
430 // boolean parameter indicates whether get/setPerm is to be used
431 // rather than get/setTemp)
432
433 //
434 // Session Tool start right at the session once the user has been set
435 // while persistent and authorized Tools are started when the user has
436 // logged in
437 //
438 User user = data.getUser();
439
440 // Note: Session tools are currently lost after the login action
441 // because the anonymous user is replaced the the real user object.
442 // We should either store the session pull tools in the session or
443 // make Turbine.loginAction() copy the session pull tools into the
444 // new user object.
445 populateWithSessionTools(sessionTools, context, pipelineData, user);
446
447 if (!TurbineSecurity.isAnonymousUser(user))
448 {
449 if (user.hasLoggedIn())
450 {
451 populateWithSessionTools(authorizedTools, context, pipelineData, user);
452 populateWithPermTools(persistentTools, context, pipelineData, user);
453 }
454 }
455 }
456
457 /**
458 * Populate the given context with the global tools
459 *
460 * @param context a Velocity Context to populate
461 */
462 private void populateWithGlobalTools(Context context)
463 {
464 for (Iterator<ToolData> it = globalTools.iterator(); it.hasNext();)
465 {
466 ToolData toolData = it.next();
467 try
468 {
469 Object tool = toolData.toolClass.newInstance();
470
471 // global tools are init'd with a null data parameter
472 initTool(tool, null);
473
474 // put the tool in the context
475 context.put(toolData.toolName, tool);
476 }
477 catch (Exception e)
478 {
479 log.error("Could not instantiate global tool "
480 + toolData.toolName + " from a "
481 + toolData.toolClassName + " object", e);
482 }
483 }
484 }
485
486 /**
487 * Populate the given context with the request-scope tools
488 *
489 * @param context a Velocity Context to populate
490 * @param data a RunData instance
491 */
492 private void populateWithRequestTools(Context context, RunData data)
493 {
494 // Iterate the tools
495 for (Iterator<ToolData> it = requestTools.iterator(); it.hasNext();)
496 {
497 ToolData toolData = it.next();
498 try
499 {
500 // Fetch Object through the Pool.
501 Object tool = pool.getInstance(toolData.toolClass);
502
503 // request tools are init'd with a RunData object
504 initTool(tool, data);
505
506 // put the tool in the context
507 context.put(toolData.toolName, tool);
508 }
509 catch (Exception e)
510 {
511 log.error("Could not instantiate request tool "
512 + toolData.toolName + " from a "
513 + toolData.toolClassName + " object", e);
514 }
515 }
516 }
517
518
519 /**
520 * Populate the given context with the request-scope tools
521 *
522 * @param context a Velocity Context to populate
523 * @param data a RunData instance
524 */
525 private void populateWithRequestTools(Context context, PipelineData pipelineData)
526 {
527 // Iterate the tools
528 for (Iterator<ToolData> it = requestTools.iterator(); it.hasNext();)
529 {
530 ToolData toolData = it.next();
531 try
532 {
533 // Fetch Object through the Pool.
534 Object tool = pool.getInstance(toolData.toolClass);
535
536 initTool(tool, pipelineData);
537
538 // put the tool in the context
539 context.put(toolData.toolName, tool);
540 }
541 catch (Exception e)
542 {
543 log.error("Could not instantiate request tool "
544 + toolData.toolName + " from a "
545 + toolData.toolClassName + " object", e);
546 }
547 }
548 }
549
550 /**
551 * Populate the given context with the session-scoped tools.
552 *
553 * @param tools The list of tools with which to populate the
554 * session.
555 * @param context The context to populate.
556 * @param data The current RunData object
557 * @param user The <code>User</code> object whose storage to
558 * retrieve the tool from.
559 */
560 @SuppressWarnings({ "unused", "null" })
561 private void populateWithSessionTools(List<ToolData> tools, Context context,
562 PipelineData pipelineData, User user)
563 {
564 //Map runDataMap = (Map)pipelineData.get(RunData.class);
565 //RunData data = (RunData) runDataMap.get(RunData.class);
566 RunData runData = (RunData)pipelineData;
567 // Iterate the tools
568 for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
569 {
570 ToolData toolData = it.next();
571 try
572 {
573 // ensure that tool is created only once for a user
574 // by synchronizing against the user object
575 synchronized (runData.getSession())
576 {
577 // first try and fetch the tool from the user's
578 // hashtable
579 Object tool = runData.getSession().getAttribute(
580 SESSION_TOOLS_ATTRIBUTE_PREFIX
581 + toolData.toolClassName);
582
583 if (tool == null)
584 {
585 // if not there, an instance must be fetched from
586 // the pool
587 tool = pool.getInstance(toolData.toolClass);
588
589 // session tools are init'd with the User object
590 initTool(tool, user);
591
592 // store the newly created tool in the session
593 runData.getSession().setAttribute(
594 SESSION_TOOLS_ATTRIBUTE_PREFIX
595 + tool.getClass().getName(), tool);
596 }
597
598 // *NOT* else
599 if(tool != null)
600 {
601 // This is a semantics change. In the old
602 // Turbine, Session tools were initialized and
603 // then refreshed every time they were pulled
604 // into the context if "refreshToolsPerRequest"
605 // was wanted.
606 //
607 // RunDataApplicationTools now have a parameter
608 // for refresh. If it is not refreshed immediately
609 // after init(), the parameter value will be undefined
610 // until the 2nd run. So we refresh all the session
611 // tools on every run, even if we just init'ed it.
612 //
613
614 if (refreshToolsPerRequest)
615 {
616 refreshTool(tool, pipelineData);
617 }
618
619 // put the tool in the context
620 log.debug("Adding " + tool + " to ctx as "
621 + toolData.toolName);
622 context.put(toolData.toolName, tool);
623 }
624 else
625 {
626 log.info("Tool " + toolData.toolName
627 + " was null, skipping it.");
628 }
629 }
630 }
631 catch (Exception e)
632 {
633 log.error("Could not instantiate session tool "
634 + toolData.toolName + " from a "
635 + toolData.toolClassName + " object", e);
636 }
637 }
638 }
639
640 /**
641 * Populate the given context with the session-scoped tools.
642 *
643 * @param tools The list of tools with which to populate the
644 * session.
645 * @param context The context to populate.
646 * @param data The current RunData object
647 * @param user The <code>User</code> object whose storage to
648 * retrieve the tool from.
649 */
650 @SuppressWarnings({ "unused", "null" })
651 private void populateWithSessionTools(List<ToolData> tools, Context context,
652 RunData data, User user)
653 {
654 // Iterate the tools
655 for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
656 {
657 ToolData toolData = it.next();
658 try
659 {
660 // ensure that tool is created only once for a user
661 // by synchronizing against the user object
662 synchronized (data.getSession())
663 {
664 // first try and fetch the tool from the user's
665 // hashtable
666 Object tool = data.getSession().getAttribute(
667 SESSION_TOOLS_ATTRIBUTE_PREFIX
668 + toolData.toolClassName);
669
670 if (tool == null)
671 {
672 // if not there, an instance must be fetched from
673 // the pool
674 tool = pool.getInstance(toolData.toolClass);
675
676 // session tools are init'd with the User object
677 initTool(tool, user);
678
679 // store the newly created tool in the session
680 data.getSession().setAttribute(
681 SESSION_TOOLS_ATTRIBUTE_PREFIX
682 + tool.getClass().getName(), tool);
683 }
684
685 // *NOT* else
686 if(tool != null)
687 {
688 // This is a semantics change. In the old
689 // Turbine, Session tools were initialized and
690 // then refreshed every time they were pulled
691 // into the context if "refreshToolsPerRequest"
692 // was wanted.
693 //
694 // RunDataApplicationTools now have a parameter
695 // for refresh. If it is not refreshed immediately
696 // after init(), the parameter value will be undefined
697 // until the 2nd run. So we refresh all the session
698 // tools on every run, even if we just init'ed it.
699 //
700
701 if (refreshToolsPerRequest)
702 {
703 refreshTool(tool, data);
704 }
705
706 // put the tool in the context
707 log.debug("Adding " + tool + " to ctx as "
708 + toolData.toolName);
709 context.put(toolData.toolName, tool);
710 }
711 else
712 {
713 log.info("Tool " + toolData.toolName
714 + " was null, skipping it.");
715 }
716 }
717 }
718 catch (Exception e)
719 {
720 log.error("Could not instantiate session tool "
721 + toolData.toolName + " from a "
722 + toolData.toolClassName + " object", e);
723 }
724 }
725 }
726
727
728
729 /**
730 * Populate the given context with the perm-scoped tools.
731 *
732 * @param tools The list of tools with which to populate the
733 * session.
734 * @param context The context to populate.
735 * @param data The current RunData object
736 * @param user The <code>User</code> object whose storage to
737 * retrieve the tool from.
738 */
739 private void populateWithPermTools(List<ToolData> tools, Context context,
740 PipelineData pipelineData, User user)
741 {
742 // Iterate the tools
743 for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
744 {
745 ToolData toolData = it.next();
746 try
747 {
748 // ensure that tool is created only once for a user
749 // by synchronizing against the user object
750 synchronized (user)
751 {
752 // first try and fetch the tool from the user's
753 // hashtable
754 Object tool = user.getPerm(toolData.toolClassName);
755
756 if (tool == null)
757 {
758 // if not there, an instance must be fetched from
759 // the pool
760 tool = pool.getInstance(toolData.toolClass);
761
762 // session tools are init'd with the User object
763 initTool(tool, user);
764
765 // store the newly created tool in the user's hashtable
766 user.setPerm(toolData.toolClassName, tool);
767 }
768
769 // *NOT* else
770 if(tool != null)
771 {
772 // This is a semantics change. In the old
773 // Turbine, Session tools were initialized and
774 // then refreshed every time they were pulled
775 // into the context if "refreshToolsPerRequest"
776 // was wanted.
777 //
778 // RunDataApplicationTools now have a parameter
779 // for refresh. If it is not refreshed immediately
780 // after init(), the parameter value will be undefined
781 // until the 2nd run. So we refresh all the session
782 // tools on every run, even if we just init'ed it.
783 //
784
785 if (refreshToolsPerRequest)
786 {
787 refreshTool(tool, pipelineData);
788 }
789
790 // put the tool in the context
791 log.debug("Adding " + tool + " to ctx as "
792 + toolData.toolName);
793 log.warn("Persistent scope tools are deprecated.");
794 context.put(toolData.toolName, tool);
795 }
796 else
797 {
798 log.info("Tool " + toolData.toolName
799 + " was null, skipping it.");
800 }
801 }
802 }
803 catch (Exception e)
804 {
805 log.error("Could not instantiate perm tool "
806 + toolData.toolName + " from a "
807 + toolData.toolClassName + " object", e);
808 }
809 }
810 }
811
812 /**
813 * Populate the given context with the perm-scoped tools.
814 *
815 * @param tools The list of tools with which to populate the
816 * session.
817 * @param context The context to populate.
818 * @param data The current RunData object
819 * @param user The <code>User</code> object whose storage to
820 * retrieve the tool from.
821 */
822 private void populateWithPermTools(List<ToolData> tools, Context context,
823 RunData data, User user)
824 {
825 // Iterate the tools
826 for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
827 {
828 ToolData toolData = it.next();
829 try
830 {
831 // ensure that tool is created only once for a user
832 // by synchronizing against the user object
833 synchronized (user)
834 {
835 // first try and fetch the tool from the user's
836 // hashtable
837 Object tool = user.getPerm(toolData.toolClassName);
838
839 if (tool == null)
840 {
841 // if not there, an instance must be fetched from
842 // the pool
843 tool = pool.getInstance(toolData.toolClass);
844
845 // session tools are init'd with the User object
846 initTool(tool, user);
847
848 // store the newly created tool in the user's hashtable
849 user.setPerm(toolData.toolClassName, tool);
850 }
851
852 // *NOT* else
853 if(tool != null)
854 {
855 // This is a semantics change. In the old
856 // Turbine, Session tools were initialized and
857 // then refreshed every time they were pulled
858 // into the context if "refreshToolsPerRequest"
859 // was wanted.
860 //
861 // RunDataApplicationTools now have a parameter
862 // for refresh. If it is not refreshed immediately
863 // after init(), the parameter value will be undefined
864 // until the 2nd run. So we refresh all the session
865 // tools on every run, even if we just init'ed it.
866 //
867
868 if (refreshToolsPerRequest)
869 {
870 refreshTool(tool, data);
871 }
872
873 // put the tool in the context
874 log.debug("Adding " + tool + " to ctx as "
875 + toolData.toolName);
876 log.warn("Persistent scope tools are deprecated.");
877 context.put(toolData.toolName, tool);
878 }
879 else
880 {
881 log.info("Tool " + toolData.toolName
882 + " was null, skipping it.");
883 }
884 }
885 }
886 catch (Exception e)
887 {
888 log.error("Could not instantiate perm tool "
889 + toolData.toolName + " from a "
890 + toolData.toolClassName + " object", e);
891 }
892 }
893 }
894
895
896
897 /**
898 * Return the absolute path to the resources directory
899 * used by the application tools.
900 *
901 * @return the absolute path of the resources directory
902 */
903 public String getAbsolutePathToResourcesDirectory()
904 {
905 return Turbine.getRealPath(resourcesDirectory);
906 }
907
908 /**
909 * Return the resources directory. This is
910 * relative to the web context.
911 *
912 * @return the relative path of the resources directory
913 */
914 public String getResourcesDirectory()
915 {
916 return resourcesDirectory;
917 }
918
919 /**
920 * Refresh the global tools. We can
921 * only refresh those tools that adhere to
922 * ApplicationTool interface because we
923 * know those types of tools have a refresh
924 * method.
925 */
926 private void refreshGlobalTools()
927 {
928 for (Iterator<ToolData> it = globalTools.iterator(); it.hasNext();)
929 {
930 ToolData toolData = it.next();
931 Object tool = globalContext.get(toolData.toolName);
932 refreshTool(tool, null);
933 }
934 }
935
936 /**
937 * Release the request-scope tool instances in the
938 * given Context back to the pool
939 *
940 * @param context the Velocity Context to release tools from
941 */
942 public void releaseTools(Context context)
943 {
944 // only the request tools can be released - other scoped
945 // tools will have continuing references to them
946 releaseTools(context, requestTools);
947 }
948
949 /**
950 * Release the given list of tools from the context back
951 * to the pool
952 *
953 * @param context the Context containing the tools
954 * @param tools a List of ToolData objects
955 */
956 private void releaseTools(Context context, List<ToolData> tools)
957 {
958 for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
959 {
960 ToolData toolData = it.next();
961 Object tool = context.remove(toolData.toolName);
962
963 if (tool != null)
964 {
965 pool.putInstance(tool);
966 }
967 }
968 }
969
970 /**
971 * Initialized a given Tool with the passed init Object
972 *
973 * @param tool A Tool Object
974 * @param param The Init Parameter
975 *
976 * @throws Exception If anything went wrong.
977 */
978 private void initTool(Object tool, Object param)
979 throws Exception
980 {
981 if (param instanceof PipelineData)
982 {
983 if (tool instanceof PipelineDataApplicationTool)
984 {
985 ((PipelineDataApplicationTool) tool).init(param);
986 }
987 else if (tool instanceof RunDataApplicationTool)
988 {
989 RunData data = getRunData((PipelineData)param);
990 ((RunDataApplicationTool) tool).init(data);
991 }
992 else if (tool instanceof ApplicationTool)
993 {
994 RunData data = getRunData((PipelineData)param);
995 ((ApplicationTool) tool).init(data);
996 }
997 }
998 else
999 {
1000 if (tool instanceof PipelineDataApplicationTool)
1001 {
1002 ((PipelineDataApplicationTool) tool).init(param);
1003 }
1004 else if (tool instanceof RunDataApplicationTool)
1005 {
1006 ((RunDataApplicationTool) tool).init(param);
1007 }
1008 else if (tool instanceof ApplicationTool)
1009 {
1010 ((ApplicationTool) tool).init(param);
1011 }
1012 }
1013 }
1014
1015 /**
1016 * Refresh a given Tool.
1017 *
1018 * @param tool A Tool Object
1019 * @param data The current RunData Object
1020 */
1021 private void refreshTool(Object tool, Object dataObject)
1022 {
1023 RunData data = null;
1024 PipelineData pipelineData = null;
1025 if (dataObject instanceof PipelineData)
1026 {
1027 pipelineData = (PipelineData)dataObject;
1028 data = getRunData(pipelineData);
1029 if (tool instanceof PipelineDataApplicationTool)
1030 {
1031 ((PipelineDataApplicationTool) tool).refresh(pipelineData);
1032 }
1033 }
1034 if (tool instanceof ApplicationTool)
1035 {
1036 ((ApplicationTool) tool).refresh();
1037 }
1038 else if (tool instanceof RunDataApplicationTool)
1039 {
1040 ((RunDataApplicationTool) tool).refresh(data);
1041 }
1042 }
1043
1044 private RunData getRunData(PipelineData pipelineData)
1045 {
1046 if(!(pipelineData instanceof RunData)){
1047 throw new RuntimeException("Can't cast to rundata from pipeline data.");
1048 }
1049 return (RunData)pipelineData;
1050 }
1051 }