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.composite;
20
21 import java.beans.BeanDescriptor;
22 import java.beans.BeanInfo;
23 import java.beans.PropertyDescriptor;
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31
32 import javax.el.ELException;
33 import javax.el.ValueExpression;
34 import javax.el.VariableMapper;
35 import javax.faces.FacesException;
36 import javax.faces.application.ProjectStage;
37 import javax.faces.application.Resource;
38 import javax.faces.component.ActionSource;
39 import javax.faces.component.EditableValueHolder;
40 import javax.faces.component.UIComponent;
41 import javax.faces.component.UIPanel;
42 import javax.faces.component.UniqueIdVendor;
43 import javax.faces.component.ValueHolder;
44 import javax.faces.context.FacesContext;
45 import javax.faces.view.AttachedObjectHandler;
46 import javax.faces.view.ViewDeclarationLanguage;
47 import javax.faces.view.facelets.ComponentConfig;
48 import javax.faces.view.facelets.ComponentHandler;
49 import javax.faces.view.facelets.FaceletContext;
50 import javax.faces.view.facelets.FaceletException;
51 import javax.faces.view.facelets.FaceletHandler;
52 import javax.faces.view.facelets.MetaRuleset;
53 import javax.faces.view.facelets.Metadata;
54 import javax.faces.view.facelets.TagException;
55 import javax.faces.view.facelets.TextHandler;
56
57 import org.apache.myfaces.view.facelets.AbstractFaceletContext;
58 import org.apache.myfaces.view.facelets.FaceletCompositionContext;
59 import org.apache.myfaces.view.facelets.TemplateClient;
60 import org.apache.myfaces.view.facelets.TemplateContext;
61 import org.apache.myfaces.view.facelets.el.VariableMapperWrapper;
62 import org.apache.myfaces.view.facelets.tag.ComponentContainerHandler;
63 import org.apache.myfaces.view.facelets.tag.TagHandlerUtils;
64 import org.apache.myfaces.view.facelets.tag.jsf.ActionSourceRule;
65 import org.apache.myfaces.view.facelets.tag.jsf.ComponentBuilderHandler;
66 import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
67 import org.apache.myfaces.view.facelets.tag.jsf.EditableValueHolderRule;
68 import org.apache.myfaces.view.facelets.tag.jsf.ValueHolderRule;
69 import org.apache.myfaces.view.facelets.tag.jsf.core.AjaxHandler;
70
71
72
73
74
75
76
77
78
79 public class CompositeComponentResourceTagHandler extends ComponentHandler
80 implements ComponentBuilderHandler, TemplateClient
81 {
82 private final Resource _resource;
83
84 private Metadata _mapper;
85
86 private Class<?> _lastType = Object.class;
87
88 protected volatile Map<String, FaceletHandler> _facetHandlersMap;
89
90 protected final Collection<FaceletHandler> _componentHandlers;
91
92 protected final Collection<FaceletHandler> _facetHandlers;
93
94 public CompositeComponentResourceTagHandler(ComponentConfig config, Resource resource)
95 {
96 super(config);
97 _resource = resource;
98 _facetHandlers = TagHandlerUtils.findNextByType(nextHandler, javax.faces.view.facelets.FacetHandler.class,
99 InsertFacetHandler.class);
100 _componentHandlers = TagHandlerUtils.findNextByType(nextHandler,
101 javax.faces.view.facelets.ComponentHandler.class,
102 ComponentContainerHandler.class, TextHandler.class);
103 }
104
105 public UIComponent createComponent(FaceletContext ctx)
106 {
107 FacesContext facesContext = ctx.getFacesContext();
108 UIComponent component = facesContext.getApplication().createComponent(facesContext, _resource);
109
110
111
112
113
114 if (!facesContext.isProjectStage(ProjectStage.Production))
115 {
116 BeanInfo beanInfo = (BeanInfo) component.getAttributes().get(UIComponent.BEANINFO_KEY);
117 for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors())
118 {
119 ValueExpression ve = (ValueExpression) propertyDescriptor.getValue("required");
120 if (ve != null)
121 {
122 Object value = ve.getValue (facesContext.getELContext());
123 Boolean required = null;
124 if (value instanceof Boolean)
125 {
126 required = (Boolean) value;
127 }
128 else
129 {
130 required = Boolean.getBoolean(value.toString());
131 }
132
133 if (required != null && required.booleanValue())
134 {
135 Object attrValue = this.tag.getAttributes().get (propertyDescriptor.getName());
136
137 if (attrValue == null)
138 {
139 throw new TagException(this.tag, "Attribute '" + propertyDescriptor.getName()
140 + "' is required");
141 }
142 }
143 }
144 }
145 }
146 return component;
147 }
148
149 @SuppressWarnings("unchecked")
150 @Override
151 public void applyNextHandler(FaceletContext ctx, UIComponent c)
152 throws IOException
153 {
154
155
156 applyNextHandlerIfNotApplied(ctx, c);
157
158 applyCompositeComponentFacelet(ctx,c);
159
160 if (ComponentHandler.isNew(c))
161 {
162 FacesContext facesContext = ctx.getFacesContext();
163
164 ViewDeclarationLanguage vdl = facesContext.getApplication().getViewHandler().
165 getViewDeclarationLanguage(facesContext, facesContext.getViewRoot().getViewId());
166
167 FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(ctx);
168 List<AttachedObjectHandler> handlers = mctx.getAttachedObjectHandlers(c);
169
170 if (handlers != null)
171 {
172 vdl.retargetAttachedObjects(facesContext, c, handlers);
173
174
175 mctx.removeAttachedObjectHandlers(c);
176 }
177
178 vdl.retargetMethodExpressions(facesContext, c);
179
180 if ( FaceletCompositionContext.getCurrentInstance(ctx).isMarkInitialState())
181 {
182
183 c.markInitialState();
184
185 c.getFacet(UIComponent.COMPOSITE_FACET_NAME).markInitialState();
186 }
187 }
188 }
189
190 @SuppressWarnings("unchecked")
191 protected void applyNextHandlerIfNotApplied(FaceletContext ctx, UIComponent c)
192 throws IOException
193 {
194
195
196 CompositeComponentBeanInfo beanInfo =
197 (CompositeComponentBeanInfo) c.getAttributes().get(UIComponent.BEANINFO_KEY);
198
199 BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor();
200
201 boolean insertChildrenUsed = (beanDescriptor.getValue(InsertChildrenHandler.INSERT_CHILDREN_USED) != null);
202
203 List<String> insertFacetList = (List<String>) beanDescriptor.getValue(InsertFacetHandler.INSERT_FACET_USED);
204
205 if (nextHandler instanceof javax.faces.view.facelets.CompositeFaceletHandler)
206 {
207 for (FaceletHandler handler :
208 ((javax.faces.view.facelets.CompositeFaceletHandler)nextHandler).getHandlers())
209 {
210 if (handler instanceof javax.faces.view.facelets.FacetHandler)
211 {
212 if (insertFacetList == null ||
213 !insertFacetList.contains(((javax.faces.view.facelets.FacetHandler)handler).getFacetName(ctx)))
214 {
215 handler.apply(ctx, c);
216 }
217 }
218 else if (handler instanceof InsertFacetHandler)
219 {
220 if (insertFacetList == null ||
221 !insertFacetList.contains( ((InsertFacetHandler)handler).getFacetName(ctx)))
222 {
223 handler.apply(ctx, c);
224 }
225 }
226 else if (insertChildrenUsed)
227 {
228 if (!(handler instanceof javax.faces.view.facelets.ComponentHandler ||
229 handler instanceof ComponentContainerHandler ||
230 handler instanceof TextHandler))
231 {
232 handler.apply(ctx, c);
233 }
234 }
235 else
236 {
237 handler.apply(ctx, c);
238 }
239 }
240 }
241 else
242 {
243 if (nextHandler instanceof javax.faces.view.facelets.FacetHandler)
244 {
245 if (insertFacetList == null ||
246 !insertFacetList.contains(((javax.faces.view.facelets.FacetHandler)nextHandler).getFacetName(ctx)))
247 {
248 nextHandler.apply(ctx, c);
249 }
250 }
251 else if (nextHandler instanceof InsertFacetHandler)
252 {
253 if (insertFacetList == null ||
254 !insertFacetList.contains( ((InsertFacetHandler)nextHandler).getFacetName(ctx)) )
255 {
256 nextHandler.apply(ctx, c);
257 }
258 }
259 else if (insertChildrenUsed)
260 {
261 if (!(nextHandler instanceof javax.faces.view.facelets.ComponentHandler ||
262 nextHandler instanceof ComponentContainerHandler ||
263 nextHandler instanceof TextHandler))
264 {
265 nextHandler.apply(ctx, c);
266 }
267 }
268 else
269 {
270 nextHandler.apply(ctx, c);
271 }
272 }
273
274
275 Map<String, PropertyDescriptor> facetPropertyDescriptorMap = (Map<String, PropertyDescriptor>)
276 beanDescriptor.getValue(UIComponent.FACETS_KEY);
277
278 if (facetPropertyDescriptorMap != null)
279 {
280 List<String> facetsRequiredNotFound = null;
281 for (Map.Entry<String, PropertyDescriptor> entry : facetPropertyDescriptorMap.entrySet())
282 {
283 ValueExpression requiredExpr = (ValueExpression) entry.getValue().getValue("required");
284 if (requiredExpr != null)
285 {
286 Boolean required = (Boolean) requiredExpr.getValue(ctx.getFacesContext().getELContext());
287 if (Boolean.TRUE.equals(required))
288 {
289 initFacetHandlersMap(ctx);
290 if (!_facetHandlersMap.containsKey(entry.getKey()))
291 {
292 if (facetsRequiredNotFound == null)
293 {
294 facetsRequiredNotFound = new ArrayList(facetPropertyDescriptorMap.size());
295 }
296 facetsRequiredNotFound.add(entry.getKey());
297 }
298
299 }
300 }
301 }
302 if (facetsRequiredNotFound != null && !facetsRequiredNotFound.isEmpty())
303 {
304 throw new TagException(getTag(), "The following facets are required by the component: "
305 + facetsRequiredNotFound);
306 }
307 }
308 }
309
310 protected void applyCompositeComponentFacelet(FaceletContext faceletContext, UIComponent compositeComponentBase)
311 throws IOException
312 {
313 FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(faceletContext);
314 AbstractFaceletContext actx = (AbstractFaceletContext) faceletContext;
315 UIPanel compositeFacetPanel
316 = (UIPanel) compositeComponentBase.getFacets().get(UIComponent.COMPOSITE_FACET_NAME);
317 if (compositeFacetPanel == null)
318 {
319 compositeFacetPanel = (UIPanel)
320 faceletContext.getFacesContext().getApplication().createComponent(
321 faceletContext.getFacesContext(), UIPanel.COMPONENT_TYPE, null);
322 compositeFacetPanel.getAttributes().put(ComponentSupport.COMPONENT_ADDED_BY_HANDLER_MARKER,
323 Boolean.TRUE);
324 compositeComponentBase.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, compositeFacetPanel);
325
326
327
328 UniqueIdVendor uniqueIdVendor = mctx.getUniqueIdVendorFromStack();
329 if (uniqueIdVendor == null)
330 {
331 uniqueIdVendor = ComponentSupport.getViewRoot(faceletContext, compositeComponentBase);
332 }
333 if (uniqueIdVendor != null)
334 {
335
336
337 String uid = uniqueIdVendor.createUniqueId(faceletContext.getFacesContext(),
338 mctx.getSharedStringBuilder()
339 .append(compositeComponentBase.getId())
340 .append("__f_")
341 .append("cc_facet").toString());
342 compositeFacetPanel.setId(uid);
343 }
344 }
345
346
347
348
349
350
351 Iterator<AjaxHandler> it = ((AbstractFaceletContext) faceletContext).getAjaxHandlers();
352 if (it != null)
353 {
354 while(it.hasNext())
355 {
356 mctx.addAttachedObjectHandler(
357 compositeComponentBase, it.next());
358 }
359 }
360
361 VariableMapper orig = faceletContext.getVariableMapper();
362 try
363 {
364 faceletContext.setVariableMapper(new VariableMapperWrapper(orig));
365 actx.pushCompositeComponentClient(this);
366 Resource resourceForCurrentView = faceletContext.getFacesContext().getApplication().
367 getResourceHandler().createResource(_resource.getResourceName(), _resource.getLibraryName());
368 if (resourceForCurrentView != null)
369 {
370
371 resourceForCurrentView = new CompositeResouceWrapper(resourceForCurrentView);
372 }
373 else
374 {
375
376
377 throw new TagException(getTag(), "Composite Component " + getTag().getQName()
378 + " requires a default instance that can be found by the installed ResourceHandler.");
379 }
380 actx.applyCompositeComponent(compositeFacetPanel, resourceForCurrentView);
381 }
382 finally
383 {
384 actx.popCompositeComponentClient();
385 faceletContext.setVariableMapper(orig);
386 }
387 }
388
389 @Override
390 public void setAttributes(FaceletContext ctx, Object instance)
391 {
392 if (instance != null)
393 {
394 UIComponent component = (UIComponent) instance;
395
396 Class<?> type = instance.getClass();
397 if (_mapper == null || !_lastType.equals(type))
398 {
399 _lastType = type;
400 BeanInfo beanInfo = (BeanInfo)component.getAttributes().get(UIComponent.BEANINFO_KEY);
401 _mapper = createMetaRuleset(type , beanInfo).finish();
402 }
403
404 _mapper.applyMetadata(ctx, instance);
405 }
406 }
407
408 protected MetaRuleset createMetaRuleset(Class<?> type, BeanInfo beanInfo)
409 {
410 MetaRuleset m = new CompositeMetaRulesetImpl(this.getTag(), type, beanInfo);
411
412 m.ignore("binding").ignore("id");
413
414
415 m.addRule(CompositeComponentRule.INSTANCE);
416
417
418 m.addRule(RetargetMethodExpressionRule.INSTANCE);
419
420 if (ActionSource.class.isAssignableFrom(type))
421 {
422 m.addRule(ActionSourceRule.INSTANCE);
423 }
424
425 if (ValueHolder.class.isAssignableFrom(type))
426 {
427 m.addRule(ValueHolderRule.INSTANCE);
428
429 if (EditableValueHolder.class.isAssignableFrom(type))
430 {
431 m.ignore("submittedValue");
432 m.ignore("valid");
433 m.addRule(EditableValueHolderRule.INSTANCE);
434 }
435 }
436
437 return m;
438 }
439
440 private void initFacetHandlersMap(FaceletContext ctx)
441 {
442 if (_facetHandlersMap == null)
443 {
444 Map<String, FaceletHandler> map = new HashMap<String, FaceletHandler>();
445
446 for (FaceletHandler handler : _facetHandlers)
447 {
448 if (handler instanceof javax.faces.view.facelets.FacetHandler )
449 {
450 map.put( ((javax.faces.view.facelets.FacetHandler)handler).getFacetName(ctx), handler);
451 }
452 else if (handler instanceof InsertFacetHandler)
453 {
454 map.put( ((InsertFacetHandler)handler).getFacetName(ctx), handler);
455 }
456 }
457 _facetHandlersMap = map;
458 }
459 }
460
461 public boolean apply(FaceletContext ctx, UIComponent parent, String name)
462 throws IOException, FacesException, FaceletException, ELException
463 {
464 if (name != null)
465 {
466
467 if (_facetHandlers == null || _facetHandlers.isEmpty())
468 {
469 checkFacetRequired(ctx, parent, name);
470 return true;
471 }
472
473 initFacetHandlersMap(ctx);
474
475 FaceletHandler handler = _facetHandlersMap.get(name);
476
477 if (handler != null)
478 {
479 AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
480
481
482
483 FaceletCompositionContext fcc = actx.getFaceletCompositionContext();
484 UIComponent innerCompositeComponent = fcc.getCompositeComponentFromStack();
485 fcc.popCompositeComponentToStack();
486
487
488 TemplateContext itc = actx.popTemplateContext();
489 try
490 {
491 handler.apply(ctx, parent);
492 }
493 finally
494 {
495 actx.pushTemplateContext(itc);
496 fcc.pushCompositeComponentToStack(innerCompositeComponent);
497 }
498 return true;
499
500 }
501 else
502 {
503 checkFacetRequired(ctx, parent, name);
504 return true;
505 }
506 }
507 else
508 {
509 AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
510
511
512
513 FaceletCompositionContext fcc = actx.getFaceletCompositionContext();
514 UIComponent innerCompositeComponent = fcc.getCompositeComponentFromStack();
515 fcc.popCompositeComponentToStack();
516
517
518 TemplateContext itc = actx.popTemplateContext();
519 try
520 {
521 for (FaceletHandler handler : _componentHandlers)
522 {
523 handler.apply(ctx, parent);
524 }
525 }
526 finally
527 {
528 actx.pushTemplateContext(itc);
529 fcc.pushCompositeComponentToStack(innerCompositeComponent);
530 }
531 return true;
532 }
533 }
534
535 private void checkFacetRequired(FaceletContext ctx, UIComponent parent, String name)
536 {
537 AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
538 FaceletCompositionContext fcc = actx.getFaceletCompositionContext();
539 UIComponent innerCompositeComponent = fcc.getCompositeComponentFromStack();
540
541 CompositeComponentBeanInfo beanInfo =
542 (CompositeComponentBeanInfo) innerCompositeComponent.getAttributes()
543 .get(UIComponent.BEANINFO_KEY);
544
545 BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor();
546
547 Map<String, PropertyDescriptor> insertFacetPropertyDescriptorMap = (Map<String, PropertyDescriptor>)
548 beanDescriptor.getValue(InsertFacetHandler.INSERT_FACET_KEYS);
549
550 if (insertFacetPropertyDescriptorMap != null && insertFacetPropertyDescriptorMap.containsKey(name))
551 {
552 ValueExpression requiredExpr
553 = (ValueExpression) insertFacetPropertyDescriptorMap.get(name).getValue("required");
554
555 if (requiredExpr != null &&
556 Boolean.TRUE.equals(requiredExpr.getValue(ctx.getFacesContext().getELContext())))
557 {
558
559 throw new TagException(this.tag, "Cannot find facet with name '"+name+"' in composite component");
560 }
561 }
562 }
563 }