1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.view.facelets.tag;
20
21 import org.apache.myfaces.shared.util.ClassUtils;
22 import org.apache.myfaces.view.facelets.util.ParameterCheck;
23
24 import javax.faces.view.facelets.FaceletContext;
25 import javax.faces.view.facelets.MetaRule;
26 import javax.faces.view.facelets.MetaRuleset;
27 import javax.faces.view.facelets.Metadata;
28 import javax.faces.view.facelets.MetadataTarget;
29 import javax.faces.view.facelets.Tag;
30 import javax.faces.view.facelets.TagAttribute;
31 import javax.faces.view.facelets.TagException;
32 import java.beans.IntrospectionException;
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.WeakHashMap;
38 import java.util.logging.Level;
39 import java.util.logging.Logger;
40 import org.apache.myfaces.view.facelets.PassthroughRule;
41 import org.apache.myfaces.view.facelets.tag.jsf.PassThroughLibrary;
42
43
44
45
46
47
48 public final class MetaRulesetImpl extends MetaRuleset
49 {
50 private final static Metadata NONE = new NullMetadata();
51
52
53 private final static Logger log = Logger.getLogger(MetaRulesetImpl.class.getName());
54
55
56
57
58
59
60
61
62
63
64 private volatile static WeakHashMap<ClassLoader, Map<String, MetadataTarget>> metadata
65 = new WeakHashMap<ClassLoader, Map<String, MetadataTarget>>();
66
67
68
69
70 public static void clearMetadataTargetCache()
71 {
72 metadata.remove(ClassUtils.getContextClassLoader());
73 }
74
75 private static Map<String, MetadataTarget> getMetaData()
76 {
77 ClassLoader cl = ClassUtils.getContextClassLoader();
78
79 Map<String, MetadataTarget> metadata = (Map<String, MetadataTarget>)
80 MetaRulesetImpl.metadata.get(cl);
81
82 if (metadata == null)
83 {
84
85
86 synchronized (MetaRulesetImpl.metadata)
87 {
88 metadata = createMetaData(cl, metadata);
89 }
90 }
91
92 return metadata;
93 }
94
95 private static Map<String, MetadataTarget> createMetaData(ClassLoader cl, Map<String, MetadataTarget> metadata)
96 {
97 metadata = (Map<String, MetadataTarget>) MetaRulesetImpl.metadata.get(cl);
98 if (metadata == null)
99 {
100 metadata = new HashMap<String, MetadataTarget>();
101 MetaRulesetImpl.metadata.put(cl, metadata);
102 }
103 return metadata;
104 }
105
106 private final static TagAttribute[] EMPTY = new TagAttribute[0];
107
108 private final Map<String, TagAttribute> _attributes;
109
110 private final TagAttribute[] _passthroughAttributes;
111
112 private final List<Metadata> _mappers;
113
114 private final List<MetaRule> _rules;
115
116 private final Tag _tag;
117
118 private final Class<?> _type;
119
120 private final List<MetaRule> _passthroughRules;
121
122 public MetaRulesetImpl(Tag tag, Class<?> type)
123 {
124 _tag = tag;
125 _type = type;
126 TagAttribute[] allAttributes = _tag.getAttributes().getAll();
127
128
129
130 int initialSize = allAttributes.length > 0 ? (allAttributes.length * 4 + 3) / 3 : 4;
131 _attributes = new HashMap<String, TagAttribute>(initialSize);
132 _mappers = new ArrayList<Metadata>(initialSize);
133
134
135 _rules = new ArrayList<MetaRule>(8);
136 _passthroughRules = new ArrayList<MetaRule>(2);
137
138
139
140
141
142 TagAttribute[] passthroughAttribute = _tag.getAttributes().getAll(
143 PassThroughLibrary.NAMESPACE);
144 TagAttribute[] passthroughAttributeAlias = _tag.getAttributes().getAll(
145 PassThroughLibrary.ALIAS_NAMESPACE);
146
147 if (passthroughAttribute.length > 0 ||
148 passthroughAttributeAlias.length > 0)
149 {
150 _passthroughAttributes = new TagAttribute[passthroughAttribute.length+
151 passthroughAttributeAlias.length];
152 int i = 0;
153 for (TagAttribute attribute : allAttributes)
154 {
155
156
157 if (attribute.getNamespace().length() > 0 &&
158 (PassThroughLibrary.NAMESPACE.equals(attribute.getNamespace()) ||
159 PassThroughLibrary.ALIAS_NAMESPACE.equals(attribute.getNamespace())))
160 {
161 _passthroughAttributes[i] = attribute;
162 i++;
163 }
164 else
165 {
166 _attributes.put(attribute.getLocalName(), attribute);
167 }
168 }
169 }
170 else
171 {
172 _passthroughAttributes = EMPTY;
173
174 for (TagAttribute attribute : allAttributes)
175 {
176 _attributes.put(attribute.getLocalName(), attribute);
177 }
178 }
179
180
181 _rules.add(BeanPropertyTagRule.INSTANCE);
182 }
183
184 public MetaRuleset add(Metadata mapper)
185 {
186 ParameterCheck.notNull("mapper", mapper);
187
188 if (!_mappers.contains(mapper))
189 {
190 _mappers.add(mapper);
191 }
192
193 return this;
194 }
195
196 public MetaRuleset addRule(MetaRule rule)
197 {
198 ParameterCheck.notNull("rule", rule);
199
200 if (rule instanceof PassthroughRule)
201 {
202 _passthroughRules.add(rule);
203 }
204 else
205 {
206 _rules.add(rule);
207 }
208
209 return this;
210 }
211
212 public MetaRuleset alias(String attribute, String property)
213 {
214 ParameterCheck.notNull("attribute", attribute);
215 ParameterCheck.notNull("property", property);
216
217 TagAttribute attr = (TagAttribute) _attributes.remove(attribute);
218 if (attr != null)
219 {
220 _attributes.put(property, attr);
221 }
222
223 return this;
224 }
225
226 public Metadata finish()
227 {
228 MetadataTarget target = null;
229
230 assert !_rules.isEmpty();
231
232 if (!_attributes.isEmpty())
233 {
234 target = this._getMetadataTarget();
235 int ruleEnd = _rules.size() - 1;
236
237
238 for (Map.Entry<String, TagAttribute> entry : _attributes.entrySet())
239 {
240 Metadata data = null;
241
242 int i = ruleEnd;
243
244
245 do
246 {
247 MetaRule rule = _rules.get(i);
248 data = rule.applyRule(entry.getKey(), entry.getValue(), target);
249 i--;
250 } while (data == null && i >= 0);
251
252 if (data == null)
253 {
254 if (log.isLoggable(Level.SEVERE))
255 {
256 log.severe(entry.getValue() + " Unhandled by MetaTagHandler for type " + _type.getName());
257 }
258 }
259 else
260 {
261 _mappers.add(data);
262 }
263 }
264 }
265
266 if (_passthroughAttributes.length > 0 &&
267 _passthroughRules.size() > 0)
268 {
269 if (target == null)
270 {
271 target = this._getMetadataTarget();
272 }
273 int ruleEnd = _passthroughRules.size() - 1;
274
275
276 for (TagAttribute passthroughAttribute : _passthroughAttributes)
277 {
278 Metadata data = null;
279
280 int i = ruleEnd;
281
282
283 do
284 {
285 MetaRule rule = _passthroughRules.get(i);
286 data = rule.applyRule(passthroughAttribute.getLocalName(),
287 passthroughAttribute, target);
288 i--;
289 } while (data == null && i >= 0);
290
291 if (data == null)
292 {
293 if (log.isLoggable(Level.SEVERE))
294 {
295 log.severe(passthroughAttribute.getLocalName() +
296 " Unhandled by MetaTagHandler for type " + _type.getName());
297 }
298 }
299 else
300 {
301 _mappers.add(data);
302 }
303 }
304 }
305
306 if (_mappers.isEmpty())
307 {
308 return NONE;
309 }
310 else
311 {
312 return new MetadataImpl(_mappers.toArray(new Metadata[_mappers.size()]));
313 }
314 }
315
316 public MetaRuleset ignore(String attribute)
317 {
318 ParameterCheck.notNull("attribute", attribute);
319
320 _attributes.remove(attribute);
321
322 return this;
323 }
324
325 public MetaRuleset ignoreAll()
326 {
327 _attributes.clear();
328
329 return this;
330 }
331
332 private MetadataTarget _getMetadataTarget()
333 {
334 Map<String, MetadataTarget> metadata = getMetaData();
335 String metaKey = _type.getName();
336
337 MetadataTarget meta = metadata.get(metaKey);
338 if (meta == null)
339 {
340 try
341 {
342 meta = new MetadataTargetImpl(_type);
343 }
344 catch (IntrospectionException e)
345 {
346 throw new TagException(_tag, "Error Creating TargetMetadata", e);
347 }
348
349 synchronized(metadata)
350 {
351
352
353
354
355
356 metadata.put(metaKey, meta);
357 }
358 }
359
360 return meta;
361 }
362
363 private static class NullMetadata extends Metadata
364 {
365
366
367
368 @Override
369 public void applyMetadata(FaceletContext ctx, Object instance)
370 {
371
372 }
373 }
374 }