Camel recipientList 太长会导致 StackOverflow 错误
Camel recipientList so long it causes StackOverflow error
在后续步骤中将数据写入这些文件之前,我正在使用收件人列表初始化 30 多个带有 header 的文件。 (edit) 我正在按给定字段将文件拆分为大约 30 个文件,这些新文件需要与原始文件相同的 header。 header 和 split-by-type 是将使用文件的应用程序的要求。
超过 30 个,comma-separated,当 camel 尝试解析字符串时,一个字符串中的完整文件路径会导致 Whosebug 错误。我通过增加堆栈大小解决了这个问题(目前)。
但必须有更强大的解决方案,也许我可以以某种方式使用相对文件路径?
(编辑)代码:
@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);
}
}
你是对的。我能够使用实际的 Apache Camel 2.21.1 通过以下测试重现它。 recipientList
在 WhosebugError
上失败,端点列表以逗号分隔。但是,如果您传递 List<String>
个端点,该路由将按预期工作。因此,您可以修改 SplitFileByProductType
处理器以创建端点列表,而不是逗号分隔的字符串。
public class LongRecipientListCausesWhosebug 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 WhosebugError 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);
}
}
在后续步骤中将数据写入这些文件之前,我正在使用收件人列表初始化 30 多个带有 header 的文件。 (edit) 我正在按给定字段将文件拆分为大约 30 个文件,这些新文件需要与原始文件相同的 header。 header 和 split-by-type 是将使用文件的应用程序的要求。
超过 30 个,comma-separated,当 camel 尝试解析字符串时,一个字符串中的完整文件路径会导致 Whosebug 错误。我通过增加堆栈大小解决了这个问题(目前)。
但必须有更强大的解决方案,也许我可以以某种方式使用相对文件路径?
(编辑)代码:
@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);
}
}
你是对的。我能够使用实际的 Apache Camel 2.21.1 通过以下测试重现它。 recipientList
在 WhosebugError
上失败,端点列表以逗号分隔。但是,如果您传递 List<String>
个端点,该路由将按预期工作。因此,您可以修改 SplitFileByProductType
处理器以创建端点列表,而不是逗号分隔的字符串。
public class LongRecipientListCausesWhosebug 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 WhosebugError 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);
}
}