/*
|
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
*/
|
package com.megatim.fdxconvert.util;
|
|
import com.megatim.typefichier.validator.utilities.Constantes;
|
import com.megatim.fdxconvert.pojo.DataToImport;
|
import com.megatim.fdxconvert.pojo.FileToValidateDescription;
|
import com.megatim.fdxconvert.exceptions.AttributeFormatException;
|
import static com.megatim.typefichier.validator.utilities.Utilities.getCharset;
|
import com.megatim.fdxconvert.model.AlphaNumeriqueField;
|
import com.megatim.fdxconvert.model.TruncatedElement;
|
import com.megatim.fdxconvert.model.Validateur;
|
import com.megatim.fdxconvert.pojo.ResultFileParsing;
|
import com.megatim.fdxconvert.service.ConfigurationService;
|
import java.beans.IntrospectionException;
|
import java.beans.PropertyDescriptor;
|
import java.io.BufferedReader;
|
import java.io.BufferedWriter;
|
import java.io.File;
|
import java.io.FileInputStream;
|
import java.io.FileNotFoundException;
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.io.InputStreamReader;
|
import java.lang.reflect.Field;
|
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.Method;
|
import java.math.BigDecimal;
|
import java.nio.charset.Charset;
|
import java.nio.charset.StandardCharsets;
|
import java.nio.file.Files;
|
import java.nio.file.LinkOption;
|
import java.nio.file.Path;
|
import java.nio.file.Paths;
|
import java.nio.file.StandardOpenOption;
|
import java.text.Normalizer;
|
import java.time.LocalDate;
|
import java.time.LocalDateTime;
|
import java.time.format.DateTimeFormatter;
|
import java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.Collections;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.logging.Level;
|
import java.util.logging.Logger;
|
import java.util.stream.Collectors;
|
import org.apache.commons.csv.CSVFormat;
|
import org.apache.commons.csv.CSVParser;
|
import org.apache.commons.csv.CSVRecord;
|
import org.apache.commons.text.StringEscapeUtils;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Workbook;
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
/**
|
*
|
* @author mela
|
*/
|
public class ImportData {
|
|
/**
|
* Méthode qui parse le fichier csv et en extrait les données
|
*
|
* @param <T>
|
* @param datIm
|
* @return
|
* @throws java.lang.Exception
|
*/
|
public static <T> List<T> importDataFromCsvFile(DataToImport<T> datIm) throws Exception {
|
|
// FileReader reader = null;
|
List<String[]> datas = new ArrayList<>();
|
|
List<T> listeToReturn = new ArrayList<>();
|
|
if (datIm != null) {
|
|
try ( FileInputStream fis = new FileInputStream(datIm.getFile()); InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8); BufferedReader reader = new BufferedReader(isr)) {
|
|
String line = "";
|
|
while ((line = reader.readLine()) != null) {
|
|
String[] row = line.split(datIm.getRowDelimiter());
|
|
for (String r : row) {
|
|
String[] values = new String[datIm.getFields().size()];
|
|
String[] columns = r.split(datIm.getColumnDelimiter());
|
|
int ss = 0;
|
|
while (ss < datIm.getFields().size() && ss < columns.length) {
|
|
values[ss] = columns[ss];
|
|
ss++;
|
}
|
|
datas.add(values);
|
|
}
|
|
}
|
|
} catch (FileNotFoundException ex) {
|
|
Logger.getLogger(ImportData.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
|
|
} catch (IOException ex) {
|
|
Logger.getLogger(ImportData.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
|
|
}
|
|
if (!datas.isEmpty()) {
|
|
//tous les champs du type paramétré
|
Field[] fields = datIm.getType().getDeclaredFields();
|
|
// mettre les champs du type paramétré dans une map afin de faciliter leur accès
|
Map<String, Field> fieldsToMap = fieldsToMap(fields);
|
|
datas.forEach(d -> {
|
|
try {
|
|
T obj = datIm.getType().newInstance();
|
|
Map<String, String> map = tabToMap(datIm.getFields(), d);
|
|
for (Field field : fields) {
|
|
String fieldName = field.getName();
|
|
if (map.containsKey(fieldName) && fieldsToMap.containsKey(fieldName)) {
|
|
try {
|
|
Object converted = convertToPrimitive(field, map.get(fieldName));
|
Method method = new PropertyDescriptor(fieldName, datIm.getType()).getWriteMethod();
|
method.invoke(obj, converted);
|
|
} catch (IntrospectionException | IllegalAccessException | InvocationTargetException ex) {
|
|
Logger.getLogger(ImportData.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
|
|
} catch (IllegalArgumentException | ClassCastException ex) {
|
|
throw new AttributeFormatException("Erreur de type sur le champ " + fieldName);
|
|
}
|
|
}
|
|
}
|
|
listeToReturn.add(obj);
|
|
} catch (InstantiationException | IllegalAccessException ex) {
|
|
Logger.getLogger(ImportData.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
return listeToReturn;
|
|
}
|
|
/**
|
* Méthode qui extrait les données d'un fichier csv et les normalise
|
*
|
* @param rawCsvData : objet contenant les informations de validationdonnées
|
* @param validateur : Validateur du type fichier auquel appartient le
|
* fichier à valider
|
* @param outputFile : fichier texte généré en sortie
|
* @param headerPresent : renseigne si le fichier a une ligne d'entête
|
* @param alphaNumeriqueToBeTruncated : liste des champs à tronquer
|
* @throws Exception
|
*/
|
public static void parseCsvFile(FileToValidateDescription rawCsvData, Validateur validateur, File outputFile, boolean headerPresent, Set<AlphaNumeriqueField> alphaNumeriqueToBeTruncated) throws Exception {
|
|
Map<Integer, Map> mapParams = ParserUtils.getValidateurElements(validateur);
|
AtomicInteger numeroLigne = new AtomicInteger(0);
|
AtomicBoolean columnTruncated = new AtomicBoolean();
|
int lineNumber = 1;
|
|
if (rawCsvData != null) {
|
Charset charset = getCharset(rawCsvData.getFile());
|
|
AtomicBoolean withHeader = new AtomicBoolean(headerPresent);
|
Path pathOfTruncatedElts = createTruncatedEltsPath(validateur, rawCsvData.getFile());
|
|
try ( FileInputStream fis = new FileInputStream(rawCsvData.getFile()); InputStreamReader isr = new InputStreamReader(fis, charset); BufferedReader reader = new BufferedReader(isr)) {
|
try ( BufferedWriter bufferWriter = Files.newBufferedWriter(outputFile.toPath(), charset, StandardOpenOption.APPEND, StandardOpenOption.CREATE, StandardOpenOption.SYNC); BufferedWriter truncateWriter = Files.newBufferedWriter(pathOfTruncatedElts, StandardCharsets.UTF_8, StandardOpenOption.APPEND, StandardOpenOption.CREATE, StandardOpenOption.SYNC)) {
|
|
CSVParser parser = new CSVParser(reader, CSVFormat.DEFAULT.builder()
|
.setSkipHeaderRecord(headerPresent)
|
.setIgnoreSurroundingSpaces(true)
|
.setTrim(true)
|
.setDelimiter(StringEscapeUtils.unescapeJava(rawCsvData.getColumnDelimiter()))
|
.setRecordSeparator(StringEscapeUtils.unescapeJava(rawCsvData.getRowDelimiter()))
|
.build());
|
|
for (CSVRecord record : parser) {
|
|
String[] columnsTableLine = new String[record.size()];
|
AtomicInteger i = new AtomicInteger(0);
|
|
if (!withHeader.get()) {
|
|
record.forEach(column -> {
|
columnsTableLine[i.get()] = column != null ? column.replaceAll(" {2,}", " ").replaceAll("\r", "").replaceAll("\n", "").replaceAll("\t", "").trim() : "";
|
i.set(i.get() + 1);
|
});
|
|
//Nettoyage d'une colonne de chaque ligne
|
ResultFileParsing resultFileParsing = buildFinalColumnsTableLine(outputFile, columnsTableLine, mapParams, alphaNumeriqueToBeTruncated, numeroLigne.incrementAndGet(), truncateWriter);
|
String[] finalColumnsTableLine = resultFileParsing.getFinalColumnsTableLine();
|
columnTruncated.set(resultFileParsing.isColumnTruncated());
|
|
String[] encodedStrings = ParserUtils.encodeStrings(finalColumnsTableLine, charset);
|
ParserUtils.writeToFile(encodedStrings, bufferWriter);
|
|
lineNumber++;
|
} else {
|
withHeader.set(false);
|
}
|
|
}
|
|
} catch (Exception e) {
|
Logger.getLogger(ImportData.class.getName()).log(Level.SEVERE, e.getMessage(), e);
|
}
|
|
//Si au moins une colonne a été tronqué, alors copier le fichier dont les lignes ont été tronqué dans le répertoire d'archivage
|
if (columnTruncated.get()) {
|
Path originalFilePathInArchiveFolder = createOriginalFileInArchive(validateur, rawCsvData.getFile());
|
|
//Copie du fichier dont les colonnes ont été tronqués vers le répertoire archivage
|
if (rawCsvData.getFile().exists()) {
|
Files.copy(rawCsvData.getFile().toPath(), originalFilePathInArchiveFolder);
|
}
|
|
} else {//Sinon supprimer le fichier des éléments tronqués, car il est vide
|
Files.deleteIfExists(pathOfTruncatedElts);
|
}
|
}
|
}
|
}
|
|
/**
|
* Méthode qui extrait les données dans un fichier txt en respectant
|
* scrupuleusement la taille de chaque colonne
|
*
|
* @param rawCsvData : objet contenant les informations de validationdonnées
|
* @param validateur : Validateur du type fichier auquel appartient le
|
* fichier à valider
|
* @param outputFile : fichier texte généré en sortie
|
* @param headerPresent : renseigne si le fichier a une ligne d'entête
|
* @throws Exception
|
*/
|
public static void parseFileByFieldLength(FileToValidateDescription rawCsvData, Validateur validateur, File outputFile, boolean headerPresent) throws Exception {
|
System.out.println("----------------------In parseFileByFieldLength------------------");
|
Map<Integer, Map> mapParams = ParserUtils.getValidateurElements(validateur);
|
//boolean result = true;
|
int nbLine = 0;
|
|
if (rawCsvData != null) {
|
|
Charset charset = getCharset(rawCsvData.getFile());
|
|
//Lecture des lignes du fichier et chargment dans une liste
|
try ( FileInputStream fis = new FileInputStream(rawCsvData.getFile()); InputStreamReader isr = new InputStreamReader(fis, charset); BufferedReader reader = new BufferedReader(isr)) {
|
|
try ( //Initialisation du write pour traiter chaque ligne du fichier
|
BufferedWriter bufferWriter = Files.newBufferedWriter(outputFile.toPath(), charset, StandardOpenOption.APPEND, StandardOpenOption.CREATE, StandardOpenOption.SYNC);) {
|
|
boolean withHeader = headerPresent;
|
|
StringBuilder line = new StringBuilder();
|
|
int c = 0;
|
|
boolean carriageReaded = false; //Indique si on a lu un retour chariot
|
|
char lastCharacter = '\u0000';
|
|
while ((c = reader.read()) != -1) {
|
|
char characterRead = (char) c;
|
|
if (characterRead == '\r') {
|
|
if (carriageReaded) { //On a lu le retour chariot deux fois consécutives donc on a pas de séparateur de ligne au sens windows
|
|
//On ajoute les deux caractère à la chaîne que nous construisons
|
line.append('\r').append(characterRead);
|
|
carriageReaded = false; //On marque que la lecture d'une nouvelle ligne redémarre
|
|
} else { // Première lecture du retour chariot
|
|
carriageReaded = true; // On marque que nous avons lu un retour chariot
|
|
}
|
|
} else {
|
|
if (carriageReaded) { // Le caractère précédemment lu c'est le retour chariot
|
|
if (characterRead == '\n') { // Si le nouveau caractère lu est un saut de ligne c'est que nous venons de lire une nouvelle ligne
|
|
//On effectue les traitements propres à la ligne
|
String newLine = line.toString();
|
nbLine++;
|
|
if (!withHeader) {
|
|
parseLineUsingFieldLength(newLine, mapParams, rawCsvData.getColumnDelimiter(), bufferWriter, charset);
|
|
} else {
|
|
withHeader = false;
|
|
}
|
|
line = new StringBuilder(); //On réinitialise notre constructeur de ligne
|
|
carriageReaded = false; //On marque que la lecture d'une nouvelle ligne redémarre
|
|
} else {
|
|
line.append(' '); //On change le saut de ligne par un espace
|
|
}
|
|
} else {
|
|
if (characterRead == '\n') {
|
|
if (lastCharacter != '\n') {
|
|
line.append(' ');
|
|
}
|
|
} else {
|
|
line.append(characterRead);
|
|
}
|
|
}
|
|
}
|
|
lastCharacter = characterRead;
|
}
|
|
} //Fermeture du writer
|
|
}
|
|
}
|
|
}
|
|
/**
|
* Méthode qui parcours un fichier txt caractère par caractère afin d'en
|
* extraire les données et de les normaliser
|
*
|
* @param rawCsvData : objet contenant les informations de validationdonnées
|
* @param validateur : Validateur du type fichier auquel appartient le
|
* fichier à valider
|
* @param outputFile : fichier texte généré en sortie
|
* @param headerPresent : renseigne si le fichier a une ligne d'entête
|
* @param alphaNumeriqueToBeTruncated : liste des champs à tronquer
|
* @throws Exception
|
*/
|
public static void parseFileCharacterByCharacter(FileToValidateDescription rawCsvData, Validateur validateur, File outputFile, boolean headerPresent, Set<AlphaNumeriqueField> alphaNumeriqueToBeTruncated) throws Exception {
|
|
Map<Integer, Map> mapParams = ParserUtils.getValidateurElements(validateur);
|
AtomicInteger numeroLigne = new AtomicInteger(0);
|
AtomicBoolean columnTruncated = new AtomicBoolean();
|
|
if (rawCsvData != null) {
|
|
Charset charset = getCharset(rawCsvData.getFile());
|
Path pathOfTruncatedElts = createTruncatedEltsPath(validateur, rawCsvData.getFile());
|
|
//Lecture des lignes du fichier et chargement dans une liste
|
try ( FileInputStream fis = new FileInputStream(rawCsvData.getFile()); InputStreamReader isr = new InputStreamReader(fis, charset); BufferedReader reader = new BufferedReader(isr)) {
|
|
try ( //Initialisation du write pour traiter chaque ligne du fichier
|
BufferedWriter bufferWriter = Files.newBufferedWriter(outputFile.toPath(), charset, StandardOpenOption.APPEND, StandardOpenOption.CREATE, StandardOpenOption.SYNC); BufferedWriter truncateWriter = Files.newBufferedWriter(pathOfTruncatedElts, StandardCharsets.UTF_8, StandardOpenOption.APPEND, StandardOpenOption.CREATE, StandardOpenOption.SYNC)) {
|
|
boolean withHeader = headerPresent;
|
|
StringBuilder line = new StringBuilder();
|
|
int c = 0;
|
|
boolean carriageReaded = false; //Indique si on a lu un retour chariot
|
|
char lastCharacter = '\u0000';
|
|
while ((c = reader.read()) != -1) {
|
|
char characterRead = (char) c;
|
|
if (characterRead == '\r') {
|
|
if (carriageReaded) { //On a lu le retour chariot deux fois consécutives donc on a pas de séparateur de ligne au sens windows
|
|
//On ajoute les deux caractère à la chaîne que nous construisons
|
line.append('\r').append(characterRead);
|
|
carriageReaded = false; //On marque que la lecture d'une nouvelle ligne redémarre
|
|
} else { // Première lecture du retour chariot
|
|
carriageReaded = true; // On marque que nous avons lu un retour chariot
|
|
}
|
|
} else {
|
|
if (carriageReaded) { // Le caractère précédemment lu c'est le retour chariot
|
|
if (characterRead == '\n') { // Si le nouveau caractère lu est un saut de ligne c'est que nous venons de lire une nouvelle ligne
|
|
//On effectue les traitements propres à la ligne
|
String newLine = line.toString();
|
|
if (ParserUtils.characterOfDelimiteur(rawCsvData.getColumnDelimiter()) != '\0') {
|
newLine = newLine.replaceAll(" {2,}", " ");
|
}
|
|
if (!withHeader) {
|
|
//Représente les colonnes extraites de chaque ligne du fichier
|
//String[] columnsTableLine = newLine.split(rawCsvData.getColumnDelimiter());
|
String[] columnsTableLine;
|
|
if (rawCsvData.getColumnDelimiter().equals("\\t")) {
|
|
columnsTableLine = ParserUtils.splitIntoColumns(newLine, '\t');
|
ResultFileParsing resultFileParsing = buildFinalColumnsTableLine(outputFile, columnsTableLine, mapParams, alphaNumeriqueToBeTruncated, numeroLigne.incrementAndGet(), truncateWriter);
|
String[] finalColumnsTableLine = resultFileParsing.getFinalColumnsTableLine();
|
columnTruncated.set(resultFileParsing.isColumnTruncated());
|
|
String[] encodedStrings = ParserUtils.encodeStrings(finalColumnsTableLine, charset);
|
ParserUtils.writeToFile(encodedStrings, bufferWriter);
|
|
} else if (rawCsvData.getColumnDelimiter().isEmpty()) {
|
parseLineUsingFieldLength(newLine, mapParams, rawCsvData.getColumnDelimiter(), bufferWriter, charset);
|
} else {
|
|
columnsTableLine = (newLine).split(rawCsvData.getColumnDelimiter());
|
ResultFileParsing resultFileParsing = buildFinalColumnsTableLine(outputFile, columnsTableLine, mapParams, alphaNumeriqueToBeTruncated, numeroLigne.incrementAndGet(), truncateWriter);
|
String[] finalColumnsTableLine = resultFileParsing.getFinalColumnsTableLine();
|
|
if (!columnTruncated.get()) {
|
columnTruncated.set(resultFileParsing.isColumnTruncated());
|
}
|
|
String[] encodedStrings = ParserUtils.encodeStrings(finalColumnsTableLine, charset);
|
ParserUtils.writeToFile(encodedStrings, bufferWriter);
|
|
}
|
|
//Nettoyage d'une colonne de chaque ligne
|
} else {
|
|
withHeader = false;
|
|
}
|
|
line = new StringBuilder(); //On réinitialise notre constructeur de ligne
|
|
carriageReaded = false; //On marque que la lecture d'une nouvelle ligne redémarre
|
|
} else {
|
|
line.append(' '); //On change le saut de ligne par un espace
|
|
}
|
|
} else {
|
|
if (characterRead == '\n') {
|
|
if (lastCharacter != '\n') {
|
|
line.append(' ');
|
|
}
|
|
} else {
|
|
line.append(characterRead);
|
|
}
|
|
}
|
|
}
|
|
lastCharacter = characterRead;
|
}
|
|
} //Fermeture du writer
|
|
}
|
|
//Si au moins une colonne a été tronqué, alors copier le fichier dont les lignes ont été tronqué dans le répertoire d'archivage
|
if (columnTruncated.get()) {
|
Path originalFilePathInArchiveFolder = createOriginalFileInArchive(validateur, rawCsvData.getFile());
|
|
//Copie du fichier dont les colonnes ont été tronqués vers le répertoire archivage
|
if (rawCsvData.getFile().exists()) {
|
Files.copy(rawCsvData.getFile().toPath(), originalFilePathInArchiveFolder);
|
}
|
|
} else {//Sinon supprimer le fichier des éléments tronqués, car il est vide
|
Files.deleteIfExists(pathOfTruncatedElts);
|
}
|
}
|
|
}
|
|
/**
|
* Méthode qui extrait les données d'un fichier xlsx et les normalise
|
*
|
* @param validateur : Validateur du type fichier auquel appartient le
|
* fichier à valider
|
* @param outputFile : fichier texte généré en sortie
|
* @param headerPresent : renseigne si le fichier a une ligne d'entête
|
* @param alphaNumeriqueToBeTruncated : liste des champs à tronquer
|
* @param filePath : Fichier qui contient les données à extraire
|
* @throws IOException
|
* @throws Exception
|
*/
|
public static void parseXlsxFile(String filePath, boolean headerPresent, File outputFile, Validateur validateur, Set<AlphaNumeriqueField> alphaNumeriqueToBeTruncated) throws Exception {
|
AtomicBoolean columnTruncated = new AtomicBoolean();
|
Path pathOfTruncatedElts = createTruncatedEltsPath(validateur, new File(filePath));
|
|
try ( InputStream is = new FileInputStream(filePath); Workbook wb = new XSSFWorkbook(is)) {
|
parseExcelFile(filePath, wb, headerPresent, outputFile, validateur, alphaNumeriqueToBeTruncated, pathOfTruncatedElts);
|
}
|
treatTruncatedElements(filePath, pathOfTruncatedElts, validateur, columnTruncated);
|
|
}
|
|
public static void parseXlsFile(String filePath, boolean headerPresent, File outputFile, Validateur validateur, Set<AlphaNumeriqueField> alphaNumeriqueToBeTruncated) throws Exception {
|
AtomicBoolean columnTruncated = new AtomicBoolean();
|
Path pathOfTruncatedElts = createTruncatedEltsPath(validateur, new File(filePath));
|
|
try ( InputStream is = new FileInputStream(filePath); Workbook wb = new HSSFWorkbook(is)) {
|
parseExcelFile(filePath, wb, headerPresent, outputFile, validateur, alphaNumeriqueToBeTruncated, pathOfTruncatedElts);
|
}
|
treatTruncatedElements(filePath, pathOfTruncatedElts, validateur, columnTruncated);
|
|
}
|
|
private static void parseExcelFile(String filePath, Workbook wb, boolean headerPresent, File outputFile, Validateur validateur, Set<AlphaNumeriqueField> alphaNumeriqueToBeTruncated, Path pathOfTruncatedElts) throws IOException, Exception {
|
Map<Integer, Map> mapParams = ParserUtils.getValidateurElements(validateur);
|
final int maxPosition = Collections.max(mapParams.keySet());
|
AtomicInteger numeroLigne = new AtomicInteger(0);
|
AtomicBoolean columnTruncated = new AtomicBoolean();
|
Charset charset = getCharset(new File(filePath));
|
|
try ( BufferedWriter bufferWriter = Files.newBufferedWriter(outputFile.toPath(), charset, StandardOpenOption.APPEND, StandardOpenOption.CREATE, StandardOpenOption.SYNC); BufferedWriter truncateWriter = Files.newBufferedWriter(pathOfTruncatedElts, Charset.defaultCharset(), StandardOpenOption.APPEND, StandardOpenOption.CREATE, StandardOpenOption.SYNC)) {
|
|
for (int i = 0; i < wb.getNumberOfSheets(); i++) {
|
Sheet sheet = wb.getSheetAt(i);
|
AtomicInteger numberOfColumns = new AtomicInteger(0);
|
AtomicBoolean withHeader = new AtomicBoolean(headerPresent);
|
AtomicInteger lineNumber = new AtomicInteger(1);
|
|
for (org.apache.poi.ss.usermodel.Row r : sheet) {
|
|
if (!withHeader.get()) {
|
for (int cn = 0; cn < r.getLastCellNum(); cn++) {
|
numberOfColumns.incrementAndGet();
|
}
|
//Représente les colonnes extraites de chaque ligne du fichier
|
String[] columnsTableLine = new String[numberOfColumns.get()];
|
AtomicInteger index = new AtomicInteger(0);
|
|
for (int cn = 0; cn < r.getLastCellNum(); cn++) {
|
if (cn < maxPosition) {
|
Map<String, String> map = mapParams.get(index.get() + 1);
|
|
//Prendre aussi les cellules vides en considération
|
org.apache.poi.ss.usermodel.Cell c = r.getCell(cn, org.apache.poi.ss.usermodel.Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
|
String value = com.megatim.typefichier.validator.utilities.ParserUtils.getXlxsCellValue(c,
|
wb,
|
map.get(Constantes.LIBELLE_TYPE_DONNEE),
|
map.get(Constantes.LIBELLE_FORMAT_DATE),
|
map.get(Constantes.LIBELLE_SEPARATEUR_DATE),
|
map.get(Constantes.ERROR_CODE));
|
columnsTableLine[index.get()] = value;
|
index.incrementAndGet();
|
} else {
|
break;
|
}
|
}
|
|
try {
|
//Nettoyage d'une colonne de chaque ligne
|
ResultFileParsing resultFileParsing = buildFinalColumnsTableLine(outputFile, columnsTableLine, mapParams, alphaNumeriqueToBeTruncated, numeroLigne.incrementAndGet(), truncateWriter);
|
String[] finalColumnsTableLine = resultFileParsing.getFinalColumnsTableLine();
|
columnTruncated.set(resultFileParsing.isColumnTruncated());
|
|
ParserUtils.writeToFile(finalColumnsTableLine, bufferWriter);
|
|
} catch (Exception ex) {
|
Logger.getLogger(ImportData.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
|
}
|
} else {
|
withHeader.set(false);
|
}
|
lineNumber.incrementAndGet();
|
}
|
}
|
|
}
|
}
|
|
private static void treatTruncatedElements(String filePath, Path pathOfTruncatedElts, Validateur validateur, AtomicBoolean columnTruncated) throws IOException {
|
//Si au moins une colonne a été tronqué, alors copier le fichier dont les lignes ont été tronqué dans le répertoire d'archivage
|
if (columnTruncated.get()) {
|
Path pathoriginalFilePath = Paths.get(filePath);
|
Path originalFilePathInArchiveFolder = createOriginalFileInArchive(validateur, new File(filePath));
|
|
//Copie du fichier dont les colonnes ont été tronqués vers le répertoire archivage
|
if (Files.exists(pathoriginalFilePath, LinkOption.NOFOLLOW_LINKS)) {
|
Files.copy(pathoriginalFilePath, originalFilePathInArchiveFolder);
|
}
|
|
} else {//Sinon supprimer le fichier des éléments tronqués, car il est vide
|
Files.deleteIfExists(pathOfTruncatedElts);
|
}
|
}
|
|
/**
|
* Méthode qui met les libellés des colonnes et leurs valeurs
|
* correspondantes dans une map
|
*
|
* @param titles : ensemble des noms de colonnes
|
* @param values : ensemble des données
|
* @return : rentourne une map (clé,valeur) = (nom_de_la_colonne,
|
* valeur_colonne)
|
*/
|
private static Map<String, String> tabToMap(List<String> titles, String[] values) {
|
Map<String, String> map = new HashMap<>();
|
for (int i = 0; i < titles.size(); i++) {
|
map.put(titles.get(i), values[i]);
|
}
|
|
return map;
|
}
|
|
/**
|
* Méthode qui met un tableau de Field dans une
|
* map<nom_du_champ,objet représentant_le_champ>
|
* afin de faciliter leur accès
|
*
|
* @param fields
|
* @return
|
*/
|
private static Map<String, Field> fieldsToMap(Field[] fields) {
|
Map<String, Field> map = new HashMap<>();
|
for (Field f : fields) {
|
map.put(f.getName(), f);
|
}
|
|
return map;
|
}
|
|
/**
|
* Méthode qui fait la conversion de la donnée extraite vers un type
|
* primitif
|
*
|
* @param field : objet contenant les informations sur le type auquel
|
* appartient le champ de la donnée extraite
|
* @param value : donnée à convertir
|
* @return : retourne un String si le type du champ ne figure pas dans la
|
* liste ci-dessus
|
*/
|
private static Object convertToPrimitive(Field field, String value) {
|
Object obj = value;
|
|
if (field.getType().isAssignableFrom(Integer.class)
|
|| field.getType().isAssignableFrom(int.class)) {
|
obj = Integer.valueOf(value);
|
} else if (field.getType().isAssignableFrom(Double.class)
|
|| field.getType().isAssignableFrom(double.class)) {
|
obj = Double.valueOf(value);
|
} else if (field.getType().isAssignableFrom(java.math.BigDecimal.class)) {
|
obj = new java.math.BigDecimal(value);
|
} else if (field.getType().isAssignableFrom(Float.class)
|
|| field.getType().isAssignableFrom(float.class)) {
|
obj = Float.valueOf(value);
|
} else if (field.getType().isAssignableFrom(Long.class)
|
|| field.getType().isAssignableFrom(long.class)) {
|
obj = Long.valueOf(value);
|
} else if (field.getType().isAssignableFrom(Boolean.class)
|
|| field.getType().isAssignableFrom(boolean.class)) {
|
Boolean.valueOf(value);
|
}
|
|
return obj;
|
}
|
|
/**
|
* Méthode permettant de construire la donnée finale à écrire dans le
|
* fichier texte
|
*
|
* @param outputFile
|
* @param initialColumnsTableLine
|
* @param mapParams
|
* @param fieldsToBeTruncated
|
* @param numeroLigne
|
* @param truncateWriter
|
* @return
|
* @throws Exception
|
*/
|
private static ResultFileParsing buildFinalColumnsTableLine(File outputFile, String[] initialColumnsTableLine, Map<Integer, Map> mapParams, Set<AlphaNumeriqueField> fieldsToBeTruncated, int numeroLigne, BufferedWriter truncateWriter) throws Exception {
|
|
String[] finalColumnsTableLine = new String[mapParams.size() - 1];
|
String[] columnsTableLine = new String[mapParams.size() - 1];
|
|
//On copie les éléments à normaliser dans un nouveau tableau
|
for (int j = 0; j < finalColumnsTableLine.length; j++) {
|
|
//Arreter la copie si on atteint la fin du tableau initial
|
if (j == initialColumnsTableLine.length) {
|
j = finalColumnsTableLine.length;
|
} else {
|
final String result = initialColumnsTableLine[j] != null && !initialColumnsTableLine[j].isEmpty()
|
? Normalizer
|
.normalize(initialColumnsTableLine[j], Normalizer.Form.NFD) //Retrait des caractères accentués
|
.replaceAll("\\p{M}+", "")
|
: "";
|
columnsTableLine[j] = result;
|
}
|
}
|
|
//Type de données utilisé pour retourner le résultat de la construction des lignes de données
|
ResultFileParsing resultFileParsing = new ResultFileParsing();
|
|
int index = 0;
|
|
for (String str : columnsTableLine) {
|
|
String columnTableLine = str != null ? str.trim() : "";
|
|
if (index < mapParams.size() - 1) {
|
|
Map<String, String> map = mapParams.get(index + 1);
|
|
final int taille = Integer.parseInt(map.get(Constantes.LIBELLE_TAILLE));
|
String typeDonnee = map.get(Constantes.LIBELLE_TYPE_DONNEE);
|
|
//Traitement d'une donnée de type décimal
|
if (typeDonnee.equalsIgnoreCase(Constantes.LIBELLE_DECIMAL)) {
|
finalColumnsTableLine[index] = normalizeDecimal(columnTableLine, map);
|
|
//Traitement d'une donnée de type DATE
|
} else if (typeDonnee.equalsIgnoreCase(Constantes.LIBELLE_DATE)) {
|
|
if (columnTableLine.length() < taille) {
|
finalColumnsTableLine[index] = generateUnknown(taille - columnTableLine.length(), " ") + columnTableLine;
|
|
} else if (columnTableLine.length() == taille) {
|
finalColumnsTableLine[index] = columnTableLine;
|
|
} else {
|
finalColumnsTableLine[index] = columnTableLine.substring(0, taille);
|
}
|
|
//Traitement d'une donnée de type NUMERIQUE
|
} else if (typeDonnee.equalsIgnoreCase(Constantes.LIBELLE_NUMERIQUE)) {
|
finalColumnsTableLine[index] = normalizeNumber(columnTableLine, taille);
|
//
|
} else if (typeDonnee.equalsIgnoreCase(Constantes.LIBELLE_ALPHANUMERIQUE)) { //Traitement d'une donnée de type ALPHANUMERIQUE
|
|
if (columnTableLine.length() < taille) {
|
|
finalColumnsTableLine[index] = generateUnknown(taille - columnTableLine.length(), " ") + columnTableLine;
|
|
} else if (columnTableLine.length() == taille) {
|
|
finalColumnsTableLine[index] = columnTableLine;
|
|
} else {
|
|
if (!fieldsToBeTruncated.isEmpty()) {
|
|
//Récupérer l'index de début du champ en cours de traitement
|
int indexDebutChamp = Integer.parseInt(map.get(Constantes.LIBELLE_INDEX));
|
|
//Mettre les champs à tronquer dans une liste afin d'y rechercher le champ en cours de traitement
|
List<AlphaNumeriqueField> liste = Arrays.asList(fieldsToBeTruncated.toArray(new AlphaNumeriqueField[0]))
|
.stream().filter(a -> {
|
|
// ici on vérifie si l'index de début du champ en cours de traitement correspond à l'index d'un des champs à tronquer
|
//Car si 2 champs ont le même index, alors il s'agit d'un seul champ
|
return a.getIndex() == indexDebutChamp;
|
}).collect(Collectors.toList());
|
|
// Si on a trouvé un champ à tronquer qui a le même index que le champ courant alors, tronquer le champ
|
boolean found = (liste.size() == 1);
|
|
if (found) {
|
|
AlphaNumeriqueField alphaField = liste.get(0);
|
|
String finalData = columnTableLine.substring(0, taille);
|
|
TruncatedElement truncatedElement = new TruncatedElement(alphaField.getValidateur().getCodeTypeFichier(),
|
alphaField.getCodeColonne(), columnTableLine, finalData,
|
outputFile.getName(), LocalDateTime.now(), numeroLigne, taille, columnTableLine.length());
|
|
// Journalisation du champs tronqués
|
writeTruncatedElementsToFile(truncatedElement, truncateWriter);
|
|
resultFileParsing.setColumnTruncated(true);
|
|
finalColumnsTableLine[index] = finalData;
|
} else {
|
finalColumnsTableLine[index] = columnTableLine;
|
}
|
|
} else {
|
finalColumnsTableLine[index] = columnTableLine;
|
}
|
}
|
} else {
|
finalColumnsTableLine[index] = columnTableLine;
|
}
|
}
|
|
index++;
|
|
}
|
|
resultFileParsing.setFinalColumnsTableLine(finalColumnsTableLine);
|
return resultFileParsing;
|
}
|
|
/**
|
* Méthode qui normalise un nombre en ajoutant des zéros à gauche
|
*
|
* @param value
|
* @param taille
|
* @return
|
*/
|
private static String normalizeNumber(String value, int taille) {
|
String newValue = value
|
.trim()
|
.replaceAll("\\s+", "")
|
.replaceAll("\\u00A0", "")//nbsp
|
.replaceAll(" ", "")//nbsp
|
.replaceAll("\\p{Z}", "")
|
.replaceAll("\t", "")
|
.replaceAll("\r", "")
|
.replaceAll("\n", "");
|
|
try {
|
if (!newValue.matches("\\d+")) {
|
newValue = new BigDecimal(newValue.replace(',', '.')).longValue() + "";//Remplacer la virgule par le point
|
}
|
} catch (Exception ex) {
|
}
|
return generateUnknown(taille - newValue.length(), " ") + newValue;
|
}
|
|
/**
|
* Méthode qui normalise les nombres décimaux conformat aux tailles, en
|
* ajoutant éventuellement des zéros à gauche de la partie entière et à
|
* droite de la partie décimale renseignés dans le validateur
|
*
|
* @param value : chaîne à normaliser
|
* @param map : map contenant les infos sur les parties entire et décimale
|
* @return
|
*/
|
private static String normalizeDecimal(String value, Map<String, String> map) {
|
|
//Taille totale du nombre décimal
|
int taille = Integer.parseInt(map.get(Constantes.LIBELLE_TAILLE));
|
int taillePartieDecimale = Integer.parseInt(map.get(Constantes.LIBELLE_TAILLE_PARTIE_DECIMALE));
|
String separateurDecimal = map.get(Constantes.LIBELLE_SEPARATEUR_DECIMAL);
|
int tailleReelle = taille + taillePartieDecimale + separateurDecimal.trim().length();
|
|
String newValue = value.trim()
|
.replaceAll("\\s+", "")
|
.replaceAll("\\u00A0", "")//nbsp
|
.replaceAll(" ", "")//nbsp
|
.replaceAll("\\p{Z}", "")
|
.replaceAll("\t", "")
|
.replaceAll("\r", "")
|
.replaceAll("\n", "");
|
|
if (newValue.length() >= tailleReelle) {
|
return newValue;
|
}
|
if (newValue.matches("^\\d+[,.]?\\d+$")
|
|| newValue.matches("[-+]?\\d+(\\.\\d+)?[eE][-+]?\\d+")
|
|| newValue.matches("^\\d{1,3},\\d+E[+-]?\\d+$")) {//Notation scientifique
|
try {
|
newValue = new BigDecimal(newValue.replace(',', '.')).toPlainString();//Remplacer la virgule par le point
|
} catch (Exception ex) {
|
}
|
}
|
return generateUnknown(tailleReelle - newValue.length(), " ") + newValue;
|
}
|
|
/**
|
* Méthode qui génère un nombre précis d'un quelconque caractère
|
*
|
* @param nbOfCharacter : nombre de fois à générer le caractère
|
* @param character : caractère à générer
|
* @return
|
*/
|
private static String generateUnknown(int nbOfCharacter, String character) {
|
String str = "";
|
|
for (int i = 0; i < nbOfCharacter; i++) {
|
str += character;
|
}
|
return str;
|
}
|
|
/**
|
* Méthode qui extrait les données en se basant sur la taille des champs
|
* définis dans le validateur
|
*/
|
private static void parseLineUsingFieldLength(String line, Map<Integer, Map> mapParams, String delimiteurColonne, BufferedWriter bufferWriter, Charset charset) throws IOException {
|
|
String[] columnsTableLine = new String[mapParams.size() - 1];
|
|
try {
|
int index = 0;
|
int i = 1;
|
|
while (i < mapParams.size()) {
|
Map<String, String> map = mapParams.get(i);
|
|
int taille = Integer.parseInt(map.get(Constantes.LIBELLE_TAILLE));
|
|
if (i == mapParams.size() - 1) {
|
columnsTableLine[i - 1] = line.substring(index);
|
} else {
|
columnsTableLine[i - 1] = line.substring(index, index + taille);
|
}
|
|
index = index + taille;
|
|
//recupérer le charactère correspondant au delimiteur
|
char character = ParserUtils.characterOfDelimiteur(delimiteurColonne);
|
|
//Si le démimiteur n'est pas la chaîne vide
|
if (character != '\0') {
|
|
//Si on ne trouve pas le délimiteur après avoir lu le champ précédent, on arrete le traitement de cette ligne car fichier mal formaté
|
if ((i < mapParams.size() - 1) && (line.charAt(index) != character)) {
|
|
//Interrompre l'extraction des données en remplissant la condition de sortie de laboucle
|
i = mapParams.size();
|
} else {
|
|
//Incrementer l'index un afin de traverser le séparateur
|
index = index + 1;
|
}
|
|
}
|
i++;
|
}
|
|
String[] encodedStrings = ParserUtils.encodeStrings(columnsTableLine, charset);
|
ParserUtils.writeToFile(encodedStrings, bufferWriter);
|
|
} catch (Exception ex) {
|
Logger.getLogger(ImportData.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
|
}
|
|
}
|
|
/**
|
* Méthode qui écrit les informations sur les éléments tronqués dans un
|
* fichier
|
*
|
* @param t
|
* @param bufferWriter
|
* @throws IOException
|
*/
|
private static void writeTruncatedElementsToFile(TruncatedElement t, final BufferedWriter bufferWriter) throws IOException {
|
|
//Ecriture dans le fichier output
|
StringBuilder safeLineBuilder = new StringBuilder(0);
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
LocalDateTime date = t.getDateAction();
|
|
safeLineBuilder.append("Fichier:").append(t.getFileName()).append("|");
|
safeLineBuilder.append("Date:").append(date.format(formatter)).append("|");
|
safeLineBuilder.append("Ligne:").append(t.getLineNumber()).append("|");
|
safeLineBuilder.append("Colonne:").append(t.getCodeColonne()).append("|");
|
safeLineBuilder.append("Taille attendue:").append(t.getTailleAttendue()).append("|");
|
safeLineBuilder.append("Donnée finale:").append(t.getFinalData()).append("|");
|
safeLineBuilder.append("Taille trouvée:").append(t.getTailleTrouvee()).append("|");
|
safeLineBuilder.append("Donnée initiale:").append(t.getInitialData());
|
|
String safeLine = safeLineBuilder.toString();
|
|
if (safeLine.length() > 0) {
|
|
bufferWriter.write(safeLine + System.lineSeparator());
|
|
}
|
}
|
|
/**
|
* Méthode qui retourne le nom fichier sans extension
|
*
|
* @param file
|
* @return
|
*/
|
private static String fileNameWithoutExtension(File file) {
|
int index = file.getName().lastIndexOf(".");
|
|
if (index > 0) {
|
|
return file.getName().substring(0, index);
|
} else {
|
return file.getName();
|
}
|
}
|
|
/**
|
* Méthode qui construit le chemin du fichier qui va contenit les logs des
|
* éléments tronqués
|
*
|
* @param validateur
|
* @param outputFile
|
* @return
|
* @throws IOException
|
*/
|
private static Path createTruncatedEltsPath(Validateur validateur, File outputFile) throws IOException {
|
final String arhivageDirectory = ConfigurationService.getInstance().getCurrentConfig().getArchivesDir();
|
final String today = LocalDate.now().toString();
|
|
Path logDir = Paths.get(arhivageDirectory, today, validateur.getCodeTypeFichier(), "logs");
|
|
if (!Files.exists(logDir, LinkOption.NOFOLLOW_LINKS)) {
|
Files.createDirectories(logDir);
|
}
|
|
Path pathOfTruncatedElts = Paths.get(arhivageDirectory, today, validateur.getCodeTypeFichier(), "logs", fileNameWithoutExtension(outputFile) + "_truncated_elements.txt");
|
|
return pathOfTruncatedElts;
|
|
}
|
|
/**
|
* méthode permettant de construire le chemin du fichier d'origine dans le
|
* répertoire d'archivages
|
*
|
* @param validateur
|
* @param originalFile
|
* @return
|
* @throws IOException
|
*/
|
private static Path createOriginalFileInArchive(Validateur validateur, File originalFile) throws IOException {
|
final String arhivageDirectory = ConfigurationService.getInstance().getCurrentConfig().getArchivesDir();
|
final String today = LocalDate.now().toString();
|
|
Path originalFilesDir = Paths.get(arhivageDirectory, today, validateur.getCodeTypeFichier(), "fichiers");
|
|
if (!Files.exists(originalFilesDir, LinkOption.NOFOLLOW_LINKS)) {
|
Files.createDirectories(originalFilesDir);
|
}
|
|
Path originalFilePath = Paths.get(arhivageDirectory, today, validateur.getCodeTypeFichier(), "fichiers", originalFile.getName());
|
final String fileNameWithoutExtension = fileNameWithoutExtension(originalFile);
|
|
//Si le fichier existe dans le répertoire d'archivages, alors ajouter un numero d'ordre dans son nom
|
if (Files.exists(originalFilePath, LinkOption.NOFOLLOW_LINKS)) {
|
List<Path> existingFiles = Files.list(originalFilesDir).filter(p
|
-> p.toString().contains(fileNameWithoutExtension)).collect(Collectors.toList());
|
|
int nbFiles = existingFiles.size();
|
|
if (nbFiles > 0) {
|
originalFilePath = Paths.get(arhivageDirectory, today, validateur.getCodeTypeFichier(), "fichiers",
|
fileNameWithoutExtension + "(" + nbFiles + ")" + getFileExtension(originalFile));
|
}
|
}
|
|
return originalFilePath;
|
}
|
|
/**
|
* Méthode qui retourne l'extension d'un fichier
|
*
|
* @param file
|
* @return
|
*/
|
private static String getFileExtension(File file) {
|
int index = file.getName().lastIndexOf(".");
|
|
if (index <= 0) {
|
return "";
|
|
} else {
|
return file.getName().substring(index);
|
}
|
}
|
|
}
|