View Javadoc

1   /*
2    * $Id: AbstractInformation.java,v 1.7 2010/08/10 14:02:30 oeuillot Exp $
3    */
4   package org.rcfaces.core.internal.contentAccessor;
5   
6   import java.io.ByteArrayOutputStream;
7   import java.io.IOException;
8   import java.io.ObjectOutputStream;
9   import java.io.Serializable;
10  import java.lang.reflect.Array;
11  import java.security.MessageDigest;
12  import java.util.Collection;
13  import java.util.Collections;
14  import java.util.HashMap;
15  import java.util.Iterator;
16  import java.util.Map;
17  import java.util.Map.Entry;
18  
19  import javax.faces.component.StateHolder;
20  import javax.faces.component.UIComponentBase;
21  import javax.faces.context.FacesContext;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.rcfaces.core.internal.Constants;
26  import org.rcfaces.core.internal.lang.StringAppender;
27  import org.rcfaces.core.internal.util.Base64;
28  import org.rcfaces.core.internal.util.MessageDigestSelector;
29  import org.rcfaces.core.internal.util.StateHolderTools;
30  
31  /**
32   * 
33   * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
34   * @version $Revision: 1.7 $ $Date: 2010/08/10 14:02:30 $
35   */
36  public class AbstractInformation implements StateHolder,
37          IResourceKeyParticipant {
38      private static final String REVISION = "$Revision: 1.7 $";
39  
40      private static final Log LOG = LogFactory.getLog(AbstractInformation.class);
41  
42      private static final int INITIAL_KEY_SIZE = 4096;
43  
44      private static final int INITIAL_SERIALIZATION_SIZE = 16000;
45  
46      private Map attributes;
47  
48      private boolean transientState;
49  
50      private String cachedParticipeKey = null;
51  
52      private long hashCode = 0;
53  
54      public final Object getAttribute(String attributeName) {
55          if (attributes == null) {
56              return null;
57          }
58  
59          return attributes.get(attributeName);
60      }
61  
62      public final Object setAttribute(String attributeName, Object attributeValue) {
63          cachedParticipeKey = null;
64  
65          if (attributes == null) {
66              attributes = new HashMap();
67          }
68  
69          return attributes.put(attributeName, attributeValue);
70      }
71  
72      public final Map getAttributes() {
73          if (attributes == null) {
74              return Collections.EMPTY_MAP;
75          }
76          return attributes;
77      }
78  
79      public int hashCode() {
80          return computeCachedParticipeKey().hashCode();
81      }
82  
83      private String computeCachedParticipeKey() {
84          if (cachedParticipeKey != null) {
85              return cachedParticipeKey;
86          }
87  
88          StringAppender sa = new StringAppender(INITIAL_KEY_SIZE);
89          participeKey(sa);
90  
91          cachedParticipeKey = sa.toString();
92  
93          return cachedParticipeKey;
94      }
95  
96      public boolean equals(Object obj) {
97          if (this == obj)
98              return true;
99          if (obj == null)
100             return false;
101         if (getClass() != obj.getClass())
102             return false;
103         final AbstractInformation other = (AbstractInformation) obj;
104 
105         return computeCachedParticipeKey().equals(
106                 other.computeCachedParticipeKey());
107     }
108 
109     public void restoreState(FacesContext context, Object state) {
110         cachedParticipeKey = null;
111 
112         Object states[] = (Object[]) state;
113 
114         attributes = new HashMap(states.length / 2);
115 
116         for (int i = 0; i < states.length;) {
117             String key = (String) states[i++];
118 
119             Object value = states[i++];
120             if (StateHolderTools.isPrimitive(value) == false) {
121                 value = UIComponentBase.restoreAttachedState(context, value);
122             }
123 
124             attributes.put(key, value);
125         }
126     }
127 
128     public Object saveState(FacesContext context) {
129         Object ret[] = new Object[attributes.size() * 2];
130 
131         int i = 0;
132         for (Iterator it = attributes.entrySet().iterator(); it.hasNext();) {
133             Map.Entry entry = (Entry) it.next();
134 
135             ret[i++] = entry.getKey();
136 
137             Object value = entry.getValue();
138 
139             if (StateHolderTools.isPrimitive(value)) {
140                 ret[i++] = value;
141                 continue;
142             }
143 
144             ret[i++] = UIComponentBase.saveAttachedState(context, value);
145         }
146 
147         return ret;
148     }
149 
150     public boolean isTransient() {
151         return transientState;
152     }
153 
154     public void setTransient(boolean transientState) {
155         this.transientState = transientState;
156     }
157 
158     protected void appendToKey(StringAppender sa, String propertyName,
159             Object value) {
160         LOG.debug("Ignore key '" + propertyName + "'.");
161     }
162 
163     protected boolean participeSerializableHashCode(StringAppender sa,
164             String propertyName, Serializable serializable) {
165 
166         if (serializable == null) {
167             participeValue(sa, propertyName, null);
168             return true;
169         }
170 
171         try {
172             ByteArrayOutputStream byos = new ByteArrayOutputStream(
173                     INITIAL_SERIALIZATION_SIZE);
174             ObjectOutputStream oos = new ObjectOutputStream(byos);
175 
176             oos.writeObject(serializable);
177 
178             oos.close();
179 
180             byte result[] = byos.toByteArray();
181 
182             MessageDigest messageDigest = MessageDigestSelector
183                     .getInstance(Constants.SERIALISATION_HASH_ALGORITHMS);
184 
185             byte digested[] = messageDigest.digest(result);
186 
187             String hashCode = Base64.encodeBytes(digested,
188                     Base64.DONT_BREAK_LINES);
189 
190             StringAppender hc = new StringAppender(hashCode, 16);
191             hc.append(':').append(result.length);
192 
193             participeValue(sa, propertyName, hc);
194 
195             return true;
196 
197         } catch (IOException ex) {
198             LOG.error("Can not compute hashcode of serializable "
199                     + serializable, ex);
200         }
201 
202         return false;
203     }
204 
205     public void participeKey(StringAppender sa) {
206         for (Iterator it = attributes.entrySet().iterator(); it.hasNext();) {
207             Map.Entry entry = (Entry) it.next();
208 
209             String key = (String) entry.getKey();
210 
211             sa.append(IResourceKeyParticipant.RESOURCE_KEY_SEPARATOR).append(
212                     key);
213 
214             Object value = entry.getValue();
215             if (value == null) {
216                 continue;
217             }
218 
219             participeValue(sa, key, value);
220         }
221     }
222 
223     private void participeValue(StringAppender sa, String key, Object value) {
224 
225         if ((value instanceof String) || (value instanceof Number)
226                 || (value instanceof Boolean)) {
227             sa.append(IResourceKeyParticipant.RESOURCE_KEY_SEPARATOR).append(
228                     String.valueOf(value));
229             return;
230         }
231 
232         if (value instanceof StringAppender) {
233             sa.append(IResourceKeyParticipant.RESOURCE_KEY_SEPARATOR).append(
234                     (StringAppender) value);
235             return;
236         }
237 
238         if (value instanceof IResourceKeyParticipant) {
239             sa.append(IResourceKeyParticipant.RESOURCE_KEY_SEPARATOR);
240             ((IResourceKeyParticipant) value).participeKey(sa);
241             return;
242         }
243 
244         if (value.getClass().isArray()) {
245             int len = Array.getLength(value);
246             sa.append('[');
247             for (int i = 0; i < len; i++) {
248                 if (i > 0) {
249                     sa.append(',');
250                 }
251 
252                 Object valueItem = Array.get(value, i);
253                 if (valueItem == null) {
254                     continue;
255                 }
256 
257                 participeValue(sa, key, valueItem);
258             }
259 
260             sa.append(']');
261 
262             return;
263         }
264 
265         if (value instanceof Collection) {
266             Collection cl = (Collection) value;
267 
268             sa.append('[');
269             boolean first = true;
270             for (Iterator it = cl.iterator(); it.hasNext();) {
271                 if (first) {
272                     first = false;
273                 } else {
274                     sa.append(',');
275                 }
276 
277                 Object valueItem = it.next();
278                 if (valueItem == null) {
279                     continue;
280                 }
281 
282                 participeValue(sa, key, valueItem);
283             }
284 
285             sa.append(']');
286 
287             return;
288         }
289 
290         appendToKey(sa, key, value);
291 
292     }
293 
294 }