1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package jakarta.faces.application; 20 21 import jakarta.faces.component.behavior.Behavior; 22 import jakarta.faces.component.search.SearchExpressionHandler; 23 import jakarta.faces.component.search.SearchKeywordResolver; 24 import jakarta.faces.event.ActionListener; 25 import jakarta.faces.event.SystemEvent; 26 import jakarta.faces.event.SystemEventListener; 27 import jakarta.faces.validator.Validator; 28 29 import java.util.Collection; 30 import java.util.Collections; 31 import java.util.Iterator; 32 import java.util.Locale; 33 import java.util.Map; 34 import java.util.ResourceBundle; 35 36 import jakarta.el.ELContextListener; 37 import jakarta.el.ELException; 38 import jakarta.el.ELResolver; 39 import jakarta.el.ExpressionFactory; 40 import jakarta.el.ValueExpression; 41 import jakarta.faces.FacesException; 42 import jakarta.faces.component.UIComponent; 43 import jakarta.faces.context.ExternalContext; 44 import jakarta.faces.context.FacesContext; 45 import jakarta.faces.convert.Converter; 46 import jakarta.faces.el.MethodBinding; 47 import jakarta.faces.el.PropertyResolver; 48 import jakarta.faces.el.ReferenceSyntaxException; 49 import jakarta.faces.el.ValueBinding; 50 import jakarta.faces.el.VariableResolver; 51 import jakarta.faces.flow.FlowHandler; 52 53 /** 54 * <p> 55 * Application represents a per-web-application singleton object where applications based on JavaServer Faces (or 56 * implementations wishing to provide extended functionality) can register application-wide singletons that provide 57 * functionality required by JavaServer Faces. Default implementations of each object are provided for cases where the 58 * application does not choose to customize the behavior. 59 * </p> 60 * 61 * <p> 62 * The instance of {@link Application} is created by calling the <code>getApplication()</code> method of 63 * {@link ApplicationFactory}. Because this instance is shared, it must be implemented in a thread-safe manner. 64 * </p> 65 * 66 * Holds webapp-wide resources for a JSF application. There is a single one of these for a web application, accessable 67 * via 68 * 69 * <pre> 70 * FacesContext.getCurrentInstance().getApplication() 71 * </pre> 72 * 73 * In particular, this provides a factory for UIComponent objects. It also provides convenience methods for creating 74 * ValueBinding objects. 75 * 76 * See Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a> 77 */ 78 @SuppressWarnings("deprecation") 79 public abstract class Application 80 { 81 82 /** 83 * Retrieve the current Myfaces Application Instance, lookup 84 * on the application map. All methods introduced on jsf 1.2 85 * for Application interface should thrown by default 86 * UnsupportedOperationException, but the ri scan and find the 87 * original Application impl, and redirect the call to that 88 * method instead throwing it, allowing application implementations 89 * created before jsf 1.2 continue working. 90 * 91 * Note: every method, which uses getMyfacesApplicationInstance() to 92 * delegate itself to the current ApplicationImpl MUST be 93 * overriden by the current ApplicationImpl to prevent infinite loops. 94 */ 95 private Application getMyfacesApplicationInstance() 96 { 97 FacesContext facesContext = FacesContext.getCurrentInstance(); 98 if (facesContext != null) 99 { 100 ExternalContext externalContext = facesContext.getExternalContext(); 101 if (externalContext != null) 102 { 103 return (Application) externalContext.getApplicationMap().get( 104 "org.apache.myfaces.application.ApplicationImpl"); 105 } 106 } 107 return null; 108 } 109 110 private Application getMyfacesApplicationInstance(FacesContext facesContext) 111 { 112 if (facesContext != null) 113 { 114 ExternalContext externalContext = facesContext.getExternalContext(); 115 if (externalContext != null) 116 { 117 return (Application) externalContext.getApplicationMap().get( 118 "org.apache.myfaces.application.ApplicationImpl"); 119 } 120 } 121 return null; 122 } 123 124 // The concrete methods throwing UnsupportedOperationExceptiom were added for JSF 1.2. 125 // They supply default to allows old Application implementations to still work. 126 127 /** 128 * @since 2.0 129 * 130 * FIXME: Notify EG, this should not be abstract and throw UnsupportedOperationException 131 * 132 * @param behaviorId 133 * @param behaviorClass 134 */ 135 public void addBehavior(String behaviorId, String behaviorClass) 136 { 137 Application application = getMyfacesApplicationInstance(); 138 if (application != null) 139 { 140 application.addBehavior(behaviorId, behaviorClass); 141 return; 142 } 143 throw new UnsupportedOperationException(); 144 } 145 146 /** 147 * Define a new mapping from a logical "component type" to an actual java class name. This controls what type is 148 * created when method createComponent of this class is called. 149 * <p> 150 * Param componentClass must be the fully-qualified class name of some class extending the UIComponent class. The 151 * class must have a default constructor, as instances of it will be created using Class.newInstance. 152 * <p> 153 * It is permitted to override a previously defined mapping, ie to call this method multiple times with the same 154 * componentType string. The createComponent method will simply use the last defined mapping. 155 */ 156 /** 157 * Register a new mapping of component type to the name of the corresponding {@link UIComponent} class. This allows 158 * subsequent calls to <code>createComponent()</code> to serve as a factory for {@link UIComponent} instances. 159 * 160 * @param componentType 161 * - The component type to be registered 162 * @param componentClass 163 * - The fully qualified class name of the corresponding {@link UIComponent} implementation 164 * 165 * @throws NullPointerException 166 * if <code>componentType</code> or <code>componentClass</code> is <code>null</code> 167 */ 168 public abstract void addComponent(String componentType, String componentClass); 169 170 /** 171 * Register a new converter class that is capable of performing conversions for the specified target class. 172 * 173 * @param targetClass 174 * - The class for which this converter is registered 175 * @param converterClass 176 * - The fully qualified class name of the corresponding {@link Converter} implementation 177 * 178 * @throws NullPointerException 179 * if <code>targetClass</code> or <code>converterClass</code> is <code>null</code> 180 */ 181 public abstract void addConverter(Class<?> targetClass, String converterClass); 182 183 /** 184 * Register a new mapping of converter id to the name of the corresponding {@link Converter} class. This allows 185 * subsequent calls to createConverter() to serve as a factory for {@link Converter} instances. 186 * 187 * @param converterId 188 * - The converterId to be registered 189 * @param converterClass 190 * - The fully qualified class name of the corresponding {@link Converter} implementation 191 * 192 * @throws NullPointerException 193 * if <code>componentType</code> or <code>componentClass</code> is <code>null</code> 194 */ 195 public abstract void addConverter(String converterId, String converterClass); 196 197 /** 198 * 199 * @since 2.0 200 * @param validatorId 201 */ 202 public void addDefaultValidatorId(String validatorId) 203 { 204 } 205 206 /** 207 * <p> 208 * Provide a way for Faces applications to register an <code>ELContextListener</code> that will be notified on 209 * creation of <code>ELContext</code> instances. 210 * <p> 211 * 212 * <p> 213 * An implementation is provided that throws <code>UnsupportedOperationException</code> so that users that decorate 214 * the <code>Application</code> continue to work. 215 * </p> 216 * 217 * @since 1.2 218 */ 219 public void addELContextListener(ELContextListener listener) 220 { 221 Application application = getMyfacesApplicationInstance(); 222 if (application != null) 223 { 224 application.addELContextListener(listener); 225 return; 226 } 227 throw new UnsupportedOperationException(); 228 } 229 230 /** 231 * <p> 232 * Cause an the argument <code>resolver</code> to be added to the resolver chain as specified in section 5.5.1 of 233 * the JavaServer Faces Specification. 234 * </p> 235 * 236 * <p> 237 * It is not possible to remove an <code>ELResolver</code> registered with this method, once it has been registered. 238 * </p> 239 * 240 * <p> 241 * It is illegal to register an ELResolver after the application has received any requests from the client. If an 242 * attempt is made to register a listener after that time, an IllegalStateException must be thrown. This restriction 243 * is in place to allow the JSP container to optimize for the common case where no additional 244 * <code>ELResolvers</code> are in the chain, aside from the standard ones. It is permissible to add 245 * <code>ELResolvers</code> before or after initialization to a CompositeELResolver that is already in the chain. 246 * <p> 247 * 248 * <p> 249 * The default implementation throws <code>UnsupportedOperationException</code> and is provided for the sole purpose 250 * of not breaking existing applications that extend {@link Application}. 251 * </p> 252 * 253 * @since 1.2 254 */ 255 public void addELResolver(ELResolver resolver) 256 { 257 // The following concrete methods were added for JSF 1.2. They supply default 258 // implementations that throw UnsupportedOperationException. 259 // This allows old Application implementations to still work. 260 Application application = getMyfacesApplicationInstance(); 261 if (application != null) 262 { 263 application.addELResolver(resolver); 264 return; 265 } 266 throw new UnsupportedOperationException(); 267 } 268 269 /** 270 *Register a new mapping of validator id to the name of the corresponding <code>Validator</code> class. This allows 271 * subsequent calls to <code>createValidator()</code> to serve as a factory for <code>Validator</code> instances. 272 * 273 *@param validatorId The validator id to be registered 274 *@param validatorClass The fully qualified class name of the corresponding Validator implementation 275 * 276 *@throws NullPointerException 277 * if <code>validatorId</code> or <code>validatorClass</code> is <code>null</code> 278 */ 279 public abstract void addValidator(String validatorId, String validatorClass); 280 281 /** 282 * 283 * @param behaviorId 284 * @return 285 * @throws FacesException 286 * @since 2.0 287 * 288 * FIXME: Notify EG, this should not be abstract and throw UnsupportedOperationException 289 */ 290 public Behavior createBehavior(String behaviorId) throws FacesException 291 { 292 Application application = getMyfacesApplicationInstance(); 293 if (application != null) 294 { 295 return application.createBehavior(behaviorId); 296 } 297 throw new UnsupportedOperationException(); 298 } 299 300 /** 301 * ??? 302 * 303 * @param context 304 * @param componentResource 305 * @return 306 * 307 * @since 2.0 308 */ 309 public UIComponent createComponent(FacesContext context, Resource componentResource) 310 { 311 Application application = getMyfacesApplicationInstance(context); 312 if (application != null) 313 { 314 return application.createComponent(context, componentResource); 315 } 316 throw new UnsupportedOperationException(); 317 } 318 319 /** 320 * 321 * @param context 322 * @param componentType 323 * @param rendererType 324 * @return 325 * 326 * @since 2.0 327 */ 328 public UIComponent createComponent(FacesContext context, String componentType, String rendererType) 329 { 330 Application application = getMyfacesApplicationInstance(context); 331 if (application != null) 332 { 333 return application.createComponent(context, componentType, rendererType); 334 } 335 throw new UnsupportedOperationException(); 336 } 337 338 /** 339 * <p> 340 * Create a new UIComponent subclass, using the mappings defined by previous calls to the addComponent method of 341 * this class. 342 * </p> 343 * 344 * @throws FacesException 345 * if there is no mapping defined for the specified componentType, or if an instance of the specified 346 * type could not be created for any reason. 347 */ 348 public abstract UIComponent createComponent(String componentType) throws FacesException; 349 350 /** 351 * <p> 352 * Create an object which has an associating "binding" expression tying the component to a user property. 353 * </p> 354 * 355 * <p> 356 * First the specified value-binding is evaluated; if it returns a non-null value then the component 357 * "already exists" and so the resulting value is simply returned. 358 * </p> 359 * 360 * <p> 361 * Otherwise a new UIComponent instance is created using the specified componentType, and the new object stored via 362 * the provided value-binding before being returned. 363 * </p> 364 * 365 * @deprecated 366 */ 367 public abstract UIComponent createComponent(ValueBinding componentBinding, FacesContext context, 368 String componentType) throws FacesException; 369 370 /** 371 * <p> 372 * Call the <code>getValue()</code> method on the specified <code>ValueExpression</code>. If it returns a 373 * <code>{@link UIComponent}</code> instance, return it as the value of this method. If it does not, instantiate a 374 * new <code>{@link UIComponent}</code> instance of the specified component type, pass the new component to the 375 * <code>setValue()</code> method of the specified <code>ValueExpression</code>, and return it. 376 * </p> 377 * 378 * @param componentExpression 379 * - <code>ValueExpression</code> representing a component value expression (typically specified by the 380 * <code>component</code> attribute of a custom tag) 381 * @param context 382 * - {@link FacesContext} for the current request 383 * @param componentType 384 * - Component type to create if the ValueExpression does not return a component instance 385 * 386 * @throws FacesException 387 * if a <code>{@link UIComponent}</code> cannot be created 388 * @throws NullPointerException 389 * if any parameter is null 390 * <p> 391 * A default implementation is provided that throws <code>UnsupportedOperationException</code> so that 392 * users that decorate <code>Application</code> can continue to function 393 * </p> 394 * 395 * @since 1.2 396 */ 397 public UIComponent createComponent(ValueExpression componentExpression, FacesContext context, String componentType) 398 throws FacesException 399 { 400 Application application = getMyfacesApplicationInstance(context); 401 if (application != null) 402 { 403 return application.createComponent(componentExpression, context, componentType); 404 } 405 throw new UnsupportedOperationException(); 406 } 407 408 /** 409 * 410 * @param componentExpression 411 * @param context 412 * @param componentType 413 * @param rendererType 414 * @return 415 * 416 * @since 2.0 417 */ 418 public UIComponent createComponent(ValueExpression componentExpression, FacesContext context, String componentType, 419 String rendererType) 420 { 421 Application application = getMyfacesApplicationInstance(context); 422 if (application != null) 423 { 424 return application.createComponent(componentExpression, context, componentType, rendererType); 425 } 426 throw new UnsupportedOperationException(); 427 } 428 429 /** 430 * <p> 431 * Instantiate and return a new <code>{@link Converter}</code> instance of the class that has registered itself as 432 * capable of performing conversions for objects of the specified type. If no such <code>{@link Converter}</code> 433 * class can be identified, return null. 434 * </p> 435 * 436 * <p> 437 * To locate an appropriate <code>{@link Converter}</code> class, the following algorithm is performed, stopping as 438 * soon as an appropriate <code>{@link Converter}</code> class is found: Locate a <code>{@link Converter}</code> 439 * registered for the target class itself. Locate a <code>{@link Converter}</code> registered for interfaces that 440 * are implemented by the target class (directly or indirectly). Locate a <code>{@link Converter}</code> registered 441 * for the superclass (if any) of the target class, recursively working up the inheritance hierarchy. 442 * </p> 443 * 444 * <p> 445 * If the <code>{@link Converter}</code> has a single argument constructor that accepts a Class, instantiate the 446 * <code>{@link Converter}</code> using that constructor, passing the argument <code>targetClass</code> as 447 * the sole argument. Otherwise, simply use the zero-argument constructor. 448 * 449 * @param targetClass 450 * - Target class for which to return a <code>{@link Converter}</code> 451 * 452 * @throws FacesException 453 * if the <code>{@link Converter}</code> cannot be created 454 * @throws NullPointerException 455 * if <code>targetClass</code> is <code>null</code> 456 * 457 */ 458 public abstract Converter createConverter(Class<?> targetClass); 459 460 /** 461 * Instantiate and return a new <code>{@link Converter}</code> instance of the class specified by a previous call to 462 * <code>addConverter()</code> for the specified converter id. If there is no such registration for this converter 463 * id, return <code>null</code>. 464 * 465 * @param converterId 466 * - The converter id for which to create and return a new <code>{@link Converter}</code> instance 467 * 468 * @throws FacesException 469 * if the <code>{@link Converter}</code> cannot be created 470 * @throws NullPointerException 471 * if converterId is <code>null</code> 472 */ 473 public abstract Converter createConverter(String converterId); 474 475 /** 476 * Create an object which can be used to invoke an arbitrary method via an EL expression at a later time. This is 477 * similar to createValueBinding except that it can invoke an arbitrary method (with parameters) rather than just 478 * get/set a javabean property. 479 * <p> 480 * This is used to invoke ActionListener method, and ValueChangeListener methods. 481 * 482 * @deprecated 483 */ 484 public abstract MethodBinding createMethodBinding(String ref, Class<?>[] params) throws ReferenceSyntaxException; 485 486 /** 487 * Instantiate and return a new <code>{@link Validator}</code> instance of the class specified by a previous call to 488 * <code>addValidator()</code> for the specified validator id. 489 * 490 * @param validatorId The <code>{@link Validator}</code> id for which to create and return a new 491 * Validator instance 492 * 493 * @throws FacesException 494 * if a <code>{@link Validator}</code> of the specified id cannot be created 495 * @throws NullPointerException 496 * if validatorId is <code>null</code> 497 */ 498 public abstract Validator createValidator(String validatorId) throws FacesException; 499 500 /** 501 * <p> 502 * Create an object which can be used to invoke an arbitrary method via an EL expression at a later time. This is 503 * similar to createValueBinding except that it can invoke an arbitrary method (with parameters) rather than just 504 * get/set a javabean property. 505 * </p> 506 * This is used to invoke ActionListener method, and ValueChangeListener methods. 507 * 508 * @deprecated 509 */ 510 public abstract ValueBinding createValueBinding(String ref) throws ReferenceSyntaxException; 511 512 /** 513 * <p> 514 * Get a value by evaluating an expression. 515 * </p> 516 * 517 * <p> 518 * Call <code>{@link #getExpressionFactory()}</code> then call 519 * <code>ExpressionFactory.createValueExpression(jakarta.el.ELContext, java.lang.String, java.lang.Class)</code> 520 * passing the argument <code>expression</code> and <code>expectedType</code>. Call 521 * <code>{@link FacesContext#getELContext()}</code> and pass it to 522 * <code>ValueExpression.getValue(jakarta.el.ELContext)</code>, returning the result. 523 * </p> 524 * 525 * <p> 526 * An implementation is provided that throws <code>UnsupportedOperationException</code> so that users that decorate 527 * the <code>Application</code> continue to work. 528 * <p> 529 * 530 * @throws jakarta.el.ELException 531 */ 532 public <T> T evaluateExpressionGet(FacesContext context, String expression, Class<? extends T> expectedType) 533 throws ELException 534 { 535 Application application = getMyfacesApplicationInstance(context); 536 if (application != null) 537 { 538 return application.evaluateExpressionGet(context, expression, expectedType); 539 } 540 throw new UnsupportedOperationException(); 541 } 542 543 /** 544 * <p> 545 * Return the default <code>ActionListener</code> to be registered for all <code>ActionSource</code> components 546 * in this appication. If not explicitly set, a default implementation must be provided that performs the 547 * following functions: 548 * </p> 549 * <ul> 550 * <li>The <code>processAction()</code> method must first call <code>FacesContext.renderResponse()</code>in order to 551 * bypass any intervening lifecycle phases, once the method returns.</li> 552 * 553 * <li>The <code>processAction()</code> method must next determine the logical 554 * outcome of this event, as follows:</li> 555 * 556 * <li>If the originating component has a non-<code>null action</code> property, retrieve the <code> 557 * MethodBinding</code> from the property, and call <code>invoke()</code> 558 * on it. Convert the returned value (if any) to a String, and use it as the logical outcome.</li> 559 * <li>Otherwise, the logical outcome is null.</li> 560 * <li>The <code>processAction()</code> method must finally retrieve the <code>NavigationHandler</code> instance 561 * for this application and call 562 * code>NavigationHandler.handleNavigation(jakarta.faces.context.FacesContext, 563 * java.lang.String, java.lang.String)</code> passing:</li> 564 * <li>the {@link FacesContext} for the current request</li> 565 * <li>If there is a <code>MethodBinding</code> instance for the <code>action</code> property of this component, the 566 * result of calling {@link MethodBinding#getExpressionString()} on it, null otherwise</li> 567 * <li>the logical outcome as determined above</li> 568 * </ul> 569 * <p> 570 * Note that the specification for the default <code>ActionListener</code> contiues to call for the use of a 571 * deprecated property (<code>action</code>) and class (<code>MethodBinding</code>). Unfortunately, this is 572 * necessary because the default ActionListener must continue to work with components that do not implement 573 * {@link jakarta.faces.component.ActionSource2}, and only implement {@link jakarta.faces.component.ActionSource}. 574 */ 575 public abstract ActionListener getActionListener(); 576 577 /** 578 * 579 * @return 580 * 581 * @since 2.0 582 * 583 * FIXME: Notify EG, this should not be abstract and throw UnsupportedOperationException 584 */ 585 public Iterator<String> getBehaviorIds() 586 { 587 Application application = getMyfacesApplicationInstance(); 588 if (application != null) 589 { 590 return application.getBehaviorIds(); 591 } 592 // It is better to return an empty iterator, 593 // to keep compatiblity with previous jsf 2.0 Application 594 // instances 595 return Collections.EMPTY_LIST.iterator(); 596 } 597 598 /** 599 * Return an <code>Iterator</code> over the set of currently defined component types for this 600 * <code>Application</code>. 601 */ 602 public abstract Iterator<String> getComponentTypes(); 603 604 /** 605 * Return an <code>Iterator</code> over the set of currently registered converter ids for this 606 * <code>Application</code> 607 * 608 * @return 609 */ 610 public abstract Iterator<String> getConverterIds(); 611 612 /** 613 *Return an <code>Iterator</code> over the set of <code>Class</code> instances for which <code>{@link Converter} 614 * </code> <code>classes</code>have been explicitly registered. 615 * 616 * @return 617 */ 618 public abstract Iterator<Class<?>> getConverterTypes(); 619 620 /** 621 *Return the default <code>Locale</code> for this application. If not explicitly set, <code>null</code> is 622 * returned. 623 * 624 * @return 625 */ 626 public abstract Locale getDefaultLocale(); 627 628 /** 629 * Return the <code>renderKitId</code> to be used for rendering this application. If not explicitly set, 630 * <code>null</code> is returned. 631 * 632 * @return 633 */ 634 public abstract String getDefaultRenderKitId(); 635 636 /** 637 * 638 * @return 639 * 640 * @since 2.0 641 */ 642 public Map<String, String> getDefaultValidatorInfo() 643 { 644 Application application = getMyfacesApplicationInstance(); 645 if (application != null) 646 { 647 return application.getDefaultValidatorInfo(); 648 } 649 throw new UnsupportedOperationException(); 650 } 651 652 /** 653 * <p> 654 * If no calls have been made to <code>addELContextListener(jakarta.el.ELContextListener)</code>, this method must 655 * return an empty array 656 * <p> 657 * . 658 * 659 * <p> 660 * Otherwise, return an array representing the list of listeners added by calls to 661 * <code>addELContextListener(jakarta.el.ELContextListener)</code>. 662 * <p> 663 * 664 * <p> 665 * An <code>implementation</code> is provided that throws UnsupportedOperationException so that users that decorate 666 * the <code>Application</code> continue to work. 667 * </p> 668 * 669 * @since 1.2 670 */ 671 public ELContextListener[] getELContextListeners() 672 { 673 Application application = getMyfacesApplicationInstance(); 674 if (application != null) 675 { 676 return application.getELContextListeners(); 677 } 678 throw new UnsupportedOperationException(); 679 } 680 681 /** 682 * Return the singleton <code>ELResolver</code> instance to be used for all EL resolution. This is actually an 683 * instance of <code>CompositeELResolver</code> that must contain the following ELResolver instances in the 684 * following order: 685 * <ul> 686 * <li><code>ELResolver</code> instances declared using the <el-resolver> element in the application 687 * configuration resources.</li> 688 * 689 * <li>An <code> implementation</code> that wraps the head of the legacy VariableResolver chain, as per section 690 * <code> VariableResolver ChainWrapper</code> in Chapter 5 in the spec document.</li> 691 * 692 * <li>An <code>implementation</code> that wraps the head of the legacy PropertyResolver chain, as per section 693 * <code>PropertyResolver ChainWrapper</code> in Chapter 5 in the spec document.</li> 694 * 695 * <li>Any <code>ELResolver</code> instances added by calls to 696 * <code>{@link #addELResolver(jakarta.el.ELResolver)}</code>.</li> 697 * 698 * <li>The default implementation throws <code>UnsupportedOperationException</code> and is provided for the sole 699 * purpose of not breaking existing applications that extend <code>{@link Application}</code>.</li> 700 * </ul> 701 * 702 * @since 1.2 703 */ 704 public ELResolver getELResolver() 705 { 706 Application application = getMyfacesApplicationInstance(); 707 if (application != null) 708 { 709 return application.getELResolver(); 710 } 711 throw new UnsupportedOperationException(); 712 } 713 714 /** 715 * <p> 716 * Return the <code>ExpressionFactory</code> instance for this application. This instance is used by the convenience 717 * method <code>{@link #evaluateExpressionGet(FacesContext, java.lang.String, java.lang.Class)}. 718 * </code> 719 * </p> 720 * 721 * <p> 722 * The implementation must return the <code>ExpressionFactory</code> from the JSP container by calling <code> 723 * JspFactory.getDefaultFactory().getJspApplicationContext(servletContext).getExpressionFactory()</code>. 724 * </p> 725 * 726 * <p> 727 * An implementation is provided that throws <code>UnsupportedOperationException</code> so that users that decorate 728 * the <code>Application</code> continue to work. 729 * </p> 730 * 731 * @since 1.2 732 * @return 733 */ 734 public ExpressionFactory getExpressionFactory() 735 { 736 Application application = getMyfacesApplicationInstance(); 737 if (application != null) 738 { 739 return application.getExpressionFactory(); 740 } 741 throw new UnsupportedOperationException(); 742 } 743 744 /** 745 * Return the fully qualified class name of the <code>ResourceBundle</code> to be used for JavaServer Faces messages 746 * for this application. If not explicitly set, <code>null</code> is returned. 747 */ 748 public abstract String getMessageBundle(); 749 750 /** 751 *Return the <code>{@link NavigationHandler}</code> instance that will be passed the outcome returned by any 752 * invoked application action for this web application. If not explicitly set, a default implementation must be 753 * provided that performs the functions described in the <code>{@link NavigationHandler}</code> class description. 754 */ 755 public abstract NavigationHandler getNavigationHandler(); 756 757 /** 758 * <p> 759 * Return the project stage for the currently running application instance. The default value is <code> 760 * {@link ProjectStage#Production}</code> 761 * </p> 762 * 763 * <p> 764 * The implementation of this method must perform the following algorithm or an equivalent with the same end result 765 * to determine the value to return. 766 * </p> 767 * 768 * <ul> 769 * <li>If the value has already been determined by a previous call to this method, simply return that value.</li> 770 * <li>Look for a <code>JNDI</code> environment entry under the key given by the value of 771 * <code>{@link ProjectStage#PROJECT_STAGE_JNDI_NAME}</code> (return type of java.lang.String). If found, continue 772 * with the algorithm below, otherwise, look for an entry in the <code>initParamMap</code> of the 773 * <code>ExternalContext</code> from the current <code>FacesContext</code> with the key 774 * <code>{@link ProjectStage#PROJECT_STAGE_PARAM_NAME}</code></li> 775 * <li>If a value is found found, see if an enum constant can be obtained by calling 776 * <code>ProjectStage.valueOf()</code>, passing the value from the <code>initParamMap</code>. If this succeeds 777 * without exception, save the value and return it.</li> 778 * <li>If not found, or any of the previous attempts to discover the enum constant value have failed, log a 779 * descriptive error message, assign the value as <code>ProjectStage.Production</code> and return it.</li> 780 * </ul> 781 * 782 * @since 2.0 783 */ 784 public ProjectStage getProjectStage() 785 { 786 Application application = getMyfacesApplicationInstance(); 787 if (application != null) 788 { 789 return application.getProjectStage(); 790 } 791 throw new UnsupportedOperationException(); 792 } 793 794 /** 795 * Get the object used by the VariableResolver to read and write named properties on java beans, Arrays, Lists and 796 * Maps. This object is used by the ValueBinding implementation, and during the process of configuring 797 * "managed bean" properties. 798 * 799 * @deprecated 800 */ 801 public abstract PropertyResolver getPropertyResolver(); 802 803 /** 804 * <p> 805 * Find a <code>ResourceBundle</code> as defined in the application configuration resources under the specified 806 * name. If a <code>ResourceBundle</code> was defined for the name, return an instance that uses the locale of the 807 * current <code>{@link jakarta.faces.component.UIViewRoot}</code>. 808 * </p> 809 * 810 * <p> 811 * The default implementation throws <code>UnsupportedOperationException</code> and is provided for the sole purpose 812 * of not breaking existing applications that extend this class. 813 * </p> 814 * 815 * @return <code>ResourceBundle</code> for the current UIViewRoot, otherwise null 816 * 817 * @throws FacesException 818 * if a bundle was defined, but not resolvable 819 * @throws NullPointerException 820 * if ctx == null || name == null 821 */ 822 public ResourceBundle getResourceBundle(FacesContext ctx, String name) 823 { 824 Application application = getMyfacesApplicationInstance(ctx); 825 if (application != null) 826 { 827 return application.getResourceBundle(ctx, name); 828 } 829 throw new UnsupportedOperationException(); 830 } 831 832 /** 833 * <p> 834 * Return the singleton, stateless, thread-safe <code>{@link ResourceHandler}</code> for this application. The JSF 835 * implementation must support the following techniques for declaring an alternate implementation of <code> 836 * ResourceHandler</code>. 837 * </p> 838 * 839 * <ul> 840 * <li>The <code>ResourceHandler</code> implementation is declared in the application configuration resources by 841 * giving the fully qualified class name as the value of the <code><resource-handler></code> element 842 * within the 843 * <code>application</code> element.</li> 844 * <li>RELEASE_PENDING(edburns) It can also be declared via an annotation as 845 * specified in [287-ConfigAnnotations].</li> 846 * </ul> 847 * 848 * <p> 849 * In all of the above cases, the runtime must employ the decorator pattern as for every other pluggable artifact in 850 * JSF. 851 * </p> 852 * 853 * @since 2.0 854 */ 855 public ResourceHandler getResourceHandler() 856 { 857 Application application = getMyfacesApplicationInstance(); 858 if (application != null) 859 { 860 return application.getResourceHandler(); 861 } 862 throw new UnsupportedOperationException(); 863 } 864 865 /** 866 * Return the <code>StateManager</code> instance that will be utilized during the Restore View and Render Response 867 * phases of the request processing lifecycle. If not explicitly set, a default implementation must be provided that 868 * performs the functions described in the <code>StateManager</code> description in the JavaServer Faces 869 * Specification. 870 */ 871 public abstract StateManager getStateManager(); 872 873 /** 874 * Return an <code>Iterator</code> over the supported <code>Locales</code> for this appication. 875 */ 876 public abstract Iterator<Locale> getSupportedLocales(); 877 878 /** 879 *Return an <code>Iterator</code> over the set of currently registered validator ids for this 880 * <code>Application</code>. 881 */ 882 public abstract Iterator<String> getValidatorIds(); 883 884 /** 885 * Get the object used to resolve expressions of form "#{...}". 886 * 887 * @deprecated 888 */ 889 public abstract VariableResolver getVariableResolver(); 890 891 /** 892 * Set the <code>{@link ViewHandler}</code> instance that will be utilized during the 893 * <code> Restore View and Render Response</code> phases of the request processing lifecycle. 894 * 895 * @return 896 */ 897 public abstract ViewHandler getViewHandler(); 898 899 /** 900 * 901 * @param facesContext 902 * @param systemEventClass 903 * @param sourceBaseType 904 * @param source 905 * 906 * @since 2.0 907 */ 908 public void publishEvent(FacesContext facesContext, Class<? extends SystemEvent> systemEventClass, 909 Class<?> sourceBaseType, Object source) 910 { 911 Application application = getMyfacesApplicationInstance(facesContext); 912 if (application != null) 913 { 914 application.publishEvent(facesContext, systemEventClass, sourceBaseType, source); 915 return; 916 } 917 throw new UnsupportedOperationException(); 918 } 919 920 /** 921 * <p> 922 * If there are one or more listeners for events of the type represented by <code>systemEventClass</code>, call 923 * those listeners,passing source as the <code>source</code> of the event. The implementation should be as fast as 924 * possible in determining whether or not a listener for the given <code>systemEventClass</code> and 925 * <code>source</code> has been installed, and should return immediately once such a determination has been made. 926 * The implementation of <code>publishEvent</code> must honor the requirements stated in 927 * <code>{@link #subscribeToEvent(java.lang.Class, java.lang.Class, 928 * SystemEventListener)}</code> 929 * <p> 930 * <p> 931 * The default implementation must implement an algorithm semantically equivalent to the following to locate 932 * listener instances and to invoke them. 933 * <p> 934 * <ul> 935 * <li>If the <code>source</code> argument implements 936 * <code>{@link jakarta.faces.event.SystemEventListenerHolder}</code>, call 937 * <code>{@linkjakarta.faces.event.SystemEventListenerHolder#getListenersForEventClass(java.lang.Class)}</code> 938 * on it, passing the 939 * <code>systemEventClass</code> argument. If the list is not empty, perform algorithm 940 * <code>traverseListenerList</code> on the list.</li> 941 * 942 * <li>If any <code>Application</code> level listeners have been installed by previous calls to <code>{@link 943 * #subscribeToEvent(java.lang.Class, java.lang.Class, SystemEventListener)}</code>, perform algorithm 944 * <code>traverseListenerList</code> on the list.</li> 945 * 946 * <li>If any <code>Application</code> level listeners have been installed by previous calls to 947 * <code>{@link #subscribeToEvent(java.lang.Class, SystemEventListener)}</code>, perform algorithm 948 * <code>traverseListenerList</code> on the list.</li> 949 * </ul> 950 * 951 * <p> 952 * If the act of invoking the <code>processListener</code> method causes an 953 * <code>{@link jakarta.faces.event.AbortProcessingException}</code> to be thrown, 954 * processing of the listeners must be aborted. 955 * </p> 956 * 957 * <p> 958 * Algorithm <code>traverseListenerList</code>: For each listener in the list, 959 * </p> 960 * 961 * <ul> 962 * <li>Call 963 * <code>{@link SystemEventListener#isListenerForSource(java.lang.Object)}</code>, passing the <code>source</code> 964 * argument. If this returns <code>false</code>, take no action on the listener.</li> 965 * 966 * <li>Otherwise, if the event to be passed to the listener instances has not yet been constructed, construct the 967 * event, passing <code>source</code> as the argument to the one-argument constructor that takes an 968 * <code>Object</code>. This same event instance must be passed to all listener instances.</li> 969 * 970 * <li>Call 971 * <code>{@link SystemEvent#isAppropriateListener(jakarta.faces.event.FacesListener)}</code>, passing the listener 972 * instance as the argument. If this returns <code>false</code>, take no action on the listener.</li> 973 * 974 * <li>Call <code>{@link SystemEvent#processListener(jakarta.faces.event.FacesListener)}</code>, 975 * passing the listener instance.</li> 976 * </ul> 977 * 978 * @param systemEventClass 979 * - The Class of event that is being published. Must be non-null. 980 * 981 * @param source 982 * - The <code>source</code> for the event of type systemEventClass. Must be non- <code>null</code>, and 983 * must implement <code>{@link jakarta.faces.event.SystemEventListenerHolder}</code>. 984 * 985 * @since 2.0 986 */ 987 public void publishEvent(FacesContext facesContext, Class<? extends SystemEvent> systemEventClass, Object source) 988 { 989 Application application = getMyfacesApplicationInstance(facesContext); 990 if (application != null) 991 { 992 application.publishEvent(facesContext, systemEventClass, source); 993 return; 994 } 995 throw new UnsupportedOperationException(); 996 } 997 998 /** 999 * <p> 1000 * Remove the argument <code>listener</code> from the list of <code>ELContextListeners</code>. If <code>listener 1001 * </code> is null, no exception is thrown and no action is performed. If <code>listener</code> is not in the list, 1002 * no exception is thrown and no action is performed. 1003 * <p> 1004 * 1005 * <p> 1006 * An implementation is provided that throws <code>UnsupportedOperationException</code> so that users that decorate 1007 * the <code>Application</code> continue to work. 1008 * 1009 * @param listener 1010 */ 1011 public void removeELContextListener(ELContextListener listener) 1012 { 1013 Application application = getMyfacesApplicationInstance(); 1014 if (application != null) 1015 { 1016 application.removeELContextListener(listener); 1017 return; 1018 } 1019 throw new UnsupportedOperationException(); 1020 } 1021 1022 /** 1023 * Set the default <code>{@link ActionListener}</code> to be registered for all 1024 * <code>{@link jakarta.faces.component.ActionSource}</code> 1025 * components. 1026 * 1027 * @param listener 1028 * - The new default <code>{@link ActionListener}</code> 1029 * 1030 * @throws NullPointerException 1031 * if listener is null 1032 */ 1033 public abstract void setActionListener(ActionListener listener); 1034 1035 /** 1036 * Set the default <code>Locale</code> for this application. 1037 * 1038 * @param locale 1039 * - The new default <code>Locale</code> 1040 * 1041 * @throws NullPointerException 1042 * if listener is null 1043 */ 1044 public abstract void setDefaultLocale(Locale locale); 1045 1046 /** 1047 * Return the <code>renderKitId</code> to be used for rendering this application. If not explicitly set, <code>null 1048 * </code> is returned. 1049 * 1050 * @param renderKitId 1051 */ 1052 public abstract void setDefaultRenderKitId(String renderKitId); 1053 1054 /** 1055 * Set the fully qualified class name of the <code>ResourceBundle </code> to be used for JavaServer Faces messages 1056 * for this application. See the JavaDocs for the <code>java.util.ResourceBundle </code> class for more information 1057 * about the syntax for resource bundle names. 1058 * 1059 * @param bundle 1060 * - Base name of the resource bundle to be used 1061 * 1062 * @throws NullPointerException 1063 * if bundle is null 1064 */ 1065 public abstract void setMessageBundle(String bundle); 1066 1067 /** 1068 * Set the {@link NavigationHandler} instance that will be passed the outcome returned by any invoked application 1069 * action for this web application. 1070 * 1071 * @param handler 1072 * - The new NavigationHandler instance 1073 */ 1074 public abstract void setNavigationHandler(NavigationHandler handler); 1075 1076 /** 1077 * The recommended way to affect the execution of the EL is to provide an <el-resolver> element at the right 1078 * place in the application configuration resources which will be considered in the normal course of expression 1079 * evaluation. This method now will cause the argument resolver to be wrapped inside an implementation of ELResolver 1080 * and exposed to the EL resolution system as if the user had called addELResolver(jakarta.el.ELResolver). 1081 * 1082 * @deprecated 1083 */ 1084 public abstract void setPropertyResolver(PropertyResolver resolver); 1085 1086 /** 1087 * 1088 * @param resourceHandler 1089 * 1090 * @since 2.0 1091 */ 1092 public void setResourceHandler(ResourceHandler resourceHandler) 1093 { 1094 Application application = getMyfacesApplicationInstance(); 1095 if (application != null) 1096 { 1097 application.setResourceHandler(resourceHandler); 1098 return; 1099 } 1100 throw new UnsupportedOperationException(); 1101 } 1102 1103 /** 1104 *Set the {@link StateManager} instance that will be utilized during the <code>Restore View and Render Response 1105 * </code> phases of the request processing lifecycle. 1106 * 1107 * @param manager The new {@link StateManager}instance 1108 * 1109 * @throws IllegalStateException 1110 * if this method is called after at least one request has been processed by the <code>Lifecycle</code> 1111 * instance for this application. 1112 * @throws NullPointerException 1113 * if manager is <code>null</code> 1114 */ 1115 public abstract void setStateManager(StateManager manager); 1116 1117 /** 1118 * Set the <code>Locale</code> instances representing the supported <code>Locales</code> for this application. 1119 * 1120 * @param locales The set of supported <code>Locales</code> for this application 1121 * 1122 * @throws NullPointerException 1123 * if the argument newLocales is <code>null</code>. 1124 * 1125 */ 1126 public abstract void setSupportedLocales(Collection<Locale> locales); 1127 1128 /** 1129 * The recommended way to affect the execution of the EL is to provide an <el-resolver> element at the right 1130 * place in the application configuration resources which will be considered in the normal course of expression 1131 * evaluation. This method now will cause the argument resolver to be wrapped inside an implementation of ELResolver 1132 * and exposed to the EL resolution system as if the user had called addELResolver(jakarta.el.ELResolver). 1133 * 1134 * @deprecated 1135 */ 1136 public abstract void setVariableResolver(VariableResolver resolver); 1137 1138 /** 1139 * Set the {@link ViewHandler} instance that will be utilized during the <code>Restore View and Render Response 1140 * </code> phases of the request processing lifecycle. 1141 * 1142 * @param handler 1143 * - The new {@link ViewHandler} instance 1144 * 1145 * @throws IllegalStateException 1146 * if this method is called after at least one request has been processed by the <code>Lifecycle</code> 1147 * instance for this application. 1148 * @throws NullPointerException 1149 * if <code>handler</code> is <code>null</code> 1150 */ 1151 public abstract void setViewHandler(ViewHandler handler); 1152 1153 /** 1154 * 1155 * @param systemEventClass 1156 * @param sourceClass 1157 * @param listener 1158 * 1159 * @since 2.0 1160 */ 1161 public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass, Class<?> sourceClass, 1162 SystemEventListener listener) 1163 { 1164 Application application = getMyfacesApplicationInstance(); 1165 if (application != null) 1166 { 1167 application.subscribeToEvent(systemEventClass, sourceClass, listener); 1168 return; 1169 } 1170 throw new UnsupportedOperationException(); 1171 } 1172 1173 /** 1174 * 1175 * @param systemEventClass 1176 * @param listener 1177 * 1178 * @since 2.0 1179 */ 1180 public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass, SystemEventListener listener) 1181 { 1182 Application application = getMyfacesApplicationInstance(); 1183 if (application != null) 1184 { 1185 application.subscribeToEvent(systemEventClass, listener); 1186 return; 1187 } 1188 subscribeToEvent(systemEventClass, null, listener); 1189 } 1190 1191 /** 1192 * 1193 * @param systemEventClass 1194 * @param sourceClass 1195 * @param listener 1196 * 1197 * @since 2.0 1198 */ 1199 public void unsubscribeFromEvent(Class<? extends SystemEvent> systemEventClass, Class<?> sourceClass, 1200 SystemEventListener listener) 1201 { 1202 Application application = getMyfacesApplicationInstance(); 1203 if (application != null) 1204 { 1205 application.unsubscribeFromEvent(systemEventClass, sourceClass, listener); 1206 return; 1207 } 1208 throw new UnsupportedOperationException(); 1209 } 1210 1211 /** 1212 * 1213 * @param systemEventClass 1214 * @param listener 1215 * 1216 * @since 2.0 1217 */ 1218 public void unsubscribeFromEvent(Class<? extends SystemEvent> systemEventClass, SystemEventListener listener) 1219 { 1220 Application application = getMyfacesApplicationInstance(); 1221 if (application != null) 1222 { 1223 application.unsubscribeFromEvent(systemEventClass, listener); 1224 return; 1225 } 1226 unsubscribeFromEvent(systemEventClass, null, listener); 1227 } 1228 1229 /** 1230 * @since 2.2 1231 * @return 1232 */ 1233 public FlowHandler getFlowHandler() 1234 { 1235 Application application = getMyfacesApplicationInstance(); 1236 if (application != null) 1237 { 1238 return application.getFlowHandler(); 1239 } 1240 throw new UnsupportedOperationException(); 1241 } 1242 1243 /** 1244 * @since 2.2 1245 * @param flowHandler 1246 */ 1247 public void setFlowHandler(FlowHandler flowHandler) 1248 { 1249 Application application = getMyfacesApplicationInstance(); 1250 if (application != null) 1251 { 1252 application.setFlowHandler(flowHandler); 1253 return; 1254 } 1255 throw new UnsupportedOperationException(); 1256 1257 } 1258 1259 public void addSearchKeywordResolver(SearchKeywordResolver resolver) 1260 { 1261 // The following concrete methods were added for JSF 1.2. They supply default 1262 // implementations that throw UnsupportedOperationException. 1263 // This allows old Application implementations to still work. 1264 Application application = getMyfacesApplicationInstance(); 1265 if (application != null) 1266 { 1267 application.addSearchKeywordResolver(resolver); 1268 return; 1269 } 1270 throw new UnsupportedOperationException(); 1271 } 1272 1273 public SearchKeywordResolver getSearchKeywordResolver() 1274 { 1275 Application application = getMyfacesApplicationInstance(); 1276 if (application != null) 1277 { 1278 return application.getSearchKeywordResolver(); 1279 } 1280 throw new UnsupportedOperationException(); 1281 } 1282 1283 /** 1284 * @since 2.3 1285 * @return 1286 */ 1287 public SearchExpressionHandler getSearchExpressionHandler() 1288 { 1289 Application application = getMyfacesApplicationInstance(); 1290 if (application != null) 1291 { 1292 return application.getSearchExpressionHandler(); 1293 } 1294 throw new UnsupportedOperationException(); 1295 } 1296 1297 /** 1298 * @since 2.3 1299 * @param searchExpressionHandler 1300 */ 1301 public void setSearchExpressionHandler(SearchExpressionHandler searchExpressionHandler) 1302 { 1303 Application application = getMyfacesApplicationInstance(); 1304 if (application != null) 1305 { 1306 application.setSearchExpressionHandler(searchExpressionHandler); 1307 return; 1308 } 1309 throw new UnsupportedOperationException(); 1310 } 1311 }