【问题标题】:Let Camel handle various URI types让 Camel 处理各种 URI 类型
【发布时间】:2016-05-04 07:46:46
【问题描述】:

我想编写一个 Camel Route,它获取一个 URI(可以是 http、ftp、文件……),然后获取数据并将其本地存储在一个文件中。

这个 URI-String 可以是,例如:

根据这个字符串,应该使用正确的 Camel 组件来访问数据。类似于 Java 中的 case/switch:

(1) 接收 URI(来自 uri="vm:incomingUri")

(2) 选择“正确”的骆驼组件

switch(URI)
case HTTP: use Camel HTTP component
case FTP: use Camel FTP component
case JMS: use Camel JMS component
...

(3) 使用“正确”的 Camel 组件从该 URI 读取数据

(4) 本地存储文件(到 uri="file://...)

示例: 从“vm:incomingUri”我读到一个字符串“ftp://localhost/example.txt”。那现在最终需要发生的应该是这样的:

<route>
    <from uri="ftp://localhost/example.txt"/>
    <to uri="file://tmpDir/example.txt"/>
</route>

这在 Camel 中会是什么样子?

【问题讨论】:

  • 您很可能想看看新的"dynamic to" 语法(如果您使用的是Camel 2.16+)或recipient list 模式。两者都将允许对 uri 进行动态评估。

标签: apache-camel


【解决方案1】:

我相信一个困难是,对于您提到的组件(HTTP、FTP、文件、JMS),您可能希望使用生产者或消费者:

  • FTP、文件:绝对是读取文件的消费者。
  • HTTP(或HTTP4):肯定是生产者,向服务器发送请求(服务器的回复将由新的消息体)
  • JMS:取决于您是要从队列中读取数据(消费者),还是向带有ReplyTo 标头的队列发送消息,然后等待应答(生产者)。

制片人:

如果您使用的是 Camel 2.16+,则可以使用新的 "dynamic to" 语法。它与常规的“to”基本相同,除了端点 uri 可以使用 simple 表达式(或者,可选地,另一种类型的表达式)动态评估。或者,您可以使用 content-enricher patternenrich 风格,它还支持从 Camel 2.16 开始的动态 uri。

如果您使用的是旧版本的 Camel,或者如果您需要动态路由到多个端点(不仅仅是一个),您可以使用 recipient list 模式。

这是一个例子。我们将通过调用端点来转换消息体;该端点的 uri 将在名为 TargetUri 的标头中找到,并将针对每条消息进行动态评估。

// An instance of this class is registered as 'testbean' in the registry. Instead of
// sending to this bean, I could send to a FTP or HTTP endpoint, or whatever.
public class TestBean {
    public String toUpperCase(final String str) {
        return str.toUpperCase();
    }
}

// This route sends a message to our example route for testing purpose. Of course, we
// could send any message as long as the 'TargetUri' header contains a valid endpoint uri
from("file:inbox?move=done&moveFailed=failed")
.setHeader("TargetUri").constant("bean:testbean?method=toUpperCase")
.setBody().constant("foo")
.to("direct:test");

// 1. The toD example :
from("direct:test")
.toD("${header.TargetUri}") 
.to("log:myRoute");

// 2. The recipient list example :
from("direct:test")
.recipientList(header("TargetUri"))
.to("log:myRoute");

// 3. The enrich example :
from("direct:test")
.enrich().simple("${header.TargetUri}") // add an AggregationStrategy if necessary
.to("log:myRoute");

消费者:

使用 Camel 2.16+,您可以使用 content-enricher patternpollEnrich 风格。

对于旧版本的 Camel,您可以在处理器中使用 ConsumerTemplate

// 4. The pollEnrich example (assuming the TargetUri header contains, e.g., a file
// or ftp uri) :
from("direct:test")
.pollEnrich().simple("${header.TargetUri}") // add an AggregationStrategy if necessary
.to("log:myRoute");

// 5. The ConsumerTemplate example (same assumption as above)
from("direct:test")
.process(new Processor() {
    @Override
    public void process(Exchange exchange) throws Exception {
        String uri = exchange.getIn().getHeader("TargetUri", String.class);
        ConsumerTemplate consumer = exchange.getContext().createConsumerTemplate();
        final Object data = consumer.receiveBody(uri);
        exchange.getIn().setBody(data);
    }
})
.to("log:myRoute");

生产者还是消费者?

遗憾的是,我想不出任何真正优雅的解决方案来处理这两者 - 我认为您将不得不根据 uri 和已知组件路由到两个分支......这是我可能会做的事情(使用 Camel 2.16+),它不是很漂亮:

// This example only handles http and ftp endpoints properly
from("direct:test")
.choice()
    .when(header("TargetUri").startsWith("http"))
        .enrich().simple("${header.TargetUri}")
    .endChoice()
    .when(header("TargetUri").startsWith("ftp"))
        .pollEnrich().simple("${header.TargetUri}")
    .endChoice()
.end()
.to("log:myRoute");

【讨论】:

  • 回复:“...或者如果您需要动态路由到多个端点”。我的问题是:我必须从几个不同的端点进行路由(请记住:我进入一个 URI(作为字符串),并且我必须从该 URI 获取数据。所以该 URI 成为我的“来自(“URI ...” ))。
  • 我理解您的问题的方式是:您想从静态端点(vm:incomingUri)接收消息,然后路由到动态端点(取决于消息内容)以丰富/转换消息,然后最终将丰富/转换的消息发送到静态端点 (file:...)。这就是我试图在我的例子中说明的。这不是你想做的吗?你真的想设置新的路由来持续接收来自动态端点的新消息吗?
  • 多想一下:当你提到 HTTP 端点时,我的回答比你提到 FTP 或文件端点时更有意义......使用 HTTP(假设你正在发送 HTTP 请求)你将要使用生产者(与我使用 java bean 的示例相同);使用 FTP 或文件,您将需要使用消费者...所以我认为您需要调用一些与其他端点不同的端点(pollEnrich 用于 FTP 之类的东西;enrichtorecipientList 用于某些东西像 HTTP)。我会尝试将其添加到我的答案中。
  • "vm:incomingUri" 只开始整个事情:从 "vm:incomingUri" 我只得到我需要读取的文件的 URI(通过 FTP 或 JMS 或...)跨度>
【解决方案2】:

可以使用

<to uri="{{some.endpoint}}"/>

但您需要将其添加到属性中。

<cm:property name="some.endpoint" value="SomeEndPoint"/>

您可以添加任何您想要的端点 http、ftp、文件、日志、jms、vm 等。

SomeEndPoint 的值。

  1. 日志组件:log:mock

  2. JMS 组件:activemq:someQueueName

  3. 文件组件:file://someFileShare

  4. VMComponent:vm:toSomeRoute

【讨论】:

  • 这对我不起作用,因为配置是静态的(请参阅我在原始问题中的编辑)
猜你喜欢
  • 2011-04-08
  • 2014-09-19
  • 2012-09-04
  • 1970-01-01
  • 2013-06-04
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-26
相关资源
最近更新 更多