使用CXFRS端点和xPath在Camel中使用基于内容的路由时遇到问题

时间:2013-02-08 02:11:11

标签: xpath apache-camel cxfrs

我正在尝试使用xPath创建一个由REST有效内容中的内容确定的路由。我已成功使用基于邮件头的路由:

<when>
   <simple>${headers.operationName} == 'createContainerOutput'</simple>
   <bean ref="containerOutputProcessor"/>
</when>

正确调用containerOutputProcessor ...

但对于此xPath路由:

<when>
    <xpath>/*[local-name()='order-request']/@type='TrayOutput'</xpath>
    <bean ref="containerOutputProcessor"/>
</when>

我得到了例外:

org.apache.camel.NoTypeConversionAvailableException:没有类型转换器可用于将类型:org.apache.cxf.message.MessageContentsList转换为所需类型:org.w3c.dom.Document,其值为[com.mmi.ws. ContainerOutputOrderRequest @ 6290dc]

此有效负载

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<order-request type="TrayOutput">
    <parameter name="orderName">Example Tray Output Order</parameter>
    <parameter name="enableScan">true</parameter>
    <parameter name="autoStart">false</parameter>
    <parameter name="priority">3</parameter>
    <item barcode="23990001"/>
    <item barcode="23990002"/>
</order-request>

这种路由是个好主意吗?是否有更好的方法根据提交的订单请求类型进行路由?

感谢您对我的任何帮助/指导!


这是完整的背景

<?xml version='1.0' encoding='UTF-8'?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:jaxrs="http://cxf.apache.org/jaxrs"
    xmlns:cxf="http://camel.apache.org/schema/cxf"
    xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
     http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
     http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
     http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
     http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd">

  <!-- enable Spring @Component scan -->
  <context:component-scan base-package="com.mmi.ws"/>

    <!--  web service beans -->
  <bean id="containerOutputWS" class="com.mmi.ws.service.impl.ContainerOutputWSImpl" />
  <bean id="containerTypesWS" class="com.mmi.ws.service.impl.ContainerTypesWSImpl" />


  <!-- processor beans -->
  <bean id="containerOutputProcessor" class="com.mmi.ws.service.ContainerOutputProcessor" />
  <bean id="containerTypesProcessor" class="com.mmi.ws.service.ContainerTypesProcessor" />
  <bean id="unsupportedPathProcessor" class="com.mmi.ws.service.UnsupportedPathProcessor" />


  <!-- Define the real JAXRS back end service  -->
  <jaxrs:server id="restService"
                address="http://localhost:9998/sc" 
                staticSubresourceResolution="true">
    <jaxrs:serviceBeans>
      <ref bean="containerOutputWS"/>
      <ref bean="containerTypesWS"/>
    </jaxrs:serviceBeans>       
  </jaxrs:server>

  <!--  define the restful server and client endpoints -->
  <cxf:rsServer id="rsServer" address="http://localhost:9999/sc" loggingFeatureEnabled="true" loggingSizeLimit="20">
    <cxf:serviceBeans >
      <ref bean="containerOutputWS"/>
      <ref bean="containerTypesWS"/>
    </cxf:serviceBeans>
  </cxf:rsServer>

  <cxf:rsServer id="rsClient" address="http://localhost:9998/sc" loggingFeatureEnabled="true" loggingSizeLimit="20">
    <cxf:serviceBeans >
      <ref bean="containerOutputWS"/>
      <ref bean="containerTypesWS"/>
    </cxf:serviceBeans>
  </cxf:rsServer>


  <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
    <!-- 
       any classes in the below 'packageScan'packages that extends RouteBuilder
       will be added as a camel route.  At least one route is required to start the cxf web service
    -->
    <packageScan>
        <package>com.mmi.ws</package>
    </packageScan>

    <dataFormats>
     <xstream id="xstream-utf8" encoding="UTF-8"/>
     <xstream id="xstream-default"/>
    </dataFormats>

    <!-- route starts from the cxf webservice  -->
    <route streamCache="true">
       <from uri="cxfrs://bean://rsServer"/>
        <log message="XML payload to send to REST WS:${body}" />        
        <setHeader headerName="CamelCxfRsUsingHttpAPI"><constant>True</constant> </setHeader>
        <choice>
            <when>
                <simple>${headers.operationName} == 'getContainers'</simple>
                <bean ref="containerTypesProcessor"/>
            </when>
            <when>
                <xpath>/*[local-name()='order-request']/@type='TrayOutput'</xpath>
                <bean ref="containerOutputProcessor"/>
            </when>
            <otherwise>
                <bean ref="unsupportedPathProcessor"/>
                <to uri="cxfrs://bean://rsClient"/>
            </otherwise>
        </choice>
    </route>    
  </camelContext>
</beans>

和Web服务类:

@Path("/container/output/")
public class ContainerOutputWSImpl 
{
    @POST
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public ContainerOutputView createContainerOutput(ContainerOutputOrderRequest containerOutput) {
        // TODO Auto-generated method stub
        return new ContainerOutputView();
    }
}

最后,xml有效负载和错误堆栈:

Address: http://localhost:9999/sc/container/output/
Encoding: ISO-8859-1
Http-Method: POST
Content-Type: application/xml
Headers: {accept-encoding=[gzip,deflate], connection=[keep-alive], Content-Length=[384], content-type=[application/xml], Host=[localhost:9999], User-Agent=[Apache-HttpClient/4.1.1 (java 1.5)]}
Payload: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<order-request type="TrayOutput">
    <parameter name="orderName">Example Tray Output Order</parameter>
    <parameter name="enableScan">true</parameter>
    <parameter name="autoStart">false</parameter>
    <parameter name="priority">3</parameter>
    <item barcode="23990001"/>
    <item barcode="23990002"/>
</order-request>

--------------------------------------
[ERROR] 2013-02-07  17:53:37.059  [qtp27633254-28: DefaultErrorHandler] Failed delivery for (MessageId: ID-PWY-EHANSEN-3070-1360288389778-0-2 on ExchangeId: ID-PWY-EHANSEN-3070-1360288389778-0-1). Exhausted after delivery attempt: 1 caught: org.apache.camel.RuntimeCamelException: org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: org.apache.cxf.message.MessageContentsList to the required type: org.w3c.dom.Document with value [com.mmi.ws.ContainerOutputOrderRequest@9fbbe5]
org.apache.camel.RuntimeCamelException: org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: org.apache.cxf.message.MessageContentsList to the required type: org.w3c.dom.Document with value [com.mmi.ws.ContainerOutputOrderRequest@9fbbe5]
    at org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException(ObjectHelper.java:1271)
    at org.apache.camel.builder.xml.XPathBuilder.getDocument(XPathBuilder.java:1027)
    at org.apache.camel.builder.xml.XPathBuilder.doInEvaluateAs(XPathBuilder.java:850)
    at org.apache.camel.builder.xml.XPathBuilder.evaluateAs(XPathBuilder.java:757)
    at org.apache.camel.builder.xml.XPathBuilder.matches(XPathBuilder.java:145)
    at org.apache.camel.processor.ChoiceProcessor.process(ChoiceProcessor.java:66)
    at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:73)
    at org.apache.camel.processor.DelegateAsyncProcessor.processNext(DelegateAsyncProcessor.java:99)
    at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:90)
    at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:73)
    at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:73)
    at org.apache.camel.processor.DelegateAsyncProcessor.processNext(DelegateAsyncProcessor.java:99)
    at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:90)
    at org.apache.camel.processor.interceptor.TraceInterceptor.process(TraceInterceptor.java:91)
    at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:73)
    at org.apache.camel.processor.RedeliveryErrorHandler.processErrorHandler(RedeliveryErrorHandler.java:334)
    at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:220)
    at org.apache.camel.processor.interceptor.StreamCachingInterceptor.process(StreamCachingInterceptor.java:52)
    at org.apache.camel.processor.RouteContextProcessor.processNext(RouteContextProcessor.java:45)
    at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:90)
    at org.apache.camel.processor.interceptor.DefaultChannel.process(DefaultChannel.java:303)
    at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:73)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:117)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:80)
    at org.apache.camel.processor.RouteContextProcessor.processNext(RouteContextProcessor.java:45)
    at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:90)
    at org.apache.camel.processor.UnitOfWorkProcessor.processAsync(UnitOfWorkProcessor.java:150)
    at org.apache.camel.processor.UnitOfWorkProcessor.process(UnitOfWorkProcessor.java:117)
    at org.apache.camel.processor.RouteInflightRepositoryProcessor.processNext(RouteInflightRepositoryProcessor.java:48)
    at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:90)
    at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:73)
    at org.apache.camel.processor.DelegateAsyncProcessor.processNext(DelegateAsyncProcessor.java:99)
    at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:90)
    at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:73)
    at org.apache.camel.component.cxf.jaxrs.CxfRsInvoker.asyncInvoke(CxfRsInvoker.java:87)
    at org.apache.camel.component.cxf.jaxrs.CxfRsInvoker.performInvocation(CxfRsInvoker.java:57)
    at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96)
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:201)
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:102)
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:58)
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:94)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
    at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
    at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.serviceRequest(JettyHTTPDestination.java:355)
    at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.doService(JettyHTTPDestination.java:319)
    at org.apache.cxf.transport.http_jetty.JettyHTTPHandler.handle(JettyHTTPHandler.java:72)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1074)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1010)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:255)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
    at org.eclipse.jetty.server.Server.handle(Server.java:365)
    at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485)
    at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:937)
    at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:998)
    at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:856)
    at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:240)
    at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:627)
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:51)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
    at java.lang.Thread.run(Thread.java:722)

1 个答案:

答案 0 :(得分:5)

在基于内容的路由器之前,您可以转换消息以从内部CXF列表中取出有效内容。使用简单语言从列表中获取第一个索引有一个技巧:

<transform>
   <simple>${body[0]}</simple>
</transform>
<choice>
   ...

你是否在类路径上有camel-jaxb。如果是这样,它可以在没有这个技巧的情况下开箱即用。但不确定,因为CXF有点特别。还取决于您使用的Camel / CXF版本。当你提问时,你应该提到这一点!