9

Really stumped on this one - trying to utilize Spring-ws's @Endpoint and @PayloadRoot to automagically stand up some WSDL endpoints, but I keep getting a 404 (deploying into Tomcat 7.0.54). I've scoured this thing looking for naming inconsistencies (seems to be the most common cause of problems), but am finding nothing!

pom.xml:

    <dependency>
        <groupId>org.springframework.ws</groupId>
        <artifactId>spring-ws-core</artifactId>
        <version>1.5.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.ws</groupId>
        <artifactId>spring-ws-core-tiger</artifactId>
        <version>1.5.2</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.9</version>
    </dependency>
    <dependency>
        <groupId>org.codehaus.castor</groupId>
        <artifactId>castor</artifactId>
        <version>1.2</version>
    </dependency>

Web.xml:

<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
    <servlet-name>weather</servlet-name>
    <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>weather</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

weather-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
                       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<bean id="weatherService" class="com.nick.example.weather.WeatherServiceImpl"/>

<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping"/>

<bean id="temperatureEndpoint" class="com.nick.example.weather.TemperatureMarshallingEndpoint">
    <property name="weatherService" ref="weatherService"/>
</bean>

<bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">
    <property name="marshaller" ref="marshaller"/>
    <property name="unmarshaller" ref="marshaller"/>
</bean>

<bean id="marshaller" class="org.springframework.oxm.castor.CastorMarshaller">
    <property name="mappingLocation" value="classpath:mapping.xml"/>
</bean>

<bean id="temperature" class="org.springframework.ws.wsdl.wsdl11.DynamicWsdl11Definition">
    <property name="builder">
        <bean class="org.springframework.ws.wsdl.wsdl11.builder.XsdBasedSoap11Wsdl4jDefinitionBuilder">
            <property name="schema" value="/WEB-INF/temperature.xsd"/>
            <property name="portTypeName" value="Weather"/>
            <property name="locationUri" value="http://localhost:8080/weather/services"/>
        </bean>
    </property>
</bean>
</beans>

temperature.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified"
       elementFormDefault="qualified"
       targetNamespace="http://nick.com/weather/schemas"
       xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:element name="GetTemperaturesRequest">
<xs:complexType>
  <xs:sequence>
    <xs:element type="xs:string" name="city"/>
    <xs:element type="xs:date" name="date" maxOccurs="5" minOccurs="1"/>
  </xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GetTemperaturesResponse">
<xs:complexType>
  <xs:sequence>
    <xs:element name="TemperatureInfo" maxOccurs="5" minOccurs="1">
      <xs:complexType>
        <xs:sequence>
          <xs:element type="xs:float" name="min"/>
          <xs:element type="xs:float" name="max"/>
          <xs:element type="xs:float" name="average"/>
        </xs:sequence>
        <xs:attribute type="xs:string" name="city" use="optional"/>
        <xs:attribute type="xs:date" name="date" use="optional"/>
      </xs:complexType>
    </xs:element>
  </xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

TemperatureMarshallingEndpoint.java:

package com.nick.example.weather;

import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;

import java.util.List;

@Endpoint
public class TemperatureMarshallingEndpoint {

private static final String namespaceUri = "http://nick.com/weather/schemas";

private WeatherService weatherService;

public void setWeatherService(WeatherService weatherService) {
    this.weatherService = weatherService;
}

@PayloadRoot(
        localPart = "GetTemperaturesRequest",
        namespace = namespaceUri)
protected GetTemperaturesResponse getTemperature(GetTemperaturesRequest request) {
    List<TemperatureInfo> temperatures = weatherService.getTemperatures(request.getCity(), request.getDates());
    return new GetTemperaturesResponse(temperatures);
}
}

I'm deploying to Tomcat right off the root ("/") - no errors, deploys fine. Below is the resulting wsdl, but one interesting note is that I can hit it with any URL starting with http://localhost:8080 and ending with "/temperature.wsdl". i.e. http://localhost:8080/weather/services/temperature.wsdl nets me the same wsdl as http://localhost:8080/blah/blah/blah/temperature.wsdl

WSDL:

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:schema="http://nick.com/weather/schemas" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="http://nick.com/weather/schemas">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://nick.com/weather/schemas">
<xs:element name="GetTemperaturesRequest">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="city" type="xs:string"/>
            <xs:element maxOccurs="5" minOccurs="1" name="date" type="xs:date"/>
        </xs:sequence>
     </xs:complexType>
</xs:element>
<xs:element name="GetTemperaturesResponse">
    <xs:complexType>
        <xs:sequence>
            <xs:element maxOccurs="5" minOccurs="1" name="TemperatureInfo">
                 <xs:complexType>
                     <xs:sequence>
                          <xs:element name="min" type="xs:float"/>
                          <xs:element name="max" type="xs:float"/>
                          <xs:element name="average" type="xs:float"/>
                     </xs:sequence>
                     <xs:attribute name="city" type="xs:string" use="optional"/>
                     <xs:attribute name="date" type="xs:date" use="optional"/>
                 </xs:complexType>
            </xs:element> 
        </xs:sequence>
    </xs:complexType>
</xs:element>
</xs:schema>
</wsdl:types>
<wsdl:message name="GetTemperaturesRequest">
    <wsdl:part element="schema:GetTemperaturesRequest" name="GetTemperaturesRequest"></wsdl:part>
</wsdl:message>
<wsdl:message name="GetTemperaturesResponse">
    <wsdl:part element="schema:GetTemperaturesResponse" name="GetTemperaturesResponse"></wsdl:part>
</wsdl:message>
<wsdl:portType name="Weather">
    <wsdl:operation name="GetTemperatures">
        <wsdl:input message="schema:GetTemperaturesRequest" name="GetTemperaturesRequest"></wsdl:input>
        <wsdl:output message="schema:GetTemperaturesResponse" name="GetTemperaturesResponse"></wsdl:output>
    </wsdl:operation>
</wsdl:portType>
<wsdl:binding name="WeatherBinding" type="schema:Weather">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="GetTemperatures">
        <soap:operation soapAction=""/>
        <wsdl:input name="GetTemperaturesRequest">
            <soap:body use="literal"/>
        </wsdl:input>
        <wsdl:output name="GetTemperaturesResponse">
            <soap:body use="literal"/>
        </wsdl:output>
    </wsdl:operation>
</wsdl:binding>
<wsdl:service name="WeatherService">
    <wsdl:port binding="schema:WeatherBinding" name="WeatherPort">
        <soap:address location="http://localhost:8080/weather/services"/>
    </wsdl:port>
</wsdl:service>
</wsdl:definitions>

I am trying to setup a SoapUI test against these by pointing SoapUI to: http://localhost:8080/weather/services/temperature.wsdl

Which generates a correct-looking (I think) SOAP request:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://nick.com/weather/schemas">
<soapenv:Header/>
<soapenv:Body>
   <sch:GetTemperaturesRequest>
      <sch:city>Chicago</sch:city>
      <!--1 to 5 repetitions:-->
      <sch:date>2014-06-24</sch:date>
   </sch:GetTemperaturesRequest>
</soapenv:Body>
</soapenv:Envelope>

But sending the request through gives me a 404 response:

HTTP/1.1 404 Not Found

Any insights on what I might be doing wrong? THANKS!

Nick
  • 449
  • 1
  • 6
  • 17
  • Thank you for detailing out your layout like you did!! You may have been stuck at the time but tying the pieces together like you did made my job learning this SO much easier! I would upvote you more than once if I could! – Lorin S. May 01 '15 at 02:54

1 Answers1

5

Wow, unbelievable - of all things, it was the access modifier on my "getTemperature()" method in TemperatureMarshallingEndpoint. It was "protected", but needed to be "public" (works like a charm after making the change!)

Nick
  • 449
  • 1
  • 6
  • 17