in impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionHandlerImpl.java [369:573]
public void invokeOnComponent(final SearchExpressionContext searchExpressionContext,
UIComponent previous, String topExpression, final ContextCallback topCallback)
{
if (topExpression == null)
{
topExpression = "";
}
else
{
topExpression = topExpression.trim();
}
// Command pattern to apply the keyword or command to the base and then invoke the callback
FacesContext facesContext = searchExpressionContext.getFacesContext();
SearchExpressionHandler handler = facesContext.getApplication().getSearchExpressionHandler();
//Step 1: find base
// Case ':' (root)
char separatorChar = facesContext.getNamingContainerSeparatorChar();
if (topExpression.charAt(0) == separatorChar)
{
UIComponent findBase = ComponentUtils.findRootComponent(previous);
handler.invokeOnComponent(searchExpressionContext, findBase, topExpression.substring(1), topCallback);
return;
}
//Step 2: Once you have a base where you can start, apply an expression
if (topExpression.charAt(0) == KEYWORD_PREFIX.charAt(0))
{
// A keyword means apply a command over the current source using an expression and the result must be
// feedback into the algorithm.
String command = extractKeyword(topExpression, 1, separatorChar);
final String remaining =
command.length()+1 < topExpression.length() ?
topExpression.substring(1+command.length()+1) : null;
// If the keyword is @child, @composite, @form, @namingcontainer, @next, @none, @parent, @previous,
// @root, @this , all commands change the source to be applied the action
if (remaining != null)
{
if (facesContext.getApplication().getSearchKeywordResolver().isLeaf(searchExpressionContext, command))
{
throw new FacesException("Expression cannot have keywords or ids at the right side: "+command);
}
this.applyKeyword(searchExpressionContext, previous, command, remaining, new ContextCallback()
{
@Override
public void invokeContextCallback(FacesContext facesContext, UIComponent target)
{
handler.invokeOnComponent(
searchExpressionContext, target, remaining, topCallback);
}
});
}
else
{
// Command completed, apply parent callback
this.applyKeyword(searchExpressionContext, previous, command, null, topCallback);
}
}
else
{
//Split expression into tokens and apply loop
String nextExpression = null;
String expression;
if (topExpression.indexOf(":@") > 0)
{
int idx = topExpression.indexOf(":@");
nextExpression = topExpression.substring(idx+1);
expression = topExpression.substring(0, idx);
}
else
{
expression = topExpression;
}
// Use findComponent(...) passing the expression provided
UIComponent target = previous.findComponent(expression);
if (target == null)
{
// If no component is found ...
// First try to find the base component.
// Extract the base id from the expression string
int idx = expression.indexOf(separatorChar);
String base = idx > 0 ? expression.substring(0, idx) : expression;
// From the context component clientId, check if the base is part of the clientId
String contextClientId = previous.getClientId(facesContext);
int startCommon = contextClientId.lastIndexOf(base+facesContext.getNamingContainerSeparatorChar());
if (startCommon >= 0
&& (startCommon == 0 || contextClientId.charAt(startCommon-1) == separatorChar )
&& (startCommon+base.length() <= contextClientId.length()-1 ||
contextClientId.charAt(startCommon+base.length()+1) == separatorChar ))
{
// If there is a match, try to find a the first parent component whose id is equals to
// the base id
UIComponent parent = previous;
while (parent != null )
{
if (base.equals(parent.getId()) && parent instanceof NamingContainer)
{
break;
}
else
{
parent = parent.getParent();
}
}
// if a base component is found ...
if (parent != null)
{
target = parent.findComponent(expression);
if (target == null && !searchExpressionContext.getExpressionHints().contains(
SearchExpressionHint.SKIP_VIRTUAL_COMPONENTS))
{
contextClientId = parent.getClientId(facesContext);
// If no component is found,
String targetClientId = contextClientId.substring(0, startCommon+base.length()) +
expression.substring(base.length());
if (nextExpression != null)
{
final String childExpression = nextExpression;
parent.invokeOnComponent(facesContext, targetClientId, new ContextCallback()
{
@Override
public void invokeContextCallback(FacesContext context, UIComponent target)
{
handler.invokeOnComponent(
searchExpressionContext, target, childExpression, topCallback);
}
});
}
else
{
parent.invokeOnComponent(facesContext, targetClientId, topCallback);
}
return;
}
}
}
}
if (target != null)
{
if (nextExpression != null)
{
handler.invokeOnComponent(searchExpressionContext, target, nextExpression, topCallback);
}
else
{
topCallback.invokeContextCallback(facesContext, target);
}
return;
}
// At this point if the algorithm hasn't returned and the topExpression does not have any separator char
// we need to do the search backward using findComponent.
if (target == null
&& searchExpressionContext.getSource() == previous
&& (topExpression.indexOf(separatorChar + "@") == -1) ) // updated for MYFACES-4695
{
UIComponent baseNC = previous.getNamingContainer();
if (baseNC != null && baseNC.getParent() != null)
{
UIComponent parentNC = getParentNamingContainerUIViewRoot(baseNC.getParent());
while (target == null && parentNC != null)
{
UIComponent parent = parentNC.getParent();
target = parentNC.findComponent(expression);
if (parent != null)
{
parentNC = getParentNamingContainerUIViewRoot(parent);
}
else
{
parentNC = null;
}
}
if (target != null)
{
topCallback.invokeContextCallback(facesContext, target);
return;
}
}
}
if (target == null && nextExpression == null)
{
return;
}
topCallback.invokeContextCallback(facesContext, previous);
}
}