Author: danielc.roth
Date: 2008-10-08 15:37:15 -0400 (Wed, 08 Oct 2008)
New Revision: 9233
Added:
trunk/examples/ui/src/org/jboss/seam/example/ui/EqualityValidatorBean.java
trunk/examples/ui/view/equalityValidator.xhtml
trunk/ui/src/main/config/component/equalityValidator.xml
trunk/ui/src/main/java/org/jboss/seam/ui/validator/EqualityValidator.java
Modified:
trunk/doc/Seam_Reference_Guide/en-US/Controls.xml
trunk/examples/ui/view/template.xhtml
Log:
JBSEAM-2809
EqualityValidator + example + docs
Modified: trunk/doc/Seam_Reference_Guide/en-US/Controls.xml
===================================================================
--- trunk/doc/Seam_Reference_Guide/en-US/Controls.xml 2008-10-08 18:43:43 UTC (rev 9232)
+++ trunk/doc/Seam_Reference_Guide/en-US/Controls.xml 2008-10-08 19:37:15 UTC (rev 9233)
@@ -474,7 +474,47 @@
</h:outputText>]]></programlisting>
</section>
+
<section>
+
<title><literal><s:equalityValidator></literal></title>
+
+ <para><emphasis>Description</emphasis></para>
+ <para>
+ Tag to nest inside an input control to validate that its parent's
+ value is the same as the referenced control's id.
+ </para>
+
+ <para><emphasis>Attributes</emphasis></para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>for</literal> — The id of a control
to validate against.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>message</literal> — Message to show
on failure.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>messageId</literal> — Message id to
show on failure.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para><emphasis>Usage</emphasis></para>
+ <programlisting><![CDATA[<h:inputText id="name"
value="#{bean.name}"/>
+<h:inputText id="nameVerification" >
+ <s:validateEquality for="name" />
+</h:inputText>]]></programlisting>
+ </section>
+
+
+
+
+
+ <section>
<title><literal><s:validate></literal></title>
<para><emphasis>Description</emphasis></para>
@@ -933,6 +973,7 @@
</section>
+
<section>
<title><literal><s:fileUpload></literal></title>
Added: trunk/examples/ui/src/org/jboss/seam/example/ui/EqualityValidatorBean.java
===================================================================
--- trunk/examples/ui/src/org/jboss/seam/example/ui/EqualityValidatorBean.java
(rev 0)
+++ trunk/examples/ui/src/org/jboss/seam/example/ui/EqualityValidatorBean.java 2008-10-08
19:37:15 UTC (rev 9233)
@@ -0,0 +1,59 @@
+package org.jboss.seam.example.ui;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.international.StatusMessages;
+import org.jboss.seam.international.StatusMessage.Severity;
+import org.jboss.seam.util.Strings;
+
+@Name("equalityValidatorBean")
+(a)Scope(ScopeType.SESSION)
+public class EqualityValidatorBean
+{
+
+ private String name;
+
+ private String nameVerification;
+
+ @In
+ private StatusMessages statusMessages;
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public String getNameVerification()
+ {
+ return nameVerification;
+ }
+
+ public void setNameVerification(String nameVerification)
+ {
+ this.nameVerification = nameVerification;
+ }
+
+ public void check()
+ {
+ if (Strings.isEmpty(name))
+ {
+ statusMessages.addToControl("name", Severity.WARN, "Enter a
name!");
+ }
+ if (Strings.isEmpty(nameVerification))
+ {
+ statusMessages.addToControl("nameVerification", Severity.WARN,
"Enter a name verification!");
+ }
+ if (name != null && nameVerification != null &&
!name.equals(nameVerification))
+ {
+ statusMessages.addToControl("nameVerification", Severity.WARN,
"Name and Name Verification not equal (should have been caught by equality
validator!)");
+ }
+ }
+
+}
Added: trunk/examples/ui/view/equalityValidator.xhtml
===================================================================
--- trunk/examples/ui/view/equalityValidator.xhtml (rev 0)
+++ trunk/examples/ui/view/equalityValidator.xhtml 2008-10-08 19:37:15 UTC (rev 9233)
@@ -0,0 +1,25 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
+
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.com/products/seam/taglib"
+ template="template.xhtml">
+ <ui:param name="tagName" value="s:validateEquality" />
+ <ui:define name="body">
+ <p>Validates that two inputs are equal</p>
+ <h:form>
+ <h:panelGrid columns="3">
+ <s:label for="name">Name</s:label>
+ <h:inputText id="name" value="#{equalityValidatorBean.name}"
/>
+ <h:message for="name" />
+ <s:label for="nameVerification">Name Verification</s:label>
+ <h:inputText id="nameVerification"
value="#{equalityValidatorBean.nameVerification}">
+ <s:validateEquality for="name" />
+ </h:inputText>
+ <h:message for="nameVerification" />
+ <h:commandButton action="#{equalityValidatorBean.check}"
value="Check name" />
+ </h:panelGrid>
+ </h:form>
+ </ui:define>
+</ui:composition>
Modified: trunk/examples/ui/view/template.xhtml
===================================================================
--- trunk/examples/ui/view/template.xhtml 2008-10-08 18:43:43 UTC (rev 9232)
+++ trunk/examples/ui/view/template.xhtml 2008-10-08 19:37:15 UTC (rev 9233)
@@ -97,6 +97,11 @@
<code>s:graphicImage</code>
<f:param name="personId" value="1" />
</s:link></li>
+
+ <li><s:link view="/equalityValidator.xhtml">
+ <code>s:equalityValidator</code>
+ </s:link></li>
+
</ul>
</s:div>
<s:div styleClass="content">
Added: trunk/ui/src/main/config/component/equalityValidator.xml
===================================================================
--- trunk/ui/src/main/config/component/equalityValidator.xml (rev
0)
+++ trunk/ui/src/main/config/component/equalityValidator.xml 2008-10-08 19:37:15 UTC (rev
9233)
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE components PUBLIC "-//AJAX4JSF//CDK Generator config/EN"
"http://jboss.org/jbossrichfaces/component-config.dtd" >
+<components>
+ <validator generate="false">
+ <id>org.jboss.seam.ui.EqualityValidator</id>
+ <classname>org.jboss.seam.ui.validator.EqualityValidator</classname>
+ <description>
+ <![CDATA[Validate that the value of two components are equal]]>
+ </description>
+ <tag>
+ <name>validateEquality</name>
+ <classname>org.jboss.seam.ui.taglib.ModelValidatorTag</classname>
+ <superclass>javax.faces.webapp.ValidatorELTag</superclass>
+ </tag>
+ </validator>
+</components>
Added: trunk/ui/src/main/java/org/jboss/seam/ui/validator/EqualityValidator.java
===================================================================
--- trunk/ui/src/main/java/org/jboss/seam/ui/validator/EqualityValidator.java
(rev 0)
+++ trunk/ui/src/main/java/org/jboss/seam/ui/validator/EqualityValidator.java 2008-10-08
19:37:15 UTC (rev 9233)
@@ -0,0 +1,295 @@
+package org.jboss.seam.ui.validator;
+
+import javax.el.ELException;
+import javax.el.ValueExpression;
+import javax.faces.FacesException;
+import javax.faces.application.Application;
+import javax.faces.component.EditableValueHolder;
+import javax.faces.component.StateHolder;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+import javax.faces.convert.ConverterException;
+import javax.faces.render.Renderer;
+import javax.faces.validator.Validator;
+import javax.faces.validator.ValidatorException;
+
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+
+/**
+ * Validate two fields are equal
+ *
+ * @author pmuir
+ *
+ */
+public class EqualityValidator implements Validator, StateHolder
+{
+
+ private static LogProvider log = Logging.getLogProvider(EqualityValidator.class);
+
+ public static final String MESSAGE_ID =
"org.jboss.seam.ui.validator.NOT_EQUAL";
+
+ public static final String VALIDATOR_ID =
"org.jboss.seam.ui.validator.Equality";
+
+ private String forId;
+
+ private String message;
+ private String messageId;
+
+ public EqualityValidator()
+ {
+ this.message = "Value does not equal that in #0";
+ this.messageId = MESSAGE_ID;
+ }
+
+ public EqualityValidator(String forId)
+ {
+ this();
+ setFor(forId);
+ }
+
+ public EqualityValidator(String forId, String message, String messageId)
+ {
+ this(forId);
+ if (message != null)
+ {
+ setMessage(message);
+ }
+ if (messageId != null)
+ {
+ setMessageId(messageId);
+ }
+ }
+
+ public void validate(FacesContext context, UIComponent component, Object value) throws
ValidatorException
+ {
+ if (!(component instanceof EditableValueHolder))
+ {
+ throw new FacesException("Must attach an equality validator to an input
component");
+ }
+ String forId = getFor();
+ if (forId == null)
+ {
+ throw new FacesException("Must specify a component to validate equality
against");
+ }
+ UIComponent otherComponent = component.findComponent(forId);
+ Object other = new OtherComponent(context, otherComponent).getValue();
+ if (value == null && other == null)
+ {
+ // Thats fine
+ }
+ else if (value != null)
+ {
+ if (!value.equals(other))
+ {
+ String otherComponentId = otherComponent.getId();
+ throw new
ValidatorException(FacesMessages.createFacesMessage(javax.faces.application.FacesMessage.SEVERITY_ERROR,
getMessageId(), getMessage(), otherComponentId, value, other));
+ }
+ }
+ }
+
+ public String getFor()
+ {
+ return forId;
+ }
+
+ public void setFor(String forId)
+ {
+ this.forId = forId;
+ }
+
+ public String getMessage()
+ {
+ return message;
+ }
+
+ public void setMessage(String message)
+ {
+ this.message = message;
+ }
+
+ public String getMessageId()
+ {
+ return messageId;
+ }
+
+ public void setMessageId(String messageId)
+ {
+ this.messageId = messageId;
+ }
+
+ public boolean isTransient()
+ {
+ return false;
+ }
+
+ public void restoreState(FacesContext context, Object state)
+ {
+ Object[] fields = (Object []) state;
+ forId = (String) fields[0];
+ message = (String) fields[1];
+ messageId = (String) fields[2];
+ }
+
+ public Object saveState(FacesContext context)
+ {
+ Object[] state = new Object[3];
+ state[0] = forId;
+ state[1] = message;
+ state[2] = messageId;
+ return state;
+ }
+
+ public void setTransient(boolean newTransientValue)
+ {
+ // No-op
+ }
+
+
+ /**
+ * Simple data strcuture to hold info on the "other" component
+ * @author pmuir
+ *
+ */
+ private class OtherComponent
+ {
+
+ private FacesContext context;
+ private UIComponent component;
+ private EditableValueHolder editableValueHolder;
+
+ private Renderer renderer;
+ private Converter converter;
+
+ public OtherComponent(FacesContext facesContext, UIComponent component)
+ {
+ this.component = component;
+ this.context = facesContext;
+ if (!(component instanceof EditableValueHolder))
+ {
+ throw new IllegalStateException("forId must reference an
EditableValueHolder (\"input\") component");
+ }
+ editableValueHolder = (EditableValueHolder) component;
+ initRenderer();
+ initConverter();
+ }
+
+ private void initRenderer()
+ {
+ if (renderer == null)
+ {
+ String rendererType = component.getRendererType();
+ if (rendererType != null)
+ {
+ renderer = context.getRenderKit().getRenderer(component.getFamily(),
rendererType);
+ if (null == renderer)
+ {
+ log.trace("Can't get Renderer for type " +
rendererType);
+ }
+ }
+ else
+ {
+ if (log.isTraceEnabled())
+ {
+ String id = component.getId();
+ id = (null != id) ? id : component.getClass().getName();
+ log.trace("No renderer-type for component " + id);
+ }
+ }
+ }
+ }
+
+ private void initConverter() {
+ converter = editableValueHolder.getConverter();
+ if (converter != null) {
+ return;
+ }
+
+ ValueExpression valueExpression =
component.getValueExpression("value");
+ if (valueExpression == null) {
+ return;
+ }
+
+ Class converterType;
+ try {
+ converterType = valueExpression.getType(context.getELContext());
+ }
+ catch (ELException e) {
+ throw new FacesException(e);
+ }
+
+ // if converterType is null, String, or Object, assume
+ // no conversion is needed
+ if (converterType == null || converterType == String.class || converterType ==
Object.class)
+ {
+ return;
+ }
+
+ // if getType returns a type for which we support a default
+ // conversion, acquire an appropriate converter instance.
+ try
+ {
+ Application application = context.getApplication();
+ converter = application.createConverter(converterType);
+ }
+ catch (Exception e)
+ {
+ throw new FacesException(e);
+ }
+ }
+
+ private Object getConvertedValue(Object newSubmittedValue) throws
ConverterException
+ {
+
+ Object newValue;
+
+ if (renderer != null)
+ {
+ newValue = renderer.getConvertedValue(context, component,
newSubmittedValue);
+ }
+ else if (newSubmittedValue instanceof String)
+ {
+ // If there's no Renderer, and we've got a String, run it through the
Converter (if any)
+ if (converter != null) {
+ newValue = converter.getAsObject(context, component,
+ (String) newSubmittedValue);
+ }
+ else
+ {
+ newValue = newSubmittedValue;
+ }
+ }
+ else
+ {
+ newValue = newSubmittedValue;
+ }
+ return newValue;
+ }
+
+ public Object getValue()
+ {
+ Object submittedValue = editableValueHolder.getLocalValue();
+ if (submittedValue == null)
+ {
+ return null;
+ }
+
+ Object newValue = null;
+
+ try
+ {
+ newValue = getConvertedValue(submittedValue);
+ }
+ catch (ConverterException ce)
+ {
+ // Any errors will be attached by JSF
+ return null;
+ }
+
+ return newValue;
+ }
+
+ }
+}