2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to you under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shale.view;
19  
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.Map;
23  
24  import javax.faces.FactoryFinder;
25  import javax.faces.application.Application;
26  import javax.faces.application.FacesMessage;
27  import javax.faces.component.EditableValueHolder;
28  import javax.faces.component.UIComponent;
29  import javax.faces.component.UIViewRoot;
30  import javax.faces.context.ExternalContext;
31  import javax.faces.context.FacesContext;
32  import javax.faces.el.ValueBinding;
33  import javax.faces.lifecycle.Lifecycle;
34  import javax.faces.lifecycle.LifecycleFactory;
35  
36  /***
37   * <p>Convenient abstract base class for application beans that wish to
38   * interact with JavaServer Faces request processing facilities.
39   * <strong>WARNING</strong> - These methods are only effective during
40   * the lifecycle of a JavaServer Faces request.</p>
41   *
42   * $Id: AbstractFacesBean.java 464373 2006-10-16 04:21:54Z rahul $
43   */
44  public abstract class AbstractFacesBean {
45  
46  
47      // -------------------------------- JavaServer Faces Object Accessor Methods
48  
49  
50      /***
51       * <p>Retiurn the <code>Application</code> instance for the current
52       * web application.</p>
53       */
54      protected Application getApplication() {
55  
56          return FacesContext.getCurrentInstance().getApplication();
57  
58      }
59  
60  
61      /***
62       * <p>Return a <code>Map</code> of the application scope attributes
63       * for this web application.</p>
64       */
65      protected Map getApplicationMap() {
66  
67          return getExternalContext().getApplicationMap();
68  
69      }
70  
71  
72      /***
73       * <p>Return the <code>ExternalContext</code> instance for the
74       * current request.</p>
75       */
76      protected ExternalContext getExternalContext() {
77  
78          return FacesContext.getCurrentInstance().getExternalContext();
79  
80      }
81  
82  
83      /***
84       * <p>Return the <code>FacesContext</code> instance for the
85       * current request.</p>
86       */
87      protected FacesContext getFacesContext() {
88  
89          return FacesContext.getCurrentInstance();
90  
91      }
92  
93  
94      /***
95       * <p>Return the configured <code>Lifecycle</code> instance for
96       * the current application.</p>
97       */
98      protected Lifecycle getLifecycle() {
99  
100         String lifecycleId =
101           getExternalContext().getInitParameter("javax.faces.LIFECYCLE_ID");
102         if (lifecycleId == null || lifecycleId.length() == 0) {
103             lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;
104         }
105         LifecycleFactory lifecycleFactory = (LifecycleFactory)
106           FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
107         return lifecycleFactory.getLifecycle(lifecycleId);
108 
109     }
110 
111 
112     /***
113      * <p>Return a <code>Map</code> of the request headers included in this
114      * request.  If there is more than one header for a particular header
115      * name, only the first value is included in this map.</p>
116      */
117     protected Map getRequestHeaderMap() {
118 
119         return getExternalContext().getRequestHeaderMap();
120 
121     }
122 
123 
124     /***
125      * <p>Return a <code>Map</code> of the request scope attributes
126      * for this request.</p>
127      */
128     protected Map getRequestMap() {
129 
130         return getExternalContext().getRequestMap();
131 
132     }
133 
134 
135     /***
136      * <p>Return a <code>Map</code> of the request parameters included in this
137      * request.  If there is more than one value for a particular parameter
138      * name, only the first value is included in this map.</p>
139      */
140     protected Map getRequestParameterMap() {
141 
142         return getExternalContext().getRequestParameterMap();
143 
144     }
145 
146 
147     /***
148      * <p>Return a <code>Map</code> of the session scope attributes
149      * for the current user.</p>
150      */
151     protected Map getSessionMap() {
152 
153         return getExternalContext().getSessionMap();
154 
155     }
156 
157 
158     // --------------------------------------------------- Bean Accessor Methods
159 
160 
161     /***
162      * <p>Return the named bean from request, session, or application scope.
163      * If this is a managed bean, it might also get created as a side effect.
164      * Return <code>null</code> if no such bean can be found or created.</p>
165      *
166      * @param name Name of the desired bean
167      */
168     protected Object getBean(String name) {
169 
170         FacesContext context = getFacesContext();
171         return context.getApplication().getVariableResolver().
172           resolveVariable(context, name);
173 
174     }
175 
176 
177     /***
178      * <p>Replace the value of any attribute stored in request scope,
179      * session scope, or application scope, under the specified name.
180      * If there is no such value, store this value as a new request
181      * scope attribute under the specified name.</p>
182      *
183      * @param name Name of the attribute to replace or create
184      * @param value Value to be stored
185      */
186     protected void setBean(String name, Object value) {
187 
188         setValue("#{" + name + "}", value);
189 
190     }
191 
192 
193     // -------------------------------------------- Expression Evauation Methods
194 
195 
196     /***
197      * <p>Evaluate the specified value binding expression and return
198      * the value it points at.</p>
199      *
200      * @param expr Value binding expression to be evaluated
201      */
202     protected Object getValue(String expr) {
203 
204         ValueBinding vb = getApplication().createValueBinding(expr);
205         return vb.getValue(getFacesContext());
206 
207     }
208 
209 
210     /***
211      * <p>Evaluate the specified value binding expression, and replace
212      * the value it points at.</p>
213      *
214      * @param expr Value binding expression pointing at a writeable property
215      * @param value New value to store there
216      */
217     protected void setValue(String expr, Object value) {
218 
219         ValueBinding vb = getApplication().createValueBinding(expr);
220         vb.setValue(getFacesContext(), value);
221 
222     }
223 
224 
225     // ----------------------------------------------- Save/Restore Data Methods
226 
227 
228     /***
229      * <p>The attribute name under which saved data will be stored on the
230      * view root component.</p>
231      */
232     private static final String DATA_KEY = "org.apache.shale.DATA";
233 
234 
235 
236     /***
237      * <p>Return the data object stored (typically when the component tree
238      * was previously rendered) under the specified key, if any; otherwise,
239      * return <code>null</code>.</p>
240      *
241      * <p><strong>IMPLEMENTATION NOTE:</strong> Data objects will become
242      * available only after the <em>Restore View</em> phase of the request
243      * processing lifecycle has been completed.  A common place to reinitialize
244      * state information, then, would be in the <code>preprocess()</code>
245      * event handler of a {@link ViewController} backing bean.</p>
246      *
247      * @param key Key under which to retrieve the requested data
248      */
249     public Object retrieveData(String key) {
250 
251         FacesContext context = getFacesContext();
252         if (context == null) {
253             return null;
254         }
255         UIViewRoot view = context.getViewRoot();
256         if (view == null) {
257             return null;
258         }
259         Map map = (Map) view.getAttributes().get(DATA_KEY);
260         if (map != null) {
261             return map.get(key);
262         } else {
263             return null;
264         }
265 
266     }
267 
268 
269     /***
270      * <p>Save the specified data object (which <strong>MUST</strong> be
271      * <code>Serializable</code>) under the specified key, such that it can
272      * be retrieved (via <code>getData()</code>) on a s subsequent request
273      * immediately after the component tree has been restored.</p>
274      *
275      * <p><strong>IMPLEMENTATION NOTE:</strong> In order to successfully save
276      * data objects, this method must be called before the <em>Render Response</em>
277      * phase of the request processing lifecycle is executed.  A common scenario
278      * is to save state information in the <code>prerender()</code> event handler
279      * of a {@link ViewController} backing bean.</p>
280      *
281      * @param key Key under which to store the requested data
282      * @param data Data object to be stored
283      */
284     public void saveData(String key, Object data) {
285 
286         Map map = (Map)
287            getFacesContext().getViewRoot().getAttributes().get(DATA_KEY);
288         if (map == null) {
289             map = new HashMap();
290             getFacesContext().getViewRoot().getAttributes().put(DATA_KEY, map);
291         }
292         map.put(key, data);
293 
294     }
295 
296 
297     // -------------------------------------------------- Erase Submitted Values
298 
299 
300     /***
301      * <p>Erase submitted values on all <code>EditableValueHolder</code>
302      * components in the current view.  This method should be called if
303      * you have input components bound to data values, submit the form,
304      * and then arbitrarily change the data that the binding points at
305      * without going through the <em>Update Model Values</em> phase of
306      * the request processing lifecycle.</p>
307      */
308     protected void erase() {
309 
310         UIComponent view = getFacesContext().getViewRoot();
311         if (view != null) {
312             erase(view);
313         }
314 
315     }
316 
317 
318     /***
319      * <p>Private helper method for <code>erase()</code> that recursively
320      * descends the component tree and performs the required processing.</p>
321      *
322      * @param component The component to be erased
323      */
324     private void erase(UIComponent component) {
325 
326         // Erase the component itself (if needed)
327         if (component instanceof EditableValueHolder) {
328             ((EditableValueHolder) component).setSubmittedValue(null);
329         }
330         // Process the facets and children of this component
331         Iterator kids = component.getFacetsAndChildren();
332         while (kids.hasNext()) {
333             erase((UIComponent) kids.next());
334         }
335 
336     }
337 
338 
339     // ----------------------------------------------- Request Parameter Methods
340 
341 
342     /***
343      * <p>Return the first (or only) value for the specified request parameter.
344      * If no such request parameter exists for the current requset, return
345      * <code>null</code> instead.</p>
346      *
347      * @param name Name of the request parameter to look for
348      */
349     public String getRequestParameter(String name) {
350 
351         return (String) getExternalContext().getRequestParameterMap().get(name);
352 
353     }
354 
355 
356     /***
357      * <p>Return an array of all the values for the specified request parameter,
358      * if there are any.  If no such request parameter exists for the current
359      * request, return <code>null</code> instead.</p>
360      *
361      * @param name Name of the request parameter to look for
362      */
363     public String[] getRequestParameterValues(String name) {
364 
365         return (String[])
366           getExternalContext().getRequestParameterValuesMap().get(name);
367 
368     }
369 
370 
371     // ------------------------------------------------------------- Log Methods
372 
373 
374     /***
375      * <p>Log the specified message to the server's log file.</p>
376      *
377      * @param message Message to be logged
378      */
379     protected void log(String message) {
380 
381         FacesContext context = getFacesContext();
382         ExternalContext econtext = null;
383         if (context != null) {
384             econtext = context.getExternalContext();
385         }
386         if (econtext != null) {
387             econtext.log(message);
388         } else {
389             System.out.println(message);
390         }
391 
392     }
393 
394 
395     /***
396      * <p>Log the specified message and exception to the server's log file.</p>
397      *
398      * @param message Message to be logged
399      * @param throwable Exception to be logged
400      */
401     protected void log(String message, Throwable throwable) {
402 
403         FacesContext context = getFacesContext();
404         ExternalContext econtext = null;
405         if (context != null) {
406             econtext = context.getExternalContext();
407         }
408         if (econtext != null) {
409             econtext.log(message, throwable);
410         } else {
411             System.out.println(message);
412             throwable.printStackTrace(System.out);
413         }
414 
415     }
416 
417 
418     // --------------------------------------------------------- Message Methods
419 
420 
421     /***
422      * <p>Enqueue a global <code>FacesMessage</code> (not associated with any
423      * particular component) containing the specified summary text and a
424      * message severity level of <code>FacesMessage.SEVERITY_INFO</code>.</p>
425      *
426      * @param summary Summary text for this message
427      */
428     protected void info(String summary) {
429 
430         getFacesContext().addMessage(null,
431           new FacesMessage(FacesMessage.SEVERITY_INFO, summary, null));
432 
433     }
434 
435 
436     /***
437      * <p>Enqueue a <code>FacesMessage</code> (associated with the
438      * specified component) containing the specified summary text and a
439      * message severity level of <code>FacesMessage.SEVERITY_INFO</code>.</p>
440      *
441      * @param component Component with which this message is associated
442      * @param summary Summary text for this message
443      */
444     protected void info(UIComponent component, String summary) {
445 
446         FacesContext context = getFacesContext();
447         context.addMessage(component.getClientId(context),
448            new FacesMessage(FacesMessage.SEVERITY_INFO, summary, null));
449 
450     }
451 
452 
453     /***
454      * <p>Enqueue a global <code>FacesMessage</code> (not associated with any
455      * particular component) containing the specified summary text and a
456      * message severity level of <code>FacesMessage.SEVERITY_WARN</code>.</p>
457      *
458      * @param summary Summary text for this message
459      */
460     protected void warn(String summary) {
461 
462         getFacesContext().addMessage(null,
463           new FacesMessage(FacesMessage.SEVERITY_WARN, summary, null));
464 
465     }
466 
467 
468     /***
469      * <p>Enqueue a <code>FacesMessage</code> (associated with the
470      * specified component) containing the specified summary text and a
471      * message severity level of <code>FacesMessage.SEVERITY_WARN</code>.</p>
472      *
473      * @param component Component with which this message is associated
474      * @param summary Summary text for this message
475      */
476     protected void warn(UIComponent component, String summary) {
477 
478         FacesContext context = getFacesContext();
479         context.addMessage(component.getClientId(context),
480            new FacesMessage(FacesMessage.SEVERITY_WARN, summary, null));
481 
482     }
483 
484 
485     /***
486      * <p>Enqueue a global <code>FacesMessage</code> (not associated with any
487      * particular component) containing the specified summary text and a
488      * message severity level of <code>FacesMessage.SEVERITY_ERROR</code>.</p>
489      *
490      * @param summary Summary text for this message
491      */
492     protected void error(String summary) {
493 
494         getFacesContext().addMessage(null,
495           new FacesMessage(FacesMessage.SEVERITY_ERROR, summary, null));
496 
497     }
498 
499 
500     /***
501      * <p>Enqueue a <code>FacesMessage</code> (associated with the
502      * specified component) containing the specified summary text and a
503      * message severity level of <code>FacesMessage.SEVERITY_ERROR</code>.</p>
504      *
505      * @param component Component with which this message is associated
506      * @param summary Summary text for this message
507      */
508     protected void error(UIComponent component, String summary) {
509 
510         FacesContext context = getFacesContext();
511         context.addMessage(component.getClientId(context),
512            new FacesMessage(FacesMessage.SEVERITY_ERROR, summary, null));
513 
514     }
515 
516 
517     /***
518      * <p>Enqueue a global <code>FacesMessage</code> (not associated with any
519      * particular component) containing the specified summary text and a
520      * message severity level of <code>FacesMessage.SEVERITY_FATAL</code>.</p>
521      *
522      * @param summary Summary text for this message
523      */
524     protected void fatal(String summary) {
525 
526         getFacesContext().addMessage(null,
527           new FacesMessage(FacesMessage.SEVERITY_FATAL, summary, null));
528 
529     }
530 
531 
532     /***
533      * <p>Enqueue a <code>FacesMessage</code> (associated with the
534      * specified component) containing the specified summary text and a
535      * message severity level of <code>FacesMessage.SEVERITY_FATAL</code>.</p>
536      *
537      * @param component Component with which this message is associated
538      * @param summary Summary text for this message
539      */
540     protected void fatal(UIComponent component, String summary) {
541 
542         FacesContext context = getFacesContext();
543         context.addMessage(component.getClientId(context),
544            new FacesMessage(FacesMessage.SEVERITY_FATAL, summary, null));
545 
546     }
547 
548 
549 }