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.application.viewstate;
20  
21  import javax.faces.context.ExternalContext;
22  import javax.faces.context.FacesContext;
23  
24  import org.apache.myfaces.application.StateCache;
25  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
26  import org.apache.myfaces.shared.util.WebConfigParamUtils;
27  
28  class ClientSideStateCacheImpl extends StateCache<Object, Object>
29  {
30      
31      /**
32       * Define the time in minutes where the view state is valid when
33       * client side state saving is used. By default it is set to 0
34       * (infinite).
35       */
36      @JSFWebConfigParam(since="2.1.9, 2.0.15", defaultValue="0", group="state")
37      public static final String INIT_PARAM_CLIENT_VIEW_STATE_TIMEOUT = 
38              "org.apache.myfaces.CLIENT_VIEW_STATE_TIMEOUT";
39      public static final Long INIT_PARAM_CLIENT_VIEW_STATE_TIMEOUT_DEFAULT = 0L;
40      
41      private static final int STATE_PARAM = 0;
42      private static final int VIEWID_PARAM = 1;
43      private static final int TIMESTAMP_PARAM = 2;
44      
45      private static final Object[] EMPTY_STATES = new Object[]{null, null};
46      
47      private Long _clientViewStateTimeout;
48  
49      @Override
50      public Object saveSerializedView(FacesContext facesContext,
51              Object serializedView)
52      {
53          // The state in this case the state is saved on the token sent to
54          // the client (isWriteStateAfterRenderViewRequired() is set to true).
55          // No additional operation is required here.
56          return encodeSerializedState(facesContext, serializedView);
57      }
58  
59      @Override
60      public Object restoreSerializedView(FacesContext facesContext,
61              String viewId, Object viewState)
62      {
63          Object[] state = (Object[]) viewState;
64          long clientViewStateTimeout = getClientViewStateTimeout(facesContext.getExternalContext());
65          
66          if (clientViewStateTimeout > 0L)
67          {
68              Long timeStamp = (Long) state[TIMESTAMP_PARAM];
69              if (timeStamp == null)
70              {
71                  //If no timestamp, state is invalid.
72                  return null;
73              }
74              long passedTime = (System.currentTimeMillis() - timeStamp.longValue()) / 60000;
75              
76              if (passedTime > clientViewStateTimeout)
77              {
78                  //expire
79                  return null;
80              }
81          }
82          
83          String restoredViewId = (String) state[VIEWID_PARAM];
84          
85          if (viewId != null && !viewId.equals(restoredViewId))
86          {
87              //invalid viewId, expire
88              return null;
89          }
90          
91          //return the state
92          if (state[STATE_PARAM] == null)
93          {
94              return EMPTY_STATES;
95          }
96          else
97          {
98              Object serializedView = state[STATE_PARAM];
99              if (serializedView instanceof Object[] &&
100             ((Object[])serializedView).length == 2 &&
101             ((Object[])serializedView)[0] == null &&
102             ((Object[])serializedView)[1] == null)
103             {
104                 // Remember inside the state null is stored as an empty array.
105                 return null;
106             }
107             
108             return state[STATE_PARAM];
109         }
110     }
111 
112     @Override
113     public Object encodeSerializedState(FacesContext facesContext,
114             Object serializedView)
115     {
116         Object[] state = null;
117         
118         if (getClientViewStateTimeout(facesContext.getExternalContext()).longValue() > 0L)
119         {
120             state = new Object[3];
121             state[TIMESTAMP_PARAM] = System.currentTimeMillis();
122         }
123         else
124         {
125             state = new Object[2];
126         }
127         
128         if (serializedView == null)
129         {
130             state[STATE_PARAM] = EMPTY_STATES;
131         }
132         else if (serializedView instanceof Object[] &&
133             ((Object[])serializedView).length == 2 &&
134             ((Object[])serializedView)[0] == null &&
135             ((Object[])serializedView)[1] == null)
136         {
137             // The generated state can be considered zero, set it as null
138             // into the map.
139             state[STATE_PARAM] = null;
140         }
141         else
142         {
143             state[STATE_PARAM] = serializedView;
144         }
145 
146         state[VIEWID_PARAM] = facesContext.getViewRoot().getViewId();
147         
148         return state;
149     }
150 
151     @Override
152     public boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext)
153     {
154         return true;
155     }
156 
157     /**
158      * @return the _clientViewStateTimeout
159      */
160     protected Long getClientViewStateTimeout(ExternalContext context)
161     {
162         if (_clientViewStateTimeout == null)
163         {
164             _clientViewStateTimeout = WebConfigParamUtils.getLongInitParameter(
165                     context, INIT_PARAM_CLIENT_VIEW_STATE_TIMEOUT,
166                     INIT_PARAM_CLIENT_VIEW_STATE_TIMEOUT_DEFAULT);
167             if (_clientViewStateTimeout.longValue() < 0L)
168             {
169                 _clientViewStateTimeout = 0L;
170             }
171         }
172         return _clientViewStateTimeout;
173     }
174 
175 }