This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository tutti. See http://git.codelutin.com/tutti.git commit 45aacd562efa18241aba5280b93d851112a67dbb Author: Tony CHEMIT <chemit@codelutin.com> Date: Thu Dec 11 13:50:11 2014 +0100 ajout service d'import des caractéristicques d'un trait --- .../FishingOperationImportService.java | 167 ++++++++++++++++ ...olumnFileFishingOperationNotFoundException.java | 15 ++ .../ImportFromColumnFileInvalidRowException.java | 29 +++ .../operationimport/ImportFromColumnFileModel.java | 213 +++++++++++++++++++++ 4 files changed, 424 insertions(+) diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/operationimport/FishingOperationImportService.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/operationimport/FishingOperationImportService.java new file mode 100644 index 0000000..89709e4 --- /dev/null +++ b/tutti-service/src/main/java/fr/ifremer/tutti/service/operationimport/FishingOperationImportService.java @@ -0,0 +1,167 @@ +package fr.ifremer.tutti.service.operationimport; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import fr.ifremer.tutti.persistence.entities.data.FishingOperation; +import fr.ifremer.tutti.persistence.entities.protocol.OperationFieldMappingRow; +import fr.ifremer.tutti.persistence.entities.protocol.TuttiProtocol; +import fr.ifremer.tutti.service.AbstractTuttiService; +import fr.ifremer.tutti.service.PersistenceService; +import fr.ifremer.tutti.service.TuttiDataContext; +import fr.ifremer.tutti.service.TuttiServiceContext; +import org.apache.commons.lang3.StringUtils; +import org.nuiton.csv.AbstractImportErrorInfo; +import org.nuiton.csv.Import2; +import org.nuiton.csv.ImportConf; +import org.nuiton.csv.ImportRow; +import org.nuiton.csv.ext.CsvReaders; +import org.nuiton.jaxx.application.ApplicationTechnicalException; +import org.nuiton.util.DateUtil; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.Date; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * Created on 12/11/14. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 3.10 + */ +public class FishingOperationImportService extends AbstractTuttiService { + + protected PersistenceService persistenceService; + + private TuttiDataContext dataContext; + + @Override + public void setServiceContext(TuttiServiceContext context) { + super.setServiceContext(context); + persistenceService = getService(PersistenceService.class); + dataContext = context.getDataContext(); + } + + public void importCaracteristicsFromColumnFile(File columnsFile, FishingOperation fishingoperation) throws ImportFromColumnFileInvalidRowException, ImportFromColumnFileFishingOperationNotFoundException { + + // Get import file headers + Set<String> headers = Sets.newHashSet(CsvReaders.getHeader(columnsFile, ';')); + + // Create import model + ImportFromColumnFileModel importModel = new ImportFromColumnFileModel(';', new HashSet<>(headers), persistenceService, dataContext, fishingoperation); + ImportConf conf = new ImportConf(); + conf.setStrictMode(false); + + // Create matching row predicate + MatchingFishingOperationNaturalIdPredicate matchingRowPredicate = new MatchingFishingOperationNaturalIdPredicate( + fishingoperation.getStationNumber(), + fishingoperation.getFishingOperationNumber(), + fishingoperation.getGearShootingStartDate(), + dataContext.getProtocol()); + + try (Import2<FishingOperation> operationUIModelImport = Import2.newImport(conf, importModel, new FileInputStream(columnsFile))) { + + doImport(operationUIModelImport, matchingRowPredicate); + + } catch (FileNotFoundException e) { + throw new ApplicationTechnicalException("Could not find import file " + columnsFile); + } + + } + + protected void doImport(Import2<FishingOperation> operationUIModelImport, + MatchingFishingOperationNaturalIdPredicate matchingRowPredicate) throws ImportFromColumnFileInvalidRowException, ImportFromColumnFileFishingOperationNotFoundException { + + + boolean found = false; + for (ImportRow<FishingOperation> next : operationUIModelImport) { + + FishingOperation fishingOperation = next.getBean(); + + if (matchingRowPredicate.apply(fishingOperation)) { + if (!next.isValid()) { + + Set<AbstractImportErrorInfo<FishingOperation>> errors = next.getErrors(); + throw new ImportFromColumnFileInvalidRowException(errors); + + } + + // valid row was found + // can quit right now the import + found = true; + + break; + } + + } + + if (!found) { + throw new ImportFromColumnFileFishingOperationNotFoundException(); + } + + } + + protected static class MatchingFishingOperationNaturalIdPredicate implements Predicate<FishingOperation> { + + protected final String stationNumber; + + protected final Integer fishingOperationNumber; + + protected final Date modelGearShootingStartOnlyDate; + + protected final Map<String, OperationFieldMappingRow> mappingRowsByField; + + MatchingFishingOperationNaturalIdPredicate(String stationNumber, + Integer fishingOperationNumber, + Date modelGearShootingStartDate, + TuttiProtocol protocol) { + this.stationNumber = stationNumber; + this.fishingOperationNumber = fishingOperationNumber; + + if (modelGearShootingStartDate != null) { + this.modelGearShootingStartOnlyDate = DateUtil.getDay(modelGearShootingStartDate); + } else { + this.modelGearShootingStartOnlyDate = null; + } + + this.mappingRowsByField = Maps.uniqueIndex(protocol.getOperationFieldMapping(), new Function<OperationFieldMappingRow, String>() { + @Override + public String apply(OperationFieldMappingRow operationFieldMappingRow) { + return operationFieldMappingRow.getField(); + } + }); + } + + @Override + public boolean apply(FishingOperation fishingOperation) { + + OperationFieldMappingRow operationNumberRow = mappingRowsByField.get(FishingOperation.PROPERTY_FISHING_OPERATION_NUMBER); + OperationFieldMappingRow stationNumberRow = mappingRowsByField.get(FishingOperation.PROPERTY_STATION_NUMBER); + OperationFieldMappingRow startDateRow = mappingRowsByField.get(FishingOperation.PROPERTY_GEAR_SHOOTING_START_DATE); + + String operationNumberColumn = operationNumberRow != null ? operationNumberRow.getImportColumn() : null; + String stationColumn = stationNumberRow != null ? stationNumberRow.getImportColumn() : null; + String startDateColumn = startDateRow != null ? startDateRow.getImportColumn() : null; + + boolean sameStationNumber = Objects.equals(fishingOperation.getStationNumber(), stationNumber); + boolean sameFishingOperationNumber = Objects.equals(fishingOperation.getFishingOperationNumber(), fishingOperationNumber); + // check if the dates (not time) are equals, but push the time to the model + Date gearShootingStartDate = fishingOperation.getGearShootingStartDate(); + if (gearShootingStartDate != null) { + gearShootingStartDate = DateUtil.getDay(gearShootingStartDate); + } + boolean sameGearShootingStartDate = Objects.equals(modelGearShootingStartOnlyDate, gearShootingStartDate); + + return (StringUtils.isBlank(stationColumn) || sameStationNumber) + && (StringUtils.isBlank(operationNumberColumn) || sameFishingOperationNumber) + && (StringUtils.isBlank(startDateColumn) || sameGearShootingStartDate); + } + } + +} diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/operationimport/ImportFromColumnFileFishingOperationNotFoundException.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/operationimport/ImportFromColumnFileFishingOperationNotFoundException.java new file mode 100644 index 0000000..66cb57e --- /dev/null +++ b/tutti-service/src/main/java/fr/ifremer/tutti/service/operationimport/ImportFromColumnFileFishingOperationNotFoundException.java @@ -0,0 +1,15 @@ +package fr.ifremer.tutti.service.operationimport; + +/** + * When no matching fishing operation was found in from column file import file. + * + * Created on 12/11/14. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 3.10 + */ +public class ImportFromColumnFileFishingOperationNotFoundException extends Exception { + + private static final long serialVersionUID = 1L; + +} diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/operationimport/ImportFromColumnFileInvalidRowException.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/operationimport/ImportFromColumnFileInvalidRowException.java new file mode 100644 index 0000000..03771fe --- /dev/null +++ b/tutti-service/src/main/java/fr/ifremer/tutti/service/operationimport/ImportFromColumnFileInvalidRowException.java @@ -0,0 +1,29 @@ +package fr.ifremer.tutti.service.operationimport; + +import fr.ifremer.tutti.persistence.entities.data.FishingOperation; +import org.nuiton.csv.AbstractImportErrorInfo; + +import java.util.Set; + +/** + * When the row to match in fishing operation import from column file is not valid. + * + * Created on 12/11/14. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 3.10 + */ +public class ImportFromColumnFileInvalidRowException extends Exception { + + private static final long serialVersionUID = 1L; + + private final Set<AbstractImportErrorInfo<FishingOperation>> errors; + + public ImportFromColumnFileInvalidRowException(Set<AbstractImportErrorInfo<FishingOperation>> errors) { + this.errors = errors; + } + + public Set<AbstractImportErrorInfo<FishingOperation>> getErrors() { + return errors; + } +} diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/operationimport/ImportFromColumnFileModel.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/operationimport/ImportFromColumnFileModel.java new file mode 100644 index 0000000..fdfb2ed --- /dev/null +++ b/tutti-service/src/main/java/fr/ifremer/tutti/service/operationimport/ImportFromColumnFileModel.java @@ -0,0 +1,213 @@ +package fr.ifremer.tutti.service.operationimport; + +import fr.ifremer.tutti.persistence.entities.CaracteristicMap; +import fr.ifremer.tutti.persistence.entities.TuttiEntities; +import fr.ifremer.tutti.persistence.entities.data.FishingOperation; +import fr.ifremer.tutti.persistence.entities.protocol.CaracteristicMappingRow; +import fr.ifremer.tutti.persistence.entities.protocol.CaracteristicType; +import fr.ifremer.tutti.persistence.entities.protocol.OperationFieldMappingRow; +import fr.ifremer.tutti.persistence.entities.protocol.TuttiProtocol; +import fr.ifremer.tutti.persistence.entities.referential.Caracteristic; +import fr.ifremer.tutti.persistence.entities.referential.CaracteristicQualitativeValue; +import fr.ifremer.tutti.persistence.entities.referential.Gear; +import fr.ifremer.tutti.persistence.entities.referential.Person; +import fr.ifremer.tutti.persistence.entities.referential.TuttiLocation; +import fr.ifremer.tutti.persistence.entities.referential.Vessel; +import fr.ifremer.tutti.service.PersistenceService; +import fr.ifremer.tutti.service.TuttiCsvUtil; +import fr.ifremer.tutti.service.TuttiDataContext; +import org.apache.commons.lang3.StringUtils; +import org.nuiton.csv.ImportRuntimeException; +import org.nuiton.csv.ValueParser; +import org.nuiton.csv.ValueSetter; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.nuiton.i18n.I18n.t; + +/** + * Created on 12/11/14. + * + * @author Kevin Morin - morin@codelutin.com + * @since 3.10 + */ +public class ImportFromColumnFileModel extends TuttiCsvUtil.AbstractTuttiImportModel<FishingOperation> { + + private final FishingOperation fishingOperation; + + public ImportFromColumnFileModel(char separator, Set<String> headers, + PersistenceService persistenceService, + TuttiDataContext dataContext, + FishingOperation fishingOperation) { + super(separator); + this.fishingOperation = fishingOperation; + + TuttiProtocol protocol = dataContext.getProtocol(); + Collection<OperationFieldMappingRow> operationFieldMapping = protocol.getOperationFieldMapping(); + + String zoneId = dataContext.getProgram().getZone().getId(); + + for (OperationFieldMappingRow mappingRow : operationFieldMapping) { + String importColumn = mappingRow.getImportColumn(); + boolean importColumnsInHeaders = headers.remove(importColumn); + if (StringUtils.isNotBlank(importColumn) && importColumnsInHeaders) { + + String field = mappingRow.getField(); + ValueParser valueParser; + switch (field) { + case FishingOperation.PROPERTY_FISHING_OPERATION_NUMBER: + valueParser = TuttiCsvUtil.INTEGER; + break; + + case FishingOperation.PROPERTY_GEAR_SHOOTING_START_LATITUDE: + case FishingOperation.PROPERTY_GEAR_SHOOTING_START_LONGITUDE: + case FishingOperation.PROPERTY_GEAR_SHOOTING_END_LATITUDE: + case FishingOperation.PROPERTY_GEAR_SHOOTING_END_LONGITUDE: + case FishingOperation.PROPERTY_TRAWL_DISTANCE: + valueParser = TuttiCsvUtil.FLOAT; + break; + + case FishingOperation.PROPERTY_GEAR_SHOOTING_START_DATE: + case FishingOperation.PROPERTY_GEAR_SHOOTING_END_DATE: + valueParser = TuttiCsvUtil.DAY_TIME; + break; + + case FishingOperation.PROPERTY_FISHING_OPERATION_RECTILIGNE: + valueParser = TuttiCsvUtil.PRIMITIVE_BOOLEAN; + break; + + case FishingOperation.PROPERTY_FISHING_OPERATION_VALID: + valueParser = TuttiCsvUtil.BOOLEAN; + break; + + case FishingOperation.PROPERTY_GEAR: + List<Gear> gears = new ArrayList<>(dataContext.getFishingGears()); + gears.addAll(dataContext.getScientificGears()); + Map<String, Gear> gearUniverse = TuttiEntities.splitById(gears); + valueParser = newForeignKeyValue(Gear.class, field, gearUniverse); + break; + + case FishingOperation.PROPERTY_VESSEL: + List<Vessel> vessels = new ArrayList<>(dataContext.getFishingVessels()); + vessels.addAll(dataContext.getScientificVessels()); + Map<String, Vessel> vesselUniverse = TuttiEntities.splitById(vessels); + valueParser = newForeignKeyValue(Vessel.class, field, vesselUniverse); + break; + + case FishingOperation.PROPERTY_SECONDARY_VESSEL: + vessels = new ArrayList<>(dataContext.getFishingVessels()); + vessels.addAll(dataContext.getScientificVessels()); + vesselUniverse = TuttiEntities.splitById(vessels); + valueParser = newForeignKeyListValue(Vessel.class, field, vesselUniverse); + break; + + case FishingOperation.PROPERTY_STRATA: + Map<String, TuttiLocation> strataUniverse = TuttiEntities.splitById( + persistenceService.getAllFishingOperationStrata(zoneId)); + valueParser = newForeignKeyValue(TuttiLocation.class, field, strataUniverse); + break; + + case FishingOperation.PROPERTY_SUB_STRATA: + Map<String, TuttiLocation> subStrataUniverse = TuttiEntities.splitById( + persistenceService.getAllFishingOperationSubStrata(zoneId, null)); + valueParser = newForeignKeyValue(TuttiLocation.class, field, subStrataUniverse); + break; + + case FishingOperation.PROPERTY_LOCATION: + Map<String, TuttiLocation> locationUniverse = TuttiEntities.splitById( + persistenceService.getAllFishingOperationLocation(zoneId, null, null)); + valueParser = newForeignKeyValue(TuttiLocation.class, field, locationUniverse); + break; + + case FishingOperation.PROPERTY_RECORDER_PERSON: + Map<String, Person> personUniverse = TuttiEntities.splitById(dataContext.getPersons()); + valueParser = newForeignKeyListValue(Person.class, field, personUniverse); + break; + + default: + valueParser = TuttiCsvUtil.STRING; + + } + newMandatoryColumn(importColumn, field, valueParser); + + } else if (!importColumnsInHeaders) { + throw new ImportRuntimeException(t("tutti.editFishingOperation.action.importColumns.missingHeader", importColumn)); + } + } + + Collection<CaracteristicMappingRow> caracteristicMappingRows = protocol.getCaracteristicMapping(); + for (final CaracteristicMappingRow mappingRow : caracteristicMappingRows) { + String importColumn = mappingRow.getImportColumn(); + if (StringUtils.isNotBlank(importColumn) && headers.remove(importColumn)) { + + int pmfmId = Integer.parseInt(mappingRow.getPmfmId()); + final Caracteristic caracteristic = persistenceService.getCaracteristic(pmfmId); + + ValueSetter<FishingOperation, String> setter = new ValueSetter<FishingOperation, String>() { + @Override + public void set(FishingOperation fishingOperation, String value) throws Exception { + + Serializable realValue = null; + if (StringUtils.isNotBlank(value)) { + switch (caracteristic.getCaracteristicType()) { + case QUALITATIVE: + for (CaracteristicQualitativeValue cqv : caracteristic.getQualitativeValue()) { + if (value.equals(cqv.getId())) { + realValue = cqv; + break; + } + } + break; + + case NUMBER: + realValue = Float.parseFloat(value); + break; + + default: + realValue = value; + } + } + + CaracteristicMap caracteristicMap; + if (CaracteristicType.GEAR_USE_FEATURE.toString().equals(mappingRow.getTab())) { + caracteristicMap = fishingOperation.getGearUseFeatures(); + if (caracteristicMap == null) { + caracteristicMap = new CaracteristicMap(); + fishingOperation.setGearUseFeatures(caracteristicMap); + } + + } else { + caracteristicMap = fishingOperation.getVesselUseFeatures(); + if (caracteristicMap == null) { + caracteristicMap = new CaracteristicMap(); + fishingOperation.setVesselUseFeatures(caracteristicMap); + } + } + caracteristicMap.put(caracteristic, realValue); + + } + }; + newMandatoryColumn(importColumn, setter); + + } + } + + + for (String header : headers) { + newIgnoredColumn(header); + } + } + + @Override + public FishingOperation newEmptyInstance() { +// FishingOperation fishingOperation = FishingOperations.newFishingOperation(); +// EditFishingOperationUIModel model = getModel(); +// toBeanBinder.copy(model, fishingOperation); + return fishingOperation; + } +} -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.