View Javadoc

    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.om.security.User;
    35  import org.apache.turbine.pipeline.PipelineData;
    36  import org.apache.turbine.services.InitializationException;
    37  import org.apache.turbine.services.TurbineBaseService;
    38  import org.apache.turbine.services.TurbineServices;
    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 1706239 2015-10-01 13:18:35Z 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     @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                     // hashtable
    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         for (Iterator<ToolData> it = globalTools.iterator(); it.hasNext();)
    942         {
    943             ToolData toolData = it.next();
    944             Object tool = globalContext.get(toolData.toolName);
    945             refreshTool(tool, null);
    946         }
    947     }
    948
    949     /**
    950      * Release the request-scope tool instances in the
    951      * given Context back to the pool
    952      *
    953      * @param context the Velocity Context to release tools from
    954      */
    955     @Override
    956     public void releaseTools(Context context)
    957     {
    958         // only the request tools can be released - other scoped
    959         // tools will have continuing references to them
    960         releaseTools(context, requestTools);
    961     }
    962
    963     /**
    964      * Release the given list of tools from the context back
    965      * to the pool
    966      *
    967      * @param context the Context containing the tools
    968      * @param tools a List of ToolData objects
    969      */
    970     private void releaseTools(Context context, List<ToolData> tools)
    971     {
    972         for (Iterator<ToolData> it = tools.iterator(); it.hasNext();)
    973         {
    974             ToolData toolData = it.next();
    975             Object tool = context.remove(toolData.toolName);
    976
    977             if (tool != null)
    978             {
    979                 pool.putInstance(tool);
    980             }
    981         }
    982     }
    983
    984     /**
    985      * Initialized a given Tool with the passed init Object
    986      *
    987      * @param tool A Tool Object
    988      * @param param The Init Parameter
    989      *
    990      * @throws Exception If anything went wrong.
    991      */
    992     private void initTool(Object tool, Object param)
    993         throws Exception
    994     {
    995         if (param instanceof PipelineData)
    996         {
    997             if (tool instanceof PipelineDataApplicationTool)
    998             {
    999                 ((PipelineDataApplicationTool) tool).init(param);
    1000             }
    1001             else if (tool instanceof RunDataApplicationTool)
    1002             {
    1003                 RunData data = getRunData((PipelineData)param);
    1004                 ((RunDataApplicationTool) tool).init(data);
    1005             }
    1006             else if (tool instanceof ApplicationTool)
    1007             {
    1008                 RunData data = getRunData((PipelineData)param);
    1009                 ((ApplicationTool) tool).init(data);
    1010             }
    1011         }
    1012         else
    1013         {
    1014             if (tool instanceof PipelineDataApplicationTool)
    1015             {
    1016                 ((PipelineDataApplicationTool) tool).init(param);
    1017             }
    1018             else if (tool instanceof RunDataApplicationTool)
    1019             {
    1020                 ((RunDataApplicationTool) tool).init(param);
    1021             }
    1022             else if (tool instanceof ApplicationTool)
    1023             {
    1024                 ((ApplicationTool) tool).init(param);
    1025             }
    1026         }
    1027     }
    1028
    1029     /**
    1030      * Refresh a given Tool.
    1031      *
    1032      * @param tool A Tool Object
    1033      * @param pipelineData The current RunData Object
    1034      */
    1035     private void refreshTool(Object tool, Object dataObject)
    1036     {
    1037         RunData data = null;
    1038         PipelineData pipelineData = null;
    1039         if (dataObject instanceof PipelineData)
    1040         {
    1041             pipelineData = (PipelineData)dataObject;
    1042             data = getRunData(pipelineData);
    1043             if (tool instanceof PipelineDataApplicationTool)
    1044             {
    1045                 ((PipelineDataApplicationTool) tool).refresh(pipelineData);
    1046             }
    1047         }
    1048         if (tool instanceof ApplicationTool)
    1049         {
    1050             ((ApplicationTool) tool).refresh();
    1051         }
    1052         else if (tool instanceof RunDataApplicationTool)
    1053         {
    1054             ((RunDataApplicationTool) tool).refresh(data);
    1055         }
    1056     }
    1057
    1058     private RunData getRunData(PipelineData pipelineData)
    1059     {
    1060         if(!(pipelineData instanceof RunData)){
    1061             throw new RuntimeException("Can't cast to rundata from pipeline data.");
    1062         }
    1063         return (RunData)pipelineData;
    1064     }
    1065 }