Coverage Report - org.apache.myfaces.view.facelets.tag.TagAttributeImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
TagAttributeImpl
0%
0/144
0%
0/132
7.2
 
 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.util.Arrays;
 22  
 
 23  
 import javax.el.ELException;
 24  
 import javax.el.ExpressionFactory;
 25  
 import javax.el.MethodExpression;
 26  
 import javax.el.ValueExpression;
 27  
 import javax.faces.component.UIComponent;
 28  
 import javax.faces.view.Location;
 29  
 import javax.faces.view.facelets.FaceletContext;
 30  
 import javax.faces.view.facelets.TagAttribute;
 31  
 import javax.faces.view.facelets.TagAttributeException;
 32  
 
 33  
 import org.apache.myfaces.util.ExternalSpecifications;
 34  
 import org.apache.myfaces.view.facelets.AbstractFaceletContext;
 35  
 import org.apache.myfaces.view.facelets.el.CompositeComponentELUtils;
 36  
 import org.apache.myfaces.view.facelets.el.ContextAwareTagMethodExpression;
 37  
 import org.apache.myfaces.view.facelets.el.ContextAwareTagValueExpression;
 38  
 import org.apache.myfaces.view.facelets.el.ContextAwareTagValueExpressionUEL;
 39  
 import org.apache.myfaces.view.facelets.el.ELText;
 40  
 import org.apache.myfaces.view.facelets.el.LocationMethodExpression;
 41  
 import org.apache.myfaces.view.facelets.el.LocationValueExpression;
 42  
 import org.apache.myfaces.view.facelets.el.LocationValueExpressionUEL;
 43  
 import org.apache.myfaces.view.facelets.el.ResourceELUtils;
 44  
 import org.apache.myfaces.view.facelets.el.ResourceLocationValueExpression;
 45  
 import org.apache.myfaces.view.facelets.el.ResourceLocationValueExpressionUEL;
 46  
 import org.apache.myfaces.view.facelets.el.TagMethodExpression;
 47  
 import org.apache.myfaces.view.facelets.el.TagValueExpression;
 48  
 import org.apache.myfaces.view.facelets.el.TagValueExpressionUEL;
 49  
 import org.apache.myfaces.view.facelets.el.ValueExpressionMethodExpression;
 50  
 
 51  
 /**
 52  
  * Representation of a Tag's attribute in a Facelet File
 53  
  * 
 54  
  * @author Jacob Hookom
 55  
  * @version $Id$
 56  
  */
 57  
 public final class TagAttributeImpl extends TagAttribute
 58  
 {
 59  
 
 60  
     private final static int EL_LITERAL = 1;
 61  
     
 62  
     private final static int EL_CC = 2;
 63  
     
 64  
     private final static int EL_CC_ATTR_ME = 4;
 65  
     
 66  
     private final static int EL_RESOURCE = 8;
 67  
     
 68  
     private final int capabilities;
 69  
 
 70  
     private final String localName;
 71  
 
 72  
     private final Location location;
 73  
 
 74  
     private final String namespace;
 75  
 
 76  
     private final String qName;
 77  
 
 78  
     private final String value;
 79  
 
 80  
     private String string;
 81  
 
 82  
     /**
 83  
      * This variable is used to cache created expressions using
 84  
      * getValueExpression or getMethodExpression methods. It uses
 85  
      * a racy single check strategy, because if the expression can be
 86  
      * cached the same instance will be built.
 87  
      */
 88  
     private volatile Object[] cachedExpression;
 89  
 
 90  
     public TagAttributeImpl(Location location, String ns, String localName, String qName, String value)
 91  0
     {
 92  
         boolean literal;
 93  
         boolean compositeComponentExpression;
 94  
         boolean compositeComponentAttrMethodExpression;
 95  
         boolean resourceExpression;
 96  0
         this.location = location;
 97  0
         this.namespace = ns;
 98  
         // "xmlns" attribute name can be swallowed by SAX compiler, so we should check if
 99  
         // localName is null or empty and if that so, assign it from the qName 
 100  
         // (if localName is empty it is not prefixed, so it is save to set it directly). 
 101  0
         this.localName = (localName == null) ? qName : ((localName.length() > 0) ? localName : qName);
 102  0
         this.qName = qName;
 103  0
         this.value = value;
 104  
 
 105  
         try
 106  
         {
 107  0
             literal = ELText.isLiteral(this.value);
 108  
         }
 109  0
         catch (ELException e)
 110  
         {
 111  0
             throw new TagAttributeException(this, e);
 112  0
         }
 113  
         
 114  0
         compositeComponentExpression = !literal ? 
 115  
                 CompositeComponentELUtils.isCompositeComponentExpression(this.value) : 
 116  
                     false;
 117  0
         compositeComponentAttrMethodExpression = compositeComponentExpression ? 
 118  
                 CompositeComponentELUtils.isCompositeComponentAttrsMethodExpression(this.value) : 
 119  
                     false;
 120  0
         resourceExpression = !literal ? ResourceELUtils.isResourceExpression(this.value) : false;
 121  
 
 122  0
         this.capabilities = (literal ? EL_LITERAL : 0) | (compositeComponentExpression ? EL_CC : 0) | 
 123  
             (compositeComponentAttrMethodExpression ? EL_CC_ATTR_ME : 0) | ( resourceExpression ? EL_RESOURCE : 0); 
 124  0
     }
 125  
 
 126  
     /**
 127  
      * If literal, return {@link Boolean#getBoolean(java.lang.String) Boolean.getBoolean(java.lang.String)} passing our
 128  
      * value, otherwise call {@link #getObject(FaceletContext, Class) getObject(FaceletContext, Class)}.
 129  
      * 
 130  
      * @see Boolean#getBoolean(java.lang.String)
 131  
      * @see #getObject(FaceletContext, Class)
 132  
      * @param ctx
 133  
      *            FaceletContext to use
 134  
      * @return boolean value
 135  
      */
 136  
     public boolean getBoolean(FaceletContext ctx)
 137  
     {
 138  0
         if ((this.capabilities & EL_LITERAL) != 0)
 139  
         {
 140  0
             return Boolean.valueOf(this.value).booleanValue();
 141  
         }
 142  
         else
 143  
         {
 144  0
             return ((Boolean) this.getObject(ctx, Boolean.class)).booleanValue();
 145  
         }
 146  
     }
 147  
 
 148  
     /**
 149  
      * If literal, call {@link Integer#parseInt(java.lang.String) Integer.parseInt(String)}, otherwise call
 150  
      * {@link #getObject(FaceletContext, Class) getObject(FaceletContext, Class)}.
 151  
      * 
 152  
      * @see Integer#parseInt(java.lang.String)
 153  
      * @see #getObject(FaceletContext, Class)
 154  
      * @param ctx
 155  
      *            FaceletContext to use
 156  
      * @return int value
 157  
      */
 158  
     public int getInt(FaceletContext ctx)
 159  
     {
 160  0
         if ((this.capabilities & EL_LITERAL) != 0)
 161  
         {
 162  0
             return Integer.parseInt(this.value);
 163  
         }
 164  
         else
 165  
         {
 166  0
             return ((Number) this.getObject(ctx, Integer.class)).intValue();
 167  
         }
 168  
     }
 169  
 
 170  
     /**
 171  
      * Local name of this attribute
 172  
      * 
 173  
      * @return local name of this attribute
 174  
      */
 175  
     public String getLocalName()
 176  
     {
 177  0
         return this.localName;
 178  
     }
 179  
 
 180  
     /**
 181  
      * The location of this attribute in the FaceletContext
 182  
      * 
 183  
      * @return the TagAttribute's location
 184  
      */
 185  
     public Location getLocation()
 186  
     {
 187  0
         return this.location;
 188  
     }
 189  
 
 190  
     /**
 191  
      * Create a MethodExpression, using this attribute's value as the expression String.
 192  
      * 
 193  
      * @see ExpressionFactory#createMethodExpression(javax.el.ELContext, java.lang.String, java.lang.Class,
 194  
      *      java.lang.Class[])
 195  
      * @see MethodExpression
 196  
      * @param ctx
 197  
      *            FaceletContext to use
 198  
      * @param type
 199  
      *            expected return type
 200  
      * @param paramTypes
 201  
      *            parameter type
 202  
      * @return a MethodExpression instance
 203  
      */
 204  
     public MethodExpression getMethodExpression(FaceletContext ctx, Class type, Class[] paramTypes)
 205  
     {
 206  0
         AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
 207  
         
 208  
         //volatile reads are atomic, so take the tuple to later comparison.
 209  0
         Object[] localCachedExpression = cachedExpression; 
 210  
         
 211  0
         if (actx.isAllowCacheELExpressions() && localCachedExpression != null &&
 212  
             (localCachedExpression.length % 3 == 0))
 213  
         {
 214  
             //If the expected type and paramTypes are the same return the cached one
 215  0
             for (int i = 0; i < (localCachedExpression.length/3); i++)
 216  
             {
 217  0
                 if ( ((type == null && localCachedExpression[(i*3)] == null ) ||
 218  
                      (type != null && type.equals(localCachedExpression[(i*3)])) ) &&
 219  
                      (Arrays.equals(paramTypes, (Class[]) localCachedExpression[(i*3)+1])) )
 220  
                 {
 221  0
                     if ((this.capabilities & EL_CC) != 0 &&
 222  
                         localCachedExpression[(i*3)+2] instanceof LocationMethodExpression)
 223  
                     {
 224  0
                         UIComponent cc = actx.getFaceletCompositionContext().getCompositeComponentFromStack();
 225  0
                         if (cc != null)
 226  
                         {
 227  0
                             Location location = (Location) cc.getAttributes().get(
 228  
                                     CompositeComponentELUtils.LOCATION_KEY);
 229  0
                             if (location != null)
 230  
                             {
 231  0
                                 return ((LocationMethodExpression)localCachedExpression[(i*3)+2]).apply(
 232  
                                         actx.getFaceletCompositionContext().getCompositeComponentLevel(), location);
 233  
                             }
 234  
                         }
 235  0
                         return ((LocationMethodExpression)localCachedExpression[(i*3)+2]).apply(
 236  
                                 actx.getFaceletCompositionContext().getCompositeComponentLevel());
 237  
                     }
 238  0
                     return (MethodExpression) localCachedExpression[(i*3)+2];
 239  
                 }
 240  
             }
 241  
         }
 242  
         
 243  0
         actx.beforeConstructELExpression();
 244  
         try
 245  
         {
 246  0
             MethodExpression methodExpression = null;
 247  
             
 248  
             // From this point we can suppose this attribute contains a ELExpression
 249  
             // Now we have to check if the expression points to a composite component attribute map
 250  
             // and if so deal with it as an indirection.
 251  
             // NOTE that we have to check if the expression refers to cc.attrs for a MethodExpression
 252  
             // (#{cc.attrs.myMethod}) or only for MethodExpression parameters (#{bean.method(cc.attrs.value)}).
 253  0
             if ((this.capabilities & EL_CC_ATTR_ME) != 0)
 254  
             {
 255  
                 // The MethodExpression is on parent composite component attribute map.
 256  
                 // create a pointer that are referred to the real one that is created in other side
 257  
                 // (see VDL.retargetMethodExpressions for details)
 258  
                 
 259  
                 // check for params in the the MethodExpression
 260  0
                 if (ExternalSpecifications.isUnifiedELAvailable() && this.value.contains("("))
 261  
                 {
 262  
                     // if we don't throw this exception here, another ELException will be
 263  
                     // thrown later, because #{cc.attrs.method(param)} will not work as a
 264  
                     // ValueExpression pointing to a MethodExpression
 265  0
                     throw new ELException("Cannot add parameters to a MethodExpression "
 266  
                             + "pointing to cc.attrs");
 267  
                 }
 268  
                 
 269  0
                 ValueExpression valueExpr = this.getValueExpression(ctx, Object.class);
 270  0
                 methodExpression = new ValueExpressionMethodExpression(valueExpr);
 271  
                 
 272  0
                 if (actx.getFaceletCompositionContext().isWrapTagExceptionsAsContextAware())
 273  
                 {
 274  0
                     methodExpression = new ContextAwareTagMethodExpression(this, methodExpression);
 275  
                 }
 276  
                 else
 277  
                 {
 278  0
                     methodExpression = new TagMethodExpression(this, methodExpression);
 279  
                 }
 280  0
             }
 281  
             else
 282  
             {
 283  0
                 ExpressionFactory f = ctx.getExpressionFactory();
 284  0
                 methodExpression = f.createMethodExpression(ctx, this.value, type, paramTypes);
 285  
 
 286  0
                 if (actx.getFaceletCompositionContext().isWrapTagExceptionsAsContextAware())
 287  
                 {
 288  0
                     methodExpression = new ContextAwareTagMethodExpression(this, methodExpression);
 289  
                 }
 290  
                 else
 291  
                 {
 292  0
                     methodExpression = new TagMethodExpression(this, methodExpression);
 293  
                 }
 294  
 
 295  
                 // if the MethodExpression contains a reference to the current composite
 296  
                 // component, the Location also has to be stored in the MethodExpression 
 297  
                 // to be able to resolve the right composite component (the one that was
 298  
                 // created from the file the Location is pointing to) later.
 299  
                 // (see MYFACES-2561 for details)
 300  0
                 if ((this.capabilities & EL_CC) != 0)
 301  
                 {
 302  0
                     Location currentLocation = getLocation();
 303  0
                     Location ccLocation = (Location) actx.getFaceletCompositionContext().
 304  
                             getCompositeComponentFromStack().getAttributes().get(
 305  
                                     CompositeComponentELUtils.LOCATION_KEY);
 306  0
                     if (ccLocation != null && !ccLocation.getPath().equals(currentLocation.getPath()))
 307  
                     {
 308  
                         // #{cc} from a template called from inside a composite component, disable caching on 
 309  
                         // this expression. The reason is we need to change the Location object used as
 310  
                         // reference as the one in the stack, and that depends on the template hierarchy.
 311  0
                         currentLocation = ccLocation;
 312  
                     }
 313  0
                     methodExpression = new LocationMethodExpression(currentLocation, methodExpression, 
 314  
                             actx.getFaceletCompositionContext().getCompositeComponentLevel());
 315  
                 }
 316  
             }
 317  
             
 318  
                 
 319  0
             if (actx.isAllowCacheELExpressions() && !actx.isAnyFaceletsVariableResolved())
 320  
             {
 321  0
                 if (localCachedExpression != null && (localCachedExpression.length % 3 == 0))
 322  
                 {
 323  
                     // If you use a racy single check, assign
 324  
                     // the volatile variable at the end.
 325  0
                     Object[] array = new Object[localCachedExpression.length+3];
 326  0
                     array[0] = type;
 327  0
                     array[1] = paramTypes;
 328  0
                     array[2] = methodExpression;
 329  0
                     for (int i = 0; i < localCachedExpression.length; i++)
 330  
                     {
 331  0
                         array[i+3] = localCachedExpression[i];
 332  
                     }
 333  0
                     cachedExpression = array;
 334  0
                 }
 335  
                 else
 336  
                 {
 337  0
                     cachedExpression = new Object[]{type, paramTypes, methodExpression};
 338  
                 }
 339  
             }
 340  
 
 341  0
             return methodExpression; 
 342  
         }
 343  0
         catch (Exception e)
 344  
         {
 345  0
             throw new TagAttributeException(this, e);
 346  
         }
 347  
         finally
 348  
         {
 349  0
             actx.afterConstructELExpression();
 350  
         }
 351  
     }
 352  
     
 353  
     /**
 354  
      * The resolved Namespace for this attribute
 355  
      * 
 356  
      * @return resolved Namespace
 357  
      */
 358  
     public String getNamespace()
 359  
     {
 360  0
         return this.namespace;
 361  
     }
 362  
 
 363  
     /**
 364  
      * Delegates to getObject with Object.class as a param
 365  
      * 
 366  
      * @see #getObject(FaceletContext, Class)
 367  
      * @param ctx
 368  
      *            FaceletContext to use
 369  
      * @return Object representation of this attribute's value
 370  
      */
 371  
     public Object getObject(FaceletContext ctx)
 372  
     {
 373  0
         return this.getObject(ctx, Object.class);
 374  
     }
 375  
 
 376  
     /**
 377  
      * The qualified name for this attribute
 378  
      * 
 379  
      * @return the qualified name for this attribute
 380  
      */
 381  
     public String getQName()
 382  
     {
 383  0
         return this.qName;
 384  
     }
 385  
 
 386  
     /**
 387  
      * Return the literal value of this attribute
 388  
      * 
 389  
      * @return literal value
 390  
      */
 391  
     public String getValue()
 392  
     {
 393  0
         return this.value;
 394  
     }
 395  
 
 396  
     /**
 397  
      * If literal, then return our value, otherwise delegate to getObject, passing String.class.
 398  
      * 
 399  
      * @see #getObject(FaceletContext, Class)
 400  
      * @param ctx
 401  
      *            FaceletContext to use
 402  
      * @return String value of this attribute
 403  
      */
 404  
     public String getValue(FaceletContext ctx)
 405  
     {
 406  0
         if ((this.capabilities & EL_LITERAL) != 0)
 407  
         {
 408  0
             return this.value;
 409  
         }
 410  
         else
 411  
         {
 412  0
             return (String) this.getObject(ctx, String.class);
 413  
         }
 414  
     }
 415  
 
 416  
     /**
 417  
      * If literal, simply coerce our String literal value using an ExpressionFactory, otherwise create a ValueExpression
 418  
      * and evaluate it.
 419  
      * 
 420  
      * @see ExpressionFactory#coerceToType(java.lang.Object, java.lang.Class)
 421  
      * @see ExpressionFactory#createValueExpression(javax.el.ELContext, java.lang.String, java.lang.Class)
 422  
      * @see ValueExpression
 423  
      * @param ctx
 424  
      *            FaceletContext to use
 425  
      * @param type
 426  
      *            expected return type
 427  
      * @return Object value of this attribute
 428  
      */
 429  
     public Object getObject(FaceletContext ctx, Class type)
 430  
     {
 431  0
         if ((this.capabilities & EL_LITERAL) != 0)
 432  
         {
 433  0
             if (String.class.equals(type))
 434  
             {
 435  0
                 return this.value;
 436  
             }
 437  
             else
 438  
             {
 439  
                 try
 440  
                 {
 441  0
                     return ctx.getExpressionFactory().coerceToType(this.value, type);
 442  
                 }
 443  0
                 catch (Exception e)
 444  
                 {
 445  0
                     throw new TagAttributeException(this, e);
 446  
                 }
 447  
             }
 448  
         }
 449  
         else
 450  
         {
 451  0
             ValueExpression ve = this.getValueExpression(ctx, type);
 452  
             try
 453  
             {
 454  0
                 return ve.getValue(ctx);
 455  
             }
 456  0
             catch (Exception e)
 457  
             {
 458  0
                 throw new TagAttributeException(this, e);
 459  
             }
 460  
         }
 461  
     }
 462  
 
 463  
     /**
 464  
      * Create a ValueExpression, using this attribute's literal value and the passed expected type.
 465  
      * 
 466  
      * @see ExpressionFactory#createValueExpression(javax.el.ELContext, java.lang.String, java.lang.Class)
 467  
      * @see ValueExpression
 468  
      * @param ctx
 469  
      *            FaceletContext to use
 470  
      * @param type
 471  
      *            expected return type
 472  
      * @return ValueExpression instance
 473  
      */
 474  
     public ValueExpression getValueExpression(FaceletContext ctx, Class type)
 475  
     {
 476  0
         AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
 477  
         
 478  
         //volatile reads are atomic, so take the tuple to later comparison.
 479  0
         Object[] localCachedExpression = cachedExpression;
 480  0
         if (actx.isAllowCacheELExpressions() && localCachedExpression != null && localCachedExpression.length == 2)
 481  
         {
 482  
             //If the expected type is the same return the cached one
 483  0
             if (localCachedExpression[0] == null && type == null)
 484  
             {
 485  
                 // If #{cc} recalculate the composite component level
 486  0
                 if ((this.capabilities & EL_CC) != 0)
 487  
                 {
 488  0
                     UIComponent cc = actx.getFaceletCompositionContext().getCompositeComponentFromStack();
 489  0
                     if (cc != null)
 490  
                     {
 491  0
                         Location location = (Location) cc.getAttributes().get(
 492  
                                 CompositeComponentELUtils.LOCATION_KEY);
 493  0
                         if (location != null)
 494  
                         {
 495  0
                             return ((LocationValueExpression)localCachedExpression[1]).apply(
 496  
                                     actx.getFaceletCompositionContext().getCompositeComponentLevel(), location);
 497  
                         }
 498  
                     }
 499  0
                     return ((LocationValueExpression)localCachedExpression[1]).apply(
 500  
                             actx.getFaceletCompositionContext().getCompositeComponentLevel());
 501  
                 }
 502  0
                 return (ValueExpression) localCachedExpression[1];
 503  
             }
 504  0
             else if (localCachedExpression[0] != null && localCachedExpression[0].equals(type))
 505  
             {
 506  
                 // If #{cc} recalculate the composite component level
 507  0
                 if ((this.capabilities & EL_CC) != 0)
 508  
                 {
 509  0
                     UIComponent cc = actx.getFaceletCompositionContext().getCompositeComponentFromStack();
 510  0
                     if (cc != null)
 511  
                     {
 512  0
                         Location location = (Location) cc.getAttributes().get(
 513  
                                 CompositeComponentELUtils.LOCATION_KEY);
 514  0
                         if (location != null)
 515  
                         {
 516  0
                             return ((LocationValueExpression)localCachedExpression[1]).apply(
 517  
                                     actx.getFaceletCompositionContext().getCompositeComponentLevel(), location);
 518  
                         }
 519  
                     }
 520  0
                     return ((LocationValueExpression)localCachedExpression[1]).apply(
 521  
                             actx.getFaceletCompositionContext().getCompositeComponentLevel());
 522  
                 }
 523  0
                 return (ValueExpression) localCachedExpression[1];
 524  
             }
 525  
         }
 526  
 
 527  0
         actx.beforeConstructELExpression();
 528  
         try
 529  
         {
 530  0
             ExpressionFactory f = ctx.getExpressionFactory();
 531  0
             ValueExpression valueExpression = f.createValueExpression(ctx, this.value, type);
 532  
             
 533  0
             if (ExternalSpecifications.isUnifiedELAvailable())
 534  
             {
 535  0
                 if (actx.getFaceletCompositionContext().isWrapTagExceptionsAsContextAware())
 536  
                 {
 537  0
                     valueExpression = new ContextAwareTagValueExpressionUEL(this, valueExpression);
 538  
                 }
 539  
                 else
 540  
                 {
 541  0
                     valueExpression = new TagValueExpressionUEL(this, valueExpression);
 542  
                 }
 543  
             }
 544  
             else
 545  
             {
 546  0
                 if (actx.getFaceletCompositionContext().isWrapTagExceptionsAsContextAware())
 547  
                 {
 548  0
                     valueExpression = new ContextAwareTagValueExpression(this, valueExpression);
 549  
                 }
 550  
                 else
 551  
                 {
 552  0
                     valueExpression = new TagValueExpression(this, valueExpression);
 553  
                 }
 554  
             }
 555  
 
 556  
             // if the ValueExpression contains a reference to the current composite
 557  
             // component, the Location also has to be stored in the ValueExpression 
 558  
             // to be able to resolve the right composite component (the one that was
 559  
             // created from the file the Location is pointing to) later.
 560  
             // (see MYFACES-2561 for details)
 561  0
             if ((this.capabilities & EL_CC) != 0)
 562  
             {
 563  
                 // In MYFACES-4099 it was found that #{cc} could happen outside a composite component. In that
 564  
                 // case, getLocation() will point to the template. To solve the problem, it is better to get
 565  
                 // the location of the composite component from the stack directly, but only when the path
 566  
                 // is different.
 567  0
                 Location currentLocation = getLocation();
 568  0
                 Location ccLocation = (Location) actx.getFaceletCompositionContext().
 569  
                         getCompositeComponentFromStack().getAttributes().get(
 570  
                                 CompositeComponentELUtils.LOCATION_KEY);
 571  0
                 if (ccLocation != null && !ccLocation.getPath().equals(currentLocation.getPath()))
 572  
                 {
 573  
                     // #{cc} from a template called from inside a composite component, disable caching on 
 574  
                     // this expression. The reason is we need to change the Location object used as
 575  
                     // reference as the one in the stack, and that depends on the template hierarchy.
 576  
                     //cacheable = false;
 577  0
                     currentLocation = ccLocation;
 578  
                 }
 579  0
                 if (ExternalSpecifications.isUnifiedELAvailable())
 580  
                 {
 581  0
                     valueExpression = new LocationValueExpressionUEL(currentLocation, valueExpression, 
 582  
                             actx.getFaceletCompositionContext().getCompositeComponentLevel());
 583  
                 }
 584  
                 else
 585  
                 {
 586  0
                     valueExpression = new LocationValueExpression(currentLocation, valueExpression, 
 587  
                             actx.getFaceletCompositionContext().getCompositeComponentLevel());
 588  
                 }
 589  0
             }
 590  0
             else if ((this.capabilities & EL_RESOURCE) != 0)
 591  
             {
 592  0
                 if (ExternalSpecifications.isUnifiedELAvailable())
 593  
                 {
 594  0
                     valueExpression = new ResourceLocationValueExpressionUEL(getLocation(), valueExpression);
 595  
                 }
 596  
                 else
 597  
                 {
 598  0
                     valueExpression = new ResourceLocationValueExpression(getLocation(), valueExpression);
 599  
                 }
 600  
             }
 601  
             
 602  
             
 603  0
             if (actx.isAllowCacheELExpressions() && !actx.isAnyFaceletsVariableResolved())
 604  
             {
 605  0
                 cachedExpression = new Object[]{type, valueExpression};
 606  
             }
 607  0
             return valueExpression;
 608  
         }
 609  0
         catch (Exception e)
 610  
         {
 611  0
             throw new TagAttributeException(this, e);
 612  
         }
 613  
         finally
 614  
         {
 615  0
             actx.afterConstructELExpression();
 616  
         }
 617  
     }
 618  
 
 619  
     /**
 620  
      * If this TagAttribute is literal (not #{..} or ${..})
 621  
      * 
 622  
      * @return true if this attribute is literal
 623  
      */
 624  
     public boolean isLiteral()
 625  
     {
 626  0
         return (this.capabilities & EL_LITERAL) != 0;
 627  
     }
 628  
 
 629  
     /*
 630  
      * (non-Javadoc)
 631  
      * 
 632  
      * @see java.lang.Object#toString()
 633  
      */
 634  
     public String toString()
 635  
     {
 636  0
         if (this.string == null)
 637  
         {
 638  0
             this.string = this.location + " " + this.qName + "=\"" + this.value + "\"";
 639  
         }
 640  0
         return this.string;
 641  
     }
 642  
 
 643  
 }