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