001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package com.sun.rave.web.ui.appbase;
043:
044: import com.sun.rave.web.ui.appbase.faces.ViewHandlerImpl;
045: import java.util.HashMap;
046: import java.util.Iterator;
047: import java.util.List;
048: import java.util.Map;
049:
050: import javax.faces.FactoryFinder;
051: import javax.faces.application.Application;
052: import javax.faces.application.FacesMessage;
053: import javax.faces.component.EditableValueHolder;
054: import javax.faces.component.UIComponent;
055: import javax.faces.component.UIViewRoot;
056: import javax.faces.context.ExternalContext;
057: import javax.faces.context.FacesContext;
058: import javax.faces.el.ValueBinding;
059: import javax.faces.lifecycle.Lifecycle;
060: import javax.faces.lifecycle.LifecycleFactory;
061:
062: /**
063: * <p><strong>FacesBean</strong> is the abstract base class for all page beans,
064: * request scope data beans, session scope data beans, and application scope
065: * data beans that wish to participate in the provided JavaServer Faces
066: * integration support. Concrete subclasses of this class will typically
067: * be registered as managed beans, so that they get created on demand
068: * (and added to the relevant scope's attributes).</p>
069: *
070: * <p><strong>NOTE</strong> - These integration methods will operate
071: * successfully <em>only</em> within the lifetime of a JavaServer Faces
072: * request.</p>
073: */
074: public abstract class FacesBean {
075:
076: // ------------------------------------------------------------- Constructor
077:
078: public FacesBean() {
079: }
080:
081: // --------------------------------------------------- Convenience Accessors
082:
083: /**
084: * <p>Return the <code>Application</code> instance for the current
085: * web application.</p>
086: */
087: protected Application getApplication() {
088:
089: return FacesContext.getCurrentInstance().getApplication();
090:
091: }
092:
093: /**
094: * <p>Return a <code>Map</code> of the application scope attributes
095: * for this web application.</p>
096: */
097: protected Map getApplicationMap() {
098:
099: return getExternalContext().getApplicationMap();
100:
101: }
102:
103: /**
104: * <p>Return a <code>List</code> of the exceptions that have been
105: * logged, swallowed, and cached during the processing of this request
106: * so far. If there are no such cached exceptions, return <code>null</code>
107: * instead.</p>
108: *
109: * <p>The application runtime framework causes exceptions thrown from
110: * any of the following sources to be logged (to the application server's
111: * log), swallowed, and added to this list:</p>
112: * <ul>
113: * <li>Application lifecycle methods (<code>init()</code>, <code>preprocess()</code>,
114: * <code>prerender()</code>, and <code>destroy()</code>) on an
115: * {@link AbstractPageBean}.</li>
116: * <li>Phase listener methods (<code>beforeXxx()</code>, <code>afterXxx()</code>)
117: * on an {@link AbstractPageBean}.</li>
118: * <li>Exception thrown during the rendering of the selected view during
119: * <em>Render Response</em> phase of the request processing lifecycle.</li>
120: * </ul>
121: */
122: protected List getCachedExceptions() {
123:
124: return (List) getFacesContext().getExternalContext()
125: .getRequestMap().get(ViewHandlerImpl.CACHED_EXCEPTIONS);
126:
127: }
128:
129: /**
130: * <p>Return the <code>FacesContext</code> instance for the current
131: * request. This method has been restored for backwards compatibilty.</p>
132: *
133: * @deprecated Use <code>getFacesContext()</code> instead
134: */
135: protected FacesContext getContext() {
136:
137: return getFacesContext();
138:
139: }
140:
141: /**
142: * <p>Return the <code>ExternalContext</code> instance for the
143: * current request.</p>
144: */
145: protected ExternalContext getExternalContext() {
146:
147: return FacesContext.getCurrentInstance().getExternalContext();
148:
149: }
150:
151: /**
152: * <p>Return the <code>FacesContext</code> instance for the current
153: * request.</p>
154: */
155: protected FacesContext getFacesContext() {
156:
157: return FacesContext.getCurrentInstance();
158:
159: }
160:
161: /**
162: * <p>Return the configured <code>Lifecycle</code> instance for the
163: * current web application.</p>
164: */
165: protected Lifecycle getLifecycle() {
166:
167: String lifecycleId = getExternalContext().getInitParameter(
168: "javax.faces.LIFECYCLE_ID"); //NOI18N
169: if (lifecycleId == null || lifecycleId.length() == 0) {
170: lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;
171: }
172: LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
173: .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
174: return lifecycleFactory.getLifecycle(lifecycleId);
175:
176: }
177:
178: /**
179: * <p>Return a <code>Map</code> of the request scope attributes for
180: * the current request.</p>
181: */
182: protected Map getRequestMap() {
183:
184: return getExternalContext().getRequestMap();
185:
186: }
187:
188: /**
189: * <p>Return a <code>Map</code> of the session scope attributes for the
190: * current user's session. Note that calling this method will cause a
191: * session to be created if there is not already one associated with
192: * this request.</p>
193: */
194: protected Map getSessionMap() {
195:
196: return getExternalContext().getSessionMap();
197:
198: }
199:
200: // ------------------------------------------------------- Bean Manipulation
201:
202: /**
203: * <p>Return any attribute stored in request scope, session scope, or
204: * application scope under the specified name. If no such
205: * attribute is found, and if this name is the registered name of a
206: * managed bean, cause a new instance of this managed bean to be created
207: * (and stored in an appropriate scope, if necessary) and returned.
208: * If no attribute exists, and no managed bean was created, return
209: * <code>null</code>.</p>
210: *
211: * @param name Name of the attribute to be retrieved
212: */
213: protected Object getBean(String name) {
214:
215: return getApplication().getVariableResolver().resolveVariable(
216: getFacesContext(), name);
217:
218: }
219:
220: /**
221: * <p>Replace the value of any attribute stored in request scope,
222: * session scope, or application scope under the specified name. If there
223: * is no such attribute, create a new request scope attribute under this
224: * name, and store the value there.</p>
225: */
226: protected void setBean(String name, Object value) {
227:
228: setValue("#{" + name + "}", value); //NOI18N
229:
230: }
231:
232: // ----------------------------------------------- Save/Restore Data Methods
233:
234: /**
235: * <p>The attribute name under which saved data will be stored on the
236: * view root component.</p>
237: */
238: private static final String DATA_KEY = "com.sun.rave.web.ui.appbase.DATA";
239:
240: /**
241: * <p>Return the data object stored (typically when the component tree
242: * was previously rendered) under the specified key, if any; otherwise,
243: * return <code>null</code>.</p>
244: *
245: * <p><strong>IMPLEMENTATION NOTE:</strong> Data objects will become
246: * available only after the <em>Restore View</em> phase of the request
247: * processing lifecycle has been completed. A common place to reinitialize
248: * state information, then, would be in the <code>preprocess()</code>
249: * event handler of a page bean.</p>
250: *
251: * @param key Key under which to retrieve the requested data
252: */
253: public Object retrieveData(String key) {
254:
255: FacesContext context = getFacesContext();
256: if (context == null) {
257: return null;
258: }
259: UIViewRoot view = context.getViewRoot();
260: if (view == null) {
261: return null;
262: }
263: Map map = (Map) view.getAttributes().get(DATA_KEY);
264: if (map != null) {
265: return map.get(key);
266: } else {
267: return null;
268: }
269:
270: }
271:
272: /**
273: * <p>Save the specified data object (which <strong>MUST</strong> be
274: * <code>Serializable</code>) under the specified key, such that it can
275: * be retrieved (via <code>getData()</code>) on a s subsequent request
276: * immediately after the component tree has been restored.</p>
277: *
278: * <p><strong>IMPLEMENTATION NOTE:</strong> In order to successfully save
279: * data objects, this method must be called before the <em>Render Response</em>
280: * phase of the request processing lifecycle is executed. A common scenario
281: * is to save state information in the <code>prerender()</code> event handler
282: * of a page bean.</p>
283: *
284: * @param key Key under which to store the requested data
285: * @param data Data object to be stored
286: */
287: public void saveData(String key, Object data) {
288:
289: Map map = (Map) getFacesContext().getViewRoot().getAttributes()
290: .get(DATA_KEY);
291: if (map == null) {
292: map = new HashMap();
293: getFacesContext().getViewRoot().getAttributes().put(
294: DATA_KEY, map);
295: }
296: map.put(key, data);
297:
298: }
299:
300: // ------------------------------------------------------ Value Manipulation
301:
302: /**
303: * <p>Evaluate the specified value binding expression, and return
304: * the value that it points at.</p>
305: *
306: * @param expr Value binding expression (including delimiters)
307: */
308: protected Object getValue(String expr) {
309:
310: ValueBinding vb = getApplication().createValueBinding(expr);
311: return (vb.getValue(getFacesContext()));
312:
313: }
314:
315: /**
316: * <p>Evaluate the specified value binding expression, and update
317: * the value that it points at.</p>
318: *
319: * @param expr Value binding expression (including delimiters) that
320: * must point at a writeable property
321: * @param value New value for the property pointed at by <code>expr</code>
322: */
323: protected void setValue(String expr, Object value) {
324:
325: ValueBinding vb = getApplication().createValueBinding(expr);
326: vb.setValue(getFacesContext(), value);
327:
328: }
329:
330: // -------------------------------------------------- Component Manipulation
331:
332: /**
333: * <p>Erase previously submitted values for all input components on this
334: * page. This method <strong>MUST</strong> be called if you have bound
335: * input components to database columns, and then arbitrarily navigate
336: * the underlying <code>RowSet</code> to a different row in an event
337: * handler method.</p>
338: */
339: protected void erase() {
340:
341: erase(getFacesContext().getViewRoot());
342:
343: }
344:
345: /**
346: * <p>Private helper method for <code>erase()</code> that recursively
347: * descends the component tree and performs the required processing.</p>
348: *
349: * @param component The component to be erased
350: */
351: private void erase(UIComponent component) {
352:
353: // Erase the component itself (if needed)
354: if (component instanceof EditableValueHolder) {
355: ((EditableValueHolder) component).setSubmittedValue(null);
356: }
357: // Process the facets and children of this component
358: Iterator kids = component.getFacetsAndChildren();
359: while (kids.hasNext()) {
360: erase((UIComponent) kids.next());
361: }
362:
363: }
364:
365: // ------------------------------------------------------------- Log Methods
366:
367: /**
368: * <p>Log the specified message to the container's log file.</p>
369: *
370: * @param message Message to be logged
371: */
372: protected void log(String message) {
373:
374: FacesContext context = FacesContext.getCurrentInstance();
375: if (context != null) {
376: getExternalContext().log(message);
377: } else {
378: System.out.println(message);
379: }
380:
381: }
382:
383: /**
384: * <p>Log the specified message and exception to the container's
385: * log file.</p>
386: *
387: * @param message Message to be logged
388: * @param throwable Exception to be logged
389: */
390: protected void log(String message, Throwable throwable) {
391:
392: FacesContext context = FacesContext.getCurrentInstance();
393: if (context != null) {
394: getExternalContext().log(message, throwable);
395: } else {
396: System.out.println(message);
397: throwable.printStackTrace(System.out);
398: }
399:
400: }
401:
402: // --------------------------------------------------------- Message Methods
403:
404: /**
405: * <p>Enqueue a global <code>FacesMessage</code> (not associated
406: * with any particular componen) containing the specified summary text
407: * and a message severity level of <code>FacesMessage.SEVERITY_INFO</code>.
408: * </p>
409: *
410: * @param summary Summary text for this message
411: */
412: protected void info(String summary) {
413:
414: getFacesContext().addMessage(
415: null,
416: new FacesMessage(FacesMessage.SEVERITY_INFO, summary,
417: null));
418:
419: }
420:
421: /**
422: * <p>Enqueue a <code>FacesMessage</code> associated with the
423: * specified component, containing the specified summary text
424: * and a message severity level of <code>FacesMessage.SEVERITY_INFO</code>.
425: * </p>
426: *
427: * @param component Component with which this message is associated
428: * @param summary Summary text for this message
429: */
430: protected void info(UIComponent component, String summary) {
431:
432: getFacesContext().addMessage(
433: component.getClientId(getFacesContext()),
434: new FacesMessage(FacesMessage.SEVERITY_INFO, summary,
435: null));
436:
437: }
438:
439: /**
440: * <p>Enqueue a global <code>FacesMessage</code> (not associated
441: * with any particular componen) containing the specified summary text
442: * and a message severity level of <code>FacesMessage.SEVERITY_WARN</code>.
443: * </p>
444: *
445: * @param summary Summary text for this message
446: */
447: protected void warn(String summary) {
448:
449: getFacesContext().addMessage(
450: null,
451: new FacesMessage(FacesMessage.SEVERITY_WARN, summary,
452: null));
453:
454: }
455:
456: /**
457: * <p>Enqueue a <code>FacesMessage</code> associated with the
458: * specified component, containing the specified summary text
459: * and a message severity level of <code>FacesMessage.SEVERITY_WARN</code>.
460: * </p>
461: *
462: * @param component Component with which this message is associated
463: * @param summary Summary text for this message
464: */
465: protected void warn(UIComponent component, String summary) {
466:
467: getFacesContext().addMessage(
468: component.getClientId(getFacesContext()),
469: new FacesMessage(FacesMessage.SEVERITY_WARN, summary,
470: null));
471:
472: }
473:
474: /**
475: * <p>Enqueue a global <code>FacesMessage</code> (not associated
476: * with any particular componen) containing the specified summary text
477: * and a message severity level of <code>FacesMessage.SEVERITY_ERROR</code>.
478: * </p>
479: *
480: * @param summary Summary text for this message
481: */
482: protected void error(String summary) {
483:
484: getFacesContext().addMessage(
485: null,
486: new FacesMessage(FacesMessage.SEVERITY_ERROR, summary,
487: null));
488:
489: }
490:
491: /**
492: * <p>Enqueue a <code>FacesMessage</code> associated with the
493: * specified component, containing the specified summary text
494: * and a message severity level of <code>FacesMessage.SEVERITY_ERROR</code>.
495: * </p>
496: *
497: * @param component Component with which this message is associated
498: * @param summary Summary text for this message
499: */
500: protected void error(UIComponent component, String summary) {
501:
502: getFacesContext().addMessage(
503: component.getClientId(getFacesContext()),
504: new FacesMessage(FacesMessage.SEVERITY_ERROR, summary,
505: null));
506:
507: }
508:
509: /**
510: * <p>Enqueue a global <code>FacesMessage</code> (not associated
511: * with any particular componen) containing the specified summary text
512: * and a message severity level of <code>FacesMessage.SEVERITY_FATAL</code>.
513: * </p>
514: *
515: * @param summary Summary text for this message
516: */
517: protected void fatal(String summary) {
518:
519: getFacesContext().addMessage(
520: null,
521: new FacesMessage(FacesMessage.SEVERITY_FATAL, summary,
522: null));
523:
524: }
525:
526: /**
527: * <p>Enqueue a <code>FacesMessage</code> associated with the
528: * specified component, containing the specified summary text
529: * and a message severity level of <code>FacesMessage.SEVERITY_FATAL</code>.
530: * </p>
531: *
532: * @param component Component with which this message is associated
533: * @param summary Summary text for this message
534: */
535: protected void fatal(UIComponent component, String summary) {
536:
537: getFacesContext().addMessage(
538: component.getClientId(getFacesContext()),
539: new FacesMessage(FacesMessage.SEVERITY_FATAL, summary,
540: null));
541:
542: }
543:
544: }
|