diff --git a/Documentation_fichier_Yaml.md b/Documentation_fichier_Yaml.md index 733ed2fe46622e626bd199356fd7d50615d6be1a..d5fd3b58bc67d83c09943617a3e8e3330b150eb0 100644 --- a/Documentation_fichier_Yaml.md +++ b/Documentation_fichier_Yaml.md @@ -339,7 +339,6 @@ Pour les checkers GroovyExpression, on récupère dans le script des information -> datatypes.get("nom du datatype").getValues().get("nom de la variable").get("nom du composant") datatypesValues : idem que datatypes -> datatypesValues.get("nom du datatype").get("nom de la variable").get("nom du composant") - params : la section params dans laquelle on peut rajouter des information que l'on souhaite utiliser dans le script.. ``` yaml @@ -354,12 +353,6 @@ Pour les checkers GroovyExpression, on récupère dans le script des information .find{it.get("nom de la variable").equals(params.get("codeVariable"))} .get("nom de l'unité").equals(datum.get(params.get("variable")).get(params.get("component"))); references: variables_et_unites_par_types_de_donnees - datatype: "piegeage_en_montee" - variable: "Nombre d'individus" - codeVariable: nombre_d_individus - component: unit - - ``` Cette formulation vérifie que la valeur du component qualité de la variable SWC est vide ou égale à 0,1 ou 2 L'expression doit renvoyer true diff --git a/src/main/java/fr/inra/oresing/checker/CheckerFactory.java b/src/main/java/fr/inra/oresing/checker/CheckerFactory.java index ca8617e0d62f7740664d62bac7a01df14c1b4bce..cce2221f53684c8e7459f49d6f5c80a1ac7b6244 100644 --- a/src/main/java/fr/inra/oresing/checker/CheckerFactory.java +++ b/src/main/java/fr/inra/oresing/checker/CheckerFactory.java @@ -24,9 +24,12 @@ import java.util.stream.Stream; @Slf4j public class CheckerFactory { + @Deprecated public static final String COLUMNS = "columns"; + + @Deprecated public static final String VARIABLE_COMPONENT_KEY = "variableComponentKey"; - public static final String REQUIRED = "required"; + @Autowired private OreSiRepository repository; @@ -85,18 +88,21 @@ public class CheckerFactory { CheckerTarget checkerTarget = CheckerTarget.getInstance(variableComponentKey, app, repository.getRepository(app)); if ("Reference".equals(checkerDescription.getName())) { variableComponentChecker = getCheckerOnReferenceChecker(app, dataType, locale, checkerDescription, checkerTarget); - } else if ("Date".equals(checkerDescription.getName())) { - String pattern = checkerDescription.getParams().get(DateLineChecker.PARAM_PATTERN); - variableComponentChecker = new DateLineChecker(checkerTarget, pattern, checkerDescription.getParams()); - } else if ("Integer".equals(checkerDescription.getName())) { - variableComponentChecker = new IntegerChecker(checkerTarget, checkerDescription.getParams()); - } else if ("Float".equals(checkerDescription.getName())) { - variableComponentChecker = new FloatChecker(checkerTarget, checkerDescription.getParams()); - } else if ("RegularExpression".equals(checkerDescription.getName())) { - String pattern = checkerDescription.getParams().get(RegularExpressionChecker.PARAM_PATTERN); - variableComponentChecker = new RegularExpressionChecker(checkerTarget, pattern, checkerDescription.getParams()); } else { - throw new IllegalArgumentException("checker inconnu " + checkerDescription.getName()); + final Configuration.CheckerConfigurationDescription configuration = checkerDescription.getParams(); + if ("Date".equals(checkerDescription.getName())) { + String pattern = configuration.getPattern(); + variableComponentChecker = new DateLineChecker(checkerTarget, pattern, configuration); + } else if ("Integer".equals(checkerDescription.getName())) { + variableComponentChecker = new IntegerChecker(checkerTarget, configuration); + } else if ("Float".equals(checkerDescription.getName())) { + variableComponentChecker = new FloatChecker(checkerTarget, configuration); + } else if ("RegularExpression".equals(checkerDescription.getName())) { + String pattern = configuration.getPattern(); + variableComponentChecker = new RegularExpressionChecker(checkerTarget, pattern, configuration); + } else { + throw new IllegalArgumentException("checker inconnu " + checkerDescription.getName()); + } } Preconditions.checkState(variableComponentChecker.getTarget().getTarget().equals(variableComponentKey)); checkersBuilder.add(variableComponentChecker); @@ -105,7 +111,7 @@ public class CheckerFactory { private CheckerOnOneVariableComponentLineChecker getCheckerOnReferenceChecker(Application app, String dataType, String locale, Configuration.CheckerDescription checkerDescription, CheckerTarget checkerTarget) { CheckerOnOneVariableComponentLineChecker variableComponentChecker; - String refType = checkerDescription.getParams().get(ReferenceLineChecker.PARAM_REFTYPE); + String refType = checkerDescription.getParams().getRefType(); ReferenceValueRepository referenceValueRepository = repository.getRepository(app).referenceValue(); ImmutableMap<String, UUID> referenceValues; ImmutableMap<String, String> display = null; @@ -151,16 +157,15 @@ public class CheckerFactory { Configuration.LineValidationRuleDescription lineValidationRuleDescription = validationEntry.getValue(); Configuration.CheckerDescription checkerDescription = lineValidationRuleDescription.getChecker(); LineChecker lineChecker; - Map<String, String> params = checkerDescription.getParams(); - String pattern; + Configuration.CheckerConfigurationDescription configurationDescription = checkerDescription.getParams(); if (GroovyLineChecker.NAME.equals(checkerDescription.getName())) { - String expression = params.get(GroovyLineChecker.PARAM_EXPRESSION); - lineChecker = GroovyLineChecker.forExpression(expression, app, repository.getRepository(app), params); + String expression = configurationDescription.getExpression(); + lineChecker = GroovyLineChecker.forExpression(expression, app, repository.getRepository(app), configurationDescription); checkersBuilder.add(lineChecker); } else { - List<CheckerTarget> checkerTargets = buildCheckerTarget(params, app); + List<CheckerTarget> checkerTargets = buildCheckerTarget(configurationDescription, app); if (checkerTargets != null) { - checkerTargets.forEach(checkerTarget -> buildCheckers(app, checkerDescription, params, checkerTarget, checkersBuilder)); + checkerTargets.forEach(checkerTarget -> buildCheckers(app, checkerDescription, checkerTarget, checkersBuilder)); } else { throw new IllegalArgumentException(String.format("Pour le checker de ligne %s, le paramètre %s doit être fourni.", checkerDescription.getName(), param)); } @@ -169,37 +174,35 @@ public class CheckerFactory { } } - private void buildCheckers(Application app, Configuration.CheckerDescription checkerDescription, Map<String, String> params, CheckerTarget target, ImmutableSet.Builder<LineChecker> checkersBuilder) { - String pattern; + private void buildCheckers(Application app, Configuration.CheckerDescription checkerDescription, CheckerTarget target, ImmutableSet.Builder<LineChecker> checkersBuilder) { + Configuration.CheckerConfigurationDescription checkerConfigurationDescription = checkerDescription.getParams(); switch (checkerDescription.getName()) { case "Date": - pattern = params.get(DateLineChecker.PARAM_PATTERN); - checkersBuilder.add(new DateLineChecker(target, pattern, params)); + checkersBuilder.add(new DateLineChecker(target, checkerConfigurationDescription.getPattern(), checkerConfigurationDescription)); break; case "Integer": - checkersBuilder.add(new IntegerChecker(target, params)); + checkersBuilder.add(new IntegerChecker(target, checkerConfigurationDescription)); break; case "Float": - checkersBuilder.add(new FloatChecker(target, params)); + checkersBuilder.add(new FloatChecker(target, checkerConfigurationDescription)); break; case "RegularExpression": - pattern = params.get(RegularExpressionChecker.PARAM_PATTERN); - checkersBuilder.add(new RegularExpressionChecker(target, pattern, params)); + checkersBuilder.add(new RegularExpressionChecker(target, checkerConfigurationDescription.getPattern(), checkerConfigurationDescription)); break; case "Reference": - String refType = checkerDescription.getParams().get(ReferenceLineChecker.PARAM_REFTYPE); + String refType = checkerConfigurationDescription.getRefType(); ReferenceValueRepository referenceValueRepository = repository.getRepository(app).referenceValue(); ImmutableMap<String, UUID> referenceValues = referenceValueRepository.getReferenceIdPerKeys(refType); - checkersBuilder.add(new ReferenceLineChecker(target, refType, referenceValues, null, params)); + checkersBuilder.add(new ReferenceLineChecker(target, refType, referenceValues, null, checkerConfigurationDescription)); break; default: throw new IllegalArgumentException("checker inconnu " + checkerDescription.getName()); } } - private List<CheckerTarget> buildCheckerTarget(Map<String, String> params, Application application) { - String columnsString = params.getOrDefault(COLUMNS, null); - String variableComponentKeyParam = params.getOrDefault(VARIABLE_COMPONENT_KEY, null); + private List<CheckerTarget> buildCheckerTarget(Configuration.CheckerConfigurationDescription params, Application application) { + String columnsString = params.getColumns(); + String variableComponentKeyParam = params.getVariableComponentKey(); if (!Strings.isNullOrEmpty(columnsString)) { return Stream.of(columnsString.split(",")) .map(column -> CheckerTarget.getInstance(column, application, repository.getRepository(application))) diff --git a/src/main/java/fr/inra/oresing/checker/CheckerOnOneVariableComponentLineChecker.java b/src/main/java/fr/inra/oresing/checker/CheckerOnOneVariableComponentLineChecker.java index 329f4d3d7361aada3dfbd502198261524839eb1a..301bd624e500e54ebe2c0a0f0c465648ff41a562 100644 --- a/src/main/java/fr/inra/oresing/checker/CheckerOnOneVariableComponentLineChecker.java +++ b/src/main/java/fr/inra/oresing/checker/CheckerOnOneVariableComponentLineChecker.java @@ -8,7 +8,7 @@ import fr.inra.oresing.rest.ValidationCheckResult; import java.util.Map; -public interface CheckerOnOneVariableComponentLineChecker extends LineChecker { +public interface CheckerOnOneVariableComponentLineChecker<C extends LineCheckerConfiguration> extends LineChecker<C> { CheckerTarget getTarget(); @@ -16,7 +16,7 @@ public interface CheckerOnOneVariableComponentLineChecker extends LineChecker { VariableComponentKey variableComponentKey = (VariableComponentKey) getTarget().getTarget(); String value = values.get(variableComponentKey); try { - ValidationCheckResult check = CheckerDecorator.check(values, value, getParams(), getTarget()); + ValidationCheckResult check = CheckerDecorator.check(values, value, getConfiguration(), getTarget()); if(ValidationLevel.WARN.equals(check.getLevel())){ value = check.getMessage(); }else{ @@ -32,7 +32,7 @@ public interface CheckerOnOneVariableComponentLineChecker extends LineChecker { default ValidationCheckResult checkReference(Map<String, String> values) { String value = values.get(getTarget().getTarget()); try { - ValidationCheckResult check = CheckerDecorator.check(values, value, getParams(), getTarget()); + ValidationCheckResult check = CheckerDecorator.check(values, value, getConfiguration(), getTarget()); if(ValidationLevel.WARN.equals(check.getLevel())){ value = check.getMessage(); }else{ @@ -44,9 +44,5 @@ public interface CheckerOnOneVariableComponentLineChecker extends LineChecker { return check(value); } - default Map<String, String> getParams(){ - return Map.of(); - } - ValidationCheckResult check(String value); } \ No newline at end of file diff --git a/src/main/java/fr/inra/oresing/checker/DateLineChecker.java b/src/main/java/fr/inra/oresing/checker/DateLineChecker.java index 8160a0a3c8a8fd97489c4dc29de8992719f92f23..191c59b1f1d59b067e9ebb6a42c11318de4ccb6a 100644 --- a/src/main/java/fr/inra/oresing/checker/DateLineChecker.java +++ b/src/main/java/fr/inra/oresing/checker/DateLineChecker.java @@ -8,15 +8,14 @@ import java.time.format.DateTimeParseException; import java.time.temporal.TemporalAccessor; import java.util.Map; -public class DateLineChecker implements CheckerOnOneVariableComponentLineChecker { +public class DateLineChecker implements CheckerOnOneVariableComponentLineChecker<DateLineCheckerConfiguration> { public static final String PARAM_PATTERN = "pattern"; - public static final String PARAM_DURATION = "duration"; public static final String PARAM_DATE_TIME_FORMATTER = "dateTimeFormatter"; public static final String PARAM_DATE = "date"; public static final String PATTERN_DATE_REGEXP = "^date:.{19}:"; private final CheckerTarget target; - private final Map<String, String> params; + private final DateLineCheckerConfiguration configuration; public CheckerTarget getTarget(){ return this.target; @@ -29,8 +28,8 @@ public class DateLineChecker implements CheckerOnOneVariableComponentLineChecker return formattedDate.replaceAll(PATTERN_DATE_REGEXP, ""); } - public DateLineChecker(CheckerTarget target, String pattern, Map<String, String> params) { - this.params = params; + public DateLineChecker(CheckerTarget target, String pattern, DateLineCheckerConfiguration configuration) { + this.configuration = configuration; this.target = target; this.dateTimeFormatter = DateTimeFormatter.ofPattern(pattern); this.pattern = pattern; @@ -64,7 +63,7 @@ public class DateLineChecker implements CheckerOnOneVariableComponentLineChecker } @Override - public Map<String, String> getParams() { - return params; + public DateLineCheckerConfiguration getConfiguration() { + return configuration; } } \ No newline at end of file diff --git a/src/main/java/fr/inra/oresing/checker/DateLineCheckerConfiguration.java b/src/main/java/fr/inra/oresing/checker/DateLineCheckerConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..32d38cfe954a91f2b7807c69266e391f4b8088d4 --- /dev/null +++ b/src/main/java/fr/inra/oresing/checker/DateLineCheckerConfiguration.java @@ -0,0 +1,17 @@ +package fr.inra.oresing.checker; + +/** + * Configuration pour un checker de type "Date" + */ +public interface DateLineCheckerConfiguration extends LineCheckerConfiguration { + + /** + * Le format dans lequel doit être la la date qui sera validée (par exemple, "dd/MM/yyyy") + */ + String getPattern(); + + /** + * La {@link fr.inra.oresing.model.Duration} pour cette donnée. + */ + String getDuration(); +} diff --git a/src/main/java/fr/inra/oresing/checker/FloatChecker.java b/src/main/java/fr/inra/oresing/checker/FloatChecker.java index 07d6ee26ab0ae6a317f83576041ba6992feaded3..1af380c99fa2ac9ebecccfe77699d7410d322689 100644 --- a/src/main/java/fr/inra/oresing/checker/FloatChecker.java +++ b/src/main/java/fr/inra/oresing/checker/FloatChecker.java @@ -4,18 +4,17 @@ import com.google.common.collect.ImmutableMap; import fr.inra.oresing.rest.DefaultValidationCheckResult; import fr.inra.oresing.rest.ValidationCheckResult; -import java.util.Map; - -public class FloatChecker implements CheckerOnOneVariableComponentLineChecker { +public class FloatChecker implements CheckerOnOneVariableComponentLineChecker<FloatCheckerConfiguration> { private final CheckerTarget target; - private final Map<String, String> params; + private final FloatCheckerConfiguration configuration; public CheckerTarget getTarget(){ return this.target; } - public FloatChecker(CheckerTarget target, Map<String, String> params) { - this.params = params;this.target = target; + public FloatChecker(CheckerTarget target, FloatCheckerConfiguration configuration) { + this.target = target; + this.configuration = configuration; } @Override @@ -34,7 +33,7 @@ public class FloatChecker implements CheckerOnOneVariableComponentLineChecker { } @Override - public Map<String, String> getParams() { - return params; + public FloatCheckerConfiguration getConfiguration() { + return configuration; } } \ No newline at end of file diff --git a/src/main/java/fr/inra/oresing/checker/FloatCheckerConfiguration.java b/src/main/java/fr/inra/oresing/checker/FloatCheckerConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..34bfa14f7c520d317d5153ccca5e905c9f9709fb --- /dev/null +++ b/src/main/java/fr/inra/oresing/checker/FloatCheckerConfiguration.java @@ -0,0 +1,7 @@ +package fr.inra.oresing.checker; + +/** + * Configuration pour un checker de type nombre à virgule + */ +public interface FloatCheckerConfiguration extends LineCheckerConfiguration { +} diff --git a/src/main/java/fr/inra/oresing/checker/GroovyLineChecker.java b/src/main/java/fr/inra/oresing/checker/GroovyLineChecker.java index 6b551b48be1deeb107d0c680aaeb8236565b9093..8bdb02b762ba3a594be6c03294240cd56a0153d1 100644 --- a/src/main/java/fr/inra/oresing/checker/GroovyLineChecker.java +++ b/src/main/java/fr/inra/oresing/checker/GroovyLineChecker.java @@ -1,9 +1,11 @@ package fr.inra.oresing.checker; import com.google.common.collect.ImmutableMap; +import fr.inra.oresing.checker.decorators.DecoratorConfiguration; import fr.inra.oresing.groovy.BooleanGroovyExpression; import fr.inra.oresing.groovy.GroovyExpression; import fr.inra.oresing.model.Application; +import fr.inra.oresing.model.Configuration; import fr.inra.oresing.model.ReferenceValue; import fr.inra.oresing.model.VariableComponentKey; import fr.inra.oresing.persistence.DataRow; @@ -14,44 +16,62 @@ import fr.inra.oresing.rest.ValidationCheckResult; import java.util.*; -public class GroovyLineChecker implements LineChecker { +public class GroovyLineChecker implements LineChecker<GroovyLineCheckerConfiguration> { public static final String NAME = "GroovyExpression"; - public static final String PARAM_EXPRESSION = "expression"; - - public static final String PARAM_REFERENCES = "references"; - - public static final String PARAM_DATATYPES = "datatypes"; - private final BooleanGroovyExpression expression; private final Application application; private final OreSiRepository.RepositoryForApplication repository; - private Map<String, String> params = new HashMap<>(); + private final GroovyLineCheckerConfiguration configuration; - private GroovyLineChecker(BooleanGroovyExpression expression, Application app, OreSiRepository.RepositoryForApplication repository, Map<String, String> params) { + private GroovyLineChecker(BooleanGroovyExpression expression, Application app, OreSiRepository.RepositoryForApplication repository, GroovyLineCheckerConfiguration configuration) { this.expression = expression; this.application = app; this.repository = repository; - this.params = params; + this.configuration = configuration; } - public static GroovyLineChecker forExpression(String expression, Application app, OreSiRepository.RepositoryForApplication repository, Map<String, String> params) { + public static GroovyLineChecker forExpression(String expression, Application app, OreSiRepository.RepositoryForApplication repository, GroovyLineCheckerConfiguration configuration) { BooleanGroovyExpression groovyExpression = BooleanGroovyExpression.forExpression(expression); - return new GroovyLineChecker(groovyExpression, app, repository, params); + return new GroovyLineChecker(groovyExpression, app, repository, configuration); } public static Optional<GroovyExpression.CompilationError> validateExpression(String expression) { return GroovyExpression.validateExpression(expression); } - public static ImmutableMap<String, Object> buildContext(Object datum, Application application, Map<String, String> params, OreSiRepository.RepositoryForApplication repository) { + public static ImmutableMap<String, Object> buildContext(Object datum, Application application, DecoratorConfiguration params, OreSiRepository.RepositoryForApplication repository) { + Optional<String> configurationReferences = Optional.of(params) + .map(DecoratorConfiguration::getReferences); + Optional<String> configurationDataTypes = Optional.empty(); + ImmutableMap<String, Object> context = buildContext(datum, application, repository, configurationReferences, configurationDataTypes); + return context; + } + + public static ImmutableMap<String, Object> buildContext(Object datum, Application application, Configuration.VariableComponentDescriptionConfiguration params, OreSiRepository.RepositoryForApplication repository) { + Optional<String> configurationReferences = Optional.of(params) + .map(Configuration.VariableComponentDescriptionConfiguration::getReferences); + Optional<String> configurationDataTypes = Optional.empty(); + ImmutableMap<String, Object> context = buildContext(datum, application, repository, configurationReferences, configurationDataTypes); + return context; + } + + public static ImmutableMap<String, Object> buildContext(Object datum, Application application, GroovyLineCheckerConfiguration params, OreSiRepository.RepositoryForApplication repository) { + Optional<String> configurationReferences = Optional.of(params) + .map(GroovyLineCheckerConfiguration::getReferences); + Optional<String> configurationDataTypes = Optional.of(params) + .map(GroovyLineCheckerConfiguration::getDatatypes); + ImmutableMap<String, Object> context = buildContext(datum, application, repository, configurationReferences, configurationDataTypes); + return context; + } + + private static ImmutableMap<String, Object> buildContext(Object datum, Application application, OreSiRepository.RepositoryForApplication repository, Optional<String> configurationReferences, Optional<String> configurationDataTypes) { Map<String, List<ReferenceValue>> references = new HashMap<>(); Map<String, List<DataRow>> datatypes = new HashMap<>(); Map<String, List<Map<String, String>>> referencesValues = new HashMap<>(); Map<String, List<Map<String, Map<String, String>>>> datatypesValues = new HashMap<>(); - Optional.ofNullable(params) - .map(p -> p.get(PARAM_REFERENCES)) + configurationReferences .ifPresent(refs -> { Arrays.stream(refs.split(",")) .forEach(ref -> { @@ -63,8 +83,7 @@ public class GroovyLineChecker implements LineChecker { }); }); - Optional.ofNullable(params) - .map(p -> p.get(PARAM_DATATYPES)) + configurationDataTypes .ifPresent(datas -> { Arrays.stream(datas.split(",")) .forEach(dataType -> { @@ -91,10 +110,14 @@ public class GroovyLineChecker implements LineChecker { builder.put("referencesValues", referencesValues); builder.put("datatypes", datatypes); builder.put("datatypesValues", datatypesValues); - builder.put("params", Optional.ofNullable(params).orElseGet(HashMap::new)); return builder.build(); } + @Override + public GroovyLineCheckerConfiguration getConfiguration() { + return configuration; + } + public ValidationCheckResult check(Map<VariableComponentKey, String> datum) { Map<String, Map<String, String>> datumAsMap = new LinkedHashMap<>(); for (Map.Entry<VariableComponentKey, String> entry2 : datum.entrySet()) { @@ -103,13 +126,13 @@ public class GroovyLineChecker implements LineChecker { String value = entry2.getValue(); datumAsMap.computeIfAbsent(variable, k -> new LinkedHashMap<>()).put(component, value); } - Map<String, Object> context = buildContext(datumAsMap, application, params, repository); + Map<String, Object> context = buildContext(datumAsMap, application, configuration, repository); return evaluate(context); } @Override public ValidationCheckResult checkReference(Map<String, String> datum) { - Map<String, Object> context = buildContext(datum, application, params, repository); + Map<String, Object> context = buildContext(datum, application, configuration, repository); return evaluate(context); } diff --git a/src/main/java/fr/inra/oresing/checker/GroovyLineCheckerConfiguration.java b/src/main/java/fr/inra/oresing/checker/GroovyLineCheckerConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..6e6449febea1aaf9ebfcb0a707f590f8ab3923c7 --- /dev/null +++ b/src/main/java/fr/inra/oresing/checker/GroovyLineCheckerConfiguration.java @@ -0,0 +1,24 @@ +package fr.inra.oresing.checker; + +/** + * Configuration pour un checker de type "Expression Groovy" + */ +public interface GroovyLineCheckerConfiguration extends LineCheckerConfiguration { + + /** + * L'expression groovy elle-même. Elle doit retourner un booléen. + */ + String getExpression(); + + /** + * Les référentiels qui devront être chargés puis injectés dans le contexte au moment de + * l'évaluation de l'expression {@link #getExpression()} + */ + String getReferences(); + + /** + * Les types de données qui devront être chargées puis injectés dans le contexte au moment de + * l'évaluation de l'expression {@link #getExpression()} + */ + String getDatatypes(); +} diff --git a/src/main/java/fr/inra/oresing/checker/IntegerChecker.java b/src/main/java/fr/inra/oresing/checker/IntegerChecker.java index 32b7ed5330309aea759a2c66ae582c02466649db..c2f78f4bc1dcc6649198ec2a83229fad108d8a5b 100644 --- a/src/main/java/fr/inra/oresing/checker/IntegerChecker.java +++ b/src/main/java/fr/inra/oresing/checker/IntegerChecker.java @@ -4,18 +4,16 @@ import com.google.common.collect.ImmutableMap; import fr.inra.oresing.rest.DefaultValidationCheckResult; import fr.inra.oresing.rest.ValidationCheckResult; -import java.util.Map; - -public class IntegerChecker implements CheckerOnOneVariableComponentLineChecker { +public class IntegerChecker implements CheckerOnOneVariableComponentLineChecker<IntegerCheckerConfiguration> { private final CheckerTarget target; - private final Map<String, String> params; + private final IntegerCheckerConfiguration configuration; public CheckerTarget getTarget(){ return this.target; } - public IntegerChecker(CheckerTarget target, Map<String, String> params) { - this.params = params; + public IntegerChecker(CheckerTarget target, IntegerCheckerConfiguration configuration) { + this.configuration = configuration; this.target = target; } @@ -34,7 +32,7 @@ public class IntegerChecker implements CheckerOnOneVariableComponentLineChecker } @Override - public Map<String, String> getParams() { - return params; + public IntegerCheckerConfiguration getConfiguration() { + return configuration; } } \ No newline at end of file diff --git a/src/main/java/fr/inra/oresing/checker/IntegerCheckerConfiguration.java b/src/main/java/fr/inra/oresing/checker/IntegerCheckerConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..38664cb817c0ff587a96828b2ddb50b1c1b479a5 --- /dev/null +++ b/src/main/java/fr/inra/oresing/checker/IntegerCheckerConfiguration.java @@ -0,0 +1,7 @@ +package fr.inra.oresing.checker; + +/** + * Configuration pour un checker de type nombre entier + */ +public interface IntegerCheckerConfiguration extends LineCheckerConfiguration { +} diff --git a/src/main/java/fr/inra/oresing/checker/LineChecker.java b/src/main/java/fr/inra/oresing/checker/LineChecker.java index 06cecbd4ca65a185e2bc7c138c1a161041fe185c..eb24f8bf54c9428675ebecbcf909bfed73a88222 100644 --- a/src/main/java/fr/inra/oresing/checker/LineChecker.java +++ b/src/main/java/fr/inra/oresing/checker/LineChecker.java @@ -5,11 +5,9 @@ import fr.inra.oresing.rest.ValidationCheckResult; import java.util.Map; -public interface LineChecker { +public interface LineChecker<C extends LineCheckerConfiguration> { ValidationCheckResult check(Map<VariableComponentKey, String> values); ValidationCheckResult checkReference(Map<String, String> values); - default Map<String, String> getParams(){ - return Map.of(); - } + C getConfiguration(); } \ No newline at end of file diff --git a/src/main/java/fr/inra/oresing/checker/LineCheckerConfiguration.java b/src/main/java/fr/inra/oresing/checker/LineCheckerConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..fd33c636421118660c9abada9b4f2b19c60b9336 --- /dev/null +++ b/src/main/java/fr/inra/oresing/checker/LineCheckerConfiguration.java @@ -0,0 +1,9 @@ +package fr.inra.oresing.checker; + +import fr.inra.oresing.checker.decorators.DecoratorConfiguration; + +/** + * Indique qu'un objet a vocation à contenir des paramètres de configuration pour configurer un {@link LineChecker} + */ +public interface LineCheckerConfiguration extends DecoratorConfiguration { +} diff --git a/src/main/java/fr/inra/oresing/checker/ReferenceLineChecker.java b/src/main/java/fr/inra/oresing/checker/ReferenceLineChecker.java index 617f70054a6250d26474121e3d74bf3b1fdfd682..ab77e3125d0f588e75ab1545689f87ce6ec8ce2f 100644 --- a/src/main/java/fr/inra/oresing/checker/ReferenceLineChecker.java +++ b/src/main/java/fr/inra/oresing/checker/ReferenceLineChecker.java @@ -2,19 +2,17 @@ package fr.inra.oresing.checker; import com.google.common.collect.ImmutableMap; -import java.util.Map; import java.util.UUID; -public class ReferenceLineChecker implements CheckerOnOneVariableComponentLineChecker { +public class ReferenceLineChecker implements CheckerOnOneVariableComponentLineChecker<ReferenceLineCheckerConfiguration> { - public static final String PARAM_REFTYPE = "refType"; private final String reference; public ImmutableMap<String, UUID> referenceValues; public ImmutableMap<String, String> display; - private final Map<String, String> params; + private final ReferenceLineCheckerConfiguration configuration; private final CheckerTarget target; - public ReferenceLineChecker(CheckerTarget target, String reference, ImmutableMap<String, UUID> referenceValues, ImmutableMap<String, String> display, Map<String, String> params) { - this.params = params; + public ReferenceLineChecker(CheckerTarget target, String reference, ImmutableMap<String, UUID> referenceValues, ImmutableMap<String, String> display, ReferenceLineCheckerConfiguration configuration) { + this.configuration = configuration; this.target = target; this.reference = reference; this.referenceValues = referenceValues; @@ -53,7 +51,7 @@ public class ReferenceLineChecker implements CheckerOnOneVariableComponentLineCh } @Override - public Map<String, String> getParams() { - return params; + public ReferenceLineCheckerConfiguration getConfiguration() { + return configuration; } } \ No newline at end of file diff --git a/src/main/java/fr/inra/oresing/checker/ReferenceLineCheckerConfiguration.java b/src/main/java/fr/inra/oresing/checker/ReferenceLineCheckerConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..eaa05911d8eb8fcd5814b8c05b4bdd1ede43c810 --- /dev/null +++ b/src/main/java/fr/inra/oresing/checker/ReferenceLineCheckerConfiguration.java @@ -0,0 +1,13 @@ +package fr.inra.oresing.checker; + +/** + * Configuration pour un checker de type "Reference" qui permet de s'assurer qu'une donnée + * est bien une valeur parmi celle du référentiel. + */ +public interface ReferenceLineCheckerConfiguration extends LineCheckerConfiguration { + + /** + * Le référentiel dans lequel la valeur vérifiée devra être contenu + */ + String getRefType(); +} diff --git a/src/main/java/fr/inra/oresing/checker/RegularExpressionChecker.java b/src/main/java/fr/inra/oresing/checker/RegularExpressionChecker.java index 057f2e9c4d5d79317779d39d7f5a63cf30cad658..ed7380b824fd95febd82eef459ba97283c85a766 100644 --- a/src/main/java/fr/inra/oresing/checker/RegularExpressionChecker.java +++ b/src/main/java/fr/inra/oresing/checker/RegularExpressionChecker.java @@ -4,26 +4,23 @@ import com.google.common.collect.ImmutableMap; import fr.inra.oresing.rest.DefaultValidationCheckResult; import fr.inra.oresing.rest.ValidationCheckResult; -import java.util.Map; import java.util.function.Predicate; import java.util.regex.Pattern; -public class RegularExpressionChecker implements CheckerOnOneVariableComponentLineChecker { - - public static final String PARAM_PATTERN = "pattern"; +public class RegularExpressionChecker implements CheckerOnOneVariableComponentLineChecker<RegularExpressionCheckerConfiguration> { private final String patternString; private final Predicate<String> predicate; private final CheckerTarget target; - private final Map<String, String> params; + private final RegularExpressionCheckerConfiguration configuration; public CheckerTarget getTarget(){ return this.target; } - public RegularExpressionChecker(CheckerTarget target, String patternString, Map<String, String> params) { - this.params = params; + public RegularExpressionChecker(CheckerTarget target, String patternString, RegularExpressionCheckerConfiguration configuration) { + this.configuration = configuration; this.target = target; this.patternString = patternString; predicate = Pattern.compile(patternString).asMatchPredicate(); @@ -45,7 +42,7 @@ public class RegularExpressionChecker implements CheckerOnOneVariableComponentLi } @Override - public Map<String, String> getParams() { - return params; + public RegularExpressionCheckerConfiguration getConfiguration() { + return configuration; } } \ No newline at end of file diff --git a/src/main/java/fr/inra/oresing/checker/RegularExpressionCheckerConfiguration.java b/src/main/java/fr/inra/oresing/checker/RegularExpressionCheckerConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..064c5e2de8263ac5f54d106ad64bff1f03c8e7ef --- /dev/null +++ b/src/main/java/fr/inra/oresing/checker/RegularExpressionCheckerConfiguration.java @@ -0,0 +1,12 @@ +package fr.inra.oresing.checker; + +/** + * Configuration pour un checker de type expression régulière + */ +public interface RegularExpressionCheckerConfiguration extends LineCheckerConfiguration { + + /** + * L'expression régulière à laquelle doit être conforme la valeur qui sera vérifiée. + */ + String getPattern(); +} diff --git a/src/main/java/fr/inra/oresing/checker/decorators/CheckerDecorator.java b/src/main/java/fr/inra/oresing/checker/decorators/CheckerDecorator.java index c119739de0c58717ae79a2255f51a482ef3ec830..b288525b08fa28dd3e05bf6edc59d530a1babf3c 100644 --- a/src/main/java/fr/inra/oresing/checker/decorators/CheckerDecorator.java +++ b/src/main/java/fr/inra/oresing/checker/decorators/CheckerDecorator.java @@ -11,8 +11,8 @@ import java.util.Map; public class CheckerDecorator { public static List<ICheckerDecorator> checkerDecorators = List.of( new CodifyDecorator(),new GroovyDecorator(), new RequiredDecorator()); - public static <T> ValidationCheckResult check(Map<T, String> values, String value, Map<String, String> params, CheckerTarget target) throws DecoratorException { - if(params == null || params.isEmpty()){ + public static <T> ValidationCheckResult check(Map<T, String> values, String value, DecoratorConfiguration params, CheckerTarget target) throws DecoratorException { + if (params == null) { return DefaultValidationCheckResult.warn(value, null); } for (ICheckerDecorator checkerDecorator : checkerDecorators) { diff --git a/src/main/java/fr/inra/oresing/checker/decorators/CodifyDecorator.java b/src/main/java/fr/inra/oresing/checker/decorators/CodifyDecorator.java index 4957466597a0831243c3e2d4d17c0a28464eb25b..55427fe14bc4bfa0ee537cbd239089b6ab37cba5 100644 --- a/src/main/java/fr/inra/oresing/checker/decorators/CodifyDecorator.java +++ b/src/main/java/fr/inra/oresing/checker/decorators/CodifyDecorator.java @@ -7,20 +7,16 @@ import fr.inra.oresing.rest.ValidationCheckResult; import org.assertj.core.util.Strings; import java.util.Map; -import java.util.Optional; public class CodifyDecorator implements ICheckerDecorator { - public static final String PARAMS_CODIFY = "codify"; - public ValidationCheckResult check(Map<? extends Object, String> values, String value, Map<String, String> params, CheckerTarget target) throws DecoratorException { - - boolean codify = params.containsKey(PARAMS_CODIFY) && - Optional.ofNullable(params.get(PARAMS_CODIFY)) - .map(req -> req == null || Boolean.parseBoolean(req)) - .orElse(false); - if (codify && !Strings.isNullOrEmpty(value)) { - value = OreSiService.escapeKeyComponent(value); + public ValidationCheckResult check(Map<? extends Object, String> values, String value, DecoratorConfiguration params, CheckerTarget target) throws DecoratorException { + String valueAfterCodification; + if (params.isCodify() && !Strings.isNullOrEmpty(value)) { + valueAfterCodification = OreSiService.escapeKeyComponent(value); + } else { + valueAfterCodification = value; } - return DefaultValidationCheckResult.warn(value, null); + return DefaultValidationCheckResult.warn(valueAfterCodification, null); } } \ No newline at end of file diff --git a/src/main/java/fr/inra/oresing/checker/decorators/DecoratorConfiguration.java b/src/main/java/fr/inra/oresing/checker/decorators/DecoratorConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..f725b6ecb504039aa8675a14153959405f6ed955 --- /dev/null +++ b/src/main/java/fr/inra/oresing/checker/decorators/DecoratorConfiguration.java @@ -0,0 +1,28 @@ +package fr.inra.oresing.checker.decorators; + +/** + * Configuration de la décoration d'une donnée. + */ +public interface DecoratorConfiguration { + + /** + * Indique que la donnée doit être transformée pour subir un échappement afin d'être utilisable comme clé + */ + boolean isCodify(); + + /** + * Indique que la validation doit remonter une erreur si donnée est absente + */ + boolean isRequired(); + + /** + * Avant d'être vérifiée, la donnée doit être transformée en appliquant cette expression. + */ + String getGroovy(); + + /** + * Les référentiels qui devront être chargés puis injectés dans le contexte au moment de + * l'évaluation de l'expression {@link #getGroovy()} + */ + String getReferences(); +} diff --git a/src/main/java/fr/inra/oresing/checker/decorators/GroovyDecorator.java b/src/main/java/fr/inra/oresing/checker/decorators/GroovyDecorator.java index cdfdbd4f54d9263ee65e500160744ec7eef8451e..d32607aff5c8fbcd14f3347ed92ad24897c40a69 100644 --- a/src/main/java/fr/inra/oresing/checker/decorators/GroovyDecorator.java +++ b/src/main/java/fr/inra/oresing/checker/decorators/GroovyDecorator.java @@ -3,26 +3,24 @@ package fr.inra.oresing.checker.decorators; import com.google.common.collect.ImmutableMap; import fr.inra.oresing.checker.CheckerTarget; import fr.inra.oresing.checker.GroovyLineChecker; -import fr.inra.oresing.groovy.GroovyExpression; +import fr.inra.oresing.groovy.StringGroovyExpression; import fr.inra.oresing.rest.DefaultValidationCheckResult; import fr.inra.oresing.rest.ValidationCheckResult; import java.util.Map; -import java.util.Optional; public class GroovyDecorator implements ICheckerDecorator { - public static final String PARAMS_GROOVY = "groovy"; - public ValidationCheckResult check(Map<? extends Object, String> values, String value, Map<String, String> params, CheckerTarget target) throws DecoratorException { - - GroovyExpression groovyExpression=Optional.ofNullable(params.get(PARAMS_GROOVY)) - .map(req -> GroovyExpression.forExpression(req)) - .orElse((GroovyExpression) null); - if (groovyExpression!=null) { + public ValidationCheckResult check(Map<? extends Object, String> values, String value, DecoratorConfiguration params, CheckerTarget target) throws DecoratorException { + String groovy = params.getGroovy(); + String valueAfterDecoration; + if (groovy == null) { + valueAfterDecoration = value; + } else { ImmutableMap<String, Object> context = GroovyLineChecker.buildContext(values, target.getApplication(), params, target.getRepository()); - value = groovyExpression.evaluate(context).toString(); - + StringGroovyExpression groovyExpression = StringGroovyExpression.forExpression(groovy); + valueAfterDecoration = groovyExpression.evaluate(context); } - return DefaultValidationCheckResult.warn(value, null); + return DefaultValidationCheckResult.warn(valueAfterDecoration, null); } } \ No newline at end of file diff --git a/src/main/java/fr/inra/oresing/checker/decorators/ICheckerDecorator.java b/src/main/java/fr/inra/oresing/checker/decorators/ICheckerDecorator.java index 413b9357adfaa5bffc566e4e3c88fd094a493187..05871c801765fa2cbb654fafac5950b2633f30cb 100644 --- a/src/main/java/fr/inra/oresing/checker/decorators/ICheckerDecorator.java +++ b/src/main/java/fr/inra/oresing/checker/decorators/ICheckerDecorator.java @@ -6,5 +6,5 @@ import fr.inra.oresing.rest.ValidationCheckResult; import java.util.Map; public interface ICheckerDecorator { - ValidationCheckResult check(Map<? extends Object, String> values, String value, Map<String, String> params, CheckerTarget target) throws DecoratorException; + ValidationCheckResult check(Map<? extends Object, String> values, String value, DecoratorConfiguration params, CheckerTarget target) throws DecoratorException; } \ No newline at end of file diff --git a/src/main/java/fr/inra/oresing/checker/decorators/RequiredDecorator.java b/src/main/java/fr/inra/oresing/checker/decorators/RequiredDecorator.java index 3f65ecb18596690755e524d447634e33c04f5a1e..d518d6d3e1d480ffa4292406a40d0d470a5c104b 100644 --- a/src/main/java/fr/inra/oresing/checker/decorators/RequiredDecorator.java +++ b/src/main/java/fr/inra/oresing/checker/decorators/RequiredDecorator.java @@ -7,16 +7,11 @@ import fr.inra.oresing.rest.ValidationCheckResult; import org.assertj.core.util.Strings; import java.util.Map; -import java.util.Optional; public class RequiredDecorator implements ICheckerDecorator { - public static final String PARAMS_REQUIRED = "required"; - public ValidationCheckResult check(Map<? extends Object, String> values, String value, Map<String, String> params, CheckerTarget target) throws DecoratorException { - boolean required = params.containsKey(PARAMS_REQUIRED) && - Optional.ofNullable(params.get(PARAMS_REQUIRED)) - .map(req->req==null || Boolean.parseBoolean(req)) - .orElse(false); + public ValidationCheckResult check(Map<? extends Object, String> values, String value, DecoratorConfiguration params, CheckerTarget target) throws DecoratorException { + boolean required = params.isRequired(); if (required && Strings.isNullOrEmpty(value)) { throw new DecoratorException(DefaultValidationCheckResult.error(target.getInternationalizedKey("requiredValue"), ImmutableMap.of("target", target.getTarget()))); }else if (!required && Strings.isNullOrEmpty(value)) { diff --git a/src/main/java/fr/inra/oresing/model/Configuration.java b/src/main/java/fr/inra/oresing/model/Configuration.java index d5208c786d48cffd8a52974779b22970fbe4adf6..e10a26621040a52db535a68bceede28b01436af6 100644 --- a/src/main/java/fr/inra/oresing/model/Configuration.java +++ b/src/main/java/fr/inra/oresing/model/Configuration.java @@ -1,7 +1,12 @@ package fr.inra.oresing.model; import com.google.common.collect.MoreCollectors; -import fr.inra.oresing.checker.ReferenceLineChecker; +import fr.inra.oresing.checker.DateLineCheckerConfiguration; +import fr.inra.oresing.checker.FloatCheckerConfiguration; +import fr.inra.oresing.checker.GroovyLineCheckerConfiguration; +import fr.inra.oresing.checker.IntegerCheckerConfiguration; +import fr.inra.oresing.checker.ReferenceLineCheckerConfiguration; +import fr.inra.oresing.checker.RegularExpressionCheckerConfiguration; import fr.inra.oresing.model.internationalization.Internationalization; import fr.inra.oresing.model.internationalization.InternationalizationMap; import lombok.Getter; @@ -10,7 +15,16 @@ import lombok.ToString; import org.springframework.util.CollectionUtils; import javax.annotation.Nullable; -import java.util.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TreeMap; @Getter @Setter @@ -52,9 +66,9 @@ public class Configuration { for (Map.Entry<String, LineValidationRuleDescription> validation : validations.entrySet()) { CheckerDescription checker = validation.getValue().getChecker(); if (checker != null) { - String refType = Optional.ofNullable(checker) - .map(c -> c.getParams()) - .map(param -> param.get(ReferenceLineChecker.PARAM_REFTYPE)) + String refType = Optional.of(checker) + .map(CheckerDescription::getParams) + .map(CheckerConfigurationDescription::getRefType) .orElse(null); if ("Reference".equals(checker.getName()) && refType != null) { DependencyNode node = nodes.computeIfAbsent(refType, k -> new DependencyNode(refType)); @@ -202,7 +216,15 @@ public class Configuration { CheckerDescription checker; @Nullable String defaultValue; - Map<String, String> params; + VariableComponentDescriptionConfiguration params; + } + + @Getter + @Setter + @ToString + public static class VariableComponentDescriptionConfiguration { + String references; // à remplacer par une collection car split(',') + boolean replace; } @Getter @@ -210,7 +232,30 @@ public class Configuration { @ToString public static class CheckerDescription { String name; - Map<String, String> params = new LinkedHashMap<>(); + CheckerConfigurationDescription params; + } + + @Getter + @Setter + @ToString + public static class CheckerConfigurationDescription implements + RegularExpressionCheckerConfiguration, + FloatCheckerConfiguration, + IntegerCheckerConfiguration, + DateLineCheckerConfiguration, + ReferenceLineCheckerConfiguration, + GroovyLineCheckerConfiguration { + String pattern; + String refType; + String expression; + String columns; + String variableComponentKey; + String references; // à remplacer par une collection car split(',') + String datatypes; + String duration; + String groovy; + boolean codify; + boolean required; } @Getter diff --git a/src/main/java/fr/inra/oresing/model/LocalDateTimeRange.java b/src/main/java/fr/inra/oresing/model/LocalDateTimeRange.java index 21d607e7c11c1781deee29865d285795f1844adc..870a4431708f241a1778d64d4f2c63626f67c7e7 100644 --- a/src/main/java/fr/inra/oresing/model/LocalDateTimeRange.java +++ b/src/main/java/fr/inra/oresing/model/LocalDateTimeRange.java @@ -31,8 +31,8 @@ public class LocalDateTimeRange { public LocalDateTimeRange toLocalDateTimeRange(String str, DateTimeFormatter dateTimeFormatter, DateLineChecker dateLineChecker) { String pattern = "01/" + str; final LocalDate date = LocalDate.parse(pattern, DateTimeFormatter.ofPattern("dd/MM/yyyy")); - if (dateLineChecker.getParams() != null && dateLineChecker.getParams().containsKey(DateLineChecker.PARAM_DURATION)) { - return new Duration(dateLineChecker.getParams().get(DateLineChecker.PARAM_DURATION)).getLocalDateTimeRange(date); + if (dateLineChecker.getConfiguration() != null && dateLineChecker.getConfiguration().getDuration() != null) { + return new Duration(dateLineChecker.getConfiguration().getDuration()).getLocalDateTimeRange(date); } return LocalDateTimeRange.between(LocalDate.from(date.atStartOfDay()), date.plus(1L, ChronoUnit.MONTHS)); } @@ -45,10 +45,10 @@ public class LocalDateTimeRange { @Override public LocalDateTimeRange toLocalDateTimeRange(String str, DateTimeFormatter dateTimeFormatter, DateLineChecker dateLineChecker) { - if (dateLineChecker.getParams() != null && dateLineChecker.getParams().containsKey(DateLineChecker.PARAM_DURATION)) { + if (dateLineChecker.getConfiguration() != null && dateLineChecker.getConfiguration().getDuration() != null) { String pattern = "01/01/" + str; final LocalDate date = LocalDate.parse(pattern, DateTimeFormatter.ofPattern("dd/MM/yyyy")); - return new Duration(dateLineChecker.getParams().get(DateLineChecker.PARAM_DURATION)).getLocalDateTimeRange(date); + return new Duration(dateLineChecker.getConfiguration().getDuration()).getLocalDateTimeRange(date); } return LocalDateTimeRange.forYear(Year.parse(str, dateTimeFormatter)); } @@ -61,9 +61,9 @@ public class LocalDateTimeRange { @Override public LocalDateTimeRange toLocalDateTimeRange(String str, DateTimeFormatter dateTimeFormatter, DateLineChecker dateLineChecker) { - if (dateLineChecker.getParams() != null && dateLineChecker.getParams().containsKey(DateLineChecker.PARAM_DURATION)) { + if (dateLineChecker.getConfiguration() != null && dateLineChecker.getConfiguration().getDuration() != null) { final LocalDate date = LocalDate.parse(str, DateTimeFormatter.ofPattern("dd/MM/yyyy")); - return new Duration(dateLineChecker.getParams().get(DateLineChecker.PARAM_DURATION)).getLocalDateTimeRange(date); + return new Duration(dateLineChecker.getConfiguration().getDuration()).getLocalDateTimeRange(date); } return LocalDateTimeRange.forDay(LocalDate.parse(str, dateTimeFormatter)); } @@ -77,9 +77,9 @@ public class LocalDateTimeRange { @Override public LocalDateTimeRange toLocalDateTimeRange(String str, DateTimeFormatter dateTimeFormatter, DateLineChecker dateLineChecker) { final LocalDate startDate = LocalDate.parse(str, dateTimeFormatter); - if(dateLineChecker.getParams() != null && dateLineChecker.getParams().containsKey(DateLineChecker.PARAM_DURATION)){ + if(dateLineChecker.getConfiguration() != null && dateLineChecker.getConfiguration().getDuration() != null){ final LocalDateTime date = LocalDateTime.parse(str, DateTimeFormatter.ofPattern(getPattern())); - return new Duration(dateLineChecker.getParams().get(DateLineChecker.PARAM_DURATION)).getLocalDateTimeRange(date); + return new Duration(dateLineChecker.getConfiguration().getDuration()).getLocalDateTimeRange(date); } return LocalDateTimeRange.forDay(startDate); } diff --git a/src/main/java/fr/inra/oresing/rest/ApplicationConfigurationService.java b/src/main/java/fr/inra/oresing/rest/ApplicationConfigurationService.java index 10f23f93a886b97254204acec9cc1c3037b91167..6d54d0018f00f08f20fec70bfddbe1a607558471 100644 --- a/src/main/java/fr/inra/oresing/rest/ApplicationConfigurationService.java +++ b/src/main/java/fr/inra/oresing/rest/ApplicationConfigurationService.java @@ -6,16 +6,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.exc.InvalidFormatException; import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException; import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; +import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; import com.google.common.collect.TreeMultiset; import fr.inra.oresing.OreSiTechnicalException; -import fr.inra.oresing.checker.CheckerFactory; -import fr.inra.oresing.checker.DateLineChecker; import fr.inra.oresing.checker.GroovyLineChecker; -import fr.inra.oresing.checker.ReferenceLineChecker; -import fr.inra.oresing.checker.decorators.GroovyDecorator; import fr.inra.oresing.groovy.GroovyExpression; import fr.inra.oresing.model.Configuration; import fr.inra.oresing.model.LocalDateTimeRange; @@ -33,7 +30,17 @@ import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -330,11 +337,11 @@ public class ApplicationConfigurationService { builder.recordAuthorizationScopeVariableComponentWrongChecker(authorizationScopeVariableComponentKey, "Date"); } String refType = null; - Map<String, String> params = authorizationScopeVariableComponentChecker.getParams(); - if (params == null) { + Configuration.CheckerConfigurationDescription checkerConfigurationDescription = authorizationScopeVariableComponentChecker.getParams(); + if (checkerConfigurationDescription == null) { builder.recordAuthorizationScopeVariableComponentReftypeNull(authorizationScopeVariableComponentKey, configuration.getReferences().keySet()); } else { - refType = params.getOrDefault(ReferenceLineChecker.PARAM_REFTYPE, null); + refType = checkerConfigurationDescription.getRefType(); if (refType == null || !configuration.getReferences().containsKey(refType)) { builder.recordAuthorizationScopeVariableComponentReftypeUnknown(authorizationScopeVariableComponentKey, refType, configuration.getReferences().keySet()); } else { @@ -379,7 +386,7 @@ public class ApplicationConfigurationService { } Optional.ofNullable(timeScopeVariableComponentChecker) .map(checkerDescription -> checkerDescription.getParams()) - .map(params -> params.getOrDefault(DateLineChecker.PARAM_PATTERN, null)) + .map(Configuration.CheckerConfigurationDescription::getPattern) .ifPresent(pattern -> { if (!LocalDateTimeRange.getKnownPatterns().contains(pattern)) { builder.recordTimeScopeVariableComponentPatternUnknown(timeScopeVariableComponentKey, pattern, LocalDateTimeRange.getKnownPatterns()); @@ -421,7 +428,7 @@ public class ApplicationConfigurationService { String lineValidationRuleKey = validationEntry.getKey(); Configuration.CheckerDescription checker = lineValidationRuleDescription.getChecker(); if (GroovyLineChecker.NAME.equals(checker.getName())) { - String expression = checker.getParams().get(GroovyLineChecker.PARAM_EXPRESSION); + String expression = checker.getParams().getExpression(); if (StringUtils.isBlank(expression)) { builder.recordMissingRequiredExpression(lineValidationRuleKey); } else { @@ -444,8 +451,8 @@ public class ApplicationConfigurationService { if (variableComponentDescription != null) { Configuration.CheckerDescription checkerDescription = variableComponentDescription.getChecker(); if ("Reference".equals(checkerDescription.getName())) { - if (checkerDescription.getParams() != null && checkerDescription.getParams().containsKey(ReferenceLineChecker.PARAM_REFTYPE)) { - String refType = checkerDescription.getParams().get(ReferenceLineChecker.PARAM_REFTYPE); + if (checkerDescription.getParams() != null && checkerDescription.getParams().getRefType() != null) { + String refType = checkerDescription.getParams().getRefType(); if (!references.contains(refType)) { builder.unknownReferenceForChecker(dataType, datum, component, refType, references); } @@ -599,17 +606,19 @@ public class ApplicationConfigurationService { continue; } ImmutableSet<String> variableComponentCheckers = ImmutableSet.of("Date", "Float", "Integer", "RegularExpression", "Reference"); - String columns = checker.getParams().get(CheckerFactory.COLUMNS); + String columns = checker.getParams().getColumns(); Set<String> groovyColumn = Optional.ofNullable(checker) .map(check->check.getParams()) - .filter(params->params.containsKey(GroovyDecorator.PARAMS_GROOVY)) - .map(params-> params.getOrDefault(CheckerFactory.COLUMNS, "")) + .filter(params->params.getGroovy() != null) + .map(params-> MoreObjects.firstNonNull(params.getColumns(), "")) + + // autant mettre une collection dans le YAML directement .map(values-> values.split(",")) .map(values-> Arrays.stream(values).collect(Collectors.toSet())) .orElse(Set.of()); if (GroovyLineChecker.NAME.equals(checker.getName())) { - String expression = checker.getParams().get(GroovyLineChecker.PARAM_EXPRESSION); + String expression = checker.getParams().getExpression(); if (StringUtils.isBlank(expression)) { builder.recordMissingRequiredExpression(validationRuleDescriptionEntryKey); } else { @@ -636,8 +645,8 @@ public class ApplicationConfigurationService { } } if ("Reference".equals(checker.getName())) { - if (checker.getParams() != null && checker.getParams().containsKey(ReferenceLineChecker.PARAM_REFTYPE)) { - String refType = checker.getParams().get(ReferenceLineChecker.PARAM_REFTYPE); + if (checker.getParams() != null && checker.getParams().getRefType() != null) { + String refType = checker.getParams().getRefType(); if (!references.contains(refType)) { builder.unknownReferenceForCheckerInReference(validationRuleDescriptionEntryKey, reference, refType, references); } diff --git a/src/main/java/fr/inra/oresing/rest/OreSiService.java b/src/main/java/fr/inra/oresing/rest/OreSiService.java index aa3c7c3807481436c10ddbec7ed85caff5bfc8e5..5b0e25b1ded003db3276de19a2450b5dd0e82fb7 100644 --- a/src/main/java/fr/inra/oresing/rest/OreSiService.java +++ b/src/main/java/fr/inra/oresing/rest/OreSiService.java @@ -4,19 +4,60 @@ import com.google.common.base.Charsets; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Splitter; -import com.google.common.collect.*; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultiset; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Iterators; +import com.google.common.collect.Maps; +import com.google.common.collect.MoreCollectors; +import com.google.common.collect.Ordering; +import com.google.common.collect.SetMultimap; +import com.google.common.collect.Sets; import com.google.common.primitives.Ints; import fr.inra.oresing.OreSiTechnicalException; -import fr.inra.oresing.checker.*; -import fr.inra.oresing.checker.decorators.GroovyDecorator; +import fr.inra.oresing.checker.CheckerFactory; +import fr.inra.oresing.checker.DateLineChecker; +import fr.inra.oresing.checker.DateValidationCheckResult; +import fr.inra.oresing.checker.FloatChecker; +import fr.inra.oresing.checker.GroovyLineChecker; +import fr.inra.oresing.checker.IntegerChecker; +import fr.inra.oresing.checker.InvalidDatasetContentException; +import fr.inra.oresing.checker.LineChecker; +import fr.inra.oresing.checker.ReferenceLineChecker; +import fr.inra.oresing.checker.ReferenceLineCheckerConfiguration; +import fr.inra.oresing.checker.ReferenceValidationCheckResult; import fr.inra.oresing.groovy.CommonExpression; import fr.inra.oresing.groovy.Expression; import fr.inra.oresing.groovy.StringGroovyExpression; -import fr.inra.oresing.model.*; +import fr.inra.oresing.model.Application; +import fr.inra.oresing.model.Authorization; +import fr.inra.oresing.model.BinaryFile; +import fr.inra.oresing.model.BinaryFileDataset; +import fr.inra.oresing.model.Configuration; +import fr.inra.oresing.model.Data; +import fr.inra.oresing.model.LocalDateTimeRange; +import fr.inra.oresing.model.ReferenceValue; +import fr.inra.oresing.model.VariableComponentKey; import fr.inra.oresing.model.internationalization.Internationalization; import fr.inra.oresing.model.internationalization.InternationalizationDisplay; import fr.inra.oresing.model.internationalization.InternationalizationReferenceMap; -import fr.inra.oresing.persistence.*; +import fr.inra.oresing.persistence.AuthenticationService; +import fr.inra.oresing.persistence.BinaryFileInfos; +import fr.inra.oresing.persistence.DataRepository; +import fr.inra.oresing.persistence.DataRow; +import fr.inra.oresing.persistence.OreSiRepository; +import fr.inra.oresing.persistence.ReferenceValueRepository; +import fr.inra.oresing.persistence.SqlPolicy; +import fr.inra.oresing.persistence.SqlSchema; +import fr.inra.oresing.persistence.SqlSchemaForApplication; +import fr.inra.oresing.persistence.SqlService; import fr.inra.oresing.persistence.roles.OreSiRightOnApplicationRole; import fr.inra.oresing.persistence.roles.OreSiUserRole; import lombok.Value; @@ -50,7 +91,19 @@ import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; @@ -778,7 +831,8 @@ public class OreSiService { dateValidationCheckResultImmutableMap.put(variableComponentKey, (DateValidationCheckResult) validationCheckResult); } if (validationCheckResult instanceof ReferenceValidationCheckResult) { - if (!lineChecker.getParams().isEmpty() && lineChecker.getParams().containsKey(GroovyDecorator.PARAMS_GROOVY)) { + ReferenceLineCheckerConfiguration configuration = (ReferenceLineCheckerConfiguration) lineChecker.getConfiguration(); + if (configuration.getGroovy() != null) { values.put((VariableComponentKey) ((ReferenceValidationCheckResult) validationCheckResult).getTarget().getTarget(), ((ReferenceValidationCheckResult) validationCheckResult).getValue().toString()); } ReferenceValidationCheckResult referenceValidationCheckResult = (ReferenceValidationCheckResult) validationCheckResult; @@ -919,16 +973,16 @@ public class OreSiService { Map<VariableComponentKey, String> rowWithValues = new LinkedHashMap(rowWithData.datum); defaultValueExpressions.entrySet().stream() .forEach(variableComponentKeyExpressionEntry -> { - Map<String, String> params = Optional.ofNullable(data) + Configuration.VariableComponentDescriptionConfiguration params = Optional.ofNullable(data) .map(columnDescriptionLinkedHashMap -> columnDescriptionLinkedHashMap.get(variableComponentKeyExpressionEntry.getKey().getVariable())) .map(columnDescription -> columnDescription.getComponents()) .map(variableComponentDescriptionLinkedHashMap -> variableComponentDescriptionLinkedHashMap.get(variableComponentKeyExpressionEntry.getKey().getComponent())) .map(variableComponentDescription -> variableComponentDescription.getParams()) - .orElseGet(HashMap::new); + .orElseGet(Configuration.VariableComponentDescriptionConfiguration::new); ImmutableMap<String, Object> evaluationContext = GroovyLineChecker.buildContext(rowWithData.getDatum(), application, params, repository); String evaluate = variableComponentKeyExpressionEntry.getValue().evaluate(evaluationContext); if (StringUtils.isNotBlank(evaluate)) { - if (params != null && Boolean.parseBoolean(params.get("replace"))) { + if (params.isReplace()) { rowWithValues.put(variableComponentKeyExpressionEntry.getKey(), evaluate); } else { rowWithDefaults.put(variableComponentKeyExpressionEntry.getKey(), evaluate); diff --git a/src/test/java/fr/inra/oresing/checker/GroovyLineCheckerTest.java b/src/test/java/fr/inra/oresing/checker/GroovyLineCheckerTest.java index b72dfefb0c474158768f6d040ca67794b80d3b73..3d0939d7ff73d49bfb42db68d2a9c762e2e3447d 100644 --- a/src/test/java/fr/inra/oresing/checker/GroovyLineCheckerTest.java +++ b/src/test/java/fr/inra/oresing/checker/GroovyLineCheckerTest.java @@ -40,7 +40,7 @@ public class GroovyLineCheckerTest { Application application = Mockito.mock(Application.class); OreSiRepository.RepositoryForApplication repository = Mockito.mock(OreSiRepository.RepositoryForApplication.class); - GroovyLineChecker groovyLineChecker = GroovyLineChecker.forExpression(expression, application,repository,null); + GroovyLineChecker groovyLineChecker = GroovyLineChecker.forExpression(expression, application,repository, getConfiguration(expression)); ImmutableMap<VariableComponentKey, String> validDatum = ImmutableMap.of( new VariableComponentKey("temperature", "valeur"), "-12", @@ -85,7 +85,7 @@ public class GroovyLineCheckerTest { Application application = Mockito.mock(Application.class); OreSiRepository.RepositoryForApplication repository = Mockito.mock(OreSiRepository.RepositoryForApplication.class); - GroovyLineChecker groovyLineChecker = GroovyLineChecker.forExpression(expression, application,repository,null); + GroovyLineChecker groovyLineChecker = GroovyLineChecker.forExpression(expression, application, repository, getConfiguration(expression)); ImmutableMap<VariableComponentKey, String> validDatum = ImmutableMap.of( new VariableComponentKey("temperature", "valeur"), "-12", @@ -98,4 +98,38 @@ public class GroovyLineCheckerTest { Assert.assertTrue(e.getMessage().contains("L'évaluation de l’expression n'a pas retourné une valeur booléenne mais 261.15.")); } } + + private GroovyLineCheckerConfiguration getConfiguration(String expression) { + return new GroovyLineCheckerConfiguration() { + @Override + public String getExpression() { + return expression; + } + + @Override + public String getReferences() { + return null; + } + + @Override + public String getDatatypes() { + return null; + } + + @Override + public boolean isCodify() { + throw new UnsupportedOperationException("doublure de test"); + } + + @Override + public boolean isRequired() { + throw new UnsupportedOperationException("doublure de test"); + } + + @Override + public String getGroovy() { + throw new UnsupportedOperationException("doublure de test"); + } + }; + } } \ No newline at end of file diff --git a/src/test/java/fr/inra/oresing/model/LocalDateTimeRangeTest.java b/src/test/java/fr/inra/oresing/model/LocalDateTimeRangeTest.java index 24424576c2fe88525abbda0d272c744a4ef7d57e..59dcc4f800acc7399efae654a6ad0aeaedbfc5b7 100644 --- a/src/test/java/fr/inra/oresing/model/LocalDateTimeRangeTest.java +++ b/src/test/java/fr/inra/oresing/model/LocalDateTimeRangeTest.java @@ -1,11 +1,11 @@ package fr.inra.oresing.model; import fr.inra.oresing.checker.DateLineChecker; +import fr.inra.oresing.checker.DateLineCheckerConfiguration; import org.junit.Assert; import org.junit.Test; import java.time.Year; -import java.util.Map; public class LocalDateTimeRangeTest { @@ -28,23 +28,57 @@ public class LocalDateTimeRangeTest { } @Test public void testDayPattern() { - LocalDateTimeRange range = LocalDateTimeRange.parse("01/01/2020", new DateLineChecker(null, "dd/MM/yyyy", Map.of(DateLineChecker.PARAM_DURATION, "2 MONTHS"))); + LocalDateTimeRange range = LocalDateTimeRange.parse("01/01/2020", new DateLineChecker(null, "dd/MM/yyyy", getDateCheckerConfiguration("2 MONTHS"))); Assert.assertEquals("[\"2020-01-01 00:00:00\",\"2020-03-01 00:00:00\")", range.toSqlExpression()); range = LocalDateTimeRange.parse("01/01/2020", new DateLineChecker(null, "dd/MM/yyyy", null)); Assert.assertEquals("[\"2020-01-01 00:00:00\",\"2020-01-02 00:00:00\")", range.toSqlExpression()); } @Test public void testSemiHourlyPattern() { - LocalDateTimeRange range = LocalDateTimeRange.parse("01/01/2020 01:30:00", new DateLineChecker(null, "dd/MM/yyyy HH:mm:ss", Map.of(DateLineChecker.PARAM_DURATION, "30 MINUTES"))); + LocalDateTimeRange range = LocalDateTimeRange.parse("01/01/2020 01:30:00", new DateLineChecker(null, "dd/MM/yyyy HH:mm:ss", getDateCheckerConfiguration("30 MINUTES"))); Assert.assertEquals("[\"2020-01-01 01:30:00\",\"2020-01-01 02:00:00\")", range.toSqlExpression()); range = LocalDateTimeRange.parse("01/01/2020 01:30:00", new DateLineChecker(null, "dd/MM/yyyy HH:mm:ss", null)); Assert.assertEquals("[\"2020-01-01 00:00:00\",\"2020-01-02 00:00:00\")", range.toSqlExpression()); } @Test public void testMounthPattern() { - LocalDateTimeRange range = LocalDateTimeRange.parse("01/2020", new DateLineChecker(null, "MM/yyyy", Map.of(DateLineChecker.PARAM_DURATION, "2 MONTHS"))); + LocalDateTimeRange range = LocalDateTimeRange.parse("01/2020", new DateLineChecker(null, "MM/yyyy", getDateCheckerConfiguration("2 MONTHS"))); Assert.assertEquals("[\"2020-01-01 00:00:00\",\"2020-03-01 00:00:00\")", range.toSqlExpression()); range = LocalDateTimeRange.parse("01/2020", new DateLineChecker(null, "MM/yyyy", null)); Assert.assertEquals("[\"2020-01-01 00:00:00\",\"2020-02-01 00:00:00\")", range.toSqlExpression()); } + + private DateLineCheckerConfiguration getDateCheckerConfiguration(String duration) { + return new DateLineCheckerConfiguration() { + @Override + public String getPattern() { + throw new UnsupportedOperationException("doublure de test"); + } + + @Override + public String getDuration() { + return duration; + } + + @Override + public boolean isCodify() { + throw new UnsupportedOperationException("doublure de test"); + } + + @Override + public boolean isRequired() { + throw new UnsupportedOperationException("doublure de test"); + } + + @Override + public String getGroovy() { + throw new UnsupportedOperationException("doublure de test"); + } + + @Override + public String getReferences() { + throw new UnsupportedOperationException("doublure de test"); + } + }; + } } \ No newline at end of file diff --git a/src/test/resources/data/monsore/monsore-with-repository.yaml b/src/test/resources/data/monsore/monsore-with-repository.yaml index d6d75547133832529e287a2f1cdcfe0451c9b5ee..892ffbb53a72154e6ef7998b83c7891c906fbe9b 100644 --- a/src/test/resources/data/monsore/monsore-with-repository.yaml +++ b/src/test/resources/data/monsore/monsore-with-repository.yaml @@ -421,30 +421,30 @@ dataTypes: name: GroovyExpression params: expression: > + String datatype = "piegeage_en_montee"; + String variable = "Couleur des individus"; + String codeVariable = "couleur_des_individus"; + String component = "unit"; return referencesValues.get("variables_et_unites_par_types_de_donnees") - .findAll{it.get("nom du type de données").equals(params.get("datatype"))} - .find{it.get("nom de la variable").equals(params.get("codeVariable"))} - .get("nom de l'unité").equals(datum.get(params.get("variable")).get(params.get("component"))); + .findAll{it.get("nom du type de données").equals(datatype)} + .find{it.get("nom de la variable").equals(codeVariable)} + .get("nom de l'unité").equals(datum.get(variable).get(component)); references: variables_et_unites_par_types_de_donnees - datatype: "piegeage_en_montee" - variable: "Couleur des individus" - codeVariable: couleur_des_individus - component: unit unitOfIndividus: description: "vérifie l'unité du nombre d'individus" checker: name: GroovyExpression params: expression: > + String datatype = "piegeage_en_montee"; + String variable = "Nombre d'individus"; + String codeVariable = "nombre_d_individus"; + String component = "unit"; return referencesValues.get("variables_et_unites_par_types_de_donnees") - .findAll{it.get("nom du type de données").equals(params.get("datatype"))} - .find{it.get("nom de la variable").equals(params.get("codeVariable"))} - .get("nom de l'unité").equals(datum.get(params.get("variable")).get(params.get("component"))); + .findAll{it.get("nom du type de données").equals(datatype)} + .find{it.get("nom de la variable").equals(codeVariable)} + .get("nom de l'unité").equals(datum.get(variable).get(component)); references: variables_et_unites_par_types_de_donnees - datatype: "piegeage_en_montee" - variable: "Nombre d'individus" - codeVariable: nombre_d_individus - component: unit format: headerLine: 4 firstRowLine: 5 diff --git a/src/test/resources/data/monsore/monsore.yaml b/src/test/resources/data/monsore/monsore.yaml index f11cc867bbf1dfec7c93659be416bd85d305aaab..bba2c879390d535f3a33b5c893a8024223979fa2 100644 --- a/src/test/resources/data/monsore/monsore.yaml +++ b/src/test/resources/data/monsore/monsore.yaml @@ -419,30 +419,30 @@ dataTypes: name: GroovyExpression params: expression: > + String datatype = "piegeage_en_montee"; + String variable = "Couleur des individus"; + String codeVariable = "couleur_des_individus"; + String component = "unit"; return referencesValues.get("variables_et_unites_par_types_de_donnees") - .findAll{it.get("nom du type de données").equals(params.get("datatype"))} - .find{it.get("nom de la variable").equals(params.get("codeVariable"))} - .get("nom de l'unité").equals(datum.get(params.get("variable")).get(params.get("component"))); + .findAll{it.get("nom du type de données").equals(datatype)} + .find{it.get("nom de la variable").equals(codeVariable)} + .get("nom de l'unité").equals(datum.get(variable).get(component)); references: variables_et_unites_par_types_de_donnees - datatype: "piegeage_en_montee" - variable: "Couleur des individus" - codeVariable: couleur_des_individus - component: unit unitOfIndividus: description: "vérifie l'unité du nombre d'individus" checker: name: GroovyExpression params: expression: > + String datatype = "piegeage_en_montee"; + String variable = "Nombre d'individus"; + String codeVariable = "nombre_d_individus"; + String component = "unit"; return referencesValues.get("variables_et_unites_par_types_de_donnees") - .findAll{it.get("nom du type de données").equals(params.get("datatype"))} - .find{it.get("nom de la variable").equals(params.get("codeVariable"))} - .get("nom de l'unité").equals(datum.get(params.get("variable")).get(params.get("component"))); + .findAll{it.get("nom du type de données").equals(datatype)} + .find{it.get("nom de la variable").equals(codeVariable)} + .get("nom de l'unité").equals(datum.get(variable).get(component)); references: variables_et_unites_par_types_de_donnees - datatype: "piegeage_en_montee" - variable: "Nombre d'individus" - codeVariable: nombre_d_individus - component: unit format: headerLine: 4 firstRowLine: 5