Верблюдский получатель так долго, что это вызывает ошибку StackOverflow - PullRequest
0 голосов
/ 29 мая 2018

Я использую Список получателей для инициализации 30+ файлов с заголовком, прежде чем записывать данные в эти файлы на последующих шагах.( edit ) Я разбил файл примерно на 30 файлов по заданному полю, эти новые файлы должны иметь тот же заголовок, что и исходный файл.Заголовки и разделение по типу являются требованиями приложения, которое будет использовать файлы.

Наличие более 30 разделенных запятыми полных путей к файлам в одной строке приводит к ошибке StackOverflow при попытке верблюдаразобрать строку.Я решил это (на данный момент), увеличив размер стека.

Но должно быть более надежное решение, может быть, я могу как-то использовать относительные пути к файлам?

( edit ) Код:

@Component
public class SplitterRoutesBuilder extends SpringRouteBuilder {

   @Autowired
   private ApplicationConfig configuration;

   @Autowired
   private MyFileFormat fileFormat;

   @Override
   public void configure() throws Exception {

     from(configuration.getFrom())
     .to("bean:splitFileByProductType?method=initialize(*)")
     // split file
     .split(body().tokenize(fileFormat.getLineEnd())).streaming().to("bean:splitFileByProductType?method=processLine(*)")
     .recipientList(header(SplitFileByProductType.WRITE_FILENAME_HEADER))
     .end();
    }
}

Затем в SplitFileByProductType:

   public void processLine(Exchange exchange) throws EmptyLineException {
       String line = exchange.getIn().getBody(String.class);
       String originalFileName = (String) exchange.getIn().getHeader(ORIGINAL_FILENAME_HEADER);
       // various checks and errorhandling omitted for clariry
       setoutputFileExchangeHeader(exchange, values[index].trim(), originalFileName, leftOversFileName);
       exchange.getIn().setBody(line + fileFormat.getLineEnd());
}

Фактическая работа выполняется здесь:

private void setoutputFileExchangeHeader(Exchange exchange, String product, String originalFileName, String leftOversFileName) {
    if (isProductType(product)) {
        // a regular line, write to appropriate file
        exchange.getIn().setHeader(WRITE_FILENAME_HEADER,
                fileNameFormatter.getProductFileDestination(originalFileName, product));
    } else if (PRODUCT_COLUMN_NAME.equals(product)) {
        // this is the header line, write the header to all files
        exchange.getIn().setHeader(WRITE_FILENAME_HEADER, getAllFileNames(originalFileName, leftOversFileName));
    } else {
        // product not regognized, line goes to 'rest'
        exchange.getIn().setHeader(WRITE_FILENAME_HEADER, leftOversFileName);
    }
}

1 Ответ

0 голосов
/ 30 мая 2018

Вы правы.Я смог воспроизвести его с помощью следующего теста, используя настоящий Apache Camel 2.21.1.recipientList завершается с ошибкой StackOverflowError с разделенным запятыми списком конечных точек.Однако, если вы передадите List<String> конечных точек, маршрут будет работать как положено.Таким образом, вы можете изменить ваш SplitFileByProductType процессор для создания списка конечных точек вместо строки, разделенной запятыми.


public class LongRecipientListCausesStackOverflow extends CamelTestSupport {

    private static final int COUNT = 300;
    private static final String BASE_DIR = "D://temp/cameltest/";

    @Override
    protected RoutesBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("direct:in")
                        .recipientList(header("to"))
                        .to("mock:done");
            }
        };
    }

    @Before
    public void clenup() throws Exception{
        FileUtils.deleteDirectory(new File(BASE_DIR));
    }

    @Test
    public void fails() throws Exception { //fails, throws StackOverflowError with header("to") of type String
        MockEndpoint mockEndpoint = getMockEndpoint("mock:done");
        String recipientListString = IntStream.range(0,COUNT).mapToObj(subDir -> "file:"+BASE_DIR+subDir).collect(Collectors.joining(","));
        template.sendBodyAndHeader("direct:in","", "to", recipientListString);
        mockEndpoint.assertIsSatisfied();
        Assert.assertEquals(COUNT, new File(BASE_DIR).listFiles().length);
    }

    @Test
    public void passes() throws Exception { //pass with header("to") of type List<String>
        MockEndpoint mockEndpoint = getMockEndpoint("mock:done");
        List<String> recipientListList = IntStream.range(0,COUNT).mapToObj(subDir -> "file:"+BASE_DIR+subDir).collect(Collectors.toList());
        template.sendBodyAndHeader("direct:in","", "to", recipientListList);
        mockEndpoint.assertIsSatisfied();
        Assert.assertEquals(COUNT, new File(BASE_DIR).listFiles().length);
    }
}
...