2009/05/20 - Apache Shale has been retired.
For more information, please explore the Attic.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shale.dialog.faces;
19
20 import java.util.Map;
21
22 import javax.faces.context.FacesContext;
23 import javax.faces.event.PhaseEvent;
24 import javax.faces.event.PhaseId;
25 import javax.faces.event.PhaseListener;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.shale.dialog.Constants;
30 import org.apache.shale.dialog.DialogContext;
31 import org.apache.shale.dialog.DialogContextListener;
32 import org.apache.shale.dialog.DialogContextManager;
33 import org.apache.shale.dialog.DialogHelper;
34
35 /***
36 * <p>Phase listener that saves and restores the dialog identifier for the
37 * currently active dialog, if any. Based on the presence of certain
38 * request parameters, it can also cause a new {@link DialogContext}
39 * instance to be created and started, optionally associated with a parent
40 * {@link DialogContext} instance also belonging to the same user.</p>
41 *
42 * @since 1.0.4
43 */
44 public final class DialogPhaseListener implements PhaseListener {
45
46
47
48
49
50 /***
51 * Serial version UID.
52 */
53 private static final long serialVersionUID = 5219990658057949928L;
54
55
56 /***
57 * <p>Creates a new instance of DialogPhaseListener.</p>
58 */
59 public DialogPhaseListener() {
60 if (log.isInfoEnabled()) {
61 log.info("Instantiating DialogPhaseListener()");
62 }
63 }
64
65
66
67
68
69 /***
70 * <p>Generic attribute name (on the view root component of the current
71 * JSF component tree) under which the context identifier for the
72 * dialog instance that is current for this view (if any) should be
73 * stored and retrieved.</p>
74 */
75 private static final String CONTEXT_ID_ATTR =
76 "org.apache.shale.dialog.CONTEXT_ID";
77
78
79 /***
80 * <p>Generic attribute name (on the view root component of the current
81 * JSF component tree) under which the opaque state information for the
82 * current {@link DialogContext} instance (if any) should be stored and
83 * retrieved.</p>
84 */
85 private static final String CONTEXT_OPAQUE_ATTR =
86 "org.apache.shale.dialog.OPAQUE_STATE";
87
88
89
90
91
92 /***
93 * <p>The <code>Log</code> instance for this class.</p>
94 */
95 private Log log = LogFactory.getLog(DialogPhaseListener.class);
96
97
98
99
100
101 /***
102 * <p>Return the phase identifier we are interested in.</p>
103 *
104 * @return The phase identifier of interest
105 */
106 public PhaseId getPhaseId() {
107 return PhaseId.ANY_PHASE;
108 }
109
110
111 /***
112 * <p>After the <em>Restore View</em> phase, retrieve the current
113 * dialog identifier (if any), and restore the corresponding
114 * {@link DialogContext}. If this view is not currently executing
115 * a {@link DialogContext} instance, optionally create a new
116 * instance based o the presence of request parameters.</p>
117 *
118 * @param event The phase event to be processed
119 */
120 public void afterPhase(PhaseEvent event) {
121
122 if (log.isTraceEnabled()) {
123 log.trace("afterPhase(phaseId='" + event.getPhaseId()
124 + "',facesContext='" + event.getFacesContext() + "')");
125 }
126
127 if (PhaseId.RESTORE_VIEW.equals(event.getPhaseId())) {
128 afterRestoreView(event.getFacesContext());
129 } else if (PhaseId.RENDER_RESPONSE.equals(event.getPhaseId())) {
130 afterRenderResponse(event.getFacesContext());
131 }
132
133 }
134
135
136 /***
137 * <p>Before the <em>Render Response</em> phase, acquire the current
138 * dialog identifier (if any), and store it in the view.</p>
139 *
140 * @param event The phase event to be processed
141 */
142 public void beforePhase(PhaseEvent event) {
143
144 if (log.isTraceEnabled()) {
145 log.trace("beforePhase(phaseId='" + event.getPhaseId()
146 + "',facesContext='" + event.getFacesContext() + "')");
147 }
148
149 if (PhaseId.RENDER_RESPONSE.equals(event.getPhaseId())) {
150 beforeRenderResponse(event.getFacesContext());
151 }
152
153 }
154
155
156
157
158
159 /***
160 * <p>Fire an <code>onActivate</code> event to all registered listeners
161 * of the specified {@link DialogContext} instance.</p>
162 *
163 * @param dcontext {@link DialogContext} instance being activated
164 */
165 private void activate(DialogContext dcontext) {
166
167 DialogContextListener[] listeners = dcontext.getDialogContextListeners();
168 for (int i = 0; i < listeners.length; i++) {
169 listeners[i].onActivate();
170 }
171
172 }
173
174
175 /***
176 * <p>Perform the required processing after the <em>Render Response</em>
177 * phase of request processing lifecycle has been completed for the
178 * current request:</p>
179 * <ul>
180 * <li>If there is a currently active {@link DialogContext} instance
181 * for the current request, fire an <code>onPassivate()</code> event
182 * to all of its registered {@link DialogContextListener}s.</li>
183 * </ul>
184 *
185 * @param context <code>FacesContext</code> for the current request
186 *
187 * @since 1.1.0
188 */
189 private void afterRenderResponse(FacesContext context) {
190
191 DialogContext dcontext = DialogHelper.getDialogContext(context);
192 if (dcontext != null) {
193 passivate(dcontext);
194 }
195
196 }
197
198
199 /***
200 * <p>Perform the required processing after the <em>Restore View Phase</em>
201 * of the request processing lifecycle has been completed for the current
202 * request:</p>
203 * <ul>
204 * <li>If the restored view contains an appropriate attribute containing
205 * the <code>id</code> of an existing {@link DialogContext} instance
206 * for the current user, this instance is restored.<li>
207 * <li>If there is no such <code>id</code> of an existing {@link DialogContext}
208 * instance, AND if the request includes a parameter specifying a
209 * dialog name, a new instance of the specified dialog will be created
210 * and associated with the current view.</li>
211 * <li>In the latter case, if the request also includes a parameter specifying
212 * the <code>id</code> of an active {@link DialogContext} instance for
213 * the current user, that existing instance will be configured as the
214 * parent {@link DialogContext} instance for the newly created instance.</li>
215 * <li>(Since 1.1.0) If a {@link DialogContext} instance was restored
216 * for the current request, fire an <code>onActivate()</code>
217 * event to all of its registered {@link DialogContextListener}s.</li>
218 * </ul>
219 *
220 * @param context <code>FacesContext</code> for the current request
221 */
222 private void afterRestoreView(FacesContext context) {
223
224
225
226
227
228
229 String id = (String)
230 context.getViewRoot().getAttributes().get(CONTEXT_ID_ATTR);
231 if (id == null) {
232 id = (String) context.getExternalContext().getRequestParameterMap().
233 get(Constants.DIALOG_ID);
234 }
235 if (id != null) {
236 DialogContext dcontext = restore(context, id);
237 if (dcontext != null) {
238 activate(dcontext);
239 }
240 return;
241 }
242
243
244
245
246
247
248
249 String dialogName = (String) context.getExternalContext().
250 getRequestParameterMap().get(Constants.DIALOG_NAME);
251 String parentId = (String) context.getExternalContext().
252 getRequestParameterMap().get(Constants.PARENT_ID);
253 if (dialogName != null) {
254
255
256 DialogContext dcontext = create(context, dialogName, parentId);
257 if (dcontext == null) {
258 return;
259 }
260
261
262 dcontext.start(context);
263 if (log.isDebugEnabled()) {
264 log.debug("afterRestoreView() creating dialog context with id '"
265 + id + "' for FacesContext instance '"
266 + context + "' associated with parent dialog context id '"
267 + parentId + "' and advancing to viewId '"
268 + context.getViewRoot().getViewId() + "'");
269 }
270
271 }
272
273 }
274
275
276 /***
277 * <p>Before the <em>Render Response</em> phase, acquire the current
278 * dialog identifier (if any), along with any corresponding opaque
279 * state information, and store it in the view.</p>
280 *
281 * @param context <code>FacesContext</code> for the current request
282 */
283 private void beforeRenderResponse(FacesContext context) {
284
285 DialogContext dcontext = (DialogContext)
286 context.getExternalContext().getRequestMap().get(Constants.CONTEXT_BEAN);
287 Map map = context.getViewRoot().getAttributes();
288 if ((dcontext != null) && dcontext.isActive()) {
289 if (log.isDebugEnabled()) {
290 log.debug("beforeRenderResponse() saving dialog context id '"
291 + dcontext.getId()
292 + "' for FacesContext instance '"
293 + context + "'");
294 }
295 map.put(CONTEXT_ID_ATTR, dcontext.getId());
296 Object opaqueState = dcontext.getOpaqueState();
297 if (opaqueState != null) {
298 map.put(CONTEXT_OPAQUE_ATTR, opaqueState);
299 }
300 } else {
301 if (log.isTraceEnabled()) {
302 log.trace("beforeRenderResponse() erasing dialog context id "
303 + " for FacesContext instance '"
304 + context + "'");
305 }
306 map.remove(CONTEXT_ID_ATTR);
307 map.remove(CONTEXT_OPAQUE_ATTR);
308 }
309
310 }
311
312
313
314 /***
315 * <p>Create and return a new {@link DialogContext} for the specified
316 * dialog name and optional parent id. If no such {@link DialogContext}
317 * can be created, return <code>null</code> instead.</p>
318 *
319 * @param context FacesContext for the current request
320 * @param dialogName Logical name of the dialog to be created
321 * @param parentId Parent dialog context instance (if any)
322 * @return The newly created {@link DialogContext}, may be null
323 */
324 private DialogContext create(FacesContext context, String dialogName,
325 String parentId) {
326
327 DialogContextManager manager =
328 DialogHelper.getDialogContextManager(context);
329 if (manager == null) {
330 return null;
331 }
332 DialogContext parent = null;
333 if (parentId != null) {
334 parent = manager.get(parentId);
335 }
336 DialogContext dcontext = manager.create(context, dialogName, parent);
337 return dcontext;
338
339 }
340
341
342 /***
343 * <p>Fire an <code>onPassivate</code> event to all registered listeners
344 * of the specified {@link DialogContext} instance.</p>
345 *
346 * @param dcontext {@link DialogContext} instance being activated
347 */
348 private void passivate(DialogContext dcontext) {
349
350 DialogContextListener[] listeners = dcontext.getDialogContextListeners();
351 for (int i = 0; i < listeners.length; i++) {
352 listeners[i].onPassivate();
353 }
354
355 }
356
357
358 /***
359 * <p>Restore access to the {@link DialogContext} with the specified id,
360 * if possible. If there was any opaque state information stored, update
361 * the corresponding {@link DialogContext} instance as well.</p>
362 *
363 * @param context FacesContext for the current request
364 * @param dialogId Dialog identifier of the {@link DialogContext}
365 * to be restored
366 *
367 * @return The restored {@link DialogContext} instance (if any)
368 */
369 private DialogContext restore(FacesContext context, String dialogId) {
370
371 DialogContextManager manager =
372 DialogHelper.getDialogContextManager(context);
373 if (manager == null) {
374 return null;
375 }
376 DialogContext dcontext = manager.get(dialogId);
377 if (dcontext == null) {
378 return null;
379 }
380 if (log.isDebugEnabled()) {
381 log.debug("afterPhase() restoring dialog context with id '"
382 + dialogId + "' for FacesContext instance '"
383 + context + "'");
384 }
385 context.getExternalContext().getRequestMap().put(Constants.CONTEXT_BEAN, dcontext);
386 Object opaqueState = context.getViewRoot().getAttributes().get(CONTEXT_OPAQUE_ATTR);
387 if (opaqueState != null) {
388 dcontext.setOpaqueState(opaqueState);
389 }
390 return dcontext;
391
392 }
393
394
395 }