user2957378
user2957378

Reputation: 637

Spring Tomcat Deployment: Soap call returns "405: Method not allowed"

I was running a webapp application which publishes REST and SOAP services. Both of them were working fine when I run my app by gradle run (spring-boot plugin) or as an Java Application from STS. SOAP Services work perfectly when called from SoapUI or from $.soap ajax invocation from index.html whenever the application is run from gradle run or STS. I've just tried to deploy my webapp on Tomcat 7. Webapp static content and REST services are working fine. The problem is that SOAP services do not work.

I'm getting the following error code, either from index.html $.soap calls or from SoapUI tests:

POST http://localhost:8080/soap/ 405 (Method Not Allowed)

This is my servlet-context.xml file:

<?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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
                        http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-4.1.xsd">

<!--    DispatcherServlet Context: defines this servlet's request-processing
    infrastructure

    Enables the Spring MVC @Controller programming model -->
    <mvc:annotation-driven />

<!--    Handles HTTP GET requests for /resources/** by efficiently serving up
    static resources in the ${webappRoot}/resources directory -->
    <mvc:resources mapping="/resources/**" location="/resources/" />

<!--    Resolves views selected for rendering by @Controllers to .jsp resources
    in the /WEB-INF/views directory -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <context:component-scan base-package="com.stw_2015.app" />
</beans>

And this the structure of my @Endpoint annotated class:

@Endpoint
public class SoapController {
    private static final String NAMESPACE_URI = "http://com.stw_2015.app/soap";
    private static final Logger logger = LoggerFactory.getLogger(SoapController.class);


    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "registerActionRequest")
    @ResponsePayload
    public RegisterActionResponse registerAction (
            @RequestPayload RegisterActionRequest registerActionRequest) {

        ................

    }
}

Possibly, the reason is that POST requests to SOAP service are being rejected by Spring. Is there any way to enable them? All my REST services are GET requests, but I do know that @RequestMapping annotated methods can be annotated as GET or POST requests listeners. However, for my Soap service, I just don't know.

Can someone help me out? Thank you!

PD: Please tell me if I should paste some other file contents.

Upvotes: 1

Views: 5548

Answers (1)

user2957378
user2957378

Reputation: 637

I managed to solve the problem. I was really missing the key point. All my Soap Services were using some MessageDispatcherServlet bean defined as this:

@EnableWs
@Configuration
public class SoapWebServicesConfig extends WsConfigurerAdapter {
    @Bean
    public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
        MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(applicationContext);
        servlet.setTransformWsdlLocations(true);
        return new ServletRegistrationBean(servlet, "/soap/*");
    }

    // http://localhost:8080/soap/soap_description.wsdl -> Accesible
    @Bean(name = "soap_description")
    public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema actionsSchema) {
        DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
        wsdl11Definition.setPortTypeName("SoapPort");
        wsdl11Definition.setLocationUri("/soap");
        wsdl11Definition.setTargetNamespace("http://com.stw_2015.app/soap");
        wsdl11Definition.setSchema(actionsSchema);
        return wsdl11Definition;
    }

    @Bean
    public XsdSchema actionsSchema() {
        return new SimpleXsdSchema(new ClassPathResource("soap_description.xsd"));
    }
}

As I said, these services were working fine if run from STS or gradle run. The problem is this servlet was not defined on my web.xml file. Now that file look like this:

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

    <!-- The definition of the Root Spring Container shared by all Servlets 
        and Filters -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/root-context.xml</param-value>
    </context-param>

    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Processes application requests -->

    <servlet>
        <servlet-name>spring-ws</servlet-name>
        <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring-ws</servlet-name>
        <url-pattern>/soap/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

Before that, the appServlet servlet (which is configured with servlet-context.xml I previously showed) was trying to handle "/soap/*" requests. Now, spring-ws servlet is handling those requests, while appServlet is handling the rest of them.

Finally, I had to create a file like this, called spring-ws-servlet.xml and located at "WEB-INF" folder:

<?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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
                        http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-4.1.xsd">

    <!-- DispatcherServlet Context: defines this servlet's request-processing 
        infrastructure Enables the Spring MVC @Controller programming model -->
    <mvc:annotation-driven />
    <context:component-scan base-package="com.stw_2015.app" />
</beans>

Upvotes: 1

Related Questions