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.util;
20
21 import java.util.AbstractMap;
22 import java.util.AbstractSet;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.Map;
26 import java.util.Set;
27
28 import org.apache.myfaces.trinidad.bean.FacesBean;
29 import org.apache.myfaces.trinidad.bean.PropertyKey;
30
31 /**
32 * Map implementation that exposes the properties of a FacesBean
33 * as a Map. This Map supports Iterator.remove(), treats
34 * putting a null value as identical to removing the value,
35 * but does not support null keys. The keys may be either
36 * Strings or {@link PropertyKey}s, but all Map.Entry objects
37 * will return String keys.
38 *
39 */
40 public class ValueMap extends AbstractMap<String, Object>
41 {
42 public ValueMap(FacesBean bean)
43 {
44 _bean = bean;
45 }
46
47 @Override
48 public Object get(Object key)
49 {
50 if (key == null)
51 throw new NullPointerException();
52
53 PropertyKey propertyKey = _getPropertyKey(key);
54
55
56 if (propertyKey.isList())
57 {
58 Class<?> type = propertyKey.getType();
59 if (type.isArray())
60 type = type.getComponentType();
61
62 return _bean.getEntries(propertyKey, type);
63 }
64 else
65 {
66 Object val = _bean.getProperty(propertyKey);
67 return (val != null) ? val : propertyKey.getDefault();
68 }
69 }
70
71 @Override
72 public Object put(String key, Object value)
73 {
74 if (key == null)
75 throw new NullPointerException();
76
77 return _putInternal(_getPropertyKey(key), value);
78 }
79
80
81 @Override
82 public Object remove(Object key)
83 {
84 PropertyKey propertyKey = _getPropertyKey(key);
85 Object oldValue = _bean.getProperty(propertyKey);
86 _bean.setProperty(propertyKey, null);
87 if (_entries != null)
88 _entries._keys.remove(propertyKey);
89
90 return oldValue;
91 }
92
93 @Override
94 public Set<Map.Entry<String, Object>> entrySet()
95 {
96 if (_entries == null)
97 {
98 HashSet<PropertyKey> keySet = new HashSet<PropertyKey>();
99 keySet.addAll(_bean.keySet());
100 keySet.addAll(_bean.bindingKeySet());
101 _entries = new MakeEntries(keySet);
102 }
103
104 return _entries;
105 }
106
107 private Object _putInternal(PropertyKey propertyKey, Object value)
108 {
109 assert propertyKey != null;
110
111 Object oldValue = _bean.getProperty(propertyKey);
112 _bean.setProperty(propertyKey, value);
113 if (_entries != null)
114 {
115 if (value == null)
116 _entries._keys.remove(propertyKey);
117 else
118 _entries._keys.add(propertyKey);
119 }
120
121 return oldValue;
122 }
123
124 private class MakeEntries extends AbstractSet<Map.Entry<String, Object>>
125 {
126 public MakeEntries(Set<PropertyKey> keys)
127 {
128 _keys = keys;
129 }
130
131 @Override
132 public int size()
133 {
134 return _keys.size();
135 }
136
137 @Override
138 public boolean remove(Object o)
139 {
140 if (!(o instanceof EntryImpl))
141 return false;
142
143 String keyName = ((EntryImpl) o).getKey();
144 return (ValueMap.this.remove(keyName) != null);
145 }
146
147 @Override
148 public Iterator<Map.Entry<String, Object>> iterator()
149 {
150 final Iterator<PropertyKey> base = _keys.iterator();
151 return new Iterator<Map.Entry<String, Object>>()
152 {
153 public boolean hasNext()
154 {
155 return base.hasNext();
156 }
157
158 public Map.Entry<String, Object> next()
159 {
160 _lastEntry = new EntryImpl(base.next());
161 return _lastEntry;
162 }
163
164 public void remove()
165 {
166 if (_lastEntry == null)
167 throw new IllegalStateException();
168 base.remove();
169 ValueMap.this.remove(_lastEntry.getKey());
170 _lastEntry = null;
171
172
173 }
174
175 private EntryImpl _lastEntry;
176 };
177 }
178
179 private Set<PropertyKey> _keys;
180 }
181
182 private class EntryImpl implements Entry<String, Object>
183 {
184 public EntryImpl(PropertyKey key)
185 {
186 assert key != null;
187
188 _key = key;
189 }
190
191 public String getKey()
192 {
193 return _key.getName();
194 }
195
196 public Object getValue()
197 {
198 return get(_key);
199 }
200
201 public Object setValue(Object value)
202 {
203 return _putInternal(_key, value);
204 }
205
206 @SuppressWarnings("unchecked")
207 @Override
208 public boolean equals(Object o)
209 {
210 if (o == this)
211 return true;
212
213 if (!(o instanceof Map.Entry))
214 return false;
215
216 Map.Entry<Object, Object> e = (Map.Entry<Object, Object>)o;
217 Object k1 = getKey();
218 Object k2 = e.getKey();
219 if (k1 == k2 || (k1 != null && k1.equals(k2)))
220 {
221 Object v1 = getValue();
222 Object v2 = e.getValue();
223 if (v1 == v2 || (v1 != null && v1.equals(v2)))
224 return true;
225 }
226
227 return false;
228 }
229
230 @Override
231 public int hashCode()
232 {
233 Object value = getValue();
234 return _key.hashCode() ^ (value==null ? 0 : value.hashCode());
235 }
236
237 private final PropertyKey _key;
238 }
239
240 private PropertyKey _getPropertyKey(Object key)
241 {
242 if (key instanceof String)
243 {
244 String keyString = (String) key;
245 PropertyKey propertyKey = _bean.getType().findKey(keyString);
246 if (propertyKey == null)
247 propertyKey = PropertyKey.createPropertyKey(keyString);
248
249 return propertyKey;
250 }
251
252 if (key instanceof PropertyKey)
253 {
254 return (PropertyKey) key;
255 }
256
257 throw new ClassCastException();
258 }
259
260 private FacesBean _bean;
261 private MakeEntries _entries;
262 }