1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.facelets;
20
21 import java.beans.BeanInfo;
22 import java.beans.IntrospectionException;
23
24 import java.beans.Introspector;
25 import java.beans.PropertyDescriptor;
26
27 import java.lang.reflect.InvocationTargetException;
28 import java.lang.reflect.Method;
29
30 import java.util.ArrayList;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.WeakHashMap;
36 import java.util.logging.Level;
37
38 import javax.faces.view.facelets.FaceletContext;
39 import javax.faces.view.facelets.MetaRule;
40 import javax.faces.view.facelets.MetaRuleset;
41 import javax.faces.view.facelets.Metadata;
42 import javax.faces.view.facelets.MetadataTarget;
43 import javax.faces.view.facelets.Tag;
44 import javax.faces.view.facelets.TagAttribute;
45 import javax.faces.view.facelets.TagAttributeException;
46 import javax.faces.view.facelets.TagConfig;
47 import javax.faces.view.facelets.TagException;
48 import javax.faces.view.facelets.TagHandler;
49
50 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
51
52
53
54
55
56
57
58
59
60
61
62 public abstract class MetaTagHandler extends TagHandler {
63 private Class lastType = Object.class;
64
65 private Metadata mapper;
66
67 public MetaTagHandler(TagConfig config) {
68 super(config);
69 }
70
71
72
73
74
75
76
77 protected MetaRuleset createMetaRuleset(Class type) {
78 assert (type != null);
79 return new MetaRulesetImpl(this.tag, type);
80 }
81
82
83
84
85
86
87
88
89 protected void setAttributes(FaceletContext ctx, Object instance) {
90 if (instance != null) {
91 Class type = instance.getClass();
92 if (mapper == null || !this.lastType.equals(type)) {
93 this.lastType = type;
94 this.mapper = this.createMetaRuleset(type).finish();
95 }
96 this.mapper.applyMetadata(ctx, instance);
97 }
98 }
99
100
101 private static class BeanPropertyTagRule extends MetaRule {
102
103 final static class LiteralPropertyMetadata extends Metadata {
104
105 private final Method method;
106
107 private final TagAttribute attribute;
108
109 private Object[] value;
110
111 public LiteralPropertyMetadata(Method method,
112 TagAttribute attribute) {
113 this.method = method;
114 this.attribute = attribute;
115 }
116
117 public void applyMetadata(FaceletContext ctx, Object instance) {
118 if (value == null) {
119 String str = this.attribute.getValue();
120 value = new Object[] { ctx.getExpressionFactory().coerceToType(str,
121 method.getParameterTypes()[0]) };
122 }
123 try {
124 method.invoke(instance, this.value);
125 } catch (InvocationTargetException e) {
126 throw new TagAttributeException(this.attribute,
127 e.getCause());
128 } catch (Exception e) {
129 throw new TagAttributeException(this.attribute, e);
130 }
131 }
132
133 }
134
135 final static class DynamicPropertyMetadata extends Metadata {
136
137 private final Method method;
138
139 private final TagAttribute attribute;
140
141 private final Class type;
142
143 public DynamicPropertyMetadata(Method method,
144 TagAttribute attribute) {
145 this.method = method;
146 this.type = method.getParameterTypes()[0];
147 this.attribute = attribute;
148 }
149
150 public void applyMetadata(FaceletContext ctx, Object instance) {
151 try {
152 this.method.invoke(instance,
153 new Object[] { this.attribute.getObject(ctx,
154 this.type) });
155 } catch (InvocationTargetException e) {
156 throw new TagAttributeException(this.attribute,
157 e.getCause());
158 } catch (Exception e) {
159 throw new TagAttributeException(this.attribute, e);
160 }
161 }
162 }
163
164 public final static BeanPropertyTagRule Instance =
165 new BeanPropertyTagRule();
166
167 public Metadata applyRule(String name, TagAttribute attribute,
168 MetadataTarget meta) {
169 Method m = meta.getWriteMethod(name);
170
171
172 if (m != null) {
173 if (attribute.isLiteral()) {
174 return new LiteralPropertyMetadata(m, attribute);
175 } else {
176 return new DynamicPropertyMetadata(m, attribute);
177 }
178 }
179
180 return null;
181 }
182
183 }
184
185 private static class MetaRulesetImpl extends MetaRuleset {
186
187 private final static WeakHashMap metadata = new WeakHashMap();
188
189 static final private TrinidadLogger log =
190 TrinidadLogger.createTrinidadLogger(MetaRulesetImpl.class);
191
192 private final Tag tag;
193
194 private final Class type;
195
196 private final Map attributes;
197
198 private final List mappers;
199
200 private final List rules;
201
202 public MetaRulesetImpl(Tag tag, Class type) {
203 this.tag = tag;
204 this.type = type;
205 this.attributes = new HashMap();
206 this.mappers = new ArrayList();
207 this.rules = new ArrayList();
208
209
210 TagAttribute[] attrs = this.tag.getAttributes().getAll();
211 for (int i = 0; i < attrs.length; i++) {
212 attributes.put(attrs[i].getLocalName(), attrs[i]);
213 }
214
215
216 this.rules.add(BeanPropertyTagRule.Instance);
217 }
218
219 public MetaRuleset ignore(String attribute) {
220 assert (attribute != null);
221 this.attributes.remove(attribute);
222 return this;
223 }
224
225 public MetaRuleset alias(String attribute, String property) {
226 assert (attribute != null);
227 assert (property != null);
228 TagAttribute attr =
229 (TagAttribute)this.attributes.remove(attribute);
230 if (attr != null) {
231 this.attributes.put(property, attr);
232 }
233 return this;
234 }
235
236 public MetaRuleset add(Metadata mapper) {
237 assert (mapper != null);
238 if (!this.mappers.contains(mapper)) {
239 this.mappers.add(mapper);
240 }
241 return this;
242 }
243
244 public MetaRuleset addRule(MetaRule rule) {
245 assert (rule != null);
246 this.rules.add(rule);
247 return this;
248 }
249
250 private final MetadataTarget getMetadataTarget() {
251 String key = this.type.getName();
252 MetadataTarget meta = (MetadataTarget)metadata.get(key);
253 if (meta == null) {
254 try {
255 meta = new MetadataTargetImpl(type);
256 } catch (IntrospectionException e) {
257 throw new TagException(this.tag, "Error Creating TargetMetadata", e);
258 }
259 metadata.put(key, meta);
260 }
261 return meta;
262 }
263
264 public Metadata finish() {
265 if (!this.attributes.isEmpty()) {
266 if (this.rules.isEmpty()) {
267 if (log.isLoggable(Level.SEVERE)) {
268 for (Iterator itr =
269 this.attributes.values().iterator();
270 itr.hasNext(); ) {
271 log.severe(itr.next() +
272 " Unhandled by MetaTagHandler for type " +
273 this.type.getName());
274 }
275 }
276 } else {
277 MetadataTarget target = this.getMetadataTarget();
278
279 Map.Entry entry;
280 MetaRule rule;
281 Metadata data;
282 int ruleEnd = this.rules.size() - 1;
283 for (Iterator itr = this.attributes.entrySet().iterator();
284 itr.hasNext(); ) {
285 entry = (Map.Entry)itr.next();
286 data = null;
287 int i = ruleEnd;
288 while (data == null && i >= 0) {
289 rule = (MetaRule)this.rules.get(i);
290 data = rule.applyRule((String)entry.getKey(), (TagAttribute)entry.getValue(), target);
291 i--;
292 }
293 if (data == null) {
294 if (log.isLoggable(Level.SEVERE)) {
295 log.severe(entry.getValue() +
296 " Unhandled by MetaTagHandler for type " +
297 this.type.getName());
298 }
299 } else {
300 this.mappers.add(data);
301 }
302 }
303 }
304 }
305
306 if (this.mappers.isEmpty()) {
307 return NONE;
308 } else {
309 return new MetadataImpl((Metadata[])this.mappers.toArray(new Metadata[this.mappers.size()]));
310 }
311 }
312
313 public MetaRuleset ignoreAll() {
314 this.attributes.clear();
315 return this;
316 }
317
318 private final static Metadata NONE = new Metadata() {
319 public void applyMetadata(FaceletContext ctx, Object instance) {
320
321 }
322 };
323
324 final static class MetadataImpl extends Metadata {
325
326 private final Metadata[] mappers;
327 private final int size;
328
329 public MetadataImpl(Metadata[] mappers) {
330 this.mappers = mappers;
331 this.size = mappers.length;
332 }
333
334 public void applyMetadata(FaceletContext ctx, Object instance) {
335 for (int i = 0; i < size; i++) {
336 this.mappers[i].applyMetadata(ctx, instance);
337 }
338 }
339
340 }
341 }
342
343 private static class MetadataTargetImpl extends MetadataTarget {
344
345 private final Map pd;
346 private final Class type;
347
348
349 public MetadataTargetImpl(Class type) throws IntrospectionException {
350 this.type = type;
351 this.pd = new HashMap();
352 BeanInfo info = Introspector.getBeanInfo(type);
353 PropertyDescriptor[] pda = info.getPropertyDescriptors();
354 for (int i = 0; i < pda.length; i++) {
355 this.pd.put(pda[i].getName(), pda[i]);
356 }
357 }
358
359 public PropertyDescriptor getProperty(String name) {
360 return (PropertyDescriptor)this.pd.get(name);
361 }
362
363 public boolean isTargetInstanceOf(Class type) {
364 return type.isAssignableFrom(this.type);
365 }
366
367 public Class getTargetClass() {
368 return this.type;
369 }
370
371 public Class getPropertyType(String name) {
372 PropertyDescriptor pd = this.getProperty(name);
373 if (pd != null) {
374 return pd.getPropertyType();
375 }
376 return null;
377 }
378
379 public Method getWriteMethod(String name) {
380 PropertyDescriptor pd = this.getProperty(name);
381 if (pd != null) {
382 return pd.getWriteMethod();
383 }
384 return null;
385 }
386
387 public Method getReadMethod(String name) {
388 PropertyDescriptor pd = this.getProperty(name);
389 if (pd != null) {
390 return pd.getReadMethod();
391 }
392 return null;
393 }
394
395 }
396
397 }
398