通过Spring XML使用CXF-RS客户端配置Camel Producer

时间:2014-03-23 21:11:33

标签: java spring cxf apache-camel

我今天下午一直在努力了解Camel&它的webservices组件。我试图为我能想到的最简单的情况设置最简单的Camel端点:我已经定义了一个每5秒触发一次的计时器。当它触发时,我想点击一个远程RESTful URL,检索一些JSON,并用它来初始化一个新的数据对象。

我的骆驼路线如下:

    <route>
        <from uri="timer:aTimer?fixedRate=true&amp;period=5s"/>
        <to uri="log:com.foocorp.demonstrations?level=WARN"/>
        <to uri="cxfrs://bean://bitcoinPriceSvc"/>
        <process ref="itemRetriever"/>
        <log message="{$body}"/>
    </route>

bitcoinPriceSvc在我的Spring配置中定义为:

    <cxf:rsClient id="bitcoinPriceSvc" address="http://api.coindesk.com/v1/bpi/currentprice.json"
              serviceClass="com.foocorp.demonstrations.ws.service.RemoteService"
              loggingFeatureEnabled="true" skipFaultLogging="true"
        />

ItemRetriever类如下:

public class ItemRetriever implements Processor
{
    private static final Log log = LogFactory.getLog(ItemRetriever.class);

    @Override
    public void process(Exchange exchange) throws Exception
    {
        exchange.setPattern(ExchangePattern.InOut);
        Message message = exchange.getIn();
        message.setHeader(Exchange.HTTP_METHOD, "GET");
        message.setHeader(Exchange.HTTP_PATH, "/currentprice.json");
        message.setHeader(CxfConstants.CAMEL_CXF_RS_RESPONSE_CLASS, BitcoinPrice.class);
        message.getBody();

        BitcoinPrice price = (BitcoinPrice)exchange.getOut().getBody();
        log.error("Got price: " + price);
    }
}

似乎ws调用实际上正在进行,但它是作为POST而不是GET进行的,因此它失败并出现405错误。

    2014-03-23 17:06:47,317 [Camel (camel-1) thread #0 - timer://aTimer] ERROR org.apache.camel.processor.DefaultErrorHandler - Failed delivery for (MessageId: ID-ibc-win-52811-1395608519935-0-115 on ExchangeId: ID-ibc-win-52811-1395608519935-0-116). Exhausted after delivery attempt: 1 caught: org.apache.camel.component.cxf.CxfOperationException: JAXRS operation failed invoking timer://aTimer?fixedRate=true&period=5s with statusCode: 405

Message History
---------------------------------------------------------------------------------------------------------------------------------------
RouteId              ProcessorId          Processor                                                                        Elapsed (ms)
[route1            ] [route1            ] [timer://aTimer?fixedRate=true&period=5s                                       ] [       235]
[route1            ] [to1               ] [log:com.foocorp.demonstrations?level=WARN                                ] [         0]
[route1            ] [to2               ] [cxfrs://bean://bitcoinPriceSvc                                                ] [       234]

Exchange
---------------------------------------------------------------------------------------------------------------------------------------
Exchange[
        Id                  ID-ibc-win-52811-1395608519935-0-116
        ExchangePattern     InOnly
        Headers             {breadcrumbId=ID-ibc-win-52811-1395608519935-0-115, CamelRedelivered=false, CamelRedeliveryCounter=0, firedTime=Sun Mar 23 17:06:47 EDT 2014}
        BodyType            null
        Body                [Body is null]
]

Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------
org.apache.camel.component.cxf.CxfOperationException: JAXRS operation failed invoking timer://aTimer?fixedRate=true&period=5s with statusCode: 405
        at org.apache.camel.component.cxf.jaxrs.CxfRsProducer.populateCxfRsProducerException(CxfRsProducer.java:317)
        at org.apache.camel.component.cxf.jaxrs.CxfRsProducer.invokeHttpClient(CxfRsProducer.java:177)
        at org.apache.camel.component.cxf.jaxrs.CxfRsProducer.process(CxfRsProducer.java:87)
        at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
        at org.apache.camel.processor.SendProcessor$2.doInAsyncProducer(SendProcessor.java:132)
        at org.apache.camel.impl.ProducerCache.doInAsyncProducer(ProducerCache.java:307)
        at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:127)
        at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:72)
        at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:398)
        at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
        at org.apache.camel.processor.Pipeline.process(Pipeline.java:118)
        at org.apache.camel.processor.Pipeline.process(Pipeline.java:80)
        at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
        at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:139)
        at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:64)
        at java.util.TimerThread.mainLoop(Timer.java:555)
        at java.util.TimerThread.run(Timer.java:505)

2014-03-23 17:12:12,082 [Camel (camel-1) thread #0 - timer://aTimer] WARN  com.foocorp.demonstrations - Exchange[ExchangePattern: InOnly, BodyType: null, Body: [Body is null]]
2014-03-23 17:12:12,086 [Camel (camel-1) thread #0 - timer://aTimer] INFO  org.apache.cxf.interceptor.LoggingOutInterceptor - Outbound Message
---------------------------
ID: 123
Address: http://api.coindesk.com/v1/bpi/currentprice.json
Http-Method: POST
Content-Type: */*
Headers: {firedTime=[Sun Mar 23 17:12:12 EDT 2014], breadcrumbId=[ID-ibc-win-52811-1395608519935-0-245], Content-Type=[*/*], Accept=[*/*]}

我错过了什么?谢谢!

1 个答案:

答案 0 :(得分:2)

事实证明你可以(并且确实需要)指定HttpMethod,尽管文档非常不透明。

    <route>
        <from uri="timer:aTimer?fixedRate=true&amp;period=60s"/>
        <setHeader headerName="CamelHttpMethod">
            <constant>GET</constant>
        </setHeader>
        <to uri="cxfrs://bean://bitcoinPriceSvc"/>
        <process ref="itemRetriever"/>
        <to uri="log:com.foocorps.demonstrations?level=INFO"/>
        <log message="{$body}"/>
    </route>

这里的关键是“魔术”setHeader调用。此外,当不得不在Camel的http调用上完成配置时,我不公平地指责CXF ......

更好的是:

    <route>
        <from uri="timer:aTimer?fixedRate=true&amp;period=60s"/>
        <setHeader headerName="CamelHttpMethod">
            <constant>GET</constant>
        </setHeader>
        <to uri="http4://foo.com/api/dosomething"/>
        <unmarshall ref="json"/>
        <to uri="bean:aDomainPojo"/>
        <to uri="log:com.foocorps.demonstrations?level=INFO"/>
        <log message="{$body}"/>
    </route>

    <dataFormats>
        <json id="json" library="Jackson"/>
    </dataFormats>

现在bean可以访问数据Map。