r307 - in trunk: coser-business/src/main/java/fr/ifremer/coser coser-business/src/main/java/fr/ifremer/coser/services coser-business/src/main/resources/fr/ifremer/coser/data coser-business/src/main/resources/i18n coser-business/src/test/java/fr/ifremer/coser/services coser-ui/src/main/java/fr/ifremer/coser/ui
Author: chatellier Date: 2010-11-30 13:15:21 +0000 (Tue, 30 Nov 2010) New Revision: 307 Log: Control des classes de longueur seulement pour les captures de type "poissons" Modified: trunk/coser-business/src/main/java/fr/ifremer/coser/CoserBusinessConfig.java trunk/coser-business/src/main/java/fr/ifremer/coser/services/ControlService.java trunk/coser-business/src/main/resources/fr/ifremer/coser/data/Length-error-validation.xml trunk/coser-business/src/main/resources/i18n/coser-business_en_GB.properties trunk/coser-business/src/main/resources/i18n/coser-business_fr_FR.properties trunk/coser-business/src/test/java/fr/ifremer/coser/services/ControlServiceTest.java trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/CoserFrameHandler.java Modified: trunk/coser-business/src/main/java/fr/ifremer/coser/CoserBusinessConfig.java =================================================================== --- trunk/coser-business/src/main/java/fr/ifremer/coser/CoserBusinessConfig.java 2010-11-30 09:56:42 UTC (rev 306) +++ trunk/coser-business/src/main/java/fr/ifremer/coser/CoserBusinessConfig.java 2010-11-30 13:15:21 UTC (rev 307) @@ -92,6 +92,11 @@ return result; } + public String getControlTypeFish() { + String result = getOption(CoserBusinessOption.CONTROL_TYPE_FISH.key); + return result; + } + public double getSelectionOccurrenceFilter() { double result = getOptionAsDouble(CoserBusinessOption.SELECTION_FILTER_OCCURRENCE.key); return result; @@ -113,6 +118,7 @@ CONTROL_NOBSMIN("coser.control.nobsmin", _("coser.config.control.nobsmin.description"), "1.0", Double.class, false, false), CONTROL_DIFF_CATCH_LENGTH("coser.control.diffcatchlength", _("coser.config.control.diffcatchlength.description"), "5.0", Double.class, false, false), + CONTROL_TYPE_FISH("coser.control.typeFish", _("coser.config.control.typeFish.description"), "Pisces + Agnatha", String.class, false, false), SELECTION_FILTER_OCCURRENCE("coser.selection.occurrenceFilter", _("coser.config.selection.occurrenceFilter.description"), "5.0", Double.class, false, false), SELECTION_FILTER_DENSITY("coser.selection.densityFilter", _("coser.config.selection.densityFilter.description"), "5.0", Double.class, false, false); Modified: trunk/coser-business/src/main/java/fr/ifremer/coser/services/ControlService.java =================================================================== --- trunk/coser-business/src/main/java/fr/ifremer/coser/services/ControlService.java 2010-11-30 09:56:42 UTC (rev 306) +++ trunk/coser-business/src/main/java/fr/ifremer/coser/services/ControlService.java 2010-11-30 13:15:21 UTC (rev 307) @@ -37,6 +37,8 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.xwork.StringUtils; @@ -60,9 +62,9 @@ import fr.ifremer.coser.CoserConstants.ValidationLevel; import fr.ifremer.coser.bean.Control; import fr.ifremer.coser.bean.Project; +import fr.ifremer.coser.control.ControlError; import fr.ifremer.coser.control.DiffCatchLengthControlError; import fr.ifremer.coser.control.ProgressMonitor; -import fr.ifremer.coser.control.ControlError; import fr.ifremer.coser.data.AbstractDataEntity; import fr.ifremer.coser.data.Catch; import fr.ifremer.coser.data.Haul; @@ -92,7 +94,10 @@ protected ActionValidatorManager validator; protected ActionContext context; - + + /** Pattern des tailles de poisson (ex : 1.5, 1.50, 2.00). */ + protected static final Pattern FISH_LENGTH_PATTERN = Pattern.compile("^\\d+(\\.[05]0*)?$"); + /** * Initialise le context xworks. * @@ -819,7 +824,7 @@ itHaul.next(); // skip header // declare all necessary data - Set<String> refTaxSpecies = new HashSet<String>(); + Map<String, Integer> refTaxSpecies = new HashMap<String, Integer>(); Set<String> catchYear = new HashSet<String>(); Set<String> lengthYear = new HashSet<String>(); Set<String> haulYear = new HashSet<String>(); @@ -829,14 +834,31 @@ Set<String> haulYearHaul = new HashSet<String>(); Set<String> lengthYearHaul = new HashSet<String>(); Set<String> catchYearHaul = new HashSet<String>(); + Map<String, Integer[]> specyTypes = new HashMap<String, Integer[]>(); // parcourt de toutes les données while (itReftax.hasNext() ) { String[] tuple = itReftax.next(); // "C_Perm","NumSys","NivSys","C_VALIDE","L_VALIDE","AA_VALIDE","C_TxP\u00E8re","Taxa" - refTaxSpecies.add(tuple[3]); + String specyName = tuple[3]; + Integer iNumSys = Integer.valueOf(tuple[1]); + refTaxSpecies.put(specyName, iNumSys); } + // parcourt du fichier des types de données + Map<String, Integer[]> mapType = new HashMap<String, Integer[]>(); + Iterator<String[]> itTypeSpecies = project.getTypeEspeces().iterator(); + itTypeSpecies.next(); // skip header + while (itTypeSpecies.hasNext()) { + // "Types";"Commentaire";"NumSys min";"NumSys max" + String[] tuple = itTypeSpecies.next(); + String specyType = tuple[0]; + + Integer iMinNumSys = Integer.valueOf(tuple[2]); + Integer iMaxNumSys = Integer.valueOf(tuple[3]); + mapType.put(specyType, new Integer[]{iMinNumSys, iMaxNumSys}); + } + while (itCatch.hasNext()) { String[] catchData = itCatch.next(); campagneNames.add(catchData[Catch.INDEX_SURVEY]); @@ -847,7 +869,7 @@ // Contrôle des noms d'espèces dans fichiers CAPTURES et TAILLES qui // doivent être dans le référentiel "reftax": CAPTURES$Espece et // TAILLES$Espece doivent exister dans REFTAX$ C_VALIDE - if (!refTaxSpecies.contains(catchData[Catch.INDEX_SPECIES])) { + if (!refTaxSpecies.containsKey(catchData[Catch.INDEX_SPECIES])) { ControlError error = new ControlError(); error.setCategory(Category.CATCH); error.addLineNumber(catchData[Catch.INDEX_LINE]); @@ -862,19 +884,20 @@ progress.setText(_("coser.business.control.step.crossFileChech", 25)); progress.setCurrent(25); } - + while (itLength.hasNext()) { String[] lengthData = itLength.next(); + String species = lengthData[Length.INDEX_SPECIES]; campagneNames.add(lengthData[Length.INDEX_SURVEY]); lengthYear.add(lengthData[Length.INDEX_YEAR]); lengthYearHaulSpecies.add(lengthData[Length.INDEX_YEAR] + "|" + - lengthData[Length.INDEX_HAUL] + "|" + lengthData[Length.INDEX_SPECIES]); + lengthData[Length.INDEX_HAUL] + "|" + species); lengthYearHaul.add(lengthData[Length.INDEX_YEAR] + "|" + lengthData[Length.INDEX_HAUL]); - + // Contrôle des noms d'espèces dans fichiers CAPTURES et TAILLES qui // doivent être dans le référentiel "reftax": CAPTURES$Espece et // TAILLES$Espece doivent exister dans REFTAX$ C_VALIDE - if (!refTaxSpecies.contains(lengthData[Length.INDEX_SPECIES])) { + if (!refTaxSpecies.containsKey(species)) { ControlError error = new ControlError(); error.setCategory(Category.LENGTH); error.addLineNumber(lengthData[Length.INDEX_LINE]); @@ -883,6 +906,40 @@ error.setDetailMessage(_("coser.business.control.error.nonExistantSpeciesDetail", lengthData[Length.INDEX_SPECIES])); crossFilesErrors.add(error); } + + else { + // ne doit être fait que si l'escepe existe + + // Contrôle sur le champ TAILLES$Longueur : + // pour les poissons, vérifier que la première décimale n'est que 0 ou 5 + // Décision : Warning si différent de 0 ou 5 -> demander la vérification + // de l'unité et/ou du pas. + // Rappeler que le champ Longueur, quelque soit les espèces, doit être en + // cm et inviter l'utilisateur à vérifier toutes ces données de longueur + + Integer speciesNumSys = refTaxSpecies.get(species); + for (Map.Entry<String, Integer[]> speciesTypeEntry : specyTypes.entrySet()) { + // seulement pour les poissons + String speciesType = speciesTypeEntry.getKey(); + Integer[] bound = speciesTypeEntry.getValue(); + // si le type courant et le type de la config + // et que l'espece courant est de ce type (bornes) + // et que la longueur n'est pas valide + // alors c'est une erreur + if (speciesType.equals(config.getControlTypeFish()) && + speciesNumSys >= bound[0] && speciesNumSys <= bound[1] && + !isValidFishLength(lengthData[Length.INDEX_LENGTH])) { + ControlError error = new ControlError(); + error.setCategory(Category.LENGTH); + error.addLineNumber(lengthData[Length.INDEX_LINE]); + error.setLevel(ValidationLevel.WARNING); + error.setMessage(_("coser.business.control.error.invalidLengthLengthStep")); + error.setDetailMessage(_("coser.business.control.error.invalidLengthLengthStepDetail", lengthData[Length.INDEX_LENGTH])); + error.setTipMessage(_("coser.business.control.error.invalidLengthLengthStepTip")); + crossFilesErrors.add(error); + } + } + } } if (progress != null) { @@ -972,4 +1029,15 @@ return crossFilesErrors; } + + /** + * Return {@code true} if given length is valid length (cm or half cm). + * + * @param length lengthto test + * @return {@code true} if given length is valid length (cm or half cm) + */ + protected boolean isValidFishLength(String length) { + Matcher mLength = FISH_LENGTH_PATTERN.matcher(length); + return mLength.matches(); + } } Modified: trunk/coser-business/src/main/resources/fr/ifremer/coser/data/Length-error-validation.xml =================================================================== --- trunk/coser-business/src/main/resources/fr/ifremer/coser/data/Length-error-validation.xml 2010-11-30 09:56:42 UTC (rev 306) +++ trunk/coser-business/src/main/resources/fr/ifremer/coser/data/Length-error-validation.xml 2010-11-30 13:15:21 UTC (rev 307) @@ -65,10 +65,6 @@ <message>length attribute is not a valid double</message> </field-validator> </field> - <validator type="coserExpression"> - <param name="expression"><![CDATA[lengthAsString.endsWith(".00") || lengthAsString.endsWith(".0") || lengthAsString.endsWith(".50") || lengthAsString.endsWith(".5")]]></param> - <message>coser.business.control.error.invalidLengthLengthStep</message> - </validator> <field name="numberAsString"> <field-validator type="checkDouble"> <param name="notAvailable">NA</param> Modified: trunk/coser-business/src/main/resources/i18n/coser-business_en_GB.properties =================================================================== --- trunk/coser-business/src/main/resources/i18n/coser-business_en_GB.properties 2010-11-30 09:56:42 UTC (rev 306) +++ trunk/coser-business/src/main/resources/i18n/coser-business_en_GB.properties 2010-11-30 13:15:21 UTC (rev 307) @@ -33,6 +33,8 @@ coser.business.control.error.duplicatedLine=Duplicated line coser.business.control.error.duplicatedLineDetails=Duplicated line for key \: %s coser.business.control.error.invalidLengthLengthStep=Invalid length step (authorized centimeters and half-centimeters) +coser.business.control.error.invalidLengthLengthStepDetail=Invalid length step %s +coser.business.control.error.invalidLengthLengthStepTip=Length field must be in centimeters. coser.business.control.error.minObservationCount=Minimum number of observation not reached coser.business.control.error.minObservationCountDetail=Minimum number of observation not reached (%s) \: %.2f coser.business.control.error.missingYearHaulForCatchData=Missing hauls in haul data for some catch @@ -60,6 +62,7 @@ coser.business.selection.notValidatedControl=Not validated control \! coser.config.control.diffcatchlength.description=Percentage difference allowed between catch and length (in percent, for example 5% set 5.0) coser.config.control.nobsmin.description=Minimal observation number +coser.config.control.typeFish.description=Fish species code type coser.config.database.directory.description=Coser database directory (all Coser data) coser.config.projects.directory.description=Coser projects directory coser.config.reference.species.description=Species reference file location (reftax) Modified: trunk/coser-business/src/main/resources/i18n/coser-business_fr_FR.properties =================================================================== --- trunk/coser-business/src/main/resources/i18n/coser-business_fr_FR.properties 2010-11-30 09:56:42 UTC (rev 306) +++ trunk/coser-business/src/main/resources/i18n/coser-business_fr_FR.properties 2010-11-30 13:15:21 UTC (rev 307) @@ -32,7 +32,9 @@ coser.business.control.error.diffCatchLengthDetail=Diff\u00E9rence entre les captures et taille pour l'esp\u00E8ce %s (ann\u00E9e %s) coser.business.control.error.duplicatedLine=Ligne en doublon coser.business.control.error.duplicatedLineDetails=Ligne en doublon pour la cl\u00E9 \: %s -coser.business.control.error.invalidLengthLengthStep=Pas de longeur invalide (autoris\u00E9 centim\u00E8tre et demi-centim\u00E8tre) +coser.business.control.error.invalidLengthLengthStep=Pas de longueur invalide (autoris\u00E9 centim\u00E8tre et demi-centim\u00E8tre) +coser.business.control.error.invalidLengthLengthStepDetail=Pas longueur %s invalide +coser.business.control.error.invalidLengthLengthStepTip=Le champs de longueur doit \u00EAtre en centim\u00E8tre (ou demi centim\u00E8tre) coser.business.control.error.minObservationCount=Nombre minimal d'observation non atteint coser.business.control.error.minObservationCountDetail=Nombre minimal d'observation non atteint (%s) \: %.2f coser.business.control.error.missingYearHaulForCatchData=Traits manquants dans les traits pour certaines captures @@ -60,6 +62,7 @@ coser.business.selection.notValidatedControl=Contr\u00F4le non valid\u00E9 \! coser.config.control.diffcatchlength.description=Pourcentage d'\u00E9cart tol\u00E9r\u00E9 entre les captures et les tailles (en pourcent, par exemple pour 5% mettre 5.0) coser.config.control.nobsmin.description=Nombre minimal d'observation +coser.config.control.typeFish.description=Nom du type d'esp\u00E8ces correspondant aux poissons coser.config.database.directory.description=Emplacement du dossier de toutes les donn\u00E9es relatives \u00E0 Coser coser.config.projects.directory.description=Emplacement du dossier de sauvegarde des projets coser.config.reference.species.description=Emplacement du fichier de r\u00E9f\u00E9rence des esp\u00E8ces (Reftax) Modified: trunk/coser-business/src/test/java/fr/ifremer/coser/services/ControlServiceTest.java =================================================================== --- trunk/coser-business/src/test/java/fr/ifremer/coser/services/ControlServiceTest.java 2010-11-30 09:56:42 UTC (rev 306) +++ trunk/coser-business/src/test/java/fr/ifremer/coser/services/ControlServiceTest.java 2010-11-30 13:15:21 UTC (rev 307) @@ -54,7 +54,7 @@ private static final Log log = LogFactory.getLog(ControlServiceTest.class); - protected ControlService validationService = new ControlService(config); + protected ControlService controlService = new ControlService(config); /** * Test les validations sur les champs vide. @@ -65,12 +65,12 @@ Catch myCatch = new Catch(); myCatch.setData(new String[]{"1", "","","","","",""}); - List<ControlError> errors = validationService.validate(myCatch, Category.CATCH); + List<ControlError> errors = controlService.validate(myCatch, Category.CATCH); Assert.assertNotNull(errors); Assert.assertEquals(4, errors.size()); myCatch.setData(new String[]{"1", "Toto","","","","999",""}); - errors = validationService.validate(myCatch, Category.CATCH); + errors = controlService.validate(myCatch, Category.CATCH); Assert.assertNotNull(errors); Assert.assertEquals(3, errors.size()); } @@ -82,7 +82,7 @@ public void testDoubleValidation() { Catch myCatch = new Catch(); myCatch.setData(new String[]{"1", "Test survey","1999","Test trait","Test sp","NA","12"}); - List<ControlError> errors = validationService.validate(myCatch, Category.CATCH); + List<ControlError> errors = controlService.validate(myCatch, Category.CATCH); log.warn(errors); Assert.assertTrue(errors.isEmpty()); } @@ -95,9 +95,10 @@ Length myLength = new Length(); // "Survey","Year","Haul","Species","Sex","Maturity","Length","Number","Weight","Age" myLength.setData(new String[]{"1", "Test survey","1999","Test trait","Test sp","i","m","23.25", "3.00", "44.99", "12"}); - List<ControlError> errors = validationService.validate(myLength, Category.LENGTH); + List<ControlError> errors = controlService.validate(myLength, Category.LENGTH); log.warn(errors); - Assert.assertEquals(1, errors.size()); + // TODO test a refaire (croisement de fichier) + //Assert.assertEquals(1, errors.size()); } /** @@ -107,16 +108,16 @@ public void test5DecimalValidation() { Haul haulBean = new Haul(); haulBean.setData(new String[]{"1", "COSER_TEST","2010","TRAIT3","10","STR3","0.06","43.89","1.73","115.00"}); - List<ControlError> errors = validationService.validate(haulBean, Category.HAUL); + List<ControlError> errors = controlService.validate(haulBean, Category.HAUL); Assert.assertEquals(3, errors.size()); haulBean.setData(new String[]{"1","COSER_TEST","2010","TRAIT3","10","STR3","0.06000","43.89000","1.73234","115.00"}); - errors = validationService.validate(haulBean, Category.HAUL); + errors = controlService.validate(haulBean, Category.HAUL); Assert.assertTrue(errors.isEmpty()); } /** - * Test, si un poids est reseigné, la capture doit l'etre. + * Test, si un poids est renseigné, la capture doit l'etre. */ @Test public void testWeigthWithNonCapture() { @@ -125,10 +126,27 @@ dataCatch.add(new String[]{"Line", "Campagne","Annee","Trait","Espece","Nombre","Poids"}); dataCatch.add(new String[]{"1", "Test survey","1999","Test trait","Test sp","0","12"}); control.setCatch(dataCatch); - List<ControlError> errors = validationService.validateCategory(control, Category.CATCH, null); + List<ControlError> errors = controlService.validateCategory(control, Category.CATCH, null); if (log.isDebugEnabled()) { log.debug("Validation errors = " + errors); } Assert.assertEquals(2, errors.size()); } + + /** + * Test si le pas de longueur est valid pour les poissons. + */ + @Test + public void testValidFishLength() { + Assert.assertTrue(controlService.isValidFishLength("4")); + Assert.assertTrue(controlService.isValidFishLength("4.5")); + Assert.assertTrue(controlService.isValidFishLength("0")); + Assert.assertTrue(controlService.isValidFishLength("0.5")); + Assert.assertTrue(controlService.isValidFishLength("1.50")); + Assert.assertTrue(controlService.isValidFishLength("1.00")); + Assert.assertTrue(controlService.isValidFishLength("1.500")); + Assert.assertFalse(controlService.isValidFishLength("")); + Assert.assertFalse(controlService.isValidFishLength("1.3")); + Assert.assertFalse(controlService.isValidFishLength("1.001")); + } } Modified: trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/CoserFrameHandler.java =================================================================== --- trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/CoserFrameHandler.java 2010-11-30 09:56:42 UTC (rev 306) +++ trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/CoserFrameHandler.java 2010-11-30 13:15:21 UTC (rev 307) @@ -161,6 +161,7 @@ modelBuilder.addCategory(_("coser.config.category.configuration"), _("coser.config.category.configuration.description")); modelBuilder.addOption(CoserBusinessConfig.CoserBusinessOption.CONTROL_NOBSMIN); modelBuilder.addOption(CoserBusinessConfig.CoserBusinessOption.CONTROL_DIFF_CATCH_LENGTH); + modelBuilder.addOption(CoserBusinessConfig.CoserBusinessOption.CONTROL_TYPE_FISH); modelBuilder.addOption(CoserBusinessConfig.CoserBusinessOption.SELECTION_FILTER_OCCURRENCE); modelBuilder.addOption(CoserBusinessConfig.CoserBusinessOption.SELECTION_FILTER_DENSITY);
participants (1)
-
chatellier@users.labs.libre-entreprise.org