[seam-commits] Seam SVN: r13193 - in examples/trunk/booking-simplified/src/main: java/org/jboss/seam/examples/booking/account and 3 other directories.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Wed Jun 16 16:00:41 EDT 2010


Author: lincolnthree
Date: 2010-06-16 16:00:40 -0400 (Wed, 16 Jun 2010)
New Revision: 13193

Added:
   examples/trunk/booking-simplified/src/main/java/org/jboss/seam/examples/booking/account/PasswordConfirmValidator.java
   examples/trunk/booking-simplified/src/main/java/org/jboss/seam/faces/
   examples/trunk/booking-simplified/src/main/java/org/jboss/seam/faces/component/
   examples/trunk/booking-simplified/src/main/java/org/jboss/seam/faces/component/UIInputContainer.java
Modified:
   examples/trunk/booking-simplified/src/main/java/org/jboss/seam/examples/booking/account/PasswordManagerBean.java
   examples/trunk/booking-simplified/src/main/webapp/password.xhtml
Log:
XVal for passwords

Added: examples/trunk/booking-simplified/src/main/java/org/jboss/seam/examples/booking/account/PasswordConfirmValidator.java
===================================================================
--- examples/trunk/booking-simplified/src/main/java/org/jboss/seam/examples/booking/account/PasswordConfirmValidator.java	                        (rev 0)
+++ examples/trunk/booking-simplified/src/main/java/org/jboss/seam/examples/booking/account/PasswordConfirmValidator.java	2010-06-16 20:00:40 UTC (rev 13193)
@@ -0,0 +1,71 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc., and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.seam.examples.booking.account;
+
+import javax.faces.application.FacesMessage;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.validator.FacesValidator;
+import javax.faces.validator.Validator;
+import javax.faces.validator.ValidatorException;
+import javax.inject.Inject;
+
+import org.jboss.seam.examples.booking.model.User;
+import org.jboss.seam.faces.validation.InputField;
+
+/**
+ * @author <a href="mailto:lincolnbaxter at gmail.com">Lincoln Baxter, III</a>
+ * 
+ */
+ at FacesValidator(value = "passwordConfirmValidator")
+public class PasswordConfirmValidator implements Validator
+{
+   @Inject
+   @Authenticated
+   User currentUser;
+
+   @Inject
+   @InputField
+   private String oldPassword;
+
+   @Inject
+   @InputField
+   private String newPassword;
+
+   @Inject
+   @InputField
+   private String confirmNewPassword;
+
+   public void validate(final FacesContext context, final UIComponent comp, final Object components) throws ValidatorException
+   {
+      if ((currentUser.getPassword() != null) && currentUser.getPassword().equals(oldPassword))
+      {
+         throw new ValidatorException(new FacesMessage("Your original password was incorrect."));
+      }
+
+      if ((newPassword != null) && !newPassword.equals(confirmNewPassword))
+      {
+         throw new ValidatorException(new FacesMessage("New passwords did not match."));
+      }
+   }
+
+}

Modified: examples/trunk/booking-simplified/src/main/java/org/jboss/seam/examples/booking/account/PasswordManagerBean.java
===================================================================
--- examples/trunk/booking-simplified/src/main/java/org/jboss/seam/examples/booking/account/PasswordManagerBean.java	2010-06-16 19:32:21 UTC (rev 13192)
+++ examples/trunk/booking-simplified/src/main/java/org/jboss/seam/examples/booking/account/PasswordManagerBean.java	2010-06-16 20:00:40 UTC (rev 13193)
@@ -39,19 +39,11 @@
 
    public void changePassword()
    {
-      if (user.getPassword().equals(confirmPassword))
-      {
-         em.merge(user);
-         messages.info(new BundleKey("messages.properties", "account.passwordChanged")).textDefault("Password successfully updated.");
-         changed = true;
-      }
-      else
-      {
-         // FIXME reverting isn't going to work here
-         // revertUser();
-         confirmPassword = null;
-         messages.error(new BundleKey("messages.properties", "account.passwordsDoNotMatch")).textDefault("Passwords do not match. Please re-type the new password.");
-      }
+      em.merge(user);
+      messages.info(new BundleKey("messages.properties", "account.passwordChanged")).textDefault("Password successfully updated.");
+      changed = true;
+      // messages.error(new BundleKey("messages.properties",
+      // "account.passwordsDoNotMatch")).textDefault("Passwords do not match. Please re-type the new password.");
    }
 
    public boolean isChanged()

Added: examples/trunk/booking-simplified/src/main/java/org/jboss/seam/faces/component/UIInputContainer.java
===================================================================
--- examples/trunk/booking-simplified/src/main/java/org/jboss/seam/faces/component/UIInputContainer.java	                        (rev 0)
+++ examples/trunk/booking-simplified/src/main/java/org/jboss/seam/faces/component/UIInputContainer.java	2010-06-16 20:00:40 UTC (rev 13193)
@@ -0,0 +1,548 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc., and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.seam.faces.component;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.el.ValueReference;
+import javax.faces.FacesException;
+import javax.faces.application.FacesMessage;
+import javax.faces.component.EditableValueHolder;
+import javax.faces.component.FacesComponent;
+import javax.faces.component.NamingContainer;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIComponentBase;
+import javax.faces.component.UIMessage;
+import javax.faces.component.UINamingContainer;
+import javax.faces.component.UIViewRoot;
+import javax.faces.component.html.HtmlOutputLabel;
+import javax.faces.context.FacesContext;
+import javax.faces.validator.BeanValidator;
+import javax.validation.Validation;
+import javax.validation.ValidationException;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+import javax.validation.metadata.PropertyDescriptor;
+
+/**
+ * <strong>UIInputContainer</strong> is a supplemental component for a JSF 2.0
+ * composite component encapsulating one or more input components
+ * (<strong>EditableValueHolder</strong>), their corresponding message
+ * components (<strong>UIMessage</strong>) and a label
+ * (<strong>HtmlOutputLabel</strong>). This component takes care of wiring the
+ * label to the first input and the messages to each input in sequence. It also
+ * assigns two implicit attribute values, "required" and "invalid" to indicate
+ * that a required input field is present and whether there are any validation
+ * errors, respectively. To determine if a input field is required, both the
+ * required attribute is consulted and whether the property has Bean Validation
+ * constraints. Finally, if the "label" attribute is not provided on the
+ * composite component, the label value will be derived from the id of the
+ * composite component, for convenience.
+ * 
+ * <p>
+ * Composite component definition example (minus layout):
+ * </p>
+ * 
+ * <pre>
+ * &lt;cc:interface componentType="org.jboss.seam.faces.InputContainer"/>
+ * &lt;cc:implementation>
+ *   &lt;h:outputLabel id="label" value="#{cc.attrs.label}:" styleClass="#{cc.attrs.invalid ? 'invalid' : ''}">
+ *     &lt;h:ouputText styleClass="required" rendered="#{cc.attrs.required}" value="*"/>
+ *   &lt;/h:outputLabel>
+ *   &lt;cc:insertChildren/>
+ *   &lt;h:message id="message" errorClass="invalid message" rendered="#{cc.attrs.invalid}"/>
+ * &lt;/cc:implementation>
+ * </pre>
+ * 
+ * <p>
+ * Composite component usage example:
+ * </p>
+ * 
+ * <pre>
+ * &lt;example:inputContainer id="name">
+ *   &lt;h:inputText id="input" value="#{person.name}"/>
+ * &lt;/example:inputContainer>
+ * </pre>
+ * 
+ * <p>
+ * Possible enhancements:
+ * </p>
+ * <ul>
+ * <li>append styleClass "invalid" to label, inputs and messages when invalid</li>
+ * </ul>
+ * 
+ * <p>
+ * NOTE: Firefox does not properly associate a label with the target input if
+ * the input id contains a colon (:), the default separator character in JSF.
+ * JSF 2 allows developers to set the value via an initialization parameter
+ * (context-param in web.xml) keyed to javax.faces.SEPARATOR_CHAR. We recommend
+ * that you override this setting to make the separator an underscore (_).
+ * </p>
+ * 
+ * @author Dan Allen
+ */
+ at FacesComponent(UIInputContainer.COMPONENT_TYPE)
+public class UIInputContainer extends UIComponentBase implements NamingContainer
+{
+   /**
+    * The standard component type for this component.
+    */
+   public static final String COMPONENT_TYPE = "org.jboss.seam.faces.InputContainer";
+
+   protected static final String HTML_ID_ATTR_NAME = "id";
+   protected static final String HTML_CLASS_ATTR_NAME = "class";
+   protected static final String HTML_STYLE_ATTR_NAME = "style";
+
+   private boolean beanValidationPresent = false;
+
+   public UIInputContainer()
+   {
+      beanValidationPresent = isClassPresent("javax.validation.Validator");
+   }
+
+   @Override
+   public String getFamily()
+   {
+      return UINamingContainer.COMPONENT_FAMILY;
+   }
+
+   /**
+    * The name of the auto-generated composite component attribute that holds a
+    * boolean indicating whether the the template contains an invalid input.
+    */
+   public String getInvalidAttributeName()
+   {
+      return "invalid";
+   }
+
+   /**
+    * The name of the auto-generated composite component attribute that holds a
+    * boolean indicating whether the template contains a required input.
+    */
+   public String getRequiredAttributeName()
+   {
+      return "required";
+   }
+
+   /**
+    * The name of the composite component attribute that holds the string label
+    * for this set of inputs. If the label attribute is not provided, one will
+    * be generated from the id of the composite component or, if the id is
+    * defaulted, the name of the property bound to the first input.
+    */
+   public String getLabelAttributeName()
+   {
+      return "label";
+   }
+
+   /**
+    * The name of the auto-generated composite component attribute that holds
+    * the elements in this input container. The elements include the label, a
+    * list of inputs and a cooresponding list of messages.
+    */
+   public String getElementsAttributeName()
+   {
+      return "elements";
+   }
+
+   /**
+    * The name of the composite component attribute that holds a boolean
+    * indicating whether the component template should be enclosed in an HTML
+    * element, so that it be referenced from JavaScript.
+    */
+   public String getEncloseAttributeName()
+   {
+      return "enclose";
+   }
+
+   public String getContainerElementName()
+   {
+      return "div";
+   }
+
+   public String getDefaultLabelId()
+   {
+      return "label";
+   }
+
+   public String getDefaultInputId()
+   {
+      return "input";
+   }
+
+   public String getDefaultMessageId()
+   {
+      return "message";
+   }
+
+   @Override
+   public void encodeBegin(final FacesContext context) throws IOException
+   {
+      if (!isRendered())
+      {
+         return;
+      }
+
+      super.encodeBegin(context);
+
+      InputContainerElements elements = scan(getFacet(UIComponent.COMPOSITE_FACET_NAME), null, context);
+      // assignIds(elements, context);
+      wire(elements, context);
+
+      getAttributes().put(getElementsAttributeName(), elements);
+
+      if (elements.hasValidationError())
+      {
+         getAttributes().put(getInvalidAttributeName(), true);
+      }
+
+      // set the required attribute, but only if the user didn't already assign
+      // it
+      if (!getAttributes().containsKey(getRequiredAttributeName()) && elements.hasRequiredInput())
+      {
+         getAttributes().put(getRequiredAttributeName(), true);
+      }
+
+      if (!getAttributes().containsKey(getLabelAttributeName()))
+      {
+         getAttributes().put(getLabelAttributeName(), generateLabel(elements, context));
+      }
+
+      if (Boolean.TRUE.equals(getAttributes().get(getEncloseAttributeName())))
+      {
+         startContainerElement(context);
+      }
+   }
+
+   @Override
+   public void encodeEnd(final FacesContext context) throws IOException
+   {
+      if (!isRendered())
+      {
+         return;
+      }
+
+      super.encodeEnd(context);
+
+      if (Boolean.TRUE.equals(getAttributes().get(getEncloseAttributeName())))
+      {
+         endContainerElement(context);
+      }
+   }
+
+   protected void startContainerElement(final FacesContext context) throws IOException
+   {
+      context.getResponseWriter().startElement(getContainerElementName(), this);
+      String style = (getAttributes().get("style") != null ? getAttributes().get("style").toString().trim() : null);
+      if (style.length() > 0)
+      {
+         context.getResponseWriter().writeAttribute(HTML_STYLE_ATTR_NAME, style, HTML_STYLE_ATTR_NAME);
+      }
+      String styleClass = (getAttributes().get("styleClass") != null ? getAttributes().get("styleClass").toString().trim() : null);
+      if (styleClass.length() > 0)
+      {
+         context.getResponseWriter().writeAttribute(HTML_CLASS_ATTR_NAME, styleClass, HTML_CLASS_ATTR_NAME);
+      }
+      context.getResponseWriter().writeAttribute(HTML_ID_ATTR_NAME, getClientId(context), HTML_ID_ATTR_NAME);
+   }
+
+   protected void endContainerElement(final FacesContext context) throws IOException
+   {
+      context.getResponseWriter().endElement(getContainerElementName());
+   }
+
+   protected String generateLabel(final InputContainerElements elements, final FacesContext context)
+   {
+      String name = getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX) ? elements.getPropertyName(context) : getId();
+      return name.substring(0, 1).toUpperCase() + name.substring(1);
+   }
+
+   /**
+    * Walk the component tree branch built by the composite component and locate
+    * the input container elements.
+    * 
+    * @return a composite object of the input container elements
+    */
+   protected InputContainerElements scan(final UIComponent component, InputContainerElements elements, final FacesContext context)
+   {
+      if (elements == null)
+      {
+         elements = new InputContainerElements();
+      }
+
+      // NOTE we need to walk the tree ignoring rendered attribute because it's
+      // condition
+      // could be based on what we discover
+      if ((elements.getLabel() == null) && (component instanceof HtmlOutputLabel))
+      {
+         elements.setLabel((HtmlOutputLabel) component);
+      }
+      else if (component instanceof EditableValueHolder)
+      {
+         elements.registerInput((EditableValueHolder) component, getDefaultValidator(context), context);
+      }
+      else if (component instanceof UIMessage)
+      {
+         elements.registerMessage((UIMessage) component);
+      }
+      // may need to walk smarter to ensure "element of least suprise"
+      for (UIComponent child : component.getChildren())
+      {
+         scan(child, elements, context);
+      }
+
+      return elements;
+   }
+
+   // assigning ids seems to break form submissions, but I don't know why
+   public void assignIds(final InputContainerElements elements, final FacesContext context)
+   {
+      boolean refreshIds = false;
+      if (getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
+      {
+         setId(elements.getPropertyName(context));
+         refreshIds = true;
+      }
+      UIComponent label = elements.getLabel();
+      if (label != null)
+      {
+         if (label.getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
+         {
+            label.setId(getDefaultLabelId());
+         }
+         else if (refreshIds)
+         {
+            label.setId(label.getId());
+         }
+      }
+      for (int i = 0, len = elements.getInputs().size(); i < len; i++)
+      {
+         UIComponent input = (UIComponent) elements.getInputs().get(i);
+         if (input.getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
+         {
+            input.setId(getDefaultInputId() + (i == 0 ? "" : (i + 1)));
+         }
+         else if (refreshIds)
+         {
+            input.setId(input.getId());
+         }
+      }
+      for (int i = 0, len = elements.getMessages().size(); i < len; i++)
+      {
+         UIComponent msg = elements.getMessages().get(i);
+         if (msg.getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
+         {
+            msg.setId(getDefaultMessageId() + (i == 0 ? "" : (i + 1)));
+         }
+         else if (refreshIds)
+         {
+            msg.setId(msg.getId());
+         }
+      }
+   }
+
+   /**
+    * Wire the label and messages to the input(s)
+    */
+   protected void wire(final InputContainerElements elements, final FacesContext context)
+   {
+      elements.wire(context);
+   }
+
+   /**
+    * Get the default Bean Validation Validator to read the contraints for a
+    * property.
+    */
+   private Validator getDefaultValidator(final FacesContext context) throws FacesException
+   {
+      if (!beanValidationPresent)
+      {
+         return null;
+      }
+
+      ValidatorFactory validatorFactory;
+      Object cachedObject = context.getExternalContext().getApplicationMap().get(BeanValidator.VALIDATOR_FACTORY_KEY);
+      if (cachedObject instanceof ValidatorFactory)
+      {
+         validatorFactory = (ValidatorFactory) cachedObject;
+      }
+      else
+      {
+         try
+         {
+            validatorFactory = Validation.buildDefaultValidatorFactory();
+         }
+         catch (ValidationException e)
+         {
+            throw new FacesException("Could not build a default Bean Validator factory", e);
+         }
+         context.getExternalContext().getApplicationMap().put(BeanValidator.VALIDATOR_FACTORY_KEY, validatorFactory);
+      }
+      return validatorFactory.getValidator();
+   }
+
+   private boolean isClassPresent(final String fqcn)
+   {
+      try
+      {
+         if (Thread.currentThread().getContextClassLoader() != null)
+         {
+            return Thread.currentThread().getContextClassLoader().loadClass(fqcn) != null;
+         }
+         else
+         {
+            return Class.forName(fqcn) != null;
+         }
+      }
+      catch (ClassNotFoundException e)
+      {
+         return false;
+      }
+      catch (NoClassDefFoundError e)
+      {
+         return false;
+      }
+   }
+
+   public static class InputContainerElements
+   {
+      private String propertyName;
+      private HtmlOutputLabel label;
+      private final List<EditableValueHolder> inputs = new ArrayList<EditableValueHolder>();
+      private final List<UIMessage> messages = new ArrayList<UIMessage>();
+      private boolean validationError = false;
+      private boolean requiredInput = false;
+
+      public HtmlOutputLabel getLabel()
+      {
+         return label;
+      }
+
+      public void setLabel(final HtmlOutputLabel label)
+      {
+         this.label = label;
+      }
+
+      public List<EditableValueHolder> getInputs()
+      {
+         return inputs;
+      }
+
+      public void registerInput(final EditableValueHolder input, final Validator validator, final FacesContext context)
+      {
+         inputs.add(input);
+         if (input.isRequired() || isRequiredByConstraint(input, validator, context))
+         {
+            requiredInput = true;
+         }
+         if (!input.isValid())
+         {
+            validationError = true;
+         }
+         // optimization to avoid loop if already flagged
+         else if (!validationError)
+         {
+            Iterator<FacesMessage> it = context.getMessages(((UIComponent) input).getClientId(context));
+            while (it.hasNext())
+            {
+               if (it.next().getSeverity().compareTo(FacesMessage.SEVERITY_WARN) >= 0)
+               {
+                  validationError = true;
+                  break;
+               }
+            }
+         }
+      }
+
+      public List<UIMessage> getMessages()
+      {
+         return messages;
+      }
+
+      public void registerMessage(final UIMessage message)
+      {
+         messages.add(message);
+      }
+
+      public boolean hasValidationError()
+      {
+         return validationError;
+      }
+
+      public boolean hasRequiredInput()
+      {
+         return requiredInput;
+      }
+
+      private boolean isRequiredByConstraint(final EditableValueHolder input, final Validator validator, final FacesContext context)
+      {
+         if (validator == null)
+         {
+            return false;
+         }
+
+         // NOTE believe it or not, getValueReference on ValueExpression is
+         // broken, so we have to do it ourselves
+         ValueReference vref = new ValueExpressionAnalyzer(((UIComponent) input).getValueExpression("value")).getValueReference(context.getELContext());
+         PropertyDescriptor d = validator.getConstraintsForClass(vref.getBase().getClass()).getConstraintsForProperty((String) vref.getProperty());
+         return (d != null) && d.hasConstraints();
+      }
+
+      public String getPropertyName(final FacesContext context)
+      {
+         if (propertyName != null)
+         {
+            return propertyName;
+         }
+
+         if (inputs.size() == 0)
+         {
+            return null;
+         }
+
+         propertyName = (String) new ValueExpressionAnalyzer(((UIComponent) inputs.get(0)).getValueExpression("value")).getValueReference(context.getELContext()).getProperty();
+         return propertyName;
+      }
+
+      public void wire(final FacesContext context)
+      {
+         int numInputs = inputs.size();
+         if (numInputs > 0)
+         {
+            if (label != null)
+            {
+               label.setFor(((UIComponent) inputs.get(0)).getClientId(context));
+            }
+            for (int i = 0, len = messages.size(); i < len; i++)
+            {
+               if (i < numInputs)
+               {
+                  messages.get(i).setFor(((UIComponent) inputs.get(i)).getClientId(context));
+               }
+            }
+         }
+      }
+   }
+}

Modified: examples/trunk/booking-simplified/src/main/webapp/password.xhtml
===================================================================
--- examples/trunk/booking-simplified/src/main/webapp/password.xhtml	2010-06-16 19:32:21 UTC (rev 13192)
+++ examples/trunk/booking-simplified/src/main/webapp/password.xhtml	2010-06-16 20:00:40 UTC (rev 13193)
@@ -4,6 +4,7 @@
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
+   xmlns:s="http://jboss.org/seam/faces"
    xmlns:p="http://http://java.sun.com/jsf/composite/components/property"
    template="/WEB-INF/layout/template.xhtml">
 
@@ -23,13 +24,16 @@
          
             <fieldset>
             
-               <p:input id="password">
-                  <h:inputSecret id="input" value="#{currentUser.password}" redisplay="true"/>
+               <p:input id="old">
+                  <h:inputSecret id="password"  value="#{currentUser.password}" />
                </p:input>
+            
+               <p:input id="new">
+                  <h:inputSecret id="password" value="#{currentUser.password}" redisplay="true"/>
+               </p:input>
 
-               <p:input id="confirmPassword">
-                  <h:inputSecret id="input" value="#{passwordManager.confirmPassword}" redisplay="true"
-                     binding="#{registrationFormControls.confirmPassword}"/>
+               <p:input id="confirm">
+                  <h:inputSecret id="password" value="#{currentUser.password}" redisplay="true" />
                </p:input>
 
                <div class="buttonBox">
@@ -40,6 +44,8 @@
                
             </fieldset>
             
+            <s:validateForm validatorId="passwordConfirmValidator" 
+            	fields="oldPassword=old:password newPassword=new:password confirmNewPassword=confirm:password"/>
          </h:form>
       </div>
 



More information about the seam-commits mailing list