You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2016/11/23 01:36:27 UTC
svn commit: r1770904 [2/3] - in /myfaces/core/branches/2.3.x:
api/src/main/java/javax/faces/ api/src/main/java/javax/faces/application/
api/src/main/java/javax/faces/component/search/
impl/src/main/java/org/apache/myfaces/application/ impl/src/main/jav...
Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchComponentUtils.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchComponentUtils.java?rev=1770904&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchComponentUtils.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchComponentUtils.java Wed Nov 23 01:36:27 2016
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.component.search;
+
+import javax.faces.component.UIComponent;
+
+/**
+ *
+ */
+public class SearchComponentUtils
+{
+
+ public static UIComponent getRootComponent(UIComponent component)
+ {
+ UIComponent parent;
+ for (;;)
+ {
+ parent = component.getParent();
+ if (parent == null)
+ {
+ return component;
+ }
+ component = parent;
+ }
+ }
+}
Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionContextFactoryImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionContextFactoryImpl.java?rev=1770904&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionContextFactoryImpl.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionContextFactoryImpl.java Wed Nov 23 01:36:27 2016
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.component.search;
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.faces.component.UIComponent;
+import javax.faces.component.search.SearchExpressionContext;
+import javax.faces.component.search.SearchExpressionContextFactory;
+import javax.faces.component.search.SearchExpressionHint;
+import javax.faces.component.visit.VisitHint;
+import javax.faces.context.FacesContext;
+
+/**
+ *
+ */
+public class SearchExpressionContextFactoryImpl extends SearchExpressionContextFactory
+{
+
+ @Override
+ public SearchExpressionContext getSearchExpressionContext(
+ FacesContext context, UIComponent source,
+ Set<SearchExpressionHint> expressionHints, Set<VisitHint> visitHints)
+ {
+ SearchExpressionContextImpl searchExpressionContext = new SearchExpressionContextImpl(context);
+ searchExpressionContext.setSource(source);
+ searchExpressionContext.setExpressionHints(expressionHints == null ?
+ new HashSet<SearchExpressionHint>(2) : expressionHints);
+ searchExpressionContext.setVisitHints(visitHints);
+ return searchExpressionContext;
+ }
+
+}
Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionContextImpl.java?rev=1770904&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionContextImpl.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionContextImpl.java Wed Nov 23 01:36:27 2016
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.component.search;
+
+import java.util.Set;
+import javax.faces.component.UIComponent;
+import javax.faces.component.search.SearchExpressionContext;
+import javax.faces.component.search.SearchExpressionHint;
+import javax.faces.component.visit.VisitHint;
+import javax.faces.context.FacesContext;
+
+/**
+ *
+ */
+public class SearchExpressionContextImpl extends SearchExpressionContext
+{
+ private final FacesContext facesContext;
+
+ private UIComponent source;
+
+ private Set<VisitHint> visitHints;
+
+ private Set<SearchExpressionHint> expressionHints;
+
+ public SearchExpressionContextImpl(FacesContext facesContext)
+ {
+ this.facesContext = facesContext;
+ }
+
+ /**
+ * @return the source
+ */
+ public UIComponent getSource()
+ {
+ return source;
+ }
+
+ /**
+ * @param source the source to set
+ */
+ public void setSource(UIComponent source)
+ {
+ this.source = source;
+ }
+
+ /**
+ * @return the visitHints
+ */
+ public Set<VisitHint> getVisitHints()
+ {
+ return visitHints;
+ }
+
+ /**
+ * @param visitHints the visitHints to set
+ */
+ public void setVisitHints(Set<VisitHint> visitHints)
+ {
+ this.visitHints = visitHints;
+ }
+
+ /**
+ * @return the expressionHints
+ */
+ public Set<SearchExpressionHint> getExpressionHints()
+ {
+ return expressionHints;
+ }
+
+ /**
+ * @param expressionHints the expressionHints to set
+ */
+ public void setExpressionHints(Set<SearchExpressionHint> expressionHints)
+ {
+ this.expressionHints = expressionHints;
+ }
+
+ /**
+ * @return the facesContext
+ */
+ public FacesContext getFacesContext()
+ {
+ return facesContext;
+ }
+
+}
Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionHandlerImpl.java?rev=1770904&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionHandlerImpl.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionHandlerImpl.java Wed Nov 23 01:36:27 2016
@@ -0,0 +1,1028 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.component.search;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import javax.faces.component.ContextCallback;
+import javax.faces.component.NamingContainer;
+import javax.faces.component.UIComponent;
+import javax.faces.component.search.ComponentNotFoundException;
+import javax.faces.component.search.SearchExpressionContext;
+import javax.faces.component.search.SearchExpressionHandler;
+import javax.faces.component.search.SearchExpressionHint;
+import javax.faces.component.search.SearchKeywordContext;
+import javax.faces.context.FacesContext;
+
+/**
+ *
+ */
+public class SearchExpressionHandlerImpl extends SearchExpressionHandler
+{
+
+ public String resolveClientId(SearchExpressionContext searchExpressionContext, String expression)
+ {
+ FacesContext facesContext = searchExpressionContext.getFacesContext();
+ UIComponent source = searchExpressionContext.getSource();
+ CollectClientIdCallback callback = new CollectClientIdCallback();
+ Set<SearchExpressionHint> hints = searchExpressionContext.getExpressionHints();
+ hints.add(SearchExpressionHint.RESOLVE_CLIENT_ID);
+ SearchExpressionHandler handler = facesContext.getApplication().getSearchExpressionHandler();
+ if (handler.isPassthroughExpression(searchExpressionContext, expression))
+ {
+ return expression;
+ }
+ else
+ {
+ handler.invokeOnComponentFromExpression(
+ searchExpressionContext, searchExpressionContext.getSource(), expression, callback);
+
+ if (!callback.isClientIdFound() && hints != null && hints.contains(SearchExpressionHint.PARENT_FALLBACK))
+ {
+ callback.invokeContextCallback(facesContext, source.getParent());
+ }
+ if (!callback.isClientIdFound())
+ {
+ if (hints != null && hints.contains(SearchExpressionHint.IGNORE_NO_RESULT))
+ {
+ //Ignore
+ }
+ else
+ {
+ throw new ComponentNotFoundException("Cannot find component for expression \""
+ + expression + "\" referenced from \""
+ + searchExpressionContext.getSource().getClientId(facesContext) + "\".");
+ }
+ }
+ return callback.getClientId();
+ }
+ }
+
+ private static class CollectClientIdCallback implements ContextCallback
+ {
+ private String clientId = null;
+
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent target)
+ {
+ if (clientId == null)
+ {
+ clientId = target.getClientId(context);
+ }
+ }
+
+ private String getClientId()
+ {
+ return clientId;
+ }
+
+ private boolean isClientIdFound()
+ {
+ return clientId != null;
+ }
+ }
+
+ public List<String> resolveClientIds(SearchExpressionContext searchExpressionContext,
+ String expressions)
+ {
+ FacesContext facesContext = searchExpressionContext.getFacesContext();
+ UIComponent source = searchExpressionContext.getSource();
+ CollectClientIdsCallback callback = new CollectClientIdsCallback();
+ Set<SearchExpressionHint> hints = searchExpressionContext.getExpressionHints();
+ hints.add(SearchExpressionHint.RESOLVE_CLIENT_ID);
+ SearchExpressionHandler handler = facesContext.getApplication().getSearchExpressionHandler();
+ for (String expression :
+ facesContext.getApplication().getSearchExpressionHandler().splitExpressions(expressions))
+ {
+ if (handler.isPassthroughExpression(searchExpressionContext, expression))
+ {
+ // It will be resolved in the client, just add the expression.
+ callback.addClientId(expression);
+ }
+ else
+ {
+ handler.invokeOnComponentFromExpression(
+ searchExpressionContext, searchExpressionContext.getSource(), expression, callback);
+ }
+ }
+ if (!callback.isClientIdFound() && hints != null && hints.contains(SearchExpressionHint.PARENT_FALLBACK))
+ {
+ callback.invokeContextCallback(facesContext, source.getParent());
+ }
+ if (!callback.isClientIdFound())
+ {
+ if (hints != null && hints.contains(SearchExpressionHint.IGNORE_NO_RESULT))
+ {
+ //Ignore
+ }
+ else
+ {
+ throw new ComponentNotFoundException("Cannot find component for expression \""
+ + expressions + "\" referenced from \""
+ + searchExpressionContext.getSource().getClientId(facesContext) + "\".");
+ }
+ }
+ return callback.getClientIds();
+ }
+
+ private static class CollectClientIdsCallback implements ContextCallback
+ {
+ private List<String> clientIds = null;
+
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent target)
+ {
+ if (clientIds == null)
+ {
+ clientIds = new ArrayList<String>();
+ }
+ clientIds.add(target.getClientId(context));
+ }
+
+ private List<String> getClientIds()
+ {
+ return clientIds == null ? Collections.emptyList() : clientIds;
+ }
+
+ private boolean isClientIdFound()
+ {
+ return clientIds != null;
+ }
+
+ private void addClientId(String clientId)
+ {
+ if (clientIds == null)
+ {
+ clientIds = new ArrayList<String>();
+ }
+ clientIds.add(clientId);
+ }
+ }
+
+ public void resolveComponent(SearchExpressionContext searchExpressionContext, String expression,
+ ContextCallback callback)
+ {
+ FacesContext facesContext = searchExpressionContext.getFacesContext();
+ SingleInvocationCallback checkCallback = new SingleInvocationCallback(callback);
+ Set<SearchExpressionHint> hints = searchExpressionContext.getExpressionHints();
+ facesContext.getApplication().getSearchExpressionHandler().invokeOnComponentFromExpression(
+ searchExpressionContext, searchExpressionContext.getSource(), expression, checkCallback);
+
+ if (!checkCallback.isInvoked() && hints != null && hints.contains(SearchExpressionHint.PARENT_FALLBACK))
+ {
+ checkCallback.invokeContextCallback(facesContext, searchExpressionContext.getSource().getParent());
+ }
+ if (!checkCallback.isInvoked())
+ {
+ if (hints != null && hints.contains(SearchExpressionHint.IGNORE_NO_RESULT))
+ {
+ //Ignore
+ }
+ else
+ {
+ throw new ComponentNotFoundException("Cannot find component for expression \""
+ + expression + "\" referenced from \""
+ + searchExpressionContext.getSource().getClientId(facesContext) + "\".");
+ }
+ }
+ }
+
+ private static class SingleInvocationCallback implements ContextCallback
+ {
+ private boolean invoked;
+
+ private final ContextCallback innerCallback;
+
+ public SingleInvocationCallback(ContextCallback innerCallback)
+ {
+ this.innerCallback = innerCallback;
+ this.invoked = false;
+ }
+
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent target)
+ {
+ if (!isInvoked())
+ {
+ try
+ {
+ innerCallback.invokeContextCallback(context, target);
+ }
+ finally
+ {
+ invoked = true;
+ }
+ }
+ }
+
+ public boolean isInvoked()
+ {
+ return invoked;
+ }
+ }
+
+ public void resolveComponents(SearchExpressionContext searchExpressionContext, String expressions,
+ ContextCallback callback)
+ {
+ FacesContext facesContext = searchExpressionContext.getFacesContext();
+ MultipleInvocationCallback checkCallback = new MultipleInvocationCallback(callback);
+ Set<SearchExpressionHint> hints = searchExpressionContext.getExpressionHints();
+ for (String expression :
+ facesContext.getApplication().getSearchExpressionHandler().splitExpressions(expressions))
+ {
+ facesContext.getApplication().getSearchExpressionHandler().invokeOnComponentFromExpression(
+ searchExpressionContext, searchExpressionContext.getSource(), expression, checkCallback);
+ }
+ // ...
+ if (!checkCallback.isInvoked() && hints != null && hints.contains(SearchExpressionHint.PARENT_FALLBACK))
+ {
+ checkCallback.invokeContextCallback(facesContext, searchExpressionContext.getSource().getParent());
+ }
+ if (!checkCallback.isInvoked())
+ {
+ if (hints != null && hints.contains(SearchExpressionHint.IGNORE_NO_RESULT))
+ {
+ //Ignore
+ }
+ else
+ {
+ throw new ComponentNotFoundException("Cannot find component for expression \""
+ + expressions + "\" referenced from \""
+ + searchExpressionContext.getSource().getClientId(facesContext) + "\".");
+ }
+ }
+ }
+
+ private static class MultipleInvocationCallback implements ContextCallback
+ {
+ private boolean invoked;
+
+ private final ContextCallback innerCallback;
+
+ public MultipleInvocationCallback(ContextCallback innerCallback)
+ {
+ this.innerCallback = innerCallback;
+ this.invoked = false;
+ }
+
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent target)
+ {
+ try
+ {
+ innerCallback.invokeContextCallback(context, target);
+ }
+ finally
+ {
+ invoked = true;
+ }
+ }
+
+ public boolean isInvoked()
+ {
+ return invoked;
+ }
+ }
+
+ public void invokeOnComponentFromExpression(final SearchExpressionContext searchExpressionContext,
+ UIComponent source, String topExpression, ContextCallback topCallback)
+ {
+ // Command pattern to apply the keyword or command to the base and then invoke the callback
+ FacesContext facesContext = searchExpressionContext.getFacesContext();
+
+ UIComponent currentBase = source;
+
+ //Step 1: find base
+ // Case ':' (root)
+ char separatorChar = facesContext.getNamingContainerSeparatorChar();
+ if (topExpression.charAt(0) == separatorChar)
+ {
+ UIComponent findBase;
+ findBase = SearchComponentUtils.getRootComponent(currentBase);
+ facesContext.getApplication().getSearchExpressionHandler().invokeOnComponentFromExpression(
+ 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.
+ final UIComponent base = currentBase;
+
+ String command = extractKeyword(topExpression, 1, separatorChar);
+ final String remaining =
+ command.length()+1 < topExpression.length() ?
+ topExpression.substring(1+command.length()+1) : null;
+
+ final ContextCallback parentCallback = topCallback;
+ final SearchExpressionHandler currentInstance =
+ facesContext.getApplication().getSearchExpressionHandler();
+
+ // 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)
+ {
+ this.applyKeyword(searchExpressionContext, base, command, new ContextCallback()
+ {
+ @Override
+ public void invokeContextCallback(FacesContext facesContext, UIComponent target)
+ {
+ currentInstance.invokeOnComponentFromExpression(
+ searchExpressionContext, target, remaining, parentCallback);
+ }
+ });
+ }
+ else
+ {
+ // Command completed, apply parent callback
+ this.applyKeyword(searchExpressionContext, base, command, parentCallback);
+ }
+ }
+ 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 = currentBase.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 = currentBase.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 = currentBase;
+ 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)
+ {
+ contextClientId = parent.getClientId(facesContext);
+ // If no component is found,
+ String targetClientId = contextClientId.substring(0, startCommon+base.length()) +
+ expression.substring(base.length());
+
+ final SearchExpressionHandler currentHandler =
+ facesContext.getApplication().getSearchExpressionHandler();
+
+ if (nextExpression != null)
+ {
+ final String childExpression = nextExpression;
+
+ parent.invokeOnComponent(facesContext, targetClientId, new ContextCallback(){
+ public void invokeContextCallback(FacesContext context, UIComponent target)
+ {
+ currentHandler.invokeOnComponentFromExpression(
+ searchExpressionContext, target, childExpression, topCallback);
+ }
+ });
+ }
+ else
+ {
+ parent.invokeOnComponent(facesContext, targetClientId, topCallback);
+ }
+ return;
+ }
+ }
+ }
+ }
+ if (target != null)
+ {
+ currentBase = target;
+ }
+ if (currentBase != null)
+ {
+ topCallback.invokeContextCallback(facesContext, currentBase);
+ }
+ }
+ }
+
+ public void applyKeyword(SearchExpressionContext searchExpressionContext, UIComponent last,
+ String command, ContextCallback topCallback)
+ {
+ // take the command and resolve it using the chain of responsibility pattern.
+ SearchKeywordContext searchContext = new SearchKeywordContext(searchExpressionContext.getFacesContext());
+ searchContext.setSearchExpressionContext(searchExpressionContext);
+ searchContext.setTopCallback(topCallback);
+ searchExpressionContext.getFacesContext().getApplication()
+ .getSearchExpressionResolver().resolve(searchContext, last, command);
+ }
+
+ public boolean isPassthroughExpression(SearchExpressionContext searchExpressionContext, String topExpression)
+ {
+ FacesContext facesContext = searchExpressionContext.getFacesContext();
+ // Command pattern to apply the keyword or command to the base and then invoke the callback
+ boolean passthrough = false;
+ //Step 1: find base
+ // Case ':' (root)
+ char separatorChar = facesContext.getNamingContainerSeparatorChar();
+ if (topExpression.charAt(0) == separatorChar)
+ {
+ //return facesContext.getApplication().getSearchExpressionHandler().isPassthroughExpression(
+ // searchExpressionContext, topExpression.substring(1));
+ // only keywords are passthrough expressions.
+ return false;
+ }
+
+ //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;
+
+ final SearchExpressionHandler currentInstance =
+ facesContext.getApplication().getSearchExpressionHandler();
+
+ // If the keyword is @child, @composite, @form, @namingcontainer, @next, @none, @parent, @previous,
+ // @root, @this , all commands change the source to be applied the action
+ passthrough = facesContext.getApplication().getSearchExpressionResolver().isPassthroughKeyword(
+ searchExpressionContext, command);
+
+ if (passthrough)
+ {
+ return remaining != null ?
+ currentInstance.isPassthroughExpression(searchExpressionContext, remaining) : true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // Only keywords are valid to be passthrough. If it contains a chain of ids, this can only be resolved
+ // server side, because the tree structure and related clientId logic is only available server side.
+ return false;
+ }
+ }
+
+ public boolean isValidExpression(SearchExpressionContext searchExpressionContext, String topExpression)
+ {
+ FacesContext facesContext = searchExpressionContext.getFacesContext();
+ // Command pattern to apply the keyword or command to the base and then invoke the callback
+ boolean isValid = true;
+ //Step 1: find base
+ // Case ':' (root)
+ char separatorChar = facesContext.getNamingContainerSeparatorChar();
+ if (topExpression.charAt(0) == separatorChar)
+ {
+ return facesContext.getApplication().getSearchExpressionHandler().isValidExpression(
+ searchExpressionContext, topExpression.substring(1));
+ }
+
+ //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;
+
+ final SearchExpressionHandler currentInstance =
+ facesContext.getApplication().getSearchExpressionHandler();
+
+ // If the keyword is @child, @composite, @form, @namingcontainer, @next, @none, @parent, @previous,
+ // @root, @this , all commands change the source to be applied the action
+ isValid = facesContext.getApplication().getSearchExpressionResolver().matchKeyword(
+ searchExpressionContext, command);
+ if (remaining != null)
+ {
+ if (facesContext.getApplication().getSearchExpressionResolver().isLeafKeyword(
+ searchExpressionContext, command))
+ {
+ isValid = false;
+ }
+ return !isValid ? false : currentInstance.isValidExpression(searchExpressionContext, remaining);
+ }
+ }
+ else
+ {
+ //Split expression into tokens and apply loop
+ String nextExpression = null;
+ String expression = null;
+ if (topExpression.indexOf(":@") > 0)
+ {
+ int idx = topExpression.indexOf(":@");
+ nextExpression = topExpression.substring(idx+1);
+ expression = topExpression.substring(0,idx);
+ }
+ else
+ {
+ expression = topExpression;
+ }
+
+ //Check expression
+ for (int i = 0; i < expression.length(); i++)
+ {
+ char c = expression.charAt(i);
+ if (Character.isLetterOrDigit(c) || c == '-' || c == '_' || c == separatorChar)
+ {
+ //continue
+ }
+ else
+ {
+ isValid = false;
+ }
+ }
+
+ if (nextExpression != null)
+ {
+ return !isValid ? false : facesContext.getApplication().getSearchExpressionHandler()
+ .isValidExpression(searchExpressionContext, nextExpression);
+ }
+ }
+ return isValid;
+ }
+
+ private static String[] splitSingleExpression(String value)
+ {
+ if (value == null)
+ {
+ return null;
+ }
+
+ List<String> tokens = new ArrayList<String>();
+ StringBuilder buffer = new StringBuilder();
+
+ int parenthesesCounter = 0;
+
+ char[] charArray = value.toCharArray();
+
+ for (int i = 0; i < charArray.length; i++)
+ {
+ char c = charArray[i];
+ if (c == '(')
+ {
+ parenthesesCounter++;
+ }
+
+ if (c == ')')
+ {
+ parenthesesCounter--;
+ }
+
+ if (parenthesesCounter == 0)
+ {
+ boolean isSeparator = false;
+
+ if (c == ':')
+ {
+ for (int j = i+1; j < charArray.length; j++)
+ {
+ if (charArray[j] == '@')
+ {
+ isSeparator = true;
+ break;
+ }
+ else if (Character.isAlphabetic(charArray[j]))
+ {
+ //Different char than @
+ break;
+ }
+ }
+ }
+
+ if (isSeparator)
+ {
+ // lets add token inside buffer to our tokens
+ tokens.add(buffer.toString());
+ // now we need to clear buffer
+ buffer.delete(0, buffer.length());
+ }
+ else
+ {
+ buffer.append(c);
+ }
+ }
+ else
+ {
+ buffer.append(c);
+ }
+ }
+
+ // lets not forget about part after the separator
+ tokens.add(buffer.toString());
+
+ return tokens.toArray(new String[tokens.size()]);
+ }
+
+ private static class ComponentExistsContextCallback implements ContextCallback
+ {
+ private boolean found;
+
+ /**
+ * @return the found
+ */
+ public boolean isFound()
+ {
+ return found;
+ }
+
+ /**
+ * @param found the found to set
+ */
+ public void setFound(boolean found)
+ {
+ this.found = found;
+ }
+
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent target)
+ {
+ found = true;
+ }
+ }
+
+ private static String extractKeyword(String expression, int startIndex, char separatorChar)
+ {
+ int parenthesesCounter = -1;
+ int count = -1;
+ for (int i = startIndex; i < expression.length(); i++)
+ {
+ char c = expression.charAt(i);
+ if (c == '(')
+ {
+ if (parenthesesCounter == -1)
+ {
+ parenthesesCounter = 0;
+ }
+ parenthesesCounter++;
+ }
+ if (c == ')')
+ {
+ parenthesesCounter--;
+ }
+ if (parenthesesCounter == 0)
+ {
+ //Close first parentheses
+ count = i+1;
+ break;
+ }
+ if (parenthesesCounter == -1)
+ {
+ if (c == separatorChar)
+ {
+ count = i;
+ break;
+ }
+ }
+ }
+ if (count == -1)
+ {
+ return expression.substring(startIndex);
+ }
+ else
+ {
+ return expression.substring(startIndex, count);
+ }
+ }
+
+ public String[] splitExpressions(String expressions)
+ {
+ // split expressions by blank or comma (and ignore blank and commas inside brackets)
+ String[] splittedExpressions = split(expressions, EXPRESSION_SEPARATOR_CHARS);
+ return splittedExpressions;
+ }
+
+ private static String[] split(String value, char... separators)
+ {
+ if (value == null)
+ {
+ return null;
+ }
+
+ List<String> tokens = new ArrayList<String>();
+ StringBuilder buffer = new StringBuilder();
+
+ int parenthesesCounter = 0;
+
+ char[] charArray = value.toCharArray();
+
+ for (char c : charArray)
+ {
+ if (c == '(')
+ {
+ parenthesesCounter++;
+ }
+
+ if (c == ')')
+ {
+ parenthesesCounter--;
+ }
+
+ if (parenthesesCounter == 0)
+ {
+ boolean isSeparator = false;
+ for (char separator : separators)
+ {
+ if (c == separator)
+ {
+ isSeparator = true;
+ }
+ }
+
+ if (isSeparator)
+ {
+ // lets add token inside buffer to our tokens
+ tokens.add(buffer.toString());
+ // now we need to clear buffer
+ buffer.delete(0, buffer.length());
+ }
+ else
+ {
+ buffer.append(c);
+ }
+ }
+ else
+ {
+ buffer.append(c);
+ }
+ }
+
+ // lets not forget about part after the separator
+ tokens.add(buffer.toString());
+
+ return tokens.toArray(new String[tokens.size()]);
+ }
+
+ public List<UIComponent> findComponentFromExpression(SearchExpressionContext searchExpressionContext,
+ UIComponent source, String topExpression)
+ {
+ // Command pattern to apply the keyword or command to the base and then invoke the callback
+ FacesContext facesContext = searchExpressionContext.getFacesContext();
+ UIComponent currentBase = source;
+ List<UIComponent> responseList = null;
+
+ searchExpressionContext.getExpressionHints().add(SearchExpressionHint.RESOLVE_COMPONENT_LIST);
+
+ //Step 1: find base
+ // Case ':' (root)
+ char separatorChar = facesContext.getNamingContainerSeparatorChar();
+ if (topExpression.charAt(0) == separatorChar)
+ {
+ UIComponent findBase;
+ findBase = SearchComponentUtils.getRootComponent(currentBase);
+ return facesContext.getApplication().getSearchExpressionHandler().findComponentFromExpression(
+ searchExpressionContext, findBase, topExpression.substring(1));
+ }
+
+ //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.
+ final UIComponent base = currentBase;
+
+ String command = extractKeyword(topExpression, 1, separatorChar);
+ final String remaining =
+ command.length()+1 < topExpression.length() ?
+ topExpression.substring(1+command.length()+1) : null;
+
+ final SearchExpressionHandler currentInstance =
+ facesContext.getApplication().getSearchExpressionHandler();
+
+ // 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)
+ {
+ List<UIComponent> resp = this.applyKeyword(searchExpressionContext, base, command);
+ if (resp != null)
+ {
+ for (UIComponent target : resp)
+ {
+ List<UIComponent> list = currentInstance.findComponentFromExpression(
+ searchExpressionContext, target, remaining);
+ if (list != null)
+ {
+ if (responseList == null)
+ {
+ responseList = list;
+ }
+ else
+ {
+ responseList.addAll(list);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ List<UIComponent> resp = this.applyKeyword(searchExpressionContext, base, command);
+ if (resp != null)
+ {
+ if (responseList == null)
+ {
+ responseList = resp;
+ }
+ else
+ {
+ responseList.addAll(resp);
+ }
+ }
+ }
+ }
+ 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 = currentBase.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 = currentBase.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 = currentBase;
+ 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)
+ {
+ contextClientId = parent.getClientId(facesContext);
+ // If no component is found,
+ String targetClientId = contextClientId.substring(0, startCommon+base.length()) +
+ expression.substring(base.length());
+
+ final SearchExpressionHandler currentHandler =
+ facesContext.getApplication().getSearchExpressionHandler();
+
+ if (nextExpression != null)
+ {
+ final String childExpression = nextExpression;
+
+ parent.invokeOnComponent(facesContext, targetClientId, new ContextCallback(){
+ public void invokeContextCallback(FacesContext context, UIComponent target)
+ {
+ currentHandler.invokeOnComponentFromExpression(
+ searchExpressionContext, target, childExpression, topCallback);
+ }
+ });
+ }
+ else
+ {
+ parent.invokeOnComponent(facesContext, targetClientId, topCallback);
+ }
+ return;
+ }*/
+ }
+ }
+ }
+ if (target != null)
+ {
+ currentBase = target;
+ }
+ if (currentBase != null)
+ {
+ if (responseList == null)
+ {
+ responseList = new ArrayList<UIComponent>();
+ }
+ responseList.add(currentBase);
+ }
+ }
+ return responseList;
+ }
+
+ public List<UIComponent> applyKeyword(SearchExpressionContext searchExpressionContext, UIComponent last,
+ String command)
+ {
+ Set<SearchExpressionHint> hints = searchExpressionContext.getExpressionHints();
+ CollectComponentCallback callback = new CollectComponentCallback();
+ searchExpressionContext.getFacesContext().getApplication().getSearchExpressionHandler().applyKeyword(
+ searchExpressionContext, last, command, callback);
+ return callback.getList();
+ }
+
+ private static class CollectComponentCallback implements ContextCallback
+ {
+ private List<UIComponent> list = null;
+
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent target)
+ {
+ if (getList() == null)
+ {
+ list = new ArrayList<UIComponent>(2);
+ }
+ getList().add(target);
+ }
+
+ /**
+ * @return the list
+ */
+ public List<UIComponent> getList()
+ {
+ return list;
+ }
+
+ }
+}
Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/ThisSearchExpressionResolver.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/ThisSearchExpressionResolver.java?rev=1770904&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/ThisSearchExpressionResolver.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/component/search/ThisSearchExpressionResolver.java Wed Nov 23 01:36:27 2016
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.component.search;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.search.SearchExpressionContext;
+import javax.faces.component.search.SearchKeywordContext;
+import javax.faces.component.search.SearchExpressionResolver;
+
+/**
+ *
+ */
+public class ThisSearchExpressionResolver extends SearchExpressionResolver
+{
+ public static final String THIS_KEYWORD = "this";
+
+ @Override
+ public void resolve(SearchKeywordContext expressionContext, UIComponent last, String command)
+ {
+ if (command != null && command.equalsIgnoreCase(THIS_KEYWORD))
+ {
+ expressionContext.invokeContextCallback(expressionContext.getFacesContext(), last);
+ }
+ }
+
+ @Override
+ public boolean matchKeyword(SearchExpressionContext searchExpressionContext, String keyword)
+ {
+ return THIS_KEYWORD.equalsIgnoreCase(keyword);
+ }
+
+ @Override
+ public boolean isPassthroughKeyword(SearchExpressionContext searchExpressionContext, String keyword)
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isLeafKeyword(SearchExpressionContext searchExpressionContext, String keyword)
+ {
+ return false;
+ }
+}
Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/DefaultFacesConfigurationProvider.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/DefaultFacesConfigurationProvider.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/DefaultFacesConfigurationProvider.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/DefaultFacesConfigurationProvider.java Wed Nov 23 01:36:27 2016
@@ -109,6 +109,7 @@ public class DefaultFacesConfigurationPr
FACTORY_NAMES.add(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY);
FACTORY_NAMES.add(FactoryFinder.VISIT_CONTEXT_FACTORY);
FACTORY_NAMES.add(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY);
+ FACTORY_NAMES.add(FactoryFinder.SEARCH_EXPRESSION_CONTEXT_FACTORY);
}
/**
@@ -283,6 +284,10 @@ public class DefaultFacesConfigurationPr
{
factory.addFaceletCacheFactory(className);
}
+ else if(factoryName.equals(FactoryFinder.SEARCH_EXPRESSION_CONTEXT_FACTORY))
+ {
+ factory.addSearchExpressionContextFactory(className);
+ }
else
{
throw new IllegalStateException("Unexpected factory name " + factoryName);
Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/FacesConfigDispenser.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/FacesConfigDispenser.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/FacesConfigDispenser.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/FacesConfigDispenser.java Wed Nov 23 01:36:27 2016
@@ -126,4 +126,11 @@ public abstract class FacesConfigDispens
{
}
+ /**
+ * @since 2.3
+ * @param factoryClassName
+ */
+ public void feedSearchExpressionContextFactory(String factoryClassName)
+ {
+ }
}
Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java Wed Nov 23 01:36:27 2016
@@ -136,6 +136,7 @@ import org.apache.myfaces.shared.util.We
import org.apache.myfaces.shared_impl.util.serial.DefaultSerialFactory;
import org.apache.myfaces.shared_impl.util.serial.SerialFactory;
import org.apache.myfaces.cdi.dependent.BeanEntry;
+import org.apache.myfaces.component.search.SearchExpressionContextFactoryImpl;
import org.apache.myfaces.config.element.ViewPoolMapping;
import org.apache.myfaces.config.element.facelets.FaceletTagLibrary;
import org.apache.myfaces.lifecycle.LifecycleImpl;
@@ -189,6 +190,8 @@ public class FacesConfigurator
private static final String DEFAULT_FLASH_FACTORY = ServletFlashFactoryImpl.class.getName();
private static final String DEFAULT_CLIENT_WINDOW_FACTORY = ClientWindowFactoryImpl.class.getName();
private static final String DEFAULT_FLOW_FACTORY = FlowHandlerFactoryImpl.class.getName();
+ private static final String DEFAULT_SEARCH_EXPRESSION_CONTEXT_FACTORY =
+ SearchExpressionContextFactoryImpl.class.getName();
private static final String DEFAULT_FACES_CONFIG = "/WEB-INF/faces-config.xml";
private static final String INJECTED_BEAN_STORAGE_KEY = "org.apache.myfaces.spi.BEAN_ENTRY_STORAGE";
@@ -676,6 +679,9 @@ public class FacesConfigurator
DEFAULT_CLIENT_WINDOW_FACTORY);
setFactories(FactoryFinder.FLOW_HANDLER_FACTORY, dispenser.getFlowHandlerFactoryIterator(),
DEFAULT_FLOW_FACTORY);
+ setFactories(FactoryFinder.SEARCH_EXPRESSION_CONTEXT_FACTORY,
+ dispenser.getSearchExpressionContextFactoryIterator(),
+ DEFAULT_SEARCH_EXPRESSION_CONTEXT_FACTORY);
}
private void setFactories(String factoryName, Collection<String> factories, String defaultFactory)
Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/RuntimeConfig.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/RuntimeConfig.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/RuntimeConfig.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/RuntimeConfig.java Wed Nov 23 01:36:27 2016
@@ -33,6 +33,7 @@ import java.util.logging.Logger;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
+import javax.faces.component.search.SearchExpressionResolver;
import javax.faces.context.ExternalContext;
import javax.faces.el.PropertyResolver;
import javax.faces.el.VariableResolver;
@@ -121,6 +122,8 @@ public class RuntimeConfig
private Map<String, Integer> _idByNamespace = new HashMap<String, Integer>();
private List<ViewPoolMapping> _viewPoolMappings = new ArrayList<ViewPoolMapping>();
+
+ private List<SearchExpressionResolver> _searchExpressionResolvers = new ArrayList<SearchExpressionResolver>();
public static RuntimeConfig getCurrentInstance(ExternalContext externalContext)
{
@@ -584,4 +587,18 @@ public class RuntimeConfig
{
_viewPoolMappings.add(mapping);
}
+
+ public void addApplicationSearchExpressionResolver(SearchExpressionResolver resolver)
+ {
+ if (_searchExpressionResolvers == null)
+ {
+ _searchExpressionResolvers = new ArrayList<SearchExpressionResolver>();
+ }
+ _searchExpressionResolvers.add(resolver);
+ }
+
+ public List<SearchExpressionResolver> getApplicationSearchExpressionResolvers()
+ {
+ return _searchExpressionResolvers;
+ }
}
Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/element/FacesConfigData.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/element/FacesConfigData.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/element/FacesConfigData.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/element/FacesConfigData.java Wed Nov 23 01:36:27 2016
@@ -100,6 +100,15 @@ public abstract class FacesConfigData im
{
return Collections.emptyList();
}
+
+ /**
+ * @since 2.3
+ * @return
+ */
+ public Collection<String> getSearchExpressionContextFactoryIterator()
+ {
+ return Collections.emptyList();
+ }
/** @return Iterator over ActionListener class names (in reverse order!) */
public abstract Collection<String> getActionListenerIterator();
Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/element/Factory.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/element/Factory.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/element/Factory.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/element/Factory.java Wed Nov 23 01:36:27 2016
@@ -83,4 +83,13 @@ public abstract class Factory implements
{
return Collections.emptyList();
}
+
+ /**
+ * @since 2.3
+ * @return
+ */
+ public List<String> getSearchExpressionContextFactory()
+ {
+ return Collections.emptyList();
+ }
}
Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigDispenserImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigDispenserImpl.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigDispenserImpl.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigDispenserImpl.java Wed Nov 23 01:36:27 2016
@@ -76,6 +76,7 @@ public class DigesterFacesConfigDispense
private List<String> flashFactories = new ArrayList<String>();
private List<String> clientWindowFactories = new ArrayList<String>();
private List<String> flowHandlerFactories = new ArrayList<String>();
+ private List<String> searchExpressionContextFactories = new ArrayList<String>();
private String defaultRenderKitId;
private String messageBundle;
@@ -130,7 +131,7 @@ public class DigesterFacesConfigDispense
private List <String> resourceResolvers = new ArrayList<String>();
private List<ViewPoolMapping> viewPoolMappings = new ArrayList<ViewPoolMapping>();
-
+
// Unmodifiable list/maps to avoid modifications
private transient List<String> umapplicationFactories;
private transient List<String> umexceptionHandlerFactories;
@@ -146,6 +147,7 @@ public class DigesterFacesConfigDispense
private transient List<String> umflashFactories;
private transient List<String> umclientWindowFactories;
private transient List<String> umflowHandlerFactories;
+ private transient List<String> umsearchExpressionContextFactories;
private transient List<Behavior> umbehaviors;
private transient List<String> umactionListeners;
private transient List<String> umelResolvers;
@@ -193,6 +195,7 @@ public class DigesterFacesConfigDispense
flashFactories.addAll(factory.getFlashFactory());
clientWindowFactories.addAll(factory.getClientWindowFactory());
flowHandlerFactories.addAll(factory.getFlowHandlerFactory());
+ searchExpressionContextFactories.addAll(factory.getSearchExpressionContextFactory());
}
components.putAll(config.getComponents());
@@ -1043,4 +1046,21 @@ public class DigesterFacesConfigDispense
}
return umviewPoolMappings;
}
+
+ @Override
+ public void feedSearchExpressionContextFactory(String factoryClassName)
+ {
+ searchExpressionContextFactories.add(factoryClassName);
+ }
+
+ @Override
+ public Collection<String> getSearchExpressionContextFactoryIterator()
+ {
+ if (umsearchExpressionContextFactories == null)
+ {
+ umsearchExpressionContextFactories = Collections.unmodifiableList(searchExpressionContextFactories);
+ }
+ return umsearchExpressionContextFactories;
+ }
+
}
Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigUnmarshallerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigUnmarshallerImpl.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigUnmarshallerImpl.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigUnmarshallerImpl.java Wed Nov 23 01:36:27 2016
@@ -125,6 +125,8 @@ public class DigesterFacesConfigUnmarsha
digester.addCallMethod("faces-config/factory/partial-view-context-factory", "addPartialViewContextFactory", 0);
digester.addCallMethod("faces-config/factory/tag-handler-delegate-factory", "addTagHandlerDelegateFactory", 0);
digester.addCallMethod("faces-config/factory/visit-context-factory", "addVisitContextFactory", 0);
+ digester.addCallMethod("faces-config/factory/search-expression-context-factory",
+ "addSearchExpressionContextFactory", 0);
// 2.0 specific end
digester.addObjectCreate("faces-config/application/resource-library-contracts/contract-mapping",
Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/FactoryImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/FactoryImpl.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/FactoryImpl.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/FactoryImpl.java Wed Nov 23 01:36:27 2016
@@ -41,6 +41,7 @@ public class FactoryImpl extends org.apa
private List<String> flowHandlerFactories = new ArrayList<String>();
private List<String> flashFactories = new ArrayList<String>();
private List<String> clientWindowFactories = new ArrayList<String>();
+ private List<String> searchExpressionContextFactories = new ArrayList<String>();
public void addApplicationFactory(String factory)
{
@@ -185,4 +186,16 @@ public class FactoryImpl extends org.apa
{
return clientWindowFactories;
}
+
+ public void addSearchExpressionContextFactory(String factory)
+ {
+ searchExpressionContextFactories.add(factory);
+ }
+
+ @Override
+ public List<String> getSearchExpressionContextFactory()
+ {
+ return clientWindowFactories;
+ }
+
}
Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlLabelRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlLabelRenderer.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlLabelRenderer.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlLabelRenderer.java Wed Nov 23 01:36:27 2016
@@ -29,6 +29,7 @@ import javax.faces.component.ValueHolder
import javax.faces.component.behavior.ClientBehavior;
import javax.faces.component.behavior.ClientBehaviorHolder;
import javax.faces.component.html.HtmlOutputLabel;
+import javax.faces.component.search.SearchExpressionContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
@@ -240,7 +241,9 @@ public class HtmlLabelRenderer extends H
protected String getClientId(FacesContext facesContext, UIComponent uiComponent, String forAttr)
{
- return RendererUtils.getClientId(facesContext, uiComponent, forAttr);
+ //return RendererUtils.getClientId(facesContext, uiComponent, forAttr);
+ return facesContext.getApplication().getSearchExpressionHandler().resolveClientId(
+ SearchExpressionContext.createSearchExpressionContext(facesContext, uiComponent), forAttr);
}
@Override
Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/spi/ServiceProviderFinder.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/spi/ServiceProviderFinder.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/spi/ServiceProviderFinder.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/spi/ServiceProviderFinder.java Wed Nov 23 01:36:27 2016
@@ -53,6 +53,7 @@ public abstract class ServiceProviderFin
FactoryFinder.TAG_HANDLER_DELEGATE_FACTORY,
FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY,
FactoryFinder.VISIT_CONTEXT_FACTORY,
+ FactoryFinder.SEARCH_EXPRESSION_CONTEXT_FACTORY,
"org.apache.myfaces.spi.AnnotationProvider",
"org.apache.myfaces.spi.AnnotationProviderFactory",
"org.apache.myfaces.spi.FaceletConfigResourceProvider",
Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/UILeaf.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/UILeaf.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/UILeaf.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/UILeaf.java Wed Nov 23 01:36:27 2016
@@ -33,6 +33,7 @@ import javax.faces.component.ContextCall
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.component.UniqueIdVendor;
+import javax.faces.component.search.Markup;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.context.FacesContext;
@@ -47,7 +48,7 @@ import javax.faces.view.Location;
import org.apache.commons.collections.iterators.EmptyIterator;
import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
-class UILeaf extends UIComponent implements Map<String, Object>
+class UILeaf extends UIComponent implements Markup, Map<String, Object>
{
//-------------- START TAKEN FROM UIComponentBase ----------------
private static final String _STRING_BUILDER_KEY
Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetImpl.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetImpl.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetImpl.java Wed Nov 23 01:36:27 2016
@@ -25,6 +25,7 @@ import java.util.List;
import javax.el.ValueExpression;
import javax.faces.component.UIComponent;
+import javax.faces.component.search.SearchExpressionContext;
import javax.faces.context.FacesContext;
import javax.faces.view.AttachedObjectTarget;
@@ -68,28 +69,35 @@ public class AttachedObjectTargetImpl im
if (targetsArray.length > 0)
{
List<UIComponent> targetsList = new ArrayList<UIComponent>(targetsArray.length);
- final char separatorChar = facesContext.getNamingContainerSeparatorChar();
+ //final char separatorChar = facesContext.getNamingContainerSeparatorChar();
UIComponent facetBase = topLevelComponent.getFacet(UIComponent.COMPOSITE_FACET_NAME);
for (String target : targetsArray)
{
- //UIComponent innerComponent = topLevelComponent.findComponent(
- // topLevelComponent.getId() + UINamingContainer.getSeparatorChar(facesContext) + target);
- int separator = target.indexOf(separatorChar);
- UIComponent innerComponent = null;
- if (separator == -1)
- {
- innerComponent = ComponentSupport.findComponentChildOrFacetFrom(
- facetBase, target, null);
- }
- else
- {
- innerComponent = ComponentSupport.findComponentChildOrFacetFrom(
- facetBase, target.substring(0,separator), target);
- }
+ //int separator = target.indexOf(separatorChar);
+ //UIComponent innerComponent = null;
+ List<UIComponent> resultList;
+ //if (separator == -1)
+ //{
+ //innerComponent = ComponentSupport.findComponentChildOrFacetFrom(
+ // facetBase, target, null);
+ resultList = facesContext.getApplication().getSearchExpressionHandler().
+ findComponentFromExpression(SearchExpressionContext.createSearchExpressionContext(
+ facesContext, facetBase), facetBase, target);
+ //}
+ //else
+ //{
+ //innerComponent = ComponentSupport.findComponentChildOrFacetFrom(
+ // facetBase, target.substring(0,separator), target);
+ // resultList = facesContext.getApplication().getSearchExpressionHandler().
+ // findComponentFromExpression(SearchExpressionContext.createSearchExpressionContext(
+ // facesContext, facetBase), facetBase, target.substring(0,separator));
+ //}
- if (innerComponent != null)
+ //if (innerComponent != null)
+ if (resultList != null)
{
- targetsList.add(innerComponent);
+ targetsList.addAll(resultList);
+ //targetsList.add(innerComponent);
}
}
return targetsList;
@@ -103,8 +111,6 @@ public class AttachedObjectTargetImpl im
String name = getName();
if (name != null)
{
- //UIComponent innerComponent = topLevelComponent.findComponent(
- // topLevelComponent.getId() + UINamingContainer.getSeparatorChar(facesContext) + getName());
UIComponent innerComponent = ComponentSupport.findComponentChildOrFacetFrom(
topLevelComponent.getFacet(UIComponent.COMPOSITE_FACET_NAME),
name, null);
Modified: myfaces/core/branches/2.3.x/impl/src/test/java/org/apache/myfaces/application/ApplicationImplJsfTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/test/java/org/apache/myfaces/application/ApplicationImplJsfTest.java?rev=1770904&r1=1770903&r2=1770904&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/test/java/org/apache/myfaces/application/ApplicationImplJsfTest.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/test/java/org/apache/myfaces/application/ApplicationImplJsfTest.java Wed Nov 23 01:36:27 2016
@@ -74,7 +74,7 @@ public class ApplicationImplJsfTest exte
*
* @author Jakob Korherr
*/
- private class TestApplicationWrapper extends ApplicationWrapper
+ public static class TestApplicationWrapper extends ApplicationWrapper
{
private ApplicationImpl _applicationImpl;
Added: myfaces/core/branches/2.3.x/impl/src/test/java/org/apache/myfaces/component/search/SearchBean.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/test/java/org/apache/myfaces/component/search/SearchBean.java?rev=1770904&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/test/java/org/apache/myfaces/component/search/SearchBean.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/test/java/org/apache/myfaces/component/search/SearchBean.java Wed Nov 23 01:36:27 2016
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.component.search;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.PostConstruct;
+import javax.faces.bean.ManagedBean;
+import javax.faces.bean.RequestScoped;
+
+/**
+ *
+ * @author lu4242
+ */
+@ManagedBean(name = "searchBean")
+@RequestScoped
+public class SearchBean
+{
+
+ private List<RowData> model;
+
+ public SearchBean()
+ {
+
+ }
+
+ @PostConstruct
+ public void init()
+ {
+ setModel(new ArrayList<RowData>());
+ getModel().add(new RowData("text1","style1"));
+ getModel().add(new RowData("text2","style2"));
+ getModel().add(new RowData("text3","style3"));
+ getModel().add(new RowData("text4","style4"));
+ }
+
+ /**
+ * @return the model
+ */
+ public List<RowData> getModel()
+ {
+ return model;
+ }
+
+ /**
+ * @param model the model to set
+ */
+ public void setModel(List<RowData> model)
+ {
+ this.model = model;
+ }
+
+ public static class RowData
+ {
+ private String text;
+
+ private List<String> nested;
+
+ public RowData(String text, String style)
+ {
+ super();
+ this.text = text;
+ this.style = style;
+ this.nested = new ArrayList<String>();
+ this.nested.add("A");
+ this.nested.add("B");
+ }
+
+ private String style;
+
+ public String getText()
+ {
+ return text;
+ }
+
+ public void setText(String text)
+ {
+ this.text = text;
+ }
+
+ public String getStyle()
+ {
+ return style;
+ }
+
+ public void setStyle(String style)
+ {
+ this.style = style;
+ }
+
+ /**
+ * @return the nested
+ */
+ public List<String> getNested()
+ {
+ return nested;
+ }
+
+ /**
+ * @param nested the nested to set
+ */
+ public void setNested(List<String> nested)
+ {
+ this.nested = nested;
+ }
+ }
+}