diff --git a/selcukes-commons/src/main/java/io/github/selcukes/commons/config/ConfigFactory.java b/selcukes-commons/src/main/java/io/github/selcukes/commons/config/ConfigFactory.java index 6f52bc1dc..d01bccf8e 100644 --- a/selcukes-commons/src/main/java/io/github/selcukes/commons/config/ConfigFactory.java +++ b/selcukes-commons/src/main/java/io/github/selcukes/commons/config/ConfigFactory.java @@ -18,12 +18,9 @@ import io.github.selcukes.commons.helper.FileHelper; import io.github.selcukes.commons.helper.SingletonContext; -import io.github.selcukes.commons.logging.Logger; -import io.github.selcukes.commons.logging.LoggerFactory; import io.github.selcukes.databind.DataMapper; import lombok.experimental.UtilityClass; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.logging.LogManager; @@ -31,7 +28,6 @@ @UtilityClass public class ConfigFactory { private static final String DEFAULT_LOG_BACK_FILE = "selcukes-logback.yaml"; - private static final Logger LOGGER = LoggerFactory.getLogger(ConfigFactory.class); private static final SingletonContext ENVIRONMENT_CONTEXT = SingletonContext .with(() -> DataMapper.parse(Environment.class)); @@ -53,19 +49,4 @@ public void loadLoggerProperties() { // Gobble exception } } - - public static InputStream getStream(final String fileName) { - try { - LOGGER.config(() -> String.format("Attempting to read %s as resource.", fileName)); - InputStream stream = FileHelper.loadThreadResourceAsStream(fileName); - if (stream == null) { - LOGGER.config(() -> String.format("Re-attempting to read %s as a local file.", fileName)); - return new FileInputStream(fileName); - } - return stream; - } catch (Exception ignored) { - // Gobble exception - } - return null; - } } diff --git a/selcukes-databind/src/main/java/io/github/selcukes/databind/excel/ExcelMapper.java b/selcukes-databind/src/main/java/io/github/selcukes/databind/excel/ExcelMapper.java index 7769496e9..de7c16b43 100644 --- a/selcukes-databind/src/main/java/io/github/selcukes/databind/excel/ExcelMapper.java +++ b/selcukes-databind/src/main/java/io/github/selcukes/databind/excel/ExcelMapper.java @@ -19,14 +19,13 @@ import io.github.selcukes.databind.exception.DataMapperException; import io.github.selcukes.databind.utils.DataFileHelper; import io.github.selcukes.databind.utils.Maps; +import io.github.selcukes.databind.utils.Resources; import io.github.selcukes.databind.utils.Streams; import lombok.experimental.UtilityClass; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.WorkbookFactory; -import java.io.File; -import java.io.FileInputStream; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -61,16 +60,19 @@ public Stream parse(final Class entityClass) { } /** - * It creates a workbook from the file, creates a formula evaluator, and - * then creates a map of sheet names to a list of maps of column names to - * cell values + * This method takes a file path as input, creates a workbook from the file + * at the path, and then creates a map of sheet names to a list of maps of + * column names to cell values. The first row of each sheet is assumed to + * contain column headers,and is skipped in the output. The remaining rows + * are parsed and stored in the output map. * - * @param file The file to be parsed. - * @return A map of sheet names to a list of maps of column names to - * cell values. + * @param filePath The file path of the Excel file to be parsed. + * @return A map of sheet names to a list of maps of + * column names to cell values. + * @throws DataMapperException If there is an error parsing the Excel file. */ - public static Map>> parse(File file) { - try (var workbook = WorkbookFactory.create(new FileInputStream(file))) { + public static Map>> parse(String filePath) { + try (var workbook = WorkbookFactory.create(Resources.fileStream(filePath))) { ExcelCell.setFormulaEvaluator(workbook.getCreationHelper().createFormulaEvaluator()); return Streams.of(workbook.iterator()) @@ -79,7 +81,7 @@ public static Map>> parse(File file) { .map(ExcelMapper::readRow) .collect(Collectors.toList()))); } catch (Exception e) { - throw new DataMapperException("Unable to parse Excel file " + file.getAbsolutePath(), e); + throw new DataMapperException("Unable to parse Excel file " + filePath, e); } } diff --git a/selcukes-databind/src/main/java/io/github/selcukes/databind/excel/ExcelParser.java b/selcukes-databind/src/main/java/io/github/selcukes/databind/excel/ExcelParser.java index 90a9497fb..833bb213f 100644 --- a/selcukes-databind/src/main/java/io/github/selcukes/databind/excel/ExcelParser.java +++ b/selcukes-databind/src/main/java/io/github/selcukes/databind/excel/ExcelParser.java @@ -20,11 +20,11 @@ import io.github.selcukes.databind.converters.Converter; import io.github.selcukes.databind.exception.DataMapperException; import io.github.selcukes.databind.utils.Maps; +import io.github.selcukes.databind.utils.Resources; import io.github.selcukes.databind.utils.Streams; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.WorkbookFactory; -import java.io.FileInputStream; import java.nio.file.Path; import java.util.List; import java.util.stream.Collectors; @@ -46,7 +46,7 @@ public ExcelParser(final Class entityClass) { } public Stream parse(Path filePath) { - try (var workbook = WorkbookFactory.create(new FileInputStream(filePath.toFile()))) { + try (var workbook = WorkbookFactory.create(Resources.fileStream(filePath.toString()))) { var startIndex = 0; var skip = 1; ExcelCell.setFormulaEvaluator(workbook.getCreationHelper().createFormulaEvaluator()); diff --git a/selcukes-databind/src/main/java/io/github/selcukes/databind/utils/Resources.java b/selcukes-databind/src/main/java/io/github/selcukes/databind/utils/Resources.java index 1e6419702..bec30f6ab 100644 --- a/selcukes-databind/src/main/java/io/github/selcukes/databind/utils/Resources.java +++ b/selcukes-databind/src/main/java/io/github/selcukes/databind/utils/Resources.java @@ -24,9 +24,12 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Objects; +import java.util.function.Supplier; +import java.util.stream.Stream; import static java.lang.String.format; -import static java.util.Optional.ofNullable; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; @UtilityClass public class Resources { @@ -78,6 +81,22 @@ public String createFile(final Path filePath) { } } + /** + * Copies a file from the source path to the destination path. + * + * @param sourceFile the path of the file to copy + * @param destinationFile the path to copy the file to + * @throws DataMapperException if an error occurs while copying the file + */ + public void copyFile(final Path sourceFile, final Path destinationFile) { + try { + Files.copy(sourceFile, destinationFile, REPLACE_EXISTING); + } catch (IOException e) { + throw new DataMapperException(format("Failed to copy file from [%s] to [%s]: %s", + sourceFile.toAbsolutePath(), destinationFile.toAbsolutePath(), e.getMessage())); + } + } + /** * "Find the first file in the target directory that starts with the given * file name." @@ -105,18 +124,42 @@ public static Path findFile(final Path targetDir, final String fileName) { } /** - * "If the file exists, return it as a stream, otherwise throw an - * exception." + * Returns an input stream for reading from the file at the given file path. + * This method attempts to load the file from several locations in the + * following order: + *
    + *
  1. The file is loaded from the current thread's context class loader as + * a resource
  2. + *
  3. The file is loaded from the file system using the + * {@link #newFileStream(String)} method
  4. + *
  5. The file is loaded from the class loader of the {@link Resources} + * class as a resource
  6. + *
  7. The file is loaded from the package of the {@link Resources} class as + * a resource
  8. + *
+ * The method returns the first non-null input stream that is successfully + * loaded from one of these locations. * - * @param fileName The name of the file to be loaded. - * @return InputStream + * @param filePath the path to the file to read from + * @return an input stream for the file + * @throws DataMapperException if the file cannot be loaded from any of the + * locations or an error occurs while opening + * the stream */ - public InputStream fileStream(final String fileName) { - return ofNullable(Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)) - .orElseThrow(() -> new DataMapperException( - format("Failed to load file [%s] as a stream from classpath. " + - "Make sure the file exists and is included in the classpath.", - fileName))); + public InputStream fileStream(final String filePath) { + return Stream.>of( + () -> Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath), + () -> newFileStream(filePath), + () -> Resources.class.getClassLoader().getResourceAsStream(filePath), + () -> Resources.class.getResourceAsStream(filePath)) + .parallel() + .map(Supplier::get) + .filter(Objects::nonNull) + .findFirst() + .orElseThrow( + () -> new DataMapperException(format("Failed to load file [%s] as a stream. " + + "Make sure the file exists and is accessible.", + filePath))); } /** @@ -129,4 +172,24 @@ public InputStream fileStream(final String fileName) { public Path ofTest(final String fileName) { return of(TEST_RESOURCES + File.separator + fileName); } + + /** + * Returns an input stream for reading from the file at the given file path. + * + * @param filePath the path to the file to read from + * @return an input stream for the file, or {@code null} if the + * file does not exist or an error occurs while opening the + * stream + */ + public static InputStream newFileStream(String filePath) { + Path path = Path.of(filePath); + if (Files.exists(path)) { + try { + return Files.newInputStream(path); + } catch (IOException ignored) { + // Gobble exception + } + } + return null; + } } diff --git a/selcukes-databind/src/test/java/io/github/selcukes/databind/tests/XmlTest.java b/selcukes-databind/src/test/java/io/github/selcukes/databind/tests/XmlTest.java index 3388ed4ba..2aa969e69 100644 --- a/selcukes-databind/src/test/java/io/github/selcukes/databind/tests/XmlTest.java +++ b/selcukes-databind/src/test/java/io/github/selcukes/databind/tests/XmlTest.java @@ -21,6 +21,7 @@ import io.github.selcukes.databind.DataMapper; import io.github.selcukes.databind.annotation.DataFile; import lombok.Data; +import org.testng.Assert; import org.testng.annotations.Test; import java.util.List; @@ -29,9 +30,35 @@ public class XmlTest { @Test public void xmlTest() { - CustomerInfo memberInfo = DataMapper.parse(CustomerInfo.class); - System.out.println(memberInfo.getMetaData().get("eventNotificationDate")); - System.out.println(memberInfo.getContactPersonList().get(0).get("firstName")); + var customerInfo = DataMapper.parse(CustomerInfo.class); + System.out.println(customerInfo.getMetaData().get("eventNotificationDate")); + System.out.println(customerInfo.getContactPersonList().get(0).get("firstName")); + } + + @Test + public void updateXmlTest() { + var excelData = Map.of( + "contactPersonList", List.of(Map.of( + "contactPersonId", "4567", + "email", "test@test.com", + "firstName", "Ramesh", + "lastName", "Babu", + "mobilePhone", "+15168978352", + "title", "Treasury", + "workPhone", "+19087253123"))); + var customerInfo = DataMapper.parse(CustomerInfo.class); + var contactPersonList = customerInfo.getContactPersonList(); + /* + * Streams.of(1, + * contactPersonList.size()).forEach(contactPersonList::remove); + * contactPersonList.get(0).clear(); + */ + contactPersonList.addAll(excelData.get("contactPersonList")); + + DataMapper.write(customerInfo); + var customerInfo1 = DataMapper.parse(CustomerInfo.class); + Assert.assertEquals(contactPersonList, customerInfo1.getContactPersonList()); + } @Data diff --git a/selcukes-excel-runner/src/main/java/io/github/selcukes/excel/MultiExcelData.java b/selcukes-excel-runner/src/main/java/io/github/selcukes/excel/MultiExcelData.java index 134fe589e..4518155ec 100644 --- a/selcukes-excel-runner/src/main/java/io/github/selcukes/excel/MultiExcelData.java +++ b/selcukes-excel-runner/src/main/java/io/github/selcukes/excel/MultiExcelData.java @@ -42,7 +42,7 @@ public class MultiExcelData { private static final Map>>> runtimeDataMap = new LinkedHashMap<>(); public static void init() { - var filePath = FileHelper.loadResource(ConfigFactory.getConfig().getExcel().get("suiteFile")); + var filePath = ConfigFactory.getConfig().getExcel().get("suiteFile"); var excelData = ExcelMapper.parse(filePath); var suiteName = ConfigFactory.getConfig().getExcel().get("suiteName"); excelSuite = excelData.get(suiteName); @@ -77,8 +77,7 @@ public Map getTestDataAsMap(String testName) { } private Map>> readAndCacheTestData(String testDataFile) { - var filePath = FileHelper.loadResource(testDataFile); - var testData = ExcelMapper.parse(filePath); + var testData = ExcelMapper.parse(testDataFile); testData.forEach((key, value) -> SingleExcelData.modifyFirstColumnData(value, TEST, EXAMPLE)); runtimeDataMap.put(testDataFile, testData); return testData; diff --git a/selcukes-excel-runner/src/main/java/io/github/selcukes/excel/SingleExcelData.java b/selcukes-excel-runner/src/main/java/io/github/selcukes/excel/SingleExcelData.java index 02f537b1c..0be957b27 100644 --- a/selcukes-excel-runner/src/main/java/io/github/selcukes/excel/SingleExcelData.java +++ b/selcukes-excel-runner/src/main/java/io/github/selcukes/excel/SingleExcelData.java @@ -18,7 +18,6 @@ import io.github.selcukes.commons.config.ConfigFactory; import io.github.selcukes.commons.exception.ExcelConfigException; -import io.github.selcukes.commons.helper.FileHelper; import io.github.selcukes.databind.excel.ExcelMapper; import io.github.selcukes.databind.utils.Maps; import io.github.selcukes.databind.utils.StringHelper; @@ -50,8 +49,7 @@ public class SingleExcelData { private static Map>> excelData = new LinkedHashMap<>(); public static void init() { - - var filePath = FileHelper.loadResource(ConfigFactory.getConfig().getExcel().get("dataFile")); + var filePath = ConfigFactory.getConfig().getExcel().get("dataFile"); excelData = ExcelMapper.parse(filePath); IGNORE_SHEETS.remove(TEST_SUITE_RUNNER_SHEET); logger.debug(() -> "Using excel runner sheet : " + TEST_SUITE_RUNNER_SHEET);