1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.bean;
20
21 import java.io.Serializable;
22
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ConcurrentMap;
30
31 import javax.faces.context.FacesContext;
32
33 import org.apache.myfaces.trinidad.bean.util.StateUtils;
34 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
35
36
37
38
39 public class PropertyKey
40 {
41
42
43
44 static public final int CAP_NOT_BOUND = 1;
45
46
47
48
49 static public final int CAP_TRANSIENT = 2;
50
51
52
53
54
55
56 static public final int CAP_LIST = 4;
57
58
59
60
61 static public final int CAP_STATE_HOLDER = 8;
62
63
64
65
66 static public final int CAP_PARTIAL_STATE_HOLDER = 16;
67
68
69
70
71
72
73 public enum Mutable {
74 IMMUTABLE,
75 RARELY,
76 SOMETIMES,
77 OFTEN;
78
79 public boolean isAtLeastSometimesMutable()
80 {
81 return (compareTo(SOMETIMES) > -1);
82 }
83 };
84
85
86
87
88
89 static public PropertyKey createPropertyKey(String name)
90 {
91 return new PropertyKey(name);
92 }
93
94 private static final ConcurrentMap<String, PropertyKey> _sDefaultKeyCache =
95 new ConcurrentHashMap<String, PropertyKey>();
96
97
98
99
100 public static PropertyKey getDefaultPropertyKey(String name)
101 {
102 PropertyKey cachedKey = _sDefaultKeyCache.get(name);
103
104 if (cachedKey == null)
105 {
106 cachedKey = new PropertyKey(name);
107
108
109 _sDefaultKeyCache.put(name, cachedKey);
110 }
111
112 return cachedKey;
113 }
114
115
116
117
118
119
120
121
122
123 PropertyKey(
124 String name)
125 {
126 this(name, _TYPE_DEFAULT);
127 }
128
129 PropertyKey(
130 String name,
131 Class<?> type)
132 {
133 this(name, type, null);
134 }
135
136 PropertyKey(
137 String name,
138 Class<?> type,
139 Object defaultValue)
140 {
141 this(name, type, defaultValue, _CAPS_DEFAULT, -1);
142 }
143
144
145 protected PropertyKey(
146 String name,
147 Class<?> type,
148 Object defaultValue,
149 int capabilities,
150 int index)
151 {
152 this(name, type, defaultValue, capabilities, index, Mutable.IMMUTABLE);
153 }
154
155
156 protected PropertyKey(
157 String name,
158 Class<?> type,
159 Object defaultValue,
160 int capabilities,
161 int index,
162 Mutable mutable)
163 {
164 if (mutable == null)
165 throw new NullPointerException();
166
167 if (name == null)
168 throw new NullPointerException();
169
170 if (type == null)
171 throw new NullPointerException();
172
173 if (defaultValue != null)
174 {
175
176 Class<?> boxedType = _getBoxedType(type);
177 if (!boxedType.isAssignableFrom(defaultValue.getClass()))
178 {
179 throw new IllegalStateException(_LOG.getMessage(
180 "DEFAULT_VALUE_IS_NOT_ASSIGNED_TO_TYPE", new Object[]{defaultValue, type}));
181 }
182 }
183 else
184 {
185
186 defaultValue = _getJavaDefault(type);
187
188
189 if (defaultValue == null)
190 defaultValue = _OBJECT_NULL;
191 }
192
193 if ((capabilities & ~_CAPS_ALL) != 0)
194 throw new IllegalStateException(_LOG.getMessage(
195 "CAPABILITY_MASK_NOT_UNDERSTOOD", (capabilities & ~_CAPS_ALL)));
196
197
198 boolean hasListCapability = (capabilities & CAP_LIST) != 0;
199
200 if (hasListCapability)
201 capabilities = capabilities | CAP_NOT_BOUND;
202
203 _name = name;
204 _type = type;
205 _default = defaultValue;
206 _capabilities = capabilities;
207 _index = index;
208 _mutable = mutable;
209
210
211 _serializeAsList = hasListCapability || LIST_CLASS.isAssignableFrom(_type);
212 _hashCode = _name.hashCode();
213 }
214
215
216
217
218 public Class<?> getType()
219 {
220 return _type;
221 }
222
223
224
225
226 public Object getDefault()
227 {
228 return (_default != _OBJECT_NULL) ? _default : null;
229 }
230
231
232
233
234 public FacesBean.Type getOwner()
235 {
236 return _owner;
237 }
238
239
240
241
242 public boolean getSupportsBinding()
243 {
244 return (_capabilities & CAP_NOT_BOUND) == 0;
245 }
246
247
248
249
250 public boolean isTransient()
251 {
252 return (_capabilities & CAP_TRANSIENT) != 0;
253 }
254
255
256
257
258 public boolean isList()
259 {
260 return (_capabilities & CAP_LIST) != 0;
261 }
262
263
264
265
266 public Mutable getMutable()
267 {
268 return _mutable;
269 }
270
271
272
273
274 public boolean isPartialStateHolder()
275 {
276 return (_capabilities & CAP_PARTIAL_STATE_HOLDER) != 0;
277 }
278
279
280
281
282 public String getName()
283 {
284 return _name;
285 }
286
287
288
289
290 public int getIndex()
291 {
292 return _index;
293 }
294
295
296 public Object saveValue(
297 FacesContext context,
298 Object value)
299 {
300 if ((_capabilities & CAP_STATE_HOLDER) != 0)
301 return StateUtils.saveStateHolder(context, value);
302
303
304
305 if (this._serializeAsList && (value instanceof List))
306 return StateUtils.saveList(context, value);
307
308
309
310 if ((value != null) && !(value instanceof Serializable) && _LOG.isWarning())
311 _LOG.warning(_LOG.getMessage("UNSERIALIZABLE_PROPERTY_VALUE_NO_CONTAINER",
312 new Object[]{value, this}));
313
314 return value;
315 }
316
317 public Object restoreValue(
318 FacesContext context,
319 Object savedValue)
320 {
321 if ((_capabilities & CAP_STATE_HOLDER) != 0)
322 return StateUtils.restoreStateHolder(context, savedValue);
323
324 if (this._serializeAsList && (savedValue instanceof Object[]))
325 return StateUtils.restoreList(context, savedValue);
326
327 return savedValue;
328 }
329
330
331 @Override
332 public boolean equals(Object o)
333 {
334 if (o == this)
335 return true;
336
337 if (!(o instanceof PropertyKey))
338 return false;
339
340 PropertyKey that = (PropertyKey)o;
341
342
343 if (_owner != that._owner)
344 return false;
345
346
347
348 int index = this._index;
349 if (index == -1)
350 {
351 return ((that._index == -1) &&
352 (that._name.equals(_name)) &&
353 (that._type.equals(_type)) &&
354 (that._default.equals(_default)));
355 }
356
357
358
359
360 return false;
361 }
362
363 @Override
364 public int hashCode()
365 {
366 return _hashCode;
367 }
368
369 @Override
370 public String toString()
371 {
372 String className = getClass().getName();
373 int lastPeriod = className.lastIndexOf('.');
374 if (lastPeriod >= 0)
375 className = className.substring(lastPeriod + 1);
376
377 if (_index >= 0)
378 return className + "[" + _name + "," + _index + "]";
379 return className + "[" + _name + "]";
380 }
381
382 void __setOwner(FacesBean.Type owner)
383 {
384 _owner = owner;
385 }
386
387 static private Object _getJavaDefault(
388 Class<?> type)
389 {
390 return _PRIMITIVE_DEFAULTS.get(type);
391 }
392
393 static private Class<?> _getBoxedType(
394 Class<?> type)
395 {
396 Class<?> boxedType = _BOXED_PRIMITIVES.get(type);
397 return (boxedType != null ? boxedType : type);
398 }
399
400 static private Map<Class<?>, Object> _createPrimitiveDefaults()
401 {
402 Map<Class<?>, Object> map = new HashMap<Class<?>, Object>();
403 map.put(Boolean.TYPE, Boolean.FALSE);
404 map.put(Byte.TYPE, Byte.valueOf((byte)0));
405 map.put(Character.TYPE, Character.valueOf('\0'));
406 map.put(Double.TYPE, Double.valueOf(0.0));
407 map.put(Float.TYPE, Float.valueOf(0.0f));
408 map.put(Integer.TYPE, Integer.valueOf(0));
409 map.put(Long.TYPE, Long.valueOf(0L));
410 map.put(Short.TYPE, Short.valueOf((short)0));
411
412 return Collections.unmodifiableMap(map);
413 }
414
415 static private Map<Class<?>, Class<?>> _createBoxedPrimitives()
416 {
417 Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>();
418 map.put(Boolean.TYPE, Boolean.class);
419 map.put(Byte.TYPE, Byte.class);
420 map.put(Character.TYPE, Character.class);
421 map.put(Double.TYPE, Double.class);
422 map.put(Float.TYPE, Float.class);
423 map.put(Integer.TYPE, Integer.class);
424 map.put(Long.TYPE, Long.class);
425 map.put(Short.TYPE, Short.class);
426
427 return Collections.unmodifiableMap(map);
428 }
429
430 static private final Map<Class<?>, Object> _PRIMITIVE_DEFAULTS = _createPrimitiveDefaults();
431 static private final Map<Class<?>, Class<?>> _BOXED_PRIMITIVES = _createBoxedPrimitives();
432
433 private final int _hashCode;
434 private final String _name;
435 private final int _index;
436 private final int _capabilities;
437 private final Class<?> _type;
438 private final Object _default;
439
440 private final boolean _serializeAsList;
441 private FacesBean.Type _owner;
442 private final Mutable _mutable;
443
444 private static final Class<List> LIST_CLASS = List.class;
445
446 static private final int _CAPS_DEFAULT =
447 0;
448
449 static private final int _CAPS_ALL =
450 CAP_NOT_BOUND |
451 CAP_TRANSIENT |
452 CAP_LIST |
453 CAP_STATE_HOLDER|
454 CAP_PARTIAL_STATE_HOLDER;
455
456 static private final Class<Object> _TYPE_DEFAULT = Object.class;
457
458 static private final Object _OBJECT_NULL = new Object();
459 private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
460 PropertyKey.class);
461 }
462
463
464
465