Coverage Report - org.apache.myfaces.view.facelets.tag.jsf.html.DefaultTagDecorator
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultTagDecorator
0%
0/126
0%
0/70
9
DefaultTagDecorator$1
N/A
N/A
9
DefaultTagDecorator$TagDecoratorExecutor
N/A
N/A
9
DefaultTagDecorator$TagSelector
0%
0/1
N/A
9
DefaultTagDecorator$TagSelectorImpl
0%
0/70
0%
0/64
9
 
 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.jsf.html;
 20  
 
 21  
 import java.util.Arrays;
 22  
 import javax.faces.render.Renderer;
 23  
 import javax.faces.view.facelets.FaceletException;
 24  
 import javax.faces.view.facelets.Tag;
 25  
 import javax.faces.view.facelets.TagAttribute;
 26  
 import javax.faces.view.facelets.TagAttributes;
 27  
 import javax.faces.view.facelets.TagDecorator;
 28  
 import org.apache.myfaces.view.facelets.tag.TagAttributeImpl;
 29  
 import org.apache.myfaces.view.facelets.tag.TagAttributesImpl;
 30  
 import org.apache.myfaces.view.facelets.tag.jsf.JsfLibrary;
 31  
 import org.apache.myfaces.view.facelets.tag.jsf.PassThroughLibrary;
 32  
 import org.apache.myfaces.view.facelets.tag.jsf.core.CoreLibrary;
 33  
 
 34  
 /**
 35  
  * Default implementation of TagDecorator as described in JSF 2.2 javadoc of
 36  
  * javax.faces.view.facelets.TagDecorator
 37  
  * 
 38  
  * @since 2.2
 39  
  * @author Leonardo Uribe
 40  
  */
 41  0
 public class DefaultTagDecorator implements TagDecorator
 42  
 {
 43  
     public final static String XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
 44  
     public final static String JSF_NAMESPACE = JsfLibrary.NAMESPACE;
 45  
     public final static String JSF_ALIAS_NAMESPACE = JsfLibrary.ALIAS_NAMESPACE;
 46  
     public final static String PASS_THROUGH_NAMESPACE = PassThroughLibrary.NAMESPACE;
 47  
     public final static String PASS_THROUGH_ALIAS_NAMESPACE = PassThroughLibrary.ALIAS_NAMESPACE;
 48  
     private final static String EMPTY_NAMESPACE = "";
 49  
     
 50  
     private final static String P_ELEMENTNAME = "p:"+Renderer.PASSTHROUGH_RENDERER_LOCALNAME_KEY;
 51  
     
 52  
     /**
 53  
      * Fast array for lookup of local names to be inspected. 
 54  
      */
 55  0
     static private final Object[][] LOCAL_NAME_ARR = new Object[256][];
 56  
     
 57  0
     static private final Object[] A_NAMES = new Object[]
 58  
     {
 59  
       "a", new Object[]
 60  
       {
 61  
         new TagSelectorImpl("jsf:action", "h:commandLink"),
 62  
         new TagSelectorImpl("jsf:actionListener", "h:commandLink"),
 63  
         new TagSelectorImpl("jsf:value", "h:outputLink"),
 64  
         new TagSelectorImpl("jsf:outcome", "h:link")
 65  
       }
 66  
     };
 67  
 
 68  0
     static private final Object[] B_NAMES = new Object[]
 69  
     {
 70  
       "body",   new Object[]{new TagSelectorImpl(null, "h:body")},
 71  
       "button", new Object[]{
 72  
           new TagSelectorImpl("jsf:outcome", "h:button"),
 73  
           new TagSelectorImpl(null, "h:commandButton")
 74  
       }
 75  
     };
 76  
     
 77  0
     static private final Object[] F_NAMES = new Object[]
 78  
     {
 79  
       "form", new Object[]{new TagSelectorImpl(null, "h:form")}
 80  
     };
 81  
     
 82  0
     static private final Object[] H_NAMES = new Object[]
 83  
     {
 84  
       "head", new Object[]{new TagSelectorImpl(null, "h:head")}
 85  
     };
 86  
     
 87  0
     static private final Object[] I_NAMES = new Object[]
 88  
     {
 89  
       "img", new Object[]{new TagSelectorImpl(null, "h:graphicImage")},
 90  
       // We can optimize this part, but note the decoration step is done at
 91  
       // compile time, so at the end it does not matter. The important 
 92  
       // optimization is the outer one.      
 93  
       "input", new Object[]{
 94  
           new TagSelectorImpl("type=\"button\"", "h:commandButton"),
 95  
           new TagSelectorImpl("type=\"checkbox\"", "h:selectBooleanCheckbox"),          
 96  
           
 97  
           new TagSelectorImpl("type=\"color\"", "h:inputText"),
 98  
           new TagSelectorImpl("type=\"date\"", "h:inputText"),
 99  
           new TagSelectorImpl("type=\"datetime\"", "h:inputText"),
 100  
           new TagSelectorImpl("type=\"datetime-local\"", "h:inputText"),          
 101  
           new TagSelectorImpl("type=\"email\"", "h:inputText"),
 102  
           new TagSelectorImpl("type=\"month\"", "h:inputText"),
 103  
           new TagSelectorImpl("type=\"number\"", "h:inputText"),
 104  
           new TagSelectorImpl("type=\"range\"", "h:inputText"),
 105  
           new TagSelectorImpl("type=\"search\"", "h:inputText"),
 106  
           new TagSelectorImpl("type=\"time\"", "h:inputText"),
 107  
           new TagSelectorImpl("type=\"url\"", "h:inputText"),
 108  
           new TagSelectorImpl("type=\"week\"", "h:inputText"),
 109  
           
 110  
           new TagSelectorImpl("type=\"file\"", "h:inputFile"),
 111  
           new TagSelectorImpl("type=\"hidden\"", "h:inputHidden"),
 112  
           new TagSelectorImpl("type=\"password\"", "h:inputSecret"),
 113  
           new TagSelectorImpl("type=\"reset\"", "h:commandButton"),
 114  
           new TagSelectorImpl("type=\"submit\"", "h:commandButton"),
 115  
           new TagSelectorImpl("type=\"*\"", "h:inputText")
 116  
       }
 117  
     };
 118  
     
 119  0
     static private final Object[] L_NAMES = new Object[]
 120  
     {
 121  
       "label", new Object[]{new TagSelectorImpl(null, "h:outputLabel")},
 122  
       "link",  new Object[]{new TagSelectorImpl(null, "h:outputStylesheet")}
 123  
     };
 124  
 
 125  0
     static private final Object[] S_NAMES = new Object[]
 126  
     {
 127  
       "script", new Object[]{new TagSelectorImpl(null, "h:outputScript")},
 128  
       "select", new Object[]
 129  
       {
 130  
         new TagSelectorImpl("multiple=\"*\"", "h:selectManyListbox"),
 131  
         new TagSelectorImpl(null, "h:selectOneListbox")
 132  
       }
 133  
     };
 134  
     
 135  0
     static private final Object[] T_NAMES = new Object[]
 136  
     {
 137  
       "textarea", new Object[]{new TagSelectorImpl(null, "h:inputTextarea")}
 138  
     };    
 139  
 
 140  
     static
 141  
     {
 142  0
       LOCAL_NAME_ARR['a'] = A_NAMES;
 143  0
       LOCAL_NAME_ARR['A'] = A_NAMES;
 144  0
       LOCAL_NAME_ARR['b'] = B_NAMES;
 145  0
       LOCAL_NAME_ARR['B'] = B_NAMES;
 146  0
       LOCAL_NAME_ARR['f'] = F_NAMES;
 147  0
       LOCAL_NAME_ARR['F'] = F_NAMES;
 148  0
       LOCAL_NAME_ARR['h'] = H_NAMES;
 149  0
       LOCAL_NAME_ARR['H'] = H_NAMES;
 150  0
       LOCAL_NAME_ARR['i'] = I_NAMES;
 151  0
       LOCAL_NAME_ARR['I'] = I_NAMES;
 152  0
       LOCAL_NAME_ARR['l'] = L_NAMES;
 153  0
       LOCAL_NAME_ARR['L'] = L_NAMES;
 154  0
       LOCAL_NAME_ARR['s'] = S_NAMES;
 155  0
       LOCAL_NAME_ARR['S'] = S_NAMES;
 156  0
       LOCAL_NAME_ARR['t'] = T_NAMES;
 157  0
       LOCAL_NAME_ARR['T'] = T_NAMES;
 158  
     }
 159  
     
 160  0
     static private final String[][] RESERVED_JSF_ATTRS_ARR =  new String[256][];
 161  
     
 162  0
     static private final String[] JSF_ATTRS_B_NAMES = {"binding"};
 163  
 
 164  0
     static private final String[] JSF_ATTRS_I_NAMES = {"id"};
 165  
     
 166  0
     static private final String[] JSF_ATTRS_R_NAMES = {"rendered"};
 167  
     
 168  0
     static private final String[] JSF_ATTRS_T_NAMES = {"transient"};
 169  
 
 170  
     static 
 171  
     {
 172  0
       RESERVED_JSF_ATTRS_ARR['b'] = JSF_ATTRS_B_NAMES;
 173  0
       RESERVED_JSF_ATTRS_ARR['B'] = JSF_ATTRS_B_NAMES;
 174  0
       RESERVED_JSF_ATTRS_ARR['i'] = JSF_ATTRS_I_NAMES;
 175  0
       RESERVED_JSF_ATTRS_ARR['I'] = JSF_ATTRS_I_NAMES;
 176  0
       RESERVED_JSF_ATTRS_ARR['r'] = JSF_ATTRS_R_NAMES;
 177  0
       RESERVED_JSF_ATTRS_ARR['R'] = JSF_ATTRS_R_NAMES;
 178  0
       RESERVED_JSF_ATTRS_ARR['t'] = JSF_ATTRS_T_NAMES;
 179  0
       RESERVED_JSF_ATTRS_ARR['T'] = JSF_ATTRS_T_NAMES;
 180  
     }
 181  
     
 182  0
     private static final TagDecoratorExecutor NO_MATCH_SELECTOR = new TagSelectorImpl(null, "jsf:element");
 183  
     
 184  
     public Tag decorate(Tag tag)
 185  
     {
 186  0
         boolean jsfNamespaceFound = false;
 187  
 
 188  0
         for (String namespace : tag.getAttributes().getNamespaces())
 189  
         {
 190  0
             if (JSF_NAMESPACE.equals(namespace) || JSF_ALIAS_NAMESPACE.equals(namespace))
 191  
             {
 192  0
                 jsfNamespaceFound = true;
 193  0
                 break;
 194  
             }
 195  
         }
 196  0
         if (!jsfNamespaceFound)
 197  
         {
 198  
             // Return null, so the outer CompositeTagDecorator can process the tag.
 199  0
             return null;
 200  
         }
 201  
         
 202  
         // One or many attributes has the JSF_NAMESPACE attribute set. Check empty or
 203  
         // xhtml namespace
 204  0
         if (EMPTY_NAMESPACE.equals(tag.getNamespace()) ||
 205  
             XHTML_NAMESPACE.equals(tag.getNamespace()))
 206  
         {
 207  0
             String localName = tag.getLocalName();
 208  0
             boolean processed = false;
 209  0
             if (isLocalNameDecorated(localName))
 210  
             {
 211  0
                 Object[] array = LOCAL_NAME_ARR[localName.charAt(0)];
 212  0
                 int localNameIndex = -1;
 213  0
                 if (array != null)
 214  
                 {
 215  0
                     for (int i = array.length - 2; i >= 0; i-=2)
 216  
                     {
 217  0
                         if (localName.equalsIgnoreCase((String)array[i]))
 218  
                         {
 219  0
                             localNameIndex = i;
 220  0
                             break;
 221  
                         }
 222  
                     }
 223  0
                     if (localNameIndex >= 0)
 224  
                     {
 225  0
                         Object[] tagSelectorArray = (Object[]) array[localNameIndex+1];
 226  
 
 227  0
                         for (int i = 0; i < tagSelectorArray.length; i++)
 228  
                         {
 229  0
                             TagSelector tagSelector = (TagSelector) tagSelectorArray[i];
 230  0
                             TagDecoratorExecutor executor = tagSelector.getExecutorIfApplies(tag);
 231  
 
 232  0
                             if (executor != null)
 233  
                             {
 234  0
                                 return executor.decorate(tag, convertTagAttributes(tag));
 235  
                             }
 236  
                         }
 237  
                     }
 238  
                 }
 239  
             }
 240  0
             if (!processed)
 241  
             {
 242  
                 //If no matching entry is found, let jsf:element be the value of targetTag
 243  0
                 return NO_MATCH_SELECTOR.decorate(tag, convertTagAttributes(tag));
 244  
             }
 245  0
             return null;
 246  
         }
 247  
         else
 248  
         {
 249  0
             throw new FaceletException("Attributes under "+JSF_NAMESPACE+
 250  
                 " can only be used for tags under "+ XHTML_NAMESPACE +" or tags with no namespace defined" );
 251  
         }
 252  
     }
 253  
     
 254  
     private TagAttributes convertTagAttributes(Tag tag)
 255  
     {        
 256  0
         TagAttribute[] sourceTagAttributes = tag.getAttributes().getAll();
 257  
         
 258  0
         String elementNameTagLocalName = tag.getLocalName();
 259  
 
 260  0
         TagAttribute elementNameTagAttribute = new TagAttributeImpl(
 261  
             tag.getLocation(), PASS_THROUGH_NAMESPACE , Renderer.PASSTHROUGH_RENDERER_LOCALNAME_KEY,
 262  
             P_ELEMENTNAME, elementNameTagLocalName );
 263  
         
 264  
         // 1. Count how many attributes requires to be duplicated
 265  0
         int duplicateCount = 0;
 266  
         
 267  0
         TagAttribute[] convertedTagAttributes = new TagAttribute[
 268  
             sourceTagAttributes.length+1+duplicateCount];
 269  0
         boolean elementNameTagAttributeSet = false;
 270  0
         int j = 0;
 271  
 
 272  0
         for (int i = 0; i < sourceTagAttributes.length; i++)
 273  
         {
 274  0
             TagAttribute tagAttribute = sourceTagAttributes[i];
 275  
             String convertedNamespace;
 276  
             String qname;
 277  0
             String namespace = tagAttribute.getNamespace();
 278  
             
 279  
             /*
 280  
                 -= Leonardo Uribe =- After check the javadoc and compare it with the code and try some
 281  
                 examples with the implementation done in the RI, we found that the javadoc of 
 282  
                 TagDecorator has some bugs. Below is the description of the implementation done, which
 283  
                 resembles the behavior found on the RI.
 284  
 
 285  
                 "...
 286  
                 For each of argument tag's attributes obtain a reference to a TagAttribute 
 287  
                 with the following characteristics. For discussion let such an attribute be 
 288  
                 convertedTagAttribute.
 289  
 
 290  
                     * convertedTagAttribute's location: from the argument tag's location.
 291  
 
 292  
                     * If the current attribute's namespace is http://xmlns.jcp.org/jsf, 
 293  
                         convertedTagAttribute's qualified name must be the current attribute's 
 294  
                         local name and convertedTagAttribute's namespace must be the empty string. 
 295  
                         This will have the effect of setting the current attribute as a proper 
 296  
                         property on the UIComponent instance represented by this markup.
 297  
 
 298  
                     * If the current attribute's namespace is empty, assume the current 
 299  
                         attribute's namespace is http://xmlns.jcp.org/jsf/passthrough. 
 300  
                         ConvertedTagAttribute's qualified name is the current attribute's 
 301  
                         local name prefixed by "p:". convertedTagAttribute's namespace must be 
 302  
                         http://xmlns.jcp.org/jsf/passthrough.
 303  
 
 304  
                     * Otherwise, if the current attribute's namespace is not empty, let 
 305  
                         the current attribute be convertedTagAttribute. This will have the 
 306  
                         effect of let the attribute be processed by the meta rules defined
 307  
                         by the TagHandler instance associated with the generated target 
 308  
                         component.
 309  
                 ..."        
 310  
             */            
 311  0
             if (JSF_NAMESPACE.equals(namespace) || JSF_ALIAS_NAMESPACE.equals(namespace))
 312  
             {
 313  
                 // "... If the current attribute's namespace is http://xmlns.jcp.org/jsf, convertedTagAttribute's 
 314  
                 //  qualified name must be the current attribute's local name and convertedTagAttribute's 
 315  
                 // namespace must be the empty string. This will have the effect of setting the current 
 316  
                 // attribute as a proper property on the UIComponent instance represented by this markup.
 317  0
                 convertedNamespace = "";
 318  0
                 qname = tagAttribute.getLocalName();
 319  
                 
 320  0
                 convertedTagAttributes[j] = new TagAttributeImpl(tagAttribute.getLocation(), 
 321  
                     convertedNamespace, tagAttribute.getLocalName(), qname, tagAttribute.getValue());
 322  
             }
 323  0
             else if (namespace == null)
 324  
             {
 325  
                 // should not happen, but let it because org.xml.sax.Attributes considers it
 326  
                 // -= Leonardo Uribe =- after conversation with Frank Caputo, who was the main contributor for
 327  
                 // this feature in JSF 2.2, he said that if the namespace is empty the intention is pass the
 328  
                 // attribute to the passthrough attribute map, so there is an error in the spec documentation.
 329  
                 //convertedTagAttributes[j] = tagAttribute;
 330  
                 
 331  0
                 convertedNamespace = PASS_THROUGH_NAMESPACE;
 332  0
                 qname = "p:"+tagAttribute.getLocalName();
 333  
                 
 334  0
                 convertedTagAttributes[j] = new TagAttributeImpl(tagAttribute.getLocation(), 
 335  
                     convertedNamespace, tagAttribute.getLocalName(), qname, tagAttribute.getValue());
 336  
             }
 337  0
             else if (tagAttribute.getNamespace().length() == 0)
 338  
             {
 339  
                 // "... If the current attribute's namespace is empty 
 340  
                 // let the current attribute be convertedTagAttribute. ..."
 341  
                 // -= Leonardo Uribe =- after conversation with Frank Caputo, who was the main contributor for
 342  
                 // this feature in JSF 2.2, he said that if the namespace is empty the intention is pass the
 343  
                 // attribute to the passthrough attribute map, so there is an error in the spec documentation.
 344  
                 //convertedTagAttributes[j] = tagAttribute;
 345  
                 
 346  0
                 convertedNamespace = PASS_THROUGH_NAMESPACE;
 347  0
                 qname = "p:"+tagAttribute.getLocalName();
 348  
                 
 349  0
                 convertedTagAttributes[j] = new TagAttributeImpl(tagAttribute.getLocation(), 
 350  
                     convertedNamespace, tagAttribute.getLocalName(), qname, tagAttribute.getValue());
 351  
             }
 352  
             else /*if (!tag.getNamespace().equals(tagAttribute.getNamespace()))*/
 353  
             {
 354  
                 // "... or different from the argument tag's namespace, 
 355  
                 // let the current attribute be convertedTagAttribute. ..."
 356  0
                 convertedTagAttributes[j] = tagAttribute;
 357  
             }
 358  
             
 359  0
             if (Renderer.PASSTHROUGH_RENDERER_LOCALNAME_KEY.equals(convertedTagAttributes[j].getLocalName()) && (
 360  
                 PASS_THROUGH_NAMESPACE.equals(convertedTagAttributes[j].getNamespace()) || 
 361  
                 PASS_THROUGH_ALIAS_NAMESPACE.equals(convertedTagAttributes[j].getNamespace()) ) )
 362  
             {
 363  0
                 elementNameTagAttributeSet = true;
 364  
             }
 365  0
             j++;
 366  
         }
 367  
         
 368  0
         if (elementNameTagAttributeSet)
 369  
         {
 370  
             // This is unlikely, but theorically possible.
 371  0
             return new TagAttributesImpl(Arrays.copyOf(convertedTagAttributes, convertedTagAttributes.length-1));
 372  
         }
 373  
         else
 374  
         {
 375  0
             convertedTagAttributes[convertedTagAttributes.length-1] = elementNameTagAttribute;
 376  0
             return new TagAttributesImpl(convertedTagAttributes);
 377  
         }
 378  
     }
 379  
     
 380  
     private boolean isLocalNameDecorated(String elem)
 381  
     {
 382  0
         Object[] array = LOCAL_NAME_ARR[elem.charAt(0)];
 383  0
         if (array != null)
 384  
         {
 385  0
             for (int i = array.length - 2; i >= 0; i-=2)
 386  
             {
 387  0
                 if (elem.equalsIgnoreCase((String)array[i]))
 388  
                 {
 389  0
                     return true;
 390  
                 }
 391  
             }
 392  
         }
 393  0
         return false;
 394  
     }
 395  
 
 396  
     private boolean isReservedJSFAttribute(String attr)
 397  
     {
 398  0
         String[] array = RESERVED_JSF_ATTRS_ARR[attr.charAt(0)];
 399  0
         if (array != null)
 400  
         {
 401  0
             for (int i = array.length - 1; i >= 0; i-=1)
 402  
             {
 403  0
                 if (attr.equalsIgnoreCase((String)array[i]))
 404  
                 {
 405  0
                     return true;
 406  
                 }
 407  
             }
 408  
         }
 409  0
         return false;
 410  
     }
 411  
     
 412  
     private static interface TagDecoratorExecutor
 413  
     {
 414  
         public Tag decorate(Tag orig, TagAttributes attributes);
 415  
         
 416  
     }
 417  
     
 418  0
     private static abstract class TagSelector
 419  
     {
 420  
         public abstract TagDecoratorExecutor getExecutorIfApplies(Tag tag);
 421  
     }
 422  
     
 423  0
     private static class TagSelectorImpl extends TagSelector implements TagDecoratorExecutor
 424  
     {
 425  
         //private String selector;
 426  
         private String attributeQName;
 427  
         private String attributeLocalName;
 428  
         private String attributePrefix;
 429  
         private final String attributeNamespace;
 430  
         private final String attributeAliasNamespace;
 431  
         private String matchValue;
 432  
         
 433  
         private String targetQName;
 434  
         private String targetNamespace;
 435  
         private String targetLocalName;
 436  
         
 437  
         public TagSelectorImpl(String selector, String targetQName)
 438  0
         {
 439  
             // The idea in this constructor is do the parsing step of the selector
 440  
             // just once, so the check can be done quickly.
 441  
             //this.selector = selector;
 442  0
             if (selector != null)
 443  
             {
 444  0
                 int i = selector.indexOf('=');
 445  0
                 if (i >= 0)
 446  
                 {
 447  0
                     this.attributeQName = selector.substring(0,i);
 448  0
                     String value = selector.substring(i+1);
 449  0
                     int s = value.indexOf('"');
 450  0
                     int t = value.lastIndexOf('"');
 451  0
                     if (s >= 0 && t >= 0 && t > s)
 452  
                     {
 453  0
                         this.matchValue = value.substring(s+1,t);
 454  
                     }
 455  
                     else
 456  
                     {
 457  0
                         this.matchValue = value;
 458  
                     }
 459  0
                 }
 460  
                 else
 461  
                 {
 462  0
                     this.attributeQName = selector;
 463  0
                     this.matchValue = null;
 464  
                 }
 465  
                 
 466  0
                 int j = attributeQName.indexOf(':');
 467  0
                 this.attributeLocalName = (j >= 0) ? attributeQName.substring(j+1) : attributeQName;
 468  0
                 this.attributePrefix = (j >= 0) ? attributeQName.substring(0, j) : null;
 469  0
                 this.attributeNamespace = resolveSelectorNamespace(this.attributePrefix);
 470  0
                 this.attributeAliasNamespace = resolveAliasSelectorNamespace(this.attributePrefix);
 471  0
             }
 472  
             else
 473  
             {
 474  0
                 this.attributeQName = null;
 475  0
                 this.matchValue = null;
 476  0
                 this.attributeLocalName = null;
 477  0
                 this.attributePrefix = null;
 478  0
                 this.attributeNamespace = "";
 479  0
                 this.attributeAliasNamespace = null;
 480  
             }
 481  
             
 482  0
             this.targetQName = targetQName;
 483  0
             if (targetQName != null)
 484  
             {
 485  0
                 int j = targetQName.indexOf(':');
 486  0
                 if (j >= 0)
 487  
                 {
 488  
                     //this.
 489  0
                     if (j == 1 && targetQName.charAt(0) == 'h')
 490  
                     {
 491  0
                         this.targetNamespace = HtmlLibrary.NAMESPACE;
 492  0
                         this.targetLocalName = targetQName.substring(j+1);
 493  
                     }
 494  0
                     else if (j == 3 && targetQName.startsWith("jsf"))
 495  
                     {
 496  0
                         this.targetNamespace = JsfLibrary.ALIAS_NAMESPACE;
 497  0
                         this.targetLocalName = targetQName.substring(j+1);
 498  
                     }
 499  
                 }
 500  
                 else
 501  
                 {
 502  0
                     this.targetLocalName = targetQName;
 503  
                 }
 504  
             }
 505  0
         }
 506  
 
 507  
         public TagDecoratorExecutor getExecutorIfApplies(Tag tag)
 508  
         {
 509  0
             if (attributeQName != null)
 510  
             {
 511  0
                  if (matchValue != null)
 512  
                  {
 513  0
                      String attributeNS = attributeNamespace;
 514  0
                      TagAttribute attr = tag.getAttributes().get(attributeNS, attributeLocalName);
 515  0
                      if (attr == null && attributeAliasNamespace.length() > 0)
 516  
                      {
 517  0
                          attributeNS = attributeAliasNamespace;
 518  0
                          attr = tag.getAttributes().get(attributeAliasNamespace, attributeLocalName);
 519  
                      }
 520  0
                      if (attr != null)
 521  
                      {
 522  0
                          if (attributeNS.equals(attr.getNamespace()) )
 523  
                          {
 524  
                             // if namespace is the same match
 525  0
                              if (matchValue.equals(attr.getValue()))
 526  
                              {
 527  0
                                 return this;
 528  
                              }
 529  0
                              else if ("*".equals(matchValue) && attr.getValue() != null)
 530  
                              {
 531  0
                                  return this;
 532  
                              }
 533  
                          }
 534  0
                          else if (attributeNS == "" && attr.getNamespace() == null)
 535  
                          {
 536  
                              // if namespace is empty match
 537  0
                              if (matchValue.equals(attr.getValue()))
 538  
                              {
 539  0
                                  return this;
 540  
                              }
 541  0
                              else if ("*".equals(matchValue) && attr.getValue() != null)
 542  
                              {
 543  0
                                  return this;
 544  
                              }
 545  
                          }
 546  
                      }
 547  0
                  }
 548  
                  else
 549  
                  {
 550  0
                      String attributeNS = attributeNamespace;
 551  0
                      TagAttribute attr = tag.getAttributes().get(attributeNS, attributeLocalName);
 552  0
                      if (attr == null)
 553  
                      {
 554  0
                          attributeNS = attributeAliasNamespace;
 555  0
                          attr = tag.getAttributes().get(attributeNS, attributeLocalName);
 556  
                      }
 557  0
                      if (attr != null)
 558  
                      {
 559  0
                          if (attributeNS.equals(attr.getNamespace()))
 560  
                          {
 561  
                              // if namespace is the same match
 562  0
                              return this;
 563  
                          }
 564  0
                          else if (attributeNS == "" && attr.getNamespace() == null)
 565  
                          {
 566  
                              // if namespace is empty match
 567  0
                              return this;
 568  
                          }
 569  
                      }
 570  
                  }
 571  0
                 return null;
 572  
             }
 573  
             else
 574  
             {
 575  0
                 return this;
 576  
             }
 577  
         }
 578  
         
 579  
         public Tag decorate(Tag orig, TagAttributes attributes)
 580  
         {
 581  0
             return new Tag(orig.getLocation(), this.targetNamespace, 
 582  
                 this.targetLocalName, this.targetQName, attributes);
 583  
         }
 584  
     }
 585  
 
 586  
     private static String resolveSelectorNamespace(String prefix)
 587  
     {
 588  0
         if ("jsf".equals(prefix))
 589  
         {
 590  0
             return JsfLibrary.NAMESPACE;
 591  
         }
 592  0
         else if ("h".equals(prefix))
 593  
         {
 594  0
             return HtmlLibrary.NAMESPACE;
 595  
         }
 596  0
         else if ("f".equals(prefix))
 597  
         {
 598  0
             return CoreLibrary.NAMESPACE;
 599  
         }
 600  0
         return "";
 601  
     }
 602  
 
 603  
     private static String resolveAliasSelectorNamespace(String prefix)
 604  
     {
 605  0
         if ("jsf".equals(prefix))
 606  
         {
 607  0
             return JsfLibrary.ALIAS_NAMESPACE;
 608  
         }
 609  0
         else if ("h".equals(prefix))
 610  
         {
 611  0
             return HtmlLibrary.ALIAS_NAMESPACE;
 612  
         }
 613  0
         else if ("f".equals(prefix))
 614  
         {
 615  0
             return CoreLibrary.ALIAS_NAMESPACE;
 616  
         }
 617  0
         return "";
 618  
     }
 619  
 }