001 package org.apache.turbine.services.pull; 002 003 004 /* 005 * Licensed to the Apache Software Foundation (ASF) under one 006 * or more contributor license agreements. See the NOTICE file 007 * distributed with this work for additional information 008 * regarding copyright ownership. The ASF licenses this file 009 * to you under the Apache License, Version 2.0 (the 010 * "License"); you may not use this file except in compliance 011 * with the License. You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, 016 * software distributed under the License is distributed on an 017 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 018 * KIND, either express or implied. See the License for the 019 * specific language governing permissions and limitations 020 * under the License. 021 */ 022 023 024 import java.util.ArrayList; 025 import java.util.Iterator; 026 import java.util.List; 027 028 import org.apache.commons.configuration.Configuration; 029 import org.apache.commons.logging.Log; 030 import org.apache.commons.logging.LogFactory; 031 import org.apache.fulcrum.pool.PoolService; 032 import org.apache.turbine.Turbine; 033 import org.apache.turbine.om.security.User; 034 import org.apache.turbine.pipeline.PipelineData; 035 import org.apache.turbine.services.InitializationException; 036 import org.apache.turbine.services.TurbineBaseService; 037 import org.apache.turbine.services.TurbineServices; 038 import org.apache.turbine.services.security.TurbineSecurity; 039 import org.apache.turbine.services.velocity.TurbineVelocity; 040 import org.apache.turbine.services.velocity.VelocityService; 041 import org.apache.turbine.util.RunData; 042 import org.apache.velocity.context.Context; 043 044 /** 045 * This is the concrete implementation of the Turbine 046 * Pull Service. 047 * <p> 048 * These are tools that are placed in the context by the service 049 * These tools will be made available to all your 050 * templates. You list the tools in the following way: 051 * <p> 052 * <pre> 053 * tool.<scope>.<id> = <classname> 054 * 055 * <scope> is the tool scope: global, request, session, 056 * authorized or persistent (see below for more details) 057 * <id> is the name of the tool in the context 058 * 059 * You can configure the tools in this way: 060 * tool.<id>.<parameter> = <value> 061 * 062 * So if you find "global", "request", "session" or "persistent" as second 063 * part, it is a configuration to put a tool into the toolbox, else it is a 064 * tool specific configuration. 065 * 066 * For example: 067 * 068 * tool.global.ui = org.apache.turbine.util.pull.UIManager 069 * tool.global.mm = org.apache.turbine.util.pull.MessageManager 070 * tool.request.link = org.apache.turbine.services.pull.tools.TemplateLink 071 * tool.request.page = org.apache.turbine.util.template.TemplatePageAttributes 072 * 073 * Then: 074 * 075 * tool.ui.skin = default 076 * 077 * configures the value of "skin" for the "ui" tool. 078 * 079 * Tools are accessible in all templates by the <id> given 080 * to the tool. So for the above listings the UIManager would 081 * be available as $ui, the MessageManager as $mm, the TemplateLink 082 * as $link and the TemplatePageAttributes as $page. 083 * 084 * You should avoid using tool names called "global", "request", 085 * "session" or "persistent" because of clashes with the possible Scopes. 086 * 087 * Scopes: 088 * 089 * global: tool is instantiated once and that instance is available 090 * to all templates for all requests. Tool must be threadsafe. 091 * 092 * request: tool is instantiated once for each request (although the 093 * PoolService is used to recycle instances). Tool need not 094 * be threadsafe. 095 * 096 * session: tool is instantiated once for each user session, and is 097 * stored in the session. These tools do not need to be 098 * threadsafe. 099 * 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 }