简体   繁体   中英

'No adapter for endpoint' exception - apache-camel with spring-boot & spring-ws

JVM 1.8.0_45
apache-camel 2.15.2
spring-ws 2.2.1
spring-boot 1.2.4

I am trying to use apache-camel (2.15.2) within a spring-boot application to handle incoming web service calls.

I created an initial working spring boot project (no camel) following the guidelines here http://spring.io/guides/gs/producing-web-service/

I then attempted to integrate the Camel: Spring Web Services component as a Consumer to handle incoming web service requests following guidelines in the 'Exposing Web Services' section here http://camel.apache.org/spring-web-services.html

WebServiceConfig.java

import org.apache.camel.component.spring.ws.bean.CamelEndpointMapping;

@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {

    @Bean
    public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
        MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(applicationContext);
        servlet.setTransformWsdlLocations(true);
        return new ServletRegistrationBean(servlet, "/ws/*");
    }

    // default wsdl stuff here...

    // exposing the endpoint mapping bean here rather than in spring-ws-servlet.xml (seems to work)
    @Bean  public CamelEndpointMapping  endpointMapping() {
        return new CamelEndpointMapping();
    }
}

ClaimRouter.java

import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.dataformat.JaxbDataFormat;
import org.springframework.stereotype.Component;

@Component
public class ClaimRouter extends RouteBuilder {

    @Override
    public void configure() throws Exception {

        JaxbDataFormat jaxb = new JaxbDataFormat(false);
        jaxb.setContextPath("uk.co.example.claim.ws.v2"); 

        // comment @PayloadRoot annotation in ClaimEndpointV2.java to enable requests to be mapped to this camel route
        from("spring-ws:rootqname:{http://example.co.uk/claim/ws/v2}getClaimRequest?endpointMapping=#endpointMapping")
        .to("log:uk.co.example.claim.ws.v2?level=INFO")
        .unmarshal(jaxb)
        .process(new ClaimProcessor())
        .marshal(jaxb);
    }
}

According to the log (below) incoming requests are successfully mapped to my Camel Consumer, but then it fails with 'No adapter for endpoint'

[2015-06-24 13:22:03.981] boot - 6892 DEBUG [http-nio-8090-exec-6] --- WsdlDefinitionHandlerAdapter: Transforming [/ws] to [http://localhost:8090/ws]
[2015-06-24 13:22:03.983] boot - 6892 DEBUG [http-nio-8090-exec-6] --- MessageDispatcherServlet: Successfully completed request
[2015-06-24 13:22:13.544] boot - 6892 DEBUG [http-nio-8090-exec-7] --- WebServiceMessageReceiverHandlerAdapter: Accepting incoming [org.springframework.ws.transport.http.HttpServletConnection@70863933] at [http://localhost:8090/ws]
[2015-06-24 13:22:13.547] boot - 6892 DEBUG [http-nio-8090-exec-7] --- received: Received request [SaajSoapMessage {http://example.co.uk/claim/ws/v2}getClaimRequest]
[2015-06-24 13:22:13.547] boot - 6892 DEBUG [http-nio-8090-exec-7] --- PayloadRootAnnotationMethodEndpointMapping: Looking up endpoint for [{http://example.co.uk/claim/ws/v2}getClaimRequest]
[2015-06-24 13:22:13.547] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapMessageDispatcher: Endpoint mapping [org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping@5fdbde50] has no mapping for request
[2015-06-24 13:22:13.547] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapActionAnnotationMethodEndpointMapping: Looking up endpoint for []
[2015-06-24 13:22:13.547] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapMessageDispatcher: Endpoint mapping [org.springframework.ws.soap.server.endpoint.mapping.SoapActionAnnotationMethodEndpointMapping@50bf4dcb] has no mapping for request
[2015-06-24 13:22:13.547] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapMessageDispatcher: Endpoint mapping [org.springframework.ws.soap.addressing.server.AnnotationActionEndpointMapping@8b5028a] has no mapping for request
[2015-06-24 13:22:13.548] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapMessageDispatcher: Endpoint mapping [org.apache.camel.component.spring.ws.bean.CamelEndpointMapping@7a9ff5b1] maps request to endpoint [Consumer[spring-ws://rootqname:(http://example.co.uk/claim/ws/v2)getClaimRequest?endpointMapping=%23endpointMapping]]
[2015-06-24 13:22:13.548] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapMessageDispatcher: Testing endpoint adapter [org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter@5a1e093a]
[2015-06-24 13:22:13.549] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapFaultAnnotationExceptionResolver: Resolving exception from endpoint [Consumer[spring-ws://rootqname:(http://example.co.uk/claim/ws/v2)getClaimRequest?endpointMapping=%23endpointMapping]]: java.lang.IllegalStateException: No adapter for endpoint [Consumer[spring-ws://rootqname:(http://example.co.uk/claim/ws/v2)getClaimRequest?endpointMapping=%23endpointMapping]]: Is your endpoint annotated with @Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?
[2015-06-24 13:22:13.549] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SimpleSoapExceptionResolver: Resolving exception from endpoint [Consumer[spring-ws://rootqname:(http://example.co.uk/claim/ws/v2)getClaimRequest?endpointMapping=%23endpointMapping]]: java.lang.IllegalStateException: No adapter for endpoint [Consumer[spring-ws://rootqname:(http://example.co.uk/claim/ws/v2)getClaimRequest?endpointMapping=%23endpointMapping]]: Is your endpoint annotated with @Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?
[2015-06-24 13:22:13.549] boot - 6892 DEBUG [http-nio-8090-exec-7] --- SoapMessageDispatcher: Endpoint invocation resulted in exception - responding with Fault
java.lang.IllegalStateException: No adapter for endpoint [Consumer[spring-ws://rootqname:(http://example.co.uk/claim/ws/v2)getClaimRequest?endpointMapping=%23endpointMapping]]: Is your endpoint annotated with @Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?
        at org.springframework.ws.server.MessageDispatcher.getEndpointAdapter(MessageDispatcher.java:302)
        at org.springframework.ws.server.MessageDispatcher.dispatch(MessageDispatcher.java:235)
        at org.springframework.ws.server.MessageDispatcher.reessageDispatcher.java:176)
        at org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:89)
        at org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:61)
        at org.springframework.ws.transport.http.MessageDispatcherServlet.doService(MessageDispatcherServlet.java:293)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catali.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)
[2015-06-24 13:22:13.554] boot - 6892 DEBUG [http-nio-8090-exec-7] --- sent: Sent response [SaajSoapMessage {http://schemas.xmlsoap.org/soap/envelope/}Fault] for request [SaajSoapMessage {http://example.co.uk/claim/ws/v2}getClaimRequest]
[2015-06-24 13:22:13.556] boot - 6892 DEBUG [http-nio-8090-exec-7] --- MessageDispatcherServlet: Successfully completed request

My gradle dependencies are as follows:

dependencies {
    compile("org.springframework.boot:spring-boot-starter-ws") {
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
    }
    compile("org.springframework.boot:spring-boot-starter") {
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
    }
    compile("org.springframework.boot:spring-boot-starter-log4j")
    compile("org.springframework:spring-web")
    compile("com.fasterxml.jackson.core:jackson-databind")
    compile("org.apache.camel:camel-core:2.15.2")
    compile("org.apache.camel:camel-spring-boot:2.15.2")
    compile("org.apache.camel:camel-spring-ws:2.15.2")
    compile("org.apache.camel:camel-jaxb:2.15.2")
    testCompile("org.springframework.boot:spring-boot-starter-test")
    compile 'org.slf4j:slf4j-log4j12:1.7.12'
    compile("wsdl4j:wsdl4j:1.6.1")
    jaxb("com.sun.xml.bind:jaxb-xjc:2.2.4-1")
    compile sourceSets.generated.output
}

I've researched a large number of No adapter for endpoint problems and most of them seem to be caused by the return type of the endpoint. However, I'm just creating a camel route, so presumably the camel-spring-ws integration should be providing the actual endpoint.

Am I missing a key piece of configuration/annotation or is there a more fundamental problem (some version incompatibility, perhaps)? Any help or insights much appreciated.

When spring boot is used, it registers just DefaultMethodEndpointAdapter that configures annotation driven Spring WS programming model. This makes it possible to use the various annotations like @Endpoint , @Payload auto detected.

As in our case, spring-ws endpoint has to hand over ws requests to camel endpoint, DefaultMethodEndpointAdapter won't do that job for us.

Below is the part of the code in the spring framework that does the end point adapters registration,

private void initEndpointAdapters(ApplicationContext applicationContext) throws BeansException {

    if (endpointAdapters == null) {
        Map<String, EndpointAdapter> matchingBeans = BeanFactoryUtils
                .beansOfTypeIncludingAncestors(applicationContext, EndpointAdapter.class, true, false);


        if (!matchingBeans.isEmpty()) {
            endpointAdapters = new ArrayList<EndpointAdapter>(matchingBeans.values());
            Collections.sort(endpointAdapters, new OrderComparator());          
        }

        else {
            endpointAdapters =
                    defaultStrategiesHelper.getDefaultStrategies(EndpointAdapter.class, applicationContext);
            if (logger.isDebugEnabled()) {
                logger.debug("No EndpointAdapters found, using defaults");
            }
        }
    }
} 

When we use spring-boot, DefaultMethodEndpointAdapter gets registered and hence the first 'if block' runs and hence it doesn't register other adapters like MessageEndpointAdapter , PayloadEndpointAdapter etc.

What we need in this case is, other than DefaultMethodEndpointAdapter , have to register MessageEndpointAdapter as well to offload spring-ws to camel endpoints.

So in WebServiceConfig class, add the below code,

@Bean
    public EndpointAdapter messageEndpointAdapter() {
        return new MessageEndpointAdapter();
    }

then the handover magic happens.

MessageEndpointAdapter is required for spring-ws and camel handover.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM