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.view.faces;
19
20 import java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Locale;
24 import java.util.Map;
25
26 import javax.faces.FacesException;
27 import javax.faces.application.ViewHandler;
28 import javax.faces.component.UIViewRoot;
29 import javax.faces.context.FacesContext;
30 import javax.faces.el.EvaluationException;
31 import javax.faces.el.ValueBinding;
32 import javax.faces.el.VariableResolver;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.shale.util.Messages;
37 import org.apache.shale.view.Constants;
38 import org.apache.shale.view.ViewController;
39 import org.apache.shale.view.ViewControllerMapper;
40
41 /***
42 * <p>{@link ViewViewHandler} is a custom implementation of <code>ViewHandler</code>
43 * that adds support for on-demand creation and configuration of {@link ViewController}
44 * instances, and other view related functionality.</p>
45 *
46 * $Id: ViewViewHandler.java 489926 2006-12-23 20:56:29Z craigmcc $
47 */
48
49 public class ViewViewHandler extends ViewHandler {
50
51
52
53
54
55 /***
56 * <p>Create a {@link ViewViewHandler} instance that decorates the
57 * specified <code>ViewHandler</code> provided by the JSF runtime
58 * implementation.</p>
59 *
60 * @param original Original <code>ViewHandler</code> to be decorated
61 */
62 public ViewViewHandler(ViewHandler original) {
63 this.original = original;
64 }
65
66
67
68
69
70 /***
71 * <p>Log instance for this class.</p>
72 */
73 private static final Log log = LogFactory.getLog(ViewViewHandler.class);
74
75
76 /***
77 * <p>Message resources for this class.</p>
78 */
79 private static Messages messages =
80 new Messages("org.apache.shale.view.resources.Bundle",
81 ViewViewHandler.class.getClassLoader());
82
83
84
85
86
87 /***
88 * <p>Cached {@link ViewControllerMapper} we will use to translate
89 * view identifiers to the class name of a {@link ViewController}.</p>
90 */
91 private ViewControllerMapper mapper = null;
92
93
94 /***
95 * <p>The <code>ViewHandler</code> instance we are decorating. All requests
96 * are delegated to this instance, before or after any special handling that
97 * is required.</p>
98 */
99 private ViewHandler original = null;
100
101
102
103
104
105 /*** {@inheritDoc} */
106 public Locale calculateLocale(FacesContext context) {
107 return original.calculateLocale(context);
108 }
109
110
111 /*** {@inheritDoc} */
112 public String calculateRenderKitId(FacesContext context) {
113 return original.calculateRenderKitId(context);
114 }
115
116
117 /***
118 * <p>After delegating to our original <code>ViewHandler</code>,
119 * create and initialize any {@link ViewController} associated with
120 * the specified view identifier.</p>
121 *
122 * @param context <code>FacesContext</code> for the current request
123 * @param viewId View identifier of the view to be created
124 */
125 public UIViewRoot createView(FacesContext context, String viewId) {
126 UIViewRoot view = original.createView(context, viewId);
127 setupViewController(context, view, viewId, false);
128 return view;
129 }
130
131
132 /*** {@inheritDoc} */
133 public String getActionURL(FacesContext context, String viewId) {
134 return original.getActionURL(context, viewId);
135 }
136
137
138 /*** {@inheritDoc} */
139 public String getResourceURL(FacesContext context, String path) {
140 return original.getResourceURL(context, path);
141 }
142
143
144 /*** {@inheritDoc} */
145 public void renderView(FacesContext context, UIViewRoot view)
146 throws IOException, FacesException {
147 original.renderView(context, view);
148 }
149
150
151 /***
152 * <p>After delegating to our original <code>ViewHandler</code>,
153 * create and initialize any {@link ViewController} associated with
154 * the specified view identifier.</p>
155 *
156 * @param context <code>FacesContext</code> for the current request
157 * @param viewId View identifier of the view to be restored
158 */
159 public UIViewRoot restoreView(FacesContext context, String viewId) {
160 UIViewRoot view = original.restoreView(context, viewId);
161 setupViewController(context, view, viewId, true);
162 return view;
163 }
164
165
166 /*** {@inheritDoc} */
167 public void writeState(FacesContext context) throws IOException {
168 original.writeState(context);
169 }
170
171
172
173
174
175 /***
176 * <p>Return the {@link ViewControllerMapper} instance we will use to
177 * map view identifiers to class names of the corresponding
178 * {@link ViewController} class.</p>
179 *
180 * @param context <code>FacesContext</code> for the current request
181 */
182 private ViewControllerMapper getViewControllerMapper(FacesContext context) {
183
184
185 if (mapper == null) {
186 mapper = getViewControllerMapperInstance(context);
187 }
188
189
190 if (mapper != null) {
191 return mapper;
192 }
193
194
195 ValueBinding vb = context.getApplication().createValueBinding
196 ("#{" + Constants.VIEW_MAPPER + "}");
197 ViewControllerMapper vcm = (ViewControllerMapper) vb.getValue(context);
198 return vcm;
199
200 }
201
202
203 /***
204 * <p>Create and return the custom configured {@link ViewControllerMapper}
205 * instance we will use for this application, or <code>null</code>
206 * if there is no such instance.</p>
207 *
208 * @param context <code>FacesContext</code> for the current request
209 *
210 * @deprecated As of version 1.0.3, replace the application scoped
211 * managed bean at FacesConstants.VIEW_MAPPER instead of using the
212 * deprecated context initialization parameter mentioned here
213 */
214 private ViewControllerMapper getViewControllerMapperInstance
215 (FacesContext context) {
216
217 String className =
218 context.getExternalContext().getInitParameter(Constants.VIEW_CONTROLLER_MAPPER);
219 if (className == null) {
220 return null;
221 }
222 ClassLoader cl = Thread.currentThread().getContextClassLoader();
223 if (cl == null) {
224 cl = this.getClass().getClassLoader();
225 }
226 try {
227 Class clazz = cl.loadClass(className);
228 return (ViewControllerMapper) clazz.newInstance();
229 } catch (ClassCastException e) {
230 throw new FacesException
231 (messages.getMessage("view.vcmCast",
232 new Object[] { className }), e);
233 } catch (ClassNotFoundException e) {
234 throw new FacesException
235 (messages.getMessage("view.vcmClass",
236 new Object[] { className }), e);
237 } catch (IllegalAccessException e) {
238 throw new FacesException
239 (messages.getMessage("view.vcmAccess",
240 new Object[] { className }), e);
241 } catch (InstantiationException e) {
242 throw new FacesException
243 (messages.getMessage("view.vcmInstantiate",
244 new Object[] { className }), e);
245 }
246
247 }
248
249
250 /***
251 * <p>Create and initialize an appropriate {@link ViewController} instance
252 * associated with the specified view, which was just created or just
253 * restored.</p>
254 *
255 * @param context <code>FacesContext</code> for the current request
256 * @param view <code>UIViewRoot</code> just created or restored
257 * (or <code>null</code> if there was no such view)
258 * @param viewId of the <code>UIViewRoot</code> just created or
259 * restored
260 * @param postBack <code>true</code> if this is a post back to
261 * an existing view
262 */
263 private void setupViewController(FacesContext context, UIViewRoot view,
264 String viewId, boolean postBack) {
265
266
267 if (view == null) {
268 return;
269 }
270
271
272
273 if (postBack) {
274 context.getExternalContext().getRequestMap().
275 put(FacesConstants.VIEW_POSTBACK, Boolean.TRUE);
276 }
277
278
279
280
281 if (log.isDebugEnabled()) {
282 log.debug("setupViewController(" + viewId + "," + postBack + ")");
283 }
284
285
286 ViewControllerMapper viewControllerMapper = getViewControllerMapper(context);
287 if (viewControllerMapper == null) {
288 log.warn(messages.getMessage("view.noViewControllerMapper"));
289 return;
290 }
291 String viewName = viewControllerMapper.mapViewId(viewId);
292
293
294
295 Object vc = null;
296 VariableResolver vr =
297 context.getApplication().getVariableResolver();
298 try {
299 vc = vr.resolveVariable(context, viewName);
300 if (vc == null) {
301 if (log.isDebugEnabled()) {
302 log.debug(messages.getMessage("view.noViewController",
303 new Object[] { viewId, viewName }));
304 }
305
306
307
308
309 context.getExternalContext().getRequestMap().remove
310 (FacesConstants.VIEW_NAME_RENDERED);
311 return;
312 }
313 } catch (EvaluationException e) {
314 log.warn(messages.getMessage("view.evalException",
315 new Object[] { viewId, viewName }), e);
316 return;
317 }
318
319
320 if (vc instanceof ViewController) {
321 ((ViewController) vc).setPostBack(postBack);
322 }
323
324
325 Map map = context.getExternalContext().getRequestMap();
326 map.put(FacesConstants.VIEW_NAME_RENDERED, viewName);
327 List list = (List) map.get(FacesConstants.VIEWS_INITIALIZED);
328 if (list == null) {
329 list = new ArrayList();
330 map.put(FacesConstants.VIEWS_INITIALIZED, list);
331 }
332 list.add(vc);
333
334 }
335
336
337 /***
338 * <p>Return the {@link ViewControllerCallbacks} instance we
339 * will use.</p>
340 *
341 * @param context <code>FacesContext</code> for the current request
342 *
343 * @since 1.0.1
344 */
345 private ViewControllerCallbacks getViewControllerCallbacks(FacesContext context) {
346
347 ValueBinding vb = context.getApplication().createValueBinding
348 ("#{" + FacesConstants.VIEW_CALLBACKS + "}");
349 return (ViewControllerCallbacks) vb.getValue(context);
350
351 }
352
353
354 }