Repository: camel Updated Branches: refs/heads/master 58dea1965 -> b27c98c95
CAMEL-7862-add CVSRecord annotation attribute to allow empty streams to be processed Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/c609efd6 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/c609efd6 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/c609efd6 Branch: refs/heads/master Commit: c609efd63d25b7868f6869ca4ca2b3bd74b47245 Parents: ddbbf64 Author: onders86 <ondersez...@gmail.com> Authored: Fri Mar 10 11:47:15 2017 +0300 Committer: Andrea Cosentino <anco...@gmail.com> Committed: Fri Mar 10 13:37:44 2017 +0100 ---------------------------------------------------------------------- .../camel/dataformat/bindy/BindyCsvFactory.java | 9 +++ .../dataformat/bindy/annotation/CsvRecord.java | 6 ++ .../bindy/csv/BindyCsvDataFormat.java | 83 +++++++++++++------- ...ySimpleCsvMandatoryFieldsUnmarshallTest.java | 26 ++++++ 4 files changed, 97 insertions(+), 27 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/c609efd6/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyCsvFactory.java ---------------------------------------------------------------------- diff --git a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyCsvFactory.java b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyCsvFactory.java index 943f85c..4baaa31 100755 --- a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyCsvFactory.java +++ b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyCsvFactory.java @@ -67,6 +67,7 @@ public class BindyCsvFactory extends BindyAbstractFactory implements BindyFactor private String quote; private boolean quoting; private boolean autospanLine; + private boolean allowEmptyStream; public BindyCsvFactory(Class<?> type) throws Exception { super(type); @@ -570,6 +571,10 @@ public class BindyCsvFactory extends BindyAbstractFactory implements BindyFactor autospanLine = record.autospanLine(); LOG.debug("Autospan line in last record: {}", autospanLine); + + // Get skipFirstLine parameter + allowEmptyStream = record.allowEmptyStream(); + LOG.debug("Allo empty stream parameter of the CSV: {}" + allowEmptyStream); } if (section != null) { @@ -652,4 +657,8 @@ public class BindyCsvFactory extends BindyAbstractFactory implements BindyFactor public int getMaxpos() { return maxpos; } + + public boolean isAllowEmptyStream() { + return allowEmptyStream; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/c609efd6/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/CsvRecord.java ---------------------------------------------------------------------- diff --git a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/CsvRecord.java b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/CsvRecord.java index d6573e7..6a1094d 100755 --- a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/CsvRecord.java +++ b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/CsvRecord.java @@ -84,5 +84,11 @@ public @interface CsvRecord { * Last record spans rest of line (optional) */ boolean autospanLine() default false; + + /** + * The allowEmptyStream parameter will allow to prcoess + * the unavaiable stream for CSV file. + */ + boolean allowEmptyStream() default false; } http://git-wip-us.apache.org/repos/asf/camel/blob/c609efd6/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/csv/BindyCsvDataFormat.java ---------------------------------------------------------------------- diff --git a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/csv/BindyCsvDataFormat.java b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/csv/BindyCsvDataFormat.java index 06ead20..4aa8da6 100755 --- a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/csv/BindyCsvDataFormat.java +++ b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/csv/BindyCsvDataFormat.java @@ -16,6 +16,7 @@ */ package org.apache.camel.dataformat.bindy.csv; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; @@ -105,29 +106,53 @@ public class BindyCsvDataFormat extends BindyAbstractDataFormat { outputStream.write(bytesCRLF); } } + + /** + * check emptyStream and if CVSRecord is allow to process emptyStreams + * avoid IllegalArgumentException and return empty list when unmarshalling + */ + private boolean checkEmptyStream(BindyCsvFactory factory, InputStream inputStream) throws IOException { + boolean allowEmptyStream = factory.isAllowEmptyStream(); + boolean isStreamEmpty = false; + boolean canReturnEmptyListOfModels = false; + + if(inputStream == null || inputStream.available() == 0) + isStreamEmpty = true; + + if(isStreamEmpty == true && allowEmptyStream == true) + canReturnEmptyListOfModels = true; + + return canReturnEmptyListOfModels; + } public Object unmarshal(Exchange exchange, InputStream inputStream) throws Exception { BindyCsvFactory factory = (BindyCsvFactory)getFactory(); - ObjectHelper.notNull(factory, "not instantiated"); + ObjectHelper.notNull(factory, "not instantiated"); // List of Pojos List<Map<String, Object>> models = new ArrayList<Map<String, Object>>(); // Pojos of the model Map<String, Object> model; - - InputStreamReader in = new InputStreamReader(inputStream, IOHelper.getCharsetName(exchange)); - - // Scanner is used to read big file - Scanner scanner = new Scanner(in); - - // Retrieve the separator defined to split the record - String separator = factory.getSeparator(); - String quote = factory .getQuote(); - ObjectHelper.notNull(separator, "The separator has not been defined in the annotation @CsvRecord or not instantiated during initModel."); - - int count = 0; + InputStreamReader in = null; + Scanner scanner = null; try { + + if (checkEmptyStream(factory,inputStream)) + return models; + + in = new InputStreamReader(inputStream, IOHelper.getCharsetName(exchange)); + + // Scanner is used to read big file + scanner = new Scanner(in); + + // Retrieve the separator defined to split the record + String separator = factory.getSeparator(); + String quote = factory .getQuote(); + ObjectHelper.notNull(separator, "The separator has not been defined in the annotation @CsvRecord or not instantiated during initModel."); + + int count = 0; + // If the first line of the CSV file contains columns name, then we // skip this line if (factory.getSkipFirstLine()) { @@ -136,50 +161,50 @@ public class BindyCsvDataFormat extends BindyAbstractDataFormat { scanner.nextLine(); } } - + while (scanner.hasNextLine()) { - + // Read the line String line = scanner.nextLine().trim(); - + if (ObjectHelper.isEmpty(line)) { // skip if line is empty continue; } - + // Increment counter count++; - + // Create POJO where CSV data will be stored model = factory.factory(); - + // Split the CSV record according to the separator defined in // annotated class @CSVRecord String[] tokens = line.split(separator, factory.getAutospanLine() ? factory.getMaxpos() : -1); List<String> result = Arrays.asList(tokens); // must unquote tokens before use result = unquoteTokens(result, separator, quote); - + if (result.size() == 0 || result.isEmpty()) { throw new java.lang.IllegalArgumentException("No records have been defined in the CSV"); } else { if (LOG.isDebugEnabled()) { LOG.debug("Size of the record splitted : {}", result.size()); } - + // Bind data from CSV record with model classes factory.bind(result, model, count); - + // Link objects together factory.link(model); - + // Add objects graph to the list models.add(model); - + LOG.debug("Graph of objects created: {}", model); } } - + // BigIntegerFormatFactory if models list is empty or not // If this is the case (correspond to an empty stream, ...) if (models.size() == 0) { @@ -189,8 +214,12 @@ public class BindyCsvDataFormat extends BindyAbstractDataFormat { } } finally { - scanner.close(); - IOHelper.close(in, "in", LOG); + if(scanner != null) { + scanner.close(); + } + if(in != null) { + IOHelper.close(in, "in", LOG); + } } } http://git-wip-us.apache.org/repos/asf/camel/blob/c609efd6/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindySimpleCsvMandatoryFieldsUnmarshallTest.java ---------------------------------------------------------------------- diff --git a/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindySimpleCsvMandatoryFieldsUnmarshallTest.java b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindySimpleCsvMandatoryFieldsUnmarshallTest.java index 0799792..7095782 100644 --- a/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindySimpleCsvMandatoryFieldsUnmarshallTest.java +++ b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindySimpleCsvMandatoryFieldsUnmarshallTest.java @@ -38,12 +38,18 @@ public class BindySimpleCsvMandatoryFieldsUnmarshallTest extends AbstractJUnit4S @EndpointInject(uri = "mock:result2") protected MockEndpoint resultEndpoint2; + + @EndpointInject(uri = "mock:result3") + protected MockEndpoint resultEndpoint3; @Produce(uri = "direct:start1") protected ProducerTemplate template1; @Produce(uri = "direct:start2") protected ProducerTemplate template2; + + @Produce(uri = "direct:start3") + protected ProducerTemplate template3; String header = "order nr,client ref,first name, last name,instrument code,instrument name,order type, instrument type, quantity,currency,date\r\n"; @@ -128,6 +134,24 @@ public class BindySimpleCsvMandatoryFieldsUnmarshallTest extends AbstractJUnit4S resultEndpoint1.assertIsSatisfied(); } + + @DirtiesContext + @Test + public void testEmptyLineWithAllowEmptyStreamEqualsTrue() throws Exception { + String record6 = ""; // empty line + resultEndpoint3.expectedMessageCount(1); + template3.sendBody(record6); + resultEndpoint3.assertIsSatisfied(); + } + + @DirtiesContext + @Test + public void testNonEmptyLineWithAllowEmptyStreamEqualsTrue() throws Exception { + String record3 = "1,A1,Onder,Sezgin,MYC,BB123456789,,,,,"; // mandatory + resultEndpoint3.expectedMessageCount(1); + template3.sendBody(record3); + resultEndpoint3.assertIsSatisfied(); + } @DirtiesContext @Test @@ -166,10 +190,12 @@ public class BindySimpleCsvMandatoryFieldsUnmarshallTest extends AbstractJUnit4S public static class ContextConfig extends RouteBuilder { BindyCsvDataFormat formatOptional = new BindyCsvDataFormat(org.apache.camel.dataformat.bindy.model.simple.oneclass.Order.class); BindyCsvDataFormat formatMandatory = new BindyCsvDataFormat(org.apache.camel.dataformat.bindy.model.simple.oneclassmandatory.Order.class); + BindyCsvDataFormat formatEmptyStream= new BindyCsvDataFormat(org.apache.camel.dataformat.bindy.model.simple.oneclassemptystream.Order.class); public void configure() { from("direct:start1").unmarshal(formatOptional).to("mock:result1"); from("direct:start2").unmarshal(formatMandatory).to("mock:result2"); + from("direct:start3").unmarshal(formatEmptyStream).to("mock:result3"); } }