View Javadoc
1   package fr.ifremer.tutti.service.bigfin;
2   
3   /*
4    * #%L
5    * Tutti :: Service
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2012 - 2014 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU General Public License as
13   * published by the Free Software Foundation, either version 3 of the
14   * License, or (at your option) any later version.
15   * 
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   * 
21   * You should have received a copy of the GNU General Public
22   * License along with this program.  If not, see
23   * <http://www.gnu.org/licenses/gpl-3.0.html>.
24   * #L%
25   */
26  
27  import com.google.common.base.Charsets;
28  import com.google.common.base.Function;
29  import com.google.common.base.Preconditions;
30  import com.google.common.collect.ArrayListMultimap;
31  import com.google.common.collect.Collections2;
32  import com.google.common.collect.ListMultimap;
33  import com.google.common.collect.Maps;
34  import com.google.common.collect.Multimap;
35  import com.google.common.collect.Multimaps;
36  import com.google.common.io.Files;
37  import fr.ifremer.adagio.core.dao.referential.ObjectTypeCode;
38  import fr.ifremer.adagio.core.dao.referential.pmfm.PmfmId;
39  import fr.ifremer.tutti.persistence.entities.data.Attachment;
40  import fr.ifremer.tutti.persistence.entities.data.Attachments;
41  import fr.ifremer.tutti.persistence.entities.data.BatchContainer;
42  import fr.ifremer.tutti.persistence.entities.data.CatchBatch;
43  import fr.ifremer.tutti.persistence.entities.data.FishingOperation;
44  import fr.ifremer.tutti.persistence.entities.data.SampleCategoryModel;
45  import fr.ifremer.tutti.persistence.entities.data.SpeciesBatch;
46  import fr.ifremer.tutti.persistence.entities.data.SpeciesBatchFrequency;
47  import fr.ifremer.tutti.persistence.entities.data.SpeciesBatchFrequencys;
48  import fr.ifremer.tutti.persistence.entities.data.SpeciesBatchs;
49  import fr.ifremer.tutti.persistence.entities.protocol.SpeciesProtocol;
50  import fr.ifremer.tutti.persistence.entities.protocol.TuttiProtocol;
51  import fr.ifremer.tutti.persistence.entities.referential.Caracteristic;
52  import fr.ifremer.tutti.persistence.entities.referential.CaracteristicQualitativeValue;
53  import fr.ifremer.tutti.persistence.entities.referential.Species;
54  import fr.ifremer.tutti.persistence.entities.referential.Speciess;
55  import fr.ifremer.tutti.service.AbstractTuttiService;
56  import fr.ifremer.tutti.service.PersistenceService;
57  import fr.ifremer.tutti.service.TuttiServiceContext;
58  import fr.ifremer.tutti.service.bigfin.csv.BigfinDataRow;
59  import fr.ifremer.tutti.service.bigfin.csv.BigfinDataRowModel;
60  import fr.ifremer.tutti.service.bigfin.signs.Sex;
61  import fr.ifremer.tutti.service.bigfin.signs.Sign;
62  import fr.ifremer.tutti.service.bigfin.signs.Size;
63  import fr.ifremer.tutti.service.bigfin.signs.VracHorsVrac;
64  import fr.ifremer.tutti.type.WeightUnit;
65  import java.io.File;
66  import java.io.IOException;
67  import java.io.Reader;
68  import java.io.Serializable;
69  import java.text.DateFormat;
70  import java.util.ArrayList;
71  import java.util.Collection;
72  import java.util.HashMap;
73  import java.util.List;
74  import java.util.Map;
75  import java.util.Set;
76  import org.apache.commons.collections4.CollectionUtils;
77  import org.apache.commons.collections4.IterableUtils;
78  import org.apache.commons.lang3.StringUtils;
79  import org.apache.commons.logging.Log;
80  import org.apache.commons.logging.LogFactory;
81  import org.nuiton.csv.Import;
82  import org.nuiton.csv.ImportRuntimeException;
83  import org.nuiton.jaxx.application.ApplicationBusinessException;
84  
85  import static org.nuiton.i18n.I18n.t;
86  
87  /**
88   * @author Kevin Morin (Code Lutin)
89   * @since 3.8
90   */
91  public class BigfinImportService extends AbstractTuttiService {
92  
93      private static final Log log = LogFactory.getLog(BigfinImportService.class);
94  
95      protected PersistenceService persistenceService;
96  
97      protected Caracteristic sizeCaracteristic;
98  
99      protected Caracteristic sexCaracteristic;
100 
101     protected Map<Sign, CaracteristicQualitativeValue> signsToCaracteristicValue;
102 
103     @Override
104     public void setServiceContext(TuttiServiceContext context) {
105 
106         super.setServiceContext(context);
107         persistenceService = getService(PersistenceService.class);
108 
109         signsToCaracteristicValue = new HashMap<>();
110 
111         // sex caracteristic
112         sexCaracteristic = persistenceService.getSexCaracteristic();
113         Sex.NONE.registerSign(sexCaracteristic, signsToCaracteristicValue);
114         Sex.UNKNOWN.registerSign(sexCaracteristic, signsToCaracteristicValue);
115         Sex.MALE.registerSign(sexCaracteristic, signsToCaracteristicValue);
116         Sex.FEMALE.registerSign(sexCaracteristic, signsToCaracteristicValue);
117 
118         // size caracteristic
119         sizeCaracteristic = persistenceService.getSizeCategoryCaracteristic();
120         Size.NOT_SIZED.registerSign(sizeCaracteristic, signsToCaracteristicValue);
121         Size.SMALL.registerSign(sizeCaracteristic, signsToCaracteristicValue);
122         Size.BIG.registerSign(sizeCaracteristic, signsToCaracteristicValue);
123 
124         // sorted/unsorted caracteristic
125         Caracteristic vracHorsVracCaracteristic = persistenceService.getSortedUnsortedCaracteristic();
126         VracHorsVrac.VRAC.registerSign(vracHorsVracCaracteristic, signsToCaracteristicValue);
127         VracHorsVrac.HORS_VRAC.registerSign(vracHorsVracCaracteristic, signsToCaracteristicValue);
128 
129     }
130 
131     private BigfinImportContext prepareImportContext(File importFile, FishingOperation operation, CatchBatch catchBatch) {
132 
133         TuttiProtocol protocol = persistenceService.getProtocol();
134 
135         if (protocol == null) {
136             throw new ApplicationBusinessException(t("tutti.service.bigfinimport.error.no.protocol"));
137         }
138 
139         List<Species> allReferentSpecies = persistenceService.getAllReferentSpecies();
140         Map<String, Species> speciesBySurveyCode = Maps.newTreeMap();
141         for (Species species : allReferentSpecies) {
142             String surveyCode = species.getSurveyCode();
143             if (StringUtils.isNotBlank(surveyCode)) {
144                 speciesBySurveyCode.put(surveyCode, species);
145 
146             }
147             if (species.getRefTaxCode() != null) {
148                 speciesBySurveyCode.put(species.getRefTaxCode(), species);
149             }
150         }
151 
152         Map<String, SpeciesProtocol> speciesProtocolBySurveyCode = Maps.newTreeMap();
153         for (SpeciesProtocol speciesProtocol : protocol.getSpecies()) {
154             if (StringUtils.isNotBlank(speciesProtocol.getSpeciesSurveyCode())) {
155                 speciesProtocolBySurveyCode.put(speciesProtocol.getSpeciesSurveyCode(), speciesProtocol);
156 
157             } else {
158                 speciesProtocolBySurveyCode.put(speciesProtocol.getSpeciesReferenceTaxonId().toString(), speciesProtocol);
159             }
160         }
161 
162         BatchContainer<SpeciesBatch> rootSpeciesBatch = persistenceService.getRootSpeciesBatch(operation.getIdAsInt(), false);
163 
164         // make sure we use survey codes if possible in species batches (see https://forge.codelutin.com/issues/6848)
165         if (!rootSpeciesBatch.isEmptyChildren()) {
166 
167             Map<String, Species> speciesByReferenceTaxonId = Speciess.splitReferenceSpeciesByReferenceTaxonId(allReferentSpecies);
168 
169             for (SpeciesBatch speciesBatch : rootSpeciesBatch.getChildren()) {
170                 Species species = speciesBatch.getSpecies();
171                 Integer referenceTaxonId = species.getReferenceTaxonId();
172                 Preconditions.checkNotNull(referenceTaxonId, "Can't have a null referenceTaxonId for species: " + species);
173                 Species species1 = speciesByReferenceTaxonId.get(referenceTaxonId.toString());
174                 consolidateSpecies(speciesBatch, species1);
175 
176             }
177 
178         }
179 
180         return new BigfinImportContext(importFile, operation, catchBatch, signsToCaracteristicValue, speciesBySurveyCode, speciesProtocolBySurveyCode, rootSpeciesBatch);
181 
182     }
183 
184     protected void consolidateSpecies(SpeciesBatch speciesBatch, Species species) {
185 
186         speciesBatch.setSpecies(species);
187         if (!speciesBatch.isChildBatchsEmpty()) {
188 
189             for (SpeciesBatch childBatch : speciesBatch.getChildBatchs()) {
190                 consolidateSpecies(childBatch, species);
191             }
192         }
193 
194     }
195 
196     public BigfinImportResult importFile(File importFile, FishingOperation operation, CatchBatch catchBatch) {
197 
198         Preconditions.checkNotNull(importFile);
199         Preconditions.checkArgument(importFile.exists(), "Bigfin file " + importFile + " does not exist.");
200 
201         BigfinImportContext importContext = prepareImportContext(importFile, operation, catchBatch);
202 
203         BigfinDataRowModel importModel = new BigfinDataRowModel(importContext.speciesBySurveyCode, importContext.getSpeciesBatchesById());
204 
205         try (Reader reader = Files.newReader(importFile, Charsets.UTF_8)) {
206 
207             try (Import<BigfinDataRow> importer = Import.newImport(importModel, reader)) {
208 
209                 for (BigfinDataRow bigfinDataRow : importer) {
210 
211                     if (log.isInfoEnabled()) {
212                         log.info("Check row: " + bigfinDataRow.getRecordId());
213                     }
214                     boolean rowIsSafe = importContext.checkRow(bigfinDataRow);
215 
216                     if (rowIsSafe) {
217 
218                         importContext.addRowToProcess(bigfinDataRow);
219                     }
220 
221                 }
222 
223             }
224 
225         } catch (IOException e) {
226             throw new ImportRuntimeException("Could not import bigfin data from file " + importFile, e);
227 
228         }
229 
230         if (importContext.isNoError()) {
231 
232             processSpeciesBatchRows(importContext);
233 
234             processSpeciesRows(importContext);
235 
236             addFileAsAttachment(importFile, importContext.catchBatch);
237 
238         }
239 
240         return importContext.getResult();
241 
242     }
243 
244 
245     private void processSpeciesBatchRows(BigfinImportContext importContext) {
246 
247         BigfinImportResult result = importContext.getResult();
248 
249         Multimap<SpeciesBatch, BigfinDataRow> speciesBatchRowsBySpeciesBatch = importContext.getSpeciesBatchRowsBySpeciesBatch();
250 
251         for (SpeciesBatch batch : speciesBatchRowsBySpeciesBatch.keySet()) {
252 
253             List<SpeciesBatchFrequency> existingSpeciesFrequencies = persistenceService.getAllSpeciesBatchFrequency(batch.getIdAsInt());
254 
255             Integer deletedNb = persistenceService.countFrequenciesNumber(existingSpeciesFrequencies, false);
256 
257             Collection<BigfinDataRow> bigfinDataRows = speciesBatchRowsBySpeciesBatch.get(batch);
258 
259             Species species = importContext.getSpeciesWithSurveyCode(batch.getSpecies());
260             Caracteristic lengthStepPmfm = importContext.getLengthStepPmfm(species, persistenceService);
261             List<SpeciesBatchFrequency> frequencies = createFrequencies(batch, bigfinDataRows, lengthStepPmfm);
262 
263             persistenceService.saveSpeciesBatchFrequency(batch.getIdAsInt(), frequencies);
264 
265             result.incrementNbFrequenciesDeleted(deletedNb != null ? deletedNb : 0);
266 
267             Integer importedNb = persistenceService.countFrequenciesNumber(frequencies, false);
268             result.incrementNbFrequenciesImported(importedNb != null ? importedNb : 0);
269 
270         }
271 
272     }
273 
274     private void processSpeciesRows(BigfinImportContext importContext) {
275 
276         BigfinImportResult result = importContext.getResult();
277 
278         SampleCategoryModel sampleCategoryModel = context.getSampleCategoryModel();
279         List<Integer> samplingOrder = sampleCategoryModel.getSamplingOrder();
280 
281         List<Integer> pmfmIds = new ArrayList<>();
282         pmfmIds.add(PmfmId.SORTED_UNSORTED.getValue());
283         List<Function<BigfinDataRow, Sign>> functions = new ArrayList<>();
284 
285         // put the size and order in the right order
286         for (Integer categoryId : samplingOrder) {
287             if (PmfmId.SIZE_CATEGORY.getValue().equals(categoryId)) {
288                 pmfmIds.add(categoryId);
289                 functions.add(Size.newExtractValueFunction());
290 
291             } else if (PmfmId.SEX.getValue().equals(categoryId)) {
292                 pmfmIds.add(categoryId);
293                 functions.add(Sex.newExtractValueFunction());
294             }
295         }
296 
297         List<Category> categories = new ArrayList<>();
298         for (int i = 0; i < pmfmIds.size(); i++) {
299             Category category = new Category(pmfmIds.get(i), i < functions.size() ? functions.get(i) : null);
300             categories.add(category);
301         }
302 
303         // and separate them by species
304         Multimap<Species, SpeciesBatch> batchesBySpecies = importContext.getRootSpeciesBatchBySpecies();
305 
306         // separate the imported rows by species
307         Multimap<Species, BigfinDataRow> rowsBySpecies = importContext.getSpeciesRowsBySpecies();
308 
309         // for each species imported
310         for (Species species : rowsBySpecies.keySet()) {
311 
312             // get the lengthstep pmfm associated with the species
313             Caracteristic lengthStepPmfm = importContext.getLengthStepPmfm(species, persistenceService);
314 
315             // get the rows with the current species and separate them by vrac/hors varc
316             Collection<BigfinDataRow> speciesRows = rowsBySpecies.get(species);
317             Multimap<Sign, BigfinDataRow> rowsByVracHorsVrac = Multimaps.index(speciesRows, VracHorsVrac.newExtractValueFunction());
318 
319             // get the existing species batches for the current species and separate them by vrac/hors varc
320             Collection<SpeciesBatch> speciesBatches = batchesBySpecies.get(species);
321             Map<Serializable, SpeciesBatch> speciesBatchByVracHorsVrac = Maps.uniqueIndex(speciesBatches, SpeciesBatchs.GET_SAMPLE_CATEGORY_VALUE);
322 
323             BrowseBatchesParameter commonParameter = new BrowseBatchesParameter(importContext.operation, species, lengthStepPmfm, categories, result);
324             browseBatchesToAddFrequencies(commonParameter, null, 0, speciesBatchByVracHorsVrac, rowsByVracHorsVrac);
325 
326         }
327 
328     }
329 
330 
331     /**
332      * Go deeper in the batches until it finds the last of gender or size class, then add the frequencies
333      *
334      * @param commonParameter        The parameter containing the parameters which do not change while browsing
335      * @param parentBatch            The parent batch (null if root)
336      * @param depth                  The depth in the batch children
337      * @param batchesByCaracteristic a map containing the batches by caracteristic value
338      * @param rowsByCaracteristic    a multimap containing the rows to import by caracteristic value
339      */
340     protected void browseBatchesToAddFrequencies(BrowseBatchesParameter commonParameter,
341                                                  SpeciesBatch parentBatch,
342                                                  int depth,
343                                                  Map<Serializable, SpeciesBatch> batchesByCaracteristic,
344                                                  Multimap<Sign, BigfinDataRow> rowsByCaracteristic) {
345 
346         Category category = commonParameter.getCategories().get(depth++);
347 
348         int parentSignChildrenNb = rowsByCaracteristic.keySet().size();
349 
350         for (Sign caracteristic : rowsByCaracteristic.keySet()) {
351             Collection<BigfinDataRow> bigfinDataRows = rowsByCaracteristic.get(caracteristic);
352 
353             // get the batch with the caracteristic
354             SpeciesBatch batch = batchesByCaracteristic.get(signsToCaracteristicValue.get(caracteristic));
355 
356             boolean batchHasFrequencies = false;
357 
358             // if it does not exists, create the batch
359             if (batch == null) {
360                 if (caracteristic.isNullEquivalent(parentSignChildrenNb)) {
361                     batch = parentBatch;
362 
363                 } else {
364                     batch = createSpeciesBatch(commonParameter.getSpecies(),
365                                                commonParameter.getOperation(),
366                                                category.getPmfmId(),
367                                                caracteristic,
368                                                parentBatch != null ? parentBatch.getIdAsInt() : null);
369                     // useful to be able to save the batch later in the frequency creation
370                     batch.setParentBatch(parentBatch);
371                 }
372 
373             } else {
374                 // useful to be able to save the batch later in the frequency creation
375                 batch.setFishingOperation(commonParameter.getOperation());
376                 List<SpeciesBatchFrequency> frequencies = persistenceService.getAllSpeciesBatchFrequency(batch.getIdAsInt());
377                 batchHasFrequencies = CollectionUtils.isNotEmpty(frequencies);
378             }
379 
380             // if the function is null, do not go deeper in the batch children, add the frequencies in this batch
381             if (category.getCategoryValueGetter() == null) {
382                 // if the batch is not the last one, error, we cannot add the frequencies to a more categorized batch
383                 if (CollectionUtils.isNotEmpty(batch.getChildBatchs())) {
384                     commonParameter.getResult().addWarning(t("tutti.service.bigfinImport.warning.species.tooCategorized",
385                                                              commonParameter.getSpeciesLabel(),
386                                                              sizeCaracteristic.getParameterName(),
387                                                              sexCaracteristic.getParameterName()));
388 
389                 } else {
390                     // create the frequencies
391                     Integer deletedNb = persistenceService.countFrequenciesNumber(
392                             persistenceService.getAllSpeciesBatchFrequency(batch.getIdAsInt()), false);
393 
394                     List<SpeciesBatchFrequency> frequencies = createFrequencies(batch, bigfinDataRows, commonParameter.getLengthStepPmfm());
395 
396                     persistenceService.saveSpeciesBatchFrequency(batch.getIdAsInt(), frequencies);
397 
398                     commonParameter.getResult().incrementNbFrequenciesDeleted(deletedNb != null ? deletedNb : 0);
399 
400                     Integer importedNb = persistenceService.countFrequenciesNumber(frequencies, false);
401                     commonParameter.getResult().incrementNbFrequenciesImported(importedNb != null ? importedNb : 0);
402                 }
403 
404             } else if (batchHasFrequencies) { // if the batch is supposed to be categorized again, but already has frequencies
405                 CaracteristicQualitativeValue qualitativeValue = signsToCaracteristicValue.get(caracteristic);
406                 commonParameter.getResult().addWarning(t("tutti.service.bigfinImport.warning.species.batch.frequenciesOnHigherLevel",
407                                                          commonParameter.getSpeciesLabel(), qualitativeValue.getName()));
408 
409             } else {
410                 List<SpeciesBatch> batchChildren = batch.getChildBatchs();
411 
412                 Multimap<Sign, BigfinDataRow> rowsByNewCaracteristic = Multimaps.index(bigfinDataRows, category.getCategoryValueGetter());
413 
414                 // get the children of the current batch and separate them by caracteristic
415                 Map<Serializable, SpeciesBatch> childrenByCaracteristic = new HashMap<>();
416                 if (CollectionUtils.isNotEmpty(batchChildren)) {
417 
418                     SpeciesBatch firstBatch = batchChildren.get(0);
419                     Integer categoryId = firstBatch.getSampleCategoryId();
420                     Category nextCategory = commonParameter.getCategories().get(depth);
421 
422                     // check the category is the right next one
423                     if (!nextCategory.getPmfmId().equals(categoryId)) {
424                         // if all the rows to import have a gender or size (the first category in the list) null equivalent
425                         // then ok
426                         // else error
427                         Set<Sign> signsSet = rowsByNewCaracteristic.keySet();
428                         if (signsSet.size() == 1 && signsSet.iterator().next().isNullEquivalent(parentSignChildrenNb)) {// we can go deeper
429                             category = commonParameter.getCategories().get(depth++);
430                             rowsByNewCaracteristic = Multimaps.index(bigfinDataRows, category.getCategoryValueGetter());
431 
432                             // check that this time, it is the right category. We can only skip one
433                             nextCategory = commonParameter.getCategories().get(depth);
434                             if (!nextCategory.getPmfmId().equals(categoryId)) {
435                                 commonParameter.getResult().addWarning(t("tutti.service.bigfinImport.warning.species.categoriesSkipped",
436                                                                          commonParameter.getSpeciesLabel(),
437                                                                          sizeCaracteristic.getParameterName(),
438                                                                          sexCaracteristic.getParameterName()
439                                 ));
440                                 continue;
441                             }
442 
443                         } else {
444                             commonParameter.getResult().addWarning(t("tutti.service.bigfinImport.warning.species.categorySkipped",
445                                                                      commonParameter.getSpeciesLabel(),
446                                                                      persistenceService.getCaracteristic(nextCategory.getPmfmId()).getParameterName()
447                             ));
448                             continue;
449                         }
450                     }
451                     childrenByCaracteristic.putAll(Maps.uniqueIndex(batchChildren, SpeciesBatchs.GET_SAMPLE_CATEGORY_VALUE));
452                 }
453 
454                 // go deeper in the batch children
455                 browseBatchesToAddFrequencies(commonParameter, batch, depth, childrenByCaracteristic, rowsByNewCaracteristic);
456             }
457 
458         }
459     }
460 
461     protected SpeciesBatch createSpeciesBatch(Species species,
462                                               FishingOperation operation,
463                                               Integer categoryId,
464                                               Sign signs,
465                                               Integer parentBatchId) {
466 
467         Preconditions.checkArgument(signs.getCategory().equals(categoryId));
468 
469         SpeciesBatch batch = SpeciesBatchs.newSpeciesBatch();
470         batch.setSpecies(species);
471         batch.setFishingOperation(operation);
472 
473         batch.setSampleCategoryId(categoryId);
474         batch.setSampleCategoryValue(signsToCaracteristicValue.get(signs));
475 
476         batch = persistenceService.createSpeciesBatch(batch, parentBatchId, true);
477         return batch;
478     }
479 
480     protected List<SpeciesBatchFrequency> createFrequencies(SpeciesBatch batch, Collection<BigfinDataRow> rows, Caracteristic lengthStepPmfm) {
481         Preconditions.checkNotNull(lengthStepPmfm);
482         String unit = lengthStepPmfm.getUnit();
483         Float precision = lengthStepPmfm.getPrecision();
484         // CHANGE poussin 2016, maintenant getPrecision retourne toujours quelque chose
485 //        if (precision == null) {
486 //            precision = 1f;
487 //        }
488 
489         // board measurements are in mm
490 
491         ListMultimap<Float, Float> weightsByLengthStep = ArrayListMultimap.create();
492         for (BigfinDataRow row : rows) {
493             Float weight = row.getWeight();
494             float length = row.getLength();
495 
496             if ("cm".equals(unit)) {
497                 // measurement in cm asked
498                 length = length / 10;
499             }
500 
501             int intValue = (int) (length * 10);
502             int intStep = (int) (precision * 10);
503             int correctIntStep = intValue - (intValue % intStep);
504             float lengthStep = correctIntStep / 10f;
505 
506             weightsByLengthStep.put(lengthStep, weight);
507         }
508 
509         // tous les poids du batch
510         Collection<Float> weightValues = weightsByLengthStep.values();
511         int weightValuesSize = weightValues.size();
512 
513         // poids non nuls du batch
514         Collection<Float> notNullWeights = Collections2.filter(weightValues, input -> input != null);
515         int notNullWeightsSize = notNullWeights.size();
516 
517         // si présence d'une seule valeur, mettre cette valeur dans le champ "Poids sous échantillon"
518         if (notNullWeightsSize == 1) {
519             float weight = IterableUtils.get(notNullWeights, 0);
520             weight = WeightUnit.KG.round(weight / 1000);
521             batch.setWeight(weight);
522             persistenceService.saveSpeciesBatch(batch);
523         }
524 
525         // si présence de plusieurs valeurs et aucune vide, renseigner les champs "Poids Observé" en face des classes de taille
526         boolean importWeights = weightValuesSize == notNullWeightsSize;
527 
528         List<SpeciesBatchFrequency> frequencies = new ArrayList<>();
529         for (Float lengthStep : weightsByLengthStep.keySet()) {
530             SpeciesBatchFrequency frequency = SpeciesBatchFrequencys.newSpeciesBatchFrequency();
531             frequencies.add(frequency);
532 
533             frequency.setBatch(batch);
534             frequency.setLengthStep(lengthStep);
535             frequency.setLengthStepCaracteristic(lengthStepPmfm);
536 
537             Collection<Float> weights = weightsByLengthStep.get(lengthStep);
538             frequency.setNumber(weights.size());
539 
540             if (importWeights) {
541                 // all the weights are not null
542                 float totalWeight = 0f;
543                 for (float weight : weights) {
544                     totalWeight += weight;
545                 }
546                 if (totalWeight > 0f) {
547                     // convert grams to kilograms
548                     totalWeight = WeightUnit.KG.round(totalWeight / 1000);
549                     frequency.setWeight(totalWeight);
550                 }
551             }
552         }
553         return frequencies;
554     }
555 
556     protected void addFileAsAttachment(File f, CatchBatch catchBatch) {
557         Attachment attachment = Attachments.newAttachment();
558         attachment.setObjectType(ObjectTypeCode.CATCH_BATCH);
559         attachment.setObjectId(Integer.valueOf(catchBatch.getId()));
560         attachment.setName(f.getName());
561         String date = DateFormat.getDateTimeInstance().format(context.currentDate());
562         String comment = t("tutti.service.bigfin.import.attachment.comment", date);
563         attachment.setComment(comment);
564         persistenceService.createAttachment(attachment, f);
565     }
566 
567     /**
568      * Class describing the category of a batch level and the function to separate the rows to import by category value
569      */
570     private class Category {
571 
572         private Integer pmfmId;
573 
574         /** function to get the value of the caracteristic we want to group the batches by (eg size or gender) */
575         private Function<BigfinDataRow, Sign> categoryValueGetter;
576 
577         public Category(Integer pmfmId, Function<BigfinDataRow, Sign> dataGetter) {
578             this.pmfmId = pmfmId;
579             this.categoryValueGetter = dataGetter;
580         }
581 
582         public Integer getPmfmId() {
583             return pmfmId;
584         }
585 
586         public Function<BigfinDataRow, Sign> getCategoryValueGetter() {
587             return categoryValueGetter;
588         }
589     }
590 
591     /**
592      * Class containing the common parameters for the batch browsing
593      * These parameter do not change when you go deeper.
594      */
595     private class BrowseBatchesParameter {
596         /** the current fishing operation */
597         private FishingOperation operation;
598 
599         /** the current species */
600         private Species species;
601 
602         /** the lengthstep caracteristic found in the protocol */
603         private Caracteristic lengthStepPmfm;
604 
605         /** the ordered categories */
606         private List<Category> categories;
607 
608         /** the result of the import (to add the errors) */
609         private BigfinImportResult result;
610 
611         /** label for the species in the errors */
612         private String speciesLabel;
613 
614         public BrowseBatchesParameter(FishingOperation operation, Species species, Caracteristic lengthStepPmfm,
615                                       List<Category> categories, BigfinImportResult result) {
616             this.operation = operation;
617             this.species = species;
618             this.lengthStepPmfm = lengthStepPmfm;
619             this.categories = categories;
620             this.result = result;
621 
622             speciesLabel = species.getSurveyCode();
623             if (StringUtils.isBlank(speciesLabel)) {
624                 speciesLabel = species.getRefTaxCode();
625             }
626         }
627 
628         public FishingOperation getOperation() {
629             return operation;
630         }
631 
632         public Species getSpecies() {
633             return species;
634         }
635 
636         public Caracteristic getLengthStepPmfm() {
637             return lengthStepPmfm;
638         }
639 
640         public List<Category> getCategories() {
641             return categories;
642         }
643 
644         public BigfinImportResult getResult() {
645             return result;
646         }
647 
648         public String getSpeciesLabel() {
649             return speciesLabel;
650         }
651     }
652 }