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 java.util.Map;
22  import java.util.Random;
23  import javax.faces.context.ExternalContext;
24  import javax.faces.context.FacesContext;
25  import javax.xml.bind.DatatypeConverter;
26  
27  import org.apache.myfaces.shared.renderkit.RendererUtils;
28  import org.apache.myfaces.shared.util.WebConfigParamUtils;
29  
30  /**
31   *
32   */
33  class RandomKeyFactory extends KeyFactory<byte[]>
34  {
35      private final Random random;
36      private final int length;
37  
38      public RandomKeyFactory(FacesContext facesContext)
39      {
40          length = WebConfigParamUtils.getIntegerInitParameter(
41              facesContext.getExternalContext(), 
42              ServerSideStateCacheImpl.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM, 
43              ServerSideStateCacheImpl.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
44          random = new Random(((int) System.nanoTime()) + this.hashCode());
45      }
46  
47      public Integer generateCounterKey(FacesContext facesContext)
48      {
49          ExternalContext externalContext = facesContext.getExternalContext();
50          Object sessionObj = externalContext.getSession(true);
51          Integer sequence;
52          synchronized (sessionObj) // are handled at the same time for the session
53          {
54              Map<String, Object> map = externalContext.getSessionMap();
55              sequence = (Integer) map.get(RendererUtils.SEQUENCE_PARAM);
56              if (sequence == null || sequence == Integer.MAX_VALUE)
57              {
58                  sequence = 1;
59              }
60              else
61              {
62                  sequence = sequence + 1;
63              }
64              map.put(RendererUtils.SEQUENCE_PARAM, sequence);
65          }
66          return sequence;
67      }
68  
69      @Override
70      public byte[] generateKey(FacesContext facesContext)
71      {
72          byte[] array = new byte[length];
73          byte[] key = new byte[length + 4];
74          //sessionIdGenerator.getRandomBytes(array);
75          random.nextBytes(array);
76          for (int i = 0; i < array.length; i++)
77          {
78              key[i] = array[i];
79          }
80          int value = generateCounterKey(facesContext);
81          key[array.length] = (byte) (value >>> 24);
82          key[array.length + 1] = (byte) (value >>> 16);
83          key[array.length + 2] = (byte) (value >>> 8);
84          key[array.length + 3] = (byte) (value);
85          return key;
86      }
87  
88      @Override
89      public String encode(byte[] key)
90      {
91          return DatatypeConverter.printHexBinary(key);
92      }
93  
94      @Override
95      public byte[] decode(String value)
96      {
97          try
98          {
99              return DatatypeConverter.parseHexBinary(value);
100         }
101         catch (IllegalArgumentException ex)
102         {
103             // Cannot decode, ignore silently, later it will be handled as
104             // ViewExpiredException
105         }
106         return null;
107     }
108     
109 }