Search code examples
soapapache-camelredhat

Apache Camel invoke SOAP service


I am new in Apache Camel and I use Red Hat CodeReady Studio 12.16.0.GA. I want invoke soap web service. I have used this example https://tomd.xyz/camel-consume-soap-service/

This is my camel context file

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:camel-cxf="http://camel.apache.org/schema/cxf"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd        http://camel.apache.org/schema/spring       https://camel.apache.org/schema/spring/camel-spring.xsd http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd">
    <bean class="org.apache.cxf.transport.common.gzip.GZIPInInterceptor" id="gZipInInterceptor"/>
    <bean
        class="org.apache.cxf.transport.common.gzip.GZIPOutInterceptor" id="gZipOutInterceptor"/>
    <camel-cxf:cxfEndpoint
        address="http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso"
        id="fullCountryInfoResponseClient" serviceClass="org.oorsprong.websamples_countryinfo.CountryInfoServiceSoapType">
        <camel-cxf:inInterceptors>
            <ref bean="gZipInInterceptor"/>
        </camel-cxf:inInterceptors>
        <camel-cxf:outInterceptors>
            <ref bean="gZipOutInterceptor"/>
        </camel-cxf:outInterceptors>
    </camel-cxf:cxfEndpoint>
    <bean
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" id="bean-66d2672d-c6c0-4984-bc31-90bc30bfaaef"/>
    <camelContext id="camel"
        xmlns="http://camel.apache.org/schema/spring" xmlns:order="http://fabric8.com/examples/order/v7">
        <route id="simple-route">
            <from id="_to2" uri="timer:timerName?delay=0&amp;repeatCount=1"/>
            <setBody id="_setBody2">
                <constant id="id">"US"</constant>
            </setBody>
            <bean beanType="GetFullCountryInfoBuilder.class" id="_bean1" method="getFullCountryInfo"/>
            <setHeader headerName="operationNamespace" id="_setHeader1">
                <constant>http://www.oorsprong.org/websamples.countryinfo</constant>
            </setHeader>
            <setHeader headerName="operationName" id="_setHeader2">
                <constant>FullCountryInfo</constant>
            </setHeader>
            <to id="_to1" uri="cxf:bean:fullCountryInfoResponseClient"/>
            <setBody id="_setBody1">
                <simple>${body}</simple>
            </setBody>
            <log id="_log1" message=">>>${body}"/>
        </route>
    </camelContext>
</beans>

this is my input bean

import org.oorsprong.websamples.FullCountryInfo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class GetFullCountryInfoBuilder {
    
    public GetFullCountryInfoBuilder() {}

    @Value("${id}")
    private java.lang.String id;
    @Bean
    public FullCountryInfo getFullCountryInfo(java.lang.String id) {
        FullCountryInfo request = new FullCountryInfo();
        request.setSCountryISOCode(id);

        return request;
    }
}

There is lot of problems around it. First I cannot pass input parameter into body. I tried to set body like this

      <web:FullCountryInfo xmlns:web="http://www.oorsprong.org/websamples.countryinfo">
         <web:sCountryISOCode>US</web:sCountryISOCode>
      </web:FullCountryInfo>

but got no response or just logged nothing. I have tried to use bean to create request but I get

InvocationTargetException: Error creating bean with name 'getFullCountryInfoBuilder': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'id' in value "${id}"

When I replace placeholder with constant

InvocationTargetException: Error creating bean with name 'getFullCountryInfo' defined in class path resource [com/example/GetFullCountryInfoBuilder.class]: Unsatisfied dependency expressed through method 'getFullCountryInfo' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

or when I remove input parameter from method getFullCountryInfo Camel cannot found GetFullCountryInfoBuilder class

InvocationTargetException: org.apache.camel.FailedToCreateRouteException: Failed to create route simple-route at: >>> Bean[GetFullCountryInfoBuilder.class] <<< in route: Route(simple-route)[[From[timer:timerName?delay=0&repeatCoun... because of java.lang.ClassNotFoundException: GetFullCountryInfoBuilder.class

Solution

  • The first two errors are in the field of passing a parameter to a bean method.

    Could not resolve placeholder 'id' in value "${id}" 
    

    The expression @Value("${id}") references a Spring property named id but it does not exist. Since you define a route step with this ID, I suspect that you want to pass the value "US" that you set as message body to the method.

    The Spring annotation @Value has no idea about your Camel route so this does not work.

    However you can use Camel annotations to tell Camel to inject the message body you set to "US" as argument id in your method.

    getFullCountryInfo(@Body String id) {
    

    You could also set the value into a message header with setHeader and use the annotation @Header to inject it into a method. Because when you have an input message (not a timer) you usually don't want to override the body.

    The other problem is that the bean cannot be resolved, even when you remove the parameter and set the body static.

    ClassNotFoundException: GetFullCountryInfoBuilder.class
    

    I guess this is because the beanType should be defined like this

    org.oorsprong.websamples.GetFullCountryInfoBuilder // i guessed the package name
    

    So it must be the full package/classname but without the ".class" suffix.