View Javadoc
1 package org.apache.turbine.services.pull; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache Turbine" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * "Apache Turbine", nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>;. 55 */ 56 57 import java.util.ArrayList; 58 import java.util.Iterator; 59 import java.util.List; 60 import java.util.Properties; 61 import org.apache.turbine.Turbine; 62 import org.apache.turbine.om.security.User; 63 import org.apache.turbine.services.InitializationException; 64 import org.apache.turbine.services.TurbineBaseService; 65 import org.apache.turbine.services.TurbineServices; 66 import org.apache.turbine.services.pool.PoolService; 67 import org.apache.turbine.services.resources.ResourceService; 68 import org.apache.turbine.services.resources.TurbineResources; 69 import org.apache.turbine.util.Log; 70 import org.apache.turbine.util.RunData; 71 import org.apache.velocity.VelocityContext; 72 import org.apache.velocity.context.Context; 73 74 /*** 75 * <p> 76 * This is the concrete implementation of the Turbine 77 * Pull Service. 78 * </p> 79 * <p> 80 * These are tools that are placed in the context by the service 81 * These tools will be made available to all your 82 * templates. You list the tools in the following way: 83 * </p> 84 * <pre> 85 * tool.<scope>.<id> = <classname> 86 * 87 * <scope> is the tool scope: global, request, session 88 * or persistent (see below for more details) 89 * <id> is the name of the tool in the context 90 * 91 * You can configure the tools in this way: 92 * tool.<id>.<parameter> = <value> 93 * 94 * So if you find "global", "request", "session" or "persistent" as second 95 * part, it is a configuration to put a tool into the toolbox, else it is a 96 * tool specific configuration. 97 * 98 * For example: 99 * 100 * tool.global.ui = org.apache.turbine.util.pull.UIManager 101 * tool.global.mm = org.apache.turbine.util.pull.MessageManager 102 * tool.request.link = org.apache.turbine.util.template.TemplateLink 103 * tool.request.page = org.apache.turbine.util.template.TemplatePageAttributes 104 * 105 * Then: 106 * 107 * tool.ui.skin = default 108 * 109 * configures the value of "skin" for the "ui" tool. 110 * 111 * Tools are accessible in all templates by the <id> given 112 * to the tool. So for the above listings the UIManager would 113 * be available as $ui, the MessageManager as $mm, the TemplateLink 114 * as $link and the TemplatePageAttributes as $page. 115 * 116 * You should avoid using tool names called "global", "request", 117 * "session" or "persistent" because of clashes with the possible Scopes. 118 * 119 * Scopes: 120 * 121 * global: tool is instantiated once and that instance is available 122 * to all templates for all requests. Tool must be threadsafe. 123 * 124 * request: tool is instantiated once for each request (although the 125 * PoolService is used to recycle instances). Tool need not 126 * be threadsafe. 127 * 128 * session: tool is instantiated once for each user session, and is 129 * stored in the user's temporary hashtable. Tool should be 130 * threadsafe. 131 * 132 * persistent: tool is instantitated once for each use session, and 133 * is stored in the user's permanent hashtable. This means 134 * for a logged in user the tool will be persisted in the 135 * user's objectdata. Tool should be threadsafe and 136 * Serializable. 137 * 138 * Defaults: none 139 * </pre> 140 * 141 * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a> 142 * @author <a href="mailto:sean@informage.net">Sean Legassick</a> 143 * @version $Id: TurbinePullService.java,v 1.5 2002/07/11 16:53:25 mpoeschl Exp $ 144 */ 145 public class TurbinePullService extends TurbineBaseService 146 implements PullService 147 { 148 /*** 149 * This is the container for the global web application 150 * tools that are used in conjunction with the 151 * Turbine Pull Model. All the global tools will be placed 152 * in this Context and be made accessible inside 153 * templates via the tool name specified in the TR.props 154 * file. 155 */ 156 private Context globalContext; 157 158 /*** 159 * This inner class is used in the lists below to store the 160 * tool name and class for each of request, session and persistent 161 * tools 162 */ 163 private static class ToolData 164 { 165 String toolName; 166 String toolClassName; 167 Class toolClass; 168 169 public ToolData(String toolName, String toolClassName, Class toolClass) 170 { 171 this.toolName = toolName; 172 this.toolClassName = toolClassName; 173 this.toolClass = toolClass; 174 } 175 } 176 177 /*** 178 * The lists that store tool data (name and class) for each 179 * of the different type of tool. The Lists contain ToolData 180 * objects. 181 */ 182 private List globalTools; 183 private List requestTools; 184 private List sessionTools; 185 private List persistentTools; 186 187 /*** 188 * The property tags that are used in conjunction with 189 * TurbineResources.getOrderedValues(String) to get 190 * our list of tools to instantiate (one tag for each 191 * type of tool). 192 */ 193 private static final String GLOBAL_TOOL = "tool.global"; 194 private static final String REQUEST_TOOL = "tool.request"; 195 private static final String SESSION_TOOL = "tool.session"; 196 private static final String PERSISTENT_TOOL = "tool.persistent"; 197 198 /*** 199 * Directory where application tool resources are stored. 200 */ 201 private static String resourcesDirectory; 202 203 /*** 204 * The absolute path the to resources directory used 205 * by the application tools. 206 */ 207 private static String absolutePathToResourcesDirectory; 208 209 /*** 210 * Property tag for application tool resources directory 211 */ 212 private static final String TOOL_RESOURCES_DIR 213 = "tools.resources.dir"; 214 215 /*** 216 * Default value for the application tool resources 217 * directory. The location for the resources directory 218 * is typically WEBAPP/resources. 219 */ 220 private static final String TOOL_RESOURCES_DIR_DEFAULT 221 = "/resources"; 222 223 /*** 224 * Property tag for per request tool refreshing 225 * (for obvious reasons has no effect for per-request tools) 226 */ 227 private static final String TOOLS_PER_REQUEST_REFRESH = 228 "tools.per.request.refresh"; 229 230 /*** 231 * Should we refresh the application tools on 232 * a per request basis. 233 */ 234 private static boolean refreshToolsPerRequest; 235 236 /*** 237 * Called the first time the Service is used. 238 */ 239 public void init() throws InitializationException 240 { 241 try 242 { 243 /* 244 * Make sure to setInit(true) *inside* initPull() 245 * because Tools may make calls back to the TurbinePull 246 * static methods which may cause a recursive init 247 * thing to happen. 248 */ 249 initPull(); 250 } 251 catch (Exception e) 252 { 253 throw new InitializationException( 254 "TurbinePullService failed to initialize", e); 255 } 256 } 257 258 /*** 259 * Initialize the pull system 260 * 261 * @exception Exception, a generic exception. 262 */ 263 private void initPull() throws Exception 264 { 265 Properties props = getProperties(); 266 267 /* 268 * Get the resources directory that is specificed 269 * in the TR.props or default to "/resources". 270 */ 271 resourcesDirectory = TurbineResources.getString( 272 TOOL_RESOURCES_DIR, 273 TOOL_RESOURCES_DIR_DEFAULT); 274 275 /* 276 * Get absolute path to the resources directory. 277 * 278 * This should be done before the tools initialized 279 * because a tool might need to know this value 280 * for it to initialize correctly. 281 */ 282 absolutePathToResourcesDirectory = 283 Turbine.getRealPath(resourcesDirectory); 284 285 /* 286 * Should we refresh the tool box on a per 287 * request basis. 288 */ 289 refreshToolsPerRequest = 290 new Boolean(properties.getProperty( 291 TOOLS_PER_REQUEST_REFRESH)).booleanValue(); 292 293 /* 294 * Log the fact that the application tool box will 295 * be refreshed on a per request basis. 296 */ 297 if (refreshToolsPerRequest) 298 Log.info("Pull Model tools will " 299 + "be refreshed on a per request basis."); 300 301 /* 302 * Make sure to set init true because Tools may make 303 * calls back to the TurbinePull static methods which 304 * may cause a recursive init thing to happen. 305 */ 306 setInit(true); 307 308 /* 309 * Grab each list of tools that are to be used (for global scope, 310 * request scope, session scope and persistent scope tools). 311 * They are specified respectively in the TR.props like this: 312 * 313 * tool.global.ui = org.apache.turbine.util.pull.UIManager 314 * tool.global.mm = org.apache.turbine.util.pull.MessageManager 315 * 316 * tool.request.link = org.apache.turbine.util.template.TemplateLink; 317 * 318 * tool.session.basket = org.sample.util.ShoppingBasket; 319 * 320 * tool.persistent.ui = org.apache.turbine.services.pull.util.PersistentUIManager 321 */ 322 globalTools = getTools(GLOBAL_TOOL); 323 requestTools = getTools(REQUEST_TOOL); 324 sessionTools = getTools(SESSION_TOOL); 325 persistentTools = getTools(PERSISTENT_TOOL); 326 327 /* 328 * Create and populate the global context right now 329 */ 330 globalContext = new VelocityContext(); 331 populateWithGlobalTools(globalContext); 332 } 333 334 /*** 335 * Retrieve the tool names and classes for the tools definied 336 * in the properties file with the prefix given. 337 * 338 * @param keyPrefix a String giving the property name prefix to look for 339 */ 340 private List getTools(String keyPrefix) 341 { 342 List classes = new ArrayList(); 343 344 ResourceService toolResources = 345 TurbineResources.getResources(keyPrefix); 346 347 /* 348 * There might not be any tools for this prefix 349 * so return an empty list. 350 */ 351 if (toolResources == null) 352 { 353 return classes; 354 } 355 356 Iterator it = toolResources.getKeys(); 357 while (it.hasNext()) 358 { 359 String toolName = (String) it.next(); 360 String toolClassName = toolResources.getString(toolName); 361 362 try 363 { 364 /* 365 * Create an instance of the tool class. 366 */ 367 Class toolClass = Class.forName(toolClassName); 368 369 /* 370 * Add the tool to the list being built. 371 */ 372 classes.add(new ToolData(toolName, toolClassName, toolClass)); 373 374 Log.info("Instantiated tool class " + toolClassName 375 + " to add to the context as '$" + toolName + "'"); 376 } 377 catch (Exception e) 378 { 379 Log.error("Cannot find tool class " + toolClassName 380 + ", please check the name of the class."); 381 } 382 } 383 384 return classes; 385 } 386 387 /*** 388 * Return the Context which contains all global tools that 389 * are to be used in conjunction with the Turbine 390 * Pull Model. 391 */ 392 public Context getGlobalContext() 393 { 394 return globalContext; 395 } 396 397 /*** 398 * Populate the given context with all request, session 399 * and persistent scope tools (it is assumed that the context 400 * already wraps the global context, and thus already contains 401 * the global tools). 402 * 403 * @param context a Velocity Context to populate 404 * @param data a RunData object for request specific data 405 */ 406 public void populateContext(Context context, RunData data) 407 { 408 populateWithRequestTools(context, data); 409 410 // session tools (whether session-only or persistent are 411 // very similar, so the same method is used - the 412 // boolean parameter indicates whether get/setPerm is to be used 413 // rather than get/setTemp) 414 User user = data.getUser(); 415 if (user != null) 416 { 417 populateWithSessionTools(sessionTools, context, user, false); 418 419 if (user.hasLoggedIn()) 420 { 421 populateWithSessionTools(persistentTools, context, user, true); 422 } 423 } 424 } 425 426 /*** 427 * Populate the given context with the global tools 428 * 429 * @param context a Velocity Context to populate 430 */ 431 private void populateWithGlobalTools(Context context) 432 { 433 Iterator it = globalTools.iterator(); 434 while (it.hasNext()) 435 { 436 ToolData toolData = (ToolData)it.next(); 437 try 438 { 439 Object tool = toolData.toolClass.newInstance(); 440 if (tool instanceof ApplicationTool) 441 { 442 // global tools are init'd with a null data parameter 443 ((ApplicationTool)tool).init(null); 444 } 445 // put the tool in the context 446 context.put(toolData.toolName, tool); 447 } 448 catch (Exception e) 449 { 450 Log.error( 451 "Could not instantiate tool " + toolData.toolClassName 452 + " to add to the context"); 453 } 454 } 455 } 456 457 /*** 458 * Populate the given context with the request-scope tools 459 * 460 * @param context a Velocity Context to populate 461 * @param data a RunData instance 462 */ 463 private void populateWithRequestTools(Context context, RunData data) 464 { 465 // Get the PoolService to fetch object instances from 466 PoolService pool = (PoolService) 467 TurbineServices.getInstance().getService(PoolService.SERVICE_NAME); 468 469 // Iterate the tools 470 Iterator it = requestTools.iterator(); 471 while (it.hasNext()) 472 { 473 ToolData toolData = (ToolData)it.next(); 474 try 475 { 476 Object tool = pool.getInstance(toolData.toolClass); 477 if (tool instanceof ApplicationTool) 478 { 479 // request tools are init'd with a RunData object 480 ((ApplicationTool)tool).init(data); 481 } 482 // put the tool in the context 483 context.put(toolData.toolName, tool); 484 } 485 catch (Exception e) 486 { 487 Log.error( 488 "Could not instantiate tool " + toolData.toolClassName 489 + " to add to the context",e); 490 } 491 } 492 } 493 494 /*** 495 * Populate the given context with the session-scoped tools. 496 * 497 * @param tools The list of tools with which to populate the 498 * session. 499 * @param context The context to populate. 500 * @param user The <code>User</code> object whose storage to 501 * retrieve the tool from. 502 * @param userPerm Whether to retrieve the tools from the 503 * permanent storage (as opposed to the temporary storage). 504 */ 505 private void populateWithSessionTools(List tools, Context context, 506 User user, boolean usePerm) 507 { 508 // Get the PoolService to fetch object instances from 509 PoolService pool = (PoolService) 510 TurbineServices.getInstance().getService(PoolService.SERVICE_NAME); 511 512 // Iterate the tools 513 Iterator it = tools.iterator(); 514 while (it.hasNext()) 515 { 516 ToolData toolData = (ToolData)it.next(); 517 try 518 { 519 // ensure that tool is created only once for a user 520 // by synchronizing against the user object 521 synchronized (user) 522 { 523 // first try and fetch the tool from the user's 524 // hashtable 525 Object tool = usePerm 526 ? user.getPerm(toolData.toolClassName) 527 : user.getTemp(toolData.toolClassName); 528 529 if (tool == null) 530 { 531 // if not there, an instance must be fetched from 532 // the pool 533 tool = pool.getInstance(toolData.toolClass); 534 if (tool instanceof ApplicationTool) 535 { 536 // session tools are init'd with the User object 537 ((ApplicationTool)tool).init(user); 538 } 539 // store the newly created tool in the user's hashtable 540 if (usePerm) 541 { 542 user.setPerm(toolData.toolClassName, tool); 543 } 544 else 545 { 546 user.setTemp(toolData.toolClassName, tool); 547 } 548 } 549 else if (refreshToolsPerRequest 550 && tool instanceof ApplicationTool) 551 { 552 ((ApplicationTool)tool).refresh(); 553 } 554 // put the tool in the context 555 context.put(toolData.toolName, tool); 556 } 557 } 558 catch (Exception e) 559 { 560 Log.error( 561 "Could not instantiate tool " + toolData.toolClassName 562 + " to add to the context"); 563 } 564 } 565 } 566 567 /*** 568 * Return the absolute path to the resources directory 569 * used by the application tools. 570 */ 571 public String getAbsolutePathToResourcesDirectory() 572 { 573 return absolutePathToResourcesDirectory; 574 } 575 576 /*** 577 * Return the resources directory. This is 578 * relative to the web context. 579 */ 580 public String getResourcesDirectory() 581 { 582 return resourcesDirectory; 583 } 584 585 /*** 586 * Refresh the global tools. We can 587 * only refresh those tools that adhere to 588 * ApplicationTool interface because we 589 * know those types of tools have a refresh 590 * method. 591 */ 592 public void refreshGlobalTools() 593 { 594 Iterator i = globalTools.iterator(); 595 while (i.hasNext()) 596 { 597 ToolData toolData = (ToolData)i.next(); 598 Object tool = globalContext.get(toolData.toolName); 599 if (tool instanceof ApplicationTool) 600 ((ApplicationTool)tool).refresh(); 601 } 602 } 603 604 /*** 605 * Should we refresh the ToolBox on 606 * a per request basis. 607 */ 608 public boolean refreshToolsPerRequest() 609 { 610 return refreshToolsPerRequest; 611 } 612 613 /*** 614 * Release the request-scope tool instances in the 615 * given Context back to the pool 616 * 617 * @param context the Velocity Context to release tools from 618 */ 619 public void releaseTools(Context context) 620 { 621 // Get the PoolService to release object instances to 622 PoolService pool = (PoolService) 623 TurbineServices.getInstance().getService(PoolService.SERVICE_NAME); 624 625 // only the request tools can be released - other scoped 626 // tools will have continuing references to them 627 releaseTools(context, pool, requestTools); 628 } 629 630 /*** 631 * Release the given list of tools from the context back 632 * to the pool 633 * 634 * @param context the Context containing the tools 635 * @param pool an instance of the PoolService 636 * @param tools a List of ToolData objects 637 */ 638 private void releaseTools(Context context, PoolService pool, List tools) 639 { 640 Iterator it = tools.iterator(); 641 while (it.hasNext()) 642 { 643 ToolData toolData = (ToolData)it.next(); 644 Object tool = context.remove(toolData.toolName); 645 646 if (tool != null) 647 { 648 pool.putInstance(tool); 649 } 650 } 651 } 652 }

This page was automatically generated by Maven