View Javadoc

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 &lt;el-resolver&gt; 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>&lt;resource-handler&gt;</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 &lt;el-resolver&gt; 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 &lt;el-resolver&gt; 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 }