* parameter type
* @return a MethodExpression instance
*/
public MethodExpression getMethodExpression(FaceletContext ctx, Class type, Class[] paramTypes)
{
AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
//volatile reads are atomic, so take the tuple to later comparison.
Object[] localCachedExpression = cachedExpression;
if (actx.isAllowCacheELExpressions() && localCachedExpression != null &&
(localCachedExpression.length % 3 == 0))
{
//If the expected type and paramTypes are the same return the cached one
for (int i = 0; i < (localCachedExpression.length/3); i++)
{
if ( ((type == null && localCachedExpression[(i*3)] == null ) ||
(type != null && type.equals(localCachedExpression[(i*3)])) ) &&
(Arrays.equals(paramTypes, (Class[]) localCachedExpression[(i*3)+1])) )
{
return (MethodExpression) localCachedExpression[(i*3)+2];
}
}
}
actx.beforeConstructELExpression();
try
{
MethodExpression methodExpression = null;
// From this point we can suppose this attribute contains a ELExpression
// Now we have to check if the expression points to a composite component attribute map
// and if so deal with it as an indirection.
// NOTE that we have to check if the expression refers to cc.attrs for a MethodExpression
// (#{cc.attrs.myMethod}) or only for MethodExpression parameters (#{bean.method(cc.attrs.value)}).
if ((this.capabilities & EL_CC_ATTR_ME) != 0)
{
// The MethodExpression is on parent composite component attribute map.
// create a pointer that are referred to the real one that is created in other side
// (see VDL.retargetMethodExpressions for details)
// check for params in the the MethodExpression
if (ExternalSpecifications.isUnifiedELAvailable() && this.value.contains("("))
{
// if we don't throw this exception here, another ELException will be
// thrown later, because #{cc.attrs.method(param)} will not work as a
// ValueExpression pointing to a MethodExpression
throw new ELException("Cannot add parameters to a MethodExpression "
+ "pointing to cc.attrs");
}
ValueExpression valueExpr = this.getValueExpression(ctx, Object.class);
methodExpression = new ValueExpressionMethodExpression(valueExpr);
}
else
{
ExpressionFactory f = ctx.getExpressionFactory();
methodExpression = f.createMethodExpression(ctx, this.value, type, paramTypes);
// if the MethodExpression contains a reference to the current composite
// component, the Location also has to be stored in the MethodExpression
// to be able to resolve the right composite component (the one that was
// created from the file the Location is pointing to) later.
// (see MYFACES-2561 for details)
if ((this.capabilities & EL_CC) != 0)
{
methodExpression = new LocationMethodExpression(getLocation(), methodExpression);
}
}
if (actx.getFaceletCompositionContext().isWrapTagExceptionsAsContextAware())
{
methodExpression = new ContextAwareTagMethodExpression(this, methodExpression);
}
else
{
methodExpression = new TagMethodExpression(this, methodExpression);
}
if (actx.isAllowCacheELExpressions() && !actx.isAnyFaceletsVariableResolved())
{
if (localCachedExpression != null && (localCachedExpression.length % 3 == 0))
{
// If you use a racy single check, assign
// the volatile variable at the end.
Object[] array = new Object[localCachedExpression.length+3];
array[0] = type;
array[1] = paramTypes;
array[2] = methodExpression;
for (int i = 0; i < localCachedExpression.length; i++)
{
array[i+3] = localCachedExpression[i];
}
cachedExpression = array;
}
else
{
cachedExpression = new Object[]{type, paramTypes, methodExpression};
}
}
return methodExpression;
}
catch (Exception e)
{
throw new TagAttributeException(this, e);
}
finally
{
actx.afterConstructELExpression();
}
}