开发者

spring-ws: getting an EchoEndpoint to work, not return 404

The short version: My Spring-WS SOAP EchoEndpoint responds 404 whenever I try to access it. Please help, I've spent two days trying to get it to work correctly. :-I

Longer version: I've got a Spring project where I need to make SOAP services that act, look and feel as SOAP services from the system that will be deprecated. Therefore I'm not going to be using marshalling, but rather analyse the envelope contents via XPath and make the response in a way that looks like the old system.

But leading up to that I'm having problems. I have wired spring-ws up through DispatcherServlet instead of MessageDispatcherServlet because it lives in the same space as the rest of my WEB applications REST services. Here are my related beans:

<context:component-scan base-package="com.saers.niklas.view"/>

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="" p:suffix=".jsp"/>

<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
 <property name="encoding" value="UTF-8"/>
 <property name="contentType" value="application/json"/>
 <property name="hijackSafe" value="true"/>
 <property name="hijackSafePrefixPostFix"><value>(while(1);)</value></property>
</bean>

<aop:aspectj-autoproxy />

<sws:annotation-driven />

<context:component-scan base-package="com.saers.niklas.ws"/>

<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
 <property name="interceptors">
  <bean class="com.saers.niklas.view.web.interceptors.AddObjectIDsToResponseInterceptor"/>
 </property>
</bean>

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
 <property name="defaultHandler" ref="messageDispatcher"/>
</bean>

<bean id="messageDispatcher" class="org.springframework.ws.soap.server.SoapMessageDispatcher"/>

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

<bean class="org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter">
 <property name="messageFactory">
  <bean class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory" />
 </property>
</bean>

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

My endpoint looks like this

package com.saers.niklas.ws;

import javax.xml.transform.Source;
import org.w3c.dom.*;
import org.springframework.ws.server.endpoint.annotation.*;
import org.springframework.xml.transform.StringSource;

@Endpoint
public class EchoEndpoint {

    public EchoEndpoint() {
        System.err.println("XXNJSXX: EchoEndPoint");
    }

    @PayloadRoot(localPart="echoRequest", namespace="http://niklas.saers.com/DemoService")
    public Source echo(@RequestPayload Element requestElement) {
        return new StringSource("<x/>");
    }

}

and my test looks like this:

package com.saers.niklas.ws;

import javax.xml.transform.*;
import junit.framework.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.xml.transform.*;

public class WSTest {

    private static WebServiceTemplate template;

    @BeforeClass
    public static void setUp() {
        template = new WebServiceTemplate();
        template.setDefaultUri("http://localhost:8080/MyApp/ws/");
    }

    @Test
    public void testEchoEndpoint() {
        String xml = "<echoRequest xmlns=\"http://niklas.saers.com/DemoService\">Hello world</echoRequest>";
        Source source = new StringSource(xml);
        Result result = new StringResult();
        try {
            template.sendSourceAndReceiveToResult(source, result);
            System.out.println(result);
        } catch (Exception ex) {
            ex.printStackTrace(System.err);
            Assert.fail();
        }
    }
}

The test fails with

org.springframework.ws.client.WebServiceTransportException: Not Found [404]
 at org.springframework.ws.client.core.WebServiceTemplate.handleError(WebServiceTemplate.java:622)
 at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:546)
 at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:496)
 at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:451)
 at org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:395)
 at org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:386)
 at org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:376)
 at com.saers.niklas.ws.WSTest.testKommuneEndpoint(WSTest.java:65)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
 at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
 at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
 at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
 at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
 at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
 at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
 at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
 at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
 at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
 at org.j开发者_StackOverflowunit.runners.ParentRunner.access$000(ParentRunner.java:42)
 at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
 at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
 at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
 at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
 at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

even though I get "XXNJSXX: EchoEndPoint" in the output when I start the application, so I know that it is initialized, probably just not hooked up correctly. Whenever I run my test I also see a line like:

2011-06-16 09:57:10 SaajSoapMessageFactory [INFO] Creating SAAJ 1.3 MessageFactory with SOAP 1.1 Protocol

I've also run WireShark to confirm that the request is going through exactly the way I expect it, and I really get a 404 back. Here is the request:

POST /MyApp/ws/ HTTP/1.1
Accept-Encoding: gzip
Accept: text/xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
SOAPAction: ""
Content-Type: text/xml; charset=utf-8
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Java/1.6.0_26
Host: localhost:8080
Connection: keep-alive
Content-Length: 229

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><echoRequest xmlns="http://niklas.saers.com/DemoService">Hello world</echoRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>

What am I missing?

EDIT1: I was asked if I had the same problem with MessageDispatcherServlet, so I've set one up and yes, it seems I do. Here is the addition to web.xml:

<servlet>
    <servlet-name>MDS</servlet-name>
    <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
        classpath:ws-servlet.xml
    </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>MDS</servlet-name>
    <url-pattern>/soap2/*</url-pattern>
</servlet-mapping>

All that's in ws-servlet.xml is:

<context:annotation-config />
<context:component-scan base-package="com.saers.niklas.ws"/>
<sws:annotation-driven />

I get the same 404 when calling the EchoRequest:

POST /MyApp/soap2/ HTTP/1.1
Accept-Encoding: gzip
Accept: text/xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
SOAPAction: ""
Content-Type: text/xml; charset=utf-8
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Java/1.6.0_26
Host: localhost:8080
Connection: keep-alive
Content-Length: 229

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><echoRequest xmlns="http://niklas.saers.com/DemoService">Hello world</echoRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>

But this time I'm not sure if that's because my web.xml has configured with DispatcherServlet to / further down in the file:

<servlet-mapping>
  <servlet-name>MyApp</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

Cheers

Nik


Can you try using a normal MessageDispatcherServlet instead (as recommended here http://forum.springsource.org/showthread.php?39673-Spring-WS-in-a-normal-spring-dispatcher-servlet though that's an old thread)? That's worked for me when I need both HTML and WS responses from the same webapp. It's simple to share beans between the two dispatchers if you pull out the common beans into a separate XML config file. Plus you appear to be using classpath scanning which makes it even easier. You can follow the instructions here http://springtips.blogspot.com/2007/06/using-shared-parent-application-context.html to share the singelton instances as well as the configuration of your beans.

PS There's no need for

} catch (Exception ex) {
            ex.printStackTrace(System.err);
            Assert.fail();
        }

in test code, just make the test method throw Exception. You'll still know the test needs fixing, and in Eclipse/Junit you'll get a nicer stack trace.


In my case, the solution was to pay attention to the case in the URI. I had it in all lower case, but the webservice was expecting a CamelCase action name.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜