Coverage Report - org.apache.myfaces.view.facelets.el.CompositeComponentELUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
CompositeComponentELUtils
0%
0/131
0%
0/120
8.455
 
 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.el;
 20  
 
 21  
 import java.util.ArrayList;
 22  
 import java.util.List;
 23  
 import java.util.regex.Pattern;
 24  
 
 25  
 import javax.faces.component.UIComponent;
 26  
 import javax.faces.context.FacesContext;
 27  
 import javax.faces.view.Location;
 28  
 
 29  
 /**
 30  
  * Utility class for composite components when used in EL Expressions --> #{cc}
 31  
  * 
 32  
  * @author Jakob Korherr (latest modification by $Author$)
 33  
  * @version $Revision$ $Date$
 34  
  */
 35  
 public final class CompositeComponentELUtils
 36  
 {
 37  
     
 38  
     /**
 39  
      * The key under which the component stack is stored in the FacesContext.
 40  
      * ATTENTION: this constant is duplicate in UIComponent.
 41  
      */
 42  
     //public static final String COMPONENT_STACK = "componentStack:" + UIComponent.class.getName();
 43  
     
 44  
     /**
 45  
      * The key under which the current composite component is stored in the attribute
 46  
      * map of the FacesContext.
 47  
      */
 48  
     public static final String CURRENT_COMPOSITE_COMPONENT_KEY = "org.apache.myfaces.compositecomponent.current";
 49  
     
 50  
     /**
 51  
      * The key under which the Location of the composite componente is stored
 52  
      * in the attributes map of the component by InterfaceHandler.
 53  
      */
 54  
     public static final String LOCATION_KEY = "org.apache.myfaces.compositecomponent.location";
 55  
 
 56  
     /**
 57  
      * Indicates the nesting level where the composite component was created, working as reference
 58  
      * point to all EL expressions created in that point from Facelets engine.
 59  
      */
 60  
     public static final String LEVEL_KEY = "oam.cc.ccLevel";
 61  
     
 62  
     /**
 63  
      * A regular expression used to determine if cc is used in an expression String.
 64  
      */
 65  0
     public static final Pattern CC_EXPRESSION_REGEX = Pattern.compile(".*[^\\w\\.]cc[^\\w].*");
 66  
     
 67  
     /**
 68  
      * A regular expression used to determine if cc.attrs is used as a method expression
 69  
      * in an expression String. This means cc.attrs must occur, must stand before a '(',
 70  
      * because otherwise it would be a method parameter (EL 2.2), and there must be no '.' after
 71  
      * cc.attrs unless there is a left parenthesis before it (e.g. #{cc.attrs.method(bean.parameter)}).
 72  
      * 
 73  
      * Explanation of the parts:
 74  
      * - [^\\(]* - There can be any character except a '(' before cc.attrs
 75  
      * - [^\\w\\.\\(] - There must be no word character, dot, or left parenthesis directly before cc.attrs
 76  
      * - cc\\.attrs\\. - "cc.attrs." must occur
 77  
      * - [^\\.]* - There must be no dot after cc.attrs to indicate a method invocation on cc.attrs
 78  
      * - (\\(.*)? - If there is a left paranthesis after cc.attrs, a dot is allowed again
 79  
      */
 80  0
     public static final Pattern CC_ATTRS_METHOD_EXPRESSION_REGEX
 81  
             = Pattern.compile("[^\\(]*[^\\w\\.\\(]cc\\.attrs\\.[^\\.]*(\\(.*)?");
 82  
     
 83  
     private static final String CC = "cc";
 84  
     
 85  
     private static final String CC_ATTRS = "cc.attrs";
 86  
     
 87  
     public static final String CC_FIND_COMPONENT_EXPRESSION = "oam.CC_FIND_COMPONENT_EXPRESSION";
 88  
     
 89  
     /**
 90  
      * private constructor
 91  
      */
 92  
     private CompositeComponentELUtils()
 93  0
     {
 94  
         // no instantiation of this class
 95  0
     }
 96  
     
 97  
     /**
 98  
      * Try to find a composite component on the composite component stack
 99  
      * and using UIComponent.getCurrentCompositeComponent() based on the 
 100  
      * location of the facelet page that generated the composite component.
 101  
      * @param facesContext
 102  
      * @param location
 103  
      * @return
 104  
      */
 105  
     public static UIComponent getCompositeComponentBasedOnLocation(final FacesContext facesContext, 
 106  
             final Location location)
 107  
     {
 108  
         //1 Use getCurrentComponent and getCurrentCompositeComponent to look on the component stack
 109  0
         UIComponent currentCompositeComponent = UIComponent.getCurrentCompositeComponent(facesContext);
 110  
         
 111  
         //1.1 Use getCurrentCompositeComponent first!
 112  0
         if (currentCompositeComponent != null)
 113  
         {
 114  0
             Location componentLocation = (Location) currentCompositeComponent.getAttributes().get(LOCATION_KEY);
 115  0
             if (componentLocation != null 
 116  
                     && componentLocation.getPath().equals(location.getPath()))
 117  
             {
 118  0
                 return currentCompositeComponent;
 119  
             }
 120  
         }
 121  
 
 122  0
         UIComponent currentComponent = UIComponent.getCurrentComponent(facesContext);
 123  
         
 124  0
         if (currentComponent == null)
 125  
         {
 126  
             // Cannot found any component, because we don't have any reference!
 127  0
             return null;
 128  
         }
 129  
 
 130  
         //2. Look on the stack using a recursive algorithm.
 131  0
         UIComponent matchingCompositeComponent
 132  
                 = lookForCompositeComponentOnStack(facesContext, location, currentComponent);
 133  
         
 134  0
         if (matchingCompositeComponent != null)
 135  
         {
 136  0
             return matchingCompositeComponent;
 137  
         }
 138  
         
 139  
         //2. Try to find it using UIComponent.getCurrentCompositeComponent(). 
 140  
         // This one will look the direct parent hierarchy of the component,
 141  
         // to see if the composite component can be found.
 142  0
         if (currentCompositeComponent != null)
 143  
         {
 144  0
             currentComponent = currentCompositeComponent;
 145  
         }
 146  
         else
 147  
         {
 148  
             //Try to find the composite component looking directly the parent
 149  
             //ancestor of the current component
 150  
             //currentComponent = UIComponent.getCurrentComponent(facesContext);
 151  0
             boolean found = false;
 152  0
             while (currentComponent != null && !found)
 153  
             {
 154  0
                 String findComponentExpr = (String) currentComponent.getAttributes().get(CC_FIND_COMPONENT_EXPRESSION);
 155  0
                 if (findComponentExpr != null)
 156  
                 {
 157  0
                     UIComponent foundComponent = facesContext.getViewRoot().findComponent(findComponentExpr);
 158  0
                     if (foundComponent != null)
 159  
                     {
 160  0
                         Location foundComponentLocation = (Location) currentComponent.getAttributes().get(LOCATION_KEY);
 161  0
                         if (foundComponentLocation != null 
 162  
                                 && foundComponentLocation.getPath().equals(location.getPath()))
 163  
                         {
 164  0
                             return foundComponent;
 165  
                         }
 166  
                         else
 167  
                         {
 168  0
                             while (foundComponent != null)
 169  
                             {
 170  0
                                 Location componentLocation
 171  
                                         = (Location) foundComponent.getAttributes().get(LOCATION_KEY);
 172  0
                                 if (componentLocation != null 
 173  
                                         && componentLocation.getPath().equals(location.getPath()))
 174  
                                 {
 175  0
                                     return foundComponent;
 176  
                                 }
 177  
                                 // get the composite component's parent
 178  0
                                 foundComponent = UIComponent.getCompositeComponentParent(foundComponent);
 179  0
                             }
 180  
                         }
 181  
                     }
 182  
                 }
 183  
 
 184  0
                 if (UIComponent.isCompositeComponent(currentComponent))
 185  
                 {
 186  0
                     found = true;
 187  
                 }
 188  
                 else
 189  
                 {
 190  0
                     currentComponent = currentComponent.getParent();
 191  
                 }
 192  0
             }
 193  
         }
 194  
         
 195  
         //if currentComponent != null means we have a composite component that we can check
 196  
         //Use UIComponent.getCompositeComponentParent() to traverse here.
 197  0
         while (currentComponent != null)
 198  
         {
 199  0
             Location componentLocation = (Location) currentComponent.getAttributes().get(LOCATION_KEY);
 200  0
             if (componentLocation != null 
 201  
                     && componentLocation.getPath().equals(location.getPath()))
 202  
             {
 203  0
                 return currentComponent;
 204  
             }
 205  
             // get the composite component's parent
 206  0
             currentComponent = UIComponent.getCompositeComponentParent(currentComponent);
 207  0
         }
 208  
         
 209  
         // not found
 210  0
         return null;
 211  
     }
 212  
     
 213  
     private static UIComponent lookForCompositeComponentOnStack(final FacesContext facesContext,
 214  
                                                                 final Location location,
 215  
                                                                 UIComponent currentComponent)
 216  
     {
 217  0
         if (UIComponent.isCompositeComponent(currentComponent))
 218  
         {
 219  0
             Location componentLocation = (Location) currentComponent.getAttributes().get(LOCATION_KEY);
 220  0
             if (componentLocation != null 
 221  
                     && componentLocation.getPath().equals(location.getPath()))
 222  
             {
 223  0
                 return currentComponent;
 224  
             }
 225  
         }
 226  0
         currentComponent.popComponentFromEL(facesContext);
 227  
         try
 228  
         {
 229  0
             UIComponent c = UIComponent.getCurrentComponent(facesContext);
 230  0
             if (c != null)
 231  
             {
 232  0
                 return lookForCompositeComponentOnStack( facesContext, location, c);
 233  
             }
 234  
             else
 235  
             {
 236  0
                 return null;
 237  
             }
 238  
         }
 239  
         finally
 240  
         {
 241  0
             currentComponent.pushComponentToEL(facesContext, currentComponent);
 242  
         }
 243  
     }
 244  
 
 245  
     private static int getCCLevel(UIComponent component)
 246  
     {
 247  0
         Integer ccLevel = (Integer) component.getAttributes().get(LEVEL_KEY);
 248  0
         if (ccLevel == null)
 249  
         {
 250  0
             return 0;
 251  
         }
 252  0
         return ccLevel.intValue();
 253  
     }
 254  
     
 255  
     public static UIComponent getCompositeComponentBasedOnLocation(final FacesContext facesContext, 
 256  
             UIComponent baseComponent, final Location location)
 257  
     {
 258  0
         UIComponent currentComponent = baseComponent;
 259  0
         while (currentComponent != null)
 260  
         {
 261  0
             Location componentLocation = (Location) currentComponent.getAttributes().get(
 262  
                 LOCATION_KEY);
 263  0
             if (componentLocation != null 
 264  
                     && componentLocation.getPath().equals(location.getPath()))
 265  
             {
 266  0
                 return currentComponent;
 267  
             }
 268  
             // get the composite component's parent
 269  0
             currentComponent = UIComponent.getCompositeComponentParent(currentComponent);
 270  0
         }
 271  0
         return null;
 272  
     }
 273  
 
 274  
     
 275  
     /**
 276  
      * Same as getCompositeComponentBasedOnLocation(final FacesContext facesContext, final Location location),
 277  
      * but takes into account the ccLevel to resolve the composite component. 
 278  
      * 
 279  
      * @param facesContext
 280  
      * @param location
 281  
      * @param ccLevel
 282  
      * @return 
 283  
      */
 284  
     public static UIComponent getCompositeComponentBasedOnLocation(final FacesContext facesContext, 
 285  
             final Location location, int ccLevel)
 286  
     {
 287  
         //1 Use getCurrentComponent and getCurrentCompositeComponent to look on the component stack
 288  0
         UIComponent currentCompositeComponent = UIComponent.getCurrentCompositeComponent(facesContext);
 289  
         
 290  
         //1.1 Use getCurrentCompositeComponent first!
 291  0
         if (currentCompositeComponent != null)
 292  
         {
 293  0
             Location componentLocation = (Location) currentCompositeComponent.getAttributes().get(LOCATION_KEY);
 294  0
             if (componentLocation != null 
 295  
                     && componentLocation.getPath().equals(location.getPath()) && 
 296  
                     (ccLevel == getCCLevel(currentCompositeComponent)) )
 297  
             {
 298  0
                 return currentCompositeComponent;
 299  
             }
 300  
         }
 301  
 
 302  0
         UIComponent currentComponent = UIComponent.getCurrentComponent(facesContext);
 303  
         
 304  0
         if (currentComponent == null)
 305  
         {
 306  
             // Cannot found any component, because we don't have any reference!
 307  0
             return null;
 308  
         }
 309  
         
 310  
         //2. Look on the stack using a recursive algorithm.
 311  0
         UIComponent matchingCompositeComponent
 312  
                 = lookForCompositeComponentOnStack(facesContext, location, ccLevel, currentComponent);
 313  
         
 314  0
         if (matchingCompositeComponent != null)
 315  
         {
 316  0
             return matchingCompositeComponent;
 317  
         }
 318  
         
 319  
         //2. Try to find it using UIComponent.getCurrentCompositeComponent(). 
 320  
         // This one will look the direct parent hierarchy of the component,
 321  
         // to see if the composite component can be found.
 322  0
         if (currentCompositeComponent != null)
 323  
         {
 324  0
             currentComponent = currentCompositeComponent;
 325  
         }
 326  
         else
 327  
         {
 328  
             //Try to find the composite component looking directly the parent
 329  
             //ancestor of the current component
 330  
             //currentComponent = UIComponent.getCurrentComponent(facesContext);
 331  0
             boolean found = false;
 332  0
             while (currentComponent != null && !found)
 333  
             {
 334  0
                 String findComponentExpr = (String) currentComponent.getAttributes().get(CC_FIND_COMPONENT_EXPRESSION);
 335  0
                 if (findComponentExpr != null)
 336  
                 {
 337  0
                     UIComponent foundComponent = facesContext.getViewRoot().findComponent(findComponentExpr);
 338  0
                     if (foundComponent != null)
 339  
                     {
 340  0
                         Location foundComponentLocation = (Location) currentComponent.getAttributes().get(LOCATION_KEY);
 341  0
                         if (foundComponentLocation != null 
 342  
                                 && foundComponentLocation.getPath().equals(location.getPath()) &&
 343  
                                 ccLevel == getCCLevel(foundComponent))
 344  
                         {
 345  0
                             return foundComponent;
 346  
                         }
 347  
                         else
 348  
                         {
 349  0
                             while (foundComponent != null)
 350  
                             {
 351  0
                                 Location componentLocation
 352  
                                         = (Location) foundComponent.getAttributes().get(LOCATION_KEY);
 353  0
                                 if (componentLocation != null 
 354  
                                         && componentLocation.getPath().equals(location.getPath()) &&
 355  
                                         ccLevel == getCCLevel(foundComponent))
 356  
                                 {
 357  0
                                     return foundComponent;
 358  
                                 }
 359  
                                 // get the composite component's parent
 360  0
                                 foundComponent = UIComponent.getCompositeComponentParent(foundComponent);
 361  0
                             }
 362  
                         }
 363  
                     }
 364  
                 }
 365  
 
 366  0
                 if (UIComponent.isCompositeComponent(currentComponent))
 367  
                 {
 368  0
                     found = true;
 369  
                 }
 370  
                 else
 371  
                 {
 372  0
                     currentComponent = currentComponent.getParent();
 373  
                 }
 374  0
             }
 375  
         }
 376  
         
 377  
         //if currentComponent != null means we have a composite component that we can check
 378  
         //Use UIComponent.getCompositeComponentParent() to traverse here.
 379  0
         while (currentComponent != null)
 380  
         {
 381  0
             Location componentLocation = (Location) currentComponent.getAttributes().get(LOCATION_KEY);
 382  0
             if (componentLocation != null 
 383  
                     && componentLocation.getPath().equals(location.getPath()) &&
 384  
                     ccLevel == getCCLevel(currentComponent))
 385  
             {
 386  0
                 return currentComponent;
 387  
             }
 388  
             // get the composite component's parent
 389  0
             currentComponent = UIComponent.getCompositeComponentParent(currentComponent);
 390  0
         }
 391  
         
 392  
         // not found
 393  0
         return null;
 394  
     }
 395  
 
 396  
     private static UIComponent lookForCompositeComponentOnStack(final FacesContext facesContext,
 397  
                                                                 final Location location, int ccLevel,
 398  
                                                                 UIComponent currentComponent)
 399  
     {
 400  0
         if (UIComponent.isCompositeComponent(currentComponent))
 401  
         {
 402  0
             Location componentLocation = (Location) currentComponent.getAttributes().get(LOCATION_KEY);
 403  0
             if (componentLocation != null 
 404  
                     && componentLocation.getPath().equals(location.getPath()) &&
 405  
                     (ccLevel == getCCLevel(currentComponent)) )
 406  
             {
 407  0
                 return currentComponent;
 408  
             }
 409  
         }
 410  0
         currentComponent.popComponentFromEL(facesContext);
 411  
         try
 412  
         {
 413  0
             UIComponent c = UIComponent.getCurrentComponent(facesContext);
 414  0
             if (c != null)
 415  
             {
 416  0
                 return lookForCompositeComponentOnStack( facesContext, location, ccLevel, c);
 417  
             }
 418  
             else
 419  
             {
 420  0
                 return null;
 421  
             }
 422  
         }
 423  
         finally
 424  
         {
 425  0
             currentComponent.pushComponentToEL(facesContext, currentComponent);
 426  
         }
 427  
     }
 428  
     
 429  
     /**
 430  
      * Trys to get the composite component using getCompositeComponentBasedOnLocation()
 431  
      * and saves it in an attribute on the FacesContext, which is then used by 
 432  
      * CompositeComponentImplicitObject.
 433  
      * @param facesContext
 434  
      * @param location
 435  
      */
 436  
     public static void saveCompositeComponentForResolver(FacesContext facesContext, Location location, int ccLevel)
 437  
     {
 438  0
         UIComponent cc = ccLevel > 0 ? getCompositeComponentBasedOnLocation(facesContext, location, ccLevel)
 439  
                 : getCompositeComponentBasedOnLocation(facesContext, location);
 440  0
         List<UIComponent> list = (List<UIComponent>) facesContext.getAttributes().get(CURRENT_COMPOSITE_COMPONENT_KEY);
 441  0
         if (list == null)
 442  
         {
 443  0
             list = new ArrayList<UIComponent>();
 444  0
             facesContext.getAttributes().put(CURRENT_COMPOSITE_COMPONENT_KEY, list);
 445  
         }
 446  0
         list.add(cc);
 447  0
     }
 448  
     
 449  
     /**
 450  
      * Removes the composite component from the attribute map of the FacesContext.
 451  
      * @param facesContext
 452  
      */
 453  
     public static void removeCompositeComponentForResolver(FacesContext facesContext)
 454  
     {
 455  0
         List<UIComponent> list = (List<UIComponent>) facesContext.getAttributes().get(CURRENT_COMPOSITE_COMPONENT_KEY);
 456  0
         if (list != null)
 457  
         {
 458  0
             list.remove(list.size()-1);
 459  
         }
 460  0
     }
 461  
     
 462  
     /**
 463  
      * Tests if the expression refers to the current composite component: #{cc}
 464  
      * @return
 465  
      */
 466  
     public static boolean isCompositeComponentExpression(String expression)
 467  
     {
 468  0
         if (expression.contains(CC))
 469  
         {
 470  0
             return CC_EXPRESSION_REGEX.matcher(expression).matches();
 471  
         }
 472  
         else
 473  
         {
 474  0
             return false;
 475  
         }
 476  
     }
 477  
     
 478  
     /**
 479  
      * Tests if cc.attrs is used as a method expression in an expression String. This means 
 480  
      * cc.attrs must occur, must stand before a '(', because otherwise it would be a method parameter 
 481  
      * (EL 2.2), and there must be no '.' after cc.attrs unless there is a left parenthesis
 482  
      * before it (e.g. #{cc.attrs.method(bean.parameter)}).
 483  
      * @param expression
 484  
      * @return
 485  
      */
 486  
     public static boolean isCompositeComponentAttrsMethodExpression(String expression)
 487  
     {
 488  0
         if (expression.contains(CC_ATTRS))
 489  
         {
 490  0
             return CC_ATTRS_METHOD_EXPRESSION_REGEX.matcher(expression).matches();
 491  
         }
 492  
         else
 493  
         {
 494  0
             return false;
 495  
         }
 496  
     }
 497  
     
 498  
 }