1 /*
2 * $Id: ResponseStateManager.java,v 1.30 2007/04/27 22:00:10 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.render;
42
43 import javax.faces.context.FacesContext;
44 import javax.faces.context.ResponseWriter;
45 import javax.faces.application.StateManager;
46 import javax.faces.application.StateManager.SerializedView;
47
48 import java.io.IOException;
49 import java.util.logging.Level;
50 import java.util.logging.Logger;
51
52
53
54
55 /**
56 * <p><strong>ResponseStateManager</strong> is the helper class to
57 * {@link javax.faces.application.StateManager} that knows the specific
58 * rendering technology being used to generate the response. It is a
59 * singleton abstract class, vended by the {@link RenderKit}. This
60 * class knows the mechanics of saving state, whether it be in hidden
61 * fields, session, or some combination of the two.</p>
62 */
63
64 public abstract class ResponseStateManager {
65
66 private static Logger log = Logger.getLogger("javax.faces.render");
67
68 /**
69 * <p>The name of the request parameter used by the default
70 * implementation of {@link
71 * javax.faces.application.ViewHandler#calculateRenderKitId} to
72 * derive a RenderKit ID.</p>
73 */
74 public static final String RENDER_KIT_ID_PARAM =
75 "javax.faces.RenderKitId";
76
77 /**
78 * <p>Implementations must use this value as the name and id of the client
79 * parameter in which to save the state between requests.</p>
80 *
81 * @since 1.2
82 */
83
84 public static final String VIEW_STATE_PARAM = "javax.faces.ViewState";
85
86 /*
87 * <p>Take the argument <code>state</code> and write it into the
88 * output using the current {@link ResponseWriter}, which must be
89 * correctly positioned already.</p>
90 *
91 * <p>If the state is to be written out to hidden fields, the
92 * implementation must take care to make all necessary character
93 * replacements to make the Strings suitable for inclusion as an
94 * HTTP request paramater.</p>
95 *
96 * <p>If the state saving method for this application is {@link
97 * javax.faces.application.StateManager#STATE_SAVING_METHOD_CLIENT},
98 * the implementation may encrypt the state to be saved to the
99 * client. We recommend that the state be unreadable by the client,
100 * and also be tamper evident. The reference implementation follows
101 * these recommendations. </p>
102 *
103 * <p>Write out the render kit identifier associated with this
104 * <code>ResponseStateManager</code> implementation with the name
105 * as the value of the <code>String</code> constant
106 * <code>ResponseStateManager.RENDER_KIT_ID_PARAM</code>. The
107 * render kit identifier must not be written if:</p>
108 * <ul>
109 * <li>it is the default render kit identifier as returned by
110 * {@link Application#getDefaultRenderKitId()} or</li>
111 * <li>the render kit identfier is the value of
112 * <code>RenderKitFactory.HTML_BASIC_RENDER_KIT</code> and
113 * {@link Application.getDefaultRenderKitId()} returns <code>null</code>.
114 * </li>
115 * </ul>
116 *
117 * <p>For backwards compatability with existing
118 * <code>ResponseStateManager</code> implementations, the default
119 * implementation of this method checks if the argument is an
120 * instance of <code>SerializedView</code>. If so, it calls through
121 * to {@link
122 * #writeState(javax.faces.context.FacesContext,javax.faces.application.StateManager.SerializedView}.
123 * If not, it expects the state to be a two element Object array. It creates
124 * an instance of <code>SerializedView</code> and
125 * stores the state as the treeStructure, and passes it to {@link
126 * #writeState(javax.faces.context.FacesContext,javax.faces.application.StateManager.SerializedView}.</p>
127 *
128 *
129 * @since 1.2
130 *
131 * @param context The {@link FacesContext} instance for the current request
132 * @param state The serialized state information previously saved
133 * @throws IOException if the state argument is not an array of length 2.
134 *
135 */
136 public void writeState(FacesContext context,
137 Object state) throws IOException {
138
139 SerializedView view;
140 if (state instanceof SerializedView) {
141 view = (SerializedView) state;
142 }
143 else {
144 if (state instanceof Object[]) {
145 Object[] stateArray = (Object[])state;
146 if (2 == stateArray.length) {
147 StateManager stateManager =
148 context.getApplication().getStateManager();
149 view = stateManager.new SerializedView(stateArray[0],
150 stateArray[1]);
151 } else {
152 //PENDING - I18N
153 if (log.isLoggable(Level.SEVERE)) {
154 log.log(Level.SEVERE, "State is not an expected array of length 2.");
155 }
156 throw new IOException("State is not an expected array of length 2.");
157 }
158 } else {
159 //PENDING - I18N
160 if (log.isLoggable(Level.SEVERE)) {
161 log.log(Level.SEVERE, "State is not an expected array of length 2.");
162 }
163 throw new IOException("State is not an expected array of length 2.");
164 }
165 }
166 writeState(context, view);
167 }
168
169 /**
170 * <p>Take the argument <code>state</code> and write it into
171 * the output using the current {@link ResponseWriter}, which
172 * must be correctly positioned already.</p>
173 *
174 * <p>If the {@link
175 * javax.faces.application.StateManager.SerializedView} is to be
176 * written out to hidden fields, the implementation must take care
177 * to make all necessary character replacements to make the Strings
178 * suitable for inclusion as an HTTP request paramater.</p>
179 *
180 * <p>If the state saving method for this application is {@link
181 * javax.faces.application.StateManager#STATE_SAVING_METHOD_CLIENT},
182 * the implementation may encrypt the state to be saved to the
183 * client. We recommend that the state be unreadable by the client,
184 * and also be tamper evident. The reference implementation follows
185 * these recommendations. </p>
186 *
187 * @deprecated This method has been replaced by {@link
188 * #writeState(javax.faces.context.FacesContext,java.lang.Object)}.
189 * The default implementation of this method does nothing.
190 *
191 * @param context The {@link FacesContext} instance for the current request
192 * @param state The serialized state information previously saved
193 *
194 */
195 public void writeState(FacesContext context,
196 SerializedView state) throws IOException {
197 }
198
199 /**
200 * <p>The implementation must inspect the current request and return
201 * an Object representing the tree structure and component state
202 * passed in to a previous invocation of {@link
203 * #writeState(javax.faces.context.FacesContext,java.lang.Object)}.</p>
204 *
205 * <p>For backwards compatability with existing
206 * <code>ResponseStateManager</code> implementations, the default
207 * implementation of this method calls {@link
208 * #getTreeStructureToRestore} and {@link
209 * #getComponentStateToRestore} and creates and returns a two
210 * element <code>Object</code> array with element zero containing
211 * the <code>structure</code> property and element one containing
212 * the <code>state</code> property of the
213 * <code>SerializedView</code>.</p>
214 *
215 * @since 1.2
216 *
217 * @param context The {@link FacesContext} instance for the current request
218 * @param viewId View identifier of the view to be restored
219 *
220 * @return the tree structure and component state Object passed in
221 * to <code>writeState</code>. If this is an initial request, this
222 * method returns <code>null</code>.
223 */
224
225 public Object getState(FacesContext context, String viewId) {
226 Object stateArray[] = { getTreeStructureToRestore(context, viewId),
227 getComponentStateToRestore(context) };
228 return stateArray;
229 }
230
231
232 /**
233 * <p>The implementation must inspect the current request and return
234 * the tree structure Object passed to it on a previous invocation of
235 * <code>writeState()</code>.</p>
236 *
237 * @deprecated This method has been replaced by {@link #getState}.
238 * The default implementation returns <code>null</code>.
239 *
240 * @param context The {@link FacesContext} instance for the current request
241 * @param viewId View identifier of the view to be restored
242 *
243 */
244 public Object getTreeStructureToRestore(FacesContext context,
245 String viewId) {
246 return null;
247 }
248
249
250 /**
251 * <p>The implementation must inspect the current request and return
252 * the component state Object passed to it on a previous invocation
253 * of <code>writeState()</code>.</p>
254 *
255 * @deprecated This method has been replaced by {@link #getState}.
256 * The default implementation returns <code>null</code>.
257 *
258 * @param context The {@link FacesContext} instance for the current request
259 *
260 */
261 public Object getComponentStateToRestore(FacesContext context) {
262 return null;
263 }
264
265 /**
266 * <p>Return true if the current request is a postback. This method
267 * is leveraged from the <i>Restore View Phase</i> to determine if
268 * {@link javax.faces.application.ViewHandler#restoreView} or {@link
269 * javax.faces.application.ViewHandler#createView} should be called.
270 * The default implementation must return <code>true</code> if this
271 * <code>ResponseStateManager</code> instance wrote out state on a
272 * previous request to which this request is a postback,
273 * <code>false</code> otherwise.</p>
274 *
275 * <p>The implementation if this method for the Standard HTML
276 * RenderKit must consult the {@link
277 * javax.faces.context.ExternalContext}'s
278 * <code>requestParameterMap</code> and return <code>true</code> if
279 * and only if there is a key equal to the value of the symbolic
280 * constant {@link #VIEW_STATE_PARAM}.</p>
281 *
282 * <p>For backwards compatability with implementations of
283 * <code>ResponseStateManager</code> prior to JSF 1.2, a default
284 * implementation is provided that consults the {@link
285 * javax.faces.context.ExternalContext}'s <code>requestParameterMap</code> and return
286 * <code>true</code> if its size is greater than 0.</p>
287 *
288 * @since 1.2
289 */
290
291 public boolean isPostback(FacesContext context) {
292 return (!context.getExternalContext().getRequestParameterMap().isEmpty());
293 }
294
295
296 }