1 /*
2 * $Id: StateManager.java,v 1.41 2007/04/27 22:00:02 ofung Exp $
3 */
4
5 /*
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
7 *
8 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
9 *
10 * The contents of this file are subject to the terms of either the GNU
11 * General Public License Version 2 only ("GPL") or the Common Development
12 * and Distribution License("CDDL") (collectively, the "License"). You
13 * may not use this file except in compliance with the License. You can obtain
14 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
15 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
16 * language governing permissions and limitations under the License.
17 *
18 * When distributing the software, include this License Header Notice in each
19 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
20 * Sun designates this particular file as subject to the "Classpath" exception
21 * as provided by Sun in the GPL Version 2 section of the License file that
22 * accompanied this code. If applicable, add the following below the License
23 * Header, with the fields enclosed by brackets [] replaced by your own
24 * identifying information: "Portions Copyrighted [year]
25 * [name of copyright owner]"
26 *
27 * Contributor(s):
28 *
29 * If you wish your version of this file to be governed by only the CDDL or
30 * only the GPL Version 2, indicate your decision by adding "[Contributor]
31 * elects to include this software in this distribution under the [CDDL or GPL
32 * Version 2] license." If you don't indicate a single choice of license, a
33 * recipient has the option to distribute your version of this file under
34 * either the CDDL, the GPL Version 2 or to extend the choice of license to
35 * its licensees as provided above. However, if you add GPL Version 2 code
36 * and therefore, elected the GPL Version 2 license, then the option applies
37 * only if the new code is made subject to such option by the copyright
38 * holder.
39 */
40
41 package javax.faces.application;
42
43 import javax.faces.component.NamingContainer;
44 import javax.faces.component.UIViewRoot;
45 import javax.faces.context.FacesContext;
46 import javax.faces.context.ResponseWriter;
47 import javax.faces.render.RenderKit;
48 import javax.faces.render.ResponseStateManager;
49
50 import java.io.IOException;
51
52
53 /**
54 * <p><strong>StateManager</strong> directs the process of saving and
55 * restoring the view between requests. The {@link StateManager}
56 * instance for an application is retrieved from the {@link Application}
57 * instance, and thus cannot know any details of the markup language
58 * created by the {@link RenderKit} being used to render a view. The
59 * {@link StateManager} utilizes a helper object ({@link
60 * ResponseStateManager}), that is provided by the {@link RenderKit}
61 * implementation and is therefore aware of the markup language
62 * details.</p>
63 */
64
65 public abstract class
66 StateManager {
67
68 // ------------------------------------------------------ Manifest Constants
69
70
71 /**
72 * <p>The <code>ServletContext</code> init parameter consulted by
73 * the <code>StateManager</code> to tell where the state should be
74 * saved. Valid values are given as the values of the constants:
75 * {@link #STATE_SAVING_METHOD_CLIENT} or {@link
76 * #STATE_SAVING_METHOD_SERVER}.</p>
77 * <p/>
78 * <p>If this parameter is not specified, the default value is the
79 * value of the constant {@link #STATE_SAVING_METHOD_CLIENT}. </p>
80 */
81 public static final String STATE_SAVING_METHOD_PARAM_NAME =
82 "javax.faces.STATE_SAVING_METHOD";
83
84
85 /**
86 * <p>Constant value for the initialization parameter named by
87 * the <code>STATE_SAVING_METHOD_PARAM_NAME</code> that indicates
88 * state saving should take place on the client.</p>
89 */
90 public static final String STATE_SAVING_METHOD_CLIENT = "client";
91
92
93 /**
94 * <p>Constant value for the initialization parameter named by
95 * the <code>STATE_SAVING_METHOD_PARAM_NAME</code> that indicates
96 * state saving should take place on the server.</p>
97 */
98 public static final String STATE_SAVING_METHOD_SERVER = "server";
99
100 // ---------------------------------------------------- State Saving Methods
101
102
103 /**
104 * <p>Return the tree structure and component state information for the
105 * view contained in the specified {@link FacesContext} instance as an
106 * object of type <code>StateManager.SerializedView</code>. If there
107 * is no state information to be saved, return <code>null</code>
108 * instead.</p>
109 * <p/>
110 * <p>Components may opt out of being included in the serialized view
111 * by setting their <code>transient</code> property to <code>true</code>.
112 * This must cause the component itself, as well as all of that component's
113 * children and facets, to be omitted from the saved tree structure
114 * and component state information.</p>
115 * <p/>
116 * <p>This method must also enforce the rule that, for components with
117 * non-null <code>id</code>s, all components that are descendants of the
118 * same nearest {@link NamingContainer} must have unique identifiers.</p>
119 *
120 * @param context {@link FacesContext} for the current request
121 *
122 * @throws IllegalStateException if more than one component or
123 * facet within the same {@link NamingContainer} in this view has
124 * the same non-<code>null</code> component id
125 * @deprecated this has been replaced by {@link #saveView}. The
126 * default implementation returns <code>null</code>.
127 */
128 public SerializedView saveSerializedView(FacesContext context) {
129 return null;
130 }
131
132 /**
133 * <p>Return an opaque <code>Object</code> containing sufficient
134 * information for this same instance to restore the state of the
135 * current {@link UIViewRoot} on a subsequent request. The returned
136 * object must implement <code>java.io.Serializable</code>. If there
137 * is no state information to be saved, return <code>null</code>
138 * instead.</p>
139 * <p/>
140 * <p>Components may opt out of being included in the serialized view
141 * by setting their <code>transient</code> property to <code>true</code>.
142 * This must cause the component itself, as well as all of that component's
143 * children and facets, to be omitted from the saved tree structure
144 * and component state information.</p>
145 * <p/>
146 * <p>This method must also enforce the rule that, for components with
147 * non-null <code>id</code>s, all components that are descendants of the
148 * same nearest {@link NamingContainer} must have unique identifiers.</p>
149 * <p/>
150 * <p>For backwards compatability with existing
151 * <code>StateManager</code> implementations, the default
152 * implementation of this method calls {@link #saveSerializedView}
153 * and creates and returns a two element <code>Object</code> array
154 * with element zero containing the <code>structure</code> property
155 * and element one containing the <code>state</code> property of the
156 * <code>SerializedView</code>.</p>
157 *
158 * @param context {@link FacesContext} for the current request
159 *
160 * @throws IllegalStateException if more than one component or
161 * facet within the same {@link NamingContainer} in this view has
162 * the same non-<code>null</code> component id
163 * @since 1.2
164 */
165 public Object saveView(FacesContext context) {
166 SerializedView view = saveSerializedView(context);
167 Object stateArray[] = {view.getStructure(),
168 view.getState()};
169 return stateArray;
170 }
171
172
173 /**
174 * <p>Convenience method, which must be called by
175 * <code>saveSerializedView()</code>, to construct and return a
176 * <code>Serializable</code> object that represents the structure
177 * of the entire component tree (including children and facets)
178 * of this view.</p>
179 * <p/>
180 * <p>Components may opt-out of being included in the tree structure
181 * by setting their <code>transient</code> property to <code>true</code>.
182 * This must cause the component itself, as well as all of that component's
183 * children and facets, to be omitted from the saved tree structure
184 * information.</p>
185 *
186 * @param context {@link FacesContext} for the current request
187 *
188 * @deprecated the distinction between tree structure and component
189 * state is now an implementation detail. The default
190 * implementation returns <code>null</code>.
191 */
192 protected Object getTreeStructureToSave(FacesContext context) {
193 return null;
194 }
195
196
197 /**
198 * <p>Convenience method, which must be called by
199 * <code>saveSerializedView()</code>, to construct and return a
200 * <code>Serializable</code> object that represents the state of
201 * all component properties, attributes, and attached objects, for
202 * the entire component tree (including children and facets)
203 * of this view.</p>
204 * <p/>
205 * <p>Components may opt-out of being included in the component state
206 * by setting their <code>transient</code> property to <code>true</code>.
207 * This must cause the component itself, as well as all of that component's
208 * children and facets, to be omitted from the saved component state
209 * information.</p>
210 *
211 * @param context {@link FacesContext} for the current request
212 *
213 * @deprecated the distinction between tree structure and component
214 * state is now an implementation detail. The default
215 * implementation returns <code>null</code>.
216 */
217 protected Object getComponentStateToSave(FacesContext context) {
218 return null;
219 }
220
221 /**
222 * <p>Save the state represented in the specified state
223 * <code>Object</code> instance, in an implementation dependent
224 * manner.</p>
225 * <p/>
226 * <p>This method will typically simply delegate the actual
227 * writing to the <code>writeState()</code> method of the
228 * {@link ResponseStateManager} instance provided by the
229 * {@link RenderKit} being used to render this view. This
230 * method assumes that the caller has positioned the
231 * {@link ResponseWriter} at the correct position for the
232 * saved state to be written.</p>
233 * <p/>
234 * <p>For backwards compatability with existing
235 * <code>StateManager</code> implementations, the default
236 * implementation of this method checks if the argument is an
237 * instance of <code>Object []</code> of length greater than or
238 * equal to two. If so, it creates a <code>SerializedView</code>
239 * instance with the tree structure coming from element zero and
240 * the component state coming from element one and calls through to
241 * {@link
242 * #writeState(javax.faces.context.FacesContext,javax.faces.application.StateManager.SerializedView)}.
243 * If not, does nothing.</p>
244 *
245 * @param context {@link FacesContext} for the current request
246 * @param state the Serializable state to be written,
247 * as returned by {@link #saveSerializedView}
248 *
249 * @since 1.2
250 */
251 public void writeState(FacesContext context, Object state)
252 throws IOException {
253 if (null != state && state.getClass().isArray() &&
254 state.getClass().getComponentType().equals(Object.class)) {
255 Object stateArray[] = (Object[]) state;
256 if (2 == stateArray.length) {
257 SerializedView view = new SerializedView(stateArray[0],
258 stateArray[1]);
259 writeState(context, view);
260 }
261 }
262 }
263
264 /**
265 * <p>Save the state represented in the specified
266 * <code>SerializedView</code> isntance, in an implementation
267 * dependent manner.</p>
268 * <p/>
269 * <p>This method must consult the context initialization parameter
270 * named by the symbolic constant
271 * <code>StateManager.STATE_SAVING_METHOD_PARAMETER_NAME</code>
272 * to determine whether state should be saved on the client or the
273 * server. If not present, client side state saving is assumed.</p>
274 * <p/>
275 * <p>If the init parameter indicates that client side state
276 * saving should be used, this method must delegate the actual
277 * writing to the <code>writeState()</code> method of the
278 * {@link ResponseStateManager} instance provided by the
279 * {@link RenderKit} being used to render this view. This
280 * method assumes that the caller has positioned the
281 * {@link ResponseWriter} at the correct position for the
282 * saved state to be written.</p>
283 *
284 * @param context {@link FacesContext} for the current request
285 * @param state the serialized state to be written
286 *
287 * @deprecated This method has been replaced by {@link
288 * #writeState(javax.faces.context.FacesContext,java.lang.Object)}.
289 * The default implementation of this method does nothing.
290 */
291 public void writeState(FacesContext context,
292 SerializedView state) throws IOException {
293 }
294
295 // ------------------------------------------------- State Restoring Methods
296
297
298 /**
299 * <p>Restore the tree structure and the component state of the view
300 * for the specified <code>viewId</code>, in an implementation dependent
301 * manner, and return the restored {@link UIViewRoot}. If there is no
302 * saved state information available for this <code>viewId</code>,
303 * return <code>null</code> instead.</p>
304 * <p/>
305 * <p>This method must consult the context initialization parameter
306 * named by the symbolic constant
307 * <code>StateManager.STATE_SAVING_METHOD_PARAMETER_NAME</code>
308 * to determine whether state should be saved on the client or the
309 * server. If not present, client side state saving is assumed.</p>
310 * <p/>
311 * <p>If the init parameter indicates that client side state
312 * saving should be used, this method must call the
313 * <code>getTreeStructureToRestore()</code> and (if the previous method
314 * call returned a non-null value) <code>getComponentStateToRestore()</code>
315 * methods of the {@link ResponseStateManager} instance provided by the
316 * {@link RenderKit} responsible for this view.</p>
317 *
318 * @param context {@link FacesContext} for the current request
319 * @param viewId View identifier of the view to be restored
320 * @param renderKitId the renderKitId used to render this response.
321 * Must not be <code>null</code>.
322 *
323 * @throws IllegalArgumentException if <code>renderKitId</code>
324 * is <code>null</code>.
325 */
326 public abstract UIViewRoot restoreView(FacesContext context, String viewId,
327 String renderKitId);
328
329
330 /**
331 * <p>Convenience method, which must be called by
332 * <code>restoreView()</code>, to construct and return a {@link UIViewRoot}
333 * instance (populated with children and facets) representing the
334 * tree structure of the component tree being restored. If no saved
335 * state information is available, return <code>null</code> instead.</p>
336 *
337 * @param context {@link FacesContext} for the current request
338 * @param viewId View identifier of the view to be restored
339 * @param renderKitId the renderKitId used to render this response.
340 * Must not be <code>null</code>.
341 *
342 * @throws IllegalArgumentException if <code>renderKitId</code>
343 * is <code>null</code>.
344 * @deprecated the distinction between tree structure and component
345 * state is now an implementation detail. The default
346 * implementation returns <code>null</code>.
347 */
348 protected UIViewRoot restoreTreeStructure(FacesContext context,
349 String viewId,
350 String renderKitId) {
351 return null;
352 }
353
354
355 /**
356 * <p>Convenience method, which must be called by
357 * <code>restoreView()</code>, to restore the attributes, properties,
358 * and attached objects of all components in the restored component tree.
359 * </p>
360 *
361 * @param context {@link FacesContext} for the current request
362 * @param viewRoot {@link UIViewRoot} returned by a previous call
363 * to <code>restoreTreeStructure()</code>
364 * @param renderKitId the renderKitId used to render this response.
365 * Must not be <code>null</code>.
366 *
367 * @throws IllegalArgumentException if <code>renderKitId</code>
368 * is <code>null</code>.
369 * @deprecated the distinction between tree structure and component
370 * state is now an implementation detail. The default
371 * implementation does nothing.
372 */
373 protected void restoreComponentState(FacesContext context,
374 UIViewRoot viewRoot,
375 String renderKitId) {
376 }
377
378
379 private Boolean savingStateInClient = null;
380
381 /**
382 * @return <code>true</code> if and only if the value of the
383 * <code>ServletContext</code> init parameter named by the value of
384 * the constant {@link #STATE_SAVING_METHOD_PARAM_NAME} is equal to
385 * the value of the constant {@link #STATE_SAVING_METHOD_CLIENT}.
386 * <code>false</code> otherwise.
387 *
388 * @throws NullPointerException if <code>context</code> is
389 * <code>null</code>.
390 */
391
392 public boolean isSavingStateInClient(FacesContext context) {
393 if (null != savingStateInClient) {
394 return savingStateInClient.booleanValue();
395 }
396 savingStateInClient = Boolean.FALSE;
397
398 String saveStateParam = context.getExternalContext().
399 getInitParameter(STATE_SAVING_METHOD_PARAM_NAME);
400 if (saveStateParam != null &&
401 saveStateParam.equalsIgnoreCase(STATE_SAVING_METHOD_CLIENT)) {
402 savingStateInClient = Boolean.TRUE;
403 }
404 return savingStateInClient.booleanValue();
405 }
406
407 /**
408 * <p>Convenience struct for encapsulating tree structure and
409 * component state. This is necessary to allow the API to be
410 * flexible enough to work in JSP and non-JSP environments.</p>
411 *
412 * @deprecated This class was not marked <code>Serializable</code>
413 * in the 1.0 version of the spec. It was also not a static inner
414 * class, so it can't be made to be <code>Serializable</code>.
415 * Therefore, it is being deprecated in version 1.2 of the spec.
416 * The replacement is to use an implementation dependent
417 * <code>Object</code>.
418 */
419
420 public class SerializedView extends Object {
421 private Object structure = null;
422 private Object state = null;
423
424 public SerializedView(Object newStructure, Object newState) {
425 structure = newStructure;
426 state = newState;
427 }
428
429 public Object getStructure() {
430 return structure;
431 }
432
433 public Object getState() {
434 return state;
435 }
436 }
437
438 }