3

Camel Version: 2.12.2, CXF Version: 2.7, Apache Tomcat: 7

I have the following camel-cxf.xml :

    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:s0="http://www.huawei.com/bme/cbsinterface/cbs/businessmgr"
       xmlns:s1="http://www.huawei.com/bme/cbsinterface/cbs/accountmgr"
       xmlns:cxf="http://camel.apache.org/schema/cxf"
       xmlns:http-conf="http://cxf.apache.org/transports/http/configuration"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
        http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd">

    <bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
    <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />

    <cxf:cxfEndpoint id="oneEndpoint"
                     address="${endpoint.address}"
                     serviceName="s1:WebService"
                     serviceClass="WebserviceClass"
                     endpointName="s1:WebSericePort_http"
                     wsdlURL="classpath:wsdl/WebService.wsdl">
        <cxf:inInterceptors>
            <ref bean="loggingInInterceptor" />
            <ref bean="setSoapVersionInterceptor"/>
        </cxf:inInterceptors>
        <cxf:inFaultInterceptors>
            <ref bean="loggingInInterceptor" />
            <ref bean="setSoapVersionInterceptor"/>
        </cxf:inFaultInterceptors>
        <cxf:outInterceptors>
            <ref bean="loggingOutInterceptor" />
        </cxf:outInterceptors>
        <cxf:outFaultInterceptors>
            <ref bean="loggingOutInterceptor" />
        </cxf:outFaultInterceptors>
    </cxf:cxfEndpoint>

    <http-conf:conduit name="*.http-conduit">
        <http-conf:client
                Connection="Keep-Alive"
                ConnectionTimeout="60000"
                ReceiveTimeout="90000"/>
    </http-conf:conduit>

</beans>

In my camel-context I have two processors that use the cxf endpoint to invoke two different operations. To do that I use a producerTemplate which uses "cxf:bean:oneEndpoint" as a uri.

The project is a web application deployed in Tomcat 7.

The processors consume from two different queues. After deployment both queues are propagated with a message. The problem is that one of the processors will throw an exception upon invoking the send method on the producer template. The other will work fine. The exception is:

  org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: 
  cxf://bean:oneEndpoint due to: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'oneEndpoint': Initialization of bean failed; 
  nested exception is java.lang.IllegalStateException: Could not register object [org.apache.cxf.bus.spring.SpringBus@4b0af74c] under bean name 'cxf': 
  there is already object [org.apache.cxf.bus.spring.SpringBus@24c0fe59] bound

Full stacktrace can be found here: http://pastebin.com/cDsQZ9r3

The second time the queues receive a message at the same time, everything works fine.

Any ideas?

PS. My web.xml is:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:/META-INF/spring/*.xml</param-value>
    </context-param>

</web-app>

Routes & Processors:

<route id="route1" errorHandlerRef="eh1">
    <from uri="{{queue1}}" />

    <setHeader headerName="operationName"> 
         <constant>Operation_1</constant> 
    </setHeader>
    <process ref="FirstProcessor" />
    <choice>
        <when>
            <simple>${in.headers.STATUS} == 'OK'</simple>
            <inOnly uri="{{result_queue}}" />
        </when>
        <otherwise>
            <inOnly uri="{{nok_result_queue}}" />
        </otherwise>
    </choice>
</route>

<route id="route2" errorHandlerRef="eh2">
    <from uri="{{queue2}}" />

    <setHeader headerName="operationName"> 
         <constant>Operation_2</constant> 
    </setHeader>
    <process ref="SecondProcessor" />
    <choice>
        <when>
            <simple>${in.headers.STATUS} == 'OK'</simple>
            <inOnly uri="{{result_queue}}" />
        </when>
        <otherwise>
            <inOnly uri="{{nok_result_queue}}" />
        </otherwise>
    </choice>
</route>

<property name="producerTemplate" ref="firstProcessorTemplate" />
<property name="producerTemplateUri"
    value="cxf:bean:oneEndpoint?headerFilterStrategy=#headerFilterStrategy" />

<property name="producerTemplate" ref="secondProcessorTemplate" />
<property name="producerTemplateUri"
    value="cxf:bean:oneEndpoint?headerFilterStrategy=#headerFilterStrategy" />

5
  • If initially only one queue gets a message, does the program then work? It sounds like both queues are getting a message at the same time so both of them are trying to do some initialisation and your are running into a threading issue somewhere. Commented Aug 25, 2014 at 11:47
  • Yeah this could be possible. However even if I add two different cxf Endpoints which will have the exact same configuration except their ids I get the exact same error. So I am not sure how it is possible to fix this. Isn't there a way to register the endpoint upon deployment? Commented Aug 25, 2014 at 12:30
  • Adding two different cfx end points won't help because the problem is initialising the underlying SpringBus which is shared between them. Can you post the full stack trace with line numbers for the exception? A work around may be to explicitly define a SpringBus bean and add it to the context. Commented Aug 25, 2014 at 12:45
  • Here is the stacktrace pastebin.com/cDsQZ9r3 Commented Aug 25, 2014 at 13:02
  • The solution with the bus works. Add it as an answer so I can accept it. :) Commented Aug 25, 2014 at 13:35

2 Answers 2

3

The problem is that both queues are getting a message at the same time so both of them are trying to initialise the SpringBus at the same time.

The problem is that in BusWiringBeanFactoryPostProcessor it this code:

    if (!context.containsBean(name) && (create || Bus.DEFAULT_BUS_ID.equals(name))) {
        SpringBus b = new SpringBus();
        ConfigurableApplicationContext cctx = (ConfigurableApplicationContext)context;
        cctx.getBeanFactory().registerSingleton(name, b);
        b.setApplicationContext(context);
    }

So when two beans both try and initialise the SpringBus in two different threads, they can both enter the if statement at the same time leading to the exception.

The solution is to define a SpringBus in the application context so neither bean will try create a new SpringBus as one already exists.

Sign up to request clarification or add additional context in comments.

Comments

0

Please share the routes definition which consumes messages from two different queues. Also you can look for option of using multicasting to have parallel processing in consuming messages from both queues and proceed with further opertion.
<route>
<from uri="cxf:bean:oneEndpoint"></from>
<recipientList>
<simple>direct:${header.operationName}</simple>
<log message="Got ${header.operationName}" />
</recipientList>
</route>
Your routes (route1 and route) can be renamed as same as webservice operation name. Our code is also something similar to yours. We haven't faced problem with this approach.

2 Comments

I use two routes which consume from two different queues and use two different processors. So your solution does not seem to fit. Please see my edit with the routes & processors.
You can also try some thing like this <br> <route> <from uri="cxf:bean:adcRouterEndpoint" /> <filter> <simple>${body} != null</simple> <recipientList> <simple>direct:${header.operationName}</simple> <log message="Got ${header.operationName}" /> </recipientList> </filter> </route>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.