001package 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 024import java.util.ArrayList; 025import java.util.Iterator; 026import java.util.List; 027 028import org.apache.commons.configuration2.Configuration; 029import org.apache.fulcrum.pool.PoolService; 030import org.apache.fulcrum.security.model.turbine.TurbineUserManager; 031import org.apache.logging.log4j.LogManager; 032import org.apache.logging.log4j.Logger; 033import org.apache.turbine.Turbine; 034import org.apache.turbine.annotation.AnnotationProcessor; 035import org.apache.turbine.om.security.User; 036import org.apache.turbine.pipeline.PipelineData; 037import org.apache.turbine.services.InitializationException; 038import org.apache.turbine.services.TurbineBaseService; 039import org.apache.turbine.services.TurbineServices; 040import org.apache.turbine.services.velocity.VelocityService; 041import org.apache.turbine.util.RunData; 042import 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$ 120 */ 121public class TurbinePullService 122 extends TurbineBaseService 123 implements PullService 124{ 125 /** Logging */ 126 private static Logger log = LogManager.getLogger(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 be refreshed on a per request basis."); 254 } 255 } 256 257 /** 258 * Initialize the pull tools. At this point, the 259 * service must be marked as initialized, because the 260 * tools may call the methods of this service via the 261 * static facade class TurbinePull. 262 * 263 * @throws Exception A problem happened when starting up 264 */ 265 private void initPullTools() 266 throws Exception 267 { 268 // And for reasons I never really fully understood, 269 // the tools directive is toplevel without the service 270 // prefix. This is brain-damaged but for legacy reasons we 271 // keep this. So this is the global turbine configuration: 272 Configuration conf = Turbine.getConfiguration(); 273 274 // Grab each list of tools that are to be used (for global scope, 275 // request scope, authorized scope, session scope and persistent 276 // scope tools). They are specified respectively in the TR.props 277 // like this: 278 // 279 // tool.global.ui = org.apache.turbine.util.pull.UIManager 280 // tool.global.mm = org.apache.turbine.util.pull.MessageManager 281 // 282 // tool.request.link = org.apache.turbine.services.pull.tools.TemplateLink 283 // 284 // tool.session.basket = org.sample.util.ShoppingBasket; 285 // 286 // tool.persistent.ui = org.apache.turbine.services.pull.util.PersistentUIManager 287 288 log.debug("Global Tools:"); 289 globalTools = getTools(conf.subset(GLOBAL_TOOL)); 290 log.debug("Request Tools:"); 291 requestTools = getTools(conf.subset(REQUEST_TOOL)); 292 log.debug("Session Tools:"); 293 sessionTools = getTools(conf.subset(SESSION_TOOL)); 294 log.debug("Authorized Tools:"); 295 authorizedTools = getTools(conf.subset(AUTHORIZED_TOOL)); 296 log.debug("Persistent Tools:"); 297 persistentTools = getTools(conf.subset(PERSISTENT_TOOL)); 298 299 // Create and populate the global context right now 300 301 // This is unholy, because it entwines the VelocityService and 302 // the Pull Service even further. However, there isn't much we can 303 // do for the 2.3 release. Expect this to go post-2.3 304 globalContext = velocity.getNewContext(); 305 306 populateWithGlobalTools(globalContext); 307 } 308 309 /** 310 * Retrieve the tool names and classes for the tools defined 311 * in the configuration file with the prefix given. 312 * 313 * @param toolConfig The part of the configuration describing some tools 314 */ 315 @SuppressWarnings("unchecked") 316 private List<ToolData> getTools(Configuration toolConfig) 317 { 318 List<ToolData> tools = new ArrayList<>(); 319 320 // There might not be any tools for this prefix 321 // so return an empty list. 322 if (toolConfig == null) 323 { 324 return tools; 325 } 326 327 for (Iterator<String> it = toolConfig.getKeys(); it.hasNext();) 328 { 329 String toolName = it.next(); 330 String toolClassName = toolConfig.getString(toolName); 331 332 try 333 { 334 // Create an instance of the tool class. 335 Class<ApplicationTool> toolClass = (Class<ApplicationTool>) Class.forName(toolClassName); 336 337 // Add the tool to the list being built. 338 tools.add(new ToolData(toolName, toolClassName, toolClass)); 339 340 log.info("Tool {} to add to the context as '${}'", toolClassName, toolName); 341 } 342 catch (NoClassDefFoundError | ClassNotFoundException e) 343 { 344 log.error("Cannot instantiate tool class {}", toolClassName, e); 345 } 346 } 347 348 return tools; 349 } 350 351 /** 352 * Return the Context which contains all global tools that 353 * are to be used in conjunction with the Turbine 354 * Pull Model. The tools are refreshed every time the 355 * global Context is pulled. 356 */ 357 @Override 358 public Context getGlobalContext() 359 { 360 if (refreshToolsPerRequest) 361 { 362 refreshGlobalTools(); 363 } 364 return globalContext; 365 } 366 367 /** 368 * Populate the given context with all request, session, authorized 369 * and persistent scope tools (it is assumed that the context 370 * already wraps the global context, and thus already contains 371 * the global tools). 372 * 373 * @param context a Velocity Context to populate 374 * @param data a RunData object for request specific data 375 */ 376 @Override 377 public void populateContext(Context context, RunData data) 378 { 379 populateWithRequestTools(context, data); 380 381 // session tools (whether session-only or persistent are 382 // very similar, so the same method is used - the 383 // boolean parameter indicates whether get/setPerm is to be used 384 // rather than get/setTemp) 385 386 // 387 // Session Tool start right at the session once the user has been set 388 // while persistent and authorized Tools are started when the user has 389 // logged in 390 // 391 User user = data.getUser(); 392 393 // Note: Session tools are currently lost after the login action 394 // because the anonymous user is replaced the the real user object. 395 // We should either store the session pull tools in the session or 396 // make Turbine.loginAction() copy the session pull tools into the 397 // new user object. 398 populateWithSessionTools(sessionTools, context, data, user); 399 400 TurbineUserManager userManager = 401 (TurbineUserManager)TurbineServices 402 .getInstance() 403 .getService(TurbineUserManager.ROLE); 404 405 if (!userManager.isAnonymousUser(user) && user.hasLoggedIn()) 406 { 407 populateWithSessionTools(authorizedTools, context, data, user); 408 populateWithPermTools(persistentTools, context, data, user); 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 pipelineData a PipelineData object for request specific data 420 */ 421 @Override 422 public void populateContext(Context context, PipelineData pipelineData) 423 { 424 RunData data = pipelineData.getRunData(); 425 426 populateWithRequestTools(context, pipelineData); 427 // session tools (whether session-only or persistent are 428 // very similar, so the same method is used - the 429 // boolean parameter indicates whether get/setPerm is to be used 430 // rather than get/setTemp) 431 432 // 433 // Session Tool start right at the session once the user has been set 434 // while persistent and authorized Tools are started when the user has 435 // logged in 436 // 437 User user = data.getUser(); 438 439 // Note: Session tools are currently lost after the login action 440 // because the anonymous user is replaced the the real user object. 441 // We should either store the session pull tools in the session or 442 // make Turbine.loginAction() copy the session pull tools into the 443 // new user object. 444 populateWithSessionTools(sessionTools, context, data, user); 445 446 TurbineUserManager userManager = 447 (TurbineUserManager)TurbineServices 448 .getInstance() 449 .getService(TurbineUserManager.ROLE); 450 451 if (!userManager.isAnonymousUser(user) && user.hasLoggedIn()) 452 { 453 populateWithSessionTools(authorizedTools, context, data, user); 454 populateWithPermTools(persistentTools, context, pipelineData, user); 455 } 456 } 457 458 /** 459 * Populate the given context with the global tools 460 * 461 * @param context a Velocity Context to populate 462 */ 463 private void populateWithGlobalTools(Context context) 464 { 465 for (ToolData toolData : globalTools) 466 { 467 try 468 { 469 Object tool = toolData.toolClass.getDeclaredConstructor().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 {} from a {} object", 480 toolData.toolName, toolData.toolClassName, e); 481 } 482 } 483 } 484 485 /** 486 * Populate the given context with the request-scope tools 487 * 488 * @param context a Velocity Context to populate 489 * @param data a RunData or PipelineData instance 490 */ 491 private void populateWithRequestTools(Context context, Object data) 492 { 493 // Iterate the tools 494 for (ToolData toolData : requestTools) 495 { 496 try 497 { 498 // Fetch Object through the Pool. 499 Object tool = pool.getInstance(toolData.toolClass); 500 501 // request tools are init'd with a RunData object 502 initTool(tool, data); 503 504 // put the tool in the context 505 context.put(toolData.toolName, tool); 506 } 507 catch (Exception e) 508 { 509 log.error("Could not instantiate request tool {} from a {} object", 510 toolData.toolName, toolData.toolClassName, e); 511 } 512 } 513 } 514 515 /** 516 * Populate the given context with the session-scoped tools. 517 * 518 * @param tools The list of tools with which to populate the session. 519 * @param context The context to populate. 520 * @param data The current RunData object 521 * @param user The <code>User</code> object whose storage to 522 * retrieve the tool from. 523 */ 524 private void populateWithSessionTools(List<ToolData> tools, Context context, 525 RunData data, User user) 526 { 527 // Iterate the tools 528 for (ToolData toolData : tools) 529 { 530 try 531 { 532 // ensure that tool is created only once for a user 533 // by synchronizing against the user object 534 synchronized (data.getSession()) 535 { 536 // first try and fetch the tool from the user's 537 // hashmap 538 Object tool = data.getSession().getAttribute( 539 SESSION_TOOLS_ATTRIBUTE_PREFIX 540 + toolData.toolClassName); 541 542 if (tool == null) 543 { 544 // if not there, an instance must be fetched from 545 // the pool 546 tool = pool.getInstance(toolData.toolClass); 547 548 // session tools are init'd with the User object 549 initTool(tool, user); 550 } 551 552 // *NOT* else 553 if(tool != null) 554 { 555 // store the newly created tool in the session 556 data.getSession().setAttribute( 557 SESSION_TOOLS_ATTRIBUTE_PREFIX 558 + tool.getClass().getName(), tool); 559 560 // This is a semantics change. In the old 561 // Turbine, Session tools were initialized and 562 // then refreshed every time they were pulled 563 // into the context if "refreshToolsPerRequest" 564 // was wanted. 565 // 566 // RunDataApplicationTools now have a parameter 567 // for refresh. If it is not refreshed immediately 568 // after init(), the parameter value will be undefined 569 // until the 2nd run. So we refresh all the session 570 // tools on every run, even if we just init'ed it. 571 // 572 573 if (refreshToolsPerRequest) 574 { 575 refreshTool(tool, data); 576 } 577 578 // put the tool in the context 579 log.debug("Adding {} to ctx as {}", tool, toolData.toolName); 580 context.put(toolData.toolName, tool); 581 } 582 else 583 { 584 log.info("Tool {} was null, skipping it.", toolData.toolName); 585 } 586 } 587 } 588 catch (Exception e) 589 { 590 log.error("Could not instantiate session tool {} from a {} object", 591 toolData.toolName, toolData.toolClassName, e); 592 } 593 } 594 } 595 596 /** 597 * Populate the given context with the perm-scoped tools. 598 * 599 * @param tools The list of tools with which to populate the 600 * session. 601 * @param context The context to populate. 602 * @param data The current RunData or PipelineData object 603 * @param user The <code>User</code> object whose storage to 604 * retrieve the tool from. 605 */ 606 private void populateWithPermTools(List<ToolData> tools, Context context, 607 Object data, User user) 608 { 609 // Iterate the tools 610 for (ToolData toolData : tools) 611 { 612 try 613 { 614 // ensure that tool is created only once for a user 615 // by synchronizing against the user object 616 synchronized (user) 617 { 618 // first try and fetch the tool from the user's 619 // hashtable 620 Object tool = user.getPerm(toolData.toolClassName); 621 622 if (tool == null) 623 { 624 // if not there, an instance must be fetched from 625 // the pool 626 tool = pool.getInstance(toolData.toolClass); 627 628 // session tools are init'd with the User object 629 initTool(tool, user); 630 631 // store the newly created tool in the user's hashtable 632 user.setPerm(toolData.toolClassName, tool); 633 } 634 635 // *NOT* else 636 if (tool != null) 637 { 638 // This is a semantics change. In the old 639 // Turbine, Session tools were initialized and 640 // then refreshed every time they were pulled 641 // into the context if "refreshToolsPerRequest" 642 // was wanted. 643 // 644 // RunDataApplicationTools now have a parameter 645 // for refresh. If it is not refreshed immediately 646 // after init(), the parameter value will be undefined 647 // until the 2nd run. So we refresh all the session 648 // tools on every run, even if we just init'ed it. 649 // 650 651 if (refreshToolsPerRequest) 652 { 653 refreshTool(tool, data); 654 } 655 656 // put the tool in the context 657 log.debug("Adding {} to ctx as {}", tool, toolData.toolName); 658 log.warn("Persistent scope tools are deprecated."); 659 context.put(toolData.toolName, tool); 660 } 661 else 662 { 663 log.info("Tool {} was null, skipping it.", toolData.toolName); 664 } 665 } 666 } 667 catch (Exception e) 668 { 669 log.error("Could not instantiate perm tool {} from a {} object", 670 toolData.toolName, toolData.toolClassName, e); 671 } 672 } 673 } 674 675 676 677 /** 678 * Return the absolute path to the resources directory 679 * used by the application tools. 680 * 681 * @return the absolute path of the resources directory 682 */ 683 @Override 684 public String getAbsolutePathToResourcesDirectory() 685 { 686 return Turbine.getRealPath(resourcesDirectory); 687 } 688 689 /** 690 * Return the resources directory. This is 691 * relative to the web context. 692 * 693 * @return the relative path of the resources directory 694 */ 695 @Override 696 public String getResourcesDirectory() 697 { 698 return resourcesDirectory; 699 } 700 701 /** 702 * Refresh the global tools. We can 703 * only refresh those tools that adhere to 704 * ApplicationTool interface because we 705 * know those types of tools have a refresh 706 * method. 707 */ 708 private void refreshGlobalTools() 709 { 710 if (globalTools != null) 711 { 712 for (ToolData toolData : globalTools) 713 { 714 Object tool = globalContext.get(toolData.toolName); 715 refreshTool(tool, null); 716 } 717 } 718 } 719 720 /** 721 * Release the request-scope tool instances in the 722 * given Context back to the pool 723 * 724 * @param context the Velocity Context to release tools from 725 */ 726 @Override 727 public void releaseTools(Context context) 728 { 729 // only the request tools can be released - other scoped 730 // tools will have continuing references to them 731 releaseTools(context, requestTools); 732 } 733 734 /** 735 * Release the given list of tools from the context back 736 * to the pool 737 * 738 * @param context the Context containing the tools 739 * @param tools a List of ToolData objects 740 */ 741 private void releaseTools(Context context, List<ToolData> tools) 742 { 743 if (tools != null) 744 { 745 for (ToolData toolData : tools) 746 { 747 Object tool = context.remove(toolData.toolName); 748 749 if (tool != null) 750 { 751 pool.putInstance(tool); 752 } 753 } 754 } 755 } 756 757 /** 758 * Initialized a given Tool with the passed init Object 759 * 760 * @param tool A Tool Object 761 * @param param The Init Parameter 762 * 763 * @throws Exception If anything went wrong. 764 */ 765 private void initTool(Object tool, Object param) 766 throws Exception 767 { 768 AnnotationProcessor.process(tool); 769 770 if (param instanceof PipelineData) 771 { 772 if (tool instanceof PipelineDataApplicationTool) 773 { 774 ((PipelineDataApplicationTool) tool).init(param); 775 } 776 else if (tool instanceof RunDataApplicationTool) 777 { 778 RunData data = getRunData((PipelineData)param); 779 ((RunDataApplicationTool) tool).init(data); 780 } 781 else if (tool instanceof ApplicationTool) 782 { 783 RunData data = getRunData((PipelineData)param); 784 ((ApplicationTool) tool).init(data); 785 } 786 } 787 else 788 { 789 if (tool instanceof PipelineDataApplicationTool) 790 { 791 ((PipelineDataApplicationTool) tool).init(param); 792 } 793 else if (tool instanceof RunDataApplicationTool) 794 { 795 ((RunDataApplicationTool) tool).init(param); 796 } 797 else if (tool instanceof ApplicationTool) 798 { 799 ((ApplicationTool) tool).init(param); 800 } 801 } 802 } 803 804 /** 805 * Refresh a given Tool. 806 * 807 * @param tool A Tool Object 808 * @param pipelineData The current RunData Object 809 */ 810 private void refreshTool(Object tool, Object dataObject) 811 { 812 RunData data = null; 813 PipelineData pipelineData = null; 814 if (dataObject instanceof PipelineData) 815 { 816 pipelineData = (PipelineData)dataObject; 817 data = pipelineData.getRunData(); 818 if (tool instanceof PipelineDataApplicationTool) 819 { 820 ((PipelineDataApplicationTool) tool).refresh(pipelineData); 821 } 822 } 823 if (tool instanceof ApplicationTool) 824 { 825 ((ApplicationTool) tool).refresh(); 826 } 827 else if (tool instanceof RunDataApplicationTool) 828 { 829 ((RunDataApplicationTool) tool).refresh(data); 830 } 831 } 832 833 private RunData getRunData(PipelineData pipelineData) 834 { 835 if (!(pipelineData instanceof RunData)) 836 { 837 throw new RuntimeException("Can't cast to rundata from pipeline data."); 838 } 839 return (RunData)pipelineData; 840 } 841}