Author: tchemit Date: 2009-02-03 09:37:45 +0000 (Tue, 03 Feb 2009) New Revision: 1195 Added: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/BeanValidator.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/AbstractBeanValidatorUI.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/IconValidationUI.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/ImageValidationUI.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/TranslucentValidationUI.java Removed: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/SimpleBeanValidator.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/AbstractBeanValidatorUI.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/IconValidationUI.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/ImageValidationUI.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/TranslucentValidationUI.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ui/ Modified: jaxx/trunk/jaxx-compiler-api/src/site/fr/rst/BeanValidator.rst jaxx/trunk/jaxx-compiler-validator/src/main/java/jaxx/tags/validator/BeanValidatorHandler.java jaxx/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationListDemo.jaxx jaxx/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationTableDemo.jaxx jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/JAXXValidator.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidationUtil.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidatorErrorEvent.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidatorErrorListener.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidatorField.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/SwingValidator.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/SwingValidatorErrorListModel.java jaxx/trunk/jaxx-runtime-validator/src/test/java/jaxx/runtime/validator/field/AbstractValidatorTest.java jaxx/trunk/jaxx-swing-action/src/main/resources/i18n/jaxx-swing-action-fr_FR.properties jaxx/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/Validation.jaxx jaxx/trunk/src/site/fr/rst/BeanValidator.rst Log: renommage du SimpleBeanValidator en BenaValidator deplacement du package ui vers swing (car seul swing peut l'utiliser) Modified: jaxx/trunk/jaxx-compiler-api/src/site/fr/rst/BeanValidator.rst =================================================================== --- jaxx/trunk/jaxx-compiler-api/src/site/fr/rst/BeanValidator.rst 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-compiler-api/src/site/fr/rst/BeanValidator.rst 2009-02-03 09:37:45 UTC (rev 1195) @@ -75,7 +75,7 @@ * *errorListModel* : le modèle qui contient la liste des erreurs (et est liée au composant *errorList*), doit étendre *jaxx.runtime.validator.swing.SwingValidatorErrorListModel*. Si non présent on essayera le composent d'id *errorListModel*. - * *uiClass* : le FQN de la classe utilisé pour le rendu des erreurs sur les wigets d'édition. La classe doit étendre *jaxx.runtime.validator.ui.AbstractBeanValidatorUI*. Si non présent, on utilise par défaut le render *jaxx.runtime.validator.ui.IconValidationUI*. + * *uiClass* : le FQN de la classe utilisé pour le rendu des erreurs sur les wigets d'édition. La classe doit étendre *jaxx.runtime.validator.swing.ui.AbstractBeanValidatorUI*. Si non présent, on utilise par défaut le render *jaxx.runtime.validator.swing.ui.IconValidationUI*. Le tag supporte aussi l'ajout de tag *field* comme fils pour définir explicitement des champs à validater. Modified: jaxx/trunk/jaxx-compiler-validator/src/main/java/jaxx/tags/validator/BeanValidatorHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-validator/src/main/java/jaxx/tags/validator/BeanValidatorHandler.java 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-compiler-validator/src/main/java/jaxx/tags/validator/BeanValidatorHandler.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -13,7 +13,7 @@ import jaxx.reflect.ClassDescriptorLoader; import jaxx.runtime.validator.ValidationUtil; import jaxx.runtime.validator.swing.SwingValidator; -import jaxx.runtime.validator.ui.AbstractBeanValidatorUI; +import jaxx.runtime.validator.swing.ui.AbstractBeanValidatorUI; import jaxx.tags.DefaultObjectHandler; import jaxx.types.TypeManager; import org.apache.commons.logging.Log; Modified: jaxx/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationListDemo.jaxx =================================================================== --- jaxx/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationListDemo.jaxx 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationListDemo.jaxx 2009-02-03 09:37:45 UTC (rev 1195) @@ -11,18 +11,18 @@ onContentsChanged='ok.setEnabled(errors.isEmpty())'/> <!-- validators --> - <BeanValidator id='validator' bean='model1' uiClass="jaxx.runtime.validator.ui.ImageValidationUI"> + <BeanValidator id='validator' bean='model1' uiClass="jaxx.runtime.validator.swing.ui.ImageValidationUI"> <field name="text"/> <field name="text2"/> <field name="ratio"/> </BeanValidator> - <BeanValidator id='validator2' bean='model2' uiClass="jaxx.runtime.validator.ui.IconValidationUI"> + <BeanValidator id='validator2' bean='model2' uiClass="jaxx.runtime.validator.swing.ui.IconValidationUI"> <field name="text" component="_text"/> <field name="text2" component="_text2"/> <field name="ratio" component="_ratio"/> </BeanValidator> <BeanValidator id='validator3' autoField='true' bean='identity' - uiClass="jaxx.runtime.validator.ui.TranslucentValidationUI"> + uiClass="jaxx.runtime.validator.swing.ui.TranslucentValidationUI"> <field name="email" component="email2"/> </BeanValidator> Modified: jaxx/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationTableDemo.jaxx =================================================================== --- jaxx/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationTableDemo.jaxx 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationTableDemo.jaxx 2009-02-03 09:37:45 UTC (rev 1195) @@ -11,18 +11,18 @@ onTableChanged='ok.setEnabled(errors2.getRowCount()==0)'/> <!-- validators --> - <BeanValidator id='validator' bean='model1' uiClass="jaxx.runtime.validator.ui.ImageValidationUI"> + <BeanValidator id='validator' bean='model1' uiClass="jaxx.runtime.validator.swing.ui.ImageValidationUI"> <field name="text"/> <field name="text2"/> <field name="ratio"/> </BeanValidator> - <BeanValidator id='validator2' bean='model2' uiClass="jaxx.runtime.validator.ui.IconValidationUI"> + <BeanValidator id='validator2' bean='model2' uiClass="jaxx.runtime.validator.swing.ui.IconValidationUI"> <field name="text" component="_text"/> <field name="text2" component="_text2"/> <field name="ratio" component="_ratio"/> </BeanValidator> <BeanValidator id='validator3' autoField='true' bean='identity' - uiClass="jaxx.runtime.validator.ui.TranslucentValidationUI"> + uiClass="jaxx.runtime.validator.swing.ui.TranslucentValidationUI"> <field name="email" component="email2"/> </BeanValidator> Modified: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/JAXXValidator.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/JAXXValidator.java 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/JAXXValidator.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -1,6 +1,6 @@ package jaxx.runtime; -import jaxx.runtime.validator.SimpleBeanValidator; +import jaxx.runtime.validator.BeanValidator; import java.util.List; @@ -17,7 +17,7 @@ * @param validatorId validator id * @return the associated validator, or <code>null</code> if not find */ - SimpleBeanValidator<?> getValidator(String validatorId); + BeanValidator<?> getValidator(String validatorId); /** @return the list of ids of all registred validator */ List<String> getValidatorIds(); Copied: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/BeanValidator.java (from rev 1194, jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/SimpleBeanValidator.java) =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/BeanValidator.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/BeanValidator.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -0,0 +1,450 @@ +package jaxx.runtime.validator; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ValidationAwareSupport; +import com.opensymphony.xwork2.config.Configuration; +import com.opensymphony.xwork2.config.ConfigurationManager; +import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.util.ValueStackFactory; +import com.opensymphony.xwork2.validator.ActionValidatorManager; +import com.opensymphony.xwork2.validator.DelegatingValidatorContext; +import com.opensymphony.xwork2.validator.FieldValidator; +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.Validator; +import com.opensymphony.xwork2.validator.ValidatorScope; +import org.apache.commons.beanutils.ConversionException; +import org.apache.commons.beanutils.Converter; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.util.ConverterUtil; + +import java.beans.Introspector; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + +/** @author chemit */ +public class BeanValidator<B> { + + /** + * Pour definir le niveau de validation. + * <p/> + * Par défaut, le validateur est supposé géré des erreurs, mais on peut aussi l'utiliser + * pour consigner des warnings sur le bean surveiller. + */ + public enum Scope { + ERROR, + WARNING + } + + public enum State { + VALID, + CONVERSION_ERROR, + FAILED + } + + /** la nom de la propriété bean */ + static public final String BEAN_PROERTY = "bean"; + + /** la nom de la propriété contextName */ + static public final String CONTEXT_NAME_PROPERTY = "contextName"; + + /** la nom de l'état valid */ + static public final String VALID_PROERTY = "valid"; + + /** la nom de l'état changed */ + static public final String CHANGED_PROERTY = "changed"; + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static protected final Log log = LogFactory.getLog(BeanValidator.class); + + /** the type of bean to watch */ + protected final Class<B> beanClass; + + /** the validation named context (can be null) */ + protected String contextName; + + /** to chain to a prent validator */ + protected BeanValidator<?> parentValidator; + + /** state to indicate that validator has changed since the last time bean was setted */ + protected boolean changed = false; + + /** state of the validator (is true if no errors of error scope is found) */ + protected boolean valid; + + /** bean to be watched */ + protected B bean = null; + + /** list of fields watched by this validator */ + protected List<ValidatorField<B>> fields; + + /** map of conversion errors detected by this validator */ + protected Map<String, String> conversionErrors; + + /** delgate property change support */ + protected PropertyChangeSupport pcs; + + /** listener that listens on bean modification */ + protected PropertyChangeListener l; + + protected ValidationAwareSupport validationSupport; + protected DelegatingValidatorContext validationContext; + protected transient ActionValidatorManager validator; + protected ActionContext context; + + public BeanValidator(Class<B> beanClass, String contextName) { + this.beanClass = beanClass; + this.contextName = contextName; + pcs = new PropertyChangeSupport(this); + validationSupport = new ValidationAwareSupport(); + validationContext = new DelegatingValidatorContext(validationSupport); + + // init context + ConfigurationManager confManager = new ConfigurationManager(); + Configuration conf = confManager.getConfiguration(); + + ValueStackFactory vsf = conf.getContainer().getInstance( + ValueStackFactory.class); + ValueStack vs = vsf.createValueStack(); + context = new ActionContext(vs.getContext()); + ActionContext.setContext(context); + + // init validator + validator = conf.getContainer().getInstance(ActionValidatorManager.class, "no-annotations"); + initFields(); + + conversionErrors = new TreeMap<String, String>(); + + l = new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent evt) { + validate(); + setValid(!hasErrors()); + setChanged(true); + } + }; + } + + protected void initFields() { + // init fields from detected fieldValidator in XWorks framework + fields = new ArrayList<ValidatorField<B>>(); + for (Validator v : validator.getValidators(beanClass, contextName)) { + // we only work on FieldValidator at the moment + if (v instanceof FieldValidator) { + FieldValidator fieldValidator = (FieldValidator) v; + String fName = fieldValidator.getFieldName(); + ValidatorScope fScope = fieldValidator.getValidatorScope(); + ValidatorField<B> field = new ValidatorField<B>(beanClass, fName, fScope); + if (!fields.contains(field)) { + fields.add(field); + } + } + } + + fields = Collections.unmodifiableList(fields); + } + + public Class<B> getBeanClass() { + return beanClass; + } + + public BeanValidator<?> getParentValidator() { + return parentValidator; + } + + public String getContextName() { + return contextName; + } + + public List<ValidatorField<B>> getFields() { + return fields; + } + + public ValidatorField<B> getField(String fieldName) { + for (ValidatorField<B> field : fields) { + if (fieldName.equals(field.getName())) { + return field; + } + } + return null; + } + + /** + * Retourne vrai si l'objet bean a ete modifie depuis le dernier + * {@link #setBean} + * + * @return <code>true</code> if bean was modify since last {@link #setBean(Object)} invocation + */ + public boolean isChanged() { + return changed; + } + + public boolean isValid() { + return valid; + } + + public B getBean() { + return bean; + } + + /** + * Permet de force la remise a false de l'etat de changement du bean + * + * @param changed flag to force reset of property {@link #changed} + */ + public void setChanged(boolean changed) { + this.changed = changed; + // force the property to be fired (never pass the older value) + pcs.firePropertyChange(CHANGED_PROERTY, null, changed); + } + + public void setValid(boolean valid) { + this.valid = valid; + // force the property to be fired (never pass the older value) + pcs.firePropertyChange(VALID_PROERTY, null, valid); + } + + public void setBean(B bean) { + B oldBean = this.bean; + if (log.isDebugEnabled()) { + log.debug(this + " : " + bean); + } + // clean conversions of previous bean + conversionErrors.clear(); + + if (oldBean != null) { + try { + Method method = this.bean.getClass().getMethod("removePropertyChangeListener", PropertyChangeListener.class); + method.invoke(oldBean, l); + } catch (Exception eee) { + log.info("Can't register as listener", eee); + } + } + this.bean = bean; + if (bean == null) { + // must remove all errors from this validator on errorListModel + validationSupport.clearErrorsAndMessages(); + //errors.clear(); + } else { + try { + Method method = this.bean.getClass().getMethod("addPropertyChangeListener", PropertyChangeListener.class); + method.invoke(bean, l); + } catch (Exception eee) { + log.info("Can't register as listener", eee); + } + validate(); + } + setChanged(false); + setValid(!hasErrors()); + pcs.firePropertyChange(BEAN_PROERTY, oldBean, bean); + } + + //FIXME At the moment we do not allow to change contextName, but we should be able to do it + public void setContextName(String contextName) { + String oldValidationContextName = this.contextName; + this.contextName = contextName; + // changing contextName could change fields definition + // so dettach bean, must rebuild the fields + setBean(null); + initFields(); + //pcs.firePropertyChange(CONTEXT_NAME_PROPERTY, oldValidationContextName, contextName); + } + + public void setParentValidator(BeanValidator<?> parentValidator) { + this.parentValidator = parentValidator; + } + + /** @return <code>true</code> if errors are detected, <code>false</code> otherwise */ + public boolean hasErrors() { + for (ValidatorField<B> field : fields) { + if (field.hasErrors()) { + return true; + } + } + return false; + } + + public boolean hasWarnings() { + for (ValidatorField<B> field : fields) { + if (field.hasWarnings()) { + return true; + } + } + return false; + } + + public boolean isValid(String fieldName) { + ValidatorField<B> field = getField(fieldName); + if (field == null) { + throw new IllegalArgumentException("could not find a validator field " + fieldName); + } + return field.isValid(); + } + + /** + * Convert a value. + * <p/> + * If an error occurs, then add an error in validator. + * + * @param fieldName the name of the bean property + * @param value the value to convert + * @param valueClass the type of converted value + * @return the converted value, or null if conversion was not ok + */ + public <T> T convert(String fieldName, String value, Class<T> valueClass) { + if (fieldName == null) { + throw new IllegalArgumentException("fieldName can not be null"); + } + if (valueClass == null) { + throw new IllegalArgumentException("valueClass can not be null"); + } + + // on ne convertit pas si il y a un bean et que le resultat de la validation + // pourra etre affiche quelque part + if (!canValidate() || value == null) { + return null; + } + + // remove the previous conversion error for the field + conversionErrors.remove(fieldName); + + T result; + try { + Converter converter = ConverterUtil.getConverter(valueClass); + if (converter == null) { + throw new RuntimeException("could not find converter for the type " + valueClass); + } + result = (T) converter.convert(valueClass, value); + /* Why this test ? if (result != null && !value.equals(result.toString())) { + conversionErrors.put(fieldName, "error.convertor." + Introspector.decapitalize(valueClass.getSimpleName())); + result = null; + validate(); + }*/ + } catch (ConversionException e) { + // get + conversionErrors.put(fieldName, "error.convertor." + Introspector.decapitalize(valueClass.getSimpleName())); + result = null; + validate(); + } + return result; + } + + /** + * il faut eviter le code re-intrant (durant une validation, une autre est + * demandee). Pour cela on fait la validation dans un thread, et tant + * que la premiere validation n'est pas fini, on ne repond pas aux + * solicitations. + * Cette method est public pour permettre de force une validation par + * programmation, ce qui est utile par exemple si le bean ne supporte + * pas les {@link PropertyChangeListener} + */ + public void validate() { + // on ne valide que si il y a un bean et que le resultat de la validation + // pourra etre affiche quelque part + if (!canValidate()) { + return; + } + + try { + + validationSupport.clearErrorsAndMessages(); + + //TC - 20081024 : since context is in a ThreadLocal variable, we must do the check + if (ActionContext.getContext() == null) { + ActionContext.setContext(context); + } + + validator.validate(bean, contextName, validationContext); + + // add the registred conversion errors + transfertConversionErrorsToFieldErrors(); + + if (log.isTraceEnabled()) { + log.trace("Action errors: " + validationContext.getActionErrors()); + log.trace("Action messages: " + validationContext.getActionMessages()); + log.trace("Field errors: " + validationContext.getFieldErrors()); + } + + if (log.isDebugEnabled()) { + log.debug(this + " : " + validationContext.getFieldErrors()); + } + + // dispatch in each field the new errors + dispatchErrorsToFields(); + + if (parentValidator != null) { + // chained validation + parentValidator.l.propertyChange(null); + } + } catch (ValidationException eee) { + log.warn("Error during validation", eee); + } + } + + @Override + public String toString() { + return super.toString() + "<beanClass:" + beanClass + ", contextName:" + contextName + ">"; + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + + /** @return <code>true</code> if validation is enabled, <code>false</code> otherwise. */ + protected boolean canValidate() { + return !(bean == null || fields.isEmpty()); + } + + /** + * Transfer the registred conversion errors to fieldErrors. + * <p/> + * The previously filed errors of a given field where a conversion error occurs will be removed. + */ + protected void transfertConversionErrorsToFieldErrors() { + Map map = validationContext.getFieldErrors(); + for (Entry<String, String> entry : conversionErrors.entrySet()) { + // remove from validation, errors occurs on this field + List errors = (List) map.get(entry.getKey()); + if (errors != null) { + errors.clear(); + errors.add(entry.getValue()); + } else { + errors = Collections.singletonList(entry.getValue()); + } + // add the concrete conversion error + map.put(entry.getKey(), errors); + } + validationContext.setFieldErrors(map); + } + + /** synchronize the errors found in this validator to each field. */ + protected void dispatchErrorsToFields() { + + Map map = validationContext.getFieldErrors(); + for (ValidatorField<B> field : fields) { + String fieldName = field.getName(); + boolean detectedErrors = map.containsKey(fieldName); + field.addErrors(this, detectedErrors ? (List) map.get(fieldName) : null); + } + } + +} Deleted: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/SimpleBeanValidator.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/SimpleBeanValidator.java 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/SimpleBeanValidator.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -1,450 +0,0 @@ -package jaxx.runtime.validator; - -import com.opensymphony.xwork2.ActionContext; -import com.opensymphony.xwork2.ValidationAwareSupport; -import com.opensymphony.xwork2.config.Configuration; -import com.opensymphony.xwork2.config.ConfigurationManager; -import com.opensymphony.xwork2.util.ValueStack; -import com.opensymphony.xwork2.util.ValueStackFactory; -import com.opensymphony.xwork2.validator.ActionValidatorManager; -import com.opensymphony.xwork2.validator.DelegatingValidatorContext; -import com.opensymphony.xwork2.validator.FieldValidator; -import com.opensymphony.xwork2.validator.ValidationException; -import com.opensymphony.xwork2.validator.Validator; -import com.opensymphony.xwork2.validator.ValidatorScope; -import org.apache.commons.beanutils.ConversionException; -import org.apache.commons.beanutils.Converter; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.codelutin.util.ConverterUtil; - -import java.beans.Introspector; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.TreeMap; - -/** @author chemit */ -public class SimpleBeanValidator<B> { - - /** - * Pour definir le niveau de validation. - * <p/> - * Par défaut, le validateur est supposé géré des erreurs, mais on peut aussi l'utiliser - * pour consigner des warnings sur le bean surveiller. - */ - public enum Scope { - ERROR, - WARNING - } - - public enum State { - VALID, - CONVERSION_ERROR, - FAILED - } - - /** la nom de la propriété bean */ - static public final String BEAN_PROERTY = "bean"; - - /** la nom de la propriété contextName */ - static public final String CONTEXT_NAME_PROPERTY = "contextName"; - - /** la nom de l'état valid */ - static public final String VALID_PROERTY = "valid"; - - /** la nom de l'état changed */ - static public final String CHANGED_PROERTY = "changed"; - - /** to use log facility, just put in your code: log.info(\"...\"); */ - static protected final Log log = LogFactory.getLog(SimpleBeanValidator.class); - - /** the type of bean to watch */ - protected final Class<B> beanClass; - - /** the validation named context (can be null) */ - protected String contextName; - - /** to chain to a prent validator */ - protected SimpleBeanValidator<?> parentValidator; - - /** state to indicate that validator has changed since the last time bean was setted */ - protected boolean changed = false; - - /** state of the validator (is true if no errors of error scope is found) */ - protected boolean valid; - - /** bean to be watched */ - protected B bean = null; - - /** list of fields watched by this validator */ - protected List<ValidatorField<B>> fields; - - /** map of conversion errors detected by this validator */ - protected Map<String, String> conversionErrors; - - /** delgate property change support */ - protected PropertyChangeSupport pcs; - - /** listener that listens on bean modification */ - protected PropertyChangeListener l; - - protected ValidationAwareSupport validationSupport; - protected DelegatingValidatorContext validationContext; - protected transient ActionValidatorManager validator; - protected ActionContext context; - - public SimpleBeanValidator(Class<B> beanClass, String contextName) { - this.beanClass = beanClass; - this.contextName = contextName; - pcs = new PropertyChangeSupport(this); - validationSupport = new ValidationAwareSupport(); - validationContext = new DelegatingValidatorContext(validationSupport); - - // init context - ConfigurationManager confManager = new ConfigurationManager(); - Configuration conf = confManager.getConfiguration(); - - ValueStackFactory vsf = conf.getContainer().getInstance( - ValueStackFactory.class); - ValueStack vs = vsf.createValueStack(); - context = new ActionContext(vs.getContext()); - ActionContext.setContext(context); - - // init validator - validator = conf.getContainer().getInstance(ActionValidatorManager.class, "no-annotations"); - initFields(); - - conversionErrors = new TreeMap<String, String>(); - - l = new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) { - validate(); - setValid(!hasErrors()); - setChanged(true); - } - }; - } - - protected void initFields() { - // init fields from detected fieldValidator in XWorks framework - fields = new ArrayList<ValidatorField<B>>(); - for (Validator v : validator.getValidators(beanClass, contextName)) { - // we only work on FieldValidator at the moment - if (v instanceof FieldValidator) { - FieldValidator fieldValidator = (FieldValidator) v; - String fName = fieldValidator.getFieldName(); - ValidatorScope fScope = fieldValidator.getValidatorScope(); - ValidatorField<B> field = new ValidatorField<B>(beanClass, fName, fScope); - if (!fields.contains(field)) { - fields.add(field); - } - } - } - - fields = Collections.unmodifiableList(fields); - } - - public Class<B> getBeanClass() { - return beanClass; - } - - public SimpleBeanValidator<?> getParentValidator() { - return parentValidator; - } - - public String getContextName() { - return contextName; - } - - public List<ValidatorField<B>> getFields() { - return fields; - } - - public ValidatorField<B> getField(String fieldName) { - for (ValidatorField<B> field : fields) { - if (fieldName.equals(field.getName())) { - return field; - } - } - return null; - } - - /** - * Retourne vrai si l'objet bean a ete modifie depuis le dernier - * {@link #setBean} - * - * @return <code>true</code> if bean was modify since last {@link #setBean(Object)} invocation - */ - public boolean isChanged() { - return changed; - } - - public boolean isValid() { - return valid; - } - - public B getBean() { - return bean; - } - - /** - * Permet de force la remise a false de l'etat de changement du bean - * - * @param changed flag to force reset of property {@link #changed} - */ - public void setChanged(boolean changed) { - this.changed = changed; - // force the property to be fired (never pass the older value) - pcs.firePropertyChange(CHANGED_PROERTY, null, changed); - } - - public void setValid(boolean valid) { - this.valid = valid; - // force the property to be fired (never pass the older value) - pcs.firePropertyChange(VALID_PROERTY, null, valid); - } - - public void setBean(B bean) { - B oldBean = this.bean; - if (log.isDebugEnabled()) { - log.debug(this + " : " + bean); - } - // clean conversions of previous bean - conversionErrors.clear(); - - if (oldBean != null) { - try { - Method method = this.bean.getClass().getMethod("removePropertyChangeListener", PropertyChangeListener.class); - method.invoke(oldBean, l); - } catch (Exception eee) { - log.info("Can't register as listener", eee); - } - } - this.bean = bean; - if (bean == null) { - // must remove all errors from this validator on errorListModel - validationSupport.clearErrorsAndMessages(); - //errors.clear(); - } else { - try { - Method method = this.bean.getClass().getMethod("addPropertyChangeListener", PropertyChangeListener.class); - method.invoke(bean, l); - } catch (Exception eee) { - log.info("Can't register as listener", eee); - } - validate(); - } - setChanged(false); - setValid(!hasErrors()); - pcs.firePropertyChange(BEAN_PROERTY, oldBean, bean); - } - - //FIXME At the moment we do not allow to change contextName, but we should be able to do it - public void setContextName(String contextName) { - String oldValidationContextName = this.contextName; - this.contextName = contextName; - // changing contextName could change fields definition - // so dettach bean, must rebuild the fields - setBean(null); - initFields(); - //pcs.firePropertyChange(CONTEXT_NAME_PROPERTY, oldValidationContextName, contextName); - } - - public void setParentValidator(SimpleBeanValidator<?> parentValidator) { - this.parentValidator = parentValidator; - } - - /** @return <code>true</code> if errors are detected, <code>false</code> otherwise */ - public boolean hasErrors() { - for (ValidatorField<B> field : fields) { - if (field.hasErrors()) { - return true; - } - } - return false; - } - - public boolean hasWarnings() { - for (ValidatorField<B> field : fields) { - if (field.hasWarnings()) { - return true; - } - } - return false; - } - - public boolean isValid(String fieldName) { - ValidatorField<B> field = getField(fieldName); - if (field == null) { - throw new IllegalArgumentException("could not find a validator field " + fieldName); - } - return field.isValid(); - } - - /** - * Convert a value. - * <p/> - * If an error occurs, then add an error in validator. - * - * @param fieldName the name of the bean property - * @param value the value to convert - * @param valueClass the type of converted value - * @return the converted value, or null if conversion was not ok - */ - public <T> T convert(String fieldName, String value, Class<T> valueClass) { - if (fieldName == null) { - throw new IllegalArgumentException("fieldName can not be null"); - } - if (valueClass == null) { - throw new IllegalArgumentException("valueClass can not be null"); - } - - // on ne convertit pas si il y a un bean et que le resultat de la validation - // pourra etre affiche quelque part - if (!canValidate() || value == null) { - return null; - } - - // remove the previous conversion error for the field - conversionErrors.remove(fieldName); - - T result; - try { - Converter converter = ConverterUtil.getConverter(valueClass); - if (converter == null) { - throw new RuntimeException("could not find converter for the type " + valueClass); - } - result = (T) converter.convert(valueClass, value); - /* Why this test ? if (result != null && !value.equals(result.toString())) { - conversionErrors.put(fieldName, "error.convertor." + Introspector.decapitalize(valueClass.getSimpleName())); - result = null; - validate(); - }*/ - } catch (ConversionException e) { - // get - conversionErrors.put(fieldName, "error.convertor." + Introspector.decapitalize(valueClass.getSimpleName())); - result = null; - validate(); - } - return result; - } - - /** - * il faut eviter le code re-intrant (durant une validation, une autre est - * demandee). Pour cela on fait la validation dans un thread, et tant - * que la premiere validation n'est pas fini, on ne repond pas aux - * solicitations. - * Cette method est public pour permettre de force une validation par - * programmation, ce qui est utile par exemple si le bean ne supporte - * pas les {@link PropertyChangeListener} - */ - public void validate() { - // on ne valide que si il y a un bean et que le resultat de la validation - // pourra etre affiche quelque part - if (!canValidate()) { - return; - } - - try { - - validationSupport.clearErrorsAndMessages(); - - //TC - 20081024 : since context is in a ThreadLocal variable, we must do the check - if (ActionContext.getContext() == null) { - ActionContext.setContext(context); - } - - validator.validate(bean, contextName, validationContext); - - // add the registred conversion errors - transfertConversionErrorsToFieldErrors(); - - if (log.isTraceEnabled()) { - log.trace("Action errors: " + validationContext.getActionErrors()); - log.trace("Action messages: " + validationContext.getActionMessages()); - log.trace("Field errors: " + validationContext.getFieldErrors()); - } - - if (log.isDebugEnabled()) { - log.debug(this + " : " + validationContext.getFieldErrors()); - } - - // dispatch in each field the new errors - dispatchErrorsToFields(); - - if (parentValidator != null) { - // chained validation - parentValidator.l.propertyChange(null); - } - } catch (ValidationException eee) { - log.warn("Error during validation", eee); - } - } - - @Override - public String toString() { - return super.toString() + "<beanClass:" + beanClass + ", contextName:" + contextName + ">"; - } - - public void addPropertyChangeListener(PropertyChangeListener listener) { - pcs.addPropertyChangeListener(listener); - } - - public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { - pcs.addPropertyChangeListener(propertyName, listener); - } - - public void removePropertyChangeListener(PropertyChangeListener listener) { - pcs.removePropertyChangeListener(listener); - } - - public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { - pcs.removePropertyChangeListener(propertyName, listener); - } - - /** @return <code>true</code> if validation is enabled, <code>false</code> otherwise. */ - protected boolean canValidate() { - return !(bean == null || fields.isEmpty()); - } - - /** - * Transfer the registred conversion errors to fieldErrors. - * <p/> - * The previously filed errors of a given field where a conversion error occurs will be removed. - */ - protected void transfertConversionErrorsToFieldErrors() { - Map map = validationContext.getFieldErrors(); - for (Entry<String, String> entry : conversionErrors.entrySet()) { - // remove from validation, errors occurs on this field - List errors = (List) map.get(entry.getKey()); - if (errors != null) { - errors.clear(); - errors.add(entry.getValue()); - } else { - errors = Collections.singletonList(entry.getValue()); - } - // add the concrete conversion error - map.put(entry.getKey(), errors); - } - validationContext.setFieldErrors(map); - } - - /** synchronize the errors found in this validator to each field. */ - protected void dispatchErrorsToFields() { - - Map map = validationContext.getFieldErrors(); - for (ValidatorField<B> field : fields) { - String fieldName = field.getName(); - boolean detectedErrors = map.containsKey(fieldName); - field.addErrors(this, detectedErrors ? (List) map.get(fieldName) : null); - } - } - -} Modified: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidationUtil.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidationUtil.java 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidationUtil.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -94,7 +94,7 @@ } } for (String validatorId : validatorIds) { - SimpleBeanValidator beanValidator = jaxxValidator.getValidator(validatorId); + BeanValidator beanValidator = jaxxValidator.getValidator(validatorId); if (bean == null || beanValidator.getBeanClass().isAssignableFrom(bean.getClass())) { // touch validator, only if fits the bean type (or bean is null) beanValidator.setBean(bean); @@ -125,7 +125,7 @@ } } for (String validatorId : validatorIds) { - SimpleBeanValidator beanValidator = jaxxValidator.getValidator(validatorId); + BeanValidator beanValidator = jaxxValidator.getValidator(validatorId); beanValidator.setChanged(newValue); } } @@ -138,7 +138,7 @@ * @param value the actual value to convert * @param valueClass the type of the conversion */ - public static void convert(SimpleBeanValidator<?> validator, String fieldName, String value, Class<?> valueClass) { + public static void convert(BeanValidator<?> validator, String fieldName, String value, Class<?> valueClass) { Object result = validator.convert(fieldName, value, valueClass); if (result != null) { Modified: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidatorErrorEvent.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidatorErrorEvent.java 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidatorErrorEvent.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -6,24 +6,24 @@ /** * The definition of an event on {@link ValidatorErrorListener} - * to be fired by a {@link SimpleBeanValidator}. + * to be fired by a {@link BeanValidator}. * * @author chemit */ public class ValidatorErrorEvent { /** the source of the event */ - SimpleBeanValidator source; + BeanValidator source; /** the field impacted by the validator */ ValidatorField<?> field; - public ValidatorErrorEvent(SimpleBeanValidator source, ValidatorField<?> field) { + public ValidatorErrorEvent(BeanValidator source, ValidatorField<?> field) { this.source = source; this.field = field; } - public SimpleBeanValidator getSource() { + public BeanValidator getSource() { return source; } Modified: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidatorErrorListener.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidatorErrorListener.java 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidatorErrorListener.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -1,7 +1,7 @@ package jaxx.runtime.validator; /** - * The listener contract to be used on {@link SimpleBeanValidator] + * The listener contract to be used on {@link BeanValidator] * * @author chemit */ Modified: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidatorField.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidatorField.java 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ValidatorField.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -11,10 +11,10 @@ import java.util.StringTokenizer; /** - * Definition of a field to be handled in a {@link SimpleBeanValidator]. + * Definition of a field to be handled in a {@link BeanValidator]. * <p/> * <p/> - * A such class is only registred in {@link SimpleBeanValidator} when the field of the bean + * A such class is only registred in {@link BeanValidator } when the field of the bean * was found in validator xml configuration file for a {@link com.opensymphony.xwork2.validator.FieldValidator} only. * <p/> * This class use properties {@link #beanClass}, {@link #name} to define @@ -87,7 +87,7 @@ return scope == ValidatorScope.WARNING && !errors.isEmpty(); } - public void addErrors(SimpleBeanValidator<B> validator, List errors) { + public void addErrors(BeanValidator<B> validator, List errors) { boolean hasPreviousError = !this.errors.isEmpty(); // reset errors for this field @@ -134,14 +134,14 @@ listenerList.remove(ValidatorErrorListener.class, listener); } - protected void fireNewError(SimpleBeanValidator<B> validator) { + protected void fireNewError(BeanValidator<B> validator) { ValidatorErrorEvent evt = new ValidatorErrorEvent(validator, this); for (ValidatorErrorListener listener : listenerList.getListeners(ValidatorErrorListener.class)) { listener.onNewError(evt); } } - protected void fireResolvedError(SimpleBeanValidator<B> validator) { + protected void fireResolvedError(BeanValidator<B> validator) { ValidatorErrorEvent evt = new ValidatorErrorEvent(validator, this); for (ValidatorErrorListener listener : listenerList.getListeners(ValidatorErrorListener.class)) { listener.onResolvedError(evt); Modified: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/SwingValidator.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/SwingValidator.java 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/SwingValidator.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -1,9 +1,9 @@ package jaxx.runtime.validator.swing; -import jaxx.runtime.validator.SimpleBeanValidator; +import jaxx.runtime.validator.BeanValidator; import jaxx.runtime.validator.ValidatorField; -import jaxx.runtime.validator.ui.AbstractBeanValidatorUI; -import jaxx.runtime.validator.ui.IconValidationUI; +import jaxx.runtime.validator.swing.ui.AbstractBeanValidatorUI; +import jaxx.runtime.validator.swing.ui.IconValidationUI; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jdesktop.jxlayer.JXLayer; @@ -18,11 +18,85 @@ import java.util.Map.Entry; /** - * La surcharge de {@link jaxx.runtime.validator.SimpleBeanValidator} pour les ui swing + * La surcharge de {@link jaxx.runtime.validator.BeanValidator} pour les ui swing + * <p/> + * /** + * <p/> + * Permet d'ajouter facilement le support de la validation des champs d'un + * bean et de le relier a une interface graphique. + * Utilise xwork pour la validation et JXLayer pour la visualisation. + * <p/> + * <p/> + * Le mieux pour son integration dans Jaxx est de faire de la generation pour + * force la compilation du code suivant: + * <p/> + * <pre> + * myValidor.getBean().get<field>(); + * </pre> + * <p/> + * et ceci pour chaque field ajoute a la map fieldRepresentation. De cette + * facon meme si le champs field est en texte on a une verification de son + * existance a la compilation. + * <p/> + * <p/> + * La representation en tag pourrait etre + * <pre> + * <validator id="myValidator" beanClass="{Personne.class}" errorList="$list"> + * <field name="name" component="$name"/> + * <field name="firstName" component="$firstName"/> + * <field name="birthDate" component="$birthDate"/> + * </validator> + * <validator beanClass="{Personne.class}" autoField="true" errorList="$list"> + * <fieldRepresentation name="name" component="$lastName"/> + * </validator> + * </pre> + * <p/> + * dans le premier exemple on fait un mapping explicite des champs, mais on voit + * que le nom du composant graphique est le meme que celui du champs. Pour eviter + * de longue saisie, il est possible d'utiliser le flag <b>autoField</b> + * qui pour chaque champs du ayant une methode get du bean recherche un composant + * avec cet Id. Il est aussi possible de surcharge un champs explicitement + * comme ici name, dans le cas ou le composant qui porterait ce nom serait + * utilise pour autre chose. + * <p/> + * <p/> + * Il faut un handler particulier pour ce composant car les attributs + * <b>beanClass</b> et <b>autoField</b> ne sont present que dans le XML jaxx et + * servent a la generation. Il faut aussi prendre en compte les elements + * fieldRepresentation fils du tag validator. + * <p/> + * <p/> + * Voici ce que pourrait etre le code genere par jaxx + * <pre> + * // declaration du bean + * BeanValidator<beanClass> $myValidator; + * // init du bean + * protected void createMyValidator() { + * $myValidator = new BeanValidator<beanClass>(); + * // genere seulement si autoField = true + * for (Method m : beanClass.getMethod()) { + * if (m.getName().startsWith("get")) { + * String fieldName = m.getName().substring(3).toLowerCase(); + * $myValidator.setFieldRepresentation(fieldName, $objectMap.get(fieldName)); + * } + * } + * // pour chaque tag fieldRepresentation + * myValidator.setFieldRepresentation("name", $lastName); + * // si beanClass est specifie et n'est pas Object, on force l'acces au champs + * // pour validation a la compilation + * $myValidator.getBean().getName(); + * $objectMap.put("myValidator", $myValidator); + * } + * </pre> * + * @author poussin * @author chemit + * @version 1.0 + * <p/> + * Last update: $Date: 3 févr. 2009 $ + * By : $Author: chatellier $ */ -public class SwingValidator<B> extends SimpleBeanValidator<B> { +public class SwingValidator<B> extends BeanValidator<B> { /** to use log facility, just put in your code: log.info(\"...\"); */ static private final Log log = LogFactory.getLog(SwingValidator.class); Modified: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/SwingValidatorErrorListModel.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/SwingValidatorErrorListModel.java 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/SwingValidatorErrorListModel.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -1,6 +1,6 @@ package jaxx.runtime.validator.swing; -import jaxx.runtime.validator.SimpleBeanValidator; +import jaxx.runtime.validator.BeanValidator; import jaxx.runtime.validator.ValidatorErrorEvent; import jaxx.runtime.validator.ValidatorErrorListener; import jaxx.runtime.validator.ValidatorField; @@ -22,14 +22,14 @@ private static final long serialVersionUID = 1L; /** list of registred validators */ - protected transient List<SimpleBeanValidator<?>> validators; + protected transient List<BeanValidator<?>> validators; public SwingValidatorErrorListModel() { - validators = new ArrayList<SimpleBeanValidator<?>>(); + validators = new ArrayList<BeanValidator<?>>(); } - public void registerValidator(SimpleBeanValidator<?> validator) { + public void registerValidator(BeanValidator<?> validator) { if (validators.contains(validator)) { throw new IllegalArgumentException("the validator " + validator + " is already registred in " + this); } Copied: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui (from rev 1173, jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ui) Deleted: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/AbstractBeanValidatorUI.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ui/AbstractBeanValidatorUI.java 2009-01-20 20:11:30 UTC (rev 1173) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/AbstractBeanValidatorUI.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -1,38 +0,0 @@ -package jaxx.runtime.validator.ui; - -import com.opensymphony.xwork2.ValidationAware; -import jaxx.runtime.validator.BeanValidator.Scope; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.jdesktop.jxlayer.plaf.AbstractLayerUI; - -/** - * Abstract renderer - * - * @author chemit - */ -public abstract class AbstractBeanValidatorUI extends AbstractLayerUI<javax.swing.JComponent> { - - /** to use log facility, just put in your code: log.info(\"...\"); */ - protected static Log log = LogFactory.getLog(AbstractBeanValidatorUI.class); - - /** scope */ - protected Scope scope; - - /** bean field */ - protected String field; - - /** component id */ - protected String componentId; - - /** validation context */ - protected ValidationAware validationContext; - - public AbstractBeanValidatorUI(String field, String componentId, Scope scope, ValidationAware validationContext) { - this.componentId = componentId; - this.field = field; - this.scope = scope; - this.validationContext = validationContext; - log.info("install " + this + "<field:" + field + ", componentId:" + componentId + ">"); - } -} Copied: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/AbstractBeanValidatorUI.java (from rev 1194, jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ui/AbstractBeanValidatorUI.java) =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/AbstractBeanValidatorUI.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/AbstractBeanValidatorUI.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -0,0 +1,49 @@ +package jaxx.runtime.validator.swing.ui; + +import jaxx.runtime.validator.ValidatorErrorEvent; +import jaxx.runtime.validator.ValidatorErrorListener; +import jaxx.runtime.validator.ValidatorField; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jdesktop.jxlayer.plaf.AbstractLayerUI; + +/** + * Abstract renderer + * + * @author chemit + */ +public abstract class AbstractBeanValidatorUI extends AbstractLayerUI<javax.swing.JComponent> implements ValidatorErrorListener { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static final Log log = LogFactory.getLog(AbstractBeanValidatorUI.class); + + /** the field to render */ + protected ValidatorField field; + + public AbstractBeanValidatorUI(ValidatorField field) { + this.field = field; + if (log.isInfoEnabled()) { + log.info("install " + this + "<field:" + field + ">"); + } + } + + @Override + public void onNewError(ValidatorErrorEvent event) { + dispatchValidatorErrorEvent(event); + } + + @Override + public void onResolvedError(ValidatorErrorEvent event) { + dispatchValidatorErrorEvent(event); + } + + protected void dispatchValidatorErrorEvent(ValidatorErrorEvent event) { + // check if event occurs to this field + if (!field.equals(event.getField())) { + return; + } + // repaint the layer + setDirty(true); + } + +} Deleted: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/IconValidationUI.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ui/IconValidationUI.java 2009-01-20 20:11:30 UTC (rev 1173) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/IconValidationUI.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -1,59 +0,0 @@ -package jaxx.runtime.validator.ui; - -import com.opensymphony.xwork2.ValidationAware; -import jaxx.runtime.validator.BeanValidator.Scope; -import org.jdesktop.jxlayer.JXLayer; - -import javax.swing.BorderFactory; -import javax.swing.JComponent; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.image.BufferedImage; - -/** @author chemit */ -public class IconValidationUI extends AbstractBeanValidatorUI { - - // The icon to be shown at the layer's corner - protected BufferedImage invalidIcon; - - protected Color hightlight; - - public IconValidationUI(String field, String componentId, Scope scope, ValidationAware validationContext) { - super(field, componentId, scope, validationContext); - int width = 7; - int height = 8; - hightlight = scope == Scope.ERROR ? Color.RED : Color.YELLOW; - invalidIcon = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - Graphics2D g2 = (Graphics2D) invalidIcon.getGraphics(); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); - g2.setColor(hightlight); - g2.fillRect(0, 0, width, height); - g2.setColor(Color.WHITE); - g2.drawLine(0, 0, width, height); - g2.drawLine(0, height, width, 0); - g2.dispose(); - } - - @Override - public void installUI(JComponent c) { - super.installUI(c); - c.setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 3)); - } - - @Override - public void uninstallUI(JComponent c) { - super.uninstallUI(c); - c.setBorder(null); - } - - @Override - protected void paintLayer(Graphics2D g2, JXLayer<JComponent> l) { - super.paintLayer(g2, l); - // There is no need to take insets into account for this painter - if (validationContext.getFieldErrors().containsKey(field)) { - g2.drawImage(invalidIcon, l.getWidth() - invalidIcon.getWidth() - 1, 0, null); - } - } -} Copied: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/IconValidationUI.java (from rev 1194, jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ui/IconValidationUI.java) =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/IconValidationUI.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/IconValidationUI.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -0,0 +1,83 @@ +package jaxx.runtime.validator.swing.ui; + +import jaxx.runtime.validator.ValidatorField; +import org.jdesktop.jxlayer.JXLayer; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; + +/** @author chemit */ +public class IconValidationUI extends AbstractBeanValidatorUI { + + // The icon to be shown at the layer's corner + protected static BufferedImage errorIcon; + protected static BufferedImage warningIcon; + + public IconValidationUI(ValidatorField field) { + super(field); + } + + @Override + public void installUI(JComponent c) { + super.installUI(c); + c.setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 3)); + } + + @Override + public void uninstallUI(JComponent c) { + super.uninstallUI(c); + c.setBorder(null); + } + + @Override + protected void paintLayer(Graphics2D g2, JXLayer<JComponent> l) { + super.paintLayer(g2, l); + // There is no need to take insets into account for this painter + switch (field.getScope()) { + case ERROR: + if (field.hasErrors()) { + g2.drawImage(getErrorIcon(), l.getWidth() - errorIcon.getWidth() - 1, 0, null); + } + break; + case WARNING: + if (field.hasWarnings()) { + g2.drawImage(getWarningIcon(), l.getWidth() - warningIcon.getWidth() - 1, 0, null); + } + break; + } + } + + protected static BufferedImage getErrorIcon() { + if (errorIcon == null) { + errorIcon = prepareIcon(Color.RED); + } + return errorIcon; + } + + protected static BufferedImage getWarningIcon() { + if (warningIcon == null) { + warningIcon = prepareIcon(Color.YELLOW); + } + return warningIcon; + } + + protected static BufferedImage prepareIcon(Color color) { + int width = 7; + int height = 8; + BufferedImage icon = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = (Graphics2D) icon.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + g2.setColor(color); + g2.fillRect(0, 0, width, height); + g2.setColor(Color.WHITE); + g2.drawLine(0, 0, width, height); + g2.drawLine(0, height, width, 0); + g2.dispose(); + return icon; + } +} Deleted: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/ImageValidationUI.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ui/ImageValidationUI.java 2009-01-20 20:11:30 UTC (rev 1173) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/ImageValidationUI.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -1,68 +0,0 @@ -package jaxx.runtime.validator.ui; - -import com.opensymphony.xwork2.ValidationAware; -import jaxx.runtime.validator.BeanValidator.Scope; -import org.jdesktop.jxlayer.JXLayer; - -import javax.swing.BorderFactory; -import javax.swing.ImageIcon; -import javax.swing.JComponent; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.image.BufferedImage; - -/** @author chemit */ -public class ImageValidationUI extends AbstractBeanValidatorUI { - - // The icon to be shown at the layer's corner - protected BufferedImage invalidIcon; - - protected Color hightlight; - - public ImageValidationUI(String field, String componentId, Scope scope, ValidationAware validationContext) { - super(field, componentId, scope, validationContext); - - hightlight = scope == Scope.ERROR ? Color.RED : Color.YELLOW; - ImageIcon image = null; - switch (scope) { - - case ERROR: - image = jaxx.runtime.Util.createImageIcon("error.png"); - break; - case WARNING: - image = jaxx.runtime.Util.createImageIcon("warning.png"); - break; - } - //int width = 7; - //int height = 8; - invalidIcon = new BufferedImage(image.getIconWidth(), image.getIconHeight(), BufferedImage.TYPE_INT_ARGB); - - Graphics2D g2 = (Graphics2D) invalidIcon.getGraphics(); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); - g2.drawImage(image.getImage(), 0, 0, null); - g2.dispose(); - } - - @Override - public void installUI(JComponent c) { - super.installUI(c); - c.setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 3)); - } - - @Override - public void uninstallUI(JComponent c) { - super.uninstallUI(c); - c.setBorder(null); - } - - @Override - protected void paintLayer(Graphics2D g2, JXLayer<JComponent> l) { - super.paintLayer(g2, l); - // There is no need to take insets into account for this painter - if (validationContext.getFieldErrors().containsKey(field)) { - g2.drawImage(invalidIcon, l.getWidth() - invalidIcon.getWidth() - 1, 0, null); - } - } -} \ No newline at end of file Copied: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/ImageValidationUI.java (from rev 1194, jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ui/ImageValidationUI.java) =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/ImageValidationUI.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/ImageValidationUI.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -0,0 +1,75 @@ +package jaxx.runtime.validator.swing.ui; + +import jaxx.runtime.validator.ValidatorField; +import org.jdesktop.jxlayer.JXLayer; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; + +/** @author chemit */ +public class ImageValidationUI extends AbstractBeanValidatorUI { + + protected static BufferedImage errorIcon; + protected static BufferedImage warningIcon; + + public ImageValidationUI(ValidatorField field) { + super(field); + } + + protected static BufferedImage prepareIcon(ImageIcon image) { + BufferedImage icon = new BufferedImage(image.getIconWidth(), image.getIconHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = (Graphics2D) icon.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + g2.drawImage(image.getImage(), 0, 0, null); + g2.dispose(); + return icon; + } + + @Override + public void installUI(JComponent c) { + super.installUI(c); + c.setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 3)); + } + + @Override + public void uninstallUI(JComponent c) { + super.uninstallUI(c); + c.setBorder(null); + } + + @Override + protected void paintLayer(Graphics2D g2, JXLayer<JComponent> l) { + super.paintLayer(g2, l); + switch (field.getScope()) { + case ERROR: + if (field.hasErrors()) { + g2.drawImage(getErrorIcon(), l.getWidth() - errorIcon.getWidth() - 1, 0, null); + } + break; + case WARNING: + if (field.hasWarnings()) { + g2.drawImage(getWarningIcon(), l.getWidth() - warningIcon.getWidth() - 1, 0, null); + } + break; + } + } + + protected static BufferedImage getErrorIcon() { + if (errorIcon == null) { + errorIcon = prepareIcon(jaxx.runtime.Util.createImageIcon("error.png")); + } + return errorIcon; + } + + protected static BufferedImage getWarningIcon() { + if (warningIcon == null) { + warningIcon = prepareIcon(jaxx.runtime.Util.createImageIcon("warning.png")); + } + return warningIcon; + } +} \ No newline at end of file Deleted: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/TranslucentValidationUI.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ui/TranslucentValidationUI.java 2009-01-20 20:11:30 UTC (rev 1173) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/TranslucentValidationUI.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -1,45 +0,0 @@ -package jaxx.runtime.validator.ui; - -import com.opensymphony.xwork2.ValidationAware; -import jaxx.runtime.validator.BeanValidator.Scope; -import org.jdesktop.jxlayer.JXLayer; - -import javax.swing.JComponent; -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Insets; -import java.awt.Rectangle; - -/** @author chemit */ -public class TranslucentValidationUI extends AbstractBeanValidatorUI { - - protected Color hightlight; - - public TranslucentValidationUI(String field, String componentId, Scope scope, ValidationAware validationContext) { - super(field, componentId, scope, validationContext); - hightlight = scope == Scope.ERROR ? Color.RED : Color.YELLOW; - } - - @Override - protected void paintLayer(Graphics2D g2, JXLayer<JComponent> l) { - // paints the layer as is - super.paintLayer(g2, l); - - // to be in sync with the view if the layer has a border - Insets layerInsets = l.getInsets(); - g2.translate(layerInsets.left, layerInsets.top); - - JComponent view = l.getView(); - // To prevent painting on view's border - Insets insets = view.getInsets(); - g2.clip(new Rectangle(insets.left, insets.top, - view.getWidth() - insets.left - insets.right, - view.getHeight() - insets.top - insets.bottom)); - - g2.setColor(!validationContext.getFieldErrors().containsKey(field) ? - Color.GREEN : Color.RED); - g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .2f)); - g2.fillRect(0, 0, l.getWidth(), l.getHeight()); - } -} Copied: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/TranslucentValidationUI.java (from rev 1194, jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/ui/TranslucentValidationUI.java) =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/TranslucentValidationUI.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/swing/ui/TranslucentValidationUI.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -0,0 +1,61 @@ +package jaxx.runtime.validator.swing.ui; + +import jaxx.runtime.validator.ValidatorField; +import org.jdesktop.jxlayer.JXLayer; + +import javax.swing.JComponent; +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Rectangle; + +/** @author chemit */ +public class TranslucentValidationUI extends AbstractBeanValidatorUI { + + protected Color errorHightlight; + protected Color warningHightlight; + + public TranslucentValidationUI(ValidatorField field) { + super(field); + errorHightlight = Color.RED; + warningHightlight = Color.YELLOW; + } + + @Override + protected void paintLayer(Graphics2D g2, JXLayer<JComponent> l) { + // paints the layer as is + super.paintLayer(g2, l); + + // to be in sync with the view if the layer has a border + Insets layerInsets = l.getInsets(); + g2.translate(layerInsets.left, layerInsets.top); + + JComponent view = l.getView(); + // To prevent painting on view's border + Insets insets = view.getInsets(); + g2.clip(new Rectangle(insets.left, insets.top, + view.getWidth() - insets.left - insets.right, + view.getHeight() - insets.top - insets.bottom)); + + switch (field.getScope()) { + + case ERROR: + if (field.hasErrors()) { + g2.setColor(errorHightlight); + } else { + g2.setColor(Color.WHITE); + } + break; + case WARNING: + if (field.hasErrors()) { + g2.setColor(warningHightlight); + } else { + g2.setColor(Color.WHITE); + } + break; + } + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .2f)); + g2.fillRect(0, 0, l.getWidth(), l.getHeight()); + } +} Modified: jaxx/trunk/jaxx-runtime-validator/src/test/java/jaxx/runtime/validator/field/AbstractValidatorTest.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/test/java/jaxx/runtime/validator/field/AbstractValidatorTest.java 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-runtime-validator/src/test/java/jaxx/runtime/validator/field/AbstractValidatorTest.java 2009-02-03 09:37:45 UTC (rev 1195) @@ -1,6 +1,6 @@ package jaxx.runtime.validator.field; -import jaxx.runtime.validator.SimpleBeanValidator; +import jaxx.runtime.validator.BeanValidator; import jaxx.runtime.validator.ValidatorField; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -24,7 +24,7 @@ /** to use log facility, just put in your code: log.info(\"...\"); */ static private final Log log = LogFactory.getLog(AbstractValidatorTest.class); - static protected SimpleBeanValidator<ValidatorBean> validator; + static protected BeanValidator<ValidatorBean> validator; static protected File basedir; @@ -45,7 +45,7 @@ b = new File("").getAbsolutePath(); } basedir = new File(b); - validator = new SimpleBeanValidator<ValidatorBean>(ValidatorBean.class, null); + validator = new BeanValidator<ValidatorBean>(ValidatorBean.class, null); } @Before Modified: jaxx/trunk/jaxx-swing-action/src/main/resources/i18n/jaxx-swing-action-fr_FR.properties =================================================================== --- jaxx/trunk/jaxx-swing-action/src/main/resources/i18n/jaxx-swing-action-fr_FR.properties 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/jaxx-swing-action/src/main/resources/i18n/jaxx-swing-action-fr_FR.properties 2009-02-03 09:37:45 UTC (rev 1195) @@ -1,4 +1,4 @@ -jaxx.action.done=Action '%1$s' termin\u00e9e. +jaxx.action.done=Action '%1$s' termin\u00E9e. jaxx.error.close.actions.file=Erreur lors de la fermeture du fichier d'actions jaxx.error.load.actions.class=Erreur lors du chargement des actions jaxx.error.load.actions.file=Erreur lors du chargement du fchier d'actions Modified: jaxx/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/Validation.jaxx =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/Validation.jaxx 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/Validation.jaxx 2009-02-03 09:37:45 UTC (rev 1195) @@ -16,13 +16,13 @@ <field name="ratio"/> </BeanValidator> <BeanValidator id='validator2' bean='model2' errorListModel='errors' - uiClass="jaxx.runtime.validator.ui.IconValidationUI"> + uiClass="jaxx.runtime.validator.swing.ui.IconValidationUI"> <field name="text" component="_text"/> <field name="text2" component="_text2"/> <field name="ratio" component="_ratio"/> </BeanValidator> <BeanValidator id='validator3' autoField='true' bean='identity' errorListModel='errors' - uiClass="jaxx.runtime.validator.ui.TranslucentValidationUI"> + uiClass="jaxx.runtime.validator.swing.ui.TranslucentValidationUI"> <field name="email" component="email2"/> </BeanValidator> Modified: jaxx/trunk/src/site/fr/rst/BeanValidator.rst =================================================================== --- jaxx/trunk/src/site/fr/rst/BeanValidator.rst 2009-02-03 01:38:07 UTC (rev 1194) +++ jaxx/trunk/src/site/fr/rst/BeanValidator.rst 2009-02-03 09:37:45 UTC (rev 1195) @@ -73,7 +73,7 @@ * *errorListModel* : le modèle qui contient la liste des erreurs (et est liée au composant *errorList*), doit étendre *jaxx.runtime.validator.swing.SwingValidatorErrorListModel*. Si non présent on essayera le composent d'id *errorListModel*. - * *uiClass* : le FQN de la classe utilisé pour le rendu des erreurs sur les wigets d'édition. La classe doit étendre *jaxx.runtime.validator.ui.AbstractBeanValidatorUI*. Si non présent, on utilise par défaut le render *jaxx.runtime.validator.ui.IconValidationUI*. + * *uiClass* : le FQN de la classe utilisé pour le rendu des erreurs sur les wigets d'édition. La classe doit étendre *jaxx.runtime.validator.swing.ui.AbstractBeanValidatorUI*. Si non présent, on utilise par défaut le render *jaxx.runtime.validator.swing.ui.IconValidationUI*. Le tag supporte aussi l'ajout de tag *field* comme fils pour définir explicitement des champs à validater.