Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
ViewViewHandler |
|
| 3.1538461538461537;3.154 |
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.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 464373 2006-10-16 04:21:54Z rahul $ |
|
47 | */ |
|
48 | ||
49 | public class ViewViewHandler extends ViewHandler { |
|
50 | ||
51 | ||
52 | // ------------------------------------------------------------- Constructor |
|
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 | 0 | public ViewViewHandler(ViewHandler original) { |
63 | 0 | this.original = original; |
64 | 0 | } |
65 | ||
66 | ||
67 | // -------------------------------------------------------- Static Variables |
|
68 | ||
69 | ||
70 | /** |
|
71 | * <p>Log instance for this class.</p> |
|
72 | */ |
|
73 | 0 | private static final Log log = LogFactory.getLog(ViewViewHandler.class); |
74 | ||
75 | ||
76 | /** |
|
77 | * <p>Message resources for this class.</p> |
|
78 | */ |
|
79 | 0 | private static Messages messages = |
80 | new Messages("org.apache.shale.view.resources.Bundle", |
|
81 | ViewViewHandler.class.getClassLoader()); |
|
82 | ||
83 | ||
84 | // ------------------------------------------------------ Instance Variables |
|
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 | 0 | 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 | 0 | private ViewHandler original = null; |
100 | ||
101 | ||
102 | // ----------------------------------------------------- ViewHandler Methods |
|
103 | ||
104 | ||
105 | /** {@inheritDoc} */ |
|
106 | public Locale calculateLocale(FacesContext context) { |
|
107 | 0 | return original.calculateLocale(context); |
108 | } |
|
109 | ||
110 | ||
111 | /** {@inheritDoc} */ |
|
112 | public String calculateRenderKitId(FacesContext context) { |
|
113 | 0 | 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 | 0 | UIViewRoot view = original.createView(context, viewId); |
127 | 0 | setupViewController(context, view, viewId, false); |
128 | 0 | return view; |
129 | } |
|
130 | ||
131 | ||
132 | /** {@inheritDoc} */ |
|
133 | public String getActionURL(FacesContext context, String viewId) { |
|
134 | 0 | return original.getActionURL(context, viewId); |
135 | } |
|
136 | ||
137 | ||
138 | /** {@inheritDoc} */ |
|
139 | public String getResourceURL(FacesContext context, String path) { |
|
140 | 0 | return original.getResourceURL(context, path); |
141 | } |
|
142 | ||
143 | ||
144 | /** {@inheritDoc} */ |
|
145 | public void renderView(FacesContext context, UIViewRoot view) |
|
146 | throws IOException, FacesException { |
|
147 | 0 | original.renderView(context, view); |
148 | 0 | } |
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 | 0 | UIViewRoot view = original.restoreView(context, viewId); |
161 | 0 | setupViewController(context, view, viewId, true); |
162 | 0 | return view; |
163 | } |
|
164 | ||
165 | ||
166 | /** {@inheritDoc} */ |
|
167 | public void writeState(FacesContext context) throws IOException { |
|
168 | 0 | original.writeState(context); |
169 | 0 | } |
170 | ||
171 | ||
172 | // --------------------------------------------------------- Private Methods |
|
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 | // DEPRECATED - respect the context init parameter if specified |
|
185 | 0 | if (mapper == null) { |
186 | 0 | mapper = getViewControllerMapperInstance(context); |
187 | } |
|
188 | ||
189 | // DEPRECATED - return cached instance from context init parameter |
|
190 | 0 | if (mapper != null) { |
191 | 0 | return mapper; |
192 | } |
|
193 | ||
194 | // Live lookup of the appropriate mapper as a managed bean |
|
195 | 0 | ValueBinding vb = context.getApplication().createValueBinding |
196 | ("#{" + Constants.VIEW_MAPPER + "}"); |
|
197 | 0 | ViewControllerMapper vcm = (ViewControllerMapper) vb.getValue(context); |
198 | 0 | 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 | 0 | String className = |
218 | context.getExternalContext().getInitParameter(Constants.VIEW_CONTROLLER_MAPPER); |
|
219 | 0 | if (className == null) { |
220 | 0 | return null; |
221 | } |
|
222 | 0 | ClassLoader cl = Thread.currentThread().getContextClassLoader(); |
223 | 0 | if (cl == null) { |
224 | 0 | cl = this.getClass().getClassLoader(); |
225 | } |
|
226 | try { |
|
227 | 0 | Class clazz = cl.loadClass(className); |
228 | 0 | return (ViewControllerMapper) clazz.newInstance(); |
229 | 0 | } catch (ClassCastException e) { |
230 | 0 | throw new FacesException |
231 | (messages.getMessage("view.vcmCast", |
|
232 | new Object[] { className }), e); |
|
233 | 0 | } catch (ClassNotFoundException e) { |
234 | 0 | throw new FacesException |
235 | (messages.getMessage("view.vcmClass", |
|
236 | new Object[] { className }), e); |
|
237 | 0 | } catch (IllegalAccessException e) { |
238 | 0 | throw new FacesException |
239 | (messages.getMessage("view.vcmAccess", |
|
240 | new Object[] { className }), e); |
|
241 | 0 | } catch (InstantiationException e) { |
242 | 0 | 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 | // Is there actually a view for us to procses? |
|
267 | 0 | if (view == null) { |
268 | 0 | return; |
269 | } |
|
270 | ||
271 | // Cache the postback flag so that it can be used inside |
|
272 | // the AbstractViewcontroller implementation |
|
273 | 0 | if (postBack) { |
274 | 0 | context.getExternalContext().getRequestMap(). |
275 | put(FacesConstants.VIEW_POSTBACK, Boolean.TRUE); |
|
276 | } |
|
277 | ||
278 | // Its not the responsibilty of createView method to set the viewId of the view |
|
279 | // (See JSF 1.1 spec. pg. 7-16) |
|
280 | //String viewId = view.getViewId(); |
|
281 | 0 | if (log.isDebugEnabled()) { |
282 | 0 | log.debug("setupViewController(" + viewId + "," + postBack + ")"); |
283 | } |
|
284 | ||
285 | // Map our view identifier to a corresponding managed bean name |
|
286 | 0 | ViewControllerMapper viewControllerMapper = getViewControllerMapper(context); |
287 | 0 | if (viewControllerMapper == null) { |
288 | 0 | log.warn(messages.getMessage("view.noViewControllerMapper")); |
289 | 0 | return; |
290 | } |
|
291 | 0 | String viewName = viewControllerMapper.mapViewId(viewId); |
292 | ||
293 | // Retrieve an existing instance, or one created and configured by |
|
294 | // the managed bean facility |
|
295 | 0 | Object vc = null; |
296 | 0 | VariableResolver vr = |
297 | context.getApplication().getVariableResolver(); |
|
298 | try { |
|
299 | 0 | vc = vr.resolveVariable(context, viewName); |
300 | 0 | if (vc == null) { |
301 | 0 | if (log.isDebugEnabled()) { |
302 | 0 | log.debug(messages.getMessage("view.noViewController", |
303 | new Object[] { viewId, viewName })); |
|
304 | } |
|
305 | 0 | return; |
306 | } |
|
307 | 0 | } catch (EvaluationException e) { |
308 | 0 | log.warn(messages.getMessage("view.evalException", |
309 | new Object[] { viewId, viewName }), e); |
|
310 | 0 | return; |
311 | 0 | } |
312 | ||
313 | // Set the postBack property on a ViewController instance |
|
314 | 0 | if (vc instanceof ViewController) { |
315 | 0 | ((ViewController) vc).setPostBack(postBack); |
316 | } |
|
317 | ||
318 | // Schedule this instance for later processing as needed |
|
319 | 0 | Map map = context.getExternalContext().getRequestMap(); |
320 | 0 | map.put(FacesConstants.VIEW_NAME_RENDERED, viewName); |
321 | 0 | List list = (List) map.get(FacesConstants.VIEWS_INITIALIZED); |
322 | 0 | if (list == null) { |
323 | 0 | list = new ArrayList(); |
324 | 0 | map.put(FacesConstants.VIEWS_INITIALIZED, list); |
325 | } |
|
326 | 0 | list.add(vc); |
327 | ||
328 | 0 | } |
329 | ||
330 | ||
331 | /** |
|
332 | * <p>Return the {@link ViewControllerCallbacks} instance we |
|
333 | * will use.</p> |
|
334 | * |
|
335 | * @param context <code>FacesContext</code> for the current request |
|
336 | * |
|
337 | * @since 1.0.1 |
|
338 | */ |
|
339 | private ViewControllerCallbacks getViewControllerCallbacks(FacesContext context) { |
|
340 | ||
341 | 0 | ValueBinding vb = context.getApplication().createValueBinding |
342 | ("#{" + FacesConstants.VIEW_CALLBACKS + "}"); |
|
343 | 0 | return (ViewControllerCallbacks) vb.getValue(context); |
344 | ||
345 | } |
|
346 | ||
347 | ||
348 | } |