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 javax.faces.context.FacesContext;
29
30 import org.apache.myfaces.trinidad.bean.util.StateUtils;
31 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
32
33 /**
34 * Key for an entry in a FacesBean.
35 */
36 public class PropertyKey
37 {
38 /**
39 * Capability indicating this property does not support bindings.
40 */
41 static public final int CAP_NOT_BOUND = 1;
42
43 /**
44 * Capability indicating this property is transient.
45 */
46 static public final int CAP_TRANSIENT = 2;
47
48 /**
49 * Capability indicating this property describes a list. List
50 * PropertyKeys will automatically be marked as not supporting
51 * bindings.
52 */
53 static public final int CAP_LIST = 4;
54
55 /**
56 * Capability indicating this property can use the StateHolder API.
57 */
58 static public final int CAP_STATE_HOLDER = 8;
59
60 /**
61 * Create a named PropertyKey, not attached to any type.
62 */
63 static public PropertyKey createPropertyKey(String name)
64 {
65 return new PropertyKey(name);
66 }
67
68
69
70
71
72
73
74
75
76 PropertyKey(
77 String name)
78 {
79 this(name, _TYPE_DEFAULT);
80 }
81
82 PropertyKey(
83 String name,
84 Class<?> type)
85 {
86 this(name, type, null);
87 }
88
89 PropertyKey(
90 String name,
91 Class<?> type,
92 Object defaultValue)
93 {
94 this(name, type, defaultValue, _CAPS_DEFAULT, -1);
95 }
96
97
98 protected PropertyKey(
99 String name,
100 Class<?> type,
101 Object defaultValue,
102 int capabilities,
103 int index)
104 {
105 if (name == null)
106 throw new NullPointerException();
107
108 if (type == null)
109 throw new NullPointerException();
110
111 if (defaultValue != null)
112 {
113
114 Class<?> boxedType = _getBoxedType(type);
115 if (!boxedType.isAssignableFrom(defaultValue.getClass()))
116 {
117 throw new IllegalStateException(_LOG.getMessage(
118 "DEFAULT_VALUE_IS_NOT_ASSIGNED_TO_TYPE", new Object[]{defaultValue, type}));
119 }
120 }
121 else
122 {
123
124 defaultValue = _getJavaDefault(type);
125
126
127 if (defaultValue == null)
128 defaultValue = _OBJECT_NULL;
129 }
130
131 if ((capabilities & ~_CAPS_ALL) != 0)
132 throw new IllegalStateException(_LOG.getMessage(
133 "CAPABILITY_MASK_NOT_UNDERSTOOD", (capabilities & ~_CAPS_ALL)));
134
135
136 boolean hasListCapability = (capabilities & CAP_LIST) != 0;
137
138 if (hasListCapability)
139 capabilities = capabilities | CAP_NOT_BOUND;
140
141 _name = name;
142 _type = type;
143 _default = defaultValue;
144 _capabilities = capabilities;
145 _index = index;
146
147
148 _serializeAsList = hasListCapability || LIST_CLASS.isAssignableFrom(_type);
149 _hashCode = _name.hashCode();
150 }
151
152 /**
153 * Returns the type of this property.
154 */
155 public Class<?> getType()
156 {
157 return _type;
158 }
159
160 /**
161 * Returns the default value of this property.
162 */
163 public Object getDefault()
164 {
165 return (_default != _OBJECT_NULL) ? _default : null;
166 }
167
168 /**
169 * Returns the owning type for this property key.
170 */
171 public FacesBean.Type getOwner()
172 {
173 return _owner;
174 }
175
176 /**
177 * Returns true if the property supports being bound.
178 */
179 public boolean getSupportsBinding()
180 {
181 return (_capabilities & CAP_NOT_BOUND) == 0;
182 }
183
184 /**
185 * Returns true if the property is transient.
186 */
187 public boolean isTransient()
188 {
189 return (_capabilities & CAP_TRANSIENT) != 0;
190 }
191
192 /**
193 * Returns true if the property is used to store a list.
194 */
195 public boolean isList()
196 {
197 return (_capabilities & CAP_LIST) != 0;
198 }
199
200 /**
201 * Returns the name of this property.
202 */
203 public String getName()
204 {
205 return _name;
206 }
207
208 /**
209 * Returns the index of this property.
210 */
211 public int getIndex()
212 {
213 return _index;
214 }
215
216
217 public Object saveValue(
218 FacesContext context,
219 Object value)
220 {
221 if ((_capabilities & CAP_STATE_HOLDER) != 0)
222 return StateUtils.saveStateHolder(context, value);
223
224
225
226 if (this._serializeAsList && (value instanceof List))
227 return StateUtils.saveList(context, value);
228
229
230
231 if ((value != null) && !(value instanceof Serializable) && _LOG.isWarning())
232 _LOG.warning(_LOG.getMessage("UNSERIALIZABLE_PROPERTY_VALUE_NO_CONTAINER",
233 new Object[]{value, this}));
234
235 return value;
236 }
237
238 public Object restoreValue(
239 FacesContext context,
240 Object savedValue)
241 {
242 if ((_capabilities & CAP_STATE_HOLDER) != 0)
243 return StateUtils.restoreStateHolder(context, savedValue);
244
245 if (this._serializeAsList && (savedValue instanceof Object[]))
246 return StateUtils.restoreList(context, savedValue);
247
248 return savedValue;
249 }
250
251
252 @Override
253 public boolean equals(Object o)
254 {
255 if (o == this)
256 return true;
257
258 if (!(o instanceof PropertyKey))
259 return false;
260
261 PropertyKey that = (PropertyKey)o;
262
263
264 if (_owner != that._owner)
265 return false;
266
267
268
269 int index = this._index;
270 if (index == -1)
271 {
272 return ((that._index == -1) &&
273 (that._name.equals(_name)) &&
274 (that._type.equals(_type)) &&
275 (that._default.equals(_default)));
276 }
277
278
279
280
281 return false;
282 }
283
284 @Override
285 public int hashCode()
286 {
287 return _hashCode;
288 }
289
290 @Override
291 public String toString()
292 {
293 String className = getClass().getName();
294 int lastPeriod = className.lastIndexOf('.');
295 if (lastPeriod >= 0)
296 className = className.substring(lastPeriod + 1);
297
298 if (_index >= 0)
299 return className + "[" + _name + "," + _index + "]";
300 return className + "[" + _name + "]";
301 }
302
303 void __setOwner(FacesBean.Type owner)
304 {
305 _owner = owner;
306 }
307
308 static private Object _getJavaDefault(
309 Class<?> type)
310 {
311 return _PRIMITIVE_DEFAULTS.get(type);
312 }
313
314 static private Class<?> _getBoxedType(
315 Class<?> type)
316 {
317 Class<?> boxedType = _BOXED_PRIMITIVES.get(type);
318 return (boxedType != null ? boxedType : type);
319 }
320
321 static private Map<Class<?>, Object> _createPrimitiveDefaults()
322 {
323 Map<Class<?>, Object> map = new HashMap<Class<?>, Object>();
324 map.put(Boolean.TYPE, Boolean.FALSE);
325 map.put(Byte.TYPE, Byte.valueOf((byte)0));
326 map.put(Character.TYPE, Character.valueOf('\0'));
327 map.put(Double.TYPE, Double.valueOf(0.0));
328 map.put(Float.TYPE, Float.valueOf(0.0f));
329 map.put(Integer.TYPE, Integer.valueOf(0));
330 map.put(Long.TYPE, Long.valueOf(0L));
331 map.put(Short.TYPE, Short.valueOf((short)0));
332
333 return Collections.unmodifiableMap(map);
334 }
335
336 static private Map<Class<?>, Class<?>> _createBoxedPrimitives()
337 {
338 Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>();
339 map.put(Boolean.TYPE, Boolean.class);
340 map.put(Byte.TYPE, Byte.class);
341 map.put(Character.TYPE, Character.class);
342 map.put(Double.TYPE, Double.class);
343 map.put(Float.TYPE, Float.class);
344 map.put(Integer.TYPE, Integer.class);
345 map.put(Long.TYPE, Long.class);
346 map.put(Short.TYPE, Short.class);
347
348 return Collections.unmodifiableMap(map);
349 }
350
351 static private final Map<Class<?>, Object> _PRIMITIVE_DEFAULTS = _createPrimitiveDefaults();
352 static private final Map<Class<?>, Class<?>> _BOXED_PRIMITIVES = _createBoxedPrimitives();
353
354 private final int _hashCode;
355 private final String _name;
356 private final int _index;
357 private final int _capabilities;
358 private final Class<?> _type;
359 private final Object _default;
360
361 private final boolean _serializeAsList;
362 private FacesBean.Type _owner;
363
364 private static final Class<List> LIST_CLASS = List.class;
365
366 static private final int _CAPS_DEFAULT =
367 0;
368
369 static private final int _CAPS_ALL =
370 CAP_NOT_BOUND |
371 CAP_TRANSIENT |
372 CAP_LIST |
373 CAP_STATE_HOLDER;
374
375 static private final Class<Object> _TYPE_DEFAULT = Object.class;
376
377 static private final Object _OBJECT_NULL = new Object();
378 private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
379 PropertyKey.class);
380 }
381
382
383
384