r2599 - in trunk/src: main/java/org/nuiton/validator/xwork2/field test/java/org/nuiton/validator/model test/java/org/nuiton/validator/xwork2/field test/resources test/resources/org/nuiton/validator/model
Author: Bavencoff Date: 2013-08-08 15:12:30 +0200 (Thu, 08 Aug 2013) New Revision: 2599 Url: http://nuiton.org/projects/nuiton-validator/repository/revisions/2599 Log: Add French SIREN validator. Move Luhn checksum in FrenchSiretFieldValidator to FieldValidatorUtil add Luhn checksum in FrenchFinessValidator Added: trunk/src/main/java/org/nuiton/validator/xwork2/field/FieldValidatorUtil.java trunk/src/main/java/org/nuiton/validator/xwork2/field/FrenchSirenFieldValidator.java trunk/src/test/java/org/nuiton/validator/xwork2/field/FieldValidatorUtilTest.java trunk/src/test/java/org/nuiton/validator/xwork2/field/FrenchSirenFieldValidatorTest.java Modified: trunk/src/main/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidator.java trunk/src/main/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidator.java trunk/src/test/java/org/nuiton/validator/model/Company.java trunk/src/test/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidatorTest.java trunk/src/test/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidatorTest.java trunk/src/test/resources/org/nuiton/validator/model/Company-error-validation.xml trunk/src/test/resources/validators.xml Added: trunk/src/main/java/org/nuiton/validator/xwork2/field/FieldValidatorUtil.java =================================================================== --- trunk/src/main/java/org/nuiton/validator/xwork2/field/FieldValidatorUtil.java (rev 0) +++ trunk/src/main/java/org/nuiton/validator/xwork2/field/FieldValidatorUtil.java 2013-08-08 13:12:30 UTC (rev 2599) @@ -0,0 +1,99 @@ +package org.nuiton.validator.xwork2.field; + +/** + * Util tool for Field validator + * <p/> + * + * + * @author Sylvain Bavencoff <bavencoff@codelutin.com> + * @since 3.0 + * + */ + +/** + * @author Sylvain Bavencoff <bavencoff@codelutin.com> + */ +public class FieldValidatorUtil { + + /** + * 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 value une chaine composer que de chiffre + * @return vrai si on a reussi a valider le numero + */ + public static boolean luhnChecksum(String value) { + + char[] tab = value.toCharArray(); + int sum = 0; + + // on multiple alternativement par 1 ou par 2 les chiffres + // sachant que le chiffre le plus à droite est multiplié par 1 + + // l'offset permet de savoir si le premier chiffre( le plus a gauche) doit etre + // multiplier par 1 ( offset = 0) + // multiplier par 2 (offset = 1) + int offset = (tab.length + 1) % 2; + + + for (int i = 0; i < tab.length; i++) { + + // recuperation de la valeur + int n = getDigit(tab[i]); + + // multiplication par 1 ou 2 en fonction de l'index et de l'offset + n *= (i + offset) % 2 + 1; + + // 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' => 1 a 'Z' => 36, + * les autres caractere sont aussi convertis pour que + * A|B|C|D|E|F|G|H|I|J + * K|L|M|N|O|P|Q|R|S|T + * U|V|W|X|Y|Z| | | | + * -+-+-+-+-+-+-+-+-+ + * 1|2|3|4|5|6|7|8|9|0. + * 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' + 1) % 10; + } else { + result = (c - 'a' + 1) % 10; + } + return result; + } +} Modified: trunk/src/main/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidator.java =================================================================== --- trunk/src/main/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidator.java 2013-07-23 15:54:55 UTC (rev 2598) +++ trunk/src/main/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidator.java 2013-08-08 13:12:30 UTC (rev 2599) @@ -37,9 +37,9 @@ */ public class FrenchFinessFieldValidator extends NuitonFieldValidatorSupport { - protected static final String SIRET_REGEXP = "([0-9]{2}|2A|2B)0([0-9]{6})"; + protected static final String FINESS_REGEXP = "(0[1-9]|[1-9][0-9]|2A|2B)0([0-9]{6})"; - protected static final Pattern p = Pattern.compile(SIRET_REGEXP); + protected static final Pattern p = Pattern.compile(FINESS_REGEXP); @Override protected void validateWhenNotSkip(Object object) throws ValidationException { @@ -80,7 +80,7 @@ finess = finess.replaceAll(" ", ""); Matcher m = p.matcher(finess); - if (!m.matches()) { + if (!m.matches() || ! FieldValidatorUtil.luhnChecksum(finess)) { addFieldError(fieldName, object); } } Added: trunk/src/main/java/org/nuiton/validator/xwork2/field/FrenchSirenFieldValidator.java =================================================================== --- trunk/src/main/java/org/nuiton/validator/xwork2/field/FrenchSirenFieldValidator.java (rev 0) +++ trunk/src/main/java/org/nuiton/validator/xwork2/field/FrenchSirenFieldValidator.java 2013-08-08 13:12:30 UTC (rev 2599) @@ -0,0 +1,80 @@ +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 SIREN numbers + * <p/> + * Siret can be in: + * <li>String format: "442116703" + * <li>long, int: 442116703 + * <li>Array or Collection of something: [4,4,2,1,1,6,7,0,,3] or ["442","116","70", "3"] + * + * @author ylvain Bavencoff <bavencoff@codelutin.com> + * @since 3.0 + * Validation do the Luhn checksum too + */ + +public class FrenchSirenFieldValidator extends NuitonFieldValidatorSupport { + + protected static final String SIREN_REGEXP = "[0-9]{9}"; + + protected static final Pattern p = Pattern.compile(SIREN_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 siren; + + if (value.getClass().isArray()) { + // le siren est stocker dans un tableau, par exemple un byte[] + siren = ""; + for (int i = 0; i < Array.getLength(value); i++) { + siren += String.valueOf(Array.get(value, i)); + } + } else if (value instanceof Collection<?>) { + // le siren est stocker dans une collection, + // ca doit pas arriver souvent :D, mais autant le gerer + siren = ""; + for (Object o : (Collection<?>) value) { + siren += String.valueOf(o); + } + } else { + // sinon dans tous les autres cas (String, int, long, BigInteger ...) + // on prend le toString + siren = String.valueOf(value); + } + + if (StringUtils.isEmpty(siren)) { + // no value defined + return; + } + + // Remove any space + siren = siren.replaceAll(" ", ""); + + Matcher m = p.matcher(siren); + if (!m.matches() || ! FieldValidatorUtil.luhnChecksum(siren)) { + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "frenchSiret"; + } + +} Modified: trunk/src/main/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidator.java =================================================================== --- trunk/src/main/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidator.java 2013-07-23 15:54:55 UTC (rev 2598) +++ trunk/src/main/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidator.java 2013-08-08 13:12:30 UTC (rev 2599) @@ -89,7 +89,7 @@ siret = siret.replaceAll(" ", ""); Matcher m = p.matcher(siret); - if (!m.matches() || !luhnChecksum(siret)) { + if (!m.matches() || ! FieldValidatorUtil.luhnChecksum(siret)) { addFieldError(fieldName, object); } } @@ -99,78 +99,4 @@ 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; - } } Modified: trunk/src/test/java/org/nuiton/validator/model/Company.java =================================================================== --- trunk/src/test/java/org/nuiton/validator/model/Company.java 2013-07-23 15:54:55 UTC (rev 2598) +++ trunk/src/test/java/org/nuiton/validator/model/Company.java 2013-08-08 13:12:30 UTC (rev 2599) @@ -33,10 +33,14 @@ public static final String PROPERTY_SIRET = "siret"; + public static final String PROPERTY_SIREN = "siren"; + protected String vat; protected String siret; + protected String siren; + public String getVat() { return vat; } @@ -52,4 +56,12 @@ public void setSiret(String siret) { this.siret = siret; } + + public String getSiren() { + return siren; + } + + public void setSiren(String siren) { + this.siren = siren; + } } Added: trunk/src/test/java/org/nuiton/validator/xwork2/field/FieldValidatorUtilTest.java =================================================================== --- trunk/src/test/java/org/nuiton/validator/xwork2/field/FieldValidatorUtilTest.java (rev 0) +++ trunk/src/test/java/org/nuiton/validator/xwork2/field/FieldValidatorUtilTest.java 2013-08-08 13:12:30 UTC (rev 2599) @@ -0,0 +1,25 @@ +package org.nuiton.validator.xwork2.field; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author Sylvain Bavencoff <bavencoff@codelutin.com> + */ +public class FieldValidatorUtilTest extends Assert { + + @Test + public void TestLuhnChecksum() throws Exception { + // verification sur de vrai numero siret (ca doit passer :) + assertTrue(FieldValidatorUtil.luhnChecksum("44211670300038")); + assertTrue(FieldValidatorUtil.luhnChecksum("73282932000074")); + assertTrue(FieldValidatorUtil.luhnChecksum("2A0002879")); + + // verification avec les memes, en ne modifiant que le dernier chiffre + // ca doit failer + assertFalse(FieldValidatorUtil.luhnChecksum("44211670300030")); + assertFalse(FieldValidatorUtil.luhnChecksum("73282932000070")); + assertFalse(FieldValidatorUtil.luhnChecksum("2A0002870")); + } + +} Modified: trunk/src/test/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidatorTest.java =================================================================== --- trunk/src/test/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidatorTest.java 2013-07-23 15:54:55 UTC (rev 2598) +++ trunk/src/test/java/org/nuiton/validator/xwork2/field/FrenchFinessFieldValidatorTest.java 2013-08-08 13:12:30 UTC (rev 2599) @@ -42,13 +42,23 @@ assertNull(bean.getFiness()); // Valid Finess - bean.setFiness("440123456"); + bean.setFiness("440012664"); assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", false); // Valid Finess - bean.setFiness("2B0483714"); + bean.setFiness("310001177"); assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", + false); + + // Valid Finess + bean.setFiness("2A0002879"); + assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", + false); + + // Valid Finess + bean.setFiness("2B0000236"); + assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", false); // not Valid Finess @@ -67,7 +77,7 @@ true); // not Valid Finess - bean.setFiness("441123456"); + bean.setFiness("000123456"); assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", true); @@ -81,5 +91,10 @@ assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", true); + // not Valid Finess + bean.setFiness("440012666"); + assertFieldInError(HealthEstablishment.PROPERTY_FINESS, "healthEstablishment.finess.format", + true); + } } Added: trunk/src/test/java/org/nuiton/validator/xwork2/field/FrenchSirenFieldValidatorTest.java =================================================================== --- trunk/src/test/java/org/nuiton/validator/xwork2/field/FrenchSirenFieldValidatorTest.java (rev 0) +++ trunk/src/test/java/org/nuiton/validator/xwork2/field/FrenchSirenFieldValidatorTest.java 2013-08-08 13:12:30 UTC (rev 2599) @@ -0,0 +1,67 @@ +package org.nuiton.validator.xwork2.field; + +import org.junit.Test; +import org.nuiton.validator.model.Company; + +/** + * @author Sylvain Bavencoff <bavencoff@codelutin.com> + */ +public class FrenchSirenFieldValidatorTest extends AbstractFieldValidatorTest<Company> { + + public FrenchSirenFieldValidatorTest() { + super(Company.class); + } + + @Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getSiren()); + + // Valid siren + bean.setSiren("751700782"); + assertFieldInError(Company.PROPERTY_SIREN, "company.siren.format", + false); + + // Valid siren + bean.setSiren("263903007"); + assertFieldInError(Company.PROPERTY_SIREN, "company.siren.format", + false); + + // Not Valid siren, because bad checksum + bean.setSiren("263903000"); + assertFieldInError(Company.PROPERTY_SIREN, "company.siren.format", + true); + + // Not valid siren + bean.setSiren("44211670"); + assertFieldInError(Company.PROPERTY_SIREN, "company.siren.format", + true); + + // Not valid siren + bean.setSiren("442116703000389"); + assertFieldInError(Company.PROPERTY_SIREN, "company.siren.format", + true); + + // Not valid siren + bean.setSiren("4421bf167"); + assertFieldInError(Company.PROPERTY_SIREN, "company.siren.format", + true); + + // Use requiredString for empty siren + bean.setSiren(""); + assertFieldInError(Company.PROPERTY_SIREN, "company.siren.format", + false); + + // Use required for null siren + bean.setSiren(null); + assertFieldInError(Company.PROPERTY_SIREN, "company.siren.format", + false); + + // Valid siren with spaces + bean.setSiren("535 198 188 "); + assertFieldInError(Company.PROPERTY_SIREN, "company.siren.format", + false); + + } +} \ No newline at end of file Modified: trunk/src/test/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidatorTest.java =================================================================== --- trunk/src/test/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidatorTest.java 2013-07-23 15:54:55 UTC (rev 2598) +++ trunk/src/test/java/org/nuiton/validator/xwork2/field/FrenchSiretFieldValidatorTest.java 2013-08-08 13:12:30 UTC (rev 2599) @@ -37,18 +37,6 @@ } @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 { Modified: trunk/src/test/resources/org/nuiton/validator/model/Company-error-validation.xml =================================================================== --- trunk/src/test/resources/org/nuiton/validator/model/Company-error-validation.xml 2013-07-23 15:54:55 UTC (rev 2598) +++ trunk/src/test/resources/org/nuiton/validator/model/Company-error-validation.xml 2013-08-08 13:12:30 UTC (rev 2599) @@ -32,6 +32,12 @@ </field-validator> </field> + <field name="siren"> + <field-validator type="frenchSiren"> + <message>company.siren.format</message> + </field-validator> + </field> + <field name="vat"> <field-validator type="vatIdentificationNumber"> <message>company.vat.format</message> Modified: trunk/src/test/resources/validators.xml =================================================================== --- trunk/src/test/resources/validators.xml 2013-07-23 15:54:55 UTC (rev 2598) +++ trunk/src/test/resources/validators.xml 2013-08-08 13:12:30 UTC (rev 2599) @@ -67,6 +67,7 @@ <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="frenchSiren" class="org.nuiton.validator.xwork2.field.FrenchSirenFieldValidator"/> <validator name="frenchFiness" class="org.nuiton.validator.xwork2.field.FrenchFinessFieldValidator"/> <!-- eu specific validators -->
participants (1)
-
Bavencoff@users.nuiton.org