1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.renderkit.html;
20
21 import java.io.IOException;
22 import java.util.Map;
23 import java.util.logging.Logger;
24
25 import javax.faces.context.ExternalContext;
26 import javax.faces.context.FacesContext;
27 import javax.faces.context.ResponseWriter;
28 import javax.faces.lifecycle.ClientWindow;
29 import javax.faces.render.RenderKitFactory;
30 import javax.faces.render.ResponseStateManager;
31
32 import org.apache.myfaces.application.StateCache;
33 import org.apache.myfaces.application.StateCacheFactory;
34 import org.apache.myfaces.application.viewstate.StateCacheFactoryImpl;
35 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
36 import org.apache.myfaces.renderkit.MyfacesResponseStateManager;
37 import org.apache.myfaces.renderkit.StateTokenProcessor;
38 import org.apache.myfaces.shared.config.MyfacesConfig;
39 import org.apache.myfaces.shared.renderkit.html.HTML;
40 import org.apache.myfaces.shared.util.StateUtils;
41 import org.apache.myfaces.shared.util.WebConfigParamUtils;
42
43
44
45
46
47 public class HtmlResponseStateManager extends MyfacesResponseStateManager
48 {
49 private static final Logger log = Logger.getLogger(HtmlResponseStateManager.class.getName());
50
51 public static final String STANDARD_STATE_SAVING_PARAM = "javax.faces.ViewState";
52
53 private static final String VIEW_STATE_COUNTER = "oam.partial.VIEW_STATE_COUNTER";
54 private static final String CLIENT_WINDOW_COUNTER = "oam.partial.CLIENT_WINDOW_COUNTER";
55
56 private static final String SESSION_TOKEN = "oam.rsm.SESSION_TOKEN";
57
58
59
60
61
62
63
64
65
66
67
68
69 @Deprecated
70 @JSFWebConfigParam(since="2.0.6", expectedValues="true, false", defaultValue="true", group="state",
71 deprecated=true)
72 public static final String INIT_PARAM_HANDLE_STATE_CACHING_MECHANICS
73 = "org.apache.myfaces.HANDLE_STATE_CACHING_MECHANICS";
74
75
76
77
78 @JSFWebConfigParam(since="2.2.8, 2.1.18, 2.0.24", expectedValues="true, false",
79 defaultValue="true", group="state")
80 public static final String INIT_PARAM_AUTOCOMPLETE_OFF_VIEW_STATE =
81 "org.apache.myfaces.AUTOCOMPLETE_OFF_VIEW_STATE";
82
83 private StateCacheFactory _stateCacheFactory;
84
85 private StateTokenProcessor _stateTokenProcessor;
86
87 private Boolean _autoCompleteOffViewState;
88
89 public HtmlResponseStateManager()
90 {
91 _stateCacheFactory = new StateCacheFactoryImpl();
92 _stateTokenProcessor = new DefaultStateTokenProcessor();
93 _autoCompleteOffViewState = null;
94 }
95
96 @Override
97 public void writeState(FacesContext facesContext, Object state) throws IOException
98 {
99 ResponseWriter responseWriter = facesContext.getResponseWriter();
100
101 Object savedStateObject = null;
102
103 if (!facesContext.getViewRoot().isTransient())
104 {
105
106 savedStateObject = getStateCache(facesContext).encodeSerializedState(facesContext, state);
107 }
108
109
110 writeViewStateField(facesContext, responseWriter, savedStateObject);
111
112
113 writeRenderKitIdField(facesContext, responseWriter);
114
115
116 writeWindowIdField(facesContext, responseWriter);
117 }
118
119 private void writeWindowIdField(FacesContext facesContext, ResponseWriter responseWriter) throws IOException
120 {
121 ClientWindow clientWindow = facesContext.getExternalContext().getClientWindow();
122 if (clientWindow != null)
123 {
124 responseWriter.startElement(HTML.INPUT_ELEM, null);
125 responseWriter.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_HIDDEN, null);
126 responseWriter.writeAttribute(HTML.ID_ATTR, generateUpdateClientWindowId(facesContext), null);
127 responseWriter.writeAttribute(HTML.NAME_ATTR, ResponseStateManager.CLIENT_WINDOW_PARAM, null);
128 responseWriter.writeAttribute(HTML.VALUE_ATTR, clientWindow.getId(), null);
129 responseWriter.endElement(HTML.INPUT_ELEM);
130 }
131 }
132
133 @Override
134 public void saveState(FacesContext facesContext, Object state)
135 {
136 if (!facesContext.getViewRoot().isTransient())
137 {
138 getStateCache(facesContext).saveSerializedView(facesContext, state);
139 }
140 }
141
142 private void writeViewStateField(FacesContext facesContext, ResponseWriter responseWriter, Object savedState)
143 throws IOException
144 {
145 String serializedState = _stateTokenProcessor.encode(facesContext, savedState);
146 ExternalContext extContext = facesContext.getExternalContext();
147 MyfacesConfig myfacesConfig = MyfacesConfig.getCurrentInstance(extContext);
148
149 responseWriter.startElement(HTML.INPUT_ELEM, null);
150 responseWriter.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_HIDDEN, null);
151 responseWriter.writeAttribute(HTML.NAME_ATTR, STANDARD_STATE_SAVING_PARAM, null);
152 if (myfacesConfig.isRenderViewStateId())
153 {
154
155
156
157 responseWriter.writeAttribute(HTML.ID_ATTR,
158 HtmlResponseStateManager.generateUpdateViewStateId(
159 facesContext), null);
160 }
161 responseWriter.writeAttribute(HTML.VALUE_ATTR, serializedState, null);
162 if (this.isAutocompleteOffViewState(facesContext))
163 {
164 responseWriter.writeAttribute(HTML.AUTOCOMPLETE_ATTR, "off", null);
165 }
166 responseWriter.endElement(HTML.INPUT_ELEM);
167 }
168
169 private void writeRenderKitIdField(FacesContext facesContext, ResponseWriter responseWriter) throws IOException
170 {
171
172 String defaultRenderKitId = facesContext.getApplication().getDefaultRenderKitId();
173 if (defaultRenderKitId != null && !RenderKitFactory.HTML_BASIC_RENDER_KIT.equals(defaultRenderKitId))
174 {
175 responseWriter.startElement(HTML.INPUT_ELEM, null);
176 responseWriter.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_HIDDEN, null);
177 responseWriter.writeAttribute(HTML.NAME_ATTR, ResponseStateManager.RENDER_KIT_ID_PARAM, null);
178 responseWriter.writeAttribute(HTML.VALUE_ATTR, defaultRenderKitId, null);
179 responseWriter.endElement(HTML.INPUT_ELEM);
180 }
181 }
182
183 @Override
184 public Object getState(FacesContext facesContext, String viewId)
185 {
186 Object savedState = getSavedState(facesContext);
187 if (savedState == null)
188 {
189 return null;
190 }
191
192 return getStateCache(facesContext).restoreSerializedView(facesContext, viewId, savedState);
193 }
194
195
196
197
198
199
200
201
202
203 private Object getSavedState(FacesContext facesContext)
204 {
205 Object encodedState =
206 facesContext.getExternalContext().getRequestParameterMap().get(STANDARD_STATE_SAVING_PARAM);
207 if(encodedState==null || (((String) encodedState).length() == 0))
208 {
209 return null;
210 }
211
212 Object savedStateObject = _stateTokenProcessor.decode(facesContext, (String)encodedState);
213
214 return savedStateObject;
215 }
216
217
218
219
220
221
222 @Override
223 public boolean isPostback(FacesContext context)
224 {
225 return context.getExternalContext().getRequestParameterMap().containsKey(ResponseStateManager.VIEW_STATE_PARAM);
226 }
227
228 @Override
229 public String getViewState(FacesContext facesContext, Object baseState)
230 {
231
232
233
234
235 if (baseState == null)
236 {
237 return null;
238 }
239 if (facesContext.getViewRoot().isTransient())
240 {
241 return null;
242 }
243
244 Object state = getStateCache(facesContext).saveSerializedView(facesContext, baseState);
245
246 return _stateTokenProcessor.encode(facesContext, state);
247 }
248
249 @Override
250 public boolean isStateless(FacesContext context, String viewId)
251 {
252 if (context.isPostback())
253 {
254 String encodedState =
255 context.getExternalContext().getRequestParameterMap().get(STANDARD_STATE_SAVING_PARAM);
256 if(encodedState==null || (((String) encodedState).length() == 0))
257 {
258 return false;
259 }
260
261 return _stateTokenProcessor.isStateless(context, encodedState);
262 }
263 else
264 {
265
266
267
268 throw new IllegalStateException(
269 "Cannot decide if the view is stateless or not, since the request is "
270 + "not postback (no preceding writeState(...)).");
271 }
272 }
273
274 @Override
275 public String getCryptographicallyStrongTokenFromSession(FacesContext context)
276 {
277 Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
278 String savedToken = (String) sessionMap.get(SESSION_TOKEN);
279 if (savedToken == null)
280 {
281 savedToken = getStateCache(context).createCryptographicallyStrongTokenFromSession(context);
282 sessionMap.put(SESSION_TOKEN, savedToken);
283 }
284 return savedToken;
285 }
286
287 @Override
288 public boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext)
289 {
290 return getStateCache(facesContext).isWriteStateAfterRenderViewRequired(facesContext);
291 }
292
293 protected StateCache getStateCache(FacesContext facesContext)
294 {
295 return _stateCacheFactory.getStateCache(facesContext);
296 }
297
298 public static String generateUpdateClientWindowId(FacesContext facesContext)
299 {
300
301
302
303
304
305
306
307
308
309
310
311
312 String id;
313 char separator = facesContext.getNamingContainerSeparatorChar();
314 Integer count = (Integer) facesContext.getAttributes().get(CLIENT_WINDOW_COUNTER);
315 if (count == null)
316 {
317 count = Integer.valueOf(0);
318 }
319 count += 1;
320 id = facesContext.getViewRoot().getContainerClientId(facesContext) +
321 separator + ResponseStateManager.CLIENT_WINDOW_PARAM + separator + count;
322 facesContext.getAttributes().put(CLIENT_WINDOW_COUNTER, count);
323 return id;
324 }
325
326 public static String generateUpdateViewStateId(FacesContext facesContext)
327 {
328
329
330
331
332
333
334
335
336
337
338
339
340 String id;
341 char separator = facesContext.getNamingContainerSeparatorChar();
342 Integer count = (Integer) facesContext.getAttributes().get(VIEW_STATE_COUNTER);
343 if (count == null)
344 {
345 count = Integer.valueOf(0);
346 }
347 count += 1;
348 id = facesContext.getViewRoot().getContainerClientId(facesContext) +
349 separator + ResponseStateManager.VIEW_STATE_PARAM + separator + count;
350 facesContext.getAttributes().put(VIEW_STATE_COUNTER, count);
351 return id;
352 }
353
354 private static class DefaultStateTokenProcessor extends StateTokenProcessor
355 {
356 private static final String STATELESS_TOKEN = "stateless";
357
358 @Override
359 public Object decode(FacesContext facesContext, String token)
360 {
361 if (STATELESS_TOKEN.equals(token))
362 {
363
364
365 return null;
366 }
367 Object savedStateObject = StateUtils.reconstruct((String)token, facesContext.getExternalContext());
368 return savedStateObject;
369 }
370
371 @Override
372 public String encode(FacesContext facesContext, Object savedStateObject)
373 {
374 if (facesContext.getViewRoot().isTransient())
375 {
376 return STATELESS_TOKEN;
377 }
378 String serializedState = StateUtils.construct(savedStateObject, facesContext.getExternalContext());
379 return serializedState;
380 }
381
382 @Override
383 public boolean isStateless(FacesContext facesContext, String token)
384 {
385 return STATELESS_TOKEN.equals(token);
386 }
387 }
388
389 private boolean isAutocompleteOffViewState(FacesContext facesContext)
390 {
391 if (_autoCompleteOffViewState == null)
392 {
393 _autoCompleteOffViewState = WebConfigParamUtils.getBooleanInitParameter(facesContext.getExternalContext(),
394 INIT_PARAM_AUTOCOMPLETE_OFF_VIEW_STATE, true);
395 }
396 return _autoCompleteOffViewState;
397 }
398 }