View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.renderkit.html;
20  
21  import java.io.IOException;
22  import java.util.logging.Level;
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.render.RenderKitFactory;
29  import javax.faces.render.ResponseStateManager;
30  
31  import org.apache.myfaces.application.StateCache;
32  import org.apache.myfaces.application.StateCacheFactory;
33  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
34  import org.apache.myfaces.renderkit.MyfacesResponseStateManager;
35  import org.apache.myfaces.renderkit.StateCacheFactoryImpl;
36  import org.apache.myfaces.shared.config.MyfacesConfig;
37  import org.apache.myfaces.shared.renderkit.html.HTML;
38  import org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils;
39  import org.apache.myfaces.shared.renderkit.html.util.JavascriptUtils;
40  import org.apache.myfaces.shared.util.StateUtils;
41  import org.apache.myfaces.shared.util.WebConfigParamUtils;
42  
43  /**
44   * @author Manfred Geiler (latest modification by $Author: bommel $)
45   * @version $Revision: 1187700 $ $Date: 2011-10-22 07:19:37 -0500 (Sat, 22 Oct 2011) $
46   */
47  public class HtmlResponseStateManager extends MyfacesResponseStateManager
48  {
49      //private static final Log log = LogFactory.getLog(HtmlResponseStateManager.class);
50      private static final Logger log = Logger.getLogger(HtmlResponseStateManager.class.getName());
51  
52      //private static final int TREE_PARAM = 2;
53      private static final int STATE_PARAM = 0;
54      private static final int VIEWID_PARAM = 1;
55  
56      public static final String STANDARD_STATE_SAVING_PARAM = "javax.faces.ViewState";
57      
58      /**
59       * Define if the state caching code should be handled by the ResponseStateManager or by the StateManager used.
60       * <p>
61       * This param is used to keep compatibility with previous state managers implementations depending from old myfaces
62       * way to deal with this. For example, JspStateManagerImpl requires this param set to false, but by default 
63       * it is set to true, to keep aligned with the Reference Implementation (RI).
64       * </p> 
65       */
66      @JSFWebConfigParam(since="2.0.6", expectedValues="true, false", defaultValue="true", group="state")
67      public static final String INIT_PARAM_HANDLE_STATE_CACHING_MECHANICS = "org.apache.myfaces.HANDLE_STATE_CACHING_MECHANICS";
68      
69      private Boolean _handleStateCachingMechanics;
70      
71      private StateCacheFactory _stateCacheFactory;
72      
73      public HtmlResponseStateManager()
74      {
75          _stateCacheFactory = new StateCacheFactoryImpl();
76      }
77      
78      protected boolean isHandlingStateCachingMechanics(FacesContext facesContext)
79      {
80          if (_handleStateCachingMechanics == null)
81          {
82              _handleStateCachingMechanics = WebConfigParamUtils.getBooleanInitParameter(facesContext.getExternalContext(), INIT_PARAM_HANDLE_STATE_CACHING_MECHANICS, true);
83          }
84          return _handleStateCachingMechanics.booleanValue();
85      }
86      
87      public void writeState(FacesContext facesContext, Object state) throws IOException
88      {
89          ResponseWriter responseWriter = facesContext.getResponseWriter();
90  
91          Object token = null;
92          Object[] savedState = new Object[2];
93          
94          if (isHandlingStateCachingMechanics(facesContext))
95          {
96              //token = getStateCache(facesContext).saveSerializedView(facesContext, state);
97              token = getStateCache(facesContext).encodeSerializedState(facesContext, state);
98          }
99          else
100         {
101             token = state;
102         }
103 
104         if (log.isLoggable(Level.FINEST))
105             log.finest("Writing state in client");
106 
107 
108         if (token != null)
109         {
110             savedState[STATE_PARAM] = token;
111         }
112         else
113         {
114             if (log.isLoggable(Level.FINEST))
115                 log.finest("No component states to be saved in client response!");
116         }
117 
118         savedState[VIEWID_PARAM] = facesContext.getViewRoot().getViewId();
119         
120         if (log.isLoggable(Level.FINEST))
121             log.finest("Writing view state and renderKit fields");
122 
123         // write the view state field
124         writeViewStateField(facesContext, responseWriter, savedState);
125 
126         // renderKitId field
127         writeRenderKitIdField(facesContext, responseWriter);
128     }
129     
130     @Override
131     public void saveState(FacesContext facesContext, Object state)
132     {
133         if (isHandlingStateCachingMechanics(facesContext))
134         {
135             getStateCache(facesContext).saveSerializedView(facesContext, state);
136         }
137         else
138         {
139             //This is done outside
140         }
141     }
142 
143     private void writeViewStateField(FacesContext facesContext, ResponseWriter responseWriter, Object savedState)
144         throws IOException
145     {
146         String serializedState = StateUtils.construct(savedState, facesContext.getExternalContext());
147         ExternalContext extContext = facesContext.getExternalContext();
148         MyfacesConfig myfacesConfig = MyfacesConfig.getCurrentInstance(extContext);
149         // Write Javascript viewstate if enabled and if javascript is allowed,
150         // otherwise write hidden input
151         if (JavascriptUtils.isJavascriptAllowed(extContext) && myfacesConfig.isViewStateJavascript())
152         {
153             HtmlRendererUtils.renderViewStateJavascript(facesContext, STANDARD_STATE_SAVING_PARAM, serializedState);
154         }
155         else
156         {
157             responseWriter.startElement(HTML.INPUT_ELEM, null);
158             responseWriter.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_HIDDEN, null);
159             responseWriter.writeAttribute(HTML.NAME_ATTR, STANDARD_STATE_SAVING_PARAM, null);
160             if (myfacesConfig.isRenderViewStateId())
161             {
162                 responseWriter.writeAttribute(HTML.ID_ATTR, STANDARD_STATE_SAVING_PARAM, null);
163             }
164             responseWriter.writeAttribute(HTML.VALUE_ATTR, serializedState, null);
165             responseWriter.endElement(HTML.INPUT_ELEM);
166         }
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         if (isHandlingStateCachingMechanics(facesContext))
193         {
194             return getStateCache(facesContext).restoreSerializedView(facesContext, viewId, savedState[STATE_PARAM]);
195         }
196         else
197         {
198             return savedState[STATE_PARAM];
199         }
200     }
201 
202     /* There methods are no longer required
203     @Override
204     public Object getTreeStructureToRestore(FacesContext facesContext, String viewId)
205     {
206         // Although this method won't be called anymore,
207         // it has been kept for backward compatibility.
208         Object[] savedState = getSavedState(facesContext);
209         if (savedState == null)
210         {
211             return null;
212         }
213 
214         return savedState[TREE_PARAM];
215     }
216 
217     @Override
218     public Object getComponentStateToRestore(FacesContext facesContext)
219     {
220         // Although this method won't be called anymore,
221         // it has been kept for backward compatibility.
222         Object[] savedState = getSavedState(facesContext);
223         if (savedState == null)
224         {
225             return null;
226         }
227 
228         return savedState[STATE_PARAM];
229     }*/
230 
231     /**
232      * Reconstructs the state from the "javax.faces.ViewState" request parameter.
233      * 
234      * @param facesContext
235      *            the current FacesContext
236      * 
237      * @return the reconstructed state, or <code>null</code> if there was no saved state
238      */
239     private Object[] getSavedState(FacesContext facesContext) {
240         Object encodedState = 
241             facesContext.getExternalContext().
242                 getRequestParameterMap().get(STANDARD_STATE_SAVING_PARAM);
243         if(encodedState==null || (((String) encodedState).length() == 0)) { 
244             return null;
245         }
246 
247         Object[] savedState = (Object[])StateUtils.reconstruct((String)encodedState, facesContext.getExternalContext());
248 
249 
250         if (savedState == null)
251         {
252             if (log.isLoggable(Level.FINEST)) {
253                 log.finest("No saved state");
254             }
255             return null;
256         }
257         
258         String restoredViewId = (String)savedState[VIEWID_PARAM];
259 
260         if (restoredViewId == null)
261         {
262             // no saved state or state of different viewId
263             if (log.isLoggable(Level.FINEST))
264             {
265                 log.finest("No saved state or state of a different viewId: " + restoredViewId);
266             }
267 
268             return null;
269         }
270 
271         return savedState;
272     }
273 
274     /**
275      * Checks if the current request is a postback
276      * 
277      * @since 1.2
278      */
279     @Override
280     public boolean isPostback(FacesContext context)
281     {
282         return context.getExternalContext().getRequestParameterMap().containsKey(ResponseStateManager.VIEW_STATE_PARAM);
283     }
284 
285     @Override
286     public String getViewState(FacesContext facesContext, Object baseState)
287     {
288         if (baseState == null)
289         {
290             return null;
291         }
292         
293         Object state = null;
294         if (isHandlingStateCachingMechanics(facesContext))
295         {
296             state = getStateCache(facesContext).saveSerializedView(facesContext, baseState);
297         }
298         else
299         {
300             state = baseState;
301         }
302         
303         Object[] savedState = new Object[2];
304         
305         if (state != null)
306         {
307             savedState[STATE_PARAM] = state;
308         }
309         
310         savedState[VIEWID_PARAM] = facesContext.getViewRoot().getViewId();
311         
312         return StateUtils.construct(savedState, facesContext.getExternalContext());
313     }
314     
315     @Override
316     public boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext)
317     {
318         return getStateCache(facesContext).isWriteStateAfterRenderViewRequired(facesContext);
319     }
320 
321     protected StateCache getStateCache(FacesContext facesContext)
322     {
323         return _stateCacheFactory.getStateCache(facesContext);
324     }
325 
326 }