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