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