1 /*
2 * $Id: Application.java,v 1.50 2007/04/27 22:00:02 ofung Exp $
3 */
4
5 /*
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
7 *
8 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
9 *
10 * The contents of this file are subject to the terms of either the GNU
11 * General Public License Version 2 only ("GPL") or the Common Development
12 * and Distribution License("CDDL") (collectively, the "License"). You
13 * may not use this file except in compliance with the License. You can obtain
14 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
15 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
16 * language governing permissions and limitations under the License.
17 *
18 * When distributing the software, include this License Header Notice in each
19 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
20 * Sun designates this particular file as subject to the "Classpath" exception
21 * as provided by Sun in the GPL Version 2 section of the License file that
22 * accompanied this code. If applicable, add the following below the License
23 * Header, with the fields enclosed by brackets [] replaced by your own
24 * identifying information: "Portions Copyrighted [year]
25 * [name of copyright owner]"
26 *
27 * Contributor(s):
28 *
29 * If you wish your version of this file to be governed by only the CDDL or
30 * only the GPL Version 2, indicate your decision by adding "[Contributor]
31 * elects to include this software in this distribution under the [CDDL or GPL
32 * Version 2] license." If you don't indicate a single choice of license, a
33 * recipient has the option to distribute your version of this file under
34 * either the CDDL, the GPL Version 2 or to extend the choice of license to
35 * its licensees as provided above. However, if you add GPL Version 2 code
36 * and therefore, elected the GPL Version 2 license, then the option applies
37 * only if the new code is made subject to such option by the copyright
38 * holder.
39 */
40
41 package javax.faces.application;
42
43
44 import java.util.Iterator;
45 import java.util.Collection;
46 import java.util.Locale;
47 import java.util.ResourceBundle;
48
49 import javax.faces.FacesException;
50 import javax.faces.component.UIComponent;
51 import javax.faces.context.FacesContext;
52 import javax.faces.context.ExternalContext;
53 import javax.faces.convert.Converter;
54 import javax.faces.el.MethodBinding;
55 import javax.faces.el.PropertyResolver;
56 import javax.faces.el.ReferenceSyntaxException;
57 import javax.faces.el.ValueBinding;
58 import javax.faces.el.VariableResolver;
59 import javax.faces.event.ActionListener;
60 import javax.faces.validator.Validator;
61
62 import javax.el.ELContextListener;
63 import javax.el.ExpressionFactory;
64 import javax.el.ValueExpression;
65 import javax.el.ELException;
66 import javax.el.ELResolver;
67
68
69
70 /**
71 * <p><strong>Application</strong> represents a per-web-application
72 * singleton object where applications based on JavaServer Faces (or
73 * implementations wishing to provide extended functionality) can
74 * register application-wide singletons that provide functionality
75 * required by JavaServer Faces. Default implementations of each
76 * object are provided for cases where the application does not choose
77 * to customize the behavior.</p>
78 *
79 * <p>The instance of {@link Application} is created by calling the
80 * <code>getApplication()</code> method of {@link ApplicationFactory}.
81 * Because this instance is shared, it must be implemented in a
82 * thread-safe manner.</p>
83 *
84 * <p>The application also acts as a factory for several types of
85 * Objects specified in the Faces Configuration file. Please see {@link
86 * Application#createComponent}, {@link Application#createConverter},
87 * and {@link Application#createValidator}. </p>
88 */
89
90 public abstract class Application {
91
92
93 // ------------------------------------------------------------- Properties
94
95
96 /**
97 * <p>Return the default {@link ActionListener} to be registered for
98 * all {@link javax.faces.component.ActionSource} components in this
99 * appication. If not explicitly set, a default implementation must
100 * be provided that performs the
101 *
102 * following functions:</p>
103 * <ul>
104 * <li>The <code>processAction()</code> method must first call
105 * <code>FacesContext.renderResponse()</code> in order to bypass
106 * any intervening lifecycle phases, once the method returns.</li>
107 * <li>The <code>processAction()</code> method must next determine
108 * the logical outcome of this event, as follows:
109 * <ul>
110 * <li>If the originating component has a non-<code>null</code>
111 * <code>action</code> property, retrieve the {@link
112 * MethodBinding} from the property, and call
113 * <code>invoke()</code> on it. Convert the returned value (if
114 * any) to a String, and use it as the logical outcome.</li>
115
116 * <li>Otherwise, the logical outcome is <code>null</code>.</li>
117 * </ul></li>
118
119 * <li>The <code>processAction()</code> method must finally retrieve
120 * the <code>NavigationHandler</code> instance for this
121 * application and call {@link
122 * NavigationHandler#handleNavigation} passing:
123 *
124 * <ul>
125
126 * <li>the {@link FacesContext} for the current request</li>
127
128 * <li>If there is a <code>MethodBinding</code> instance for the
129 * <code>action</code> property of this component, the result of
130 * calling {@link MethodBinding#getExpressionString} on it, null
131 * otherwise</li>
132 *
133 * <li>the logical outcome as determined above</li>
134 *
135 * </ul>
136 *
137 * </li>
138 * </ul>
139 *
140 * <p>Note that the specification for the default
141 * <code>ActionListener</code> contiues to call for the use of a
142 * <strong>deprecated</strong> property (<code>action</code>) and
143 * class (<code>MethodBinding</code>). Unfortunately, this is
144 * necessary because the default <code>ActionListener</code> must
145 * continue to work with components that do not implement {@link
146 * javax.faces.component.ActionSource2}, and only implement {@link
147 * javax.faces.component.ActionSource}.</p>
148 */
149 public abstract ActionListener getActionListener();
150
151
152 /**
153 * <p>Set the default {@link ActionListener} to be registered for all
154 * {@link javax.faces.component.ActionSource} components.</p>
155 * </p>
156 *
157 * @param listener The new default {@link ActionListener}
158 *
159 * @throws NullPointerException if <code>listener</code>
160 * is <code>null</code>
161 */
162 public abstract void setActionListener(ActionListener listener);
163
164
165 /**
166 * <p>Return the default <code>Locale</code> for this application. If
167 * not explicitly set, <code>null</code> is returned.</p>
168 */
169 public abstract Locale getDefaultLocale();
170
171
172 /**
173 * <p>Set the default <code>Locale</code> for this application.</p>
174 *
175 * @param locale The new default <code>Locale</code>
176 *
177 * @throws NullPointerException if <code>locale</code>
178 * is <code>null</code>
179 */
180 public abstract void setDefaultLocale(Locale locale);
181
182
183 /**
184 * <p>Return the <code>renderKitId</code> to be used for rendering
185 * this application. If not explicitly set, <code>null</code> is
186 * returned.</p>
187 */
188 public abstract String getDefaultRenderKitId();
189
190
191 /**
192 * <p>Set the <code>renderKitId</code> to be used to render this
193 * application. Unless the client has provided a custom {@link ViewHandler}
194 * that supports the use of multiple {@link javax.faces.render.RenderKit}
195 * instances in the same application, this method must only be called at
196 * application startup, before any Faces requests have been processed.
197 * This is a limitation of the current Specification, and may be lifted in
198 * a future release.</p>
199 */
200 public abstract void setDefaultRenderKitId(String renderKitId);
201
202
203
204 /**
205 * <p>Return the fully qualified class name of the
206 * <code>ResourceBundle</code> to be used for JavaServer Faces messages
207 * for this application. If not explicitly set, <code>null</code>
208 * is returned.</p>
209 */
210 public abstract String getMessageBundle();
211
212
213 /**
214 * <p>Set the fully qualified class name of the <code>ResourceBundle</code>
215 * to be used for JavaServer Faces messages for this application. See the
216 * JavaDocs for the <code>java.util.ResourceBundle</code> class for more
217 * information about the syntax for resource bundle names.</p>
218 *
219 * @param bundle Base name of the resource bundle to be used
220 *
221 * @throws NullPointerException if <code>bundle</code>
222 * is <code>null</code>
223 */
224 public abstract void setMessageBundle(String bundle);
225
226
227 /**
228 * <p>Return the {@link NavigationHandler} instance that will be passed
229 * the outcome returned by any invoked application action for this
230 * web application. If not explicitly set, a default implementation
231 * must be provided that performs the functions described in the
232 * {@link NavigationHandler} class description.</p>
233 */
234 public abstract NavigationHandler getNavigationHandler();
235
236
237 /**
238 * <p>Set the {@link NavigationHandler} instance that will be passed
239 * the outcome returned by any invoked application action for this
240 * web application.</p>
241 *
242 * @param handler The new {@link NavigationHandler} instance
243 *
244 * @throws NullPointerException if <code>handler</code>
245 * is <code>null</code>
246 */
247 public abstract void setNavigationHandler(NavigationHandler handler);
248
249
250
251
252 /**
253 * <p>Return a {@link PropertyResolver} instance that wraps the
254 * {@link ELResolver} instance that Faces provides to the unified EL
255 * for the resolution of expressions that appear programmatically in
256 * an application.</p>
257 *
258 * <p>Note that this no longer returns the default
259 * <code>PropertyResolver</code> since that class is now a no-op
260 * that aids in allowing custom <code>PropertyResolver</code>s to
261 * affect the EL resolution process.</p>
262 *
263 * @deprecated This has been replaced by {@link #getELResolver}.
264 */
265 public abstract PropertyResolver getPropertyResolver();
266
267
268 /**
269 * <p>Set the {@link PropertyResolver} instance that will be utilized
270 * to resolve method and value bindings.</p>
271 *
272 * <p>This method is now deprecated but the implementation must
273 * cause the argument to be set as the head of the legacy
274 * <code>PropertyResolver</code> chain, replacing any existing value
275 * that was set from the application configuration resources.</p>
276 *
277 * <p>It is illegal to call this method after
278 * the application has received any requests from the client. If an
279 * attempt is made to register a listener after that time it must have
280 * no effect. </p>
281 *
282 * @param resolver The new {@link PropertyResolver} instance
283 *
284 * @throws NullPointerException if <code>resolver</code>
285 * is <code>null</code>
286 *
287 * @deprecated The recommended way to affect the execution of the EL
288 * is to provide an <code><el-resolver></code> element at the
289 * right place in the application configuration resources which will
290 * be considered in the normal course of expression evaluation.
291 * This method now will cause the argument <code>resolver</code> to
292 * be wrapped inside an implementation of {@link ELResolver} and
293 * exposed to the EL resolution system as if the user had called
294 * {@link #addELResolver}.
295 *
296 * @throws IllegalStateException if called after the first
297 * request to the {@link javax.faces.webapp.FacesServlet} has been
298 * serviced.
299 */
300 public abstract void setPropertyResolver(PropertyResolver resolver);
301
302 /**
303 * <p>Find a <code>ResourceBundle</code> as defined in the
304 * application configuration resources under the specified name. If
305 * a <code>ResourceBundle</code> was defined for the name, return an
306 * instance that uses the locale of the current {@link
307 * javax.faces.component.UIViewRoot}.</p>
308 *
309 * <p>The default implementation throws
310 * <code>UnsupportedOperationException</code> and is provided
311 * for the sole purpose of not breaking existing applications that extend
312 * this class.</p>
313 *
314 * @return <code>ResourceBundle</code> for the current UIViewRoot,
315 * otherwise null
316 *
317 * @throws FacesException if a bundle was defined, but not resolvable
318 *
319 * @throws NullPointerException if ctx == null || name == null
320 *
321 * @since 1.2
322 */
323
324 public ResourceBundle getResourceBundle(FacesContext ctx, String name) {
325 Application app = getRIApplicationImpl(ctx);
326 if (app != null) {
327 //noinspection TailRecursion
328 return app.getResourceBundle(ctx, name);
329 }
330
331 throw new UnsupportedOperationException();
332 }
333
334
335
336 /**
337 * <p>Return the {@link VariableResolver} that wraps the {@link
338 * ELResolver} instance that Faces provides to the unified EL for
339 * the resolution of expressions that appear programmatically in an
340 * application. The implementation of the
341 * <code>VariableResolver</code>must pass <code>null</code> as the
342 * base argument for any methods invoked on the underlying
343 * <code>ELResolver</code>.</p>
344 *
345 * <p>Note that this method no longer returns the default
346 * <code>VariableResolver</code>, since that class now is a no-op
347 * that aids in allowing custom <code>VariableResolver</code>s to
348 * affect the EL resolution process.</p>
349 *
350 * @deprecated This has been replaced by {@link #getELResolver}.
351 */
352 public abstract VariableResolver getVariableResolver();
353
354
355 /**
356 * <p>Set the {@link VariableResolver} instance that will be consulted
357 * to resolve method and value bindings.</p>
358 *
359 * <p>This method is now deprecated but the implementation must
360 * cause the argument to be set as the head of the legacy
361 * <code>VariableResolver</code> chain, replacing any existing value
362 * that was set from the application configuration resources.</p>
363 *
364 * <p>It is illegal to call this method after
365 * the application has received any requests from the client. If an
366 * attempt is made to register a listener after that time it must have
367 * no effect.</p>
368 *
369 * @param resolver The new {@link VariableResolver} instance
370 *
371 * @throws NullPointerException if <code>resolver</code>
372 * is <code>null</code>
373 *
374 * @deprecated The recommended way to affect the execution of the EL
375 * is to provide an <code><el-resolver></code> element at the
376 *
377 * right place in the application configuration resources which will
378 * be considered in the normal course of expression evaluation.
379 * This method now will cause the argument <code>resolver</code> to
380 * be wrapped inside an implementation of {@link ELResolver} and
381 * exposed to the EL resolution system as if the user had called
382 * {@link #addELResolver}.
383 *
384 * @throws IllegalStateException if called after the first
385 * request to the {@link javax.faces.webapp.FacesServlet} has been
386 * serviced.
387 */
388 public abstract void setVariableResolver(VariableResolver resolver);
389
390 /**
391 * <p>Cause an the argument <code>resolver</code> to be added to the
392 * resolver chain as specified in section 5.5.1 of the JavaServer
393 * Faces Specification.</p>
394 *
395 * <p>It is not possible to remove an <code>ELResolver</code>
396 * registered with this method, once it has been registered.</p>
397 *
398 * <p>It is illegal to register an <code>ELResolver</code> after
399 * the application has received any requests from the client. If an
400 * attempt is made to register a listener after that time, an
401 * <code>IllegalStateException</code> must be thrown. This restriction is
402 * in place to allow the JSP container to optimize for the common
403 * case where no additional <code>ELResolver</code>s are in the
404 * chain, aside from the standard ones. It is permissible to add
405 * <code>ELResolver</code>s before or after initialization to a
406 * <code>CompositeELResolver</code> that is already in the
407 * chain.</p>
408 *
409 * <p>The default implementation throws
410 * <code>UnsupportedOperationException</code> and is provided
411 * for the sole purpose of not breaking existing applications that extend
412 * {@link Application}.</p>
413 *
414 * @since 1.2
415 */
416
417 public void addELResolver(ELResolver resolver) {
418 Application app = getRIApplicationImpl();
419 if (app != null) {
420 app.addELResolver(resolver);
421 } else {
422 throw new UnsupportedOperationException();
423 }
424 }
425
426 /**
427 * <p>Return the singleton {@link ELResolver} instance to be used
428 * for all EL resolution. This is actually an instance of {@link
429 * javax.el.CompositeELResolver} that must contain the following
430 * <code>ELResolver</code> instances in the following order:</p>
431 *
432 * <ol>
433 *
434 * <li><p><code>ELResolver</code> instances declared using the
435 * <el-resolver> element in the application configuration
436 * resources. </p></li>
437 *
438 * <li><p>An <code>implementation</code> that wraps the head of
439 * the legacy <code>VariableResolver</code> chain, as per section
440 * <i>VariableResolver ChainWrapper</i> in Chapter 5 in the spec
441 * document.</p></li>
442 *
443 * <li><p>An <code>implementation</code> that wraps the head of
444 * the legacy <code>PropertyResolver</code> chain, as per section
445 * <i>PropertyResolver ChainWrapper</i> in Chapter 5 in the spec
446 * document.</p></li>
447 *
448 * <li><p>Any <code>ELResolver</code> instances added by calls to
449 * {@link #addELResolver}.</p></li>
450 *
451 * </ol>
452 *
453 * <p>The default implementation throws <code>UnsupportedOperationException</code>
454 * and is provided for the sole purpose of not breaking existing applications
455 * that extend {@link Application}.</p>
456 *
457 * @since 1.2
458 */
459
460 public ELResolver getELResolver() {
461 Application app = getRIApplicationImpl();
462 if (app != null) {
463 //noinspection TailRecursion
464 return app.getELResolver();
465 }
466 throw new UnsupportedOperationException();
467 }
468
469
470 /**
471 * <p>Return the {@link ViewHandler} instance that will be utilized
472 * during the <em>Restore View</em> and <em>Render Response</em>
473 * phases of the request processing lifecycle. If not explicitly set,
474 * a default implementation must be provided that performs the functions
475 * described in the {@link ViewHandler} description in the
476 * JavaServer Faces Specification.</p>
477 */
478 public abstract ViewHandler getViewHandler();
479
480
481 /**
482 * <p>Set the {@link ViewHandler} instance that will be utilized
483 * during the <em>Restore View</em> and <em>Render Response</em>
484 * phases of the request processing lifecycle.</p>
485 *
486 * @param handler The new {@link ViewHandler} instance
487 *
488 * @throws IllegalStateException if this method is called after
489 * at least one request has been processed by the
490 * <code>Lifecycle</code> instance for this application.
491 * @throws NullPointerException if <code>handler</code>
492 * is <code>null</code>
493 */
494 public abstract void setViewHandler(ViewHandler handler);
495
496
497
498 /**
499 * <p>Return the {@link StateManager} instance that will be utilized
500 * during the <em>Restore View</em> and <em>Render Response</em>
501 * phases of the request processing lifecycle. If not explicitly set,
502 * a default implementation must be provided that performs the functions
503 * described in the {@link StateManager} description
504 * in the JavaServer Faces Specification.</p>
505 */
506 public abstract StateManager getStateManager();
507
508
509 /**
510 * <p>Set the {@link StateManager} instance that will be utilized
511 * during the <em>Restore View</em> and <em>Render Response</em>
512 * phases of the request processing lifecycle.</p>
513 *
514 * @param manager The new {@link StateManager} instance
515 *
516 * @throws IllegalStateException if this method is called after
517 * at least one request has been processed by the
518 * <code>Lifecycle</code> instance for this application.
519 * @throws NullPointerException if <code>manager</code>
520 * is <code>null</code>
521 */
522 public abstract void setStateManager(StateManager manager);
523
524
525 // ------------------------------------------------------- Object Factories
526
527
528 /**
529 * <p>Register a new mapping of component type to the name of the
530 * corresponding {@link UIComponent} class. This allows subsequent calls
531 * to <code>createComponent()</code> to serve as a factory for
532 * {@link UIComponent} instances.</p>
533 *
534 * @param componentType The component type to be registered
535 * @param componentClass The fully qualified class name of the
536 * corresponding {@link UIComponent} implementation
537 *
538 * @throws NullPointerException if <code>componentType</code> or
539 * <code>componentClass</code> is <code>null</code>
540 */
541 public abstract void addComponent(String componentType,
542 String componentClass);
543
544
545 /**
546 * <p>Instantiate and return a new {@link UIComponent} instance of the
547 * class specified by a previous call to <code>addComponent()</code> for
548 * the specified component type.</p>
549 *
550 * @param componentType The component type for which to create and
551 * return a new {@link UIComponent} instance
552 *
553 * @throws FacesException if a {@link UIComponent} of the
554 * specified type cannot be created
555 * @throws NullPointerException if <code>componentType</code>
556 * is <code>null</code>
557 */
558 public abstract UIComponent createComponent(String componentType)
559 throws FacesException;
560
561
562 /**
563 * <p>Wrap the argument <code>componentBinding</code> in an
564 * implementation of {@link ValueExpression} and call through to
565 * {@link
566 * #createComponent(javax.el.ValueExpression,javax.faces.context.FacesContext,java.lang.String)}.</p>
567 *
568 * @param componentBinding {@link ValueBinding} representing a
569 * component value binding expression (typically specified by the
570 * <code>component</code> attribute of a custom tag)
571 * @param context {@link FacesContext} for the current request
572 * @param componentType Component type to create if the {@link ValueBinding}
573 * does not return a component instance
574 *
575 * @throws FacesException if a {@link UIComponent} cannot be created
576 * @throws NullPointerException if any parameter is <code>null</code>
577 *
578 *
579 * @deprecated This has been replaced by {@link
580 * #createComponent(javax.el.ValueExpression,javax.faces.context.FacesContext,java.lang.String)}.
581 */
582 public abstract UIComponent createComponent(ValueBinding componentBinding,
583 FacesContext context,
584 String componentType)
585 throws FacesException;
586
587 /**
588 * <p>Call the <code>getValue()</code> method on the specified
589 * {@link ValueExpression}. If it returns a {@link
590 * UIComponent} instance, return it as the value of this method. If
591 * it does not, instantiate a new {@link UIComponent} instance of
592 * the specified component type, pass the new component to the
593 * <code>setValue()</code> method of the specified {@link
594 * ValueExpression}, and return it.</p>
595 *
596 * @param componentExpression {@link ValueExpression} representing a
597 * component value expression (typically specified by the
598 * <code>component</code> attribute of a custom tag)
599 * @param context {@link FacesContext} for the current request
600 * @param componentType Component type to create if the {@link
601 * ValueExpression} does not return a component instance
602 *
603 * @throws FacesException if a {@link UIComponent} cannot be created
604 * @throws NullPointerException if any parameter is <code>null</code>
605 *
606 * <p>A default implementation is provided that throws
607 * <code>UnsupportedOperationException</code> so that users
608 * that decorate <code>Application</code> can continue to function</p>.
609 *
610 * @since 1.2
611 */
612 public UIComponent createComponent(ValueExpression componentExpression,
613 FacesContext context,
614 String componentType)
615 throws FacesException {
616 if (null == componentExpression || null == context ||
617 null == componentType) {
618 // PENDING - i18n
619 StringBuilder builder = new StringBuilder(64);
620 builder.append("null parameters - ");
621 builder.append("componentExpression: ").append(componentExpression);
622 builder.append(", context: ").append(context);
623 builder.append(", componentType: ").append(componentType);
624 throw new NullPointerException(builder.toString());
625 }
626
627 Object result;
628 boolean createOne = false;
629
630 try {
631 if (null != (result =
632 componentExpression.getValue(context.getELContext()))) {
633 // if the result is not an instance of UIComponent
634 createOne = (!(result instanceof UIComponent));
635 // we have to create one.
636 }
637 if (null == result || createOne) {
638 result = this.createComponent(componentType);
639 componentExpression.setValue((context.getELContext()), result);
640 }
641 } catch (ELException elex) {
642 throw new FacesException(elex);
643 }
644
645 return (UIComponent) result;
646 }
647
648
649 /**
650 * <p>Return an <code>Iterator</code> over the set of currently defined
651 * component types for this <code>Application</code>.</p>
652 */
653 public abstract Iterator<String> getComponentTypes();
654
655
656 /**
657 * <p>Register a new mapping of converter id to the name of the
658 * corresponding {@link Converter} class. This allows subsequent calls
659 * to <code>createConverter()</code> to serve as a factory for
660 * {@link Converter} instances.</p>
661 *
662 * @param converterId The converter id to be registered
663 * @param converterClass The fully qualified class name of the
664 * corresponding {@link Converter} implementation
665 *
666 * @throws NullPointerException if <code>converterId</code>
667 * or <code>converterClass</code> is <code>null</code>
668 */
669 public abstract void addConverter(String converterId,
670 String converterClass);
671
672
673 /**
674 * <p>Register a new converter class that is capable of performing
675 * conversions for the specified target class.</p>
676 *
677 * @param targetClass The class for which this converter is registered
678 * @param converterClass The fully qualified class name of the
679 * corresponding {@link Converter} implementation
680 *
681 * @throws NullPointerException if <code>targetClass</code>
682 * or <code>converterClass</code> is <code>null</code>
683 */
684 public abstract void addConverter(Class targetClass,
685 String converterClass);
686
687
688 /**
689 * <p>Instantiate and return a new {@link Converter} instance of the
690 * class specified by a previous call to <code>addConverter()</code>
691 * for the specified converter id. If there is no such registration
692 * for this converter id, return <code>null</code>.</p>
693 *
694 * @param converterId The converter id for which to create and
695 * return a new {@link Converter} instance
696 *
697 * @throws FacesException if the {@link Converter} cannot be
698 * created
699 * @throws NullPointerException if <code>converterId</code>
700 * is <code>null</code>
701 */
702 public abstract Converter createConverter(String converterId);
703
704
705 /**
706 * <p>Instantiate and return a new {@link Converter} instance of the
707 * class that has registered itself as capable of performing conversions
708 * for objects of the specified type. If no such {@link Converter} class
709 * can be identified, return <code>null</code>.</p>
710 *
711 * <p>To locate an appropriate {@link Converter} class, the following
712 * algorithm is performed, stopping as soon as an appropriate {@link
713 * Converter} class is found:</p>
714 * <ul>
715 * <li>Locate a {@link Converter} registered for the target class itself.
716 * </li>
717 * <li>Locate a {@link Converter} registered for interfaces that are
718 * implemented by the target class (directly or indirectly).</li>
719 * <li>Locate a {@link Converter} registered for the superclass (if any)
720 * of the target class, recursively working up the inheritance
721 * hierarchy.</li>
722 * </ul>
723 *
724 * <p>If the <code>Converter</code> has a single argument constructor that
725 * accepts a <code>Class</code>, instantiate the <code>Converter</code>
726 * using that constructor, passing the argument <code>targetClass</code> as
727 * the sole argument. Otherwise, simply use the zero-argument constructor.
728 * </p>
729 *
730 * @param targetClass Target class for which to return a {@link Converter}
731 *
732 * @throws FacesException if the {@link Converter} cannot be
733 * created
734 * @throws NullPointerException if <code>targetClass</code>
735 * is <code>null</code>
736 */
737 public abstract Converter createConverter(Class targetClass);
738
739
740 /**
741 * <p>Return an <code>Iterator</code> over the set of currently registered
742 * converter ids for this <code>Application</code>.</p>
743 */
744 public abstract Iterator<String> getConverterIds();
745
746
747 /**
748 * <p>Return an <code>Iterator</code> over the set of <code>Class</code>
749 * instances for which {@link Converter} classes have been explicitly
750 * registered.</p>
751 */
752 public abstract Iterator<Class> getConverterTypes();
753
754 /**
755 * <p>Return the {@link ExpressionFactory} instance for this
756 * application. This instance is used by the convenience method
757 * {@link #evaluateExpressionGet}.</p>
758 *
759 * <p>The implementation must return the
760 * <code>ExpressionFactory</code> from the JSP container by calling
761 * <code>JspFactory.getDefaultFactory().getJspApplicationContext(servletContext).getExpressionFactory()</code>. </p>
762 *
763 * <p>An implementation is provided that throws
764 * <code>UnsupportedOperationException</code> so that users that decorate
765 * the <code>Application</code> continue to work.
766 *
767 * @since 1.2
768 */
769
770 public ExpressionFactory getExpressionFactory() {
771 Application app = getRIApplicationImpl();
772 if (app != null) {
773 //noinspection TailRecursion
774 return app.getExpressionFactory();
775 }
776
777 throw new UnsupportedOperationException();
778 }
779
780 /**
781 * <p>Get a value by evaluating an expression.</p>
782 *
783 * <p>Call {@link #getExpressionFactory} then call {@link
784 * ExpressionFactory#createValueExpression} passing the argument
785 * <code>expression</code> and <code>expectedType</code>. Call
786 * {@link FacesContext#getELContext} and pass it to {@link
787 * ValueExpression#getValue}, returning the result.</p>
788 *
789 * <p>An implementation is provided that throws
790 * <code>UnsupportedOperationException</code> so that users that decorate
791 * the <code>Application</code> continue to work.
792 *
793 */
794
795 public Object evaluateExpressionGet(FacesContext context,
796 String expression,
797 Class expectedType) throws ELException {
798 Application app = getRIApplicationImpl(context);
799 if (app != null) {
800 //noinspection TailRecursion
801 return app.evaluateExpressionGet(context, expression, expectedType);
802 }
803 throw new UnsupportedOperationException();
804 }
805
806 /**
807 * <p>Call {@link #getExpressionFactory} then call {@link
808 * ExpressionFactory#createMethodExpression}, passing the given
809 * arguments, and wrap the result in a <code>MethodBinding</code>
810 * implementation, returning it.</p>
811 *
812 * @param ref Method binding expression for which to return a
813 * {@link MethodBinding} instance
814 * @param params Parameter signatures that must be compatible with those
815 * of the method to be invoked, or a zero-length array or <code>null</code>
816 * for a method that takes no parameters
817 *
818 * @throws NullPointerException if <code>ref</code>
819 * is <code>null</code>
820 * @throws ReferenceSyntaxException if the specified <code>ref</code>
821 * has invalid syntax
822 *
823 * @deprecated This has been replaced by calling {@link
824 * #getExpressionFactory} then {@link
825 * ExpressionFactory#createMethodExpression}.
826 */
827 public abstract MethodBinding createMethodBinding(String ref,
828 Class params[])
829 throws ReferenceSyntaxException;
830
831
832 /**
833 * <p>Return an <code>Iterator</code> over the supported
834 * <code>Locale</code>s for this appication.</p>
835 */
836 public abstract Iterator<Locale> getSupportedLocales();
837
838
839 /**
840 * <p>Set the <code>Locale</code> instances representing the supported
841 * <code>Locale</code>s for this application.</p>
842 *
843 * @param locales The set of supported <code>Locale</code>s
844 * for this application
845 *
846 * @throws NullPointerException if the argument
847 * <code>newLocales</code> is <code>null</code>.
848 *
849 */
850 public abstract void setSupportedLocales(Collection<Locale> locales);
851
852 /**
853 * <p>Provide a way for Faces applications to register an
854 * <code>ELContextListener</code> that will be notified on creation
855 * of <code>ELContext</code> instances. This listener will be
856 * called once per request.</p>
857 *
858 * <p>An implementation is provided that throws
859 * <code>UnsupportedOperationException</code> so that users that decorate
860 * the <code>Application</code> continue to work.
861 *
862 * @since 1.2
863 */
864
865 public void addELContextListener(ELContextListener listener) {
866 Application app = getRIApplicationImpl();
867 if (app != null) {
868 app.addELContextListener(listener);
869 } else {
870 throw new UnsupportedOperationException();
871 }
872 }
873
874 /**
875 * <p>Remove the argument <code>listener</code> from the list of
876 * {@link ELContextListener}s. If <code>listener</code> is null, no
877 * exception is thrown and no action is performed. If
878 * <code>listener</code> is not in the list, no exception is thrown
879 * and no action is performed.</p>
880 *
881 * <p>An implementation is provided that throws
882 * <code>UnsupportedOperationException</code> so that users that decorate
883 * the <code>Application</code> continue to work.
884 *
885 * @since 1.2
886 */
887
888 public void removeELContextListener(ELContextListener listener) {
889 Application app = getRIApplicationImpl();
890 if (app != null) {
891 app.removeELContextListener(listener);
892 } else {
893 throw new UnsupportedOperationException();
894 }
895
896 }
897
898 /**
899 * <p>If no calls have been made to {@link #addELContextListener},
900 * this method must return an empty array.</p>
901 *
902 * <p>Otherwise, return an array representing the list of listeners
903 * added by calls to {@link #addELContextListener}.</p>
904 *
905 * <p>An implementation is provided that throws
906 * <code>UnsupportedOperationException</code> so that users that decorate
907 * the <code>Application</code> continue to work.
908 *
909 * @since 1.2
910 */
911
912 public ELContextListener [] getELContextListeners() {
913 Application app = getRIApplicationImpl();
914 if (app != null) {
915 //noinspection TailRecursion
916 return app.getELContextListeners();
917 } else {
918 throw new UnsupportedOperationException();
919 }
920 }
921
922
923 /**
924 * <p>Register a new mapping of validator id to the name of the
925 * corresponding {@link Validator} class. This allows subsequent calls
926 * to <code>createValidator()</code> to serve as a factory for
927 * {@link Validator} instances.</p>
928 *
929 * @param validatorId The validator id to be registered
930 * @param validatorClass The fully qualified class name of the
931 * corresponding {@link Validator} implementation
932 *
933 * @throws NullPointerException if <code>validatorId</code>
934 * or <code>validatorClass</code> is <code>null</code>
935 */
936 public abstract void addValidator(String validatorId,
937 String validatorClass);
938
939
940 /**
941 * <p>Instantiate and return a new {@link Validator} instance of the
942 * class specified by a previous call to <code>addValidator()</code>
943 * for the specified validator id.</p>
944 *
945 * @param validatorId The validator id for which to create and
946 * return a new {@link Validator} instance
947 *
948 * @throws FacesException if a {@link Validator} of the
949 * specified id cannot be created
950 * @throws NullPointerException if <code>validatorId</code>
951 * is <code>null</code>
952 */
953 public abstract Validator createValidator(String validatorId)
954 throws FacesException;
955
956
957 /**
958 * <p>Return an <code>Iterator</code> over the set of currently registered
959 * validator ids for this <code>Application</code>.</p>
960 */
961 public abstract Iterator<String> getValidatorIds();
962
963
964 /**
965 * <p>Call {@link #getExpressionFactory} then call {@link
966 * ExpressionFactory#createValueExpression}, passing the argument
967 * <code>ref</code>, <code>Object.class</code> for the expectedType,
968 * and <code>null</code>, for the fnMapper.</p>
969 *
970 *
971 * @param ref Value binding expression for which to return a
972 * {@link ValueBinding} instance
973 *
974 * @throws NullPointerException if <code>ref</code>
975 * is <code>null</code>
976 * @throws ReferenceSyntaxException if the specified <code>ref</code>
977 * has invalid syntax
978 *
979 * @deprecated This has been replaced by calling {@link
980 * #getExpressionFactory} then {@link
981 * ExpressionFactory#createValueExpression}.
982 */
983 public abstract ValueBinding createValueBinding(String ref)
984 throws ReferenceSyntaxException;
985
986
987 // --------------------------------------------------------- Private Methods
988
989
990 private static Application getRIApplicationImpl(FacesContext context) {
991 ExternalContext extContext;
992 if (context != null) {
993 extContext = context.getExternalContext();
994 } else {
995 extContext =
996 FacesContext.getCurrentInstance().getExternalContext();
997 }
998 if (extContext != null) {
999 return ((Application) extContext.getApplicationMap().
1000 get("com.sun.faces.ApplicationImpl"));
1001 }
1002 return null;
1003 }
1004
1005 private static Application getRIApplicationImpl() {
1006 return getRIApplicationImpl(null);
1007 }
1008
1009 }