Coverage Report - org.apache.turbine.services.pull.TurbinePullService
 
Classes in this File Line Coverage Branch Coverage Complexity
TurbinePullService
70%
166/235
53%
47/88
3,478
TurbinePullService$ToolData
100%
5/5
N/A
3,478
 
 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.turbine.Turbine;
 33  
 import org.apache.turbine.om.security.User;
 34  
 import org.apache.turbine.pipeline.PipelineData;
 35  
 import org.apache.turbine.services.InitializationException;
 36  
 import org.apache.turbine.services.TurbineBaseService;
 37  
 import org.apache.turbine.services.TurbineServices;
 38  
 import org.apache.turbine.services.security.TurbineSecurity;
 39  
 import org.apache.turbine.services.velocity.TurbineVelocity;
 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.&lt;scope&gt;.&lt;id&gt; = &lt;classname&gt;
 54  
  *
 55  
  * &lt;scope&gt;      is the tool scope: global, request, session,
 56  
  *              authorized or persistent (see below for more details)
 57  
  * &lt;id&gt;         is the name of the tool in the context
 58  
  *
 59  
  * You can configure the tools in this way:
 60  
  * tool.&lt;id&gt;.&lt;parameter&gt; = &lt;value&gt;
 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 1078552 2011-03-06 19:58:46Z tv $
 120  
  */
 121  58
 public class TurbinePullService
 122  
         extends TurbineBaseService
 123  
         implements PullService
 124  
 {
 125  
     /** Logging */
 126  58
     private static Log log = LogFactory.getLog(TurbinePullService.class);
 127  
 
 128  
     /** Reference to the pool service */
 129  58
     private PoolService pool = null;
 130  
 
 131  
     /** Reference to the templating (nee Velocity) service */
 132  58
     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  322
         {
 157  322
             this.toolName = toolName;
 158  322
             this.toolClassName = toolClassName;
 159  322
             this.toolClass = toolClass;
 160  322
         }
 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  58
     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  94
                     pool = (PoolService)TurbineServices.getInstance().getService(PoolService.ROLE);
 194  
 
 195  94
             if (pool == null)
 196  
             {
 197  0
                 throw new InitializationException("Pull Service requires"
 198  
                     + " configured Pool Service!");
 199  
             }
 200  
 
 201  94
             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  94
             setInit(true);
 206  
 
 207  
             // Do _NOT_ move this before the setInit(true)
 208  94
             velocity = TurbineVelocity.getService();
 209  
 
 210  62
             if (velocity != null)
 211  
             {
 212  62
                 initPullTools();
 213  
             }
 214  
             else
 215  
             {
 216  0
                 log.info("Velocity Service not configured, skipping pull tools!");
 217  
             }
 218  
         }
 219  32
         catch (Exception e)
 220  
         {
 221  32
             throw new InitializationException(
 222  
                 "TurbinePullService failed to initialize", e);
 223  62
         }
 224  62
     }
 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  94
         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  94
         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  94
         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  94
         if (refreshToolsPerRequest)
 253  
         {
 254  78
             log.info("Pull Model tools will "
 255  
                 + "be refreshed on a per request basis.");
 256  
         }
 257  94
     }
 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  62
         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  62
         log.debug("Global Tools:");
 291  62
         globalTools     = getTools(conf.subset(GLOBAL_TOOL));
 292  62
         log.debug("Request Tools:");
 293  62
         requestTools    = getTools(conf.subset(REQUEST_TOOL));
 294  62
         log.debug("Session Tools:");
 295  62
         sessionTools    = getTools(conf.subset(SESSION_TOOL));
 296  62
         log.debug("Authorized Tools:");
 297  62
         authorizedTools = getTools(conf.subset(AUTHORIZED_TOOL));
 298  62
         log.debug("Persistent Tools:");
 299  62
         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  62
         globalContext = velocity.getNewContext();
 307  
 
 308  62
         populateWithGlobalTools(globalContext);
 309  62
     }
 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  310
         List<ToolData> tools = new ArrayList<ToolData>();
 321  
 
 322  
         // There might not be any tools for this prefix
 323  
         // so return an empty list.
 324  310
         if (toolConfig == null)
 325  
         {
 326  0
             return tools;
 327  
         }
 328  
 
 329  310
         for (Iterator<String> it = toolConfig.getKeys(); it.hasNext();)
 330  
         {
 331  368
             String toolName = it.next();
 332  368
             String toolClassName = toolConfig.getString(toolName);
 333  
 
 334  
             try
 335  
             {
 336  
                 // Create an instance of the tool class.
 337  368
                 Class<ApplicationTool> toolClass = (Class<ApplicationTool>) Class.forName(toolClassName);
 338  
 
 339  
                 // Add the tool to the list being built.
 340  322
                 tools.add(new ToolData(toolName, toolClassName, toolClass));
 341  
 
 342  322
                 log.info("Tool " + toolClassName
 343  
                     + " to add to the context as '$" + toolName + "'");
 344  
             }
 345  46
             catch (Exception e)
 346  
             {
 347  46
                 log.error("Cannot instantiate tool class "
 348  
                     + toolClassName + ": ", e);
 349  322
             }
 350  368
         }
 351  
 
 352  310
         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  28
         if (refreshToolsPerRequest)
 364  
         {
 365  28
             refreshGlobalTools();
 366  
         }
 367  28
         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  10
         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  10
         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  10
         populateWithSessionTools(sessionTools, context, data, user);
 401  
 
 402  10
         if (!TurbineSecurity.isAnonymousUser(user))
 403  
         {
 404  0
             if (user.hasLoggedIn())
 405  
             {
 406  0
                 populateWithSessionTools(authorizedTools, context, data, user);
 407  0
                 populateWithPermTools(persistentTools, context, data, user);
 408  
             }
 409  
         }
 410  10
     }
 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  6
         RunData data = (RunData)pipelineData;
 426  
 
 427  6
         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  6
         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  6
         populateWithSessionTools(sessionTools, context, pipelineData, user);
 446  
 
 447  6
         if (!TurbineSecurity.isAnonymousUser(user))
 448  
         {
 449  2
             if (user.hasLoggedIn())
 450  
             {
 451  2
                 populateWithSessionTools(authorizedTools, context, pipelineData, user);
 452  2
                 populateWithPermTools(persistentTools, context, pipelineData, user);
 453  
             }
 454  
         }
 455  6
     }
 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  62
         for (Iterator<ToolData> it = globalTools.iterator(); it.hasNext();)
 465  
         {
 466  46
             ToolData toolData = it.next();
 467  
             try
 468  
             {
 469  46
                 Object tool = toolData.toolClass.newInstance();
 470  
 
 471  
                 // global tools are init'd with a null data parameter
 472  46
                 initTool(tool, null);
 473  
 
 474  
                 // put the tool in the context
 475  46
                 context.put(toolData.toolName, tool);
 476  
             }
 477  0
             catch (Exception e)
 478  
             {
 479  0
                 log.error("Could not instantiate global tool "
 480  
                     + toolData.toolName + " from a "
 481  
                     + toolData.toolClassName + " object", e);
 482  46
             }
 483  46
         }
 484  62
     }
 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  10
         for (Iterator<ToolData> it = requestTools.iterator(); it.hasNext();)
 496  
         {
 497  50
             ToolData toolData = it.next();
 498  
             try
 499  
             {
 500  
                 // Fetch Object through the Pool.
 501  50
                 Object tool = pool.getInstance(toolData.toolClass);
 502  
 
 503  
                 // request tools are init'd with a RunData object
 504  50
                 initTool(tool, data);
 505  
 
 506  
                 // put the tool in the context
 507  50
                 context.put(toolData.toolName, tool);
 508  
             }
 509  0
             catch (Exception e)
 510  
             {
 511  0
                 log.error("Could not instantiate request tool "
 512  
                     + toolData.toolName + " from a "
 513  
                     + toolData.toolClassName + " object", e);
 514  50
             }
 515  50
         }
 516  10
     }
 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  6
         for (Iterator<ToolData> it = requestTools.iterator(); it.hasNext();)
 529  
         {
 530  30
             ToolData toolData = it.next();
 531  
             try
 532  
             {
 533  
                 // Fetch Object through the Pool.
 534  30
                 Object tool = pool.getInstance(toolData.toolClass);
 535  
 
 536  30
                 initTool(tool, pipelineData);
 537  
 
 538  
                 // put the tool in the context
 539  30
                 context.put(toolData.toolName, tool);
 540  
             }
 541  0
             catch (Exception e)
 542  
             {
 543  0
                 log.error("Could not instantiate request tool "
 544  
                     + toolData.toolName + " from a "
 545  
                     + toolData.toolClassName + " object", e);
 546  30
             }
 547  30
         }
 548  6
     }
 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  8
         RunData runData = (RunData)pipelineData;
 567  
         // Iterate the tools
 568  8
         for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
 569  
         {
 570  6
             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  6
                 synchronized (runData.getSession())
 576  
                 {
 577  
                     // first try and fetch the tool from the user's
 578  
                     // hashtable
 579  6
                     Object tool = runData.getSession().getAttribute(
 580  
                             SESSION_TOOLS_ATTRIBUTE_PREFIX
 581  
                             + toolData.toolClassName);
 582  
 
 583  6
                     if (tool == null)
 584  
                     {
 585  
                         // if not there, an instance must be fetched from
 586  
                         // the pool
 587  6
                         tool = pool.getInstance(toolData.toolClass);
 588  
 
 589  
                         // session tools are init'd with the User object
 590  6
                         initTool(tool, user);
 591  
 
 592  
                         // store the newly created tool in the session
 593  6
                         runData.getSession().setAttribute(
 594  
                                 SESSION_TOOLS_ATTRIBUTE_PREFIX
 595  
                                 + tool.getClass().getName(), tool);
 596  
                     }
 597  
 
 598  
                     // *NOT* else
 599  6
                     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  6
                         if (refreshToolsPerRequest)
 615  
                         {
 616  6
                             refreshTool(tool, pipelineData);
 617  
                         }
 618  
 
 619  
                         // put the tool in the context
 620  6
                         log.debug("Adding " + tool + " to ctx as "
 621  
                                 + toolData.toolName);
 622  6
                         context.put(toolData.toolName, tool);
 623  
                     }
 624  
                     else
 625  
                     {
 626  0
                         log.info("Tool " + toolData.toolName
 627  
                                 + " was null, skipping it.");
 628  
                     }
 629  6
                 }
 630  
             }
 631  0
             catch (Exception e)
 632  
             {
 633  0
                 log.error("Could not instantiate session tool "
 634  
                     + toolData.toolName + " from a "
 635  
                     + toolData.toolClassName + " object", e);
 636  6
             }
 637  6
         }
 638  8
     }
 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  10
         for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
 656  
         {
 657  10
             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  10
                 synchronized (data.getSession())
 663  
                 {
 664  
                     // first try and fetch the tool from the user's
 665  
                     // hashtable
 666  10
                     Object tool = data.getSession().getAttribute(
 667  
                             SESSION_TOOLS_ATTRIBUTE_PREFIX
 668  
                             + toolData.toolClassName);
 669  
 
 670  10
                     if (tool == null)
 671  
                     {
 672  
                         // if not there, an instance must be fetched from
 673  
                         // the pool
 674  10
                         tool = pool.getInstance(toolData.toolClass);
 675  
 
 676  
                         // session tools are init'd with the User object
 677  10
                         initTool(tool, user);
 678  
 
 679  
                         // store the newly created tool in the session
 680  10
                         data.getSession().setAttribute(
 681  
                                 SESSION_TOOLS_ATTRIBUTE_PREFIX
 682  
                                 + tool.getClass().getName(), tool);
 683  
                     }
 684  
 
 685  
                     // *NOT* else
 686  10
                     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  10
                         if (refreshToolsPerRequest)
 702  
                         {
 703  10
                             refreshTool(tool, data);
 704  
                         }
 705  
 
 706  
                         // put the tool in the context
 707  10
                         log.debug("Adding " + tool + " to ctx as "
 708  
                                 + toolData.toolName);
 709  10
                         context.put(toolData.toolName, tool);
 710  
                     }
 711  
                     else
 712  
                     {
 713  0
                         log.info("Tool " + toolData.toolName
 714  
                                 + " was null, skipping it.");
 715  
                     }
 716  10
                 }
 717  
             }
 718  0
             catch (Exception e)
 719  
             {
 720  0
                 log.error("Could not instantiate session tool "
 721  
                     + toolData.toolName + " from a "
 722  
                     + toolData.toolClassName + " object", e);
 723  10
             }
 724  10
         }
 725  10
     }
 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  2
         for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
 744  
         {
 745  0
             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  0
                 synchronized (user)
 751  
                 {
 752  
                     // first try and fetch the tool from the user's
 753  
                     // hashtable
 754  0
                     Object tool = user.getPerm(toolData.toolClassName);
 755  
 
 756  0
                     if (tool == null)
 757  
                     {
 758  
                         // if not there, an instance must be fetched from
 759  
                         // the pool
 760  0
                         tool = pool.getInstance(toolData.toolClass);
 761  
 
 762  
                         // session tools are init'd with the User object
 763  0
                         initTool(tool, user);
 764  
 
 765  
                         // store the newly created tool in the user's hashtable
 766  0
                         user.setPerm(toolData.toolClassName, tool);
 767  
                     }
 768  
 
 769  
                     // *NOT* else
 770  0
                     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  0
                         if (refreshToolsPerRequest)
 786  
                         {
 787  0
                             refreshTool(tool, pipelineData);
 788  
                         }
 789  
 
 790  
                         // put the tool in the context
 791  0
                         log.debug("Adding " + tool + " to ctx as "
 792  
                                 + toolData.toolName);
 793  0
                         log.warn("Persistent scope tools are deprecated.");
 794  0
                         context.put(toolData.toolName, tool);
 795  
                     }
 796  
                     else
 797  
                     {
 798  0
                         log.info("Tool " + toolData.toolName
 799  
                                 + " was null, skipping it.");
 800  
                     }
 801  0
                 }
 802  
             }
 803  0
             catch (Exception e)
 804  
             {
 805  0
                 log.error("Could not instantiate perm tool "
 806  
                     + toolData.toolName + " from a "
 807  
                     + toolData.toolClassName + " object", e);
 808  0
             }
 809  0
         }
 810  2
     }
 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  0
         for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
 827  
         {
 828  0
             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  0
                 synchronized (user)
 834  
                 {
 835  
                     // first try and fetch the tool from the user's
 836  
                     // hashtable
 837  0
                     Object tool = user.getPerm(toolData.toolClassName);
 838  
 
 839  0
                     if (tool == null)
 840  
                     {
 841  
                         // if not there, an instance must be fetched from
 842  
                         // the pool
 843  0
                         tool = pool.getInstance(toolData.toolClass);
 844  
 
 845  
                         // session tools are init'd with the User object
 846  0
                         initTool(tool, user);
 847  
 
 848  
                         // store the newly created tool in the user's hashtable
 849  0
                         user.setPerm(toolData.toolClassName, tool);
 850  
                     }
 851  
 
 852  
                     // *NOT* else
 853  0
                     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  0
                         if (refreshToolsPerRequest)
 869  
                         {
 870  0
                             refreshTool(tool, data);
 871  
                         }
 872  
 
 873  
                         // put the tool in the context
 874  0
                         log.debug("Adding " + tool + " to ctx as "
 875  
                                 + toolData.toolName);
 876  0
                         log.warn("Persistent scope tools are deprecated.");
 877  0
                         context.put(toolData.toolName, tool);
 878  
                     }
 879  
                     else
 880  
                     {
 881  0
                         log.info("Tool " + toolData.toolName
 882  
                                 + " was null, skipping it.");
 883  
                     }
 884  0
                 }
 885  
             }
 886  0
             catch (Exception e)
 887  
             {
 888  0
                 log.error("Could not instantiate perm tool "
 889  
                     + toolData.toolName + " from a "
 890  
                     + toolData.toolClassName + " object", e);
 891  0
             }
 892  0
         }
 893  0
     }
 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  0
         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  46
         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  28
         for (Iterator<ToolData> it = globalTools.iterator(); it.hasNext();)
 929  
         {
 930  28
             ToolData toolData = it.next();
 931  28
             Object tool = globalContext.get(toolData.toolName);
 932  28
             refreshTool(tool, null);
 933  28
         }
 934  28
     }
 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  2
         releaseTools(context, requestTools);
 947  2
     }
 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  2
         for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
 959  
         {
 960  10
             ToolData toolData = it.next();
 961  10
             Object tool = context.remove(toolData.toolName);
 962  
 
 963  10
             if (tool != null)
 964  
             {
 965  10
                 pool.putInstance(tool);
 966  
             }
 967  10
         }
 968  2
     }
 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  142
         if (param instanceof PipelineData)
 982  
         {
 983  80
             if (tool instanceof PipelineDataApplicationTool)
 984  
             {
 985  0
                 ((PipelineDataApplicationTool) tool).init(param);
 986  
             }
 987  80
             else if (tool instanceof RunDataApplicationTool)
 988  
             {
 989  0
                 RunData data = getRunData((PipelineData)param);
 990  0
                 ((RunDataApplicationTool) tool).init(data);
 991  0
             }
 992  80
             else if (tool instanceof ApplicationTool)
 993  
             {
 994  80
                 RunData data = getRunData((PipelineData)param);
 995  80
                 ((ApplicationTool) tool).init(data);
 996  80
             }
 997  
         }
 998  
         else
 999  
         {
 1000  62
             if (tool instanceof PipelineDataApplicationTool)
 1001  
             {
 1002  0
                 ((PipelineDataApplicationTool) tool).init(param);
 1003  
             }
 1004  62
             else if (tool instanceof RunDataApplicationTool)
 1005  
             {
 1006  0
                 ((RunDataApplicationTool) tool).init(param);
 1007  
             }
 1008  62
             else if (tool instanceof ApplicationTool)
 1009  
             {
 1010  62
                 ((ApplicationTool) tool).init(param);
 1011  
             }
 1012  
         }
 1013  142
     }
 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  44
         RunData data = null;
 1024  44
         PipelineData pipelineData = null;
 1025  44
         if (dataObject instanceof PipelineData)
 1026  
         {
 1027  16
             pipelineData = (PipelineData)dataObject;
 1028  16
             data = getRunData(pipelineData);
 1029  16
             if (tool instanceof PipelineDataApplicationTool)
 1030  
             {
 1031  0
                 ((PipelineDataApplicationTool) tool).refresh(pipelineData);
 1032  
             }
 1033  
         }
 1034  44
         if (tool instanceof ApplicationTool)
 1035  
         {
 1036  44
             ((ApplicationTool) tool).refresh();
 1037  
         }
 1038  0
         else if (tool instanceof RunDataApplicationTool)
 1039  
         {
 1040  0
             ((RunDataApplicationTool) tool).refresh(data);
 1041  
         }
 1042  44
     }
 1043  
 
 1044  
     private RunData getRunData(PipelineData pipelineData)
 1045  
     {
 1046  96
         if(!(pipelineData instanceof RunData)){
 1047  0
             throw new RuntimeException("Can't cast to rundata from pipeline data.");
 1048  
         }
 1049  96
         return (RunData)pipelineData;
 1050  
     }
 1051  
 }