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.jsfcl.app;
043:
044: import java.util.Iterator;
045: import java.util.Map;
046:
047: import javax.faces.FactoryFinder;
048: import javax.faces.application.Application;
049: import javax.faces.application.FacesMessage;
050: import javax.faces.component.EditableValueHolder;
051: import javax.faces.component.UIComponent;
052: import javax.faces.context.ExternalContext;
053: import javax.faces.context.FacesContext;
054: import javax.faces.el.ValueBinding;
055: import javax.faces.event.PhaseEvent;
056: import javax.faces.event.PhaseId;
057: import javax.faces.event.PhaseListener;
058: import javax.faces.lifecycle.Lifecycle;
059: import javax.faces.lifecycle.LifecycleFactory;
060:
061: /**
062: * <p><strong>FacesBean</strong> is the abstract base class for all page beans,
063: * session scope data beans, and application scope data beans that wish to
064: * participate in the request processing lifecycle. Concrete subclasses of
065: * this class will typically be registered as managed beans, so that they get
066: * created on demand (and added to the relevant scope's attributes).</p>
067: */
068: public abstract class FacesBean implements PhaseListener {
069:
070: // ------------------------------------------------------------- Constructor
071:
072: public FacesBean() {
073: }
074:
075: // --------------------------------------------------- Convenience Accessors
076:
077: /**
078: * <p>Return the <code>Application</code> instance for the current
079: * web application.</p>
080: */
081: protected Application getApplication() {
082: return FacesContext.getCurrentInstance().getApplication();
083: }
084:
085: /**
086: * <p>Return a <code>Map</code> of the application scope attributes
087: * for this web application.</p>
088: */
089: protected Map getApplicationMap() {
090: return getExternalContext().getApplicationMap();
091: }
092:
093: /**
094: * <p>Return the <code>FacesContext</code> instance for the current
095: * request. This method has been restored for backwards compatibilty.</p>
096: */
097: protected FacesContext getContext() {
098: return getFacesContext();
099: }
100:
101: /**
102: * <p>Return the <code>ExternalContext</code> instance for the
103: * current request.</p>
104: */
105: protected ExternalContext getExternalContext() {
106: return FacesContext.getCurrentInstance().getExternalContext();
107: }
108:
109: /**
110: * <p>Return the <code>FacesContext</code> instance for the current
111: * request.</p>
112: */
113: protected FacesContext getFacesContext() {
114: return FacesContext.getCurrentInstance();
115: }
116:
117: /**
118: * <p>Return the configured <code>Lifecycle</code> instance for the
119: * current web application.</p>
120: */
121: protected Lifecycle getLifecycle() {
122: String lifecycleId = getExternalContext().getInitParameter(
123: "javax.faces.LIFECYCLE_ID"); //NOI18N
124: if (lifecycleId == null || lifecycleId.length() == 0) {
125: lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;
126: }
127: LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
128: .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
129: return lifecycleFactory.getLifecycle(lifecycleId);
130: }
131:
132: /**
133: * <p>Return a <code>Map</code> of the request scope attributes for
134: * the current request.</p>
135: */
136: protected Map getRequestMap() {
137: return getExternalContext().getRequestMap();
138: }
139:
140: /**
141: * <p>Return a <code>Map</code> of the session scope attributes for the
142: * current user's session. Note that calling this method will cause a
143: * session to be created if there is not already one associated with
144: * this request.</p>
145: */
146: protected Map getSessionMap() {
147: return getExternalContext().getSessionMap();
148: }
149:
150: // ------------------------------------------------------- Bean Manipulation
151:
152: /**
153: * <p>Return any attribute stored in request scope, session scope, or
154: * application scope under the specified name. If no such
155: * attribute is found, and if this name is the registered name of a
156: * managed bean, cause a new instance of this managed bean to be created
157: * (and stored in an appropriate scope, if necessary) and returned.
158: * If no attribute exists, and no managed bean was created, return
159: * <code>null</code>.</p>
160: *
161: * @param name Name of the attribute to be retrieved
162: */
163: protected Object getBean(String name) {
164: return getApplication().getVariableResolver().resolveVariable(
165: getFacesContext(), name);
166: }
167:
168: /**
169: * <p>Replace the value of any attribute stored in request scope,
170: * session scope, or application scope under the specified name. If there
171: * is no such attribute, create a new request scope attribute under this
172: * name, and store the value there.</p>
173: */
174: protected void setBean(String name, Object value) {
175: setValue("#{" + name + "}", value); //NOI18N
176: }
177:
178: // ------------------------------------------------------ Value Manipulation
179:
180: /**
181: * <p>Evaluate the specified value binding expression, and return
182: * the value that it points at.</p>
183: *
184: * @param expr Value binding expression (including delimiters)
185: */
186: protected Object getValue(String expr) {
187: ValueBinding vb = getApplication().createValueBinding(expr);
188: return (vb.getValue(getFacesContext()));
189: }
190:
191: /**
192: * <p>Evaluate the specified value binding expression, and update
193: * the value that it points at.</p>
194: *
195: * @param expr Value binding expression (including delimiters) that
196: * must point at a writeable property
197: * @param value New value for the property pointed at by <code>expr</code>
198: */
199: protected void setValue(String expr, Object value) {
200: ValueBinding vb = getApplication().createValueBinding(expr);
201: vb.setValue(getFacesContext(), value);
202: }
203:
204: // ----------------------------------------------------------- PhaseListener
205:
206: /**
207: * <p>Call through to the "before" lifecycle callback method
208: * for the current phase.</p>
209: *
210: * @param phaseEvent <code>PhaseEvent</code> to be processed
211: */
212: public void beforePhase(PhaseEvent phaseEvent) {
213: PhaseId phaseId = phaseEvent.getPhaseId();
214: if (PhaseId.RESTORE_VIEW.equals(phaseId)) {
215: beforeRestoreView();
216: } else if (PhaseId.APPLY_REQUEST_VALUES.equals(phaseId)) {
217: beforeApplyRequestValues();
218: } else if (PhaseId.PROCESS_VALIDATIONS.equals(phaseId)) {
219: beforeProcessValidations();
220: } else if (PhaseId.UPDATE_MODEL_VALUES.equals(phaseId)) {
221: beforeUpdateModelValues();
222: } else if (PhaseId.INVOKE_APPLICATION.equals(phaseId)) {
223: beforeInvokeApplication();
224: } else if (PhaseId.RENDER_RESPONSE.equals(phaseId)) {
225: beforeRenderResponse();
226: }
227: }
228:
229: /**
230: * <p>Call through to the "after" lifecycle callback method
231: * for the current phase.</p>
232: *
233: * @param phaseEvent <code>PhaseEvent</code> to be processed
234: */
235: public void afterPhase(PhaseEvent phaseEvent) {
236: PhaseId phaseId = phaseEvent.getPhaseId();
237: if (PhaseId.RESTORE_VIEW.equals(phaseId)) {
238: afterRestoreView();
239: } else if (PhaseId.APPLY_REQUEST_VALUES.equals(phaseId)) {
240: afterApplyRequestValues();
241: } else if (PhaseId.PROCESS_VALIDATIONS.equals(phaseId)) {
242: afterProcessValidations();
243: } else if (PhaseId.UPDATE_MODEL_VALUES.equals(phaseId)) {
244: afterUpdateModelValues();
245: } else if (PhaseId.INVOKE_APPLICATION.equals(phaseId)) {
246: afterInvokeApplication();
247: } else if (PhaseId.RENDER_RESPONSE.equals(phaseId)) {
248: afterRenderResponse();
249: }
250: }
251:
252: /**
253: * <p>Return <code>PhaseId.ANY_PHASE</code> to indicate that we are
254: * interested in all phases.</p>
255: */
256: public PhaseId getPhaseId() {
257: return PhaseId.ANY_PHASE;
258: }
259:
260: // ----------------------------------------------------- Lifecycle Callbacks
261:
262: // These methods are called by beforePhase() and afterPhase() as appropriate
263: // and allow subclasses to perform additional tasks at the corresponding
264: // moment in the request processing lifecycle for each request. The default
265: // implementations do nothing.
266:
267: protected void beforeRestoreView() {
268: }
269:
270: protected void afterRestoreView() {
271: }
272:
273: protected void beforeApplyRequestValues() {
274: }
275:
276: protected void afterApplyRequestValues() {
277: }
278:
279: protected void beforeProcessValidations() {
280: }
281:
282: protected void afterProcessValidations() {
283: }
284:
285: protected void beforeUpdateModelValues() {
286: }
287:
288: protected void afterUpdateModelValues() {
289: }
290:
291: protected void beforeInvokeApplication() {
292: }
293:
294: protected void afterInvokeApplication() {
295: }
296:
297: protected void beforeRenderResponse() {
298: }
299:
300: protected void afterRenderResponse() {
301: }
302:
303: // ------------------------------------------------------- Phase Processing
304:
305: /**
306: * <p>Return <code>true</code> if the current request was a post back
307: * for an existing view, rather than the creation of a new view. The
308: * result of this method may be used to conditionally execute one time
309: * setup that is only required when a page is first displayed.</p>
310: */
311: protected boolean isPostBack() {
312:
313: return getExternalContext().getRequestMap().get(
314: ViewHandlerImpl.CREATED_VIEW) == null;
315:
316: }
317:
318: /**
319: * <p>Skip any remaining request processing lifecycle phases for the
320: * current request, and go immediately to <em>Render Response</em>
321: * phase. This method is typically invoked when you want to throw
322: * away input values provided by the user, instead of processing them.</p>
323: */
324: protected void renderResponse() {
325: getFacesContext().renderResponse();
326: }
327:
328: // -------------------------------------------------- Component Manipulation
329:
330: /**
331: * <p>Erase previously submitted values for all input components on this
332: * page. This method <strong>MUST</strong> be called if you have bound
333: * input components to database columns, and then arbitrarily navigate
334: * the underlying <code>RowSet</code> to a different row in an event
335: * handler method.</p>
336: */
337: protected void erase() {
338: erase(getFacesContext().getViewRoot());
339: }
340:
341: /**
342: * <p>Private helper method for <code>erase()</code> that recursively
343: * descends the component tree and performs the required processing.</p>
344: *
345: * @param component The component to be erased
346: */
347: private void erase(UIComponent component) {
348: // Erase the component itself (if needed)
349: if (component instanceof EditableValueHolder) {
350: ((EditableValueHolder) component).setSubmittedValue(null);
351: }
352: // Process the facets and children of this component
353: Iterator kids = component.getFacetsAndChildren();
354: while (kids.hasNext()) {
355: erase((UIComponent) kids.next());
356: }
357: }
358:
359: // ------------------------------------------------------------- Log Methods
360:
361: /**
362: * <p>Log the specified message to the container's log file.</p>
363: *
364: * @param message Message to be logged
365: */
366: protected void log(String message) {
367: getExternalContext().log(message);
368: }
369:
370: /**
371: * <p>Log the specified message and exception to the container's
372: * log file.</p>
373: *
374: * @param message Message to be logged
375: * @param throwable Exception to be logged
376: */
377: protected void log(String message, Throwable throwable) {
378: getExternalContext().log(message, throwable);
379: }
380:
381: // --------------------------------------------------------- Message Methods
382:
383: /**
384: * <p>Enqueue a global <code>FacesMessage</code> (not associated
385: * with any particular componen) containing the specified summary text
386: * and a message severity level of <code>FacesMessage.SEVERITY_INFO</code>.
387: * </p>
388: *
389: * @param summary Summary text for this message
390: */
391: protected void info(String summary) {
392: getFacesContext().addMessage(
393: null,
394: new FacesMessage(FacesMessage.SEVERITY_INFO, summary,
395: null));
396: }
397:
398: /**
399: * <p>Enqueue a <code>FacesMessage</code> associated with the
400: * specified component, containing the specified summary text
401: * and a message severity level of <code>FacesMessage.SEVERITY_INFO</code>.
402: * </p>
403: *
404: * @param component Component with which this message is associated
405: * @param summary Summary text for this message
406: */
407: protected void info(UIComponent component, String summary) {
408: getFacesContext().addMessage(
409: component.getClientId(getFacesContext()),
410: new FacesMessage(FacesMessage.SEVERITY_INFO, summary,
411: null));
412: }
413:
414: /**
415: * <p>Enqueue a global <code>FacesMessage</code> (not associated
416: * with any particular componen) containing the specified summary text
417: * and a message severity level of <code>FacesMessage.SEVERITY_WARN</code>.
418: * </p>
419: *
420: * @param summary Summary text for this message
421: */
422: protected void warn(String summary) {
423: getFacesContext().addMessage(
424: null,
425: new FacesMessage(FacesMessage.SEVERITY_WARN, summary,
426: null));
427: }
428:
429: /**
430: * <p>Enqueue a <code>FacesMessage</code> associated with the
431: * specified component, containing the specified summary text
432: * and a message severity level of <code>FacesMessage.SEVERITY_WARN</code>.
433: * </p>
434: *
435: * @param component Component with which this message is associated
436: * @param summary Summary text for this message
437: */
438: protected void warn(UIComponent component, String summary) {
439: getFacesContext().addMessage(
440: component.getClientId(getFacesContext()),
441: new FacesMessage(FacesMessage.SEVERITY_WARN, summary,
442: null));
443: }
444:
445: /**
446: * <p>Enqueue a global <code>FacesMessage</code> (not associated
447: * with any particular componen) containing the specified summary text
448: * and a message severity level of <code>FacesMessage.SEVERITY_ERROR</code>.
449: * </p>
450: *
451: * @param summary Summary text for this message
452: */
453: protected void error(String summary) {
454: getFacesContext().addMessage(
455: null,
456: new FacesMessage(FacesMessage.SEVERITY_ERROR, summary,
457: null));
458: }
459:
460: /**
461: * <p>Enqueue a <code>FacesMessage</code> associated with the
462: * specified component, containing the specified summary text
463: * and a message severity level of <code>FacesMessage.SEVERITY_ERROR</code>.
464: * </p>
465: *
466: * @param component Component with which this message is associated
467: * @param summary Summary text for this message
468: */
469: protected void error(UIComponent component, String summary) {
470: getFacesContext().addMessage(
471: component.getClientId(getFacesContext()),
472: new FacesMessage(FacesMessage.SEVERITY_ERROR, summary,
473: null));
474: }
475:
476: /**
477: * <p>Enqueue a global <code>FacesMessage</code> (not associated
478: * with any particular componen) containing the specified summary text
479: * and a message severity level of <code>FacesMessage.SEVERITY_FATAL</code>.
480: * </p>
481: *
482: * @param summary Summary text for this message
483: */
484: protected void fatal(String summary) {
485: getFacesContext().addMessage(
486: null,
487: new FacesMessage(FacesMessage.SEVERITY_FATAL, summary,
488: null));
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_FATAL</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 fatal(UIComponent component, String summary) {
501: getFacesContext().addMessage(
502: component.getClientId(getFacesContext()),
503: new FacesMessage(FacesMessage.SEVERITY_FATAL, summary,
504: null));
505: }
506: }
|