You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ja...@apache.org on 2010/01/20 23:08:12 UTC
svn commit: r901400 - in
/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets:
AbstractFaceletContext.java impl/DefaultFaceletContext.java
tag/jsf/ComponentTagHandlerDelegate.java
tag/jsf/ValidatorTagHandlerDelegate.java
Author: jakobk
Date: Wed Jan 20 22:08:12 2010
New Revision: 901400
URL: http://svn.apache.org/viewvc?rev=901400&view=rev
Log:
MYFACES-2410 f:validateBean does not work as container for EditableValueHolders
Modified:
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletContext.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletContext.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentTagHandlerDelegate.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ValidatorTagHandlerDelegate.java
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletContext.java?rev=901400&r1=901399&r2=901400&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletContext.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletContext.java Wed Jan 20 22:08:12 2010
@@ -168,4 +168,44 @@
*/
public abstract void pushAjaxHandlerToStack(AjaxHandler parent);
+ /**
+ * Gets all validation groups on the stack.
+ * @return
+ * @since 2.0
+ */
+ public abstract Iterator<String> getValidationGroups();
+
+ /**
+ * Removes top of stack.
+ * @since 2.0
+ */
+ public abstract void popValidationGroupsToStack();
+
+ /**
+ * Pushes validationGroups to the stack.
+ * @param validationGroups
+ * @since 2.0
+ */
+ public abstract void pushValidationGroupsToStack(String validationGroups);
+
+ /**
+ * Gets all validationIds on the stack.
+ * @return
+ * @since 2.0
+ */
+ public abstract Iterator<String> getExcludedValidatorIds();
+
+ /**
+ * Removes top of stack.
+ * @since 2.0
+ */
+ public abstract void popExcludedValidatorIdToStack();
+
+ /**
+ * Pushes validatorId to the stack of excluded validatorIds.
+ * @param validatorId
+ * @since 2.0
+ */
+ public abstract void pushExcludedValidatorIdToStack(String validatorId);
+
}
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletContext.java?rev=901400&r1=901399&r2=901400&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletContext.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletContext.java Wed Jan 20 22:08:12 2010
@@ -66,6 +66,10 @@
public final static String UNIQUEID_VENDOR_STACK = "org.apache.myfaces.view.facelets.UNIQUEID_VENDOR_STACK";
public final static String AJAX_HANDLER_STACK = "org.apache.myfaces.view.facelets.AJAX_HANDLER_STACK";
+
+ public final static String VALIDATION_GROUPS_STACK = "org.apache.myfaces.view.facelets.VALIDATION_GROUPS_STACK";
+
+ public final static String EXCLUDED_VALIDATOR_IDS_STACK = "org.apache.myfaces.view.facelets.EXCLUDED_VALIDATOR_IDS_STACK";
private final FacesContext _faces;
@@ -612,4 +616,124 @@
componentStack.addFirst(parent);
}
+
+ /**
+ * Gets all validation groups on the stack.
+ * @return
+ * @since 2.0
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Iterator<String> getValidationGroups()
+ {
+ Map<Object, Object> attributes = getFacesContext().getAttributes();
+
+ LinkedList<String> validationGroupsStack
+ = (LinkedList<String>) attributes.get(VALIDATION_GROUPS_STACK);
+ if (validationGroupsStack != null && !validationGroupsStack.isEmpty())
+ {
+ return validationGroupsStack.iterator();
+ }
+ return null;
+ }
+
+ /**
+ * Removes top of stack.
+ * @since 2.0
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public void popValidationGroupsToStack()
+ {
+ Map<Object, Object> contextAttributes = getFacesContext().getAttributes();
+
+ LinkedList<String> validationGroupsStack
+ = (LinkedList<String>) contextAttributes.get(VALIDATION_GROUPS_STACK);
+ if (validationGroupsStack != null && !validationGroupsStack.isEmpty())
+ {
+ validationGroupsStack.removeFirst();
+ }
+ }
+
+ /**
+ * Pushes validationGroups to the stack.
+ * @param validationGroups
+ * @since 2.0
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public void pushValidationGroupsToStack(String validationGroups)
+ {
+ Map<Object, Object> attributes = getFacesContext().getAttributes();
+
+ LinkedList<String> validationGroupsStack
+ = (LinkedList<String>) attributes.get(VALIDATION_GROUPS_STACK);
+ if (validationGroupsStack == null)
+ {
+ validationGroupsStack = new LinkedList<String>();
+ attributes.put(VALIDATION_GROUPS_STACK, validationGroupsStack);
+ }
+
+ validationGroupsStack.addFirst(validationGroups);
+ }
+
+ /**
+ * Gets all validationIds on the stack.
+ * @return
+ * @since 2.0
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Iterator<String> getExcludedValidatorIds()
+ {
+ Map<Object, Object> attributes = getFacesContext().getAttributes();
+
+ LinkedList<String> excludedValidatorIdsStack
+ = (LinkedList<String>) attributes.get(EXCLUDED_VALIDATOR_IDS_STACK);
+ if (excludedValidatorIdsStack != null && !excludedValidatorIdsStack.isEmpty())
+ {
+ return excludedValidatorIdsStack.iterator();
+ }
+ return null;
+ }
+
+ /**
+ * Removes top of stack.
+ * @since 2.0
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public void popExcludedValidatorIdToStack()
+ {
+ Map<Object, Object> contextAttributes = getFacesContext().getAttributes();
+
+ LinkedList<String> excludedValidatorIdsStack
+ = (LinkedList<String>) contextAttributes.get(EXCLUDED_VALIDATOR_IDS_STACK);
+ if (excludedValidatorIdsStack != null && !excludedValidatorIdsStack.isEmpty())
+ {
+ excludedValidatorIdsStack.removeFirst();
+ }
+ }
+
+ /**
+ * Pushes validatorId to the stack of excluded validatorIds.
+ * @param validatorId
+ * @since 2.0
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public void pushExcludedValidatorIdToStack(String validatorId)
+ {
+ Map<Object, Object> attributes = getFacesContext().getAttributes();
+
+ LinkedList<String> excludedValidatorIdsStack
+ = (LinkedList<String>) attributes.get(EXCLUDED_VALIDATOR_IDS_STACK);
+ if (excludedValidatorIdsStack == null)
+ {
+ excludedValidatorIdsStack = new LinkedList<String>();
+ attributes.put(EXCLUDED_VALIDATOR_IDS_STACK, excludedValidatorIdsStack);
+ }
+
+ excludedValidatorIdsStack.addFirst(validatorId);
+ }
}
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentTagHandlerDelegate.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentTagHandlerDelegate.java?rev=901400&r1=901399&r2=901400&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentTagHandlerDelegate.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentTagHandlerDelegate.java Wed Jan 20 22:08:12 2010
@@ -19,6 +19,7 @@
package org.apache.myfaces.view.facelets.tag.jsf;
import java.io.IOException;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
@@ -75,7 +76,7 @@
* This constant is duplicate in javax.faces.webapp.UIComponentClassicTagBase
*/
public final static String FACET_CREATED_UIPANEL_MARKER = "org.apache.myfaces.facet.createdUIPanel";
-
+
private final ComponentHandler _delegate;
private final String _componentType;
@@ -246,7 +247,7 @@
{
// add default validators here, because this feature
// is only available in facelets (see MYFACES-2362 for details)
- addDefaultValidators(facesContext, (EditableValueHolder) c);
+ addDefaultValidators(facesContext, actx, (EditableValueHolder) c);
}
_delegate.onComponentPopulated(ctx, c, parent);
@@ -447,9 +448,11 @@
* Add the default Validators to the component.
*
* @param context The FacesContext.
+ * @param actx the AbstractFaceletContext
* @param component The EditableValueHolder to which the validators should be added
*/
- private void addDefaultValidators(FacesContext context, EditableValueHolder component)
+ private void addDefaultValidators(FacesContext context, AbstractFaceletContext actx,
+ EditableValueHolder component)
{
Application application = context.getApplication();
Map<String, String> defaultValidators = application.getDefaultValidatorInfo();
@@ -460,9 +463,77 @@
{
String validatorId = entry.getKey();
String validatorClassName = entry.getValue();
- if (shouldAddDefaultValidator(validatorId, validatorClassName, context, component))
+
+ if (shouldAddDefaultValidator(validatorId, validatorClassName, context, actx, component))
{
- component.addValidator(application.createValidator(validatorId));
+ Validator validator = null;
+ boolean created = false;
+ // check if the validator is already registered for the given component
+ for (Validator v : component.getValidators())
+ {
+ if (v.getClass().getName().equals(validatorClassName))
+ {
+ // found
+ validator = v;
+ break;
+ }
+ }
+ if (validator == null)
+ {
+ // create it
+ validator = application.createValidator(validatorId);
+ created = true;
+ }
+
+ // special things to do for a BeanValidator
+ if (validator instanceof BeanValidator)
+ {
+ BeanValidator beanValidator = (BeanValidator) validator;
+
+ // add validation groups from stack
+ Iterator<String> itValidationGroups = actx.getValidationGroups();
+ if (itValidationGroups != null && itValidationGroups.hasNext())
+ {
+ // we use a Set to eliminate duplicates
+ Set<String> groupsSet = new HashSet<String>();
+
+ // add any existing validationGroups to Set first
+ String validationGroups = beanValidator.getValidationGroups();
+ if (validationGroups != null)
+ {
+ addValidationGroups(validationGroups, groupsSet);
+ }
+ while (itValidationGroups.hasNext())
+ {
+ // note that the validationGroups from the stack are non-null
+ validationGroups = itValidationGroups.next();
+ addValidationGroups(validationGroups, groupsSet);
+ }
+
+ // join validationGroups and add them to beanValidator
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for (String group : groupsSet)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ sb.append(BeanValidator.VALIDATION_GROUPS_DELIMITER);
+ }
+ sb.append(group);
+ }
+ beanValidator.setValidationGroups(sb.toString());
+ }
+ }
+
+ if (created)
+ {
+ // add the validator to the component
+ component.addValidator(validator);
+ }
}
}
}
@@ -474,18 +545,25 @@
* @param validatorId The validatorId.
* @param validatorClassName The class name of the validator.
* @param context The FacesContext.
+ * @param actx the AbstractFaceletContext
* @param component The EditableValueHolder to which the validator should be added.
* @return true if the Validator should be added, false otherwise.
*/
private boolean shouldAddDefaultValidator(String validatorId, String validatorClassName,
- FacesContext context, EditableValueHolder component)
+ FacesContext context, AbstractFaceletContext actx,
+ EditableValueHolder component)
{
- // check if the validator is already registered for the given component
- for (Validator v : component.getValidators())
- {
- if (v.getClass().getName().equals(validatorClassName))
+ // check if the validatorId is on the exclusion list
+ Iterator<String> it = actx.getExcludedValidatorIds();
+ if (it != null)
+ {
+ while (it.hasNext())
{
- return false;
+ String excludedId = it.next();
+ if (excludedId.equals(validatorId))
+ {
+ return false;
+ }
}
}
@@ -509,6 +587,21 @@
}
/**
+ * Splits the validationGroups String with BeanValidator.VALIDATION_GROUPS_DELIMITER
+ * and then trims and adds every String in the resulting array to the Set.
+ * @param validationGroups
+ * @param set
+ */
+ private void addValidationGroups(String validationGroups, Set<String> set)
+ {
+ String[] sa = validationGroups.split(BeanValidator.VALIDATION_GROUPS_DELIMITER);
+ for (String group : sa)
+ {
+ set.add(group.trim());
+ }
+ }
+
+ /**
* Create a new UIPanel for the use as a dynamically
* created container for multiple children in a facet.
* Duplicate in javax.faces.webapp.UIComponentClassicTagBase.
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ValidatorTagHandlerDelegate.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ValidatorTagHandlerDelegate.java?rev=901400&r1=901399&r2=901400&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ValidatorTagHandlerDelegate.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ValidatorTagHandlerDelegate.java Wed Jan 20 22:08:12 2010
@@ -34,6 +34,8 @@
import javax.faces.view.facelets.TagHandlerDelegate;
import javax.faces.view.facelets.ValidatorHandler;
+import org.apache.myfaces.view.facelets.AbstractFaceletContext;
+import org.apache.myfaces.view.facelets.compiler.FaceletsCompilerUtils;
import org.apache.myfaces.view.facelets.tag.MetaRulesetImpl;
import org.apache.myfaces.view.facelets.tag.composite.CompositeComponentResourceTagHandler;
@@ -52,46 +54,108 @@
{
private ValidatorHandler _delegate;
+ /**
+ * true - this tag has children
+ * false - this tag is a leave
+ */
+ private final boolean _wrapMode;
+
public ValidatorTagHandlerDelegate(ValidatorHandler delegate)
{
_delegate = delegate;
+
+ // According to jsf 2.0 spec section 10.4.1.4
+ // this tag can be used as a leave within an EditableValueHolder
+ // or as a container to provide validator information for all
+ // EditableValueHolder-children (and grandchildren and ...)
+ // (this behavior is analog to <f:ajax>)
+ // --> Determine if we have children:
+ _wrapMode = FaceletsCompilerUtils.hasChildren(_delegate.getValidatorConfig());
}
@Override
public void apply(FaceletContext ctx, UIComponent parent) throws IOException
{
+ // Apply only if we are creating a new component
if (!ComponentHandler.isNew(parent))
{
return;
}
- if (parent instanceof EditableValueHolder)
+ if (_wrapMode)
{
- applyAttachedObject(ctx.getFacesContext(), parent);
- }
- else if (UIComponent.isCompositeComponent(parent))
- {
- CompositeComponentResourceTagHandler.addAttachedObjectHandler(parent, _delegate);
+ // the tag has children --> provide validator information for all children
+
+ // FIXME the spec says we should save the validation groups in an attribute
+ // on the parent UIComponent, but this will be a problem in the following scenario:
+ // <h:form>
+ // <f:validateBean>
+ // <h:inputText />
+ // </f:validateBean>
+ // <h:inputText />
+ // </h:form>
+ // because the validator would also be applied to the second h:inputText,
+ // which it should not, on my opinion. In addition, mojarra also does not
+ // attach the validator to the second h:inputText in this scenario (blackbox test).
+ // So I use the same way as f:ajax for this problem. -=Jakob Korherr=-
+
+ // we need methods from AbstractFaceletContext
+ AbstractFaceletContext abstractCtx = (AbstractFaceletContext) ctx;
+
+ boolean disabled = _delegate.isDisabled(ctx);
+ if (disabled)
+ {
+ // the validator is disabled --> add its id to the exclusion stack
+ String validatorId = _delegate.getValidatorConfig().getValidatorId();
+ if (validatorId != null && !"".equals(validatorId))
+ {
+ abstractCtx.pushExcludedValidatorIdToStack(validatorId);
+ _delegate.getValidatorConfig().getNextHandler().apply(ctx, parent);
+ abstractCtx.popExcludedValidatorIdToStack();
+ }
+ }
+ else
+ {
+ // the validator is enabled --> add the validation groups to the stack
+ String groups = getValidationGroups(ctx);
+ // spec: don't save the validation groups string if it is null or empty string
+ if (groups != null && !"".equals(groups))
+ {
+ abstractCtx.pushValidationGroupsToStack(groups);
+ _delegate.getValidatorConfig().getNextHandler().apply(ctx, parent);
+ abstractCtx.popValidationGroupsToStack();
+ }
+ }
}
else
{
- throw new TagException(_delegate.getTag(), "Parent not composite component or an instance of EditableValueHolder: " + parent);
+ // the tag is a leave --> attach validator to parent
+ if (parent instanceof EditableValueHolder)
+ {
+ applyAttachedObject(ctx.getFacesContext(), parent);
+ }
+ else if (UIComponent.isCompositeComponent(parent))
+ {
+ CompositeComponentResourceTagHandler.addAttachedObjectHandler(parent, _delegate);
+ }
+ else
+ {
+ throw new TagException(_delegate.getTag(), "Parent not composite component or an instance of EditableValueHolder: " + parent);
+ }
}
}
/**
* Template method for creating a Validator instance
*
- * @param ctx
- * FaceletContext to use
+ * @param ctx FaceletContext to use
* @return a new Validator instance
*/
protected Validator createValidator(FaceletContext ctx)
{
if (_delegate.getValidatorId(ctx) == null)
{
- throw new TagException(
- _delegate.getTag(),
- "Default behavior invoked of requiring a validator-id passed in the constructor, must override ValidateHandler(ValidatorConfig)");
+ throw new TagException(_delegate.getTag(), "Default behavior invoked of requiring " +
+ "a validator-id passed in the constructor, must override ValidateHandler(ValidatorConfig)");
}
return ctx.getFacesContext().getApplication().createValidator(_delegate.getValidatorId(ctx));
}
@@ -130,7 +194,7 @@
throw new TagException(_delegate.getTag(), "No Validator was created");
}
_delegate.setAttributes(faceletContext, v);
- evh.addValidator(v);
+ evh.addValidator(v);
}
public String getFor()
@@ -146,5 +210,19 @@
return forAttribute.getValue();
}
}
+
+ public String getValidationGroups(FaceletContext ctx)
+ {
+ TagAttribute attribute = _delegate.getTagAttribute("validationGroups");
+
+ if (attribute == null)
+ {
+ return null;
+ }
+ else
+ {
+ return attribute.getValue(ctx);
+ }
+ }
}