This is an automated email from the git hooks/post-receive script. New commit to annotated tag v3.0-alpha-1 in repository nuiton-validator. See https://gitlab.nuiton.org/nuiton/nuiton-validator.git commit 904321926398881581a338e5a9c67828969cab69 Author: Maven Release Manager <???> Date: Tue Jul 23 15:54:51 2013 +0000 [maven-release-plugin] copy for tag nuiton-validator-3.0-alpha-1 --- LICENSE.txt | 166 ++++++ README.txt | 0 pom.xml | 308 ++++++++++++ src/license/THIRD-PARTY.properties | 20 + .../validator/AbstractNuitonValidatorProvider.java | 119 +++++ .../java/org/nuiton/validator/NuitonValidator.java | 86 ++++ .../nuiton/validator/NuitonValidatorFactory.java | 176 +++++++ .../org/nuiton/validator/NuitonValidatorModel.java | 86 ++++ .../nuiton/validator/NuitonValidatorProvider.java | 104 ++++ .../nuiton/validator/NuitonValidatorResult.java | 308 ++++++++++++ .../org/nuiton/validator/NuitonValidatorScope.java | 78 +++ .../bean/AbstractNuitonValidatorContext.java | 389 ++++++++++++++ .../nuiton/validator/bean/AbstractValidator.java | 390 ++++++++++++++ .../validator/bean/AbstractValidatorEvent.java | 85 ++++ .../nuiton/validator/bean/ValidatorCreator.java | 53 ++ .../nuiton/validator/bean/ValidatorListener.java | 47 ++ .../validator/bean/list/BeanListValidator.java | 560 +++++++++++++++++++++ .../bean/list/BeanListValidatorEvent.java | 56 +++ .../bean/list/BeanListValidatorListener.java | 37 ++ .../bean/list/BeanListValidatorMessage.java | 152 ++++++ .../nuiton/validator/bean/list/package-info.java | 58 +++ .../org/nuiton/validator/bean/package-info.java | 71 +++ .../validator/bean/simple/SimpleBeanValidator.java | 478 ++++++++++++++++++ .../bean/simple/SimpleBeanValidatorEvent.java | 51 ++ .../bean/simple/SimpleBeanValidatorListener.java | 38 ++ .../bean/simple/SimpleBeanValidatorMessage.java | 144 ++++++ .../bean/simple/SimpleBeanValidators.java | 75 +++ .../nuiton/validator/bean/simple/package-info.java | 57 +++ .../java/org/nuiton/validator/package-info.java | 55 ++ .../validator/xwork2/XWork2NuitonValidator.java | 135 +++++ .../xwork2/XWork2NuitonValidatorProvider.java | 309 ++++++++++++ .../validator/xwork2/XWork2ScopeValidator.java | 224 +++++++++ .../validator/xwork2/XWork2ValidatorUtil.java | 232 +++++++++ .../field/CollectionFieldExpressionValidator.java | 489 ++++++++++++++++++ .../xwork2/field/CollectionUniqueKeyValidator.java | 323 ++++++++++++ .../xwork2/field/EmailFieldValidator.java | 66 +++ .../field/ExistingDirectoryFieldValidator.java | 95 ++++ .../xwork2/field/ExistingFileFieldValidator.java | 95 ++++ .../field/FieldExpressionWithParamsValidator.java | 223 ++++++++ .../xwork2/field/FrenchCityNameFieldValidator.java | 75 +++ .../xwork2/field/FrenchFinessFieldValidator.java | 92 ++++ .../xwork2/field/FrenchLastNameFieldValidator.java | 73 +++ .../field/FrenchPhoneNumberFieldValidator.java | 76 +++ .../xwork2/field/FrenchPostCodeFieldValidator.java | 76 +++ .../xwork2/field/FrenchSiretFieldValidator.java | 176 +++++++ .../field/NotExistingDirectoryFieldValidator.java | 94 ++++ .../field/NotExistingFileFieldValidator.java | 95 ++++ .../field/NuitonFieldExpressionValidator.java | 136 +++++ .../xwork2/field/NuitonFieldValidatorSupport.java | 139 +++++ .../xwork2/field/RequiredFileFieldValidator.java | 95 ++++ .../field/SkipableRequiredFieldValidator.java | 43 ++ .../SkipableRequiredStringFieldValidator.java | 43 ++ .../VATIdentificationNumberFieldValidator.java | 78 +++ .../validator/xwork2/field/package-info.java | 31 ++ .../org/nuiton/validator/xwork2/package-info.java | 31 ++ .../org.nuiton.validator.NuitonValidatorProvider | 1 + .../i18n/nuiton-validator_en_GB.properties | 4 + .../i18n/nuiton-validator_es_ES.properties | 4 + .../i18n/nuiton-validator_fr_FR.properties | 4 + src/site/apt/index.apt | 98 ++++ src/site/apt/versions.apt | 33 ++ src/site/site_fr.xml | 109 ++++ .../validator/AbstractValidatorDetectorTest.java | 159 ++++++ .../validator/NuitonValidatorFactoryTest.java | 59 +++ .../org/nuiton/validator/ValidatorTestHelper.java | 173 +++++++ .../java/org/nuiton/validator/bean/SimpleBean.java | 78 +++ .../validator/bean/list/BeanListValidatorTest.java | 528 +++++++++++++++++++ .../bean/simple/SimpleBeanValidatorTest.java | 313 ++++++++++++ .../java/org/nuiton/validator/model/Company.java | 55 ++ .../java/org/nuiton/validator/model/Contact.java | 91 ++++ .../validator/model/HealthEstablishment.java | 44 ++ .../model/ModelValidatorDetectorTestImpl.java | 186 +++++++ .../java/org/nuiton/validator/model/Person.java | 93 ++++ src/test/java/org/nuiton/validator/model/Pet.java | 98 ++++ src/test/java/org/nuiton/validator/model/Race.java | 55 ++ .../xwork2/XWork2NuitonValidatorProviderTest.java | 167 ++++++ .../xwork2/XWork2NuitonValidatorTest.java | 59 +++ .../xwork2/field/AbstractFieldValidatorTest.java | 132 +++++ .../AbstractValidatorBeanFieldValidatorTest.java | 37 ++ .../CollectionFieldExpressionValidatorTest.java | 265 ++++++++++ .../field/CollectionUniqueKeyValidatorTest.java | 114 +++++ .../xwork2/field/EmailFieldValidatorTest.java | 68 +++ .../field/ExistingDirectoryFieldValidatorTest.java | 57 +++ .../field/ExistingFileFieldValidatorTest.java | 57 +++ .../xwork2/field/FieldExpressionBean.java | 131 +++++ .../FieldExpressionWithParamsValidatorTest.java | 144 ++++++ .../field/FrenchCityNameFieldValidatorTest.java | 106 ++++ .../field/FrenchFinessFieldValidatorTest.java | 85 ++++ .../field/FrenchLastNameFieldValidatorTest.java | 87 ++++ .../field/FrenchPhoneNumberFieldValidatorTest.java | 134 +++++ .../field/FrenchPostCodeFieldValidatorTest.java | 92 ++++ .../field/FrenchSiretFieldValidatorTest.java | 103 ++++ .../NotExistingDirectoryFieldValidatorTest.java | 60 +++ .../field/NotExistingFileFieldValidatorTest.java | 63 +++ .../field/RequiredFileFieldValidatorTest.java | 56 +++ .../VATIdentificationNumberFieldValidatorTest.java | 80 +++ .../validator/xwork2/field/ValidatorBean.java | 182 +++++++ src/test/resources/log4j.properties | 32 ++ .../validator/bean/SimpleBean-error-validation.xml | 42 ++ .../validator/bean/SimpleBean-fatal-validation.xml | 46 ++ .../validator/bean/SimpleBean-info-validation.xml | 36 ++ .../bean/SimpleBean-marchepo-error-validation.xml | 37 ++ .../bean/SimpleBean-simple-validation.xml | 42 ++ .../bean/SimpleBean-warning-validation.xml | 36 ++ .../legacy/SimpleBean-error-validation.xml | 42 ++ .../legacy/SimpleBean-fatal-validation.xml | 46 ++ .../legacy/SimpleBean-info-validation.xml | 36 ++ .../legacy/SimpleBean-simple-validation.xml | 42 ++ .../legacy/SimpleBean-warning-validation.xml | 36 ++ .../validator/model/Company-error-validation.xml | 41 ++ .../validator/model/Contact-error-validation.xml | 57 +++ .../model/HealthEstablishment-error-validation.xml | 33 ++ .../validator/model/Person-error-validation.xml | 41 ++ .../validator/model/Person-warning-validation.xml | 37 ++ .../model/Pet-context-info-validation.xml | 33 ++ .../validator/model/Pet-error-validation.xml | 33 ++ .../field/FieldExpressionBean-error-validation.xml | 122 +++++ .../field/ValidatorBean-error-validation.xml | 177 +++++++ src/test/resources/validators.xml | 75 +++ 119 files changed, 13377 insertions(+) diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..e69de29 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..acaeea5 --- /dev/null +++ b/pom.xml @@ -0,0 +1,308 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.nuiton</groupId> + <artifactId>mavenpom4redmineAndCentral</artifactId> + <version>3.4.13</version> + </parent> + + <artifactId>nuiton-validator</artifactId> + <version>3.0-alpha-1</version> + + <name>Nuiton Validator</name> + <description>Simple Validator API</description> + <url>http://maven-site.nuiton.org/nuiton-validator</url> + <inceptionYear>2013</inceptionYear> + + <developers> + + <developer> + <name>Tony Chemit</name> + <id>tchemit</id> + <email>chemit at codelutin dot com</email> + <organization>CodeLutin</organization> + <organizationUrl>http://www.codelutin.com/</organizationUrl> + <timezone>Europe/Paris</timezone> + <roles> + <role>developer</role> + </roles> + </developer> + + </developers> + + <scm> + <connection> + scm:svn:http://svn.nuiton.org/svn/nuiton-validator/tags/nuiton-validator-3.0-alpha-1 + </connection> + <developerConnection> + scm:svn:http://svn.nuiton.org/svn/nuiton-validator/tags/nuiton-validator-3.0-alpha-1 + </developerConnection> + <url>http://nuiton.org/projects/nuiton-validator/repository/show/tags/nuiton-validator-3.0-alpha-1</url> + </scm> + <distributionManagement> + <site> + <id>${platform}</id> + <url>${our.site.repository}/${projectId}</url> + </site> + </distributionManagement> + + <properties> + + <projectId>nuiton-validator</projectId> + + <nuitonI18nVersion>2.5.2</nuitonI18nVersion> + + <!-- i18n configuration --> + <i18n.bundles>fr_FR,en_GB,es_ES</i18n.bundles> + + <!-- Documentation is in apt format --> + <siteSourcesType>apt</siteSourcesType> + + <!-- extra files to include in release --> + <redmine.releaseFiles>${redmine.libReleaseFiles}</redmine.releaseFiles> + + </properties> + + <dependencies> + + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>nuiton-utils</artifactId> + <version>2.6.12</version> + </dependency> + + <dependency> + <groupId>org.nuiton.i18n</groupId> + <artifactId>nuiton-i18n</artifactId> + <version>${nuitonI18nVersion}</version> + </dependency> + + <dependency> + <groupId>org.apache.struts.xwork</groupId> + <artifactId>xwork-core</artifactId> + <version>2.3.15.1</version> + <exclusions> + <exclusion> + <groupId>asm</groupId> + <artifactId>asm</artifactId> + </exclusion> + <exclusion> + <groupId>asm</groupId> + <artifactId>asm-commons</artifactId> + </exclusion> + </exclusions> + </dependency> + + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> + + <dependency> + <groupId>commons-beanutils</groupId> + <artifactId>commons-beanutils</artifactId> + </dependency> + + <dependency> + <groupId>commons-collections</groupId> + <artifactId>commons-collections</artifactId> + </dependency> + + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <scope>provided</scope> + </dependency> + + </dependencies> + + <build> + <pluginManagement> + <plugins> + + <!-- plugin i18n --> + <plugin> + <groupId>org.nuiton.i18n</groupId> + <artifactId>i18n-maven-plugin</artifactId> + <version>${nuitonI18nVersion}</version> + </plugin> + + </plugins> + </pluginManagement> + <plugins> + + <!-- plugin i18n --> + <plugin> + <groupId>org.nuiton.i18n</groupId> + <artifactId>i18n-maven-plugin</artifactId> + <configuration> + <silent>true</silent> + <bundles>fr_FR,en_GB,es_ES</bundles> + </configuration> + <executions> + <execution> + <goals> + <goal>parserJava</goal> + <goal>gen</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <artifactId>maven-jar-plugin</artifactId> + <executions> + <execution> + <id>attach-test</id> + <goals> + <goal>test-jar</goal> + </goals> + </execution> + </executions> + </plugin> + + </plugins> + </build> + + <profiles> + + <profile> + <id>reporting</id> + <activation> + <property> + <name>performRelease</name> + <value>true</value> + </property> + </activation> + + <reporting> + <plugins> + + <plugin> + <artifactId>maven-project-info-reports-plugin</artifactId> + <version>${projectInfoReportsPluginVersion}</version> + <reportSets> + <reportSet> + <reports> + <report>project-team</report> + <report>mailing-list</report> + <report>cim</report> + <report>issue-tracking</report> + <report>license</report> + <report>scm</report> + <report>dependency-info</report> + <report>dependencies</report> + <report>dependency-convergence</report> + <report>plugin-management</report> + <report>plugins</report> + <report>dependency-management</report> + <report>summary</report> + </reports> + </reportSet> + </reportSets> + </plugin> + + </plugins> + </reporting> + + </profile> + + <!-- create assemblies at release time --> + <profile> + <id>assembly-profile</id> + <activation> + <property> + <name>performRelease</name> + <value>true</value> + </property> + </activation> + <build> + <defaultGoal>package</defaultGoal> + <plugins> + + <!-- launch in a release the assembly automaticly --> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <executions> + <execution> + <id>create-assemblies</id> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + <configuration> + <attach>false</attach> + <descriptorRefs> + <descriptorRef>deps</descriptorRef> + <descriptorRef>full</descriptorRef> + </descriptorRefs> + </configuration> + </plugin> + + </plugins> + + </build> + </profile> + + <!-- perform only on a release stage when using the maven-release-plugin --> + <profile> + <id>release-profile</id> + <activation> + <property> + <name>performRelease</name> + <value>true</value> + </property> + </activation> + + <build> + <plugins> + + <!-- always compute tests source jar --> + <plugin> + <artifactId>maven-source-plugin</artifactId> + <executions> + <execution> + <id>attach-test-sources</id> + </execution> + </executions> + </plugin> + + <!-- always compute tests javadoc jar --> + <plugin> + <artifactId>maven-javadoc-plugin</artifactId> + <executions> + <execution> + <id>attach-test-javadoc</id> + <goals> + <goal>test-jar</goal> + </goals> + </execution> + </executions> + </plugin> + + </plugins> + </build> + </profile> + + </profiles> +</project> diff --git a/src/license/THIRD-PARTY.properties b/src/license/THIRD-PARTY.properties new file mode 100644 index 0000000..df76be0 --- /dev/null +++ b/src/license/THIRD-PARTY.properties @@ -0,0 +1,20 @@ +# Generated by org.codehaus.mojo.license.AddThirdPartyMojo +#------------------------------------------------------------------------------- +# Already used licenses in project : +# - BSD License +# - COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 +# - Common Public License Version 1.0 +# - Indiana University Extreme! Lab Software License, vesion 1.1.1 +# - Lesser General Public License (LGPL) v 3.0 +# - Lesser General Public License (LPGL) +# - Lesser General Public License (LPGL) v 2.1 +# - MIT License +# - New BSD License +# - The Apache Software License, Version 2.0 +#------------------------------------------------------------------------------- +# Please fill the missing licenses for dependencies : +# +# +#Sat Jul 20 16:25:49 CEST 2013 +commons-primitives--commons-primitives--1.0=The Apache Software License, Version 2.0 +javassist--javassist--3.11.0.GA=The Apache Software License, Version 2.0 diff --git a/src/main/java/org/nuiton/validator/AbstractNuitonValidatorProvider.java b/src/main/java/org/nuiton/validator/AbstractNuitonValidatorProvider.java new file mode 100644 index 0000000..5ff165a --- /dev/null +++ b/src/main/java/org/nuiton/validator/AbstractNuitonValidatorProvider.java @@ -0,0 +1,119 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * Abstract provider of validator. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public abstract class AbstractNuitonValidatorProvider implements NuitonValidatorProvider { + + protected Map<ModelEntry<?>, NuitonValidatorModel<?>> models; + + protected final String name; + + public AbstractNuitonValidatorProvider(String name) { + this.name = name; + } + + @Override + public <O> NuitonValidatorModel<O> getModel(Class<O> type, String context, NuitonValidatorScope... scopes) { + ModelEntry<O> key = ModelEntry.createModelEntry(type, context, scopes); + + @SuppressWarnings({"unchecked"}) + NuitonValidatorModel<O> model = (NuitonValidatorModel<O>) getModels().get(key); + + if (model == null) { + model = newModel(type, context, scopes); + } + return model; + } + + protected Map<ModelEntry<?>, NuitonValidatorModel<?>> getModels() { + if (models == null) { + models = new HashMap<ModelEntry<?>, NuitonValidatorModel<?>>(); + } + return models; + } + + protected static class ModelEntry<O> implements Serializable { + + private static final long serialVersionUID = 1L; + + protected final Class<O> type; + + protected final String context; + + protected final NuitonValidatorScope[] scopes; + + public static <O> ModelEntry<O> createModelEntry(Class<O> type, + String context, + NuitonValidatorScope... scopes) { + return new ModelEntry<O>(type, context, scopes); + } + + protected ModelEntry(Class<O> type, + String context, + NuitonValidatorScope... scopes) { + this.type = type; + this.context = context; + this.scopes = scopes == null ? NuitonValidatorScope.values() : scopes; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ModelEntry)) return false; + + ModelEntry<?> that = (ModelEntry<?>) o; + + if (context != null ? !context.equals(that.context) : that.context != null) + return false; + if (!Arrays.equals(scopes, that.scopes)) return false; + return type.equals(that.type); + + } + + @Override + public int hashCode() { + int result = type.hashCode(); + result = 31 * result + (context != null ? context.hashCode() : 0); + result = 31 * result + Arrays.hashCode(scopes); + return result; + } + } + + @Override + public String getName() { + return name; + } + +} diff --git a/src/main/java/org/nuiton/validator/NuitonValidator.java b/src/main/java/org/nuiton/validator/NuitonValidator.java new file mode 100644 index 0000000..abfc1f1 --- /dev/null +++ b/src/main/java/org/nuiton/validator/NuitonValidator.java @@ -0,0 +1,86 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator; + +import java.util.Set; + +/** + * Contract of a validator. + * <p/> + * To obtain validator, see the {@link NuitonValidatorFactory} api. + * + * @author tchemit <chemit@codelutin.com> + * @see NuitonValidatorFactory + * @since 2.0 + */ +public interface NuitonValidator<O> { + + /** + * Validates the given object and returns the result of validation. + * + * @param object the object to validate + * @return the result of validation for the given object + * @throws NullPointerException if object is {@code null}. + */ + NuitonValidatorResult validate(O object) throws NullPointerException; + + /** + * Obtains the model of the validator. + * + * @return the model of the validator + */ + NuitonValidatorModel<O> getModel(); + + /** + * Obtains the set of effective scopes for the validator : means the very + * scopes that the validator is dealing with. + * <p/> + * This is a subset of the model authorized scopes. + * + * @return the set of effective scopes of the validator + */ + Set<NuitonValidatorScope> getEffectiveScopes(); + + /** + * Obtains the set of effective fields for the validator : means the very + * fields validated by the validator. + * <p/> + * This is a sub set of fields of the object to validate. + * + * @return the set of effective fields of the validator + */ + Set<String> getEffectiveFields(); + + /** + * Obtains the set of effective fields for the validator for the given scope + * : means the very fields validated by the validator. + * <p/> + * This is a subset of effective fields of the validator. + * + * @param scope given scope to use + * @return the set of effective fields of the validator for the given scope + */ + Set<String> getEffectiveFields(NuitonValidatorScope scope); + +} diff --git a/src/main/java/org/nuiton/validator/NuitonValidatorFactory.java b/src/main/java/org/nuiton/validator/NuitonValidatorFactory.java new file mode 100644 index 0000000..7a6ac47 --- /dev/null +++ b/src/main/java/org/nuiton/validator/NuitonValidatorFactory.java @@ -0,0 +1,176 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.Map; +import java.util.ServiceLoader; +import java.util.TreeMap; + +/** + * Factory to obtain new validators. + * <p/> + * The factory contains a cache of {@link NuitonValidatorModel}. + * <p/> + * To obtain a new validator with no context, use this code : + * <pre> + * NuitonValidator<O> validator = NuitonValidatorFactory.newValidator(O.class); + * </pre> + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class NuitonValidatorFactory { + + /** Logger. */ + private static final Log log = + LogFactory.getLog(NuitonValidatorFactory.class); + + protected static String defaultProviderName; + + protected static Map<String, NuitonValidatorProvider> providers; + + public static <O> NuitonValidator<O> newValidator(Class<O> type, + NuitonValidatorScope... scopes) { + NuitonValidator<O> result = newValidator(type, null, scopes); + return result; + } + + public static <O> NuitonValidator<O> newValidator(Class<O> type, + String context, + NuitonValidatorScope... scopes) { + + String providerName = getDefaultProviderName(); + + NuitonValidator<O> result = newValidator(providerName, + type, + context, + scopes); + return result; + } + + public static <O> NuitonValidator<O> newValidator(String providerName, + Class<O> type, + String context, + NuitonValidatorScope... scopes) throws NullPointerException { + + if (type == null) { + throw new NullPointerException( + "type parameter can not be null."); + } + + // get the provider + NuitonValidatorProvider provider = getProvider(providerName); + + + // obtain validator model form the provider + NuitonValidatorModel<O> model = + provider.getModel(type, context, scopes); + + // obtain validator from the the provider + NuitonValidator<O> result = provider.newValidator(model); + return result; + } + + public static Map<String, NuitonValidatorProvider> getProviders() { + if (providers == null) { + providers = new TreeMap<String, NuitonValidatorProvider>(); + ServiceLoader<NuitonValidatorProvider> serviceLoader = + ServiceLoader.load(NuitonValidatorProvider.class); + + for (NuitonValidatorProvider provider : serviceLoader) { + if (log.isInfoEnabled()) { + log.info("obtain validator provider " + provider.getName()); + } + providers.put(provider.getName(), provider); + } + } + return providers; + } + + public static NuitonValidatorProvider getProvider(String providerName) throws IllegalArgumentException, NullPointerException { + + if (providerName == null) { + + // take the default validator provider name + throw new NullPointerException( + "providerName parameter can not be null."); + } + + NuitonValidatorProvider provider = getProviders().get(providerName); + if (provider == null) { + throw new IllegalArgumentException( + "Could not find provider named '" + + defaultProviderName + "', existing providers are : " + + getProviders().keySet()); + } + return provider; + } + + public static NuitonValidatorProvider getDefaultProvider() { + String providerName = getDefaultProviderName(); + NuitonValidatorProvider provider = getProvider(providerName); + return provider; + } + + public static String getDefaultProviderName() throws IllegalStateException { + + if (defaultProviderName == null) { + + // takes the first provider from existing provider + + Map<String, NuitonValidatorProvider> providers = getProviders(); + if (providers.isEmpty()) { + throw new IllegalStateException( + "Could not find any provider of validator."); + } + defaultProviderName = providers.keySet().iterator().next(); + + if (log.isInfoEnabled()) { + log.info("Set the default provider name to " + defaultProviderName); + } + } + + return defaultProviderName; + } + + public static void setDefaultProviderName(String defaultProviderName) throws IllegalArgumentException, NullPointerException { + + if (defaultProviderName == null) { + throw new NullPointerException("defaultProviderName can not be null."); + } + // check provider exists + getProvider(defaultProviderName); + + NuitonValidatorFactory.defaultProviderName = defaultProviderName; + } + + protected NuitonValidatorFactory() { + // avoid instanciation of this factory + } + + +} diff --git a/src/main/java/org/nuiton/validator/NuitonValidatorModel.java b/src/main/java/org/nuiton/validator/NuitonValidatorModel.java new file mode 100644 index 0000000..fdd7422 --- /dev/null +++ b/src/main/java/org/nuiton/validator/NuitonValidatorModel.java @@ -0,0 +1,86 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +/** + * Represents the model of a {@link NuitonValidator}. + * <p/> + * This model describing properties of a validator : + * <ul> + * <li>{@link #type} : the type of object which can be validated by the validator</li> + * <li>{@link #context} : the context of validation, if no context is required then the context is {@code null}. + * <li>{@link #scopes} : the scopes of validation (see {@link NuitonValidatorScope})</li> + * <li>{@link #fields} : the fields that can be validated by the validator</li> + * </ul> + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class NuitonValidatorModel<O> implements Serializable { + + private static final long serialVersionUID = 1L; + + /** Type of object to validate */ + protected Class<O> type; + + /** Context of validation (can be {@code null}, for no context). */ + protected String context; + + /** Set of scopes that can be validated for the type and context */ + protected Set<NuitonValidatorScope> scopes; + + /** Set of fields that can be validated for the type and context */ + protected Map<NuitonValidatorScope, String[]> fields; + + public NuitonValidatorModel(Class<O> type, + String context, + Set<NuitonValidatorScope> scopes, + Map<NuitonValidatorScope, String[]> fields) { + this.type = type; + this.context = context; + this.scopes = Collections.unmodifiableSet(scopes); + this.fields = Collections.unmodifiableMap(fields); + } + + public Class<O> getType() { + return type; + } + + public String getContext() { + return context; + } + + public Set<NuitonValidatorScope> getScopes() { + return scopes; + } + + public Map<NuitonValidatorScope, String[]> getFields() { + return fields; + } +} diff --git a/src/main/java/org/nuiton/validator/NuitonValidatorProvider.java b/src/main/java/org/nuiton/validator/NuitonValidatorProvider.java new file mode 100644 index 0000000..67399d5 --- /dev/null +++ b/src/main/java/org/nuiton/validator/NuitonValidatorProvider.java @@ -0,0 +1,104 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator; + +import java.io.File; +import java.util.ServiceLoader; +import java.util.SortedSet; +import java.util.regex.Pattern; + +/** + * Provider of {@link NuitonValidator}. + * <p/> + * An implementation of a such class provides a implementation of a validator models + * and also of validator. + * <p/> + * <b>Note:</b> Providers are used in the {@link NuitonValidatorFactory} and + * should be registered via the {@link ServiceLoader} api. + * + * @author tchemit <chemit@codelutin.com> + * @see NuitonValidatorModel + * @see NuitonValidator + * @see ServiceLoader + * @since 2.0 + */ +public interface NuitonValidatorProvider { + + /** + * Obtains the name of the provider. + * + * @return the name of the provider. + */ + String getName(); + + /** + * Obtain a validator model, the model should be cached and not be + * reinstanciated at each time a validator model is asked. + * + * @param type type of the class to validate + * @param context context of validation ({@code null} if no context) + * @param scopes filtered scope (if nothing given, then use all scopes) + * @param <O> type of the class to validate + * @return the cached model of validation + */ + <O> NuitonValidatorModel<O> getModel(Class<O> type, + String context, + NuitonValidatorScope... scopes); + + /** + * Instanciate a new validator model for the given parameters. + * + * @param type type of the class to validate + * @param context context of validation ({@code null} if no context) + * @param scopes filtered scope (if nothing given, then use all scopes) + * @param <O> type of the class to validate + * @return the new instanciated model of validation + */ + <O> NuitonValidatorModel<O> newModel(Class<O> type, + String context, + NuitonValidatorScope... scopes); + + /** + * Obtains a new validator for the given {@code model}. + * + * @param model the model of validator to use + * @param <O> type of class to validate + * @return the new validator + */ + <O> NuitonValidator<O> newValidator(NuitonValidatorModel<O> model); + + /** + * Detects in the given directory validators. + * + * @param sourceRoot root directory where to seek for validators + * @param contextFilter the pattern of context to seek + * @param scopes scopes to seek (if none given, will seek for all scopes) + * @param types types of class to seek + * @return the set of validators found + */ + SortedSet<NuitonValidator<?>> detectValidators(File sourceRoot, + Pattern contextFilter, + NuitonValidatorScope[] scopes, + Class<?>... types); +} diff --git a/src/main/java/org/nuiton/validator/NuitonValidatorResult.java b/src/main/java/org/nuiton/validator/NuitonValidatorResult.java new file mode 100644 index 0000000..d3dfa8c --- /dev/null +++ b/src/main/java/org/nuiton/validator/NuitonValidatorResult.java @@ -0,0 +1,308 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator; + +import org.apache.commons.collections.MapUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +/** + * Contains validation messages coming from the method + * {@link NuitonValidator#validate(Object)}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class NuitonValidatorResult { + + public static class FieldMap<V> extends TreeMap<String, V> { + + private static final long serialVersionUID = 1L; + } + + protected EnumMap<NuitonValidatorScope, FieldMap<List<String>>> messages; + + protected Map<String, FieldMap<Object>> tagValues; + + public boolean isValid() { + return !hasFatalMessages() && !hasErrorMessagess(); + } + + public void clear() { + messages.clear(); + } + + public boolean isEmpty() { + return messages.isEmpty(); + } + + public boolean hasMessagesForScope(NuitonValidatorScope scope) { + boolean result = false; + if (messages != null) { + FieldMap<List<String>> map = messages.get(scope); + result = !MapUtils.isEmpty(map); + } + return result; + } + + public boolean hasMessagesForScope(String field, + NuitonValidatorScope scope) { + boolean result = false; + if (messages != null) { + result = messages.containsKey(scope); + + if (result) { + FieldMap<List<String>> fieldMap = messages.get(scope); + result = fieldMap != null && fieldMap.containsKey(field); + } + } + return result; + } + + public boolean hasFatalMessages() { + boolean result = hasMessagesForScope(NuitonValidatorScope.FATAL); + return result; + } + + public boolean hasErrorMessagess() { + boolean result = hasMessagesForScope(NuitonValidatorScope.ERROR); + return result; + } + + public boolean hasInfoMessages() { + boolean result = hasMessagesForScope(NuitonValidatorScope.INFO); + return result; + } + + public boolean hasWarningMessages() { + boolean result = hasMessagesForScope(NuitonValidatorScope.WARNING); + return result; + } + + public void addMessagesForScope(NuitonValidatorScope scope, + Map<String, List<String>> newMessages) { + if (messages == null) { + messages = new EnumMap<NuitonValidatorScope, FieldMap<List<String>>>(NuitonValidatorScope.class); + } + + FieldMap<List<String>> fieldMap = messages.get(scope); + + if (fieldMap == null) { + fieldMap = new FieldMap<List<String>>(); + messages.put(scope, fieldMap); + } + + for (Map.Entry<String, List<String>> entry : newMessages.entrySet()) { + String fieldName = entry.getKey(); + List<String> messages = entry.getValue(); + List<String> oldMessages = fieldMap.get(fieldName); + if (oldMessages == null) { + oldMessages = messages; + fieldMap.put(fieldName, oldMessages); + } else { + oldMessages.addAll(messages); + } + } + } + + public void setMessagesForScope(NuitonValidatorScope scope, + String field, + List<String> messages) { + + if (this.messages == null) { + this.messages = new EnumMap<NuitonValidatorScope, FieldMap<List<String>>>(NuitonValidatorScope.class); + } + + FieldMap<List<String>> fieldMap = this.messages.get(scope); + if (fieldMap == null) { + fieldMap = new FieldMap<List<String>>(); + this.messages.put(scope, fieldMap); + } + fieldMap.put(field, messages); + } + + public List<String> getMessagesForScope(NuitonValidatorScope scope) { + + List<String> result = new ArrayList<String>(); + if (messages != null) { + FieldMap<List<String>> fieldMap = messages.get(scope); + for (List<String> messages : fieldMap.values()) { + result.addAll(messages); + } + } + return result; + } + + public List<String> getMessagesForScope(String field, + NuitonValidatorScope scope) { + + List<String> result = null; + if (messages != null) { + FieldMap<List<String>> fieldMap = messages.get(scope); + result = fieldMap.get(field); + } + if (result == null) { + result = Collections.emptyList(); + } + return result; + } + + public List<String> getFatalMessages(String field) { + List<String> result = + getMessagesForScope(field, NuitonValidatorScope.FATAL); + return result; + } + + public List<String> getErrorMessages(String field) { + List<String> result = + getMessagesForScope(field, NuitonValidatorScope.ERROR); + return result; + } + + public List<String> getInfoMessages(String field) { + List<String> result = + getMessagesForScope(field, NuitonValidatorScope.INFO); + return result; + } + + public List<String> getWarningMessages(String field) { + List<String> result = + getMessagesForScope(field, NuitonValidatorScope.WARNING); + return result; + } + + public Map<String, Object> getTagValues(String field) { + Map<String, Object> result = null; + if (tagValues != null) { + result = tagValues.get(field); + } + if (result == null) { + result = Collections.emptyMap(); + } + return result; + } + + public List<String> getFieldsForScope(NuitonValidatorScope scope) { + + List<String> result = null; + if (messages != null) { + FieldMap<List<String>> fieldMap = messages.get(scope); + if (fieldMap != null) { + result = new ArrayList<String>(fieldMap.keySet()); + } + } + if (result == null) { + result = Collections.emptyList(); + } + return result; + } + + public List<String> getFieldsForFatal() { + List<String> result = getFieldsForScope(NuitonValidatorScope.FATAL); + return result; + } + + public List<String> getFieldsForError() { + List<String> result = getFieldsForScope(NuitonValidatorScope.ERROR); + return result; + } + + public List<String> getFieldsForInfo() { + List<String> result = getFieldsForScope(NuitonValidatorScope.INFO); + return result; + } + + public List<String> getFieldsForWarning() { + List<String> result = getFieldsForScope(NuitonValidatorScope.WARNING); + return result; + } + + public void clearMessagesForScope(NuitonValidatorScope scope) { + if (messages != null) { + messages.remove(scope); + } + } + + public NuitonValidatorScope getFieldHighestScope(String field) { + if (messages == null) { + return null; + } + if (containsField(field, NuitonValidatorScope.FATAL)) { + return NuitonValidatorScope.FATAL; + } + if (containsField(field, NuitonValidatorScope.ERROR)) { + return NuitonValidatorScope.ERROR; + } + if (containsField(field, NuitonValidatorScope.WARNING)) { + return NuitonValidatorScope.WARNING; + } + if (containsField(field, NuitonValidatorScope.INFO)) { + return NuitonValidatorScope.INFO; + } + + // no scope for the field + return null; + } + + public NuitonValidatorScope[] getFieldScopes(String field) { + Set<NuitonValidatorScope> result = new HashSet<NuitonValidatorScope>(); + if (messages != null) { + + if (containsField(field, NuitonValidatorScope.FATAL)) { + result.add(NuitonValidatorScope.FATAL); + } + if (containsField(field, NuitonValidatorScope.ERROR)) { + result.add(NuitonValidatorScope.ERROR); + } + if (containsField(field, NuitonValidatorScope.WARNING)) { + result.add(NuitonValidatorScope.WARNING); + } + if (containsField(field, NuitonValidatorScope.INFO)) { + result.add(NuitonValidatorScope.INFO); + } + } + + return result.toArray(new NuitonValidatorScope[result.size()]); + } + + protected boolean containsField(String field, NuitonValidatorScope scope) { + FieldMap<List<String>> fieldMap = messages.get(scope); + return fieldMap != null && fieldMap.containsKey(field); + } + + protected EnumMap<NuitonValidatorScope, FieldMap<List<String>>> getMessages() { + return messages; + } + + protected Map<String, FieldMap<Object>> getTagValues() { + return tagValues; + } +} diff --git a/src/main/java/org/nuiton/validator/NuitonValidatorScope.java b/src/main/java/org/nuiton/validator/NuitonValidatorScope.java new file mode 100644 index 0000000..5a2b64b --- /dev/null +++ b/src/main/java/org/nuiton/validator/NuitonValidatorScope.java @@ -0,0 +1,78 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator; + +import static org.nuiton.i18n.I18n.n_; + +/** + * The differents levels of messages in validation process. + * <p/> + * The order of the enum defines the severity of validation. + * <p/> + * Always begin with fatal, then error, then if no error found, try warning, then info... + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public enum NuitonValidatorScope { + + /** + * the fatal error scope level. + * <p/> + * When a message of a such scope is found on a validator, then the + * validator is invalid and modified. + */ + FATAL(n_("validator.scope.fatal.label")), + /** + * the error scope level. + * <p/> + * When a message of a such scope is found on a validator, then the + * validator is invalid and modified. + */ + ERROR(n_("validator.scope.error.label")), + /** + * the warning scope level. + * <p/> + * When a message of a such scope is found on a validator, then the + * validator is still valid but modified. + */ + WARNING(n_("validator.scope.warning.label")), + /** + * the information scope level. + * <p/> + * When a message of a sucg scope is found on a validator, then the + * validator is still valid and not modified. + */ + INFO(n_("validator.scope.info.label")); + + private final String label; + + NuitonValidatorScope(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } +} diff --git a/src/main/java/org/nuiton/validator/bean/AbstractNuitonValidatorContext.java b/src/main/java/org/nuiton/validator/bean/AbstractNuitonValidatorContext.java new file mode 100644 index 0000000..2e1f646 --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/AbstractNuitonValidatorContext.java @@ -0,0 +1,389 @@ +package org.nuiton.validator.bean; +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 - 2012 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +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.nuiton.util.converter.ConverterUtil; +import org.nuiton.validator.NuitonValidator; +import org.nuiton.validator.NuitonValidatorResult; +import org.nuiton.validator.NuitonValidatorScope; +import org.nuiton.validator.bean.list.BeanListValidator; + +import java.beans.Introspector; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Defines a context of validation used for a single bean. + * <p/> + * {@link BeanValidator} will then used one of this object and + * {@link BeanListValidator} as many as it contains beans. + * <p/> + * This object box a {@link NuitonValidator} to get validation state each time + * a higher validator requires it. + * <p/> + * It also offers the way to create events (merge logic + * + * @param <O> type of bean to validate + * @param <V> type of bean validator used + * @param <E> type of event to create + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public abstract class AbstractNuitonValidatorContext<O, V, E> { + + /** Logger. */ + private static final Log log = + LogFactory.getLog(AbstractNuitonValidatorContext.class); + + /** Bean to validate. */ + protected O bean; + + /** + * State of validation (keep all messages of validation for the filled + * bean). + */ + protected NuitonValidatorResult messages; + + /** Validator. */ + protected NuitonValidator<O> validator; + + /** map of conversion errors detected by this validator */ + protected final Map<String, String> conversionErrors; + + /** + * State to know if the validator can be used (we keep this state for + * performance reasons : do not want to compute this value each time a + * validation is asked...). + */ + protected boolean canValidate; + + protected abstract E createEvent(V source, + O bean, + String field, + NuitonValidatorScope scope, + String[] toAdd, + String[] toDelete); + + public AbstractNuitonValidatorContext() { + conversionErrors = Maps.newTreeMap(); + } + + public O getBean() { + return bean; + } + + public void setBean(O bean) { + if (log.isDebugEnabled()) { + log.debug(this + " : " + bean); + } + + // clean conversions of previous bean + conversionErrors.clear(); + this.bean = bean; + + setCanValidate(!validator.getEffectiveFields().isEmpty() && bean != null); + } + + public NuitonValidator<O> getValidator() { + return validator; + } + + public NuitonValidatorResult getMessages() { + return messages; + } + + public boolean isCanValidate() { + return canValidate; + } + + public void setCanValidate(boolean canValidate) { + this.canValidate = canValidate; + } + + public boolean isValid() { + return messages == null || messages.isValid(); + } + + public boolean hasFatalErrors() { + boolean result = messages != null && messages.hasFatalMessages(); + return result; + } + + public boolean hasErrors() { + boolean result = messages != null && messages.hasErrorMessagess(); + return result; + } + + public boolean hasWarnings() { + boolean result = messages != null && messages.hasWarningMessages(); + return result; + } + + public boolean hasInfos() { + boolean result = messages != null && messages.hasInfoMessages(); + return result; + } + + public boolean isValid(String fieldName) { + + // field is valid if no fatal messages nor error messages + boolean result = !( + messages.hasMessagesForScope(fieldName, NuitonValidatorScope.FATAL) || + messages.hasMessagesForScope(fieldName, NuitonValidatorScope.ERROR)); + + return result; + } + + public NuitonValidatorScope getHighestScope(String field) { + + NuitonValidatorScope scope = messages.getFieldHighestScope(field); + return scope; + } + + public void setValidator(NuitonValidator<O> validator) { + this.validator = validator; + } + + public NuitonValidatorResult validate() { + NuitonValidatorResult result = validator.validate(bean); + + // treate conversion errors + // reinject them + for (Map.Entry<String, String> entry : conversionErrors.entrySet()) { + + + // remove from validation, errors occurs on this field + String field = entry.getKey(); + + + List<String> errors = result.getErrorMessages(field); + + String conversionError = entry.getValue(); + if (errors != null) { + errors.clear(); + errors.add(conversionError); + } else { + errors = Collections.singletonList(conversionError); + } + + result.setMessagesForScope(NuitonValidatorScope.ERROR, field, errors); + } + return result; + } + + /** + * Convert a value. + * <p/> + * If an error occurs, then add an error in validator. + * + * @param <T> the type of conversion + * @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 + */ + @SuppressWarnings({"unchecked"}) + 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 (!isCanValidate() || 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 + String s = Introspector.decapitalize(valueClass.getSimpleName()); + conversionErrors.put(fieldName, "error.convertor." + s); + throw e; + } + return result; + } + + public List<E> mergeMessages(V beanValidator, + NuitonValidatorResult newMessages) { + + if (newMessages == null && messages == null) { + + // no messages ever registred and ask to delete them, so nothing + // to do + return null; + } + + Set<NuitonValidatorScope> scopes = getValidator().getEffectiveScopes(); + + // list of events to send after the merge of messages + List<E> events = Lists.newArrayList(); + + for (NuitonValidatorScope scope : scopes) { + + // do the merge at scope level + mergeMessages(beanValidator, scope, newMessages, events); + + } + + if (newMessages != null) { + + //TODO tchemit 2011-01-23 Perharps it will necessary to clear the messages for memory performance ? + + // finally keep the new messages as the current messages + this.messages = newMessages; + } + + return events; + } + + protected void mergeMessages(V beanValidator, + NuitonValidatorScope scope, + NuitonValidatorResult newMessages, + List<E> events) { + + + if (newMessages == null) { + + // special case to empty all messages + + List<String> fieldsForScope = messages.getFieldsForScope(scope); + + for (String field : fieldsForScope) { + List<String> messagesForScope = messages.getMessagesForScope(field, scope); + events.add(createEvent(beanValidator, bean, field, scope, null, messagesForScope.toArray(new String[messagesForScope.size()]))); + } + + // suppress all messages for this scope + messages.clearMessagesForScope(scope); + + + } else { + + List<String> newFields = newMessages.getFieldsForScope(scope); + + if (messages == null) { + + // first time of a merge, just add new messages + + for (String field : newFields) { + List<String> messagesForScope = newMessages.getMessagesForScope(field, scope); + events.add(createEvent(beanValidator, bean, field, scope, messagesForScope.toArray(new String[messagesForScope.size()]), null)); + } + + // nothing else to do + return; + } + + List<String> oldFields = messages.getFieldsForScope(scope); + + Iterator<String> itr; + + // detects field with only new messages + itr = newFields.iterator(); + while (itr.hasNext()) { + String newField = itr.next(); + + if (!oldFields.contains(newField)) { + + // this fields has now messages but not before : new messages + List<String> messagesForScope = newMessages.getMessagesForScope(newField, scope); + events.add(createEvent(beanValidator, bean, newField, scope, messagesForScope.toArray(new String[messagesForScope.size()]), null)); + + // treated field + itr.remove(); + } + } + + // detects fields with only obsolete messages + itr = oldFields.iterator(); + while (itr.hasNext()) { + String oldField = itr.next(); + + if (!newFields.contains(oldField)) { + + // this fields has no more messages + List<String> messagesForScope = messages.getMessagesForScope(oldField, scope); + events.add(createEvent(beanValidator, bean, oldField, scope, null, messagesForScope.toArray(new String[messagesForScope.size()]))); + + // treated field + itr.remove(); + } + } + + // now deal with mixte field (toAdd and toDelete) + for (String field : newFields) { + + List<String> newMessagesForScope = newMessages.getMessagesForScope(field, scope); + List<String> oldMessagesForScope = messages.getMessagesForScope(field, scope); + + // get old obsoletes messages to delete + Set<String> toDelete = new HashSet<String>(oldMessagesForScope); + toDelete.removeAll(newMessagesForScope); + + // get new messages to add + Set<String> toAdd = new HashSet<String>(newMessagesForScope); + toAdd.removeAll(oldMessagesForScope); + + events.add(createEvent( + beanValidator, + bean, + field, + scope, + toAdd.isEmpty() ? null : toAdd.toArray(new String[toAdd.size()]), + toDelete.isEmpty() ? null : toDelete.toArray(new String[toDelete.size()]) + )); + + } + } + } +} diff --git a/src/main/java/org/nuiton/validator/bean/AbstractValidator.java b/src/main/java/org/nuiton/validator/bean/AbstractValidator.java new file mode 100644 index 0000000..c885661 --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/AbstractValidator.java @@ -0,0 +1,390 @@ +package org.nuiton.validator.bean; +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 - 2012 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import com.google.common.base.Preconditions; +import org.apache.commons.lang3.ObjectUtils; +import org.nuiton.util.beans.BeanUtil; +import org.nuiton.validator.NuitonValidator; +import org.nuiton.validator.NuitonValidatorModel; +import org.nuiton.validator.NuitonValidatorProvider; +import org.nuiton.validator.NuitonValidatorScope; + +import javax.swing.event.EventListenerList; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.Set; + +/** + * TODO + * + * @param <O> type of bean to validate + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public abstract class AbstractValidator<O> { + + /** + * Name of the bounded property {@code context}. + * + * @see #getContext() + * @see #setContext(String) + */ + public static final String CONTEXT_PROPERTY = "context"; + + /** + * Name of the bounded property {@code scopes}. + * + * @see #getScopes() + * @see #setScopes(NuitonValidatorScope...) + */ + public static final String SCOPES_PROPERTY = "scopes"; + + /** + * Name of the bounded property {@link #valid}. + * + * @see #valid + * @see #isValid() + * @see #setValid(boolean) + */ + public static final String VALID_PROPERTY = "valid"; + + /** + * Name of the bounded property {@link #changed}. + * + * @see #changed + * @see #isChanged() + * @see #setChanged(boolean) + */ + public static final String CHANGED_PROPERTY = "changed"; + +// /** Logger. */ +// private static final Log log = LogFactory.getLog(BeanValidator.class); + +// /** +// * The delegate validator used to validate the bean. +// * +// * @since 2.5.2 +// */ +// protected NuitonValidator<O> delegate; + + /** + * State to indicate that validator has changed since the last time bean was + * setted. + */ + protected boolean changed; + + /** State of the validator (is true if no errors of error scope is found). */ + protected boolean valid = true; + + /** + * State to know if the validator can be used (we keep this state for + * performance reasons : do not want to compute this value each time a + * validation is asked...). + */ + protected boolean canValidate = true; + + /** Listener that listens on bean modification. */ + protected final PropertyChangeListener l; + + /** delegate property change support */ + protected final PropertyChangeSupport pcs; + + /** A list of event listeners for this validators */ + protected final EventListenerList listenerList = new EventListenerList(); + + /** + * The provider of delegate validators. + * <p/> + * It will also produce validator model. + * + * @see NuitonValidatorProvider + */ + protected final NuitonValidatorProvider validatorProvider; + + + protected AbstractValidator(NuitonValidatorProvider validatorProvider, + Class<O> beanClass) { + + // check if given bean class is Javabean compiliant + boolean javaBeanCompiliant = BeanUtil.isJavaBeanCompiliant(beanClass); + Preconditions.checkState( + javaBeanCompiliant, + beanClass.getName() + " is not JavaBean compiliant (" + + BeanUtil.ADD_PROPERTY_CHANGE_LISTENER + ", or " + + BeanUtil.REMOVE_PROPERTY_CHANGE_LISTENER + + " method not found)."); + + this.validatorProvider = validatorProvider; + + pcs = new PropertyChangeSupport(this); + +// // build delegate validator +// rebuildDelegateValidator( +// beanClass, +// context, +// scopes +// ); + +// // context has changed +// firePropertyChange(CONTEXT_PROPERTY, +// null, +// context +// ); +// +// // scopes has changed +// firePropertyChange(SCOPES_PROPERTY, +// null, +// scopes +// ); + + l = new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + + O bean = (O) evt.getSource(); + + // the bean has changed, replay validation + doValidate(bean); + } + }; + } + + /** + * Obtain the {@link #changed} property value. + * <p/> + * Returns {@code true} if bean was modified since last + * time a bean was attached. + * + * @return {@code true} if bean was modified since last attachement of + * a bean. + */ + public boolean isChanged() { + return changed; + } + + /** + * To force the value of the property {@link #changed}. + * + * @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) + firePropertyChange(CHANGED_PROPERTY, null, changed); + } + + public boolean isCanValidate() { + return canValidate; + } + + public void setCanValidate(boolean canValidate) { + this.canValidate = canValidate; + } + + /** + * Obtain the {@link #valid} property value. + * + * @return {@code true} if attached bean is valid (no error or fatal messages) + */ + public boolean isValid() { + return valid; + } + + /** + * Change the value of the {@link #valid} property. + * + * @param valid the new value of the property + */ + public void setValid(boolean valid) { + this.valid = valid; + + // force the property to be fired (never pass the older value) + firePropertyChange(VALID_PROPERTY, null, valid); + } + + + public String getContext() { + return getModel().getContext(); + } + + public void setContext(String context) { + + String oldContext = getContext(); + + if (ObjectUtils.equals(context, oldContext)) { + + // same context do nothing + return; + } + + NuitonValidatorModel<O> model = getModel(); + + // compute the new validator model + NuitonValidatorScope[] scopes = model.getScopes().toArray( + new NuitonValidatorScope[model.getScopes().size()]); + + rebuildDelegateValidator( + model.getType(), + context, + scopes + ); + + firePropertyChange(CONTEXT_PROPERTY, + oldContext, + context + ); + } + + public Set<NuitonValidatorScope> getScopes() { + return getModel().getScopes(); + } + + public Set<NuitonValidatorScope> getEffectiveScopes() { + return getDelegate().getEffectiveScopes(); + } + + public Set<String> getEffectiveFields() { + return getDelegate().getEffectiveFields(); + } + + public Set<String> getEffectiveFields(NuitonValidatorScope scope) { + return getDelegate().getEffectiveFields(scope); + } + + public void setScopes(NuitonValidatorScope... scopes) { + + Set<NuitonValidatorScope> oldScopes = getScopes(); + + rebuildDelegateValidator( + getModel().getType(), + getModel().getContext(), + scopes + ); + + firePropertyChange(SCOPES_PROPERTY, + oldScopes, + scopes + ); + } + + public abstract void doValidate(); + + public abstract boolean hasFatalErrors(); + + public abstract boolean hasErrors(); + + public abstract boolean hasWarnings(); + + public abstract boolean hasInfos(); + + public abstract boolean isValid(String fieldName); + + public abstract NuitonValidatorScope getHighestScope(String field); + + public abstract <T> T convert(O bean, String fieldName, String value, Class<T> valueClass); + + protected abstract void doValidate(O bean); + + protected abstract NuitonValidator<O> getDelegate(); + + protected abstract void rebuildDelegateValidator(Class<O> beanType, + String context, + NuitonValidatorScope... scopes); + + public Class<O> getType() { + return getModel().getType(); + } + + /** + * Test a the validator contains the field given his name + * + * @param fieldName the name of the searched field + * @return <code>true</code> if validator contaisn this field, + * <code>false</code> otherwise + */ + public boolean containsField(String fieldName) { + Set<String> effectiveFields = getDelegate().getEffectiveFields(); + boolean result = effectiveFields.contains(fieldName); + return result; + } + + 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); + } + + public void firePropertyChange(String propertyName, + Object oldValue, + Object newValue) { + pcs.firePropertyChange(propertyName, oldValue, newValue); + } + + protected NuitonValidatorModel<O> getModel() { + return getDelegate().getModel(); + } + +// protected NuitonValidator<O> rebuildDelegateValidator(Class<O> beanType, +// String context, +// NuitonValidatorScope... scopes) { +// +// // changing context could change fields definition +// // so dettach bean, must rebuild the fields +// +// // Dettach the bean before any thing, because with the new delegate +// // validator some old fields could not be used any longer, and then +// // listeners will never have the full reset of their model... +// +// // remove all validators. +// +// if (scopes == null || scopes.length == 0) { +// scopes = NuitonValidatorScope.values(); +// } +// +// // compute the new validator model +// NuitonValidatorModel<O> model = validatorProvider.getModel(beanType, +// context, +// scopes +// ); +// +// // remove old delegate validator +// NuitonValidator<O> delegate = validatorProvider.newValidator(model); +// } +} diff --git a/src/main/java/org/nuiton/validator/bean/AbstractValidatorEvent.java b/src/main/java/org/nuiton/validator/bean/AbstractValidatorEvent.java new file mode 100644 index 0000000..42aca5e --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/AbstractValidatorEvent.java @@ -0,0 +1,85 @@ +package org.nuiton.validator.bean; +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 - 2012 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import org.nuiton.validator.NuitonValidatorScope; + +import java.util.EventObject; + +/** + * TODO + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public abstract class AbstractValidatorEvent<V> extends EventObject { + + private static final long serialVersionUID = 1L; + + /** the field impacted by the validator */ + protected String field; + + /** the scope impacted by the event */ + protected NuitonValidatorScope scope; + + protected String[] messagestoAdd; + + protected String[] messagestoDelete; + + public abstract Object getBean(); + + public AbstractValidatorEvent(V source, + String field, + NuitonValidatorScope scope, + String[] messagestoAdd, + String[] messagestoDelete) { + super(source); + this.field = field; + this.scope = scope; + this.messagestoAdd = messagestoAdd; + this.messagestoDelete = messagestoDelete; + } + + @Override + public V getSource() { + return (V) super.getSource(); + } + + public String[] getMessagesToAdd() { + return messagestoAdd; + } + + public String[] getMessagesToDelete() { + return messagestoDelete; + } + + public NuitonValidatorScope getScope() { + return scope; + } + + public String getField() { + return field; + } + +} diff --git a/src/main/java/org/nuiton/validator/bean/ValidatorCreator.java b/src/main/java/org/nuiton/validator/bean/ValidatorCreator.java new file mode 100644 index 0000000..eeb8ce8 --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/ValidatorCreator.java @@ -0,0 +1,53 @@ +package org.nuiton.validator.bean; +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 - 2012 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import org.nuiton.validator.NuitonValidatorProvider; +import org.nuiton.validator.NuitonValidatorScope; + +/** + * TODO + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public interface ValidatorCreator<V> { + + /** + * Given the parameters, instanciate a new {@link V}. + * + * @param provider the delegate validator provider + * @param type the type of object to validate + * @param context the context of validation (can be {@code null}) + * @param scopes scopes to use (if none given, will use all available scopes) + * @param <O> type of object to validate + * @return the new instance of bean validator + */ + <O> V newValidator(NuitonValidatorProvider provider, + Class<O> type, + String context, + NuitonValidatorScope... scopes + + ); +} diff --git a/src/main/java/org/nuiton/validator/bean/ValidatorListener.java b/src/main/java/org/nuiton/validator/bean/ValidatorListener.java new file mode 100644 index 0000000..36e2fa1 --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/ValidatorListener.java @@ -0,0 +1,47 @@ +package org.nuiton.validator.bean; +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 - 2012 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import org.nuiton.validator.bean.list.BeanListValidator; +import org.nuiton.validator.bean.list.BeanListValidatorEvent; + +import java.util.EventListener; + +/** + * The definition of an event on {@link BeanListValidatorEvent} + * to be fired by a {@link BeanListValidator}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public interface ValidatorListener<E extends AbstractValidatorEvent<?>> extends EventListener { + + /** + * Invoked when the {@link E} detects some changes for a + * given bean / field / scope. + * + * @param event the event + */ + void onFieldChanged(E event); +} diff --git a/src/main/java/org/nuiton/validator/bean/list/BeanListValidator.java b/src/main/java/org/nuiton/validator/bean/list/BeanListValidator.java new file mode 100644 index 0000000..1e535c6 --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/list/BeanListValidator.java @@ -0,0 +1,560 @@ +package org.nuiton.validator.bean.list; +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 - 2012 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.apache.commons.beanutils.ConversionException; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.util.beans.BeanUtil; +import org.nuiton.validator.NuitonValidator; +import org.nuiton.validator.NuitonValidatorFactory; +import org.nuiton.validator.NuitonValidatorModel; +import org.nuiton.validator.NuitonValidatorProvider; +import org.nuiton.validator.NuitonValidatorResult; +import org.nuiton.validator.NuitonValidatorScope; +import org.nuiton.validator.bean.AbstractNuitonValidatorContext; +import org.nuiton.validator.bean.AbstractValidator; + +import java.beans.PropertyChangeListener; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * To validate a list of beans. + * <p/> + * Each bean of the list will be associated with a {@link NuitonValidatorContext}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public class BeanListValidator<O> extends AbstractValidator<O> { + + /** Logger. */ + private static final Log log = LogFactory.getLog(BeanListValidator.class); + + /** + * Obtain a new {@link BeanListValidator} for the given parameters. + * <p/> + * <b>Note:</b> It will use the default provider of {@link NuitonValidator} + * + * @param type type of bean to validate + * @param context context of validation + * @param scopes authorized scopes (if {@code null}, will use all scopes) + * @param <O> type of bean to validate + * @return the new instanciated {@link BeanListValidator}. + * @throws NullPointerException if type is {@code null} + * @see NuitonValidatorFactory#getDefaultProviderName() + */ + public static <O> BeanListValidator<O> newValidator(Class<O> type, + String context, + NuitonValidatorScope... scopes) throws NullPointerException { + + + // get the provider default name + String providerName = NuitonValidatorFactory.getDefaultProviderName(); + + // get the bean validator with this provider + BeanListValidator<O> beanValidator = newValidator(providerName, + type, + context, + scopes + ); + return beanValidator; + } + + /** + * Obtain a new {@link BeanListValidator} for the given parameters. + * <p/> + * <b>Note:</b> It will use the provider of {@link NuitonValidator} + * defined by the {@code providerName}. + * + * @param providerName name of {@link NuitonValidator} to use + * @param type type of bean to validate + * @param context context of validation + * @param scopes authorized scopes (if {@code null}, will use all scopes) + * @param <O> type of bean to validate + * @return the new instanciated {@link BeanListValidator}. + * @throws NullPointerException if type is {@code null} + * @see NuitonValidatorFactory#getProvider(String) + */ + public static <O> BeanListValidator<O> newValidator(String providerName, + Class<O> type, + String context, + NuitonValidatorScope... scopes) throws NullPointerException { + + Preconditions.checkNotNull(type, "type parameter can not be null."); + + // get delegate validator provider + NuitonValidatorProvider provider = + NuitonValidatorFactory.getProvider(providerName); + + Preconditions.checkState( + provider != null, + "Could not find provider with name " + providerName); + + // create the new instance of bean validator + BeanListValidator<O> validator = new BeanListValidator<O>( + provider, type, context, scopes + ); + + return validator; + } + + /** + * Context for each bean registred. + * + * @since 2.5.2 + */ + protected final Map<O, NuitonValidatorContext<O>> contexts; + + /** + * The delegate validator used to validate the bean. + * + * @since 2.5.2 + */ + protected NuitonValidator<O> delegate; + + public BeanListValidator(NuitonValidatorProvider validatorProvider, + Class<O> beanClass, + String context) { + + this(validatorProvider, beanClass, + context, + NuitonValidatorScope.values() + ); + } + + public BeanListValidator(NuitonValidatorProvider validatorProvider, + Class<O> beanClass, + String context, + NuitonValidatorScope... scopes) { + + super(validatorProvider, beanClass); + + contexts = Maps.newHashMap(); + + // build delegate validator + rebuildDelegateValidator(beanClass, context, scopes); + + // context has changed + firePropertyChange(CONTEXT_PROPERTY, + null, + context + ); + + // scopes has changed + firePropertyChange(SCOPES_PROPERTY, + null, + scopes + ); + } + + /** + * Add a bean to validate. + * <p/> + * The bean can not be null, nor registered twice in the validator. + * + * @param bean the bean to attach (can not be {@code null}). + */ + public void addBean(O bean) { + + // bean can not be null + Preconditions.checkNotNull(bean); + + // can not register twice the same bean + Preconditions.checkState(!contexts.containsKey(bean), + "The bean " + bean + + " is already registred in this validator."); + + if (log.isDebugEnabled()) { + log.debug(this + " : " + bean); + } + + // create validator for this bean + NuitonValidator<O> validator = validatorProvider.newValidator(getModel()); + + // register it + NuitonValidatorContext<O> newcontext = + new NuitonValidatorContext<O>(bean, validator); + newcontext.setValidator(validator); + newcontext.setBean(bean); + + contexts.put(bean, newcontext); + + setCanValidate(isCanValidate() && newcontext.isCanValidate()); + + try { + + BeanUtil.addPropertyChangeListener(l, bean); + } catch (Exception eee) { + if (log.isInfoEnabled()) { + log.info("Can't register as listener for bean " + bean.getClass() + + " for reason " + eee.getMessage(), eee); + } + } + validate(bean); + + setChanged(false); + setValid(isValid0()); +// firePropertyChange(BEAN_PROPERTY, oldBean, bean); + } + + public void addAllBeans(Collection<O> beansToAdd) { + for (O bean : beansToAdd) { + addBean(bean); + } + } + + /** + * Remove the given bean from the validaotr. + * <p/> + * The bean can not be {@code null}, nor not has been previously + * registred in this validator. + * + * @param bean the bean to unregister + */ + public void removeBean(O bean) { + + // bean can not be null + Preconditions.checkNotNull(bean); + + if (log.isDebugEnabled()) { + log.debug(this + " : " + bean); + } + + // remove all messages for all fields of the validator + NuitonValidatorContext<O> context = getContext(bean); + + mergeMessages(context, null); + + contexts.remove(bean); + + try { + BeanUtil.removePropertyChangeListener(l, bean); + } catch (Exception eee) { + if (log.isInfoEnabled()) { + log.info("Can't unregister as listener for bean " + bean.getClass() + + " for reason " + eee.getMessage(), eee); + } + } + } + + /** + * Remove all the given beans fro this validator. + * <p/> + * Like in method {@link #removeBean(Object)}, each bean must be not + * {@code null} and has been previously registred in this validator. + * + * @param beansToRemove beans to remove from this validator + */ + public void removeAllBeans(Collection<O> beansToRemove) { + for (O bean : beansToRemove) { + removeBean(bean); + } + } + + /** + * Shortcut method to unregister all previously registred beans from + * this validator. + */ + public void removeAllBeans() { + Set<O> beansToRemove = getBeans(); + removeAllBeans(beansToRemove); + } + + @Override + public boolean hasFatalErrors() { + boolean result = false; + for (NuitonValidatorContext<O> context : contexts.values()) { + result = context.hasFatalErrors(); + if (result) { + break; + } + } + return result; + } + + @Override + public boolean hasErrors() { + boolean result = false; + for (NuitonValidatorContext<O> context : contexts.values()) { + result = context.hasErrors(); + if (result) { + break; + } + } + return result; + } + + @Override + public boolean hasWarnings() { + boolean result = false; + for (NuitonValidatorContext<O> context : contexts.values()) { + result = context.hasWarnings(); + if (result) { + break; + } + } + return result; + } + + @Override + public boolean hasInfos() { + boolean result = false; + for (NuitonValidatorContext<O> context : contexts.values()) { + result = context.hasInfos(); + if (result) { + break; + } + } + return result; + } + + @Override + public boolean isValid(String fieldName) { + boolean result = true; + + for (NuitonValidatorContext<O> context : contexts.values()) { + result = context.isValid(fieldName); + if (!result) { + break; + } + } + return result; + } + + @Override + public NuitonValidatorScope getHighestScope(String field) { + Set<NuitonValidatorScope> scopes = Sets.newHashSet(); + for (NuitonValidatorContext<O> context : contexts.values()) { + scopes.add(context.getHighestScope(field)); + } + NuitonValidatorScope scope = null; + if (scopes.isEmpty()) { + List<NuitonValidatorScope> scopeList = Lists.newArrayList(scopes); + Collections.sort(scopeList); + scope = scopeList.get(0); + } + return scope; + } + + @Override + public void doValidate() { + validate(); + setValid(isValid0()); + setChanged(true); + } + + /** + * Convert a value. + * <p/> + * If an error occurs, then add an error in validator. + * + * @param <T> the type of conversion + * @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 + */ + @Override + public <T> T convert(O bean, + String fieldName, + String value, + Class<T> valueClass) { + NuitonValidatorContext<O> context = getContext(bean); + T convert = null; + try { + convert = context.convert(fieldName, value, valueClass); + } catch (ConversionException e) { + // must revalidate + validate(); + } + return convert; + } + + public void addBeanListValidatorListener(BeanListValidatorListener listener) { + listenerList.add(BeanListValidatorListener.class, listener); + } + + public void removeBeanListValidatorListener(BeanListValidatorListener listener) { + listenerList.remove(BeanListValidatorListener.class, listener); + } + + public BeanListValidatorListener[] getBeanListValidatorListeners() { + return listenerList.getListeners(BeanListValidatorListener.class); + } + + public Set<O> getBeans() { + return ImmutableSet.copyOf(contexts.keySet()); + } + + @Override + protected void doValidate(O bean) { + validate(bean); + setValid(isValid0()); + setChanged(true); + } + + @Override + protected NuitonValidator<O> getDelegate() { + return delegate; + } + + @Override + protected void rebuildDelegateValidator(Class<O> beanType, + String context, + NuitonValidatorScope... scopes) { + + // changing context could change fields definition + // so dettach bean, must rebuild the fields + + // Dettach the bean before any thing, because with the new delegate + // validator some old fields could not be used any longer, and then + // listeners will never have the full reset of their model... + + // remove all validators. + + if (scopes == null || scopes.length == 0) { + scopes = NuitonValidatorScope.values(); + } + + // compute the new validator model + NuitonValidatorModel<O> model = validatorProvider.getModel(beanType, + context, + scopes + ); + + // remove old delegate validator + delegate = validatorProvider.newValidator(model); + } + + /** + * 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} + * <p/> + * <b>Note:</b> la methode est protected et on utilise la methode + * {@link #doValidate()} car la méthode ne modifie pas les etats + * internes et cela en rend son utilisation delicate (le validateur entre + * dans un etat incoherent par rapport aux messages envoyés). + */ + protected 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 (isCanValidate()) { + + for (O bean : contexts.keySet()) { + + validate(bean); + } + } + } + + protected void validate(O bean) { + NuitonValidatorContext<O> validator = getContext(bean); + NuitonValidatorResult result = validator.validate(); + mergeMessages(validator, result); + } + + protected boolean isValid0() { + boolean result = true; + for (NuitonValidatorContext<O> context : contexts.values()) { + result = context.isValid(); + if (!result) { + break; + } + } + return result; + } + + protected void mergeMessages(NuitonValidatorContext<O> context, + NuitonValidatorResult newMessages) { + + List<BeanListValidatorEvent> events = context.mergeMessages( + this, newMessages); + + if (CollectionUtils.isNotEmpty(events)) { + + // send all messages + for (BeanListValidatorEvent event : events) { + fireFieldChanged(event); + } + } + } + + protected void fireFieldChanged(BeanListValidatorEvent evt) { + + for (BeanListValidatorListener listener : + listenerList.getListeners(BeanListValidatorListener.class)) { + listener.onFieldChanged(evt); + } + } + + public NuitonValidatorContext<O> getContext(O bean) { + NuitonValidatorContext<O> context = contexts.get(bean); + Preconditions.checkState( + context != null, + "Bean " + bean + " was not register in this list validator"); + return context; + } + + + public static class NuitonValidatorContext<O> extends AbstractNuitonValidatorContext<O, BeanListValidator<O>, BeanListValidatorEvent> { + + public NuitonValidatorContext(O bean, NuitonValidator<O> validator) { + setValidator(validator); + setBean(bean); + } + + @Override + protected BeanListValidatorEvent createEvent(BeanListValidator<O> source, + O bean, + String field, + NuitonValidatorScope scope, + String[] toAdd, + String[] toDelete) { + return new BeanListValidatorEvent( + source, + bean, + field, + scope, + toAdd, + toDelete + ); + } + } +} diff --git a/src/main/java/org/nuiton/validator/bean/list/BeanListValidatorEvent.java b/src/main/java/org/nuiton/validator/bean/list/BeanListValidatorEvent.java new file mode 100644 index 0000000..777253e --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/list/BeanListValidatorEvent.java @@ -0,0 +1,56 @@ +package org.nuiton.validator.bean.list; +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 - 2012 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import org.nuiton.validator.NuitonValidatorScope; +import org.nuiton.validator.bean.AbstractValidatorEvent; + +/** + * Event to be fired when some messages changed on a given field / scope of a bean. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public class BeanListValidatorEvent extends AbstractValidatorEvent<BeanListValidator<?>> { + + private static final long serialVersionUID = 1L; + + /** the bean on which event occurs. */ + protected Object bean; + + public BeanListValidatorEvent(BeanListValidator<?> source, + Object bean, + String field, + NuitonValidatorScope scope, + String[] messagestoAdd, + String[] messagestoDelete) { + super(source, field, scope, messagestoAdd, messagestoDelete); + this.bean = bean; + } + + public Object getBean() { + return bean; + } + +} diff --git a/src/main/java/org/nuiton/validator/bean/list/BeanListValidatorListener.java b/src/main/java/org/nuiton/validator/bean/list/BeanListValidatorListener.java new file mode 100644 index 0000000..e03ff69 --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/list/BeanListValidatorListener.java @@ -0,0 +1,37 @@ +package org.nuiton.validator.bean.list; +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 - 2012 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import org.nuiton.validator.bean.ValidatorListener; + +/** + * The definition of an event on {@link BeanListValidatorEvent} + * to be fired by a {@link BeanListValidator}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public interface BeanListValidatorListener extends ValidatorListener<BeanListValidatorEvent> { + +} diff --git a/src/main/java/org/nuiton/validator/bean/list/BeanListValidatorMessage.java b/src/main/java/org/nuiton/validator/bean/list/BeanListValidatorMessage.java new file mode 100644 index 0000000..a9273dd --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/list/BeanListValidatorMessage.java @@ -0,0 +1,152 @@ +package org.nuiton.validator.bean.list; +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 - 2012 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import org.nuiton.validator.NuitonValidatorScope; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +import static org.nuiton.i18n.I18n._; + +/** + * TODO + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public class BeanListValidatorMessage<E extends BeanListValidatorMessage<?>> implements Comparable<E>, Serializable { + + private static final long serialVersionUID = 1L; + + /** the validator that produce the message */ + protected BeanListValidator<?> validator; + + /** the bean on which event occurs. */ + protected Object bean; + + /** the field that produce the message */ + protected String field; + + /** the label of the message (to be displayed somewhere) */ + protected String message; + + /** the scope of the message */ + protected NuitonValidatorScope scope; + + public BeanListValidatorMessage(BeanListValidator<?> validator, + Object bean, + String field, + String message, + NuitonValidatorScope scope) { + this.field = field; + this.bean = bean; + this.validator = validator; + this.message = message == null ? null : message.trim(); + this.scope = scope; + } + + public BeanListValidator<?> getValidator() { + return validator; + } + + public String getField() { + return field; + } + + public NuitonValidatorScope getScope() { + return scope; + } + + public String getMessage() { + return message; + } + + public Object getBean() { + return bean; + } + + @Override + public int compareTo(E o) { + // sort on scope + int result = getScope().compareTo(o.getScope()); + if (result == 0) { + // sort on field name + result = field.compareTo(o.field); + if (result == 0) { + // sort on message + result = message.compareTo(o.message); + } + } + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof BeanListValidatorMessage<?>)) { + return false; + } + + BeanListValidatorMessage<?> that = (BeanListValidatorMessage<?>) o; + + return field.equals(that.field) && + (message != null ? !message.equals(that.message) : that.message == null) && + scope == that.scope; + } + + @Override + public int hashCode() { + int result = field.hashCode(); + result = 31 * result + (bean != null ? bean.hashCode() : 0); + result = 31 * result + (message != null ? message.hashCode() : 0); + result = 31 * result + (scope != null ? scope.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return bean + "[" + scope + "] - " + getI18nError(message); + } + + public String getI18nError(String error) { + String text; + if (!error.contains("##")) { + text = _(error); + } else { + StringTokenizer stk = new StringTokenizer(error, "##"); + String errorName = stk.nextToken(); + List<String> args = new ArrayList<String>(); + while (stk.hasMoreTokens()) { + args.add(stk.nextToken()); + } + text = _(errorName, args.toArray()); + } + return text; + } +} diff --git a/src/main/java/org/nuiton/validator/bean/list/package-info.java b/src/main/java/org/nuiton/validator/bean/list/package-info.java new file mode 100644 index 0000000..0a4b06a --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/list/package-info.java @@ -0,0 +1,58 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +/** + * Package of Nuiton - BeanListValidator api. + * + * <h1>The <b>BeanValidator</b> api</h1> + * <p> + * The {@link org.nuiton.validator.bean.list.BeanListValidator} purpose is to validate + * a list of bean, with a listener api to interact with outside world. + * </p> + * It is mainly used in GUI parts of an application (Jaxx-validator use it). + * <br/> + * The idea is to attach the bean to validate insed the validator, then the + * validator listen any modification of the bean to revalidate it and fires + * events when messages has changed on a field. + * + * <pre> + * BeanListValidatorListener listener = new BeanListValidatorListener() {XXX}; + * BeanValidator<O> validator = XXX; + * validator.addBeanListValidatorListener(listener); + * validator.addBean(bean1); + * validator.addBean(bean2); + * </pre> + * + * <h2>Obtain a validator</h2> + * To obtain a bean validator use one of the factory method on the + * {@link org.nuiton.validator.bean.list.BeanListValidator}. + * <br/> + * <pre> + * BeanListValidator<O> validator = BeanListValidator.newValidator(O.class); + * </pre> + * + * <strong>To be continued...</strong> + * + * @since 2.0 + */ +package org.nuiton.validator.bean.list; diff --git a/src/main/java/org/nuiton/validator/bean/package-info.java b/src/main/java/org/nuiton/validator/bean/package-info.java new file mode 100644 index 0000000..b0f2bae --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/package-info.java @@ -0,0 +1,71 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +/** + * Package of Nuiton- beanValidator api. + * + * <strong>This api is deprecated since version 2.5.2 and will be removed in version 3.0</strong> + * + * <h1>The <b>BeanValidator</b> api</h1> + * <p> + * The {@link org.nuiton.validator.bean.BeanValidator} purpose is to validate + * a bean, with a listener api to interact with outside world. + * </p> + * It is mainly used in GUI parts of an application (Jaxx-validator use it). + * <br/> + * The idea is to attach the bean to validate insed the validator, then the + * validator listen any modification of the bean to revalidate it and fires + * events when messages has changed on a field. + * + * <pre> + * BeanValidatorListener listener = new BeanValidatorListener() {XXX}; + * BeanValidator<O> validator = XXX; + * validator.addBeanValidatorListener(listener); + * validator.setBean(o); + * </pre> + * + * <h2>Obtain a validator</h2> + * To obtain a bean validator use the factory of validators + * {@link org.nuiton.validator.bean.BeanValidatorFactory}. + * <br/> + * <pre> + * BeanValidator<O> validator = BeanValidatorFactory.newBeanValidator(O.class); + * </pre> + * + * <h2>Using the {@link org.nuiton.validator.bean.BeanValidatorFactory.BeanValidatorCreator}</h2> + * + * It is possible to use a {@link org.nuiton.validator.bean.BeanValidatorFactory.BeanValidatorCreator} to change the + * implementation of {@link org.nuiton.validator.bean.BeanValidator} + * instanticated by the factory. + * + * For this just use the method + * {@link org.nuiton.validator.bean.BeanValidatorFactory#setCreator(BeanValidatorCreator)}. + * + * By default it will us a default creator + * ({@link org.nuiton.validator.bean.BeanValidatorFactory.DefaultBeanValidatorCreator}). + * + * <strong>To be continued...</strong> + * + * @since 2.0 + */ +package org.nuiton.validator.bean; diff --git a/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidator.java b/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidator.java new file mode 100644 index 0000000..439ed3b --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidator.java @@ -0,0 +1,478 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.bean.simple; + +import com.google.common.base.Preconditions; +import org.apache.commons.beanutils.ConversionException; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.util.beans.BeanUtil; +import org.nuiton.validator.NuitonValidator; +import org.nuiton.validator.NuitonValidatorFactory; +import org.nuiton.validator.NuitonValidatorModel; +import org.nuiton.validator.NuitonValidatorProvider; +import org.nuiton.validator.NuitonValidatorResult; +import org.nuiton.validator.NuitonValidatorScope; +import org.nuiton.validator.bean.AbstractNuitonValidatorContext; +import org.nuiton.validator.bean.AbstractValidator; + +import java.beans.PropertyChangeListener; +import java.util.List; + +/** + * Validator for a javaBean object. + * <p/> + * A such validator is designed to validate to keep the validation of a bean, + * means the bean is attached to the validator (via the context field {@link #context}. + * <p/> + * A such validator is also a JavaBean and you can listen his states + * modifications via the classic java bean api. + * <p/> + * <strong>Note:</strong> The {@link SimpleBeanValidator} should never be used for + * validation in a service approch since it needs to keep a reference to the + * bean to validate. + * + * @author tchemit <chemit@codelutin.com> + * @see SimpleBeanValidatorListener + * @since 2.5.2 + */ +public class SimpleBeanValidator<O> extends AbstractValidator<O> { + + /** + * Name of the bounded property {@code bean}. + * + * @see #getBean() + * @see #setBean(Object) + */ + public static final String BEAN_PROPERTY = "bean"; + + /** Logger. */ + private static final Log log = LogFactory.getLog(SimpleBeanValidator.class); + + /** + * Obtain a new {@link SimpleBeanValidator} for the given parameters. + * <p/> + * <b>Note:</b> It will use the default provider of {@link NuitonValidator} + * + * @param type type of bean to validate + * @param context context of validation + * @param scopes authorized scopes (if {@code null}, will use all scopes) + * @param <O> type of bean to validate + * @return the new instanciated {@link SimpleBeanValidator}. + * @throws NullPointerException if type is {@code null} + * @see NuitonValidatorFactory#getDefaultProviderName() + */ + public static <O> SimpleBeanValidator<O> newValidator( + Class<O> type, + String context, + NuitonValidatorScope... scopes) throws NullPointerException { + + + // get the provider default name + String providerName = NuitonValidatorFactory.getDefaultProviderName(); + + // get the bean validator with this provider + SimpleBeanValidator<O> beanValidator = newValidator(providerName, + type, + context, + scopes + ); + return beanValidator; + } + + /** + * Obtain a new {@link SimpleBeanValidator} for the given parameters. + * <p/> + * <b>Note:</b> It will use the provider of {@link NuitonValidator} + * defined by the {@code providerName}. + * + * @param providerName name of {@link NuitonValidator} to use + * @param type type of bean to validate + * @param context context of validation + * @param scopes authorized scopes (if {@code null}, will use all scopes) + * @param <O> type of bean to validate + * @return the new instanciated {@link SimpleBeanValidator}. + * @throws NullPointerException if type is {@code null} + * @see NuitonValidatorFactory#getProvider(String) + */ + public static <O> SimpleBeanValidator<O> newValidator( + String providerName, + Class<O> type, + String context, + NuitonValidatorScope... scopes) throws NullPointerException { + + Preconditions.checkNotNull(type, + "type parameter can not be null."); + + // get delegate validator provider + NuitonValidatorProvider provider = + NuitonValidatorFactory.getProvider(providerName); + + Preconditions.checkState( + provider != null, + "Could not find provider with name " + providerName); + + // create the new instance of bean validator + SimpleBeanValidator<O> validator = new SimpleBeanValidator<O>( + provider, type, context, scopes); + + return validator; + } + + /** + * Context of the registred bean to validate. + * + * @since 2.5.2 + */ + protected final NuitonValidatorContext<O> context; + + /** + * To chain to another validator (acting as parent of this one). + * + * @since 2.5.2 + */ + protected SimpleBeanValidator<?> parentValidator; + + public SimpleBeanValidator(NuitonValidatorProvider validatorProvider, + Class<O> beanClass, + String context) { + + this(validatorProvider, beanClass, + context, + NuitonValidatorScope.values() + ); + } + + public SimpleBeanValidator(NuitonValidatorProvider validatorProvider, + Class<O> beanClass, + String context, + NuitonValidatorScope... scopes) { + + super(validatorProvider, beanClass); + + this.context = new NuitonValidatorContext<O>(); + + // build delegate validator + rebuildDelegateValidator(beanClass, context, scopes); + + // context has changed + firePropertyChange(CONTEXT_PROPERTY, + null, + context + ); + + // scopes has changed + firePropertyChange(SCOPES_PROPERTY, + null, + scopes + ); + } + + /** + * Obtain the actual bean attached to the validator. + * + * @return the bean attached to the validor or {@code null} if no bean + * is attached + */ + public O getBean() { + return context.getBean(); + } + + /** + * Change the attached bean. + * <p/> + * As a side effect, the internal + * {@link AbstractNuitonValidatorContext#messages} will be reset. + * + * @param bean the bean to attach (can be {@code null} to reset the + * validator). + */ + public void setBean(O bean) { + O oldBean = getBean(); + if (log.isDebugEnabled()) { + log.debug(this + " : " + bean); + } + + if (oldBean != null) { + try { + BeanUtil.removePropertyChangeListener(l, oldBean); + } catch (Exception eee) { + if (log.isInfoEnabled()) { + log.info("Can't unregister as listener for bean " + oldBean.getClass() + + " for reason " + eee.getMessage(), eee); + } + } + } + context.setBean(bean); + + if (bean == null) { + + // remove all messages for all fields of the validator + + mergeMessages(null); + + } else { + try { + + BeanUtil.addPropertyChangeListener(l, bean); + } catch (Exception eee) { + if (log.isInfoEnabled()) { + log.info("Can't register as listener for bean " + bean.getClass() + + " for reason " + eee.getMessage(), eee); + } + } + validate(); + } + setChanged(false); + setValid(context.isValid()); + firePropertyChange(BEAN_PROPERTY, oldBean, bean); + } + + public SimpleBeanValidator<?> getParentValidator() { + return parentValidator; + } + + public void setParentValidator(SimpleBeanValidator<?> parentValidator) { + this.parentValidator = parentValidator; + } + + @Override + public boolean hasFatalErrors() { + boolean result = context.hasFatalErrors(); + return result; + } + + @Override + public boolean hasErrors() { + boolean result = context.hasErrors(); + return result; + } + + @Override + public boolean hasWarnings() { + boolean result = context.hasWarnings(); + return result; + } + + @Override + public boolean hasInfos() { + boolean result = context.hasInfos(); + return result; + } + + @Override + public boolean isValid(String fieldName) { + + // field is valid if no fatal messages nor error messages + boolean result = context.isValid(fieldName); + return result; + } + + @Override + public NuitonValidatorScope getHighestScope(String field) { + NuitonValidatorScope scope = context.getHighestScope(field); + return scope; + } + + @Override + public <T> T convert(O bean, String fieldName, String value, Class<T> valueClass) { + Preconditions.checkState( + ObjectUtils.equals(bean, getBean()), + "Can not validate the bean [" + bean + + "] which is not the one registred [" + bean + + "] in this validator."); + + T convert = convert(fieldName, value, valueClass); + return convert; + } + + @Override + public void doValidate() { + validate(); + setValid(context.isValid()); + setChanged(true); + } + + /** + * Convert a value. + * <p/> + * If an error occurs, then add an error in validator. + * + * @param <T> the type of conversion + * @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) { + T convert = null; + + try { + convert = context.convert(fieldName, value, valueClass); + } catch (ConversionException e) { + // must revalidate + validate(); + } + return convert; + } + + public void addSimpleBeanValidatorListener(SimpleBeanValidatorListener listener) { + listenerList.add(SimpleBeanValidatorListener.class, listener); + } + + public void removeSimpleBeanValidatorListener(SimpleBeanValidatorListener listener) { + listenerList.remove(SimpleBeanValidatorListener.class, listener); + } + + public SimpleBeanValidatorListener[] getSimpleBeanValidatorListeners() { + return listenerList.getListeners(SimpleBeanValidatorListener.class); + } + + @Override + protected void doValidate(O bean) { + + Preconditions.checkState( + ObjectUtils.equals(bean, getBean()), + "Can not validate the bean [" + bean + + "] which is not the one registred [" + bean + + "] in this validator."); + + doValidate(); + } + + @Override + protected NuitonValidator<O> getDelegate() { + return context.getValidator(); + } + + @Override + protected void rebuildDelegateValidator(Class<O> beanType, + String context, + NuitonValidatorScope... scopes) { + + // changing context could change fields definition + // so dettach bean, must rebuild the fields + + // Dettach the bean before any thing, because with the new delegate + // validator some old fields could not be used any longer, and then + // listeners will never have the full reset of their model... + if (getBean() != null) { + setBean(null); + } + + if (scopes == null || scopes.length == 0) { + scopes = NuitonValidatorScope.values(); + } + + // compute the new validator model + NuitonValidatorModel<O> validatorModel = validatorProvider.getModel(beanType, + context, + scopes + ); + + // remove old delegate validator + NuitonValidator<O> delegate = validatorProvider.newValidator(validatorModel); + this.context.setValidator(delegate); + } + + /** + * 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} + * <p/> + * <b>Note:</b> la methode est protected et on utilise la methode + * {@link #doValidate()} car la méthode ne modifie pas les etats + * internes et cela en rend son utilisation delicate (le validateur entre + * dans un etat incoherent par rapport aux messages envoyés). + */ + protected 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 (isCanValidate()) { + + NuitonValidatorResult result = context.validate(); + + mergeMessages(result); + + if (parentValidator != null) { + // chained validation + // the parent validator should not be changed from this validation + boolean wasModified = parentValidator.isChanged(); + parentValidator.doValidate(); + if (!wasModified) { + // push back old state + parentValidator.setChanged(false); + } + } + } + } + + protected void fireFieldChanged(SimpleBeanValidatorEvent evt) { + + for (SimpleBeanValidatorListener listener : + listenerList.getListeners(SimpleBeanValidatorListener.class)) { + listener.onFieldChanged(evt); + } + } + + protected void mergeMessages(NuitonValidatorResult newMessages) { + + List<SimpleBeanValidatorEvent> events = context.mergeMessages(this, + newMessages); + + if (CollectionUtils.isNotEmpty(events)) { + + // send all messages + for (SimpleBeanValidatorEvent event : events) { + fireFieldChanged(event); + } + } + } + + protected static class NuitonValidatorContext<O> extends AbstractNuitonValidatorContext<O, SimpleBeanValidator<O>, SimpleBeanValidatorEvent> { + + @Override + protected SimpleBeanValidatorEvent createEvent(SimpleBeanValidator<O> source, + O bean, + String field, + NuitonValidatorScope scope, + String[] toAdd, + String[] toDelete) { + SimpleBeanValidatorEvent evt = new SimpleBeanValidatorEvent( + source, + field, + scope, + toAdd, + toDelete + ); + return evt; + } + } +} diff --git a/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidatorEvent.java b/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidatorEvent.java new file mode 100644 index 0000000..da472bc --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidatorEvent.java @@ -0,0 +1,51 @@ +package org.nuiton.validator.bean.simple; +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 - 2012 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import org.nuiton.validator.NuitonValidatorScope; +import org.nuiton.validator.bean.AbstractValidatorEvent; + +/** + * Event to be fired when some messages changed on a given field / scope of a bean. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public class SimpleBeanValidatorEvent extends AbstractValidatorEvent<SimpleBeanValidator<?>> { + + private static final long serialVersionUID = 1L; + + public SimpleBeanValidatorEvent(SimpleBeanValidator<?> source, + String field, + NuitonValidatorScope scope, + String[] messagestoAdd, + String[] messagestoDelete) { + super(source, field, scope, messagestoAdd, messagestoDelete); + } + + @Override + public Object getBean() { + return getSource().getBean(); + } +} diff --git a/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidatorListener.java b/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidatorListener.java new file mode 100644 index 0000000..5e28b8f --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidatorListener.java @@ -0,0 +1,38 @@ +package org.nuiton.validator.bean.simple; +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 - 2012 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import org.nuiton.validator.bean.ValidatorListener; +import org.nuiton.validator.bean.list.BeanListValidator; + +/** + * The definition of an event on {@link SimpleBeanValidatorEvent} + * to be fired by a {@link BeanListValidator}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public interface SimpleBeanValidatorListener extends ValidatorListener<SimpleBeanValidatorEvent> { + +} diff --git a/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidatorMessage.java b/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidatorMessage.java new file mode 100644 index 0000000..3ca40e4 --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidatorMessage.java @@ -0,0 +1,144 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.bean.simple; + +import org.nuiton.validator.NuitonValidatorScope; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +import static org.nuiton.i18n.I18n._; + +/** + * The object to box a validation message. + * + * @param <E> type of message (use for override {@link #compareTo(Object)} + * method. + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public class SimpleBeanValidatorMessage<E extends SimpleBeanValidatorMessage<?>> implements Comparable<E>, Serializable { + + private static final long serialVersionUID = 1L; + + /** the validator that produce the message */ + protected SimpleBeanValidator<?> validator; + + /** the field that produce the message */ + protected String field; + + /** the label of the message (to be displayed somewhere) */ + protected String message; + + /** the scope of the message */ + protected NuitonValidatorScope scope; + + public SimpleBeanValidatorMessage(SimpleBeanValidator<?> validator, + String field, + String message, + NuitonValidatorScope scope) { + this.field = field; + this.validator = validator; + this.message = message == null ? null : message.trim(); + this.scope = scope; + } + + public SimpleBeanValidator<?> getValidator() { + return validator; + } + + public String getField() { + return field; + } + + public NuitonValidatorScope getScope() { + return scope; + } + + public String getMessage() { + return message; + } + + @Override + public int compareTo(E o) { + // sort on scope + int result = getScope().compareTo(o.getScope()); + if (result == 0) { + // sort on field name + result = field.compareTo(o.field); + if (result == 0) { + // sort on message + result = message.compareTo(o.message); + } + } + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof SimpleBeanValidatorMessage<?>)) { + return false; + } + + SimpleBeanValidatorMessage<?> that = (SimpleBeanValidatorMessage<?>) o; + + return field.equals(that.field) && + (message != null ? !message.equals(that.message) : that.message == null) && + scope == that.scope; + } + + @Override + public int hashCode() { + int result = field.hashCode(); + result = 31 * result + (message != null ? message.hashCode() : 0); + result = 31 * result + (scope != null ? scope.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return scope + " - " + getI18nError(message); + } + + public String getI18nError(String error) { + String text; + if (!error.contains("##")) { + text = _(error); + } else { + StringTokenizer stk = new StringTokenizer(error, "##"); + String errorName = stk.nextToken(); + List<String> args = new ArrayList<String>(); + while (stk.hasMoreTokens()) { + args.add(stk.nextToken()); + } + text = _(errorName, args.toArray()); + } + return text; + } +} diff --git a/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidators.java b/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidators.java new file mode 100644 index 0000000..33dc1c0 --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/simple/SimpleBeanValidators.java @@ -0,0 +1,75 @@ +package org.nuiton.validator.bean.simple; +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 - 2012 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import org.nuiton.validator.NuitonValidatorScope; + +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.List; + +/** + * Useful methods arond {@link SimpleBeanValidator}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.4 + */ +public class SimpleBeanValidators { + + protected SimpleBeanValidators() { + // no constructor on helper class + } + + public static EnumSet<NuitonValidatorScope> getScopes( + List<SimpleBeanValidatorMessage<?>> messages) { + EnumSet<NuitonValidatorScope> result = + EnumSet.noneOf(NuitonValidatorScope.class); + for (SimpleBeanValidatorMessage<?> m : messages) { + result.add(m.getScope()); + } + return result; + } + + public static EnumMap<NuitonValidatorScope, Integer> getScopesCount( + List<SimpleBeanValidatorMessage<?>> messages) { + EnumMap<NuitonValidatorScope, Integer> result = + new EnumMap<NuitonValidatorScope, Integer>(NuitonValidatorScope.class); + for (NuitonValidatorScope s : NuitonValidatorScope.values()) { + result.put(s, 0); + } + for (SimpleBeanValidatorMessage<?> m : messages) { + + NuitonValidatorScope scope = m.getScope(); + + result.put(scope, result.get(scope) + 1); + } + + for (NuitonValidatorScope s : NuitonValidatorScope.values()) { + if (result.get(s) == 0) { + result.remove(s); + } + } + return result; + } +} diff --git a/src/main/java/org/nuiton/validator/bean/simple/package-info.java b/src/main/java/org/nuiton/validator/bean/simple/package-info.java new file mode 100644 index 0000000..703954b --- /dev/null +++ b/src/main/java/org/nuiton/validator/bean/simple/package-info.java @@ -0,0 +1,57 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +/** + * Package of Nuiton - Simple Bean Validator api. + * + * <h1>The <b>SimpleBeanValidator</b> api</h1> + * <p> + * The {@link org.nuiton.validator.bean.simple.SimpleBeanValidator} purpose is to validate + * a bean, with a listener api to interact with outside world. + * </p> + * It is mainly used in GUI parts of an application (Jaxx-validator use it). + * <br/> + * The idea is to attach the bean to validate insed the validator, then the + * validator listen any modification of the bean to revalidate it and fires + * events when messages has changed on a field. + * + * <pre> + * SimpleBeanValidatorListener listener = new SimpleBeanValidatorListener() {XXX}; + * SimpleBeanValidator<O> validator = XXX; + * validator.addSimpleBeanValidatorListener(listener); + * validator.setBean(o); + * </pre> + * + * <h2>Obtain a validator</h2> + * To obtain a bean validator use the factory method of the + * {@link org.nuiton.validator.bean.simple.SimpleBeanValidator}. + * <br/> + * <pre> + * SimpleBeanValidator<O> validator = SimpleBeanValidator.newValidator(...); + * </pre> + * + * <strong>To be continued...</strong> + * + * @since 2.0 + */ +package org.nuiton.validator.bean.simple; diff --git a/src/main/java/org/nuiton/validator/package-info.java b/src/main/java/org/nuiton/validator/package-info.java new file mode 100644 index 0000000..1219e4b --- /dev/null +++ b/src/main/java/org/nuiton/validator/package-info.java @@ -0,0 +1,55 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +/** + * Package of Nuiton-validator api. + * + * <h1>The <b>Validator</b> api</h1> + * <p> + * The {@link org.nuiton.validator.NuitonValidator} is the object responsible + * to launch validation for a given object and then return the result of + * validation in a {@link org.nuiton.validator.NuitonValidatorResult} via the + * method {@link org.nuiton.validator.NuitonValidator#validate(Object)}. + * </p> + * + * <pre> + * NuitonValidator<O> validator = XXX; + * NuitonValidatorResult result = validator.validate(o); + * </pre> + * + * <h2>Obtain a validator</h2> + * To obtain a validator use the factory of validators : {@link org.nuiton.validator.NuitonValidatorFactory}. + * <br/> + * <pre> + * NuitonValidator<O> validator = NuitonValidatorFactory.newValidator(O.class); + * </pre> + * + * <h2>Implements the validator api</h2> + * + * At the moment, there is an offered implementation based on xwork2 framework. + * + * <strong>To be continued...</strong> + * + * @since 2.0 + */ +package org.nuiton.validator; diff --git a/src/main/java/org/nuiton/validator/xwork2/XWork2NuitonValidator.java b/src/main/java/org/nuiton/validator/xwork2/XWork2NuitonValidator.java new file mode 100644 index 0000000..7518c5f --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/XWork2NuitonValidator.java @@ -0,0 +1,135 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2; + +import org.nuiton.validator.NuitonValidator; +import org.nuiton.validator.NuitonValidatorModel; +import org.nuiton.validator.NuitonValidatorResult; +import org.nuiton.validator.NuitonValidatorScope; + +import java.util.Arrays; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Implementation of {@link NuitonValidator} using {@code XWork2} validators. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class XWork2NuitonValidator<O> implements NuitonValidator<O> { + + protected NuitonValidatorModel<O> model; + + /** xworks scope validators * */ + protected Map<NuitonValidatorScope, XWork2ScopeValidator<O>> validators; + + public XWork2NuitonValidator(NuitonValidatorModel<O> model) { + + this.model = model; + + // init validators + validators = new EnumMap<NuitonValidatorScope, XWork2ScopeValidator<O>>(NuitonValidatorScope.class); + + Class<O> type = model.getType(); + String context = model.getContext(); + + Map<NuitonValidatorScope, String[]> fieldsMap = model.getFields(); + + for (Map.Entry<NuitonValidatorScope, String[]> entry : fieldsMap.entrySet()) { + + NuitonValidatorScope scope = entry.getKey(); + + String scopeContext = + XWork2ValidatorUtil.getContextForScope( + context, + scope + ); + + Set<String> fields = new HashSet<String>( + Arrays.asList(entry.getValue())); + + XWork2ScopeValidator<O> newValidator = + XWork2ValidatorUtil.newXWorkScopeValidator( + type, + scopeContext, + fields + ); + + validators.put(scope, newValidator); + } + } + + @Override + public NuitonValidatorResult validate(O object) throws NullPointerException { + + if (object == null) { + throw new NullPointerException("object parameter can not be null."); + } + + NuitonValidatorResult result = new NuitonValidatorResult(); + + for (NuitonValidatorScope scope : validators.keySet()) { + + XWork2ScopeValidator<O> validator = validators.get(scope); + + Map<String, List<String>> newMessages = validator.validate(object); + + result.addMessagesForScope(scope, newMessages); + } + return result; + } + + @Override + public Set<NuitonValidatorScope> getEffectiveScopes() { + return validators.keySet(); + } + + @Override + public Set<String> getEffectiveFields() { + Set<String> result = new HashSet<String>(); + for (XWork2ScopeValidator<O> scopeValidator : validators.values()) { + result.addAll(scopeValidator.getFieldNames()); + } + return result; + } + + @Override + public Set<String> getEffectiveFields(NuitonValidatorScope scope) { + Set<String> result = new HashSet<String>(); + XWork2ScopeValidator<O> scopeValidator = validators.get(scope); + if (scopeValidator != null) { + result.addAll(scopeValidator.getFieldNames()); + } + return result; + } + + @Override + public NuitonValidatorModel<O> getModel() { + return model; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/XWork2NuitonValidatorProvider.java b/src/main/java/org/nuiton/validator/xwork2/XWork2NuitonValidatorProvider.java new file mode 100644 index 0000000..c70265a --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/XWork2NuitonValidatorProvider.java @@ -0,0 +1,309 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.util.StringUtil; +import org.nuiton.validator.AbstractNuitonValidatorProvider; +import org.nuiton.validator.NuitonValidator; +import org.nuiton.validator.NuitonValidatorModel; +import org.nuiton.validator.NuitonValidatorScope; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Provider of validator for the xworks nuiton validator. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class XWork2NuitonValidatorProvider extends AbstractNuitonValidatorProvider { + + public static final String PROVIDER_NAME = "xwork2"; + + /** Logger. */ + private static final Log log = + LogFactory.getLog(XWork2NuitonValidatorProvider.class); + + public XWork2NuitonValidatorProvider() { + super(PROVIDER_NAME); + } + + @Override + public <O> NuitonValidatorModel<O> newModel(Class<O> type, + String context, + NuitonValidatorScope... scopes) { + + if (scopes.length == 0) { + // use all scopes + scopes = NuitonValidatorScope.values(); + } + + Map<NuitonValidatorScope, String[]> fields = + XWork2ValidatorUtil.detectFields(type, context, scopes); + + Set<NuitonValidatorScope> scopeSet = + EnumSet.noneOf(NuitonValidatorScope.class); + scopeSet.addAll(Arrays.asList(scopes)); + + return new NuitonValidatorModel<O>(type, context, scopeSet, fields); + } + + @Override + public <O> XWork2NuitonValidator<O> newValidator(NuitonValidatorModel<O> model) { + return new XWork2NuitonValidator<O>(model); + } + + @Override + public SortedSet<NuitonValidator<?>> detectValidators(File sourceRoot, + Pattern contextFilter, + NuitonValidatorScope[] scopes, + Class<?>... types) { + + if (scopes == null) { + + // use all scopes + scopes = NuitonValidatorScope.values(); + } + + SortedSet<NuitonValidator<?>> result = + new TreeSet<NuitonValidator<?>>(new ValidatorComparator()); + + for (Class<?> c : types) { + File dir = getClassDir(sourceRoot, c); + if (!dir.exists()) { + + // pas de repertoire adequate + if (log.isDebugEnabled()) { + log.debug("skip none existing directory " + dir); + } + continue; + } + String[] contexts = getContexts(c, dir); + if (log.isDebugEnabled()) { + log.debug("contexts : " + Arrays.toString(contexts)); + } + + if (contexts.length > 0) { + String[] realContexts = getContextsWithoutScopes(contexts); + + if (log.isDebugEnabled()) { + log.debug("realContexts : " + + Arrays.toString(realContexts)); + } + + if (contextFilter != null) { + + // filter contexts + realContexts = getFilterContexts(contextFilter, + realContexts + ); + if (log.isDebugEnabled()) { + log.debug("filterContexts : " + + Arrays.toString(realContexts)); + } + } + + for (String context : realContexts) { + + // on cherche le validateur + NuitonValidator<?> validator = getValidator( + c, + context.isEmpty() ? null : context, + scopes + ); + if (validator != null) { + // on enregistre le validateur + result.add(validator); + } + } + } + } + return result; + } + + /** + * Pour un context et un type d'entité donné, instancie un validateur et + * test si ce validateur est utilisable (i.e qu'il admet des champs à + * valider). + * <p/> + * Si aucun champ n'est trouvé dans le validateur, alors on retourne null. + * + * @param <O> le type du bean + * @param klass le type du bean + * @param context le context du validateur + * @param scopes les scopes a utiliser (si {@code null} alors pas de + * filtre sur les scopes) + * @return le validateur initialisé, ou <code>null</code> si aucun scope + * détecté dans le validateur. + */ + protected <O> NuitonValidator<O> getValidator(Class<O> klass, + String context, + NuitonValidatorScope... scopes) { + + NuitonValidatorModel<O> model = newModel(klass, context, scopes); + + XWork2NuitonValidator<O> valitator = newValidator(model); + + Set<NuitonValidatorScope> realScopes = valitator.getEffectiveScopes(); + if (realScopes.isEmpty()) { + valitator = null; + if (log.isDebugEnabled()) { + log.debug(klass + " : validator skip (no scopes detected)"); + } + } else { + if (log.isDebugEnabled()) { + log.debug(klass + " : keep validator " + valitator); + } + } + return valitator; + } + + protected File getClassDir(File sourceRoot, Class<?> clazz) { + String path = clazz.getPackage().getName(); + path = path.replaceAll("\\.", StringUtil.getFileSeparatorRegex()); + File dir = new File(sourceRoot, path); + return dir; + } + + protected String[] getContexts(Class<?> clazz, File dir) { + Set<String> result = new TreeSet<String>(); + ValidatorFilenameFilter filter = new ValidatorFilenameFilter(clazz); + if (log.isDebugEnabled()) { + log.debug("dir : " + dir); + } + String[] files = dir.list(filter); + for (String file : files) { + if (log.isDebugEnabled()) { + log.debug("file " + file); + } + String context = file.substring( + filter.prefix.length(), + file.length() - ValidatorFilenameFilter.SUFFIX.length() + ); + if (log.isDebugEnabled()) { + log.debug("detect " + clazz.getSimpleName() + + " context [" + context + "]"); + } + result.add(context); + } + return result.toArray(new String[result.size()]); + } + + protected String[] getContextsWithoutScopes(String[] contexts) { + Set<String> result = new TreeSet<String>(); + NuitonValidatorScope[] scopes = NuitonValidatorScope.values(); + for (String context : contexts) { + for (NuitonValidatorScope scope : scopes) { + String scopeName = scope.name().toLowerCase(); + if (!context.endsWith(scopeName)) { + // pas concerne par ce scope + continue; + } + if (log.isDebugEnabled()) { + log.debug("detect context : " + context); + } + String realContext = context.substring( + 0, + context.length() - scopeName.length() + ); + if (realContext.endsWith("-")) { + realContext = realContext.substring( + 0, + realContext.length() - 1 + ); + } + result.add(realContext); + } + } + return result.toArray(new String[result.size()]); + } + + protected String[] getFilterContexts(Pattern contextFilter, + String[] realContexts) { + List<String> result = new ArrayList<String>(); + for (String c : realContexts) { + Matcher m = contextFilter.matcher(c); + if (m.matches()) { + result.add(c); + } + } + return result.toArray(new String[result.size()]); + } + + protected static class ValidatorFilenameFilter implements FilenameFilter { + + protected static final String SUFFIX = "-validation.xml"; + + protected Class<?> clazz; + + protected String prefix; + + public ValidatorFilenameFilter(Class<?> clazz) { + this.clazz = clazz; + prefix = clazz.getSimpleName() + "-"; + } + + @Override + public boolean accept(File dir, String name) { + boolean result = name.endsWith(SUFFIX); + if (result) { + result = name.startsWith(prefix); + } + return result; + } + } + + protected static class ValidatorComparator implements Comparator<NuitonValidator<?>> { + + @Override + public int compare(NuitonValidator<?> o1, NuitonValidator<?> o2) { + + NuitonValidatorModel<?> model1 = ((XWork2NuitonValidator<?>) o1).getModel(); + NuitonValidatorModel<?> model2 = ((XWork2NuitonValidator<?>) o2).getModel(); + + String contextName1 = + model1.getType().getSimpleName() + "-" + + (model1.getContext() == null ? "" : model1.getContext()); + String contextName2 = + model2.getType().getSimpleName() + "-" + + (model2.getContext() == null ? "" : model2.getContext()); + return contextName1.compareTo(contextName2); + } + } + +} diff --git a/src/main/java/org/nuiton/validator/xwork2/XWork2ScopeValidator.java b/src/main/java/org/nuiton/validator/xwork2/XWork2ScopeValidator.java new file mode 100644 index 0000000..bb166bf --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/XWork2ScopeValidator.java @@ -0,0 +1,224 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ValidationAwareSupport; +import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.validator.ActionValidatorManager; +import com.opensymphony.xwork2.validator.DelegatingValidatorContext; +import com.opensymphony.xwork2.validator.ValidationException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * A customized validator for a given bean. + * <p/> + * Use the method {@link #validate(Object)} to obtain the messages detected by + * the validator for the given bean. + * + * @param <O> type of the bean to validate. + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class XWork2ScopeValidator<O> { + + /** Logger */ + private static final Log log = LogFactory.getLog(XWork2ScopeValidator.class); + + protected final static Map<String, List<String>> EMPTY_RESULT = + Collections.unmodifiableMap(new HashMap<String, List<String>>()); + + /** the type of bean to validate */ + protected final Class<O> type; + + /** the validation named context (can be null) */ + protected String context; + + /** the list of field names detected for this validator */ + protected Set<String> fieldNames; + + // -- + // XWorks fields + // -- + + protected ValidationAwareSupport validationSupport; + + protected DelegatingValidatorContext validationContext; + + protected ActionValidatorManager validator; + + protected ValueStack vs; + + protected XWork2ScopeValidator(Class<O> type, + String context, + Set<String> fieldNames, + ValueStack vs) { + + this.type = type; + this.context = context; + this.fieldNames = fieldNames; + + validationSupport = new ValidationAwareSupport(); + validationContext = new DelegatingValidatorContext(validationSupport); + + if (vs == null) { + + // create a standalone value stack + vs = XWork2ValidatorUtil.createValuestack(); + if (log.isDebugEnabled()) { + log.debug("create a standalone value stack " + vs); + } + } else { + if (log.isDebugEnabled()) { + log.debug("use given value stack " + vs); + } + } + + this.vs = vs; + + validator = XWork2ValidatorUtil.newValidationManager(vs); + } + + public Class<O> getType() { + return type; + } + + public String getContext() { + return context; + } + + public Set<String> getFieldNames() { + return fieldNames; + } + + public ActionValidatorManager getValidator() { + return validator; + } + + /** + * Test if the validator contains the field given his name + * + * @param fieldName the name of the searched field + * @return <code>true</code> if validator contaisn this field, + * <code>false</code> otherwise + */ + public boolean containsField(String fieldName) { + return fieldNames.contains(fieldName); + } + + /** + * Valide le bean donné et retourne les messages produits. + * + * @param bean le bean a valider (il doit etre non null) + * @return le dictionnaire des messages produits par la validation indexées + * par le nom du champs du bean impacté. + */ + public Map<String, List<String>> validate(O bean) { + + if (bean == null) { + throw new NullPointerException( + "bean parameter can not be null in method validate"); + } + + Map<String, List<String>> result = EMPTY_RESULT; + + + if (fieldNames.isEmpty()) { + return result; + } + + // on lance la validation uniquement si des champs sont a valider + try { + + //TC - 20081024 : since context is in a ThreadLocal variable, + // we must do the check + if (ActionContext.getContext() == null) { + ActionContext.setContext(new ActionContext(vs.getContext())); + } + + validator.validate(bean, context, validationContext); + + 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()); + } + + // retreave errors by field + if (validationContext.hasFieldErrors()) { + Map<?, ?> messages = validationContext.getFieldErrors(); + result = new HashMap<String, List<String>>(messages.size()); + for (Object fieldName : messages.keySet()) { + Collection<?> c = + (Collection<?>) messages.get(fieldName); + List<String> mm = new ArrayList<String>(c.size()); + for (Object message : c) { + // tchemit 2010-08-28 : trim the incoming message + // (I18n will not translate it otherwise) + String messageStr = message == null ? "" : message + ""; + mm.add(messageStr.trim()); + } + result.put(fieldName + "", mm); + } + } + + } catch (ValidationException eee) { + if (log.isWarnEnabled()) { + log.warn("Error during validation on " + type + + " for reason : " + eee.getMessage(), eee); + } + + } finally { + + // on nettoye toujours le validateur apres operation + validationSupport.clearErrorsAndMessages(); + } + + return result; + } + + @Override + public String toString() { + return super.toString() + "<beanClass:" + type + + ", contextName:" + context + ">"; + } + +} diff --git a/src/main/java/org/nuiton/validator/xwork2/XWork2ValidatorUtil.java b/src/main/java/org/nuiton/validator/xwork2/XWork2ValidatorUtil.java new file mode 100644 index 0000000..e393b47 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/XWork2ValidatorUtil.java @@ -0,0 +1,232 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.config.Configuration; +import com.opensymphony.xwork2.config.ConfigurationManager; +import com.opensymphony.xwork2.inject.Container; +import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.util.ValueStackFactory; +import com.opensymphony.xwork2.validator.ActionValidatorManager; +import com.opensymphony.xwork2.validator.FieldValidator; +import com.opensymphony.xwork2.validator.Validator; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.util.beans.BeanUtil; +import org.nuiton.validator.NuitonValidatorScope; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +/** + * Usefull methods to works with work2 validator api. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class XWork2ValidatorUtil { + + /** Logger. */ + private static final Log log = LogFactory.getLog(XWork2ValidatorUtil.class); + + /** + * a shared value stack to allow external operations on it (for example add + * some datas in stack to be usedby validators + */ + static private ValueStack sharedValueStack; + + public static ValueStack getSharedValueStack() { + if (sharedValueStack == null) { + + // init context + sharedValueStack = createValuestack(); + if (log.isDebugEnabled()) { + log.debug("init shared value stack " + sharedValueStack); + } + } + return sharedValueStack; + } + + public static ValueStack createValuestack() { + + ConfigurationManager confManager = new ConfigurationManager(); + Configuration conf = confManager.getConfiguration(); + Container container = conf.getContainer(); + ValueStackFactory stackFactory = container.getInstance(ValueStackFactory.class); + ValueStack vs = stackFactory.createValueStack(); + return vs; + } + + public static <O> XWork2ScopeValidator<O> newXWorkScopeValidator(Class<O> beanClass, String contextName, + Set<String> fields) { + return newXWorkScopeValidator(beanClass, contextName, fields, getSharedValueStack()); + } + + public static <O> XWork2ScopeValidator<O> newXWorkScopeValidator(Class<O> beanClass, String contextName, + Set<String> fields, ValueStack vs) { + + return new XWork2ScopeValidator<O>(beanClass, contextName, fields, vs); + } + + + public static String getContextForScope(String context, NuitonValidatorScope scope) { + return (context == null ? "" : context + "-") + scope.name().toLowerCase(); + } + + protected static ActionValidatorManager newValidationManager(ValueStack vs) { + + if (vs == null) { + vs = createValuestack(); + + if (log.isDebugEnabled()) { + log.debug("create a standalone value stack " + vs); + } + } else { + if (log.isDebugEnabled()) { + log.debug("use given value stack " + vs); + } + } + + ActionContext context = new ActionContext(vs.getContext()); + + // must set the action context otherwise can't obtain after validators + // with the method validator.getValidators(XXX) + // Later in the code, we could not having reference to the ValueStack + // before using a validator... Must be cleaned... + ActionContext.setContext(context); + + // init validator + Container container = context.getContainer(); + ActionValidatorManager validatorManager = + container.getInstance(ActionValidatorManager.class, "no-annotations"); + + //FIXME-tchemit 2012-07-17 work-around to fix http://nuiton.org/issues/2191 + //FIXME-tchemit 2012-07-17 will remove this when using xworks-core which fixes https://issues.apache.org/jira/browse/WW-3850 +// if (validatorManager instanceof DefaultActionValidatorManager) { +// +// FileManagerFactory fileManagerFactory = container.getInstance(FileManagerFactory.class); +// fileManagerFactory.setReloadingConfigs(String.valueOf(Boolean.FALSE)); +// ((DefaultActionValidatorManager) validatorManager).setFileManagerFactory(fileManagerFactory); +// } + + return validatorManager; + } + + public static <O> Map<NuitonValidatorScope, String[]> detectFields(Class<O> type, String context, + NuitonValidatorScope[] scopeUniverse) { + + Set<String> availableFields = BeanUtil.getReadableProperties(type); + + ActionValidatorManager validatorManager = newValidationManager(null); + + Map<NuitonValidatorScope, String[]> fields = new TreeMap<NuitonValidatorScope, String[]>(); + + for (NuitonValidatorScope scope : scopeUniverse) { + + Set<String> fieldNames = + detectFieldsForScope(validatorManager, type, scope, context, availableFields, false); + + if (log.isDebugEnabled()) { + log.debug("detected validator fields for scope " + scope + + ":" + context + " : " + fieldNames); + } + + if (!fieldNames.isEmpty()) { + + // fields detected in this validator, keep it + + fields.put(scope, fieldNames.toArray(new String[fieldNames.size()])); + } + } + + return fields; + + } + + protected static Set<String> detectFieldsForScope(ActionValidatorManager validator, + Class<?> type, + NuitonValidatorScope scope, + String context, + Set<String> availableFields, + boolean includeDefaultContext) { + + String scopeContext = getContextForScope(context, scope); + + Set<String> fields = new HashSet<String>(); + + int skip = 0; + if (scopeContext != null && !includeDefaultContext) { + // count the number of validator to skip + for (Validator<?> v : validator.getValidators(type, null)) { + // we only work on FieldValidator at the moment + if (v instanceof FieldValidator) { + skip++; + } + } + } + + for (Validator<?> v : validator.getValidators(type, scopeContext)) { + + // we only work on FieldValidator at the moment + if (v instanceof FieldValidator) { + if (skip > 0) { + skip--; + continue; + } + FieldValidator fieldValidator = (FieldValidator) v; + if (log.isDebugEnabled()) { + log.debug("context " + context + " - field " + + fieldValidator.getFieldName()); + } + String fName = fieldValidator.getFieldName(); + if (availableFields.contains(fName)) { + + // safe field + fields.add(fName); + } else { + + if (BeanUtil.isNestedReadableProperty(type, fName)) { + + fields.add(fName); + + } else { + // not a readable property, can not add it + String message = + "Field " + fName + " in scope [" + scopeContext + "] is not a readable property of " + + type.getName(); + if (log.isErrorEnabled()) { + log.error(message); + } + throw new IllegalStateException(message); + } + } + } + } + + return fields; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/CollectionFieldExpressionValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/CollectionFieldExpressionValidator.java new file mode 100644 index 0000000..81767af --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/CollectionFieldExpressionValidator.java @@ -0,0 +1,489 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.validators.FieldExpressionValidator; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * Un validateur basé sur {@link FieldExpressionValidator} qui valide sur une + * collection de propriéte. + * + * @author tchemit <chemit@codelutin.com> + */ +public class CollectionFieldExpressionValidator extends NuitonFieldExpressionValidator { + + public enum Mode { + + /** au moins une entrée de la collection doit etre valide */ + AT_LEAST_ONE, + /** exactement une entrée dela collection doit être valide */ + EXACTLY_ONE, + /** toutes les valeurs de la collection doivent etre valides */ + ALL, + /** aucune valeur de la collection doivent etre valides */ + NONE, + /** detection de clef unique */ + UNIQUE_KEY + } + + /** le mode de validation sur la liste */ + protected Mode mode; + + /** + * pour indiquer la propriété qui contient la liste à valider. + * <p/> + * Si cette prorpiété n'est pas renseignée alors on utilise la + * {@link #getFieldName()} pour obtenir la collection. + * <p/> + * Cela permet d'effectuer une validation si une collection mais portant + * en fait sur un autre champs + * + * @since 1.5 + */ + protected String collectionFieldName; + + /** + * drapeau pour utiliser le contexte de parcours pour valider + * l'expression, on dispose donc alors des variables previous, current, + * index, size et empty dans l'expression. + * <p/> + * Sinon l'expression s'applique directement sur l'entrée courant dans le + * parcours sans préfixe. + */ + protected boolean useSensitiveContext; + + /** + * expression a valider sur la premiètre entrée de la collection. + * <p/> + * Note : Pour le moment, on autorise uniquement cela en mode ALL. + */ + protected String expressionForFirst; + + /** + * expression a valider sur la dernière entrée de la collection. + * <p/> + * Note : Pour le moment, on autorise uniquement cela en mode ALL. + */ + protected String expressionForLast; + + /** + * la liste des propriétés d'une entrée de la collection qui définit la + * clef unique (en mode UNIQUE_KEY). + */ + protected String[] keys; + + /** le context de parcours */ + protected WalkerContext c; + + private boolean useFirst, useLast; + + public Mode getMode() { + return mode; + } + + public void setMode(Mode mode) { + this.mode = mode; + } + + public String getCollectionFieldName() { + return collectionFieldName; + } + + public void setCollectionFieldName(String collectionFieldName) { + this.collectionFieldName = collectionFieldName; + } + + public boolean isUseSensitiveContext() { + return useSensitiveContext; + } + + public void setUseSensitiveContext(boolean useSensitiveContext) { + this.useSensitiveContext = useSensitiveContext; + } + + public String getExpressionForFirst() { + return expressionForFirst; + } + + public void setExpressionForFirst(String expressionForFirst) { + this.expressionForFirst = expressionForFirst; + } + + public String getExpressionForLast() { + return expressionForLast; + } + + public void setExpressionForLast(String expressionForLast) { + this.expressionForLast = expressionForLast; + } + + public String[] getKeys() { + return keys; + } + + public void setKeys(String[] keys) { + if (keys != null && keys.length == 1 && keys[0].contains(",")) { + this.keys = keys[0].split(","); + } else { + this.keys = keys; + } + } + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + if (mode == null) { + throw new ValidationException("no mode defined!"); + } + useFirst = expressionForFirst != null && !expressionForFirst.trim().isEmpty(); + useLast = expressionForLast != null && !expressionForLast.trim().isEmpty(); + + if (useFirst && mode != Mode.ALL) { + throw new ValidationException("can only use expressionForFirst in " + + "mode ALL but was " + mode); + } + if (useLast && mode != Mode.ALL) { + throw new ValidationException("can only use expressionForLast in " + + "mode ALL but was " + mode); + } + + String fieldName = getFieldName(); + + Collection<?> col = getCollection(object); + + if (useSensitiveContext) { + c = new WalkerContext(col.size()); + } + + boolean answer; + + boolean pop = false; + + if (!stack.getRoot().contains(object)) { + stack.push(object); + pop = true; + } + + switch (mode) { + case ALL: + answer = validateAllEntries(col); + break; + case AT_LEAST_ONE: + answer = validateAtLeastOneEntry(col); + break; + case EXACTLY_ONE: + answer = validateExtacltyOneEntry(col); + break; + case NONE: + answer = validateNoneEntry(col); + break; + case UNIQUE_KEY: + if (keys == null || keys.length == 0) { + throw new ValidationException("no unique keys defined"); + } + answer = validateUniqueKey(col); + break; + + default: + // should never come here... + answer = false; + } + + if (!answer) { + addFieldError(fieldName, object); + } + if (pop) { + stack.pop(); + } + } + + protected ValueStack stack; + + @Override + public void setValueStack(ValueStack stack) { + super.setValueStack(stack); + this.stack = stack; + } + + @Override + public String getMessage(Object object) { + boolean pop = false; + + if (useSensitiveContext && !stack.getRoot().contains(c)) { + stack.push(c); + pop = true; + } + String message = super.getMessage(object); + + if (pop) { + stack.pop(); + } + return message; + } + + protected Boolean validateAllEntries(Collection<?> col) throws ValidationException { + boolean answer = true; + for (Object entry : col) { + answer = validateOneEntry(entry); + if (!answer) { + // validation on one entry has failed + // no need to continue + break; + } + } + return answer; + } + + protected Boolean validateNoneEntry(Collection<?> col) throws ValidationException { + boolean answer = true; + for (Object entry : col) { + boolean b = validateOneEntry(entry); + if (b) { + // one entry has sucessed, validation has failed + // no need to continue + answer = false; + break; + } + } + return answer; + } + + protected Boolean validateAtLeastOneEntry(Collection<?> col) throws ValidationException { + boolean answer = false; + for (Object entry : col) { + answer = validateOneEntry(entry); + if (answer) { + // one entry was succes, validation is ok, + // no need to continue + break; + } + } + return answer; + } + + protected Boolean validateExtacltyOneEntry(Collection<?> col) throws ValidationException { + int count = 0; + for (Object entry : col) { + boolean answer = validateOneEntry(entry); + if (answer) { + // one entry has succed + count++; + if (count > 1) { + // more than one entriy was successfull + // so validation has failed + break; + } + + } + } + return count == 1; + } + + protected Boolean validateUniqueKey(Collection<?> col) throws ValidationException { + boolean answer = true; + + Set<Integer> hashCodes = new HashSet<Integer>(); + int index = -1; + for (Object entry : col) { + index++; + // construction du hash de la clef d'unicite + Integer hash = getUniqueKeyHashCode(entry); + if (!hashCodes.contains(hash)) { + hashCodes.add(hash); + continue; + } + // une entree avec ce hash a deja ete trouvee + // on est donc en violation sur la clef unique + answer = false; + if (log.isDebugEnabled()) { + log.debug("duplicated uniquekey " + hash + " for entry " + index); + } + } + hashCodes.clear(); + return answer; + } + + protected boolean validateOneEntry(Object object) throws ValidationException { + + Boolean answer = Boolean.FALSE; + + boolean extraExpression = false; + + if (useSensitiveContext) { + c.addCurrent(object); + object = c; + + if (c.isFirst() && useFirst) { + // on valide l'expression sur la premiètre entrée + answer = evaluateExpression(expressionForFirst, object); + extraExpression = true; + } + if (c.isLast() && useLast) { + // on valide l'expression sur la dernière entrée + answer = (!extraExpression || answer) && evaluateExpression(expressionForLast, object); + extraExpression = true; + } + } + + answer = (!extraExpression || answer) && evaluateExpression(getExpression(), object); + + return answer; + } + + protected boolean evaluateExpression(String expression, Object object) throws ValidationException { + Object obj = null; + try { + obj = getFieldValue(expression, object); + } catch (ValidationException e) { + throw e; + } catch (Exception e) { + log.error(e.getMessage(), e); + // let this pass, but it will be logged right below + } + + Boolean answer = Boolean.FALSE; + + if (obj != null && obj instanceof Boolean) { + answer = (Boolean) obj; + } else { + log.warn("Got result of " + obj + " when trying to get Boolean for expression " + expression); + } + return answer; + } + + /** + * @param object the incoming object containing the collection to test + * @return the collection of the incoming object given by the fieldName property + * @throws ValidationException if any pb to retreave the collection + */ + protected Collection<?> getCollection(Object object) throws ValidationException { + String fieldName = getCollectionFieldName(); + if (fieldName == null || fieldName.trim().isEmpty()) { + // on travaille directement sur le fieldName + fieldName = getFieldName(); + } + + Object obj = null; + + // obtain the collection to test + try { + obj = getFieldValue(fieldName, object); + } catch (ValidationException e) { + throw e; + } catch (Exception e) { + // let this pass, but it will be logged right below + } + + if (obj == null) { + // la collection est nulle, donc on renvoie une collection vide + return Collections.emptyList(); + } + + if (!Collection.class.isInstance(obj)) { + throw new ValidationException("field " + fieldName + " is not a collection type! (" + obj.getClass() + ")"); + } + return (Collection<?>) obj; + } + + /** + * Calcule pour une entrée donné, le hash de la clef unique + * + * @param o l'entree de la collection dont on va calculer le hash de la clef unique + * @return le hashCode calclé de la clef unique sur l'entrée donné + * @throws ValidationException if any pb to retreave properties values + */ + protected Integer getUniqueKeyHashCode(Object o) throws ValidationException { + // calcul du hash à la volée + HashCodeBuilder builder = new HashCodeBuilder(); + for (String key : keys) { + Object property = getFieldValue(key, o); + if (log.isDebugEnabled()) { + log.debug("key " + key + " : " + property); + } + builder.append(property); + } + return builder.toHashCode(); + } + + @Override + public String getValidatorType() { + return "collectionFieldExpression"; + } + + public class WalkerContext { + + protected final int size; + + public WalkerContext(int size) { + this.size = size; + } + + protected int index = -1; + + protected Object current; + + protected Object previous; + + public void addCurrent(Object current) { + index++; + previous = this.current; + this.current = current; + } + + public Object getCurrent() { + return current; + } + + public int getIndex() { + return index; + } + + public Object getPrevious() { + return previous; + } + + public int getSize() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + public boolean isFirst() { + return index == 0; + } + + public boolean isLast() { + return index == size - 1; + } + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/CollectionUniqueKeyValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/CollectionUniqueKeyValidator.java new file mode 100644 index 0000000..f0a4f8f --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/CollectionUniqueKeyValidator.java @@ -0,0 +1,323 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.validators.FieldExpressionValidator; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Un validateur basé sur {@link FieldExpressionValidator} qui valide une clef + * unique sur une collection. + * <p/> + * Le {@link #fieldName} sert à récupérer la propriété de type de collection du + * bean. + * + * @author tchemit <chemit@codelutin.com> + */ +public class CollectionUniqueKeyValidator extends NuitonFieldValidatorSupport { + + /** + * pour indiquer la propriété qui contient la liste à valider. + * <p/> + * Si cette prorpiété n'est pas renseignée alors on utilise la + * {@link #getFieldName()} pour obtenir la collection. + * <p/> + * Cela permet d'effectuer une validation si une collection mais portant + * en fait sur un autre champs + * + * @since 1.5 + */ + protected String collectionFieldName; + + /** + * la liste des propriétés d'une entrée de la collection qui définit la + * clef unique. + */ + protected String[] keys; + + /** + * Une propriété optionnelle pour valider que l'objet reflétée par cette + * propriété ne viole pas l'intégrité de la clef unique. + * Cela permet de valider l'unicité sans que l'objet soit dans la collection + */ + protected String againstProperty; + + /** + * Une propriété optionnelle pour utiliser l'objet en cours de validation pour + * valider que l'objet reflétée par cette propriété ne viole pas l'intégrité de la clef unique. + * Cela permet de valider l'unicité sans que l'objet soit dans la collection + */ + protected boolean againstMe; + + /** + * Lors de l'utilisation de la againstProperty et qu'un ne peut pas utiliser + * le equals sur l'objet, on peut spécifier une expression pour exclure des + * tests lors de la recherche de la violation de clef unique. + */ + protected String againstIndexExpression; + + /** + * Pour ne pas traiter les valeurs nulles (si positionné à {@code true} les + * valeurs nulles ne sont pas considérée comme unique). + * + * @since 2.2.6 + */ + protected boolean nullValueSkipped; + + public String getCollectionFieldName() { + return collectionFieldName; + } + + public void setCollectionFieldName(String collectionFieldName) { + this.collectionFieldName = collectionFieldName; + } + + public String[] getKeys() { + return keys; + } + + public boolean getAgainstMe() { + return againstMe; + } + + public void setKeys(String[] keys) { + if (keys != null && keys.length == 1 && keys[0].indexOf(',') != -1) { + this.keys = keys[0].split(","); + } else { + this.keys = keys; + } + } + + public String getAgainstProperty() { + return againstProperty; + } + + public void setAgainstProperty(String againstProperty) { + this.againstProperty = againstProperty; + } + + public String getAgainstIndexExpression() { + return againstIndexExpression; + } + + public void setAgainstIndexExpression(String againstIndexExpression) { + this.againstIndexExpression = againstIndexExpression; + } + + public void setAgainstMe(boolean againstMe) { + this.againstMe = againstMe; + } + + public boolean isNullValueSkipped() { + return nullValueSkipped; + } + + public void setNullValueSkipped(boolean nullValueSkipped) { + this.nullValueSkipped = nullValueSkipped; + } + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + + if (keys == null || keys.length == 0) { + throw new ValidationException("no unique keys defined"); + } + + String fieldName = getFieldName(); + + Collection<?> col = getCollection(object); + + if (log.isDebugEnabled()) { + log.debug("collection found : " + col); + } + Object againstBean = againstProperty == null ? null : + getFieldValue(againstProperty, object); + + if (log.isDebugEnabled()) { + log.debug("againtBean = " + againstBean); + } + Integer againstIndex = (Integer) (againstIndexExpression == null ? + -1 : + getFieldValue(againstIndexExpression, object)); + if (againstIndex == null) { + againstIndex = -1; + } + if (!againstMe && againstBean == null && col.size() < 2) { + // la liste ne contient pas deux entrées donc c'est valide + return; + } + + if (againstMe) { + // try on this object + againstBean = object; + if (log.isDebugEnabled()) { + log.debug("againtBean from me = " + againstBean); + } + } + + + boolean answer = true; + + Integer againstHashCode = againstBean == null ? + null : getUniqueKeyHashCode(againstBean); + if (log.isDebugEnabled()) { + log.debug("hash for new key " + againstHashCode); + } + + if (againstHashCode == null && nullValueSkipped) { + + // clef nulle, donc pas d'erreur vu que le flag a ete positionne + return; + } + List<Integer> hashCodes = new ArrayList<Integer>(); + + int index = 0; + for (Object o : col) { + Integer hash = getUniqueKeyHashCode(o); + + if (log.isDebugEnabled()) { + log.debug("hash for object " + o + " = " + hash); + } + + if (hash == null && nullValueSkipped) { + + // clef nulle, donc pas d'erreur vu que le flag a ete positionne + continue; + } + + if (againstBean == null) { + if (hashCodes.contains(hash)) { + + // on a deja rencontre cette clef unique, + // donc la validation a echouee + answer = false; + if (log.isDebugEnabled()) { + log.debug("Found same hashcode, not unique!"); + } + break; + } + } else { + // utilisation de againstBean + if (againstIndex != -1) { + if (index != againstIndex && + hash.equals(againstHashCode)) { + // on a deja rencontre cette clef unique, + // donc la validation a echouee + answer = false; + break; + } + } else { + if (!againstBean.equals(o) && + hash.equals(againstHashCode)) { + // on a deja rencontre cette clef unique, + // donc la validation a echouee + answer = false; + break; + } + } + } + // nouveau hashcode enregistre + hashCodes.add(hash); + // index suivant + index++; + } + + if (!answer) { + addFieldError(fieldName, object); + } + } + + /** + * Calcule pour une entrée donné, le hash de la clef unique + * + * @param o l'entree de la collection dont on va calculer le hash de + * la clef unique + * @return le hashCode calclé de la clef unique sur l'entrée donné + * @throws ValidationException if any pb to retreave properties values + */ + protected Integer getUniqueKeyHashCode(Object o) + throws ValidationException { + // calcul du hash à la volée + HashCodeBuilder builder = new HashCodeBuilder(); + for (String key : keys) { + Object property = getFieldValue(key, o); + if (property == null && nullValueSkipped) { + // une valeur nulle a ete trouvee et le flag de skip est positionne + // on retourne alors null comme cas limite + return null; + } + + builder.append(property); + } + return builder.toHashCode(); + } + + /** + * @param object the incoming object containing the collection to test + * @return the collection of the incoming object given by the fieldName + * property + * @throws ValidationException if any pb to retreave the collection + */ + protected Collection<?> getCollection(Object object) + throws ValidationException { + String fieldName = getCollectionFieldName(); + if (fieldName == null || fieldName.trim().isEmpty()) { + // on travaille directement sur le fieldName + fieldName = getFieldName(); + } + + Object obj = null; + + // obtain the collection to test + try { + obj = getFieldValue(fieldName, object); + } catch (ValidationException e) { + throw e; + } catch (Exception e) { + // let this pass, but it will be logged right below + } + + if (obj == null) { + // la collection est nulle, donc on renvoie une collection vide + return Collections.emptyList(); + } + + if (!Collection.class.isInstance(obj)) { + throw new ValidationException("field " + fieldName + + " is not a collection type! (" + obj.getClass() + ')'); + } + return (Collection<?>) obj; + } + + @Override + public String getValidatorType() { + return "collectionUniqueKey"; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/EmailFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/EmailFieldValidator.java new file mode 100644 index 0000000..da5b790 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/EmailFieldValidator.java @@ -0,0 +1,66 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; +import org.apache.commons.lang3.StringUtils; +import org.nuiton.util.StringUtil; + +/** + * Validator for email addresses : + * - Deal with + in addresses + * + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class EmailFieldValidator extends NuitonFieldValidatorSupport { + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + + if (value == null) { + // no value defined + return; + } + if (value instanceof String) { + if (StringUtils.isEmpty((String) value)) { + // no value defined + return; + } + if (!StringUtil.isEmail((String) value)) { + addFieldError(fieldName, object); + } + } else { + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "emailNuiton"; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/ExistingDirectoryFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/ExistingDirectoryFieldValidator.java new file mode 100644 index 0000000..80fe7c5 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/ExistingDirectoryFieldValidator.java @@ -0,0 +1,95 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; + +import java.io.File; + +/** + * <!-- START SNIPPET: javadoc --> + * ExistingDirectoryFieldValidator checks that a File field exists and is a directory. + * <!-- END SNIPPET: javadoc --> + * <p/> + * <p/> + * <!-- START SNIPPET: parameters --> + * <ul> + * <li>fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required</li> + * </ul> + * <!-- END SNIPPET: parameters --> + * <p/> + * <p/> + * <pre> + * <!-- START SNIPPET: examples --> + * <validators> + * <!-- Plain-Validator Syntax --> + * <validator type="existingDirectory"> + * <param name="fieldName">tmp</param> + * <message>tmp is not an existing directory</message> + * </validator> + * + * <!-- Field-Validator Syntax --> + * <field name="tmp"> + * <field-validator type="existingDirectory"> + * <message>tmp is not an existing directory</message> + * </field-validator> + * </field> + * </validators> + * <!-- END SNIPPET: examples --> + * </pre> + * + * @author tchemit <chemit@codelutin.com> + */ +public class ExistingDirectoryFieldValidator extends NuitonFieldValidatorSupport { + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + if (value == null) { + // no value defined + addFieldError(fieldName, object); + return; + } + File f; + if (value instanceof File) { + f = (File) value; + } else if (value instanceof String) { + f = new File((String) value); + } else { + addFieldError(fieldName, object); + return; + } + + if (!(f.isDirectory() && f.exists())) { + // f is not a directory, nor exists + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "existingDirectory"; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/ExistingFileFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/ExistingFileFieldValidator.java new file mode 100644 index 0000000..333a601 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/ExistingFileFieldValidator.java @@ -0,0 +1,95 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; + +import java.io.File; + +/** + * <!-- START SNIPPET: javadoc --> + * ExistingFileFieldValidator checks that a File field exists. * + * <!-- END SNIPPET: javadoc --> + * <p/> + * <p/> + * <!-- START SNIPPET: parameters --> + * <ul> + * <li>fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required</li> + * </ul> + * <!-- END SNIPPET: parameters --> + * <p/> + * <p/> + * <pre> + * <!-- START SNIPPET: examples --> + * <validators> + * <!-- Plain-Validator Syntax --> + * <validator type="fileExisting"> + * <param name="fieldName">tmp</param> + * <message>tmp is not an existing file</message> + * </validator> + * + * <!-- Field-Validator Syntax --> + * <field name="tmp"> + * <field-validator type="fileExisting"> + * <message>tmp is not an existing file</message> + * </field-validator> + * </field> + * </validators> + * <!-- END SNIPPET: examples --> + * </pre> + * + * @author tchemit <chemit@codelutin.com> + */ +public class ExistingFileFieldValidator extends NuitonFieldValidatorSupport { + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + if (value == null) { + // no value defined + addFieldError(fieldName, object); + return; + } + File f; + if (value instanceof File) { + f = (File) value; + } else if (value instanceof String) { + f = new File((String) value); + } else { + addFieldError(fieldName, object); + return; + } + + if (!(f.isFile() && f.exists())) { + // f is not a file nor exists + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "existingFile"; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/FieldExpressionWithParamsValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/FieldExpressionWithParamsValidator.java new file mode 100644 index 0000000..145bfa6 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/FieldExpressionWithParamsValidator.java @@ -0,0 +1,223 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.validators.FieldExpressionValidator; +import org.nuiton.util.converter.ConverterUtil; + +import java.util.Map; +import java.util.StringTokenizer; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Extends {@link FieldExpressionValidator} to add some extra parameters available + * in the {@link #getExpression()} + * + * @author tchemit <chemit@codelutin.com> + * @since 1.3 + */ +public class FieldExpressionWithParamsValidator extends NuitonFieldExpressionValidator { + + protected static final Pattern EXTRA_BOOLEAN_PARAM_ENTRY_PATTERN = Pattern.compile("(\\w+)\\:(false|true)"); + + protected static final Pattern EXTRA_SHORT_PARAM_ENTRY_PATTERN = Pattern.compile("(\\w+)\\:(\\d+)"); + + protected static final Pattern EXTRA_INT_PARAM_ENTRY_PATTERN = Pattern.compile("(\\w+)\\:(\\d+)"); + + protected static final Pattern EXTRA_LONG_PARAM_ENTRY_PATTERN = Pattern.compile("(\\w+)\\:(\\d+)"); + + protected static final Pattern EXTRA_DOUBLE_PARAM_ENTRY_PATTERN = Pattern.compile("(\\w+)\\:(\\d+\\.\\d+)"); + + protected static final Pattern EXTRA_STRING_PARAM_ENTRY_PATTERN = Pattern.compile("(\\w+)\\:(.+)"); + + protected ValueStack stack; + + protected String booleanParams; + + protected String shortParams; + + protected String intParams; + + protected String longParams; + + protected String doubleParams; + + protected String stringParams; + + protected Map<String, Boolean> booleans; + + protected Map<String, Short> shorts; + + protected Map<String, Integer> ints; + + protected Map<String, Long> longs; + + protected Map<String, Double> doubles; + + protected Map<String, String> strings; + + public String getBooleanParams() { + return booleanParams; + } + + public void setBooleanParams(String booleanParams) { + this.booleanParams = booleanParams; + } + + public String getDoubleParams() { + return doubleParams; + } + + public void setDoubleParams(String doubleParams) { + this.doubleParams = doubleParams; + } + + public String getIntParams() { + return intParams; + } + + public void setIntParams(String intParams) { + this.intParams = intParams; + } + + public String getLongParams() { + return longParams; + } + + public void setLongParams(String longParams) { + this.longParams = longParams; + } + + public String getShortParams() { + return shortParams; + } + + public void setShortParams(String shortParams) { + this.shortParams = shortParams; + } + + public String getStringParams() { + return stringParams; + } + + public void setStringParams(String stringParams) { + this.stringParams = stringParams; + } + + public Map<String, Boolean> getBooleans() { + return booleans; + } + + public Map<String, Double> getDoubles() { + return doubles; + } + + public Map<String, Integer> getInts() { + return ints; + } + + public Map<String, Long> getLongs() { + return longs; + } + + public Map<String, Short> getShorts() { + return shorts; + } + + public Map<String, String> getStrings() { + return strings; + } + + @Override + public String getValidatorType() { + return "fieldexpressionwithparams"; + } + + @Override + public void setValueStack(ValueStack stack) { + super.setValueStack(stack); + this.stack = stack; + } + + @Override + public void validate(Object object) throws ValidationException { + super.validate(object); + } + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + + booleans = initParams(Boolean.class, booleanParams, EXTRA_BOOLEAN_PARAM_ENTRY_PATTERN); + shorts = initParams(Short.class, shortParams, EXTRA_SHORT_PARAM_ENTRY_PATTERN); + ints = initParams(Integer.class, intParams, EXTRA_INT_PARAM_ENTRY_PATTERN); + longs = initParams(Long.class, longParams, EXTRA_LONG_PARAM_ENTRY_PATTERN); + doubles = initParams(Double.class, doubleParams, EXTRA_DOUBLE_PARAM_ENTRY_PATTERN); + strings = initParams(String.class, stringParams, EXTRA_STRING_PARAM_ENTRY_PATTERN); + + boolean pop = false; + if (!stack.getRoot().contains(this)) { + stack.push(this); + pop = true; + } + + try { + super.validateWhenNotSkip(object); + } finally { + if (pop) { + stack.pop(); + } + } + + } + + protected <T> Map<String, T> initParams(Class<T> klass, String extraParams, Pattern pattern) throws ValidationException { + + if (extraParams == null || extraParams.isEmpty()) { + // not using + return null; + } + + StringTokenizer stk = new StringTokenizer(extraParams, "|"); + Map<String, T> result = new TreeMap<String, T>(); + while (stk.hasMoreTokens()) { + String entry = stk.nextToken(); + Matcher matcher = pattern.matcher(entry); + if (!matcher.matches()) { + throw new ValidationException("could not parse for extra params " + extraParams + " for type " + klass.getName()); + } + String paramName = matcher.group(1); + String paramValueStr = matcher.group(2); + T paramValue = ConverterUtil.convert(klass, paramValueStr); + if (log.isDebugEnabled()) { + log.debug("detected extra param : <type:" + klass + ", name:" + paramName + ", value:" + paramValue + ">"); + } + result.put(paramName, paramValue); + } + return result; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/FrenchCityNameFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/FrenchCityNameFieldValidator.java new file mode 100644 index 0000000..ecf4516 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/FrenchCityNameFieldValidator.java @@ -0,0 +1,75 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Validator for French cities names : + * - No number accepted + * - Accept spaces, - and ' + * + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class FrenchCityNameFieldValidator extends NuitonFieldValidatorSupport { + + protected static String CITY_NAME_REGEXP = "[^\\d]+"; + + protected static Pattern p = Pattern.compile(CITY_NAME_REGEXP); + + //TODO JC18082011 - Deal with cedex + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + + if (value == null) { + // no value defined + return; + } + if (value instanceof String) { + if ("".equals(value)) { + // no value defined + return; + } + Matcher m = p.matcher((String) value); + if (!m.matches()) { + addFieldError(fieldName, object); + } + } else { + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "frenchCityName"; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidator.java new file mode 100644 index 0000000..947b55d --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidator.java @@ -0,0 +1,92 @@ +package org.nuiton.validator.xwork2.field; + +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2013 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import com.opensymphony.xwork2.validator.ValidationException; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Sylvain Bavencoff <bavencoff@codelutin.com> + */ +public class FrenchFinessFieldValidator extends NuitonFieldValidatorSupport { + + protected static final String SIRET_REGEXP = "([0-9]{2}|2A|2B)0([0-9]{6})"; + + protected static final Pattern p = Pattern.compile(SIRET_REGEXP); + + @Override + protected void validateWhenNotSkip(Object object) throws ValidationException { + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + + if (value == null) { + // no value defined + return; + } + String finess; + + if (value.getClass().isArray()) { + // le finess est stocker dans un tableau, par exemple un byte[] + finess = ""; + for (int i = 0; i < Array.getLength(value); i++) { + finess += String.valueOf(Array.get(value, i)); + } + } else if (value instanceof Collection<?>) { + // le finess est stocker dans une collection, + // ca doit pas arriver souvent :D, mais autant le gerer + finess = ""; + for (Object o : (Collection<?>) value) { + finess += String.valueOf(o); + } + } else { + // sinon dans tous les autres cas (String, int, long, BigInteger ...) + // on prend le toString + finess = String.valueOf(value); + } + + if (StringUtils.isEmpty(finess)) { + // no value defined + return; + } + + // Remove any space + finess = finess.replaceAll(" ", ""); + + Matcher m = p.matcher(finess); + if (!m.matches()) { + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "frenchFiness"; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/FrenchLastNameFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/FrenchLastNameFieldValidator.java new file mode 100644 index 0000000..e342dec --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/FrenchLastNameFieldValidator.java @@ -0,0 +1,73 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Validator for French last names : + * - No number accepted + * - Accept spaces, - and ' + * + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class FrenchLastNameFieldValidator extends NuitonFieldValidatorSupport { + + protected static String LAST_NAME_REGEXP = "[^\\d]+"; + + protected static Pattern p = Pattern.compile(LAST_NAME_REGEXP); + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + + if (value == null) { + // no value defined + return; + } + if (value instanceof String) { + if ("".equals(value)) { + // no value defined + return; + } + Matcher m = p.matcher((String) value); + if (!m.matches()) { + addFieldError(fieldName, object); + } + } else { + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "frenchLastName"; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/FrenchPhoneNumberFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/FrenchPhoneNumberFieldValidator.java new file mode 100644 index 0000000..c1f3d09 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/FrenchPhoneNumberFieldValidator.java @@ -0,0 +1,76 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Validator used to validate French phone numbers like : + * - 0000000000 + * - 00.00.00.00.00 + * - 00-00-00-00-00 + * - 00 00 00 00 00 + * + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class FrenchPhoneNumberFieldValidator extends NuitonFieldValidatorSupport { + + protected static String PHONE_NUMBER_REGEXP = + "[0-9]{10}|(([0-9]{2}[-\\.\\s]){4})[0-9]{2}"; + + protected static Pattern p = Pattern.compile(PHONE_NUMBER_REGEXP); + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + + if (value == null) { + // no value defined + return; + } + if (value instanceof String) { + if ("".equals(value)) { + // no value defined + return; + } + Matcher m = p.matcher((String) value); + if (!m.matches()) { + addFieldError(fieldName, object); + } + } else { + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "frenchPhoneNumber"; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/FrenchPostCodeFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/FrenchPostCodeFieldValidator.java new file mode 100644 index 0000000..7555386 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/FrenchPostCodeFieldValidator.java @@ -0,0 +1,76 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Validate post codes for French cities + * <p/> + * - Take into account 2A and 2B + * - Take into account DOMs and TOMs + * - Postcodes starting with 99 are not valid + * + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class FrenchPostCodeFieldValidator extends NuitonFieldValidatorSupport { + + protected static String POST_CODE_REGEXP = + "^((0[1-9])|([1-8][0-9])|(9[0-8])|(2A)|(2B))[0-9]{3}$"; + + protected static Pattern p = Pattern.compile(POST_CODE_REGEXP); + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + + if (value == null) { + // no value defined + return; + } + if (value instanceof String) { + if ("".equals(value)) { + // no value defined + return; + } + Matcher m = p.matcher((String) value); + if (!m.matches()) { + addFieldError(fieldName, object); + } + } else { + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "frenchPostCode"; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidator.java new file mode 100644 index 0000000..cc495b4 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidator.java @@ -0,0 +1,176 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Validator for French SIRET numbers + * <p/> + * Siret can be in: + * <li>String format: "44211670300038" + * <li>long, int: 44211670300038 + * <li>Array or Collection of something: [4,4,2,1,1,6,7,0,,3,0,0,0,3,8] or ["442","116","703", "0003", "8"] + * + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + * Validation do the Luhn checksum too + */ +public class FrenchSiretFieldValidator extends NuitonFieldValidatorSupport { + + protected static final String SIRET_REGEXP = "[0-9]{14}"; + + protected static final Pattern p = Pattern.compile(SIRET_REGEXP); + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + + if (value == null) { + // no value defined + return; + } + String siret; + + if (value.getClass().isArray()) { + // le siret est stocker dans un tableau, par exemple un byte[] + siret = ""; + for (int i = 0; i < Array.getLength(value); i++) { + siret += String.valueOf(Array.get(value, i)); + } + } else if (value instanceof Collection<?>) { + // le siret est stocker dans une collection, + // ca doit pas arriver souvent :D, mais autant le gerer + siret = ""; + for (Object o : (Collection<?>) value) { + siret += String.valueOf(o); + } + } else { + // sinon dans tous les autres cas (String, int, long, BigInteger ...) + // on prend le toString + siret = String.valueOf(value); + } + + if (StringUtils.isEmpty(siret)) { + // no value defined + return; + } + + // Remove any space + siret = siret.replaceAll(" ", ""); + + Matcher m = p.matcher(siret); + if (!m.matches() || !luhnChecksum(siret)) { + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "frenchSiret"; + } + + /** + * Verifie la validite d'un numero en suivant l'algorithme Luhn tel que d'ecrit + * dans <a href="http://fr.wikipedia.org/wiki/Luhn">wikipedia</a> + * <p/> + * Algo: + * en fonction de la position du numero dans la sequence, + * on multiplie pas 1 (pour les impaires) ou par 2 pour les paires + * (1 etant le numero le plus a droite) + * On fait la somme de tous les chiffres qui resulte de ces multiplications + * (si un resultat etait 14, on ne fait pas +14 mais +1+4) + * <p/> + * Si le résultat de cette somme donne un reste de 0 une fois divisé par 10 + * le numero est valide. + * + * @param siret une chaine composer que de chiffre + * @return vrai si on a reussi a valider le numero + */ + public static boolean luhnChecksum(String siret) { + + char[] tab = siret.toCharArray(); + int sum = 0; + for (int i = tab.length - 1; i >= 0; i--) { + // recuperation de la valeur + int n = getDigit(tab[i]); + + // 1ere phase il faut faire la multiplication par 1 ou 2 + + // il faut faire x1 pour les paires et x2 sur les impaires. + // en prenant en compte que le numero siret le plus a droite est le + // 1 et le plus a gauche le 14. + // mais comme en informatique on commence a 0 :D + // il faut faire +1 sur l'indice puis un simple module 2 + 1 + // nous convient + n *= (i + 1) % 2 + 1; + + // 2eme phase il faut faire l'addition + + // si une fois multiplie il est superieur a 9, il faut additionner + // toutes ces constituante, mais comme il ne peut pas etre superieur + // a 18, cela revient a retrancher 9 + if (n > 9) { + n -= 9; + } + + // on peut directement faire la somme + sum += n; + } + + // 3eme phase on verifie que c'est bien un multiple de 10 + boolean result = sum % 10 == 0; + + return result; + } + + + /** + * Converti un char en un entier '0' => 0 et '9' => 9, et 'A' => 10 a 'Z' => 36, + * les autres caractere sont aussi convertis pour que 'a' = 10 et 'z' = 36. + * Pour les autres c'est un indedermine + * + * @param c le caractere qui doit etre converti + * @return le chiffre + */ + public static int getDigit(char c) { + int result = 0; + if (c >= '0' && c <= '9') { + result = c - '0'; + } else if (c >= 'A' && c <= 'Z') { + result = c - 'A' + 10; + } else { + result = c - 'a' + 10; + } + return result; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/NotExistingDirectoryFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/NotExistingDirectoryFieldValidator.java new file mode 100644 index 0000000..b65f731 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/NotExistingDirectoryFieldValidator.java @@ -0,0 +1,94 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; + +import java.io.File; + +/** + * <!-- START SNIPPET: javadoc --> + * NotExistingDirectoryFieldValidator checks that a File field as a directory does not exist. * + * <!-- END SNIPPET: javadoc --> + * <p/> + * <p/> + * <!-- START SNIPPET: parameters --> + * <ul> + * <li>fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required</li> + * </ul> + * <!-- END SNIPPET: parameters --> + * <p/> + * <p/> + * <pre> + * <!-- START SNIPPET: examples --> + * <validators> + * <!-- Plain-Validator Syntax --> + * <validator type="notExistingDirectory"> + * <param name="fieldName">tmp</param> + * <message>tmp is an existing directory</message> + * </validator> + * + * <!-- Field-Validator Syntax --> + * <field name="tmp"> + * <field-validator type="notExistingDirectory"> + * <message>tmp is an existing directory</message> + * </field-validator> + * </field> + * </validators> + * <!-- END SNIPPET: examples --> + * </pre> + * + * @author tchemit <chemit@codelutin.com> + */ +public class NotExistingDirectoryFieldValidator extends NuitonFieldValidatorSupport { + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + if (value == null) { + // no value defined + addFieldError(fieldName, object); + return; + } + File f; + if (value instanceof File) { + f = (File) value; + } else if (value instanceof String) { + f = new File((String) value); + } else { + addFieldError(fieldName, object); + return; + } + + if (f.exists() || f.isFile()) { + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "notExistingDirectory"; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/NotExistingFileFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/NotExistingFileFieldValidator.java new file mode 100644 index 0000000..f189e52 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/NotExistingFileFieldValidator.java @@ -0,0 +1,95 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; + +import java.io.File; + +/** + * <!-- START SNIPPET: javadoc --> + * NotExistingFileFieldValidator checks that a File field as a file does not exist. * + * <!-- END SNIPPET: javadoc --> + * <p/> + * <p/> + * <!-- START SNIPPET: parameters --> + * <ul> + * <li>fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required</li> + * </ul> + * <!-- END SNIPPET: parameters --> + * <p/> + * <p/> + * <pre> + * <!-- START SNIPPET: examples --> + * <validators> + * <!-- Plain-Validator Syntax --> + * <validator type="notExistingFile"> + * <param name="fieldName">tmp</param> + * <message>tmp is an existing file</message> + * </validator> + * + * <!-- Field-Validator Syntax --> + * <field name="tmp"> + * <field-validator type="notExistingFile"> + * <message>tmp is an existing file</message> + * </field-validator> + * </field> + * </validators> + * <!-- END SNIPPET: examples --> + * </pre> + * + * @author tchemit <chemit@codelutin.com> + */ +public class NotExistingFileFieldValidator extends NuitonFieldValidatorSupport { + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + if (value == null) { + // no value defined + addFieldError(fieldName, object); + return; + } + File f; + if (value instanceof File) { + f = (File) value; + } else if (value instanceof String) { + f = new File((String) value); + } else { + addFieldError(fieldName, object); + return; + } + + if (f.exists() || f.isDirectory()) { + // f is not a file and exist + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "notExistingFile"; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/NuitonFieldExpressionValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/NuitonFieldExpressionValidator.java new file mode 100644 index 0000000..971f6b2 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/NuitonFieldExpressionValidator.java @@ -0,0 +1,136 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.validators.FieldExpressionValidator; + +/** + * Nuiton default field validator. + * <p/> + * This validator offers a {@link #skip} property that can be used to skip or + * not the validator, this property is a OGNL expression. + * <p/> + * To use this new field validator support, just now implements the method + * {@link #validateWhenNotSkip(Object)}. This method will be invoked only if the skip + * parameter is evaluated to {@code false}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.3 + */ +public class NuitonFieldExpressionValidator extends FieldExpressionValidator { + + /** + * extra parameter at the very beginning of the + * {@link #validate(Object)} method to be able to skip (or not) the + * validator execution. + * <p/> + * by default the value is {@code false} : it seems fair to want to + * validate if the validator is used :D... + */ + protected String skip = "false"; + + /** + * Sets the value of the {@link #skip} parameter. + * + * @param skip the new value of the {@link #skip} parameter + */ + public void setSkip(String skip) { + this.skip = skip; + } + + /** + * Method to be invoked when skip parameter was not evaludated to {@code true}. + * + * @param object the object to be validated. + * @throws ValidationException is thrown if there is validation error(s). + */ + + protected void validateWhenNotSkip(Object object) throws ValidationException { + super.validate(object); + } + + @Override + public void validate(Object object) throws ValidationException { + + // evaluate the skip parameter + boolean mustSkip = evaluateSkipParameter(object); + + if (mustSkip) { + + // skip is set to true, so skip the validation + if (log.isDebugEnabled()) { + log.debug("Skip the validation from " + this + + ", due to skip parameter evaluated to true"); + } + return; + } + + // must validate + validateWhenNotSkip(object); + } + + /** + * Evaluate the skip parameter value against the object to validate. + * <p/> + * This parameter can be an OGNL expression. + * + * @param object the object to validate + * @return the evaluation of the skip parameter. + * @throws ValidationException if could not evaluate the parameter + */ + protected boolean evaluateSkipParameter(Object object) throws ValidationException { + + skip = skip.trim(); + + if ("false".equals(skip)) { + + return false; + } + + if ("true".equals(skip)) { + + return true; + } + + try { + Boolean answer = Boolean.FALSE; + Object obj; + obj = getFieldValue(skip, object); + if (obj != null && obj instanceof Boolean) { + answer = (Boolean) obj; + } + return answer; + } catch (ValidationException e) { + throw e; + } catch (Exception e) { + // let this pass, but it will be logged right below + throw new ValidationException( + "Can not evaluate boolean expression [" + skip + + "] for reason " + e.getMessage()); + } + + } + +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/NuitonFieldValidatorSupport.java b/src/main/java/org/nuiton/validator/xwork2/field/NuitonFieldValidatorSupport.java new file mode 100644 index 0000000..a486686 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/NuitonFieldValidatorSupport.java @@ -0,0 +1,139 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport; + +/** + * Nuiton default field validator. + * <p/> + * This validator offers a {@link #skip} property that can be used to skip or + * not the validator, this property is a OGNL expression. + * <p/> + * To use this new field validator support, just now implements the method + * {@link #validateWhenNotSkip(Object)}. This method will be invoked only if the skip + * parameter is evaluated to {@code false}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.3 + */ +public abstract class NuitonFieldValidatorSupport extends FieldValidatorSupport { + + /** + * extra parameter at the very beginning of the + * {@link #validate(Object)} method to be able to skip (or not) the + * validator execution. + * <p/> + * by default the value is {@code false} : it seems fair to want to + * validate if the validator is used :D... + */ + protected String skip = "false"; + + /** + * Sets the value of the {@link #skip} parameter. + * + * @param skip the new value of the {@link #skip} parameter + */ + public void setSkip(String skip) { + this.skip = skip; + } + + /** + * Method to be invoked when skip parameter was not evaludated to {@code true}. + * + * @param object the object to be validated. + * @throws ValidationException is thrown if there is validation error(s). + */ + + protected abstract void validateWhenNotSkip(Object object) throws ValidationException; + + @Override + public void validate(Object object) throws ValidationException { + + // evaluate the skip parameter + boolean mustSkip = evaluateSkipParameter(object); + + if (mustSkip) { + + // skip is set to true, so skip the validation + if (log.isDebugEnabled()) { + log.debug("Skip the validation from " + this + + ", due to skip parameter evaluated to true"); + } + return; + } + + // must validate + validateWhenNotSkip(object); + } + + /** + * Evaluate the skip parameter value against the object to validate. + * <p/> + * This parameter can be an OGNL expression. + * + * @param object the object to validate + * @return the evaluation of the skip parameter. + * @throws ValidationException if could not evaluate the parameter + */ + protected boolean evaluateSkipParameter(Object object) throws ValidationException { + + skip = skip.trim(); + + if ("false".equals(skip)) { + + return false; + } + + if ("true".equals(skip)) { + + return true; + } + + try { + Boolean answer = Boolean.FALSE; + Object obj; + obj = getFieldValue(skip, object); + if (obj != null && obj instanceof Boolean) { + answer = (Boolean) obj; + } + return answer; + } catch (ValidationException e) { + throw e; + } catch (Exception e) { + // let this pass, but it will be logged right below + throw new ValidationException( + "Can not evaluate boolean expression [" + skip + + "] for reason " + e.getMessage()); + } + + } + + @Override + public Object getFieldValue(String name, + Object object) throws ValidationException { + return super.getFieldValue(name, object); + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/RequiredFileFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/RequiredFileFieldValidator.java new file mode 100644 index 0000000..a6135ae --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/RequiredFileFieldValidator.java @@ -0,0 +1,95 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; + +import java.io.File; + +/** + * <!-- START SNIPPET: javadoc --> + * RequiredFileFieldValidator checks that a File field is not null nor have an empty filename. + * <!-- END SNIPPET: javadoc --> + * <p/> + * <p/> + * <!-- START SNIPPET: parameters --> + * <ul> + * <li>fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required</li> + * </ul> + * <!-- END SNIPPET: parameters --> + * <p/> + * <p/> + * <pre> + * <!-- START SNIPPET: examples --> + * <validators> + * <!-- Plain-Validator Syntax --> + * <validator type="requiredFile"> + * <param name="fieldName">tmp</param> + * <message>tmp is required</message> + * </validator> + * + * <!-- Field-Validator Syntax --> + * <field name="tmp"> + * <field-validator type="requiredFile"> + * <message>tmp is required</message> + * </field-validator> + * </field> + * </validators> + * <!-- END SNIPPET: examples --> + * </pre> + * + * @author tchemit <chemit@codelutin.com> + */ +public class RequiredFileFieldValidator extends NuitonFieldValidatorSupport { + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + if (value == null) { + // no value defined + addFieldError(fieldName, object); + return; + } + File f; + if (value instanceof File) { + f = (File) value; + } else if (value instanceof String) { + f = new File((String) value); + } else { + addFieldError(fieldName, object); + return; + } + + if (f.getPath().trim().isEmpty()) { + // f is not a directory nor exists + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "requiredFile"; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/SkipableRequiredFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/SkipableRequiredFieldValidator.java new file mode 100644 index 0000000..c89a153 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/SkipableRequiredFieldValidator.java @@ -0,0 +1,43 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; + +/** + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class SkipableRequiredFieldValidator extends NuitonFieldValidatorSupport { + + @Override + protected void validateWhenNotSkip(Object object) throws ValidationException { + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + + if (value == null) { + addFieldError(fieldName, object); + } + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/SkipableRequiredStringFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/SkipableRequiredStringFieldValidator.java new file mode 100644 index 0000000..9564d51 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/SkipableRequiredStringFieldValidator.java @@ -0,0 +1,43 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; + +/** + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class SkipableRequiredStringFieldValidator extends NuitonFieldValidatorSupport { + + @Override + protected void validateWhenNotSkip(Object object) throws ValidationException { + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + + if (value == null || !(value instanceof String) || "".equals(value)) { + addFieldError(fieldName, object); + } + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/VATIdentificationNumberFieldValidator.java b/src/main/java/org/nuiton/validator/xwork2/field/VATIdentificationNumberFieldValidator.java new file mode 100644 index 0000000..68d8946 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/VATIdentificationNumberFieldValidator.java @@ -0,0 +1,78 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import com.opensymphony.xwork2.validator.ValidationException; +import org.apache.commons.lang3.StringUtils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Validator for EU VAT number. + * + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class VATIdentificationNumberFieldValidator extends NuitonFieldValidatorSupport { + + protected static String VAT_INTRA_REGEXP = "^(RO\\d{2,10}|GB\\d{5}|(ATU|DK|FI|HU|LU|MT|CZ|SI)\\d{8}|IE[A-Z\\d]{8}|(DE|BG|EE|EL|LT|BE0|PT|CZ)\\d{9}|CY\\d{8}[A-Z]|(ES|GB)[A-Z\\d]{9}|(BE0|PL|SK|CZ)\\d{10}|(FR|IT|LV)\\d{11}|(LT|SE)\\d{12}|(NL|GB)[A-Z\\d]{12})$"; + + protected static Pattern p = Pattern.compile(VAT_INTRA_REGEXP); + + @Override + public void validateWhenNotSkip(Object object) throws ValidationException { + + String fieldName = getFieldName(); + Object value = getFieldValue(fieldName, object); + + if (value == null) { + // no value defined + return; + } + if (value instanceof String) { + + String vatNumber = (String) value; + if (StringUtils.isEmpty(vatNumber)) { + // no value defined + return; + } + + // Remove any space + vatNumber = vatNumber.replaceAll(" ", ""); + + Matcher m = p.matcher(vatNumber); + if (!m.matches()) { + addFieldError(fieldName, object); + } + } else { + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "VATIdentificationNumber"; + } +} diff --git a/src/main/java/org/nuiton/validator/xwork2/field/package-info.java b/src/main/java/org/nuiton/validator/xwork2/field/package-info.java new file mode 100644 index 0000000..d788651 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/field/package-info.java @@ -0,0 +1,31 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +/** + * Package of extra xworks2 field validators. + * + * <strong>To be continued...</strong> + * + * @since 2.0 + */ +package org.nuiton.validator.xwork2.field; diff --git a/src/main/java/org/nuiton/validator/xwork2/package-info.java b/src/main/java/org/nuiton/validator/xwork2/package-info.java new file mode 100644 index 0000000..e45bb25 --- /dev/null +++ b/src/main/java/org/nuiton/validator/xwork2/package-info.java @@ -0,0 +1,31 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +/** + * Package of xworks2 implementation of the Nuiton-validator api. + * + * <strong>To be continued...</strong> + * + * @since 2.0 + */ +package org.nuiton.validator.xwork2; diff --git a/src/main/resources/META-INF/services/org.nuiton.validator.NuitonValidatorProvider b/src/main/resources/META-INF/services/org.nuiton.validator.NuitonValidatorProvider new file mode 100644 index 0000000..02c867d --- /dev/null +++ b/src/main/resources/META-INF/services/org.nuiton.validator.NuitonValidatorProvider @@ -0,0 +1 @@ +org.nuiton.validator.xwork2.XWork2NuitonValidatorProvider \ No newline at end of file diff --git a/src/main/resources/i18n/nuiton-validator_en_GB.properties b/src/main/resources/i18n/nuiton-validator_en_GB.properties new file mode 100644 index 0000000..5770128 --- /dev/null +++ b/src/main/resources/i18n/nuiton-validator_en_GB.properties @@ -0,0 +1,4 @@ +validator.scope.error.label=Error +validator.scope.fatal.label=Fatal error +validator.scope.info.label=Information +validator.scope.warning.label=Warning diff --git a/src/main/resources/i18n/nuiton-validator_es_ES.properties b/src/main/resources/i18n/nuiton-validator_es_ES.properties new file mode 100644 index 0000000..db00e32 --- /dev/null +++ b/src/main/resources/i18n/nuiton-validator_es_ES.properties @@ -0,0 +1,4 @@ +validator.scope.error.label=Error +validator.scope.fatal.label=Fatal Error +validator.scope.info.label=Información +validator.scope.warning.label=Advertencias diff --git a/src/main/resources/i18n/nuiton-validator_fr_FR.properties b/src/main/resources/i18n/nuiton-validator_fr_FR.properties new file mode 100644 index 0000000..eccfedd --- /dev/null +++ b/src/main/resources/i18n/nuiton-validator_fr_FR.properties @@ -0,0 +1,4 @@ +validator.scope.error.label=Erreur +validator.scope.fatal.label=Erreur fatale +validator.scope.info.label=Information +validator.scope.warning.label=Avertissement diff --git a/src/site/apt/index.apt b/src/site/apt/index.apt new file mode 100644 index 0000000..1ae8431 --- /dev/null +++ b/src/site/apt/index.apt @@ -0,0 +1,98 @@ +~~~ +~~ #%L +~~ Nuiton Validator +~~ $Id$ +~~ $HeadURL$ +~~ %% +~~ Copyright (C) 2011 CodeLutin +~~ %% +~~ This program 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 3 of the +~~ License, or (at your option) any later version. +~~ +~~ This program 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 General Lesser Public License for more details. +~~ +~~ You should have received a copy of the GNU General Lesser Public +~~ License along with this program. If not, see +~~ <http://www.gnu.org/licenses/lgpl-3.0.html>. +~~ #L% +~~~ + ---- + Nuiton Validator + ---- + ---- + 2011-01-27 + ---- + + + +Présentation + + La librairie <Nuiton-validator> propose une api neutre de validation intégrant + la notion de niveau de validation. + +Note + + <<Nuiton-validator>> quitte le projet <nuiton-utils> pour devenir un projet autonome. + + Voici quelques liens sur le nouveau projet: + + * {{{http://svn.nuiton.org/svn/nuiton-validator}svn}} + + * {{{http://nuiton.org/projects/nuiton-validator}forge}} + + * {{{http://maven-site.nuiton.org/nuiton-validator}site}} + + [] + + A noter que le GAV de l'artefact ne change pas (<org.nuiton:nuiton-validator>). + + La dernière version stable dans nuiton-utils est la 2.7; vous pouvez dès à + présent utiliser la version 3.0-alpha-1 de nuiton-validator. + + Pour plus de détails sur les changements importants entre chaque version, + vous pouvez consulter les {{{./versions.html}Notes de versions}}. + +Implantation (xwork2) + + Actuellement la seule implantation disponible se base sur XWork2. + +* Configuration + + La configuration des validateurs se font via des fichier xml. + +* Ajout d'un validateur + + Pour enregister un nouveau validateur sur un bean, il suffit de placer dans + le même paquetage que le bean un fichier <XXX[-context]-scope-validation.xml> où + XXX est le nom non qualifié du bean. + + Le context optionel permet de définir plusieurs contexts de validation. + + Le scope parmi les suivants : fatal, error, warning, info donne le niveau de + validation. + +* Ajout d'un nouveau type de validateur + + Il est aussi possible de définir de nouveau type de validateurs : + + * créer une classe qui étend FieldValidator + + * ajouter un fichier <validators.xml> (ou ajouter dans un tel fichier la + définition du nouveau validator) à la racine du class-path. + +* I18n + + Afin de rendre le mécanisme multi-langue, on propose dans les fichiers de + validations d'utiliser des clef i18n pour les messages. + + Un nouveau parseur dans notre plugin i18n a été ajouté pour détecter ces + clefs. (<i18n:parserValidation>) + + + <Veuillez consulter la JavaDoc pour de plus ample détails sur les différentes + librairies.> diff --git a/src/site/apt/versions.apt b/src/site/apt/versions.apt new file mode 100644 index 0000000..88f986b --- /dev/null +++ b/src/site/apt/versions.apt @@ -0,0 +1,33 @@ +~~~ +~~ #%L +~~ Nuiton Config +~~ $Id$ +~~ $HeadURL$ +~~ %% +~~ Copyright (C) 2013 CodeLutin +~~ %% +~~ This program 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 3 of the +~~ License, or (at your option) any later version. +~~ +~~ This program 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 General Lesser Public License for more details. +~~ +~~ You should have received a copy of the GNU General Lesser Public +~~ License along with this program. If not, see +~~ <http://www.gnu.org/licenses/lgpl-3.0.html>. +~~ #L% +~~~ + ---- + Nuiton config + ---- + ---- + 2013-07-23 + ---- + +Utilisation de la version 3.0 + + * Pas de migration (pour le moment). \ No newline at end of file diff --git a/src/site/site_fr.xml b/src/site/site_fr.xml new file mode 100644 index 0000000..8428c9e --- /dev/null +++ b/src/site/site_fr.xml @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2013 CodeLutin + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> + + +<project name="${project.name}"> + + <skin> + <groupId>org.apache.maven.skins</groupId> + <artifactId>maven-fluido-skin</artifactId> + <version>1.3.0</version> + </skin> + + <custom> + <fluidoSkin> + <topBarEnabled>false</topBarEnabled> + <googleSearch/> + <sideBarEnabled>true</sideBarEnabled> + <searchEnabled>true</searchEnabled> + <sourceLineNumbersEnabled>true</sourceLineNumbersEnabled> + </fluidoSkin> + </custom> + + <bannerLeft> + <name>${project.name}</name> + <href>index.html</href> + </bannerLeft> + + <bannerRight> + <src>http://www.codelutin.com/images/lutinorange-codelutin.png</src> + <href>http://www.codelutin.com</href> + </bannerRight> + + <publishDate position="right" /> + <version position="right" /> + + <poweredBy> + + <logo href="http://maven.apache.org" name="Maven" + img="http://maven-site.chorem.org/public/images/logos/maven-feather.png"/> + + </poweredBy> + + <body> + + <head> + <script type="text/javascript" + src="http://maven-site.chorem.org/public/js/mavenpom-site.js"> + </script> + + <link rel="stylesheet" type="text/css" + href="http://maven-site.chorem.org/public/css/mavenpom-site.css"/> + </head> + + <links> + <item name="Nuiton.org" href="http://nuiton.org"/> + <item name="Code Lutin" href="http://www.codelutin.com"/> + <item name="Libre entreprise" href="http://www.libre-entreprise.org"/> + </links> + + <breadcrumbs> + <item name="${project.name}" + href="${project.url}/index.html"/> + </breadcrumbs> + + <menu name="Utilisateur"> + <item name="Accueil" href="index.html"/> + <item name="Note de versions" href="versions.html"/> + </menu> + + <menu ref="reports"/> + + <footer> + + <div id='projectMetas' + projectversion='${project.version}' + platform='${project.platform}' + projectid='${project.projectId}' + scm='${project.scm.developerConnection}' + scmwebeditorenabled='${project.scmwebeditorEnabled}' + scmwebeditorurl='${project.scmwebeditorUrl}' + siteSourcesType='${project.siteSourcesType}' + piwikEnabled='${project.piwikEnabled}' + piwikId='${project.piwikId}' locale='fr'> + </div> + </footer> + </body> +</project> diff --git a/src/test/java/org/nuiton/validator/AbstractValidatorDetectorTest.java b/src/test/java/org/nuiton/validator/AbstractValidatorDetectorTest.java new file mode 100644 index 0000000..b7f6d72 --- /dev/null +++ b/src/test/java/org/nuiton/validator/AbstractValidatorDetectorTest.java @@ -0,0 +1,159 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; + +import java.io.File; +import java.util.Iterator; +import java.util.SortedSet; +import java.util.regex.Pattern; + +/** + * Abstract test to detects and test your validators. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public abstract class AbstractValidatorDetectorTest { + + protected final String providerName; + + protected File rootDirectory; + + public AbstractValidatorDetectorTest(String providerName) { + this.providerName = providerName; + } + + protected NuitonValidatorProvider provider; + + protected abstract File getRootDirectory(File basedir); + + @Before + public void setUp() throws Exception { + provider = NuitonValidatorFactory.getProvider(providerName); + rootDirectory = getRootDirectory(ValidatorTestHelper.getBasedir()); + } + + @After + public void tearDown() throws Exception { + provider = null; + } + + protected SortedSet<NuitonValidator<?>> detectValidators(Class<?>... types) { + return detectValidators(null, NuitonValidatorScope.values(), types); + } + + protected SortedSet<NuitonValidator<?>> detectValidators(Pattern context, Class<?>... types) { + return detectValidators(context, NuitonValidatorScope.values(), types); + } + + protected SortedSet<NuitonValidator<?>> detectValidators(Pattern context, NuitonValidatorScope[] scopes, Class<?>... types) { + SortedSet<NuitonValidator<?>> validators = + provider.detectValidators(rootDirectory, context, scopes, types); + return validators; + } + + public void assertValidatorModel(NuitonValidator<?> validator, + String expectedContext, + Class<?> expectedType, + NuitonValidatorScope... expectedScopes) { + ValidatorTestHelper.assertValidatorModel( + validator, + expectedContext, + expectedType, + expectedScopes + ); + } + + public void assertValidatorEffectiveScopes(NuitonValidator<?> validator, + NuitonValidatorScope... expectedScopes) { + ValidatorTestHelper.assertValidatorEffectiveScopes(validator, + expectedScopes + ); + } + + public void assertValidatorEffectiveFields(NuitonValidator<?> validator, + String... expectedFields) { + + ValidatorTestHelper.assertValidatorEffectiveFields(validator, + expectedFields); + } + + public void assertValidatorEffectiveFields(NuitonValidator<?> validator, + NuitonValidatorScope scope, + String... expectedFields) { + ValidatorTestHelper.assertValidatorEffectiveFields(validator, + scope, + expectedFields); + } + + public void assertValidatorSetWithMultiContextName(SortedSet<NuitonValidator<?>> result, + Object... contextThenClass) { + + Assert.assertNotNull(result); + Assert.assertEquals(contextThenClass.length / 2, result.size()); + + Iterator<NuitonValidator<?>> itr = result.iterator(); + int index = 0; + + NuitonValidatorScope[] scopes = NuitonValidatorScope.values(); + + while (itr.hasNext()) { + NuitonValidator<?> next = itr.next(); + ValidatorTestHelper.assertValidatorModel(next, + (String) contextThenClass[2 * index], + (Class<?>) contextThenClass[2 * index + 1], + scopes); + index++; + } + + } + + public void assertValidatorSetWithSameContextName(SortedSet<NuitonValidator<?>> result, + String context, + Class<?>... contextThenClass) { + + Assert.assertNotNull(result); + Assert.assertEquals(contextThenClass.length, result.size()); + + Iterator<NuitonValidator<?>> itr = result.iterator(); + int index = 0; + + NuitonValidatorScope[] scopes = NuitonValidatorScope.values(); + + while (itr.hasNext()) { + NuitonValidator<?> next = itr.next(); + ValidatorTestHelper.assertValidatorModel(next, + context, + contextThenClass[index++], + scopes); + } + + } + + +} diff --git a/src/test/java/org/nuiton/validator/NuitonValidatorFactoryTest.java b/src/test/java/org/nuiton/validator/NuitonValidatorFactoryTest.java new file mode 100644 index 0000000..232c338 --- /dev/null +++ b/src/test/java/org/nuiton/validator/NuitonValidatorFactoryTest.java @@ -0,0 +1,59 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator; + +import org.junit.Assert; +import org.junit.Test; +import org.nuiton.validator.model.Person; +import org.nuiton.validator.xwork2.XWork2NuitonValidatorProvider; + +import java.util.Map; + +/** + * To test {@link NuitonValidatorFactory}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class NuitonValidatorFactoryTest { + + @Test + public void testGetProviders() throws Exception { + Map<String, NuitonValidatorProvider> providers = NuitonValidatorFactory.getProviders(); + Assert.assertNotNull(providers); + Assert.assertEquals(1, providers.size()); + Assert.assertTrue(providers.containsKey(XWork2NuitonValidatorProvider.PROVIDER_NAME)); + Assert.assertTrue(providers.get(XWork2NuitonValidatorProvider.PROVIDER_NAME) instanceof XWork2NuitonValidatorProvider); + } + + @Test + public void testNewValidator() throws Exception { + + NuitonValidator<Person> validator = + NuitonValidatorFactory.newValidator(Person.class); + + ValidatorTestHelper.testPerson(validator); + } + +} diff --git a/src/test/java/org/nuiton/validator/ValidatorTestHelper.java b/src/test/java/org/nuiton/validator/ValidatorTestHelper.java new file mode 100644 index 0000000..0556e9f --- /dev/null +++ b/src/test/java/org/nuiton/validator/ValidatorTestHelper.java @@ -0,0 +1,173 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator; + +import org.junit.Assert; +import org.nuiton.validator.model.Person; +import org.nuiton.validator.model.Pet; + +import java.io.File; +import java.util.List; +import java.util.Set; + +/** + * Helper methods to test the validator api. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class ValidatorTestHelper { + + public static File getBasedir() { + + // Search basedir from maven environment + String basedirPath = System.getenv("basedir"); + if (basedirPath == null) { + + // hope the tests are running from the root of the module :) + basedirPath = new File("").getAbsolutePath(); + } + return new File(basedirPath); + } + + public static void assertValidatorModel(NuitonValidator<?> validator, + String expectedContext, + Class<?> expectedType, + NuitonValidatorScope... expectedScopes) { + Assert.assertNotNull(validator); + NuitonValidatorModel<?> model = validator.getModel(); + Assert.assertNotNull(model); + Assert.assertEquals(expectedContext, model.getContext()); + Assert.assertEquals(expectedType, model.getType()); + Set<NuitonValidatorScope> scopes = model.getScopes(); + for (NuitonValidatorScope expectedScope : expectedScopes) { + Assert.assertTrue(scopes.contains(expectedScope)); + } + } + + public static void assertValidatorEffectiveScopes(NuitonValidator<?> validator, + NuitonValidatorScope... expectedScopes) { + Assert.assertNotNull(validator); + Set<NuitonValidatorScope> effectiveScopes = validator.getEffectiveScopes(); + Assert.assertEquals(expectedScopes.length, effectiveScopes.size()); + for (NuitonValidatorScope expectedScope : expectedScopes) { + Assert.assertTrue(effectiveScopes.contains(expectedScope)); + } + } + + public static void assertValidatorEffectiveFields(NuitonValidator<?> validator, + String... expectedFields) { + Assert.assertNotNull(validator); + Set<String> effectiveFields = validator.getEffectiveFields(); + Assert.assertEquals(expectedFields.length, effectiveFields.size()); + for (String expectedField : expectedFields) { + Assert.assertTrue(effectiveFields.contains(expectedField)); + } + } + + public static void assertValidatorEffectiveFields(NuitonValidator<?> validator, + NuitonValidatorScope scope, + String... expectedFields) { + Assert.assertNotNull(validator); + Set<String> effectiveFields = validator.getEffectiveFields(scope); + Assert.assertEquals(expectedFields.length, effectiveFields.size()); + for (String expectedField : expectedFields) { + Assert.assertTrue(effectiveFields.contains(expectedField)); + } + } + + public static void testPerson(NuitonValidator<Person> validator) { + Assert.assertNotNull(validator); + + Person person = new Person(); + + NuitonValidatorResult result; + + result = validator.validate(person); + + // two errors : no name, no firstname + // one warning : no pet + Assert.assertFalse(result.isValid()); + assertFieldMessages(result, NuitonValidatorScope.ERROR, Person.PROPERTY_FIRSTNAME, "person.firstname.required"); + assertFieldMessages(result, NuitonValidatorScope.ERROR, Person.PROPERTY_NAME, "person.name.required"); + assertFieldMessages(result, NuitonValidatorScope.WARNING, Person.PROPERTY_PET, "person.with.no.pet"); + + person.setFirstname("Joe"); + result = validator.validate(person); + + // one error : no name + // one warning : no pet + Assert.assertFalse(result.isValid()); + assertFieldMessages(result, NuitonValidatorScope.ERROR, Person.PROPERTY_FIRSTNAME); + assertFieldMessages(result, NuitonValidatorScope.ERROR, Person.PROPERTY_NAME, "person.name.required"); + assertFieldMessages(result, NuitonValidatorScope.WARNING, Person.PROPERTY_PET, "person.with.no.pet"); + + person.setName("Black"); + result = validator.validate(person); + + // no error + // one warning : no pet + Assert.assertTrue(result.isValid()); + assertFieldMessages(result, NuitonValidatorScope.ERROR, Person.PROPERTY_FIRSTNAME); + assertFieldMessages(result, NuitonValidatorScope.ERROR, Person.PROPERTY_NAME); + assertFieldMessages(result, NuitonValidatorScope.WARNING, Person.PROPERTY_PET, "person.with.no.pet"); + + person.addPet(new Pet()); + result = validator.validate(person); + + // no error + // no warning + Assert.assertTrue(result.isValid()); + assertFieldMessages(result, NuitonValidatorScope.ERROR, Person.PROPERTY_FIRSTNAME); + assertFieldMessages(result, NuitonValidatorScope.ERROR, Person.PROPERTY_NAME); + assertFieldMessages(result, NuitonValidatorScope.WARNING, Person.PROPERTY_PET); + + } + + public static void assertFieldMessages(NuitonValidatorResult result, + NuitonValidatorScope scope, + String field, + String... expectedMessages) { + + if (expectedMessages.length == 0) { + + // no messages + boolean hasMessages = result.hasMessagesForScope(field, scope); + Assert.assertFalse(hasMessages); + + } else { + + // with messages + boolean hasMessages = result.hasMessagesForScope(field, scope); + Assert.assertTrue(hasMessages); + + List<String> messages = result.getMessagesForScope(field, scope); + Assert.assertNotNull(hasMessages); + Assert.assertEquals(expectedMessages.length, messages.size()); + for (String expectedMessage : expectedMessages) { + Assert.assertTrue(messages.contains(expectedMessage)); + } + } + } +} diff --git a/src/test/java/org/nuiton/validator/bean/SimpleBean.java b/src/test/java/org/nuiton/validator/bean/SimpleBean.java new file mode 100644 index 0000000..d2568d2 --- /dev/null +++ b/src/test/java/org/nuiton/validator/bean/SimpleBean.java @@ -0,0 +1,78 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.bean; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +public class SimpleBean { + + protected int intValue; + + protected String stringValue; + + final PropertyChangeSupport p; + + public SimpleBean() { + p = new PropertyChangeSupport(this); + } + + public int getIntValue() { + return intValue; + } + + public String getStringValue() { + return stringValue; + } + + public void setStringValue(String stringValue) { + String old = this.stringValue; + this.stringValue = stringValue; + p.firePropertyChange("stringValue", old, stringValue); + } + + public void setIntValue(int intValue) { + int old = this.intValue; + this.intValue = intValue; + p.firePropertyChange("intValue", old, intValue); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + p.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, + PropertyChangeListener listener) { + p.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + p.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, + PropertyChangeListener listener) { + p.removePropertyChangeListener(propertyName, listener); + } +} diff --git a/src/test/java/org/nuiton/validator/bean/list/BeanListValidatorTest.java b/src/test/java/org/nuiton/validator/bean/list/BeanListValidatorTest.java new file mode 100644 index 0000000..6aad00e --- /dev/null +++ b/src/test/java/org/nuiton/validator/bean/list/BeanListValidatorTest.java @@ -0,0 +1,528 @@ +package org.nuiton.validator.bean.list; +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 - 2012 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import com.google.common.collect.ArrayListMultimap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.nuiton.validator.NuitonValidatorScope; +import org.nuiton.validator.bean.SimpleBean; + +import java.util.Arrays; +import java.util.List; + +/** + * To test the {@link BeanListValidator}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public class BeanListValidatorTest { + + /** Logger */ + private static final Log log = + LogFactory.getLog(BeanListValidatorTest.class); + + protected BeanListValidator<SimpleBean> validator; + + protected SimpleBean bean; + + protected SimpleBean bean2; + + BeanValidatorListenerImpl fatalListener; + + BeanValidatorListenerImpl errorListener; + + BeanValidatorListenerImpl warningListener; + + BeanValidatorListenerImpl infoListener; + + @Before + public void setUp() { + + bean = new SimpleBean(); + bean2 = new SimpleBean(); + } + + protected void prepareValidator(String context) { + + validator = BeanListValidator.newValidator(SimpleBean.class, context); + + validator.addBeanListValidatorListener(fatalListener = new BeanValidatorListenerImpl(NuitonValidatorScope.FATAL)); + validator.addBeanListValidatorListener(errorListener = new BeanValidatorListenerImpl(NuitonValidatorScope.ERROR)); + validator.addBeanListValidatorListener(warningListener = new BeanValidatorListenerImpl(NuitonValidatorScope.WARNING)); + validator.addBeanListValidatorListener(infoListener = new BeanValidatorListenerImpl(NuitonValidatorScope.INFO)); + } + + @After + public void tearDown() { + bean = null; + bean2 = null; + if (validator != null) { + validator.removeAllBeans(); + validator = null; + } + } + + private static final String STRING_VALUE_FATAL = "stringValue.fatal"; + + private static final String STRING_VALUE_ERROR = "stringValue.error"; + + private static final String STRING_VALUE_WARNING = "stringValue.warning"; + + private static final String INT_VALUE_FATAL = "intValue.fatal"; + + private static final String INT_VALUE_ERROR = "intValue.error"; + + private static final String INT_VALUE_INFO = "intValue.info"; + + @Test(expected = IllegalStateException.class) + public void testValidateWithBad() { + + // with marchepo context, there is a unknown field in scope error + + prepareValidator("marchepo"); + } + + @Test + public void addBean() { + prepareValidator(null); + + assertMessages(fatalListener, bean); + assertMessages(errorListener, bean); + assertMessages(warningListener, bean); + assertMessages(infoListener, bean); + + validator.addBean(bean); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + validator.addBean(bean2); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + assertMessages(fatalListener, bean2, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean2, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean2, STRING_VALUE_WARNING); + assertMessages(infoListener, bean2, INT_VALUE_INFO); + + } + + @Test + public void addAllBean() { + prepareValidator(null); + + assertMessages(fatalListener, bean); + assertMessages(errorListener, bean); + assertMessages(warningListener, bean); + assertMessages(infoListener, bean); + + assertMessages(fatalListener, bean2); + assertMessages(errorListener, bean2); + assertMessages(warningListener, bean2); + assertMessages(infoListener, bean2); + + validator.addAllBeans(Arrays.asList(bean, bean2)); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + assertMessages(fatalListener, bean2, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean2, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean2, STRING_VALUE_WARNING); + assertMessages(infoListener, bean2, INT_VALUE_INFO); + + } + + @Test + public void removeBean() { + prepareValidator(null); + + assertMessages(fatalListener, bean); + assertMessages(errorListener, bean); + assertMessages(warningListener, bean); + assertMessages(infoListener, bean); + + assertMessages(fatalListener, bean2); + assertMessages(errorListener, bean2); + assertMessages(warningListener, bean2); + assertMessages(infoListener, bean2); + + validator.addBean(bean); + validator.addBean(bean2); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + assertMessages(fatalListener, bean2, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean2, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean2, STRING_VALUE_WARNING); + assertMessages(infoListener, bean2, INT_VALUE_INFO); + + validator.removeBean(bean); + + assertMessages(fatalListener, bean); + assertMessages(errorListener, bean); + assertMessages(warningListener, bean); + assertMessages(infoListener, bean); + + validator.removeBean(bean2); + + assertMessages(fatalListener, bean2); + assertMessages(errorListener, bean2); + assertMessages(warningListener, bean2); + assertMessages(infoListener, bean2); + } + + @Test + public void removeAllBeans() { + prepareValidator(null); + + assertMessages(fatalListener, bean); + assertMessages(errorListener, bean); + assertMessages(warningListener, bean); + assertMessages(infoListener, bean); + + assertMessages(fatalListener, bean2); + assertMessages(errorListener, bean2); + assertMessages(warningListener, bean2); + assertMessages(infoListener, bean2); + + validator.addBean(bean); + validator.addBean(bean2); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + assertMessages(fatalListener, bean2, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean2, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean2, STRING_VALUE_WARNING); + assertMessages(infoListener, bean2, INT_VALUE_INFO); + + validator.removeAllBeans(Arrays.asList(bean, bean2)); + + assertMessages(fatalListener, bean); + assertMessages(errorListener, bean); + assertMessages(warningListener, bean); + assertMessages(infoListener, bean); + + assertMessages(fatalListener, bean2); + assertMessages(errorListener, bean2); + assertMessages(warningListener, bean2); + assertMessages(infoListener, bean2); + } + + @Test + public void removeAllBeans2() { + prepareValidator(null); + + assertMessages(fatalListener, bean); + assertMessages(errorListener, bean); + assertMessages(warningListener, bean); + assertMessages(infoListener, bean); + + assertMessages(fatalListener, bean2); + assertMessages(errorListener, bean2); + assertMessages(warningListener, bean2); + assertMessages(infoListener, bean2); + + validator.addBean(bean); + validator.addBean(bean2); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + assertMessages(fatalListener, bean2, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean2, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean2, STRING_VALUE_WARNING); + assertMessages(infoListener, bean2, INT_VALUE_INFO); + + validator.removeAllBeans(); + + assertMessages(fatalListener, bean); + assertMessages(errorListener, bean); + assertMessages(warningListener, bean); + assertMessages(infoListener, bean); + + assertMessages(fatalListener, bean2); + assertMessages(errorListener, bean2); + assertMessages(warningListener, bean2); + assertMessages(infoListener, bean2); + } + + @Test + public void validate() { + + prepareValidator(null); + + assertMessages(fatalListener, bean); + assertMessages(errorListener, bean); + assertMessages(warningListener, bean); + assertMessages(infoListener, bean); + + if (log.isDebugEnabled()) { + log.debug("- bean 1 ----------------------------------------------"); + } + validator.addBean(bean); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("- bean 1 ----------------------------------------------"); + } + bean.setStringValue("one"); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, INT_VALUE_ERROR); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("- bean 1 ----------------------------------------------"); + } + bean.setStringValue("oneone"); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, INT_VALUE_ERROR); + assertMessages(warningListener, bean); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("- bean 1 ----------------------------------------------"); + } + bean.setIntValue(1); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean); + assertMessages(warningListener, bean); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("- bean 1 ----------------------------------------------"); + } + bean.setIntValue(10); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean); + assertMessages(warningListener, bean); + assertMessages(infoListener, bean); + + if (log.isDebugEnabled()) { + log.debug("- bean 1 ----------------------------------------------"); + } + + bean.setStringValue(null); + bean.setIntValue(0); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + + if (log.isDebugEnabled()) { + log.debug("- bean 1 ----------------------------------------------"); + } + + bean.setStringValue("5"); + bean.setIntValue(5); + assertMessages(fatalListener, bean); + assertMessages(errorListener, bean); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("- bean 2 ----------------------------------------------"); + } + validator.addBean(bean2); + + assertMessages(fatalListener, bean2, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean2, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean2, STRING_VALUE_WARNING); + assertMessages(infoListener, bean2, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("- bean 2 ----------------------------------------------"); + } + bean2.setStringValue("one"); + + assertMessages(fatalListener, bean2, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean2, INT_VALUE_ERROR); + assertMessages(warningListener, bean2, STRING_VALUE_WARNING); + assertMessages(infoListener, bean2, INT_VALUE_INFO); + + } + + @Test + public void convert() { + + prepareValidator(null); + + assertMessages(errorListener, bean); + assertMessages(warningListener, bean); + assertMessages(infoListener, bean); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + + validator.addBean(bean); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + + Object value = validator.convert(bean, "intValue", "abc", Class.class); + + Assert.assertNull(value); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, STRING_VALUE_ERROR, "error.convertor.class"); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + bean.setStringValue("one"); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, "error.convertor.class"); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + + value = validator.convert(bean, "intValue", "3", Integer.class); + + bean.setIntValue((Integer) value); + + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + + bean.setIntValue(-1); + assertMessages(fatalListener, bean, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, bean, INT_VALUE_ERROR); + assertMessages(warningListener, bean, STRING_VALUE_WARNING); + assertMessages(infoListener, bean, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + } + + void assertMessages(BeanValidatorListenerImpl listener, + Object bean, + String... expected) { + List<String> actual = listener.getMessages(bean); + Assert.assertEquals(" shoudl have " + + Arrays.toString(expected) + " but had " + actual, + expected.length, actual.size()); + for (String m : expected) { + Assert.assertEquals("could not find " + m + " in " + actual, + true, actual.contains(m)); + } + } + + class BeanValidatorListenerImpl implements BeanListValidatorListener { + + private final NuitonValidatorScope scope; + + private final ArrayListMultimap<Object, String> messages; + + public BeanValidatorListenerImpl(NuitonValidatorScope scope) { + this.scope = scope; + messages = ArrayListMultimap.create(); + } + + + public ArrayListMultimap<Object, String> getMessages() { + return messages; + } + + public List<String> getMessages(Object bean) { + return messages.get(bean); + } + + + @Override + public void onFieldChanged(BeanListValidatorEvent event) { + if (scope != event.getScope()) { + return; + } + Object bean = event.getBean(); + String[] messagesToDelete = event.getMessagesToDelete(); + if (messagesToDelete != null && messagesToDelete.length > 0) { + if (log.isDebugEnabled()) { + log.debug(scope + "[" + bean + "] messages to delete : " + Arrays.toString(messagesToDelete)); + } + for (String m : messagesToDelete) { + messages.remove(bean, m); + } + } + String[] messagesToAdd = event.getMessagesToAdd(); + if (messagesToAdd != null && messagesToAdd.length > 0) { + if (log.isDebugEnabled()) { + log.debug(scope + "[" + bean + "] messages to add : " + Arrays.toString(messagesToAdd)); + } + messages.putAll(bean, Arrays.asList(messagesToAdd)); + } + } + } +} diff --git a/src/test/java/org/nuiton/validator/bean/simple/SimpleBeanValidatorTest.java b/src/test/java/org/nuiton/validator/bean/simple/SimpleBeanValidatorTest.java new file mode 100644 index 0000000..13bb37c --- /dev/null +++ b/src/test/java/org/nuiton/validator/bean/simple/SimpleBeanValidatorTest.java @@ -0,0 +1,313 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.bean.simple; + +import com.google.common.collect.Lists; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.nuiton.validator.NuitonValidatorScope; +import org.nuiton.validator.bean.SimpleBean; + +import java.util.Arrays; +import java.util.List; + +/** + * To test the {@link SimpleBeanValidator}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.5.2 + */ +public class SimpleBeanValidatorTest { + + /** Logger */ + private static final Log log = + LogFactory.getLog(SimpleBeanValidatorTest.class); + + protected SimpleBeanValidator<SimpleBean> validator; + + protected SimpleBean bean; + + ValidatorListenerImpl fatalListener; + + ValidatorListenerImpl errorListener; + + ValidatorListenerImpl warningListener; + + ValidatorListenerImpl infoListener; + + @Before + public void setUp() { + + bean = new SimpleBean(); + } + + protected void prepareValidator(String context) { + + validator = SimpleBeanValidator.newValidator(SimpleBean.class, context); + + validator.addSimpleBeanValidatorListener(fatalListener = new ValidatorListenerImpl(NuitonValidatorScope.FATAL)); + validator.addSimpleBeanValidatorListener(errorListener = new ValidatorListenerImpl(NuitonValidatorScope.ERROR)); + validator.addSimpleBeanValidatorListener(warningListener = new ValidatorListenerImpl(NuitonValidatorScope.WARNING)); + validator.addSimpleBeanValidatorListener(infoListener = new ValidatorListenerImpl(NuitonValidatorScope.INFO)); + } + + @After + public void tearDown() { + bean = null; + if (validator != null) { + validator.setBean(null); + validator = null; + } + } + + private static final String STRING_VALUE_FATAL = "stringValue.fatal"; + + private static final String STRING_VALUE_ERROR = "stringValue.error"; + + private static final String STRING_VALUE_WARNING = "stringValue.warning"; + + private static final String INT_VALUE_FATAL = "intValue.fatal"; + + private static final String INT_VALUE_ERROR = "intValue.error"; + + private static final String INT_VALUE_INFO = "intValue.info"; + + @Test(expected = IllegalStateException.class) + public void testValidateWithBad() { + + // with marchepo context, there is a unknown field in scope error + + prepareValidator("marchepo"); + } + + @Test + public void validate() { + + prepareValidator(null); + + assertMessages(fatalListener); + assertMessages(errorListener); + assertMessages(warningListener); + assertMessages(infoListener); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + validator.setBean(bean); + + assertMessages(fatalListener, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + bean.setStringValue("one"); + + assertMessages(fatalListener, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, INT_VALUE_ERROR); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + bean.setStringValue("oneone"); + + assertMessages(fatalListener, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, INT_VALUE_ERROR); + assertMessages(warningListener); + assertMessages(infoListener, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + bean.setIntValue(1); + + assertMessages(fatalListener, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener); + assertMessages(warningListener); + assertMessages(infoListener, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + bean.setIntValue(10); + + assertMessages(fatalListener, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener); + assertMessages(warningListener); + assertMessages(infoListener); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + + bean.setStringValue(null); + bean.setIntValue(0); + + assertMessages(fatalListener, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + + bean.setStringValue("5"); + bean.setIntValue(5); + assertMessages(fatalListener); + assertMessages(errorListener); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + } + + @Test + public void convert() { + + prepareValidator(null); + + assertMessages(errorListener); + assertMessages(warningListener); + assertMessages(infoListener); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + + validator.setBean(bean); + + assertMessages(fatalListener, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + + Object value = validator.convert("intValue", "abc", Class.class); + + Assert.assertNull(value); + + assertMessages(fatalListener, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, STRING_VALUE_ERROR, "error.convertor.class"); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + bean.setStringValue("one"); + + assertMessages(fatalListener, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, "error.convertor.class"); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + + value = validator.convert("intValue", "3", Integer.class); + + bean.setIntValue((Integer) value); + + assertMessages(fatalListener, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + + bean.setIntValue(-1); + assertMessages(fatalListener, STRING_VALUE_FATAL, INT_VALUE_FATAL); + assertMessages(errorListener, INT_VALUE_ERROR); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + if (log.isDebugEnabled()) { + log.debug("-----------------------------------------------"); + } + } + + void assertMessages(ValidatorListenerImpl listener, + String... expected) { + List<String> actual = listener.getMessages(); + Assert.assertEquals(" shoudl have " + + Arrays.toString(expected) + " but had " + actual, + expected.length, actual.size()); + for (String m : expected) { + Assert.assertEquals("could not find " + m + " in " + actual, + true, actual.contains(m)); + } + } + + static class ValidatorListenerImpl implements SimpleBeanValidatorListener { + + final NuitonValidatorScope scope; + + public ValidatorListenerImpl(NuitonValidatorScope scope) { + this.scope = scope; + } + + List<String> messages = Lists.newArrayList(); + + public List<String> getMessages() { + return messages; + } + + @Override + public void onFieldChanged(SimpleBeanValidatorEvent event) { + if (scope == event.getScope()) { + String[] messagesToDelete = event.getMessagesToDelete(); + if (messagesToDelete != null && messagesToDelete.length > 0) { + if (log.isDebugEnabled()) { + log.debug(event.getScope() + " messages to delete : " + Arrays.toString(messagesToDelete)); + } + for (String m : messagesToDelete) { + messages.remove(m); + } + } + String[] messagesToAdd = event.getMessagesToAdd(); + if (messagesToAdd != null && messagesToAdd.length > 0) { + if (log.isDebugEnabled()) { + log.debug(event.getScope() + " messages to add : " + Arrays.toString(messagesToAdd)); + } + messages.addAll(Arrays.asList(messagesToAdd)); + } + } + } + } +} diff --git a/src/test/java/org/nuiton/validator/model/Company.java b/src/test/java/org/nuiton/validator/model/Company.java new file mode 100644 index 0000000..75ab5da --- /dev/null +++ b/src/test/java/org/nuiton/validator/model/Company.java @@ -0,0 +1,55 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.model; + +/** + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class Company { + + public static final String PROPERTY_VAT_NUMBER = "vat"; + + public static final String PROPERTY_SIRET = "siret"; + + protected String vat; + + protected String siret; + + public String getVat() { + return vat; + } + + public void setVat(String vat) { + this.vat = vat; + } + + public String getSiret() { + return siret; + } + + public void setSiret(String siret) { + this.siret = siret; + } +} diff --git a/src/test/java/org/nuiton/validator/model/Contact.java b/src/test/java/org/nuiton/validator/model/Contact.java new file mode 100644 index 0000000..b0884ee --- /dev/null +++ b/src/test/java/org/nuiton/validator/model/Contact.java @@ -0,0 +1,91 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.model; + +/** + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class Contact { + + public static final String PROPERTY_LAST_NAME = "name"; + + public static final String PROPERTY_EMAIL = "email"; + + public static final String PROPERTY_PHONE = "phone"; + + public static final String PROPERTY_POSTCODE = "postCode"; + + public static final String PROPERTY_CITY = "city"; + + protected String name; + + protected String email; + + protected String phone; + + protected String postCode; + + protected String city; + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getPostCode() { + return postCode; + } + + public void setPostCode(String postCode) { + this.postCode = postCode; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/test/java/org/nuiton/validator/model/HealthEstablishment.java b/src/test/java/org/nuiton/validator/model/HealthEstablishment.java new file mode 100644 index 0000000..5d12c1d --- /dev/null +++ b/src/test/java/org/nuiton/validator/model/HealthEstablishment.java @@ -0,0 +1,44 @@ +package org.nuiton.validator.model; + +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2013 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +/** + * @author Sylvain Bavencoff <bavencoff@codelutin.com> + */ +public class HealthEstablishment { + + public static final String PROPERTY_FINESS = "finess"; + + protected String finess; + + public String getFiness() { + return finess; + } + + public void setFiness(String finess) { + this.finess = finess; + } + +} diff --git a/src/test/java/org/nuiton/validator/model/ModelValidatorDetectorTestImpl.java b/src/test/java/org/nuiton/validator/model/ModelValidatorDetectorTestImpl.java new file mode 100644 index 0000000..fc904ff --- /dev/null +++ b/src/test/java/org/nuiton/validator/model/ModelValidatorDetectorTestImpl.java @@ -0,0 +1,186 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.model; + +import org.junit.Assert; +import org.junit.Test; +import org.nuiton.validator.AbstractValidatorDetectorTest; +import org.nuiton.validator.NuitonValidator; +import org.nuiton.validator.NuitonValidatorScope; +import org.nuiton.validator.xwork2.XWork2NuitonValidatorProvider; + +import java.io.File; +import java.util.Iterator; +import java.util.SortedSet; +import java.util.regex.Pattern; + +/** + * Tests the validators defined for the test model. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class ModelValidatorDetectorTestImpl extends AbstractValidatorDetectorTest { + + public static final String CONTEXT = "context"; + + public ModelValidatorDetectorTestImpl() { + super(XWork2NuitonValidatorProvider.PROVIDER_NAME); + } + + @Override + protected File getRootDirectory(File basedir) { + File testResourcesDir = new File(basedir, "src" + File.separator + "test" + File.separator + "resources"); + return testResourcesDir; + } + + @Test + public void detectAllValidators() { + SortedSet<NuitonValidator<?>> result; + NuitonValidator<?> validator; + Iterator<NuitonValidator<?>> iterator; + + // test with all context and all scopes : 3 validators (Person + Pet + Pet (context)) + + result = detectValidators(Person.class, Pet.class); + + Assert.assertNotNull(result); + Assert.assertEquals(3, result.size()); + + iterator = result.iterator(); + validator = iterator.next(); + + assertValidatorModel(validator, null, Person.class, NuitonValidatorScope.values()); + assertValidatorEffectiveScopes(validator, NuitonValidatorScope.ERROR, NuitonValidatorScope.WARNING); + assertValidatorEffectiveFields(validator, NuitonValidatorScope.ERROR, Person.PROPERTY_NAME, Person.PROPERTY_FIRSTNAME); + assertValidatorEffectiveFields(validator, NuitonValidatorScope.WARNING, Person.PROPERTY_PET); + + validator = iterator.next(); + assertValidatorModel(validator, null, Pet.class, NuitonValidatorScope.values()); + assertValidatorEffectiveScopes(validator, NuitonValidatorScope.ERROR); + assertValidatorEffectiveFields(validator, NuitonValidatorScope.ERROR, Pet.PROPERTY_NAME); + + validator = iterator.next(); + assertValidatorModel(validator, CONTEXT, Pet.class, NuitonValidatorScope.values()); + assertValidatorEffectiveScopes(validator, NuitonValidatorScope.INFO); + assertValidatorEffectiveFields(validator, NuitonValidatorScope.INFO, Pet.PROPERTY_NAME); + } + + @Test + public void detectValidatorsWithFilteredScopes() { + + SortedSet<NuitonValidator<?>> result; + NuitonValidator<?> validator; + Iterator<NuitonValidator<?>> iterator; + + // test with no context and only scope warning : one validator (Person) + + result = detectValidators(null, new NuitonValidatorScope[]{NuitonValidatorScope.WARNING}, Person.class, Pet.class); + + Assert.assertNotNull(result); + Assert.assertEquals(1, result.size()); + + iterator = result.iterator(); + + validator = iterator.next(); + assertValidatorModel(validator, null, Person.class, NuitonValidatorScope.WARNING); + assertValidatorEffectiveScopes(validator, NuitonValidatorScope.WARNING); + assertValidatorEffectiveFields(validator, NuitonValidatorScope.WARNING, Person.PROPERTY_PET); + + // test with no context and only fatal scope : no validator + + result = detectValidators(null, + new NuitonValidatorScope[]{NuitonValidatorScope.FATAL}, Person.class, Pet.class); + + Assert.assertNotNull(result); + Assert.assertTrue(result.isEmpty()); + } + + @Test + public void detectValidatorsWithFilteredContext() { + + SortedSet<NuitonValidator<?>> result; + NuitonValidator<?> validator; + Iterator<NuitonValidator<?>> iterator; + + + // test with context 'context' and all scopes : one validator (Pet) + + result = detectValidators(Pattern.compile(CONTEXT), Person.class, Pet.class); + + Assert.assertNotNull(result); + Assert.assertEquals(1, result.size()); + + iterator = result.iterator(); + + validator = iterator.next(); + assertValidatorModel(validator, CONTEXT, Pet.class, NuitonValidatorScope.values()); + assertValidatorEffectiveScopes(validator, NuitonValidatorScope.INFO); + assertValidatorEffectiveFields(validator, NuitonValidatorScope.INFO, Pet.PROPERTY_NAME); + + + // test with specific context fake and all scopes : no validator + + result = detectValidators(Pattern.compile(".*-fake"), + Person.class, Pet.class); + + Assert.assertNotNull(result); + Assert.assertTrue(result.isEmpty()); + } + + @Test + public void detectValidatorsWithFilteredContextAndFilteredScope() { + + SortedSet<NuitonValidator<?>> result; + NuitonValidator<?> validator; + Iterator<NuitonValidator<?>> iterator; + + // test with context 'context' and info-fatal scopes : one validator (Pet) + + result = detectValidators(Pattern.compile(CONTEXT), + new NuitonValidatorScope[]{NuitonValidatorScope.INFO, NuitonValidatorScope.FATAL}, + Person.class, Pet.class); + + Assert.assertNotNull(result); + Assert.assertEquals(1, result.size()); + + iterator = result.iterator(); + + validator = iterator.next(); + assertValidatorModel(validator, CONTEXT, Pet.class, NuitonValidatorScope.FATAL, NuitonValidatorScope.INFO); + assertValidatorEffectiveScopes(validator, NuitonValidatorScope.INFO); + assertValidatorEffectiveFields(validator, NuitonValidatorScope.INFO, Pet.PROPERTY_NAME); + + // test with specific context fake and fatal scope : no validator + + result = detectValidators(Pattern.compile(".*-fake"), + new NuitonValidatorScope[]{NuitonValidatorScope.FATAL}, + Person.class, Pet.class); + + Assert.assertNotNull(result); + Assert.assertTrue(result.isEmpty()); + } + + +} diff --git a/src/test/java/org/nuiton/validator/model/Person.java b/src/test/java/org/nuiton/validator/model/Person.java new file mode 100644 index 0000000..da8deff --- /dev/null +++ b/src/test/java/org/nuiton/validator/model/Person.java @@ -0,0 +1,93 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.model; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * TODO + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class Person { + + public static final String PROPERTY_NAME = "name"; + + public static final String PROPERTY_FIRSTNAME = "firstname"; + + public static final String PROPERTY_PET = "pet"; + + protected String name; + + protected String firstname; + + protected Collection<Pet> pet; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public Collection<Pet> getPet() { + return pet; + } + + public void setPet(Collection<Pet> pet) { + this.pet = pet; + } + + public void addPet(Pet pet) { + if (this.pet == null) { + this.pet = new ArrayList<Pet>(); + } + + pet.setPerson(this); + + this.pet.add(pet); + } + + @Override + public String toString() { + String result = new ToStringBuilder(this). + append(PROPERTY_NAME, name). + append(PROPERTY_FIRSTNAME, firstname). + toString(); + return result; + } +} diff --git a/src/test/java/org/nuiton/validator/model/Pet.java b/src/test/java/org/nuiton/validator/model/Pet.java new file mode 100644 index 0000000..bc62879 --- /dev/null +++ b/src/test/java/org/nuiton/validator/model/Pet.java @@ -0,0 +1,98 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.model; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +/** + * TODO + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class Pet { + + public static final String PROPERTY_NAME = "name"; + + public static final String PROPERTY_TYPE = "type"; + + public static final String PROPERTY_PERSON = "person"; + + public static final String PROPERTY_RACE = "race"; + + protected String name; + + protected String type; + + protected Person person; + + protected Race race; + + + public void setName(String name) { + + this.name = name; + } + + public String getName() { + return name; + } + + public void setType(String type) { + this.type = type; + } + + + public String getType() { + return type; + } + + public void setPerson(Person person) { + this.person = person; + } + + + public Person getPerson() { + return person; + } + + public void setRace(Race race) { + this.race = race; + } + + public Race getRace() { + return race; + } + + @Override + public String toString() { + String result = new ToStringBuilder(this). + append(PROPERTY_NAME, this.name). + append(PROPERTY_TYPE, this.type). + append(PROPERTY_RACE, this.race). + toString(); + return result; + } + +} diff --git a/src/test/java/org/nuiton/validator/model/Race.java b/src/test/java/org/nuiton/validator/model/Race.java new file mode 100644 index 0000000..96ef660 --- /dev/null +++ b/src/test/java/org/nuiton/validator/model/Race.java @@ -0,0 +1,55 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.model; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +/** + * TODO + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class Race { + + public static final String PROPERTY_NAME = "name"; + + protected String name; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + String result = new ToStringBuilder(this). + append(PROPERTY_NAME, this.name). + toString(); + return result; + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/XWork2NuitonValidatorProviderTest.java b/src/test/java/org/nuiton/validator/xwork2/XWork2NuitonValidatorProviderTest.java new file mode 100644 index 0000000..0ed9e0d --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/XWork2NuitonValidatorProviderTest.java @@ -0,0 +1,167 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.nuiton.validator.NuitonValidator; +import org.nuiton.validator.NuitonValidatorModel; +import org.nuiton.validator.NuitonValidatorScope; +import org.nuiton.validator.ValidatorTestHelper; +import org.nuiton.validator.model.Person; +import org.nuiton.validator.model.Pet; + +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.SortedSet; +import java.util.regex.Pattern; + +/** + * To test {@link XWork2NuitonValidatorProvider}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class XWork2NuitonValidatorProviderTest { + + /** Logger. */ + private static final Log log = + LogFactory.getLog(XWork2NuitonValidatorProviderTest.class); + + protected XWork2NuitonValidatorProvider provider; + + @Before + public void setUp() { + provider = new XWork2NuitonValidatorProvider(); + } + + @Test + public void testGetModel() throws Exception { + + NuitonValidatorModel<Person> model = + provider.getModel(Person.class, null); + + Assert.assertNotNull(model); + Assert.assertNull(model.getContext()); + Assert.assertEquals(Person.class, model.getType()); + Set<NuitonValidatorScope> scopes = new HashSet<NuitonValidatorScope>( + Arrays.asList(NuitonValidatorScope.values())); + Assert.assertEquals(scopes, model.getScopes()); + } + + @Test + public void testNewValidator() throws Exception { + + + NuitonValidatorModel<Person> model = + provider.getModel(Person.class, null); + + NuitonValidator<Person> validator = provider.newValidator(model); + + Assert.assertNotNull(validator); + } + + @Test + public void testDetectValidators() { + + String context = "context"; + + File basedir = ValidatorTestHelper.getBasedir(); + File testResourcesDir = new File(basedir, "src" + File.separator + "test" + File.separator + "resources"); + + SortedSet<NuitonValidator<?>> result; + NuitonValidator<?> validator; + Iterator<NuitonValidator<?>> iterator; + + // test with all context and all scopes : two validators (Person + Pet + Pet (context)) + + result = provider.detectValidators(testResourcesDir, null, null, Person.class, Pet.class); + + Assert.assertNotNull(result); + Assert.assertEquals(3, result.size()); + + + iterator = result.iterator(); + validator = iterator.next(); + + ValidatorTestHelper.assertValidatorModel(validator, null, Person.class, NuitonValidatorScope.values()); + ValidatorTestHelper.assertValidatorEffectiveScopes(validator, NuitonValidatorScope.ERROR, NuitonValidatorScope.WARNING); + + validator = iterator.next(); + ValidatorTestHelper.assertValidatorModel(validator, null, Pet.class, NuitonValidatorScope.values()); + ValidatorTestHelper.assertValidatorEffectiveScopes(validator, NuitonValidatorScope.ERROR); + + validator = iterator.next(); + ValidatorTestHelper.assertValidatorModel(validator, context, Pet.class, NuitonValidatorScope.values()); + ValidatorTestHelper.assertValidatorEffectiveScopes(validator, NuitonValidatorScope.INFO); + + // test with no context and only scope warning : one validator (Person) + + result = provider.detectValidators(testResourcesDir, null, new NuitonValidatorScope[]{NuitonValidatorScope.WARNING}, Person.class, Pet.class); + + Assert.assertNotNull(result); + Assert.assertEquals(1, result.size()); + + iterator = result.iterator(); + + validator = iterator.next(); + ValidatorTestHelper.assertValidatorModel(validator, null, Person.class, NuitonValidatorScope.WARNING); + ValidatorTestHelper.assertValidatorEffectiveScopes(validator, NuitonValidatorScope.WARNING); + + // test with context 'context' and all scopes : one validator (Pet) + + result = provider.detectValidators(testResourcesDir, Pattern.compile(context), null, Person.class, Pet.class); + + Assert.assertNotNull(result); + Assert.assertEquals(1, result.size()); + + iterator = result.iterator(); + + validator = iterator.next(); + ValidatorTestHelper.assertValidatorModel(validator, context, Pet.class, NuitonValidatorScope.values()); + ValidatorTestHelper.assertValidatorEffectiveScopes(validator, NuitonValidatorScope.INFO); + + // test with no context and only scope fatal : no validator + result = provider.detectValidators(testResourcesDir, null, + new NuitonValidatorScope[]{NuitonValidatorScope.FATAL}, Person.class, Pet.class); + + Assert.assertNotNull(result); + Assert.assertTrue(result.isEmpty()); + + // test with specific context fake and all scopes : no validator + + result = provider.detectValidators(testResourcesDir, Pattern.compile(".*-fake"), + null, Person.class, Pet.class); + + Assert.assertNotNull(result); + Assert.assertTrue(result.isEmpty()); + } + +} diff --git a/src/test/java/org/nuiton/validator/xwork2/XWork2NuitonValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/XWork2NuitonValidatorTest.java new file mode 100644 index 0000000..cffd5d1 --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/XWork2NuitonValidatorTest.java @@ -0,0 +1,59 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2; + +import org.junit.Assert; +import org.junit.Test; +import org.nuiton.validator.NuitonValidator; +import org.nuiton.validator.NuitonValidatorModel; +import org.nuiton.validator.ValidatorTestHelper; +import org.nuiton.validator.model.Person; + +/** + * To test {@link XWork2NuitonValidator}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.0 + */ +public class XWork2NuitonValidatorTest { + + @Test + public void testNewValidator() throws Exception { + + XWork2NuitonValidatorProvider provider = + new XWork2NuitonValidatorProvider(); + + + NuitonValidatorModel<Person> model = + provider.getModel(Person.class, null); + + NuitonValidator<Person> validator = provider.newValidator(model); + + Assert.assertNotNull(validator); + + ValidatorTestHelper.testPerson(validator); + + } + +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/AbstractFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/AbstractFieldValidatorTest.java new file mode 100644 index 0000000..d7767ae --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/AbstractFieldValidatorTest.java @@ -0,0 +1,132 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.nuiton.validator.NuitonValidator; +import org.nuiton.validator.NuitonValidatorFactory; +import org.nuiton.validator.NuitonValidatorResult; + +import java.io.File; +import java.util.List; + +/** + * Abstract class to test a specific validator. + * <p/> + * To implements a test on a new validator, just extends this class + * and implements the method {@link #testValidator()}. + * + * @param <B> the type of bean to validate. + * @author tchemit <chemit@codelutin.com> + */ +public abstract class AbstractFieldValidatorTest<B> extends Assert { + + /** Logger */ + private static final Log log = + LogFactory.getLog(AbstractFieldValidatorTest.class); + + protected static NuitonValidator<?> cacheValidator; + + protected static File basedir; + + protected final Class<B> type; + + protected NuitonValidator<B> validator; + + protected B bean; + + public AbstractFieldValidatorTest(Class<B> type) { + this.type = type; + } + + /** + * the method to test the given validator on the given bean. + * <p/> + * When coming here a validator and bean were instanciated and the bean was + * setted into validator via setBean method. + * + * @throws Exception if any error ? + */ + public abstract void testValidator() throws Exception; + + @Before + @SuppressWarnings("unchecked") + public void setUp() throws Exception { + log.debug("start test " + getClass().getSimpleName()); + bean = type.newInstance(); + if (cacheValidator == null) { + validator = NuitonValidatorFactory.newValidator(type); + cacheValidator = validator; + } else { + validator = (NuitonValidator<B>) cacheValidator; + } + } + + @After + @SuppressWarnings("unchecked") + public void tearDown() { + } + + @AfterClass + public static void afterclass() throws Exception { + cacheValidator = null; + } + + @BeforeClass + public static void initValidator() throws Exception { + + String b = System.getenv("basedir"); + if (b == null) { + b = new File("").getAbsolutePath(); + } + basedir = new File(b); + } + + @SuppressWarnings("unchecked") + protected void assertFieldInError(String fieldName, String error, boolean required) { + + NuitonValidatorResult result = validator.validate(bean); + + List<String> errorMessages = result.getErrorMessages(fieldName); + + boolean errorFound = errorMessages.contains(error); + + if (required) { + + // must have this error + + assertTrue("error " + error + " should not exist but was found.", errorFound); + } else { + + // must not have this error + assertFalse("error " + error + " should exist but was not found.", errorFound); + } + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/AbstractValidatorBeanFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/AbstractValidatorBeanFieldValidatorTest.java new file mode 100644 index 0000000..f137984 --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/AbstractValidatorBeanFieldValidatorTest.java @@ -0,0 +1,37 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +/** + * Abstract class to test a specific validator for the {@link ValidatorBean}. + * + * @author tchemit <chemit@codelutin.com> + * @since 1.3 + */ +public abstract class AbstractValidatorBeanFieldValidatorTest extends AbstractFieldValidatorTest<ValidatorBean> { + + public AbstractValidatorBeanFieldValidatorTest() { + super(ValidatorBean.class); + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/CollectionFieldExpressionValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/CollectionFieldExpressionValidatorTest.java new file mode 100644 index 0000000..6b2e7e5 --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/CollectionFieldExpressionValidatorTest.java @@ -0,0 +1,265 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; +import org.nuiton.validator.xwork2.field.ValidatorBean.ValidatorBeanEntry; + +import java.util.Arrays; + +/** + * @author tchemit <chemit@codelutin.com> + */ +public class CollectionFieldExpressionValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + protected static final String PROPERTY = "entries"; + + static protected ValidatorBeanEntry beanEntry0 = new ValidatorBeanEntry(0, "stringValue"); + + static protected ValidatorBeanEntry beanEntry0Bis = new ValidatorBeanEntry(0, "fake"); + + static protected ValidatorBeanEntry beanEntry1 = new ValidatorBeanEntry(1, "fake"); + + static protected ValidatorBeanEntry beanEntry3 = new ValidatorBeanEntry(3, "fake"); + + static protected ValidatorBeanEntry beanEntry5 = new ValidatorBeanEntry(5, "fake"); + + @Test + @Override + public void testValidator() throws Exception { + assertNull(bean.getEntries()); + + // no entry + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.none", false); + + + // add a matching etry + bean.setEntries(Arrays.asList(beanEntry0)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.all", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.none", true); + + // two matching etries + bean.setEntries(Arrays.asList(beanEntry0, beanEntry0)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.none", true); + + // add a none matching etry + bean.setEntries(Arrays.asList(beanEntry0Bis)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none", false); + + // add a none matching etry and a matching entry + bean.setEntries(Arrays.asList(beanEntry0Bis, beanEntry0)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.all", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none", true); + } + + @Test + public void testValidatorWithContext() throws Exception { + assertNull(bean.getEntries()); + + // no entry + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + + // add a matching etry + bean.setEntries(Arrays.asList(beanEntry0)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + + // add a none matching etry + bean.setEntries(Arrays.asList(beanEntry0Bis)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + + // add a none matching etry and a matching entry + bean.setEntries(Arrays.asList(beanEntry0Bis, beanEntry0)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1)); + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + + bean.setEntries(Arrays.asList(beanEntry1, beanEntry0)); + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3)); + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3, beanEntry5)); + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry3, beanEntry1)); + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + } + + @Test + public void testValidatorWithContextAndFirst() throws Exception { + assertNull(bean.getEntries()); + String message = "collectionFieldExpression.all.useFirst"; + + // no entry + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0)); + assertFieldInError(PROPERTY, message, false); + + + bean.setEntries(Arrays.asList(beanEntry0Bis)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry1)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry1, beanEntry0)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3, beanEntry5)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry3, beanEntry1)); + assertFieldInError(PROPERTY, message, true); + } + + @Test + public void testValidatorWithContextAndLast() throws Exception { + assertNull(bean.getEntries()); + String message = "collectionFieldExpression.all.useLast"; + + // no entry + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0)); + assertFieldInError(PROPERTY, message, true); + + + bean.setEntries(Arrays.asList(beanEntry0Bis)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry1)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry1, beanEntry0)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry1, beanEntry3)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3, beanEntry5)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry3, beanEntry1)); + assertFieldInError(PROPERTY, message, true); + } + + @Test + public void testValidatorWithContextAndFirstAndLast() throws Exception { + assertNull(bean.getEntries()); + + String message = "collectionFieldExpression.all.useFirstAndLast"; + // no entry + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0)); + assertFieldInError(PROPERTY, message, true); + + + bean.setEntries(Arrays.asList(beanEntry0Bis)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry1)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry1, beanEntry0)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry1, beanEntry3)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3, beanEntry5)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry3, beanEntry1)); + assertFieldInError(PROPERTY, message, true); + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/CollectionUniqueKeyValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/CollectionUniqueKeyValidatorTest.java new file mode 100644 index 0000000..48855fe --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/CollectionUniqueKeyValidatorTest.java @@ -0,0 +1,114 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; +import org.nuiton.validator.xwork2.field.ValidatorBean.ValidatorBeanEntry; + +import java.util.Arrays; + +/** + * @author tchemit <chemit@codelutin.com> + */ +public class CollectionUniqueKeyValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + static protected ValidatorBeanEntry beanEntry = new ValidatorBeanEntry(0, "stringValue"); + + static protected ValidatorBeanEntry beanEntry2 = new ValidatorBeanEntry(0, "fake"); + + static protected ValidatorBeanEntry beanEntry3 = new ValidatorBeanEntry(0, "stringValue", "stringValue2"); + + @Test + @Override + public void testValidator() throws Exception { + assertNull(bean.getEntries()); + + // no entry + assertFieldInError("entries", "collectionUniqueKey.one.failed", false); + assertFieldInError("entries", "collectionUniqueKey.two.failed", false); + assertFieldInError("entries", "collectionUniqueKey.three.failed", false); + assertFieldInError("entries", "collectionUniqueKey.four.failed", false); + assertFieldInError("entries", "collectionUniqueKey.five.failed", false); + + // add a entry + bean.setEntries(Arrays.asList(beanEntry)); + + assertFieldInError("entries", "collectionUniqueKey.one.failed", false); + assertFieldInError("entries", "collectionUniqueKey.two.failed", false); + assertFieldInError("entries", "collectionUniqueKey.three.failed", false); + assertFieldInError("entries", "collectionUniqueKey.four.failed", false); + assertFieldInError("entries", "collectionUniqueKey.five.failed", false); + + // add violating property + bean.setEntry(beanEntry3); + assertFieldInError("entries", "collectionUniqueKey.one.failed", false); + assertFieldInError("entries", "collectionUniqueKey.two.failed", false); + assertFieldInError("entries", "collectionUniqueKey.three.failed", false); + assertFieldInError("entries", "collectionUniqueKey.four.failed", false); + assertFieldInError("entries", "collectionUniqueKey.five.failed", true); + + + // two entries with same key + bean.setEntries(Arrays.asList(beanEntry, beanEntry)); + + assertFieldInError("entries", "collectionUniqueKey.one.failed", true); + assertFieldInError("entries", "collectionUniqueKey.two.failed", true); + assertFieldInError("entries", "collectionUniqueKey.three.failed", true); + assertFieldInError("entries", "collectionUniqueKey.four.failed", true); + + // add a entry + bean.setEntries(Arrays.asList(beanEntry2)); + + assertFieldInError("entries", "collectionUniqueKey.one.failed", false); + assertFieldInError("entries", "collectionUniqueKey.two.failed", false); + assertFieldInError("entries", "collectionUniqueKey.three.failed", false); + assertFieldInError("entries", "collectionUniqueKey.four.failed", false); + + // add two entries (will violated unique key on intValue) + bean.setEntries(Arrays.asList(beanEntry2, beanEntry)); + + assertFieldInError("entries", "collectionUniqueKey.one.failed", true); + assertFieldInError("entries", "collectionUniqueKey.two.failed", false); + assertFieldInError("entries", "collectionUniqueKey.three.failed", false); + assertFieldInError("entries", "collectionUniqueKey.four.failed", false); + + + // two entries with same key (except validator four) + bean.setEntries(Arrays.asList(beanEntry, beanEntry3)); + assertFieldInError("entries", "collectionUniqueKey.one.failed", true); + assertFieldInError("entries", "collectionUniqueKey.two.failed", true); + assertFieldInError("entries", "collectionUniqueKey.three.failed", true); + assertFieldInError("entries", "collectionUniqueKey.four.failed", false); + + beanEntry.setStringValue2("stringValue2"); + // two entries with same key + bean.setEntries(Arrays.asList(beanEntry, beanEntry3)); + assertFieldInError("entries", "collectionUniqueKey.one.failed", true); + assertFieldInError("entries", "collectionUniqueKey.two.failed", true); + assertFieldInError("entries", "collectionUniqueKey.three.failed", true); + assertFieldInError("entries", "collectionUniqueKey.four.failed", true); + + + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/EmailFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/EmailFieldValidatorTest.java new file mode 100644 index 0000000..78e2f3b --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/EmailFieldValidatorTest.java @@ -0,0 +1,68 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; +import org.nuiton.validator.model.Contact; + +/** + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class EmailFieldValidatorTest extends AbstractFieldValidatorTest<Contact> { + + public EmailFieldValidatorTest() { + super(Contact.class); + } + + @Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getEmail()); + + // Valid email + bean.setEmail("toto@toto.com"); + assertFieldInError(Contact.PROPERTY_EMAIL, "contact.email.format", false); + + // Valid email with + + bean.setEmail("toto+validation@toto.com"); + assertFieldInError(Contact.PROPERTY_EMAIL, "contact.email.format", false); + + // Not valid email + bean.setEmail("toto"); + assertFieldInError(Contact.PROPERTY_EMAIL, "contact.email.format", true); + + // use requiredstring for that case + bean.setEmail(""); + assertFieldInError(Contact.PROPERTY_EMAIL, "contact.email.format", + false); + + // use required for that case + bean.setEmail(null); + assertFieldInError(Contact.PROPERTY_EMAIL, "contact.email.format", + false); + + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/ExistingDirectoryFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/ExistingDirectoryFieldValidatorTest.java new file mode 100644 index 0000000..ec82cdb --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/ExistingDirectoryFieldValidatorTest.java @@ -0,0 +1,57 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; + +import java.io.File; + +/** + * @author tchemit <chemit@codelutin.com> + */ +public class ExistingDirectoryFieldValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + @Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getExistingDirectory()); + assertFieldInError("existingDirectory", "existingDirectory.required", true); + + bean.setExistingDirectory(new File("")); + assertFieldInError("existingDirectory", "existingDirectory.required", true); + + // existing file + bean.setExistingDirectory(new File(basedir, "pom.xml")); + assertFieldInError("existingDirectory", "existingDirectory.required", false); + assertFieldInError("existingDirectory", "existingDirectory.not.exist", true); + + // existing directory + bean.setExistingDirectory(basedir); + assertFieldInError("existingDirectory", "existingDirectory.required", false); + assertFieldInError("existingDirectory", "existingDirectory.not.exist", false); + + } + +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/ExistingFileFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/ExistingFileFieldValidatorTest.java new file mode 100644 index 0000000..59df3d0 --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/ExistingFileFieldValidatorTest.java @@ -0,0 +1,57 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; + +import java.io.File; + +/** + * @author tchemit <chemit@codelutin.com> + */ +public class ExistingFileFieldValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + @Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getExistingFile()); + assertFieldInError("existingFile", "existingFile.required", true); + + bean.setExistingFile(new File("")); + assertFieldInError("existingFile", "existingFile.required", true); + + // existing directory + bean.setExistingFile(basedir); + assertFieldInError("existingFile", "existingFile.required", false); + assertFieldInError("existingFile", "existingFile.not.exist", true); + + // existing file + bean.setExistingFile(new File(basedir, "pom.xml")); + assertFieldInError("existingFile", "existingFile.required", false); + assertFieldInError("existingFile", "existingFile.not.exist", false); + + } + +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/FieldExpressionBean.java b/src/test/java/org/nuiton/validator/xwork2/field/FieldExpressionBean.java new file mode 100644 index 0000000..f9b0d0c --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/FieldExpressionBean.java @@ -0,0 +1,131 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +/** + * @author tchemit <chemit@codelutin.com> + */ +public class FieldExpressionBean { + + protected final PropertyChangeSupport p; + + protected boolean booleanValue; + + protected short shortValue; + + protected int intValue; + + protected long longValue; + + protected double doubleValue; + + protected String stringValue; + + public FieldExpressionBean() { + p = new PropertyChangeSupport(this); + } + + public boolean isBooleanValue() { + return booleanValue; + } + + public double getDoubleValue() { + return doubleValue; + } + + public int getIntValue() { + return intValue; + } + + public long getLongValue() { + return longValue; + } + + public short getShortValue() { + return shortValue; + } + + public String getStringValue() { + return stringValue; + } + + public void setBooleanValue(boolean newValue) { + Object oldValue = booleanValue; + booleanValue = newValue; + firePropertyChange("booleanValue", oldValue, newValue); + } + + public void setDoubleValue(double newValue) { + Object oldValue = doubleValue; + doubleValue = newValue; + firePropertyChange("doubleValue", oldValue, newValue); + } + + public void setIntValue(int newValue) { + Object oldValue = stringValue; + intValue = newValue; + firePropertyChange("intValue", oldValue, newValue); + } + + public void setLongValue(long newValue) { + Object oldValue = longValue; + longValue = newValue; + firePropertyChange("longValue", oldValue, newValue); + } + + public void setShortValue(short newValue) { + Object oldValue = shortValue; + shortValue = newValue; + firePropertyChange("shortValue", oldValue, newValue); + } + + public void setStringValue(String newValue) { + Object oldValue = stringValue; + stringValue = newValue; + firePropertyChange("stringValue", oldValue, newValue); + } + + protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + p.firePropertyChange(propertyName, oldValue, newValue); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + p.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + p.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.removePropertyChangeListener(propertyName, listener); + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/FieldExpressionWithParamsValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/FieldExpressionWithParamsValidatorTest.java new file mode 100644 index 0000000..06037a1 --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/FieldExpressionWithParamsValidatorTest.java @@ -0,0 +1,144 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; + +/** + * @author tchemit <chemit@codelutin.com> + */ +public class FieldExpressionWithParamsValidatorTest extends AbstractFieldValidatorTest<FieldExpressionBean> { + + public static final String MESSAGE = "expression.too.big##100"; + + public static final String MESSAGE2 = "expression.too.big##100##2000"; + + public FieldExpressionWithParamsValidatorTest() { + super(FieldExpressionBean.class); + } + + @Test + @Override + public void testValidator() throws Exception { + + testBooleanType(); + testShortType(); + testIntType(); + testLongType(); + testDoubleType(); + testStringType(); + + + } + + protected void testBooleanType() { + + assertEquals(false, bean.isBooleanValue()); + assertFieldInError("booleanValue", "expression.boolean.not.equals##true", true); + assertFieldInError("booleanValue", "expression.boolean.not.equals##false", false); + + bean.setBooleanValue(true); + assertFieldInError("booleanValue", "expression.boolean.not.equals##true", false); + assertFieldInError("booleanValue", "expression.boolean.not.equals##false", true); + } + + protected void testShortType() { + assertEquals(0, bean.getShortValue()); + assertFieldInError("shortValue", MESSAGE, false); + assertFieldInError("shortValue", MESSAGE2, false); + bean.setShortValue((short) 10); + assertFieldInError("shortValue", MESSAGE, false); + assertFieldInError("shortValue", MESSAGE2, false); + bean.setShortValue((short) 1000); + assertFieldInError("shortValue", MESSAGE, true); + assertFieldInError("shortValue", MESSAGE2, false); + bean.setShortValue((short) 3000); + assertFieldInError("shortValue", MESSAGE, true); + assertFieldInError("shortValue", MESSAGE2, true); + } + + protected void testIntType() { + assertEquals(0, bean.getIntValue()); + assertFieldInError("intValue", MESSAGE, false); + assertFieldInError("intValue", MESSAGE2, false); + bean.setIntValue(10); + assertFieldInError("intValue", MESSAGE, false); + assertFieldInError("intValue", MESSAGE2, false); + bean.setIntValue(1000); + assertFieldInError("intValue", MESSAGE, true); + assertFieldInError("intValue", MESSAGE2, false); + bean.setIntValue(3000); + assertFieldInError("intValue", MESSAGE, true); + assertFieldInError("intValue", MESSAGE2, true); + } + + protected void testLongType() { + assertEquals(0, bean.getLongValue()); + assertFieldInError("longValue", MESSAGE, false); + assertFieldInError("longValue", MESSAGE2, false); + bean.setLongValue(10); + assertFieldInError("longValue", MESSAGE, false); + assertFieldInError("longValue", MESSAGE2, false); + bean.setLongValue(1000); + assertFieldInError("longValue", MESSAGE, true); + assertFieldInError("longValue", MESSAGE2, false); + bean.setLongValue(3000); + assertFieldInError("longValue", MESSAGE, true); + assertFieldInError("longValue", MESSAGE2, true); + } + + protected void testDoubleType() { + assertEquals(0.0, bean.getDoubleValue(), 0); + assertFieldInError("doubleValue", MESSAGE + ".0", false); + assertFieldInError("doubleValue", "expression.too.big##100.0##2000.0", false); + bean.setDoubleValue(10); + assertFieldInError("doubleValue", MESSAGE + ".0", false); + assertFieldInError("doubleValue", "expression.too.big##100.0##2000.0", false); + bean.setDoubleValue(1000); + assertFieldInError("doubleValue", MESSAGE + ".0", true); + assertFieldInError("doubleValue", "expression.too.big##100.0##2000.0", false); + bean.setDoubleValue(3000); + assertFieldInError("doubleValue", MESSAGE + ".0", true); + assertFieldInError("doubleValue", "expression.too.big##100.0##2000.0", true); + } + + protected void testStringType() { + assertEquals(null, bean.getStringValue()); + + assertFieldInError("stringValue", "expression.stringNotValue##1000", true); + assertFieldInError("stringValue", "expression.stringNotValue##1000##3000", true); + bean.setStringValue("100"); + + assertFieldInError("stringValue", "expression.stringNotValue##1000", true); + assertFieldInError("stringValue", "expression.stringNotValue##1000##3000", true); + + bean.setStringValue("1000"); + assertFieldInError("stringValue", "expression.stringNotValue##1000", false); + assertFieldInError("stringValue", "expression.stringNotValue##1000##3000", false); + + bean.setStringValue("3000"); + assertFieldInError("stringValue", "expression.stringNotValue##1000", true); + assertFieldInError("stringValue", "expression.stringNotValue##1000##3000", false); + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/FrenchCityNameFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/FrenchCityNameFieldValidatorTest.java new file mode 100644 index 0000000..f9d9cc9 --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/FrenchCityNameFieldValidatorTest.java @@ -0,0 +1,106 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; +import org.nuiton.validator.model.Contact; + +/** + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class FrenchCityNameFieldValidatorTest extends AbstractFieldValidatorTest<Contact> { + + public FrenchCityNameFieldValidatorTest() { + super(Contact.class); + } + + @Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getCity()); + + // Valid city + bean.setCity("Nantes"); + assertFieldInError(Contact.PROPERTY_CITY, "contact.city.format", + false); + + // Valid city + bean.setCity("Couëron"); + assertFieldInError(Contact.PROPERTY_CITY, "contact.city.format", + false); + + // Valid city + bean.setCity("Saint Sébastien Sur Loire"); + assertFieldInError(Contact.PROPERTY_CITY, "contact.city.format", + false); + + // Valid city + bean.setCity("St Sebastien sur Loire"); + assertFieldInError(Contact.PROPERTY_CITY, "contact.city.format", + false); + + // Valid city + bean.setCity("St-Sebastien-sur-Loire"); + assertFieldInError(Contact.PROPERTY_CITY, "contact.city.format", + false); + + // Valid city + bean.setCity("Y"); + assertFieldInError(Contact.PROPERTY_CITY, "contact.city.format", + false); + + // Valid city + bean.setCity("Saint-Remy-en-Bouzemont-Saint-Genest-et-Isson"); + assertFieldInError(Contact.PROPERTY_CITY, "contact.city.format", + false); + + // Not Valid city name + bean.setCity("2Ville"); + assertFieldInError(Contact.PROPERTY_CITY, "contact.city.format", + true); + + // Not Valid city name + bean.setCity("Ville2Merde"); + assertFieldInError(Contact.PROPERTY_CITY, "contact.city.format", + true); + + // Not Valid city name + bean.setCity("Ville 2 Merde"); + assertFieldInError(Contact.PROPERTY_CITY, "contact.city.format", + true); + + // Use requiredstring validator for this case + bean.setCity(""); + assertFieldInError(Contact.PROPERTY_CITY, "contact.city.format", + false); + + // Use required validator for this case + bean.setCity(null); + assertFieldInError(Contact.PROPERTY_CITY, "contact.city.format", + false); + + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidatorTest.java new file mode 100644 index 0000000..df39877 --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidatorTest.java @@ -0,0 +1,85 @@ +package org.nuiton.validator.xwork2.field; + +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2013 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import org.junit.Test; +import org.nuiton.validator.model.HealthEstablishment; + +/** + * @author Sylvain Bavencoff <bavencoff@codelutin.com> + */ +public class FrenchFinessFieldValidatorTest extends AbstractFieldValidatorTest<HealthEstablishment> { + + public FrenchFinessFieldValidatorTest() { + super(HealthEstablishment.class); + } + + @Test + @Override + public void testValidator() throws Exception { + assertNull(bean.getFiness()); + + // Valid Finess + bean.setFiness("440123456"); + assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", + false); + + // Valid Finess + bean.setFiness("2B0483714"); + assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", + false); + + // not Valid Finess + bean.setFiness("2B01"); + assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", + true); + + // not Valid Finess + bean.setFiness("4402345636"); + assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", + true); + + // not Valid Finess + bean.setFiness("CC0123456"); + assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", + true); + + // not Valid Finess + bean.setFiness("441123456"); + assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", + true); + + // not Valid Finess + bean.setFiness("441B23456"); + assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", + true); + + // not Valid Finess + bean.setFiness("4402345F6"); + assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", + true); + + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/FrenchLastNameFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/FrenchLastNameFieldValidatorTest.java new file mode 100644 index 0000000..4f97926 --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/FrenchLastNameFieldValidatorTest.java @@ -0,0 +1,87 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; +import org.nuiton.validator.model.Contact; + +/** + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class FrenchLastNameFieldValidatorTest extends AbstractFieldValidatorTest<Contact> { + + public FrenchLastNameFieldValidatorTest() { + super(Contact.class); + } + + @Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getCity()); + + // Valid name + bean.setName("Couteau"); + assertFieldInError(Contact.PROPERTY_LAST_NAME, "contact.name.format", + false); + + // Valid name + bean.setName("Le Ny"); + assertFieldInError(Contact.PROPERTY_LAST_NAME, "contact.name.format", + false); + + // Valid name + bean.setName("Clémenceau"); + assertFieldInError(Contact.PROPERTY_LAST_NAME, "contact.name.format", + false); + + // Valid name + bean.setName("Couteau--Viney"); + assertFieldInError(Contact.PROPERTY_LAST_NAME, "contact.name.format", + false); + + // Not valid name + bean.setName("2Pac"); + assertFieldInError(Contact.PROPERTY_LAST_NAME, "contact.name.format", + true); + + // Not valid name + bean.setName("Nom2Merde"); + assertFieldInError(Contact.PROPERTY_LAST_NAME, "contact.name.format", + true); + + // Use requiredstring validator for that case + bean.setName(""); + assertFieldInError(Contact.PROPERTY_LAST_NAME, "contact.name.format", + false); + + // Use required validator for that case + bean.setName(null); + assertFieldInError(Contact.PROPERTY_LAST_NAME, "contact.name.format", + false); + + + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/FrenchPhoneNumberFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/FrenchPhoneNumberFieldValidatorTest.java new file mode 100644 index 0000000..879dc0c --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/FrenchPhoneNumberFieldValidatorTest.java @@ -0,0 +1,134 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; +import org.nuiton.validator.model.Contact; + +/** + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class FrenchPhoneNumberFieldValidatorTest extends AbstractFieldValidatorTest<Contact> { + + public FrenchPhoneNumberFieldValidatorTest() { + super(Contact.class); + } + + @Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getPhone()); + + // Valid phone Number + bean.setPhone("0000000000"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + false); + + // Valid phone Number + bean.setPhone("00 00 00 00 00"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + false); + + // Valid phone Number + bean.setPhone("00-00-00-00-00"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + false); + + // Valid phone Number + bean.setPhone("00.00.00.00.00"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + false); + + // Too long phone Number + bean.setPhone("00 00 00 00 00 00"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + true); + + // Too long phone Number + bean.setPhone("00-00-00-00-00-00"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + true); + + // Too long phone Number + bean.setPhone("000000000000"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + true); + + // Too long phone Number + bean.setPhone("00.00.00.00.00.00"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + true); + + // Too short phone Number + bean.setPhone("00.00.00.00"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + true); + + // Too short phone Number + bean.setPhone("00000000"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + true); + + // Too short phone Number + bean.setPhone("00-00-00-00"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + true); + + // Too short phone Number + bean.setPhone("00 00 00 00"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + true); + + // Invalid character in phone Number + bean.setPhone("00 00 ab 00 00"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + true); + + // Invalid character in phone Number + bean.setPhone("0000ab0000"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + true); + + // Invalid character in phone Number + bean.setPhone("00.00.ab.00.00"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + true); + + // Invalid character in phone Number + bean.setPhone("00-00-ab-00-00"); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + true); + //Use required string validator for this case + bean.setPhone(""); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + false); + //Use required validator for this case + bean.setPhone(null); + assertFieldInError(Contact.PROPERTY_PHONE, "contact.phoneNumber.format", + false); + + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/FrenchPostCodeFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/FrenchPostCodeFieldValidatorTest.java new file mode 100644 index 0000000..707a6e5 --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/FrenchPostCodeFieldValidatorTest.java @@ -0,0 +1,92 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; +import org.nuiton.validator.model.Contact; + +/** + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class FrenchPostCodeFieldValidatorTest extends AbstractFieldValidatorTest<Contact> { + + public FrenchPostCodeFieldValidatorTest() { + super(Contact.class); + } + + @Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getPostCode()); + + // Valid postCode + bean.setPostCode("44230"); + assertFieldInError(Contact.PROPERTY_POSTCODE, "contact.postCode.format", + false); + + // Valid postCode for Corsica + bean.setEmail("2A220"); + assertFieldInError(Contact.PROPERTY_POSTCODE, "contact.postCode.format", + false); + + // Valid postCode for DOM + bean.setEmail("97120"); + assertFieldInError(Contact.PROPERTY_POSTCODE, "contact.postCode.format", + false); + + // Valid postCode for TOM + bean.setPostCode("98120"); + assertFieldInError(Contact.PROPERTY_POSTCODE, "contact.postCode.format", + false); + + // Too long postCode + bean.setPostCode("442300"); + assertFieldInError(Contact.PROPERTY_POSTCODE, "contact.postCode.format", + true); + + // Too short postCode + bean.setPostCode("4423"); + assertFieldInError(Contact.PROPERTY_POSTCODE, "contact.postCode.format", + true); + + // postCode cannot start with 99 + bean.setPostCode("99230"); + assertFieldInError(Contact.PROPERTY_POSTCODE, "contact.postCode.format", + true); + + // postCode can be empty (use a requiredstring validator for this check) + bean.setPostCode(""); + assertFieldInError(Contact.PROPERTY_POSTCODE, "contact.postCode.format", + false); + + // postCode can be null (use a requiredstring validator for this check) + bean.setPostCode(null); + assertFieldInError(Contact.PROPERTY_POSTCODE, "contact.postCode.format", + false); + + + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidatorTest.java new file mode 100644 index 0000000..c68e02b --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidatorTest.java @@ -0,0 +1,103 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; +import org.nuiton.validator.model.Company; + +/** + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class FrenchSiretFieldValidatorTest extends AbstractFieldValidatorTest<Company> { + + public FrenchSiretFieldValidatorTest() { + super(Company.class); + } + + @Test + public void TestLuhnChecksum() throws Exception { + // verification sur de vrai numero siret (ca doit passer :) + assertTrue(FrenchSiretFieldValidator.luhnChecksum("44211670300038")); + assertTrue(FrenchSiretFieldValidator.luhnChecksum("73282932000074")); + + // verification avec les memes, en ne modifiant que le dernier chiffre + // ca doit failer + assertFalse(FrenchSiretFieldValidator.luhnChecksum("44211670300030")); + assertFalse(FrenchSiretFieldValidator.luhnChecksum("73282932000070")); + } + + @Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getSiret()); + + // Valid siret + bean.setSiret("44211670300038"); + assertFieldInError(Company.PROPERTY_SIRET, "company.siret.format", + false); + + // Valid siret + bean.setSiret("73282932000074"); + assertFieldInError(Company.PROPERTY_SIRET, "company.siret.format", + false); + + // Not Valid siret, because bad checksum + bean.setSiret("73282932000071"); + assertFieldInError(Company.PROPERTY_SIRET, "company.siret.format", + true); + + // Not valid siret + bean.setSiret("4421167030003"); + assertFieldInError(Company.PROPERTY_SIRET, "company.siret.format", + true); + + // Not valid siret + bean.setSiret("442116703000389"); + assertFieldInError(Company.PROPERTY_SIRET, "company.siret.format", + true); + + // Not valid siret + bean.setSiret("4421bf1670300038"); + assertFieldInError(Company.PROPERTY_SIRET, "company.siret.format", + true); + + // Use requiredString for empty siret + bean.setSiret(""); + assertFieldInError(Company.PROPERTY_SIRET, "company.siret.format", + false); + + // Use required for null siret + bean.setSiret(null); + assertFieldInError(Company.PROPERTY_SIRET, "company.siret.format", + false); + + // Valid siret with spaces + bean.setSiret("535 198 188 00018 "); + assertFieldInError(Company.PROPERTY_SIRET, "company.siret.format", + false); + + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/NotExistingDirectoryFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/NotExistingDirectoryFieldValidatorTest.java new file mode 100644 index 0000000..a2d271b --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/NotExistingDirectoryFieldValidatorTest.java @@ -0,0 +1,60 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; + +import java.io.File; + +/** + * @author tchemit <chemit@codelutin.com> + */ +public class NotExistingDirectoryFieldValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + @Test + @Override + public void testValidator() throws Exception { + assertNull(bean.getNotExistingDirectory()); + assertFieldInError("notExistingDirectory", "notExistingDirectory.required", true); + + bean.setNotExistingDirectory(new File("")); + assertFieldInError("notExistingDirectory", "notExistingDirectory.required", true); + + // existing directory + bean.setNotExistingDirectory(basedir); + assertFieldInError("notExistingDirectory", "notExistingDirectory.required", false); + assertFieldInError("notExistingDirectory", "notExistingDirectory.exist", true); + + // existing file + bean.setNotExistingDirectory(new File(basedir, "pom.xml")); + assertFieldInError("notExistingDirectory", "notExistingDirectory.required", false); + assertFieldInError("notExistingDirectory", "notExistingDirectory.exist", true); + + // none existing directory + bean.setNotExistingDirectory(new File(basedir, "pom.xml-" + System.currentTimeMillis())); + assertFieldInError("notExistingDirectory", "notEexistingFile.required", false); + assertFieldInError("notExistingDirectory", "notExistingDirectory.exist", false); + } + +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/NotExistingFileFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/NotExistingFileFieldValidatorTest.java new file mode 100644 index 0000000..98e47c5 --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/NotExistingFileFieldValidatorTest.java @@ -0,0 +1,63 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; + +import java.io.File; + +/** + * @author tchemit <chemit@codelutin.com> + */ +public class NotExistingFileFieldValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + @Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getNotExistingFile()); + assertFieldInError("notExistingFile", "notExistingFile.required", true); + + bean.setNotExistingFile(new File("")); + assertFieldInError("notExistingFile", "notExistingFile.required", true); + + // existing directory + bean.setNotExistingFile(basedir); + assertFieldInError("notExistingFile", "notExistingFile.required", false); + assertFieldInError("notExistingFile", "notExistingFile.exist", true); + + // existing file + bean.setNotExistingFile(new File(basedir, "pom.xml")); + assertFieldInError("notExistingFile", "notExistingFile.required", false); + assertFieldInError("notExistingFile", "notExistingFile.exist", true); + + // none existing file + bean.setNotExistingFile(new File(basedir, "pom.xml-" + System.currentTimeMillis())); + assertFieldInError("notExistingFile", "notEexistingFile.required", false); + assertFieldInError("notExistingFile", "notExistingFile.exist", false); + + + } + +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/RequiredFileFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/RequiredFileFieldValidatorTest.java new file mode 100644 index 0000000..234cc77 --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/RequiredFileFieldValidatorTest.java @@ -0,0 +1,56 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; + +import java.io.File; + +/** + * @author tchemit <chemit@codelutin.com> + */ +public class RequiredFileFieldValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + @Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getExistingFile()); + assertFieldInError("existingFile", "existingFile.required", true); + + bean.setExistingFile(new File("")); + assertFieldInError("existingFile", "existingFile.required", true); + + bean.setExistingFile(basedir); + assertFieldInError("existingFile", "existingFile.required", false); + + assertFieldInError("existingFile", "existingFile.not.exist", true); + + bean.setExistingFile(new File(basedir, "pom.xml")); + assertFieldInError("existingFile", "existingFile.required", false); + assertFieldInError("existingFile", "existingFile.not.exist", false); + + } + +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/VATIdentificationNumberFieldValidatorTest.java b/src/test/java/org/nuiton/validator/xwork2/field/VATIdentificationNumberFieldValidatorTest.java new file mode 100644 index 0000000..e6e2581 --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/VATIdentificationNumberFieldValidatorTest.java @@ -0,0 +1,80 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; +import org.nuiton.validator.model.Company; + +/** + * @author jcouteau <couteau@codelutin.com> + * @since 2.3 + */ +public class VATIdentificationNumberFieldValidatorTest extends AbstractFieldValidatorTest<Company> { + + public VATIdentificationNumberFieldValidatorTest() { + super(Company.class); + } + + @Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getVat()); + + // Valid vat + bean.setVat("FR57442116703"); + assertFieldInError(Company.PROPERTY_VAT_NUMBER, "company.vat.format", + false); + + // Not valid vat + bean.setVat("FR 57 44211670332"); + assertFieldInError(Company.PROPERTY_VAT_NUMBER, "company.vat.format", + true); + + // Not valid vat + bean.setVat("442116703000389"); + assertFieldInError(Company.PROPERTY_VAT_NUMBER, "company.vat.format", + true); + + // Valid vat, with spaces in it + bean.setVat("FR 57 442116703"); + assertFieldInError(Company.PROPERTY_VAT_NUMBER, "company.vat.format", + false); + + // Real vat, with spaces in it + bean.setVat("FR 39 535 198 188"); + assertFieldInError(Company.PROPERTY_VAT_NUMBER, "company.vat.format", + false); + + // Use required string validator for that + bean.setVat(""); + assertFieldInError(Company.PROPERTY_VAT_NUMBER, "company.vat.format", + false); + + // Use required validator for that + bean.setVat(null); + assertFieldInError(Company.PROPERTY_VAT_NUMBER, "company.vat.format", + false); + } +} diff --git a/src/test/java/org/nuiton/validator/xwork2/field/ValidatorBean.java b/src/test/java/org/nuiton/validator/xwork2/field/ValidatorBean.java new file mode 100644 index 0000000..294f965 --- /dev/null +++ b/src/test/java/org/nuiton/validator/xwork2/field/ValidatorBean.java @@ -0,0 +1,182 @@ +/* + * #%L + * Nuiton Validator + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin, Tony Chemit + * %% + * This program 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 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.validator.xwork2.field; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.File; +import java.util.Collection; + +public class ValidatorBean { + + public static class ValidatorBeanEntry { + + protected int intValue; + + protected String stringValue; + + protected String stringValue2; + + public ValidatorBeanEntry(int intValue, String stringValue) { + this.intValue = intValue; + this.stringValue = stringValue; + } + + public ValidatorBeanEntry(int intValue, String stringValue, String stringValue2) { + this.intValue = intValue; + this.stringValue = stringValue; + this.stringValue2 = stringValue2; + } + + public int getIntValue() { + return intValue; + } + + public void setIntValue(int intValue) { + this.intValue = intValue; + } + + public String getStringValue() { + return stringValue; + } + + public void setStringValue(String stringValue) { + this.stringValue = stringValue; + } + + public String getStringValue2() { + return stringValue2; + } + + public void setStringValue2(String stringValue2) { + this.stringValue2 = stringValue2; + } + } + + protected File existingFile; + + protected File notExistingFile; + + protected File existingDirectory; + + protected File notExistingDirectory; + + protected Collection<ValidatorBeanEntry> entries; + + protected String stringValue; + + protected ValidatorBeanEntry entry; + + PropertyChangeSupport p; + + public ValidatorBean() { + p = new PropertyChangeSupport(this); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + p.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + p.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.removePropertyChangeListener(propertyName, listener); + } + + public String getStringValue() { + return stringValue; + } + + public File getExistingFile() { + return existingFile; + } + + public File getNotExistingFile() { + return notExistingFile; + } + + public File getExistingDirectory() { + return existingDirectory; + } + + public File getNotExistingDirectory() { + return notExistingDirectory; + } + + public ValidatorBeanEntry getEntry() { + return entry; + } + + public Collection<ValidatorBeanEntry> getEntries() { + return entries; + } + + public void setStringValue(String stringValue) { + String old = this.stringValue; + this.stringValue = stringValue; + p.firePropertyChange("stringValue", old, existingFile); + } + + public void setExistingFile(File existingFile) { + File old = this.existingFile; + this.existingFile = existingFile; + p.firePropertyChange("existingFile", old, existingFile); + } + + public void setNotExistingFile(File notExistingFile) { + File old = this.notExistingFile; + this.notExistingFile = notExistingFile; + p.firePropertyChange("notExistingFile", old, notExistingFile); + } + + public void setExistingDirectory(File existingDirectory) { + File old = this.existingDirectory; + this.existingDirectory = existingDirectory; + p.firePropertyChange("existingDirectory", old, existingDirectory); + } + + public void setNotExistingDirectory(File notExistingDirectory) { + File old = this.notExistingDirectory; + this.notExistingDirectory = notExistingDirectory; + p.firePropertyChange("notExistingDirectory", old, notExistingDirectory); + } + + public void setEntries(Collection<ValidatorBeanEntry> entries) { + this.entries = entries; + // set null oldValue to always fire event + // otherwise it could been not sent... + p.firePropertyChange("entries", null, entries); + } + + public void setEntry(ValidatorBeanEntry entry) { + this.entry = entry; + p.firePropertyChange("entry", null, entry); + } +} diff --git a/src/test/resources/log4j.properties b/src/test/resources/log4j.properties new file mode 100644 index 0000000..8e98a06 --- /dev/null +++ b/src/test/resources/log4j.properties @@ -0,0 +1,32 @@ +### +# #%L +# Nuiton Validator +# $Id$ +# $HeadURL$ +# %% +# Copyright (C) 2011 CodeLutin, Tony Chemit +# %% +# This program 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 3 of the +# License, or (at your option) any later version. +# +# This program 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 General Lesser Public License for more details. +# +# You should have received a copy of the GNU General Lesser Public +# License along with this program. If not, see +# <http://www.gnu.org/licenses/lgpl-3.0.html>. +# #L% +### + +# Global logging configuration +log4j.rootLogger=ERROR, stdout +# Console output... +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) %M - %m%n + +log4j.logger.org.nuiton.validator=INFO diff --git a/src/test/resources/org/nuiton/validator/bean/SimpleBean-error-validation.xml b/src/test/resources/org/nuiton/validator/bean/SimpleBean-error-validation.xml new file mode 100644 index 0000000..8090351 --- /dev/null +++ b/src/test/resources/org/nuiton/validator/bean/SimpleBean-error-validation.xml @@ -0,0 +1,42 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="stringValue"> + <field-validator type="requiredstring"> + <message>stringValue.error</message> + </field-validator> + </field> + + <field name="intValue"> + <field-validator type="int"> + <param name="min">1</param> + <message>intValue.error</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/bean/SimpleBean-fatal-validation.xml b/src/test/resources/org/nuiton/validator/bean/SimpleBean-fatal-validation.xml new file mode 100644 index 0000000..e6f1cd9 --- /dev/null +++ b/src/test/resources/org/nuiton/validator/bean/SimpleBean-fatal-validation.xml @@ -0,0 +1,46 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="stringValue"> + <field-validator type="fieldexpression"> + <param name="expression"> + <![CDATA[ stringValue != null && stringValue == "5"]]></param> + <message>stringValue.fatal</message> + </field-validator> + </field> + + + <field name="intValue"> + <field-validator type="int"> + <param name="min">5</param> + <param name="max">5</param> + <message>intValue.fatal</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/bean/SimpleBean-info-validation.xml b/src/test/resources/org/nuiton/validator/bean/SimpleBean-info-validation.xml new file mode 100644 index 0000000..7b94f49 --- /dev/null +++ b/src/test/resources/org/nuiton/validator/bean/SimpleBean-info-validation.xml @@ -0,0 +1,36 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="intValue"> + <field-validator type="int"> + <param name="min">10</param> + <message>intValue.info</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/bean/SimpleBean-marchepo-error-validation.xml b/src/test/resources/org/nuiton/validator/bean/SimpleBean-marchepo-error-validation.xml new file mode 100644 index 0000000..50b82df --- /dev/null +++ b/src/test/resources/org/nuiton/validator/bean/SimpleBean-marchepo-error-validation.xml @@ -0,0 +1,37 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <!-- add a unknown field --> + + <field name="stringValueUnknown"> + <field-validator type="requiredstring"> + <message>stringValue.error.can.not.happen!</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/bean/SimpleBean-simple-validation.xml b/src/test/resources/org/nuiton/validator/bean/SimpleBean-simple-validation.xml new file mode 100644 index 0000000..8d4b2d4 --- /dev/null +++ b/src/test/resources/org/nuiton/validator/bean/SimpleBean-simple-validation.xml @@ -0,0 +1,42 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="stringValue"> + <field-validator type="requiredstring"> + <message>stringValue.null</message> + </field-validator> + </field> + + <field name="intValue"> + <field-validator type="int"> + <param name="min">1</param> + <message>intValue.null</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/bean/SimpleBean-warning-validation.xml b/src/test/resources/org/nuiton/validator/bean/SimpleBean-warning-validation.xml new file mode 100644 index 0000000..2701f03 --- /dev/null +++ b/src/test/resources/org/nuiton/validator/bean/SimpleBean-warning-validation.xml @@ -0,0 +1,36 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="stringValue"> + <field-validator type="fieldexpression"> + <param name="expression"><![CDATA[ stringValue != null && stringValue.length() > 5]]></param> + <message>stringValue.warning</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/legacy/SimpleBean-error-validation.xml b/src/test/resources/org/nuiton/validator/legacy/SimpleBean-error-validation.xml new file mode 100644 index 0000000..20b1439 --- /dev/null +++ b/src/test/resources/org/nuiton/validator/legacy/SimpleBean-error-validation.xml @@ -0,0 +1,42 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="stringValue"> + <field-validator type="requiredstring"> + <message>stringValue.error</message> + </field-validator> + </field> + + <field name="intValue"> + <field-validator type="int"> + <param name="min">1</param> + <message>intValue.error</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/legacy/SimpleBean-fatal-validation.xml b/src/test/resources/org/nuiton/validator/legacy/SimpleBean-fatal-validation.xml new file mode 100644 index 0000000..e6f1cd9 --- /dev/null +++ b/src/test/resources/org/nuiton/validator/legacy/SimpleBean-fatal-validation.xml @@ -0,0 +1,46 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="stringValue"> + <field-validator type="fieldexpression"> + <param name="expression"> + <![CDATA[ stringValue != null && stringValue == "5"]]></param> + <message>stringValue.fatal</message> + </field-validator> + </field> + + + <field name="intValue"> + <field-validator type="int"> + <param name="min">5</param> + <param name="max">5</param> + <message>intValue.fatal</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/legacy/SimpleBean-info-validation.xml b/src/test/resources/org/nuiton/validator/legacy/SimpleBean-info-validation.xml new file mode 100644 index 0000000..7b94f49 --- /dev/null +++ b/src/test/resources/org/nuiton/validator/legacy/SimpleBean-info-validation.xml @@ -0,0 +1,36 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="intValue"> + <field-validator type="int"> + <param name="min">10</param> + <message>intValue.info</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/legacy/SimpleBean-simple-validation.xml b/src/test/resources/org/nuiton/validator/legacy/SimpleBean-simple-validation.xml new file mode 100644 index 0000000..8d4b2d4 --- /dev/null +++ b/src/test/resources/org/nuiton/validator/legacy/SimpleBean-simple-validation.xml @@ -0,0 +1,42 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="stringValue"> + <field-validator type="requiredstring"> + <message>stringValue.null</message> + </field-validator> + </field> + + <field name="intValue"> + <field-validator type="int"> + <param name="min">1</param> + <message>intValue.null</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/legacy/SimpleBean-warning-validation.xml b/src/test/resources/org/nuiton/validator/legacy/SimpleBean-warning-validation.xml new file mode 100644 index 0000000..2701f03 --- /dev/null +++ b/src/test/resources/org/nuiton/validator/legacy/SimpleBean-warning-validation.xml @@ -0,0 +1,36 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="stringValue"> + <field-validator type="fieldexpression"> + <param name="expression"><![CDATA[ stringValue != null && stringValue.length() > 5]]></param> + <message>stringValue.warning</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/model/Company-error-validation.xml b/src/test/resources/org/nuiton/validator/model/Company-error-validation.xml new file mode 100644 index 0000000..7ac5b3f --- /dev/null +++ b/src/test/resources/org/nuiton/validator/model/Company-error-validation.xml @@ -0,0 +1,41 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="siret"> + <field-validator type="frenchSiret"> + <message>company.siret.format</message> + </field-validator> + </field> + + <field name="vat"> + <field-validator type="vatIdentificationNumber"> + <message>company.vat.format</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/model/Contact-error-validation.xml b/src/test/resources/org/nuiton/validator/model/Contact-error-validation.xml new file mode 100644 index 0000000..5552c3c --- /dev/null +++ b/src/test/resources/org/nuiton/validator/model/Contact-error-validation.xml @@ -0,0 +1,57 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin + %% + This program 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 3 of the + License, or (at your option) any later version. + This program 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 General Lesser Public License for more details. + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="email"> + <field-validator type="emailNuiton"> + <message>contact.email.format</message> + </field-validator> + </field> + + <field name="postCode"> + <field-validator type="frenchPostCode"> + <message>contact.postCode.format</message> + </field-validator> + </field> + + <field name="city"> + <field-validator type="frenchCityName"> + <message>contact.city.format</message> + </field-validator> + </field> + + <field name="name"> + <field-validator type="frenchLastName"> + <message>contact.name.format</message> + </field-validator> + </field> + + <field name="phone"> + <field-validator type="frenchPhoneNumber"> + <message>contact.phoneNumber.format</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/model/HealthEstablishment-error-validation.xml b/src/test/resources/org/nuiton/validator/model/HealthEstablishment-error-validation.xml new file mode 100644 index 0000000..e3f8f2f --- /dev/null +++ b/src/test/resources/org/nuiton/validator/model/HealthEstablishment-error-validation.xml @@ -0,0 +1,33 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2013 CodeLutin + %% + This program 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 3 of the + License, or (at your option) any later version. + This program 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 General Lesser Public License for more details. + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="finess"> + <field-validator type="frenchFiness"> + <message>healthEstablishment.finess.format</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/model/Person-error-validation.xml b/src/test/resources/org/nuiton/validator/model/Person-error-validation.xml new file mode 100644 index 0000000..dd137ba --- /dev/null +++ b/src/test/resources/org/nuiton/validator/model/Person-error-validation.xml @@ -0,0 +1,41 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="name"> + <field-validator type="requiredstring"> + <message>person.name.required</message> + </field-validator> + </field> + + <field name="firstname"> + <field-validator type="requiredstring"> + <message>person.firstname.required</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/model/Person-warning-validation.xml b/src/test/resources/org/nuiton/validator/model/Person-warning-validation.xml new file mode 100644 index 0000000..bdafeab --- /dev/null +++ b/src/test/resources/org/nuiton/validator/model/Person-warning-validation.xml @@ -0,0 +1,37 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="pet"> + <field-validator type="fieldexpression"> + <param name="expression"> + <![CDATA[ pet!=null || !pet.empty]]></param> + <message>person.with.no.pet</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/model/Pet-context-info-validation.xml b/src/test/resources/org/nuiton/validator/model/Pet-context-info-validation.xml new file mode 100644 index 0000000..ac91ce2 --- /dev/null +++ b/src/test/resources/org/nuiton/validator/model/Pet-context-info-validation.xml @@ -0,0 +1,33 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin + %% + This program 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 3 of the + License, or (at your option) any later version. + This program 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 General Lesser Public License for more details. + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="name"> + <field-validator type="requiredstring"> + <message>pet.name.required</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/model/Pet-error-validation.xml b/src/test/resources/org/nuiton/validator/model/Pet-error-validation.xml new file mode 100644 index 0000000..ac91ce2 --- /dev/null +++ b/src/test/resources/org/nuiton/validator/model/Pet-error-validation.xml @@ -0,0 +1,33 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin + %% + This program 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 3 of the + License, or (at your option) any later version. + This program 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 General Lesser Public License for more details. + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="name"> + <field-validator type="requiredstring"> + <message>pet.name.required</message> + </field-validator> + </field> + +</validators> diff --git a/src/test/resources/org/nuiton/validator/xwork2/field/FieldExpressionBean-error-validation.xml b/src/test/resources/org/nuiton/validator/xwork2/field/FieldExpressionBean-error-validation.xml new file mode 100644 index 0000000..fb98fe5 --- /dev/null +++ b/src/test/resources/org/nuiton/validator/xwork2/field/FieldExpressionBean-error-validation.xml @@ -0,0 +1,122 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + +<field name="booleanValue"> + <field-validator type="fieldexpressionwithparams"> + <param name="booleanParams">boolean:true</param> + <param name="expression"><![CDATA[ booleanValue == booleans.boolean]]> + </param> + <message>expression.boolean.not.equals##${booleans.boolean}</message> + </field-validator> + <field-validator type="fieldexpressionwithparams"> + <param name="booleanParams">boolean:false</param> + <param name="expression"><![CDATA[ booleanValue == booleans.boolean]]> + </param> + <message>expression.boolean.not.equals##${booleans.boolean}</message> + </field-validator> + </field> + + <field name="shortValue"> + <field-validator type="fieldexpressionwithparams"> + <param name="shortParams">short:100</param> + <param name="expression"><![CDATA[ shortValue < shorts.short]]> + </param> + <message>expression.too.big##${shorts.short}</message> + </field-validator> + <field-validator type="fieldexpressionwithparams"> + <param name="shortParams">short:100|short2:2000</param> + <param name="expression"><![CDATA[ shortValue < shorts.short || shortValue < shorts.short2]]> + </param> + <message>expression.too.big##${shorts.short}##${shorts.short2}</message> + </field-validator> + </field> + + <field name="intValue"> + <field-validator type="fieldexpressionwithparams"> + <param name="intParams">int:100</param> + <param name="expression"><![CDATA[ intValue < ints.int]]> + </param> + <message>expression.too.big##${ints.int}</message> + </field-validator> + <field-validator type="fieldexpressionwithparams"> + <param name="intParams">int:100|int2:2000</param> + <param name="expression"><![CDATA[ intValue < ints.int || intValue < ints.int2]]> + </param> + <message>expression.too.big##${ints.int}##${ints.int2}</message> + </field-validator> + </field> + + <field name="longValue"> + <field-validator type="fieldexpressionwithparams"> + <param name="longParams">long:100</param> + <param name="expression"><![CDATA[ longValue < longs.long]]> + </param> + <message>expression.too.big##${longs.long}</message> + </field-validator> + <field-validator type="fieldexpressionwithparams"> + <param name="longParams">long:100|long2:2000</param> + <param name="expression"><![CDATA[ longValue < longs.long || longValue < longs.long2]]> + </param> + <message>expression.too.big##${longs.long}##${longs.long2}</message> + </field-validator> + </field> + + <field name="doubleValue"> + <field-validator type="fieldexpressionwithparams"> + <param name="doubleParams">double:100.0</param> + <param name="expression"><![CDATA[ doubleValue < doubles.double]]> + </param> + <message>expression.too.big##${doubles.double}</message> + </field-validator> + <field-validator type="fieldexpressionwithparams"> + <param name="doubleParams">double:100.0|double2:2000.0</param> + <param name="expression"><![CDATA[ doubleValue < doubles.double || doubleValue < doubles.double2]]> + </param> + <message>expression.too.big##${doubles.double}##${doubles.double2}</message> + </field-validator> + </field> + + <field name="stringValue"> + <field-validator type="fieldexpressionwithparams"> + <param name="stringParams">string:1000</param> + <param name="expression"><![CDATA[ stringValue.equals(strings.string)]]> + </param> + <message>expression.stringNotValue##${strings.string}</message> + </field-validator> + <field-validator type="fieldexpressionwithparams"> + <param name="stringParams">string:1000|string2:3000</param> + <param name="expression"><![CDATA[ stringValue.equals(strings.string) || stringValue.equals(strings.string2)]]> + </param> + <message>expression.stringNotValue##${strings.string}##${strings.string2}</message> + </field-validator> + </field> + + + + +</validators> diff --git a/src/test/resources/org/nuiton/validator/xwork2/field/ValidatorBean-error-validation.xml b/src/test/resources/org/nuiton/validator/xwork2/field/ValidatorBean-error-validation.xml new file mode 100644 index 0000000..cc2958b --- /dev/null +++ b/src/test/resources/org/nuiton/validator/xwork2/field/ValidatorBean-error-validation.xml @@ -0,0 +1,177 @@ +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="stringValue"> + <field-validator type="requiredstring" short-circuit="true"> + <message>stringValue.required</message> + </field-validator> + </field> + + <field name="existingFile"> + <field-validator type="requiredFile" short-circuit="true"> + <message>existingFile.required</message> + </field-validator> + <field-validator type="existingFile" short-circuit="true"> + <message>existingFile.not.exist</message> + </field-validator> + </field> + + <field name="notExistingFile"> + <field-validator type="requiredFile" short-circuit="true"> + <message>notExistingFile.required</message> + </field-validator> + <field-validator type="notExistingFile" short-circuit="true"> + <message>notExistingFile.exist</message> + </field-validator> + </field> + + <field name="existingDirectory"> + <field-validator type="requiredFile" short-circuit="true"> + <message>existingDirectory.required</message> + </field-validator> + + <field-validator type="existingDirectory" short-circuit="true"> + <message>existingDirectory.not.exist</message> + </field-validator> + </field> + + <field name="notExistingDirectory"> + <field-validator type="requiredFile" short-circuit="true"> + <message>notExistingDirectory.required</message> + </field-validator> + + <field-validator type="notExistingDirectory" short-circuit="true"> + <message>notExistingDirectory.exist</message> + </field-validator> + </field> + + <field name="entries"> + + <field-validator type="collectionUniqueKey"> + <param name="keys">intValue</param> + <message>collectionUniqueKey.one.failed</message> + </field-validator> + <field-validator type="collectionUniqueKey"> + <param name="keys">stringValue</param> + <message>collectionUniqueKey.two.failed</message> + </field-validator> + <field-validator type="collectionUniqueKey"> + <param name="keys">intValue,stringValue</param> + <message>collectionUniqueKey.three.failed</message> + </field-validator> + <field-validator type="collectionUniqueKey"> + <param name="keys">intValue,stringValue,stringValue2</param> + <message>collectionUniqueKey.four.failed</message> + </field-validator> + <field-validator type="collectionUniqueKey"> + <param name="keys">stringValue</param> + <param name="againstProperty">entry</param> + <message>collectionUniqueKey.five.failed</message> + </field-validator> + + <field-validator type="collectionFieldExpression"> + <param name="mode">AT_LEAST_ONE</param> + <param name="expression"><![CDATA[ intValue == 0 && stringValue == "stringValue" ]]> + </param> + <message>collectionFieldExpression.atLeastOne</message> + </field-validator> + <field-validator type="collectionFieldExpression"> + <param name="mode">EXACTLY_ONE</param> + <param name="expression"><![CDATA[ intValue == 0 && stringValue == "stringValue" ]]> + </param> + <message>collectionFieldExpression.exactlyOne</message> + </field-validator> + <field-validator type="collectionFieldExpression"> + <param name="mode">ALL</param> + <param name="expression"><![CDATA[ intValue == 0 && stringValue == "stringValue" ]]> + </param> + <message>collectionFieldExpression.all</message> + </field-validator> + <field-validator type="collectionFieldExpression"> + <param name="mode">NONE</param> + <param name="expression"><![CDATA[ intValue == 0 && stringValue == "stringValue" ]]> + </param> + <message>collectionFieldExpression.none</message> + </field-validator> + + <!-- useContext --> + <field-validator type="collectionFieldExpression"> + <param name="mode">AT_LEAST_ONE</param> + <param name="useSensitiveContext">true</param> + <param name="expression"><![CDATA[ size > 1 && previous != null && previous.intValue < current.intValue]]></param> + <message>collectionFieldExpression.atLeastOne.useSensitiveContext</message> + </field-validator> + <field-validator type="collectionFieldExpression"> + <param name="mode">EXACTLY_ONE</param> + <param name="useSensitiveContext">true</param> + <param name="expression"><![CDATA[ size > 1 && previous != null && ( previous.intValue == 2 + current.intValue || current.intValue == 2 + previous.intValue) ]]></param> + <message>collectionFieldExpression.exactlyOne.useSensitiveContext</message> + </field-validator> + <field-validator type="collectionFieldExpression"> + <param name="mode">ALL</param> + <param name="useSensitiveContext">true</param> + <param name="expression"><![CDATA[ size > 1 && (previous == null || previous.intValue < current.intValue)]]></param> + <message>collectionFieldExpression.all.useSensitiveContext</message> + </field-validator> + <field-validator type="collectionFieldExpression"> + <param name="mode">NONE</param> + <param name="useSensitiveContext">true</param> + <param name="expression"><![CDATA[ size > 1 && previous != null && ( current.intValue == 2 + previous.intValue)]]></param> + <message>collectionFieldExpression.none.useSensitiveContext</message> + </field-validator> + + <!-- useFirst --> + <field-validator type="collectionFieldExpression"> + <param name="mode">ALL</param> + <param name="useSensitiveContext">true</param> + <param name="expressionForFirst"><![CDATA[ current.intValue == 0]]></param> + <param name="expression"><![CDATA[ previous == null || previous.intValue < current.intValue]]></param> + <message>collectionFieldExpression.all.useFirst</message> + </field-validator> + + <!-- useLast --> + <field-validator type="collectionFieldExpression"> + <param name="mode">ALL</param> + <param name="useSensitiveContext">true</param> + <param name="expressionForLast"><![CDATA[ current.intValue > 0]]></param> + <param name="expression"><![CDATA[ previous == null || previous.intValue < current.intValue]]></param> + <message>collectionFieldExpression.all.useLast</message> + </field-validator> + + <!-- useFirstAndLast --> + <field-validator type="collectionFieldExpression"> + <param name="mode">ALL</param> + <param name="useSensitiveContext">true</param> + <param name="expressionForFirst"><![CDATA[ current.intValue == 0]]></param> + <param name="expressionForLast"><![CDATA[ current.intValue > 0]]></param> + <param name="expression"><![CDATA[ previous == null || previous.intValue < current.intValue]]></param> + <message>collectionFieldExpression.all.useFirstAndLast</message> + </field-validator> + + </field> + +</validators> diff --git a/src/test/resources/validators.xml b/src/test/resources/validators.xml new file mode 100644 index 0000000..83c3b73 --- /dev/null +++ b/src/test/resources/validators.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + #%L + Nuiton Validator + $Id$ + $HeadURL$ + %% + Copyright (C) 2011 CodeLutin, Tony Chemit + %% + This program 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 3 of the + License, or (at your option) any later version. + + This program 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> + +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator Config 1.0//EN" + "http://struts.apache.org/dtds/xwork-validator-config-1.0.dtd"> +<validators> + <!-- default validators from XWork framework --> + <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/> + <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/> + <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/> + <validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/> + <validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/> + <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/> + <validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/> + <validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/> + <validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/> + <validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/> + <validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/> + <validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/> + <validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/> + <validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/> + <validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/> + <validator name="conditionalvisitor" + class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/> + + <!-- default nuiton-validator validators --> + <validator name="collectionFieldExpression" class="org.nuiton.validator.xwork2.field.CollectionFieldExpressionValidator"/> + <validator name="collectionUniqueKey" class="org.nuiton.validator.xwork2.field.CollectionUniqueKeyValidator"/> + + <!-- io validators --> + <validator name="requiredFile" class="org.nuiton.validator.xwork2.field.RequiredFileFieldValidator"/> + <validator name="existingFile" class="org.nuiton.validator.xwork2.field.ExistingFileFieldValidator"/> + <validator name="notExistingFile" class="org.nuiton.validator.xwork2.field.NotExistingFileFieldValidator"/> + <validator name="existingDirectory" class="org.nuiton.validator.xwork2.field.ExistingDirectoryFieldValidator"/> + <validator name="notExistingDirectory" class="org.nuiton.validator.xwork2.field.NotExistingDirectoryFieldValidator"/> + <validator name="fieldexpressionwithparams" class="org.nuiton.validator.xwork2.field.FieldExpressionWithParamsValidator"/> + + <!-- much much better email validator :) --> + <validator name="emailNuiton" class="org.nuiton.validator.xwork2.field.EmailFieldValidator"/> + + <!-- french specific validators --> + <validator name="frenchPhoneNumber" class="org.nuiton.validator.xwork2.field.FrenchPhoneNumberFieldValidator"/> + <validator name="frenchCityName" class="org.nuiton.validator.xwork2.field.FrenchCityNameFieldValidator"/> + <validator name="frenchLastName" class="org.nuiton.validator.xwork2.field.FrenchLastNameFieldValidator"/> + <validator name="frenchPostCode" class="org.nuiton.validator.xwork2.field.FrenchPostCodeFieldValidator"/> + <validator name="frenchSiret" class="org.nuiton.validator.xwork2.field.FrenchSiretFieldValidator"/> + <validator name="frenchFiness" class="org.nuiton.validator.xwork2.field.FrenchFinessFieldValidator"/> + + <!-- eu specific validators --> + <validator name="vatIdentificationNumber" class="org.nuiton.validator.xwork2.field.VATIdentificationNumberFieldValidator"/> + +</validators> -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.