View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.view.facelets.tag;
20  
21  import java.lang.reflect.Constructor;
22  import java.lang.reflect.InvocationTargetException;
23  import java.lang.reflect.Method;
24  import java.net.URL;
25  import java.util.HashMap;
26  import java.util.Map;
27  
28  import javax.el.ELException;
29  import javax.faces.FacesException;
30  import javax.faces.application.Resource;
31  import javax.faces.application.ResourceHandler;
32  import javax.faces.context.FacesContext;
33  import javax.faces.view.facelets.BehaviorConfig;
34  import javax.faces.view.facelets.BehaviorHandler;
35  import javax.faces.view.facelets.ComponentConfig;
36  import javax.faces.view.facelets.ComponentHandler;
37  import javax.faces.view.facelets.ConverterConfig;
38  import javax.faces.view.facelets.ConverterHandler;
39  import javax.faces.view.facelets.FaceletException;
40  import javax.faces.view.facelets.FaceletHandler;
41  import javax.faces.view.facelets.Tag;
42  import javax.faces.view.facelets.TagConfig;
43  import javax.faces.view.facelets.TagHandler;
44  import javax.faces.view.facelets.ValidatorConfig;
45  import javax.faces.view.facelets.ValidatorHandler;
46  import org.apache.myfaces.shared.config.MyfacesConfig;
47  import org.apache.myfaces.view.facelets.tag.composite.CompositeComponentResourceTagHandler;
48  import org.apache.myfaces.view.facelets.tag.composite.CompositeResouceWrapper;
49  
50  /**
51   * Base class for defining TagLibraries in Java
52   * 
53   * @author Jacob Hookom
54   * @version $Id$
55   */
56  public abstract class AbstractTagLibrary implements TagLibrary
57  {
58      private final Map<String, TagHandlerFactory> _factories;
59  
60      private final Map<String, Method> _functions;
61  
62      private final String _namespace;
63      private final String _aliasNamespace;
64      private Boolean _strictJsf2FaceletsCompatibility;
65  
66      public AbstractTagLibrary(String namespace, String aliasNamespace)
67      {
68          _namespace = namespace;
69          _aliasNamespace = aliasNamespace;
70          _factories = new HashMap<String, TagHandlerFactory>();
71          _functions = new HashMap<String, Method>();
72      }
73      
74      public AbstractTagLibrary(String namespace)
75      {
76          this(namespace,null);
77      }
78      
79  
80      /*
81       * (non-Javadoc)
82       * 
83       * @see org.apache.myfaces.view.facelets.tag.TagLibrary#containsNamespace(java.lang.String)
84       */
85      public boolean containsNamespace(String ns)
86      {
87          return _namespace.equals(ns) || (_aliasNamespace != null && _aliasNamespace.equals(ns));
88      }
89  
90      /*
91       * (non-Javadoc)
92       * 
93       * @see org.apache.myfaces.view.facelets.tag.TagLibrary#containsTagHandler(java.lang.String, java.lang.String)
94       */
95      public boolean containsTagHandler(String ns, String localName)
96      {
97          return containsNamespace(ns) && _factories.containsKey(localName);
98      }
99  
100     /*
101      * (non-Javadoc)
102      * 
103      * @see org.apache.myfaces.view.facelets.tag.TagLibrary#createTagHandler(java.lang.String, java.lang.String,
104      * org.apache.myfaces.view.facelets.tag.TagConfig)
105      */
106     public TagHandler createTagHandler(String ns, String localName, TagConfig tag) throws FacesException
107     {
108         if (containsNamespace(ns))
109         {
110             TagHandlerFactory f = _factories.get(localName);
111             if (f != null)
112             {
113                 return f.createHandler(tag);
114             }
115         }
116         
117         return null;
118     }
119 
120     /*
121      * (non-Javadoc)
122      * 
123      * @see org.apache.myfaces.view.facelets.tag.TagLibrary#containsFunction(java.lang.String, java.lang.String)
124      */
125     public boolean containsFunction(String ns, String name)
126     {
127         return containsNamespace(ns) && _functions.containsKey(name);
128     }
129 
130     /*
131      * (non-Javadoc)
132      * 
133      * @see org.apache.myfaces.view.facelets.tag.TagLibrary#createFunction(java.lang.String, java.lang.String)
134      */
135     public Method createFunction(String ns, String name)
136     {
137         return containsNamespace(ns) ? _functions.get(name) : null;
138     }
139 
140     public String getNamespace()
141     {
142         return _namespace;
143     }
144 
145     /**
146      * Add a ComponentHandler with the specified componentType and rendererType, aliased by the tag name.
147      * 
148      * @see ComponentHandler
149      * @see javax.faces.application.Application#createComponent(java.lang.String)
150      * @param name
151      *            name to use, "foo" would be &lt;my:foo />
152      * @param componentType
153      *            componentType to use
154      * @param rendererType
155      *            rendererType to use
156      */
157     protected final void addComponent(String name, String componentType, String rendererType)
158     {
159         _factories.put(name, new ComponentHandlerFactory(componentType, rendererType));
160     }
161 
162     /**
163      * Add a ComponentHandler with the specified componentType and rendererType, aliased by the tag name. The Facelet
164      * will be compiled with the specified HandlerType (which must extend AbstractComponentHandler).
165      * 
166      * @see AbstractComponentHandler
167      * @param name
168      *            name to use, "foo" would be &lt;my:foo />
169      * @param componentType
170      *            componentType to use
171      * @param rendererType
172      *            rendererType to use
173      * @param handlerType
174      *            a Class that extends AbstractComponentHandler
175      */
176     protected final void addComponent(String name, String componentType, String rendererType, 
177                                       Class<? extends TagHandler> handlerType)
178     {
179         _factories.put(name, new UserComponentHandlerFactory(componentType, rendererType, handlerType));
180     }
181     
182     protected final void addComponentFromResourceId(String name, String resourceId)
183     {
184         _factories.put(name, new UserComponentFromResourceIdHandlerFactory(resourceId));
185     }
186 
187     /**
188      * Add a ConvertHandler for the specified converterId
189      * 
190      * @see javax.faces.view.facelets.ConverterHandler
191      * @see javax.faces.application.Application#createConverter(java.lang.String)
192      * @param name
193      *            name to use, "foo" would be &lt;my:foo />
194      * @param converterId
195      *            id to pass to Application instance
196      */
197     protected final void addConverter(String name, String converterId)
198     {
199         _factories.put(name, new ConverterHandlerFactory(converterId));
200     }
201 
202     /**
203      * Add a ConvertHandler for the specified converterId of a TagHandler type
204      * 
205      * @see javax.faces.view.facelets.ConverterHandler
206      * @see javax.faces.view.facelets.ConverterConfig
207      * @see javax.faces.application.Application#createConverter(java.lang.String)
208      * @param name
209      *            name to use, "foo" would be &lt;my:foo />
210      * @param converterId
211      *            id to pass to Application instance
212      * @param type
213      *            TagHandler type that takes in a ConverterConfig
214      */
215     protected final void addConverter(String name, String converterId, Class<? extends TagHandler> type)
216     {
217         _factories.put(name, new UserConverterHandlerFactory(converterId, type));
218     }
219 
220     /**
221      * Add a ValidateHandler for the specified validatorId
222      * 
223      * @see javax.faces.view.facelets.ValidatorHandler
224      * @see javax.faces.application.Application#createValidator(java.lang.String)
225      * @param name
226      *            name to use, "foo" would be &lt;my:foo />
227      * @param validatorId
228      *            id to pass to Application instance
229      */
230     protected final void addValidator(String name, String validatorId)
231     {
232         _factories.put(name, new ValidatorHandlerFactory(validatorId));
233     }
234 
235     /**
236      * Add a ValidateHandler for the specified validatorId
237      * 
238      * @see javax.faces.view.facelets.ValidatorHandler
239      * @see javax.faces.view.facelets.ValidatorConfig
240      * @see javax.faces.application.Application#createValidator(java.lang.String)
241      * @param name
242      *            name to use, "foo" would be &lt;my:foo />
243      * @param validatorId
244      *            id to pass to Application instance
245      * @param type
246      *            TagHandler type that takes in a ValidatorConfig
247      */
248     protected final void addValidator(String name, String validatorId, Class<? extends TagHandler> type)
249     {
250         _factories.put(name, new UserValidatorHandlerFactory(validatorId, type));
251     }
252 
253     /**
254      * Use the specified HandlerType in compiling Facelets. HandlerType must extend TagHandler.
255      * 
256      * @see TagHandler
257      * @param name
258      *            name to use, "foo" would be &lt;my:foo />
259      * @param handlerType
260      *            must extend TagHandler
261      */
262     protected final void addTagHandler(String name, Class<? extends TagHandler> handlerType)
263     {
264         _factories.put(name, new HandlerFactory(handlerType));
265     }
266 
267     /**
268      * Add a UserTagHandler specified a the URL source.
269      * 
270      * @see UserTagHandler
271      * @param name
272      *            name to use, "foo" would be &lt;my:foo />
273      * @param source
274      *            source where the Facelet (Tag) source is
275      */
276     protected final void addUserTag(String name, URL source)
277     {
278         if (_strictJsf2FaceletsCompatibility == null)
279         {
280             MyfacesConfig config = MyfacesConfig.getCurrentInstance(
281                     FacesContext.getCurrentInstance().getExternalContext());
282 
283             _strictJsf2FaceletsCompatibility = config.isStrictJsf2FaceletsCompatibility();
284         }
285         if (Boolean.TRUE.equals(_strictJsf2FaceletsCompatibility))
286         {
287             _factories.put(name, new LegacyUserTagFactory(source));
288         }
289         else
290         {
291             _factories.put(name, new UserTagFactory(source));
292         }
293     }
294 
295     /**
296      * Add a Method to be used as a Function at Compilation.
297      * 
298      * @see javax.el.FunctionMapper
299      * 
300      * @param name
301      *            (suffix) of function name
302      * @param method
303      *            method instance
304      */
305     protected final void addFunction(String name, Method method)
306     {
307         _functions.put(name, method);
308     }
309     
310     /**
311      * @since 2.0
312      * @param behaviorId
313      * @param behaviorClass
314      */
315     protected final void addBehavior(String name, String behaviorId)
316     {
317         _factories.put(name, new BehaviorHandlerFactory(behaviorId));
318     }
319     
320     /**
321      * @since 2.0
322      * @param behaviorId
323      * @param behaviorClass
324      * @param handlerType
325      */
326     protected final void addBehavior(String name, String behaviorId,
327             Class<? extends TagHandler> handlerType)
328     {
329         _factories.put(name, new UserBehaviorHandlerFactory(behaviorId,handlerType));
330     }    
331 
332     private static class ValidatorConfigWrapper implements ValidatorConfig
333     {
334 
335         private final TagConfig parent;
336         private final String validatorId;
337 
338         public ValidatorConfigWrapper(TagConfig parent, String validatorId)
339         {
340             this.parent = parent;
341             this.validatorId = validatorId;
342         }
343 
344         public String getValidatorId()
345         {
346             return this.validatorId;
347         }
348 
349         public FaceletHandler getNextHandler()
350         {
351             return this.parent.getNextHandler();
352         }
353 
354         public Tag getTag()
355         {
356             return this.parent.getTag();
357         }
358 
359         public String getTagId()
360         {
361             return this.parent.getTagId();
362         }
363     }
364 
365     private static class ConverterConfigWrapper implements ConverterConfig
366     {
367         private final TagConfig parent;
368         private final String converterId;
369 
370         public ConverterConfigWrapper(TagConfig parent, String converterId)
371         {
372             this.parent = parent;
373             this.converterId = converterId;
374         }
375 
376         public String getConverterId()
377         {
378             return this.converterId;
379         }
380 
381         public FaceletHandler getNextHandler()
382         {
383             return this.parent.getNextHandler();
384         }
385 
386         public Tag getTag()
387         {
388             return this.parent.getTag();
389         }
390 
391         public String getTagId()
392         {
393             return this.parent.getTagId();
394         }
395     }
396 
397     private static class HandlerFactory implements TagHandlerFactory
398     {
399         private final static Class<?>[] CONSTRUCTOR_SIG = new Class[]{TagConfig.class};
400 
401         protected final Class<? extends TagHandler> handlerType;
402 
403         public HandlerFactory(Class<? extends TagHandler> handlerType)
404         {
405             this.handlerType = handlerType;
406         }
407 
408         public TagHandler createHandler(TagConfig cfg) throws FacesException, ELException
409         {
410             try
411             {
412                 return handlerType.getConstructor(CONSTRUCTOR_SIG).newInstance(new Object[] { cfg });
413             }
414             catch (InvocationTargetException ite)
415             {
416                 Throwable t = ite.getCause();
417                 if (t instanceof FacesException)
418                 {
419                     throw (FacesException) t;
420                 }
421                 else if (t instanceof ELException)
422                 {
423                     throw (ELException) t;
424                 }
425                 else
426                 {
427                     throw new FacesException("Error Instantiating: " + handlerType.getName(), t);
428                 }
429             }
430             catch (Exception e)
431             {
432                 throw new FacesException("Error Instantiating: " + handlerType.getName(), e);
433             }
434         }
435     }
436 
437     private static class ComponentConfigWrapper implements ComponentConfig
438     {
439 
440         protected final TagConfig parent;
441 
442         protected final String componentType;
443 
444         protected final String rendererType;
445 
446         public ComponentConfigWrapper(TagConfig parent, String componentType, String rendererType)
447         {
448             this.parent = parent;
449             this.componentType = componentType;
450             this.rendererType = rendererType;
451         }
452 
453         public String getComponentType()
454         {
455             return this.componentType;
456         }
457 
458         public String getRendererType()
459         {
460             return this.rendererType;
461         }
462 
463         public FaceletHandler getNextHandler()
464         {
465             return this.parent.getNextHandler();
466         }
467 
468         public Tag getTag()
469         {
470             return this.parent.getTag();
471         }
472 
473         public String getTagId()
474         {
475             return this.parent.getTagId();
476         }
477     }
478 
479     private static class UserTagFactory implements TagHandlerFactory
480     {
481         protected final URL location;
482 
483         public UserTagFactory(URL location)
484         {
485             this.location = location;
486         }
487 
488         public TagHandler createHandler(TagConfig cfg) throws FacesException, ELException
489         {
490             return new UserTagHandler(cfg, this.location);
491         }
492     }
493     
494     private static class LegacyUserTagFactory implements TagHandlerFactory
495     {
496         protected final URL location;
497 
498         public LegacyUserTagFactory(URL location)
499         {
500             this.location = location;
501         }
502 
503         public TagHandler createHandler(TagConfig cfg) throws FacesException, ELException
504         {
505             return new LegacyUserTagHandler(cfg, this.location);
506         }
507     }
508 
509     private static class ComponentHandlerFactory implements TagHandlerFactory
510     {
511 
512         protected final String componentType;
513 
514         protected final String renderType;
515 
516         /**
517          * @param handlerType
518          */
519         public ComponentHandlerFactory(String componentType, String renderType)
520         {
521             this.componentType = componentType;
522             this.renderType = renderType;
523         }
524 
525         public TagHandler createHandler(TagConfig cfg) throws FacesException, ELException
526         {
527             ComponentConfig ccfg = new ComponentConfigWrapper(cfg, this.componentType, this.renderType);
528             return new ComponentHandler(ccfg);
529         }
530     }
531 
532     private static class UserComponentHandlerFactory implements TagHandlerFactory
533     {
534 
535         private final static Class<?>[] CONS_SIG = new Class[] { ComponentConfig.class };
536 
537         protected final String componentType;
538 
539         protected final String renderType;
540 
541         protected final Class<? extends TagHandler> type;
542 
543         protected final Constructor<? extends TagHandler> constructor;
544 
545         /**
546          * @param handlerType
547          */
548         public UserComponentHandlerFactory(String componentType, String renderType, Class<? extends TagHandler> type)
549         {
550             this.componentType = componentType;
551             this.renderType = renderType;
552             this.type = type;
553             try
554             {
555                 this.constructor = this.type.getConstructor(CONS_SIG);
556             }
557             catch (Exception e)
558             {
559                 throw new FaceletException("Must have a Constructor that takes in a ComponentConfig", e);
560             }
561         }
562 
563         public TagHandler createHandler(TagConfig cfg) throws FacesException, ELException
564         {
565             try
566             {
567                 ComponentConfig ccfg = new ComponentConfigWrapper(cfg, componentType, renderType);
568                 return constructor.newInstance(new Object[] { ccfg });
569             }
570             catch (InvocationTargetException e)
571             {
572                 throw new FaceletException(e.getCause().getMessage(), e.getCause().getCause());
573             }
574             catch (Exception e)
575             {
576                 throw new FaceletException("Error Instantiating ComponentHandler: " + this.type.getName(), e);
577             }
578         }
579     }
580 
581     private static class ValidatorHandlerFactory implements TagHandlerFactory
582     {
583 
584         protected final String validatorId;
585 
586         public ValidatorHandlerFactory(String validatorId)
587         {
588             this.validatorId = validatorId;
589         }
590 
591         public TagHandler createHandler(TagConfig cfg) throws FacesException, ELException
592         {
593             return new ValidatorHandler(new ValidatorConfigWrapper(cfg, this.validatorId));
594         }
595     }
596 
597     private static class ConverterHandlerFactory implements TagHandlerFactory
598     {
599 
600         protected final String converterId;
601 
602         public ConverterHandlerFactory(String converterId)
603         {
604             this.converterId = converterId;
605         }
606 
607         public TagHandler createHandler(TagConfig cfg) throws FacesException, ELException
608         {
609             return new ConverterHandler(new ConverterConfigWrapper(cfg, this.converterId));
610         }
611     }
612 
613     private static class UserConverterHandlerFactory implements TagHandlerFactory
614     {
615         private final static Class<?>[] CONS_SIG = new Class[] { ConverterConfig.class };
616 
617         protected final String converterId;
618 
619         protected final Class<? extends TagHandler> type;
620 
621         protected final Constructor<? extends TagHandler> constructor;
622 
623         public UserConverterHandlerFactory(String converterId, Class<? extends TagHandler> type)
624         {
625             this.converterId = converterId;
626             this.type = type;
627             try
628             {
629                 this.constructor = this.type.getConstructor(CONS_SIG);
630             }
631             catch (Exception e)
632             {
633                 throw new FaceletException("Must have a Constructor that takes in a ConverterConfig", e);
634             }
635         }
636 
637         public TagHandler createHandler(TagConfig cfg) throws FacesException, ELException
638         {
639             try
640             {
641                 ConverterConfig ccfg = new ConverterConfigWrapper(cfg, converterId);
642                 return constructor.newInstance(new Object[] { ccfg });
643             }
644             catch (InvocationTargetException e)
645             {
646                 throw new FaceletException(e.getCause().getMessage(), e.getCause().getCause());
647             }
648             catch (Exception e)
649             {
650                 throw new FaceletException("Error Instantiating ConverterHandler: " + type.getName(), e);
651             }
652         }
653     }
654 
655     private static class UserValidatorHandlerFactory implements TagHandlerFactory
656     {
657         private final static Class<?>[] CONS_SIG = new Class[] { ValidatorConfig.class };
658 
659         protected final String validatorId;
660 
661         protected final Class<? extends TagHandler> type;
662 
663         protected final Constructor<? extends TagHandler> constructor;
664 
665         public UserValidatorHandlerFactory(String validatorId, Class<? extends TagHandler> type)
666         {
667             this.validatorId = validatorId;
668             this.type = type;
669             try
670             {
671                 this.constructor = this.type.getConstructor(CONS_SIG);
672             }
673             catch (Exception e)
674             {
675                 throw new FaceletException("Must have a Constructor that takes in a ConverterConfig", e);
676             }
677         }
678 
679         public TagHandler createHandler(TagConfig cfg) throws FacesException, ELException
680         {
681             try
682             {
683                 ValidatorConfig ccfg = new ValidatorConfigWrapper(cfg, validatorId);
684                 return constructor.newInstance(new Object[] { ccfg });
685             }
686             catch (InvocationTargetException e)
687             {
688                 throw new FaceletException(e.getCause().getMessage(), e.getCause().getCause());
689             }
690             catch (Exception e)
691             {
692                 throw new FaceletException("Error Instantiating ValidatorHandler: " + type.getName(), e);
693             }
694         }
695     }
696     
697     private static class BehaviorConfigWrapper implements BehaviorConfig
698     {
699         protected final TagConfig parent;
700 
701         protected final String behaviorId;
702 
703         public BehaviorConfigWrapper(TagConfig parent, String behaviorId)
704         {
705             this.parent = parent;
706             this.behaviorId = behaviorId;
707         }
708 
709         public FaceletHandler getNextHandler()
710         {
711             return this.parent.getNextHandler();
712         }
713 
714         public Tag getTag()
715         {
716             return this.parent.getTag();
717         }
718 
719         public String getTagId()
720         {
721             return this.parent.getTagId();
722         }
723 
724         public String getBehaviorId()
725         {
726             return this.behaviorId;
727         }
728     }
729     
730     private static class BehaviorHandlerFactory implements TagHandlerFactory
731     {
732         protected final String behaviorId;
733                
734         public BehaviorHandlerFactory(String behaviorId)
735         {
736             super();
737             this.behaviorId = behaviorId;
738         }
739 
740         public TagHandler createHandler(TagConfig cfg) throws FacesException, ELException
741         {
742             BehaviorConfig bcfg = new BehaviorConfigWrapper(cfg,this.behaviorId);
743             return new BehaviorHandler(bcfg);
744         }
745     }
746 
747     private static class UserBehaviorHandlerFactory implements TagHandlerFactory
748     {
749         private final static Class<?>[] CONS_SIG = new Class[] { BehaviorConfig.class };
750 
751         protected final String behaviorId;
752 
753         protected final Class<? extends TagHandler> type;
754 
755         protected final Constructor<? extends TagHandler> constructor;
756 
757         public UserBehaviorHandlerFactory(String behaviorId, Class<? extends TagHandler> type)
758         {
759             this.behaviorId = behaviorId;
760             this.type = type;
761             try
762             {
763                 this.constructor = this.type.getConstructor(CONS_SIG);
764             }
765             catch (Exception e)
766             {
767                 throw new FaceletException("Must have a Constructor that takes in a BehaviorConfig", e);
768             }
769         }
770 
771         public TagHandler createHandler(TagConfig cfg) throws FacesException, ELException
772         {
773             try
774             {
775                 BehaviorConfig bcfg = new BehaviorConfigWrapper(cfg,this.behaviorId);
776                 return constructor.newInstance(new Object[] { bcfg });
777             }
778             catch (InvocationTargetException e)
779             {
780                 throw new FaceletException(e.getCause().getMessage(), e.getCause().getCause());
781             }
782             catch (Exception e)
783             {
784                 throw new FaceletException("Error Instantiating BehaviorHandler: " + this.type.getName(), e);
785             }
786         }
787     }
788     
789     private static class UserComponentFromResourceIdHandlerFactory implements TagHandlerFactory
790     {
791         protected final String resourceId;
792         
793         public UserComponentFromResourceIdHandlerFactory(String resourceId)
794         {
795             this.resourceId = resourceId;
796         }
797 
798         public TagHandler createHandler(TagConfig cfg) throws FacesException, ELException
799         {
800             FacesContext facesContext = FacesContext.getCurrentInstance();
801             ResourceHandler resourceHandler = facesContext.getApplication().getResourceHandler();
802             Resource compositeComponentResourceWrapped = resourceHandler.createResourceFromId(resourceId);
803             if (compositeComponentResourceWrapped != null)
804             {
805                 Resource compositeComponentResource
806                         = new CompositeResouceWrapper(compositeComponentResourceWrapped);
807                 ComponentConfig componentConfig = new ComponentConfigWrapper(cfg,
808                         "javax.faces.NamingContainer", null);
809 
810                 return new CompositeComponentResourceTagHandler(componentConfig,
811                                                                 compositeComponentResource);
812             }
813             else
814             {
815                 throw new FaceletException(
816                     "Error Instantiating Component from <resource-id> declaration: " + this.resourceId);
817             }
818         }
819     }
820 }