1 package org.apache.turbine.services.pull;
2
3
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 */
22
23
24 import java.util.ArrayList;
25 import java.util.Iterator;
26 import java.util.List;
27
28 import org.apache.commons.configuration.Configuration;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.fulcrum.pool.PoolService;
32 import org.apache.fulcrum.security.model.turbine.TurbineUserManager;
33 import org.apache.turbine.Turbine;
34 import org.apache.turbine.annotation.AnnotationProcessor;
35 import org.apache.turbine.om.security.User;
36 import org.apache.turbine.pipeline.PipelineData;
37 import org.apache.turbine.services.InitializationException;
38 import org.apache.turbine.services.TurbineBaseService;
39 import org.apache.turbine.services.TurbineServices;
40 import org.apache.turbine.services.velocity.VelocityService;
41 import org.apache.turbine.util.RunData;
42 import org.apache.velocity.context.Context;
43
44 /**
45 * This is the concrete implementation of the Turbine
46 * Pull Service.
47 * <p>
48 * These are tools that are placed in the context by the service
49 * These tools will be made available to all your
50 * templates. You list the tools in the following way:
51 * </p>
52 * <pre>
53 * tool.<scope>.<id> = <classname>
54 *
55 * <scope> is the tool scope: global, request, session,
56 * authorized or persistent (see below for more details)
57 * <id> is the name of the tool in the context
58 *
59 * You can configure the tools in this way:
60 * tool.<id>.<parameter> = <value>
61 *
62 * So if you find "global", "request", "session" or "persistent" as second
63 * part, it is a configuration to put a tool into the toolbox, else it is a
64 * tool specific configuration.
65 *
66 * For example:
67 *
68 * tool.global.ui = org.apache.turbine.util.pull.UIManager
69 * tool.global.mm = org.apache.turbine.util.pull.MessageManager
70 * tool.request.link = org.apache.turbine.services.pull.tools.TemplateLink
71 * tool.request.page = org.apache.turbine.util.template.TemplatePageAttributes
72 *
73 * Then:
74 *
75 * tool.ui.skin = default
76 *
77 * configures the value of "skin" for the "ui" tool.
78 *
79 * Tools are accessible in all templates by the <id> given
80 * to the tool. So for the above listings the UIManager would
81 * be available as $ui, the MessageManager as $mm, the TemplateLink
82 * as $link and the TemplatePageAttributes as $page.
83 *
84 * You should avoid using tool names called "global", "request",
85 * "session" or "persistent" because of clashes with the possible Scopes.
86 *
87 * Scopes:
88 *
89 * global: tool is instantiated once and that instance is available
90 * to all templates for all requests. Tool must be threadsafe.
91 *
92 * request: tool is instantiated once for each request (although the
93 * PoolService is used to recycle instances). Tool need not
94 * be threadsafe.
95 *
96 * session: tool is instantiated once for each user session, and is
97 * stored in the session. These tools do not need to be
98 * threadsafe.
99 *
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 1773378 2016-12-09 13:19:59Z 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 = (VelocityService)TurbineServices.getInstance().getService(VelocityService.SERVICE_NAME);
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("TurbinePullService failed to initialize", e);
222 }
223 }
224
225 /**
226 * Initialize the pull service
227 *
228 * @throws Exception A problem happened when starting up
229 */
230 private void initPullService()
231 throws Exception
232 {
233 // This is the per-service configuration, prefixed with services.PullService
234 Configuration conf = getConfiguration();
235
236 // Get the resources directory that is specificed
237 // in the TR.props or default to "resources", relative to the webapp.
238 resourcesDirectory = conf.getString(
239 TOOL_RESOURCES_DIR_KEY,
240 TOOL_RESOURCES_DIR_DEFAULT);
241
242 // Should we refresh the tool box on a per
243 // request basis.
244 refreshToolsPerRequest =
245 conf.getBoolean(
246 TOOLS_PER_REQUEST_REFRESH_KEY,
247 TOOLS_PER_REQUEST_REFRESH_DEFAULT);
248
249 // Log the fact that the application tool box will
250 // be refreshed on a per request basis.
251 if (refreshToolsPerRequest)
252 {
253 log.info("Pull Model tools will "
254 + "be refreshed on a per request basis.");
255 }
256 }
257
258 /**
259 * Initialize the pull tools. At this point, the
260 * service must be marked as initialized, because the
261 * tools may call the methods of this service via the
262 * static facade class TurbinePull.
263 *
264 * @throws Exception A problem happened when starting up
265 */
266 private void initPullTools()
267 throws Exception
268 {
269 // And for reasons I never really fully understood,
270 // the tools directive is toplevel without the service
271 // prefix. This is brain-damaged but for legacy reasons we
272 // keep this. So this is the global turbine configuration:
273 Configuration conf = Turbine.getConfiguration();
274
275 // Grab each list of tools that are to be used (for global scope,
276 // request scope, authorized scope, session scope and persistent
277 // scope tools). They are specified respectively in the TR.props
278 // like this:
279 //
280 // tool.global.ui = org.apache.turbine.util.pull.UIManager
281 // tool.global.mm = org.apache.turbine.util.pull.MessageManager
282 //
283 // tool.request.link = org.apache.turbine.services.pull.tools.TemplateLink
284 //
285 // tool.session.basket = org.sample.util.ShoppingBasket;
286 //
287 // tool.persistent.ui = org.apache.turbine.services.pull.util.PersistentUIManager
288
289 log.debug("Global Tools:");
290 globalTools = getTools(conf.subset(GLOBAL_TOOL));
291 log.debug("Request Tools:");
292 requestTools = getTools(conf.subset(REQUEST_TOOL));
293 log.debug("Session Tools:");
294 sessionTools = getTools(conf.subset(SESSION_TOOL));
295 log.debug("Authorized Tools:");
296 authorizedTools = getTools(conf.subset(AUTHORIZED_TOOL));
297 log.debug("Persistent Tools:");
298 persistentTools = getTools(conf.subset(PERSISTENT_TOOL));
299
300 // Create and populate the global context right now
301
302 // This is unholy, because it entwines the VelocityService and
303 // the Pull Service even further. However, there isn't much we can
304 // do for the 2.3 release. Expect this to go post-2.3
305 globalContext = velocity.getNewContext();
306
307 populateWithGlobalTools(globalContext);
308 }
309
310 /**
311 * Retrieve the tool names and classes for the tools defined
312 * in the configuration file with the prefix given.
313 *
314 * @param toolConfig The part of the configuration describing some tools
315 */
316 @SuppressWarnings("unchecked")
317 private List<ToolData> getTools(Configuration toolConfig)
318 {
319 List<ToolData> tools = new ArrayList<ToolData>();
320
321 // There might not be any tools for this prefix
322 // so return an empty list.
323 if (toolConfig == null)
324 {
325 return tools;
326 }
327
328 for (Iterator<String> it = toolConfig.getKeys(); it.hasNext();)
329 {
330 String toolName = it.next();
331 String toolClassName = toolConfig.getString(toolName);
332
333 try
334 {
335 // Create an instance of the tool class.
336 Class<ApplicationTool> toolClass = (Class<ApplicationTool>) Class.forName(toolClassName);
337
338 // Add the tool to the list being built.
339 tools.add(new ToolData(toolName, toolClassName, toolClass));
340
341 log.info("Tool " + toolClassName
342 + " to add to the context as '$" + toolName + "'");
343 }
344 // NoClassDefFoundError + ClassNotFoundException
345 catch (Throwable 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 @Override
362 public Context getGlobalContext()
363 {
364 if (refreshToolsPerRequest)
365 {
366 refreshGlobalTools();
367 }
368 return globalContext;
369 }
370
371 /**
372 * Populate the given context with all request, session, authorized
373 * and persistent scope tools (it is assumed that the context
374 * already wraps the global context, and thus already contains
375 * the global tools).
376 *
377 * @param context a Velocity Context to populate
378 * @param data a RunData object for request specific data
379 */
380 @Override
381 public void populateContext(Context context, RunData data)
382 {
383 populateWithRequestTools(context, data);
384
385 // session tools (whether session-only or persistent are
386 // very similar, so the same method is used - the
387 // boolean parameter indicates whether get/setPerm is to be used
388 // rather than get/setTemp)
389
390 //
391 // Session Tool start right at the session once the user has been set
392 // while persistent and authorized Tools are started when the user has
393 // logged in
394 //
395 User user = data.getUser();
396
397 // Note: Session tools are currently lost after the login action
398 // because the anonymous user is replaced the the real user object.
399 // We should either store the session pull tools in the session or
400 // make Turbine.loginAction() copy the session pull tools into the
401 // new user object.
402 populateWithSessionTools(sessionTools, context, data, user);
403
404 TurbineUserManager userManager =
405 (TurbineUserManager)TurbineServices
406 .getInstance()
407 .getService(TurbineUserManager.ROLE);
408
409 if (!userManager.isAnonymousUser(user))
410 {
411 if (user.hasLoggedIn())
412 {
413 populateWithSessionTools(authorizedTools, context, data, user);
414 populateWithPermTools(persistentTools, context, data, user);
415 }
416 }
417 }
418
419 /**
420 * Populate the given context with all request, session, authorized
421 * and persistent scope tools (it is assumed that the context
422 * already wraps the global context, and thus already contains
423 * the global tools).
424 *
425 * @param context a Velocity Context to populate
426 * @param pipelineData a PipelineData object for request specific data
427 */
428 @Override
429 public void populateContext(Context context, PipelineData pipelineData)
430 {
431 // Map runDataMap = (Map) pipelineData.get(RunData.class);
432 // RunData data = (RunData)runDataMap.get(RunData.class);
433 RunData data = (RunData)pipelineData;
434
435 populateWithRequestTools(context, pipelineData);
436 // session tools (whether session-only or persistent are
437 // very similar, so the same method is used - the
438 // boolean parameter indicates whether get/setPerm is to be used
439 // rather than get/setTemp)
440
441 //
442 // Session Tool start right at the session once the user has been set
443 // while persistent and authorized Tools are started when the user has
444 // logged in
445 //
446 User user = data.getUser();
447
448 // Note: Session tools are currently lost after the login action
449 // because the anonymous user is replaced the the real user object.
450 // We should either store the session pull tools in the session or
451 // make Turbine.loginAction() copy the session pull tools into the
452 // new user object.
453 populateWithSessionTools(sessionTools, context, pipelineData, user);
454
455 TurbineUserManager userManager =
456 (TurbineUserManager)TurbineServices
457 .getInstance()
458 .getService(TurbineUserManager.ROLE);
459
460 if (!userManager.isAnonymousUser(user))
461 {
462 if (user.hasLoggedIn())
463 {
464 populateWithSessionTools(authorizedTools, context, pipelineData, user);
465 populateWithPermTools(persistentTools, context, pipelineData, user);
466 }
467 }
468 }
469
470 /**
471 * Populate the given context with the global tools
472 *
473 * @param context a Velocity Context to populate
474 */
475 private void populateWithGlobalTools(Context context)
476 {
477 for (Iterator<ToolData> it = globalTools.iterator(); it.hasNext();)
478 {
479 ToolData toolData = it.next();
480 try
481 {
482 Object tool = toolData.toolClass.newInstance();
483
484 // global tools are init'd with a null data parameter
485 initTool(tool, null);
486
487 // put the tool in the context
488 context.put(toolData.toolName, tool);
489 }
490 catch (Exception e)
491 {
492 log.error("Could not instantiate global tool "
493 + toolData.toolName + " from a "
494 + toolData.toolClassName + " object", e);
495 }
496 }
497 }
498
499 /**
500 * Populate the given context with the request-scope tools
501 *
502 * @param context a Velocity Context to populate
503 * @param pipelineData a RunData instance
504 */
505 private void populateWithRequestTools(Context context, RunData data)
506 {
507 // Iterate the tools
508 for (Iterator<ToolData> it = requestTools.iterator(); it.hasNext();)
509 {
510 ToolData toolData = it.next();
511 try
512 {
513 // Fetch Object through the Pool.
514 Object tool = pool.getInstance(toolData.toolClass);
515
516 // request tools are init'd with a RunData object
517 initTool(tool, data);
518
519 // put the tool in the context
520 context.put(toolData.toolName, tool);
521 }
522 catch (Exception e)
523 {
524 log.error("Could not instantiate request tool "
525 + toolData.toolName + " from a "
526 + toolData.toolClassName + " object", e);
527 }
528 }
529 }
530
531
532 /**
533 * Populate the given context with the request-scope tools
534 *
535 * @param context a Velocity Context to populate
536 * @param pipelineData a RunData instance
537 */
538 private void populateWithRequestTools(Context context, PipelineData pipelineData)
539 {
540 // Iterate the tools
541 for (Iterator<ToolData> it = requestTools.iterator(); it.hasNext();)
542 {
543 ToolData toolData = it.next();
544 try
545 {
546 // Fetch Object through the Pool.
547 Object tool = pool.getInstance(toolData.toolClass);
548
549 initTool(tool, pipelineData);
550
551 // put the tool in the context
552 context.put(toolData.toolName, tool);
553 }
554 catch (Exception e)
555 {
556 log.error("Could not instantiate request tool "
557 + toolData.toolName + " from a "
558 + toolData.toolClassName + " object", e);
559 }
560 }
561 }
562
563 /**
564 * Populate the given context with the session-scoped tools.
565 *
566 * @param tools The list of tools with which to populate the
567 * session.
568 * @param context The context to populate.
569 * @param pipelineData The current RunData object
570 * @param user The <code>User</code> object whose storage to
571 * retrieve the tool from.
572 */
573 private void populateWithSessionTools(List<ToolData> tools, Context context,
574 PipelineData pipelineData, User user)
575 {
576 //Map runDataMap = (Map)pipelineData.get(RunData.class);
577 //RunData data = (RunData) runDataMap.get(RunData.class);
578 RunData runData = (RunData)pipelineData;
579 // Iterate the tools
580 for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
581 {
582 ToolData toolData = it.next();
583 try
584 {
585 // ensure that tool is created only once for a user
586 // by synchronizing against the user object
587 synchronized (runData.getSession())
588 {
589 // first try and fetch the tool from the user's
590 // hashtable
591 Object tool = runData.getSession().getAttribute(
592 SESSION_TOOLS_ATTRIBUTE_PREFIX
593 + toolData.toolClassName);
594
595 if (tool == null)
596 {
597 // if not there, an instance must be fetched from
598 // the pool
599 tool = pool.getInstance(toolData.toolClass);
600
601 // session tools are init'd with the User object
602 initTool(tool, user);
603 }
604
605 // *NOT* else
606 if(tool != null)
607 {
608 // store the newly created tool in the session
609 runData.getSession().setAttribute(
610 SESSION_TOOLS_ATTRIBUTE_PREFIX
611 + tool.getClass().getName(), tool);
612
613 // This is a semantics change. In the old
614 // Turbine, Session tools were initialized and
615 // then refreshed every time they were pulled
616 // into the context if "refreshToolsPerRequest"
617 // was wanted.
618 //
619 // RunDataApplicationTools now have a parameter
620 // for refresh. If it is not refreshed immediately
621 // after init(), the parameter value will be undefined
622 // until the 2nd run. So we refresh all the session
623 // tools on every run, even if we just init'ed it.
624 //
625
626 if (refreshToolsPerRequest)
627 {
628 refreshTool(tool, pipelineData);
629 }
630
631 // put the tool in the context
632 log.debug("Adding " + tool + " to ctx as "
633 + toolData.toolName);
634 context.put(toolData.toolName, tool);
635 }
636 else
637 {
638 log.info("Tool " + toolData.toolName
639 + " was null, skipping it.");
640 }
641 }
642 }
643 catch (Exception e)
644 {
645 log.error("Could not instantiate session tool "
646 + toolData.toolName + " from a "
647 + toolData.toolClassName + " object", e);
648 }
649 }
650 }
651
652 /**
653 * Populate the given context with the session-scoped tools.
654 *
655 * @param tools The list of tools with which to populate the
656 * session.
657 * @param context The context to populate.
658 * @param pipelineData The current RunData object
659 * @param user The <code>User</code> object whose storage to
660 * retrieve the tool from.
661 */
662 private void populateWithSessionTools(List<ToolData> tools, Context context,
663 RunData data, User user)
664 {
665 // Iterate the tools
666 for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
667 {
668 ToolData toolData = it.next();
669 try
670 {
671 // ensure that tool is created only once for a user
672 // by synchronizing against the user object
673 synchronized (data.getSession())
674 {
675 // first try and fetch the tool from the user's
676 // hashmap
677 Object tool = data.getSession().getAttribute(
678 SESSION_TOOLS_ATTRIBUTE_PREFIX
679 + toolData.toolClassName);
680
681 if (tool == null)
682 {
683 // if not there, an instance must be fetched from
684 // the pool
685 tool = pool.getInstance(toolData.toolClass);
686
687 // session tools are init'd with the User object
688 initTool(tool, user);
689 }
690
691 // *NOT* else
692 if(tool != null)
693 {
694 // store the newly created tool in the session
695 data.getSession().setAttribute(
696 SESSION_TOOLS_ATTRIBUTE_PREFIX
697 + tool.getClass().getName(), tool);
698
699 // This is a semantics change. In the old
700 // Turbine, Session tools were initialized and
701 // then refreshed every time they were pulled
702 // into the context if "refreshToolsPerRequest"
703 // was wanted.
704 //
705 // RunDataApplicationTools now have a parameter
706 // for refresh. If it is not refreshed immediately
707 // after init(), the parameter value will be undefined
708 // until the 2nd run. So we refresh all the session
709 // tools on every run, even if we just init'ed it.
710 //
711
712 if (refreshToolsPerRequest)
713 {
714 refreshTool(tool, data);
715 }
716
717 // put the tool in the context
718 log.debug("Adding " + tool + " to ctx as "
719 + toolData.toolName);
720 context.put(toolData.toolName, tool);
721 }
722 else
723 {
724 log.info("Tool " + toolData.toolName
725 + " was null, skipping it.");
726 }
727 }
728 }
729 catch (Exception e)
730 {
731 log.error("Could not instantiate session tool "
732 + toolData.toolName + " from a "
733 + toolData.toolClassName + " object", e);
734 }
735 }
736 }
737
738
739
740 /**
741 * Populate the given context with the perm-scoped tools.
742 *
743 * @param tools The list of tools with which to populate the
744 * session.
745 * @param context The context to populate.
746 * @param pipelineData The current RunData object
747 * @param user The <code>User</code> object whose storage to
748 * retrieve the tool from.
749 */
750 private void populateWithPermTools(List<ToolData> tools, Context context,
751 PipelineData pipelineData, User user)
752 {
753 // Iterate the tools
754 for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
755 {
756 ToolData toolData = it.next();
757 try
758 {
759 // ensure that tool is created only once for a user
760 // by synchronizing against the user object
761 synchronized (user)
762 {
763 // first try and fetch the tool from the user's
764 // hashtable
765 Object tool = user.getPerm(toolData.toolClassName);
766
767 if (tool == null)
768 {
769 // if not there, an instance must be fetched from
770 // the pool
771 tool = pool.getInstance(toolData.toolClass);
772
773 // session tools are init'd with the User object
774 initTool(tool, user);
775
776 // store the newly created tool in the user's hashtable
777 user.setPerm(toolData.toolClassName, tool);
778 }
779
780 // *NOT* else
781 if(tool != null)
782 {
783 // This is a semantics change. In the old
784 // Turbine, Session tools were initialized and
785 // then refreshed every time they were pulled
786 // into the context if "refreshToolsPerRequest"
787 // was wanted.
788 //
789 // RunDataApplicationTools now have a parameter
790 // for refresh. If it is not refreshed immediately
791 // after init(), the parameter value will be undefined
792 // until the 2nd run. So we refresh all the session
793 // tools on every run, even if we just init'ed it.
794 //
795
796 if (refreshToolsPerRequest)
797 {
798 refreshTool(tool, pipelineData);
799 }
800
801 // put the tool in the context
802 log.debug("Adding " + tool + " to ctx as "
803 + toolData.toolName);
804 log.warn("Persistent scope tools are deprecated.");
805 context.put(toolData.toolName, tool);
806 }
807 else
808 {
809 log.info("Tool " + toolData.toolName
810 + " was null, skipping it.");
811 }
812 }
813 }
814 catch (Exception e)
815 {
816 log.error("Could not instantiate perm tool "
817 + toolData.toolName + " from a "
818 + toolData.toolClassName + " object", e);
819 }
820 }
821 }
822
823 /**
824 * Populate the given context with the perm-scoped tools.
825 *
826 * @param tools The list of tools with which to populate the
827 * session.
828 * @param context The context to populate.
829 * @param pipelineData The current RunData object
830 * @param user The <code>User</code> object whose storage to
831 * retrieve the tool from.
832 */
833 private void populateWithPermTools(List<ToolData> tools, Context context,
834 RunData data, User user)
835 {
836 // Iterate the tools
837 for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
838 {
839 ToolData toolData = it.next();
840 try
841 {
842 // ensure that tool is created only once for a user
843 // by synchronizing against the user object
844 synchronized (user)
845 {
846 // first try and fetch the tool from the user's
847 // hashtable
848 Object tool = user.getPerm(toolData.toolClassName);
849
850 if (tool == null)
851 {
852 // if not there, an instance must be fetched from
853 // the pool
854 tool = pool.getInstance(toolData.toolClass);
855
856 // session tools are init'd with the User object
857 initTool(tool, user);
858
859 // store the newly created tool in the user's hashtable
860 user.setPerm(toolData.toolClassName, tool);
861 }
862
863 // *NOT* else
864 if(tool != null)
865 {
866 // This is a semantics change. In the old
867 // Turbine, Session tools were initialized and
868 // then refreshed every time they were pulled
869 // into the context if "refreshToolsPerRequest"
870 // was wanted.
871 //
872 // RunDataApplicationTools now have a parameter
873 // for refresh. If it is not refreshed immediately
874 // after init(), the parameter value will be undefined
875 // until the 2nd run. So we refresh all the session
876 // tools on every run, even if we just init'ed it.
877 //
878
879 if (refreshToolsPerRequest)
880 {
881 refreshTool(tool, data);
882 }
883
884 // put the tool in the context
885 log.debug("Adding " + tool + " to ctx as "
886 + toolData.toolName);
887 log.warn("Persistent scope tools are deprecated.");
888 context.put(toolData.toolName, tool);
889 }
890 else
891 {
892 log.info("Tool " + toolData.toolName
893 + " was null, skipping it.");
894 }
895 }
896 }
897 catch (Exception e)
898 {
899 log.error("Could not instantiate perm tool "
900 + toolData.toolName + " from a "
901 + toolData.toolClassName + " object", e);
902 }
903 }
904 }
905
906
907
908 /**
909 * Return the absolute path to the resources directory
910 * used by the application tools.
911 *
912 * @return the absolute path of the resources directory
913 */
914 @Override
915 public String getAbsolutePathToResourcesDirectory()
916 {
917 return Turbine.getRealPath(resourcesDirectory);
918 }
919
920 /**
921 * Return the resources directory. This is
922 * relative to the web context.
923 *
924 * @return the relative path of the resources directory
925 */
926 @Override
927 public String getResourcesDirectory()
928 {
929 return resourcesDirectory;
930 }
931
932 /**
933 * Refresh the global tools. We can
934 * only refresh those tools that adhere to
935 * ApplicationTool interface because we
936 * know those types of tools have a refresh
937 * method.
938 */
939 private void refreshGlobalTools()
940 {
941 if (globalTools != null)
942 {
943 for (ToolData toolData : globalTools)
944 {
945 Object tool = globalContext.get(toolData.toolName);
946 refreshTool(tool, null);
947 }
948 }
949 }
950
951 /**
952 * Release the request-scope tool instances in the
953 * given Context back to the pool
954 *
955 * @param context the Velocity Context to release tools from
956 */
957 @Override
958 public void releaseTools(Context context)
959 {
960 // only the request tools can be released - other scoped
961 // tools will have continuing references to them
962 releaseTools(context, requestTools);
963 }
964
965 /**
966 * Release the given list of tools from the context back
967 * to the pool
968 *
969 * @param context the Context containing the tools
970 * @param tools a List of ToolData objects
971 */
972 private void releaseTools(Context context, List<ToolData> tools)
973 {
974 if (tools != null)
975 {
976 for (ToolData toolData : tools)
977 {
978 Object tool = context.remove(toolData.toolName);
979
980 if (tool != null)
981 {
982 pool.putInstance(tool);
983 }
984 }
985 }
986 }
987
988 /**
989 * Initialized a given Tool with the passed init Object
990 *
991 * @param tool A Tool Object
992 * @param param The Init Parameter
993 *
994 * @throws Exception If anything went wrong.
995 */
996 private void initTool(Object tool, Object param)
997 throws Exception
998 {
999 AnnotationProcessor.process(tool);
1000
1001 if (param instanceof PipelineData)
1002 {
1003 if (tool instanceof PipelineDataApplicationTool)
1004 {
1005 ((PipelineDataApplicationTool) tool).init(param);
1006 }
1007 else if (tool instanceof RunDataApplicationTool)
1008 {
1009 RunData data = getRunData((PipelineData)param);
1010 ((RunDataApplicationTool) tool).init(data);
1011 }
1012 else if (tool instanceof ApplicationTool)
1013 {
1014 RunData data = getRunData((PipelineData)param);
1015 ((ApplicationTool) tool).init(data);
1016 }
1017 }
1018 else
1019 {
1020 if (tool instanceof PipelineDataApplicationTool)
1021 {
1022 ((PipelineDataApplicationTool) tool).init(param);
1023 }
1024 else if (tool instanceof RunDataApplicationTool)
1025 {
1026 ((RunDataApplicationTool) tool).init(param);
1027 }
1028 else if (tool instanceof ApplicationTool)
1029 {
1030 ((ApplicationTool) tool).init(param);
1031 }
1032 }
1033 }
1034
1035 /**
1036 * Refresh a given Tool.
1037 *
1038 * @param tool A Tool Object
1039 * @param pipelineData The current RunData Object
1040 */
1041 private void refreshTool(Object tool, Object dataObject)
1042 {
1043 RunData data = null;
1044 PipelineData pipelineData = null;
1045 if (dataObject instanceof PipelineData)
1046 {
1047 pipelineData = (PipelineData)dataObject;
1048 data = getRunData(pipelineData);
1049 if (tool instanceof PipelineDataApplicationTool)
1050 {
1051 ((PipelineDataApplicationTool) tool).refresh(pipelineData);
1052 }
1053 }
1054 if (tool instanceof ApplicationTool)
1055 {
1056 ((ApplicationTool) tool).refresh();
1057 }
1058 else if (tool instanceof RunDataApplicationTool)
1059 {
1060 ((RunDataApplicationTool) tool).refresh(data);
1061 }
1062 }
1063
1064 private RunData getRunData(PipelineData pipelineData)
1065 {
1066 if(!(pipelineData instanceof RunData)){
1067 throw new RuntimeException("Can't cast to rundata from pipeline data.");
1068 }
1069 return (RunData)pipelineData;
1070 }
1071 }