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.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30 import javax.el.ValueExpression;
31
32 import javax.faces.context.FacesContext;
33 import javax.faces.el.ValueBinding;
34 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
35
36 /**
37 * Base interface for FacesBean storage objects.
38 *
39 */
40 public interface FacesBean
41 {
42 /**
43 * Returns the Type of this bean.
44 */
45 public Type getType();
46
47 /**
48 * Returns a property. If the property has not been explicitly
49 * set, and the key supports bindings, and a ValueBinding has
50 * been set for this key, that ValueBinding will be evaluated.
51 *
52 * @param key the property key
53 * @exception IllegalArgumentException if key is a list key
54 */
55
56 public Object getProperty(PropertyKey key);
57
58 /**
59 * Set a property.
60 * @exception IllegalArgumentException if key is a list key
61 */
62 public void setProperty(PropertyKey key, Object value);
63
64 /**
65 * Return a property, ignoring any value bindings.
66 *
67 * @exception IllegalArgumentException if key is a list key
68 */
69 public Object getLocalProperty(PropertyKey key);
70
71 /**
72 * Return the value expression for a key.
73 * @exception IllegalArgumentException if the property does
74 * not support value bindings.
75 */
76 public ValueExpression getValueExpression(PropertyKey key);
77
78 /**
79 * Return the value binding for a key.
80 * @exception IllegalArgumentException if the property does
81 * not support value bindings.
82 * @deprecated
83 */
84 public ValueBinding getValueBinding(PropertyKey key);
85
86 /**
87 * Gets the current unevaluated value for the specified property key.
88 * <p>The method will first look for a local value. If it exists, it will
89 * be returned. If it does not and the bean supports value expressions, the
90 * method will look for an expression with the specified key and return it
91 * directly if it exists without evaluatig its value.</p>
92 * <p>This method is mainly used when:</p>
93 * <ul>
94 * <li>The caller cannot ensure that FacesContext exists at the time
95 * of the call</li>
96 * <li>The FacesContext does not yet contains the managed bean
97 * referenced by the value binding</li>
98 * <li>The managed bean referenced by the value binding is not yet
99 * in a coherent state to evaluate the expression</li>
100 * </ul>
101 * <p>The most common use case of this method is for message attributes
102 * set on converters and validators using a value binding referencing
103 * a managed bean created by <code><f:loadBundle/><code>. Since
104 * loadBundle only creates its bean during the render response phase
105 * while converter and validators take action during process validation
106 * phase, the message property's value binding must be stored in a
107 * special <code>FacesMessage</code> implementation that will evaluate
108 * the binding only during render response.</p>
109 *
110 * @param key the parameter key of the raw property value to get.
111 *
112 * @return the local value of the specified key if it exists, a
113 * <code>ValueExpression</code> object if the specified key
114 * supports expressions and an expression was specified for that
115 * property, <code>null</code> otherwise.
116 *
117 * @throws IllegalArgumentException if the specified key is a list key.
118 *
119 * @see #getLocalProperty(PropertyKey)
120 * @see #getValueBinding(PropertyKey)
121 * @see #getValueExpression(PropertyKey)
122 */
123 public Object getRawProperty(PropertyKey key);
124
125 /**
126 * Set the value expression for a key.
127 * @exception IllegalArgumentException if the property does
128 * not support value expressions.
129 */
130 public void setValueExpression(PropertyKey key, ValueExpression expression);
131
132 /**
133 * Set the value binding for a key.
134 * @exception IllegalArgumentException if the property does
135 * not support value bindings.
136 * @deprecated
137 */
138 public void setValueBinding(PropertyKey key, ValueBinding binding);
139
140 /**
141 * Add an entry to a list. The same value may be added
142 * repeatedly; null is also a legal value. (Consumers of
143 * this API can apply more stringent rules to specific keys
144 * in cover functions.)
145 * @exception IllegalArgumentException if the key is not a list key.
146 */
147 public void addEntry(PropertyKey listKey, Object value);
148
149 /**
150 * Remove an entry from a list.
151 * @exception IllegalArgumentException if the key is not a list key.
152 */
153 public void removeEntry(PropertyKey listKey, Object value);
154
155 /**
156 * Return as an array all elements of this key that
157 * are instances of the specified class.
158 * @return an array whose instance type is the class
159 * @exception IllegalArgumentException if the key is not a list key.
160 */
161
162
163
164 public Object[] getEntries(PropertyKey listKey, Class<?> clazz);
165
166 /**
167 * Return true if at least one element of the list identified by
168 * this key is an instance of the specified class.
169 * @exception IllegalArgumentException if the key is not a list key.
170 */
171 public boolean containsEntry(PropertyKey listKey, Class<?> clazz);
172
173 /**
174 * Returns an iterator over all entries at this key.
175 * @exception IllegalArgumentException if the key is not a list key.
176 */
177
178 public Iterator<? extends Object> entries(PropertyKey listKey);
179
180 /**
181 * Copies all properties, bindings, and list entries from
182 * one bean to another. If the beans are of different types,
183 * properties will be copied by name. Incompatible properties will be
184 * ignored; specifically, properties that are lists on only one
185 * of the beans or ValueBindings on the original bean that
186 * are not allowed on the target bean.
187 */
188 public void addAll(FacesBean from);
189
190 /**
191 * Returns a Set of all PropertyKeys that have either lists
192 * or values attached.
193 */
194 public Set<PropertyKey> keySet();
195
196 /**
197 * Returns a Set of all PropertyKeys that have ValueBindings attached.
198 */
199 public Set<PropertyKey> bindingKeySet();
200
201 public void markInitialState();
202
203 /**
204 * Saves the state of a FacesBean.
205 */
206 public Object saveState(FacesContext context);
207
208 /**
209 * Restores the state of a FacesBean.
210 */
211 public void restoreState(FacesContext context, Object state);
212
213 /**
214 * Type of a FacesBean, encapsulating the set of registered
215 * PropertyKeys.
216 */
217
218 public static class Type
219 {
220 public Type()
221 {
222 this(null);
223 }
224
225 public Type(Type superType)
226 {
227 _superType = superType;
228
229
230
231 _keyMap = new HashMap<String, PropertyKey>();
232 _keyList = new ArrayList<PropertyKey>();
233 _unmodifiableKeys = Collections.unmodifiableList(_keyList);
234
235 if (_superType != null)
236 {
237 _keyMap.putAll(_superType._keyMap);
238 _keyList.addAll(_superType._keyList);
239 _index = _superType._index;
240 _superType.lock();
241 }
242
243 }
244
245 /**
246 * Find an existing key by name.
247 */
248 public PropertyKey findKey(String name)
249 {
250 return _keyMap.get(name);
251 }
252
253 /**
254 * Find an existing key by index.
255 */
256 public PropertyKey findKey(int index)
257 {
258 if ((index < 0) || (index >= _keyList.size()))
259 return null;
260
261 return _keyList.get(index);
262 }
263
264 /**
265 * Register a new key.
266 * @exception IllegalStateException if the type is already locked,
267 * or the key does not already exists.
268 */
269 public final PropertyKey registerKey(
270 String name,
271 Class<?> type,
272 Object defaultValue)
273 {
274 return registerKey(name, type, defaultValue, 0);
275 }
276
277 /**
278 * Register a new key.
279 * @exception IllegalStateException if the type is already locked,
280 * or the key does not already exists.
281 */
282 public final PropertyKey registerKey(
283 String name,
284 Class<?> type)
285 {
286 return registerKey(name, type, null, 0);
287 }
288
289 /**
290 * Register a new key.
291 * @exception IllegalStateException if the type is already locked,
292 * or the key does not already exists.
293 */
294 public final PropertyKey registerKey(
295 String name)
296 {
297 return registerKey(name, Object.class, null, 0);
298 }
299
300 /**
301 * Register a new key.
302 * @exception IllegalStateException if the type is already locked,
303 * or the key does not already exists.
304 */
305 public final PropertyKey registerKey(
306 String name,
307 int capabilities)
308 {
309 return registerKey(name, Object.class, null, capabilities);
310 }
311
312 /**
313 * Register a new key.
314 * @exception IllegalStateException if the type is already locked,
315 * or the key does not already exists.
316 */
317 public final PropertyKey registerKey(
318 String name,
319 Class<?> type,
320 int capabilities)
321 {
322 return registerKey(name, type, null, capabilities);
323 }
324
325 /**
326 * Add an alias to an existing PropertyKey.
327 * @exception IllegalStateException if the type is already locked,
328 * or a key already exists at the alias.
329 */
330 public PropertyKey registerAlias(PropertyKey key, String alias)
331 {
332 _checkLocked();
333
334 if (findKey(alias) != null)
335 throw new IllegalStateException();
336
337 _keyMap.put(alias, key);
338 return key;
339 }
340
341
342 /**
343 * Register a new key with a set of capabilities.
344 * @exception IllegalStateException if the type is already locked,
345 * or the key already exists.
346 */
347 public PropertyKey registerKey(
348 String name,
349 Class<?> type,
350 Object defaultValue,
351 int capabilities)
352 {
353 _checkLocked();
354 _checkName(name);
355
356 PropertyKey key = createPropertyKey(name,
357 type,
358 defaultValue,
359 capabilities,
360 getNextIndex());
361 addKey(key);
362 return key;
363 }
364
365
366 /**
367 * Locks the type object, preventing further changes.
368 */
369 public void lock()
370 {
371 _isLocked = true;
372 }
373
374 /**
375 * Locks the type object, preventing further changes.
376 */
377 public void lockAndRegister(
378
379 String componentFamily,
380 String rendererType)
381 {
382 lock();
383
384 TypeRepository.registerType(
385 componentFamily,
386 rendererType,
387 this);
388 }
389
390 /**
391 * Returns the iterator of registered property keys, excluding aliases.
392 */
393 public Iterator<PropertyKey> keys()
394 {
395 return propertyKeys().iterator();
396 }
397
398 /**
399 * Returns an unmodifiable <code>Collection</code> of registered property keys,
400 * excluding aliases.
401 *
402 * @return unmodifiable <code>Collection</code> with registered
403 */
404 public Collection<PropertyKey> propertyKeys()
405 {
406 return _unmodifiableKeys;
407 }
408
409 protected PropertyKey createPropertyKey(
410 String name,
411 Class<?> type,
412 Object defaultValue,
413 int capabilities,
414 int index)
415 {
416 if (_superType != null)
417 {
418 return _superType.createPropertyKey(name, type, defaultValue,
419 capabilities, index);
420 }
421
422 return new PropertyKey(name, type, defaultValue, capabilities, index);
423 }
424
425 /**
426 * Return the next available index.
427 */
428 protected int getNextIndex()
429 {
430 int index = _index;
431 _index = index + 1;
432 return index;
433 }
434
435
436 /**
437 * Add a key to the type.
438 * @exception IllegalStateException if the type is already locked,
439 * or a key with that name or index already exists.
440 */
441 protected void addKey(PropertyKey key)
442 {
443 _checkLocked();
444
445
446 PropertyKey oldValue = _keyMap.put(key.getName(), key);
447 if (oldValue != null)
448 {
449 _keyMap.put(key.getName(), oldValue);
450 throw new IllegalStateException(_LOG.getMessage(
451 "NAME_ALREADY_REGISTERED", key.getName()));
452 }
453
454 int index = key.getIndex();
455 if (index >= 0)
456 {
457 _expandListToIndex(_keyList, index);
458 oldValue = _keyList.set(index, key);
459 if (oldValue != null)
460 {
461 _keyList.set(index, oldValue);
462 throw new IllegalStateException(_LOG.getMessage(
463 "INDEX_ALREADY_REGISTERED", index));
464 }
465 }
466
467
468 key.__setOwner(this);
469 }
470
471
472 static private void _expandListToIndex(ArrayList<PropertyKey> list, int count)
473 {
474 list.ensureCapacity(count + 1);
475 int addCount = (count + 1) - list.size();
476 for (int i = 0; i < addCount; i++)
477 list.add(null);
478 }
479
480
481 private void _checkLocked()
482 {
483 if (_isLocked)
484 throw new IllegalStateException(_LOG.getMessage(
485 "TYPE_ALREADY_LOCKED"));
486 }
487
488 private void _checkName(String name)
489 {
490 if (findKey(name) != null)
491 {
492 throw new IllegalStateException(_LOG.getMessage(
493 "NAME_ALREADY_REGISTERED", name));
494 }
495 }
496
497 private final Map<String, PropertyKey> _keyMap;
498 private final List<PropertyKey> _unmodifiableKeys;
499
500 private final ArrayList<PropertyKey> _keyList;
501 private boolean _isLocked;
502 private int _index;
503 private final Type _superType;
504 static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(Type.class);
505 }
506 }