1
2
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
34
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 }