Search This Blog

Wednesday, 19 December 2012

SOAP Webservices using Spring -2

In the previous example we saw how to set up the application and add the WSDL and XSD files needed. We also configured a MessageDispatcherServlet to handle the operations exposed by our web-service.
The layout of my web folder is as below:
As can be seen the wsdl and the xsds are available inside the WEB-INF folder and therefore will not be directly accessible. Any direct attempts to reference them will result in a 404 error. This is where the SimpleWsdl11Definition bean comes into the picture:
<!-- Represents an abstraction for WSDL definitions.  -->
<bean id="SampleService"
    class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition">
    <!-- uses a SAX implementation to load this resource  -->
    <property name="wsdl" value="/WEB-INF/services/SampleService.wsdl">
    </property>
</bean>
The class internally treats the value of the wsdl property as a resource and loads the WSDL using a SAX parser. The start-up logs indicate the same:
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory  
- Creating shared instance of singleton bean 'SampleService'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory  
- Creating instance of bean 'SampleService'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory  
- Eagerly caching bean 'SampleService' to allow for resolving potential circular references
5500 [pool-2-thread-1] DEBUG org.springframework.beans.CachedIntrospectionResults  
- Getting BeanInfo for class 
[org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition]
DEBUG org.springframework.beans.CachedIntrospectionResults  
- Caching PropertyDescriptors for class 
[org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition]
5532 [pool-2-thread-1] DEBUG org.springframework.beans.CachedIntrospectionResults  
- Found bean property 'class' of type [java.lang.Class]
5532 [pool-2-thread-1] DEBUG org.springframework.beans.CachedIntrospectionResults  
- Found bean property 'source' of type [javax.xml.transform.Source]
5532 [pool-2-thread-1] DEBUG org.springframework.beans.CachedIntrospectionResults  
- Found bean property 'wsdl' of type [org.springframework.core.io.Resource]
5532 [pool-2-thread-1] DEBUG org.springframework.beans.TypeConverterDelegate  
- Converting String to [interface org.springframework.core.io.Resource] 
using property editor [org.springframework.core.io.ResourceEditor@169cccc]
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory  
- Invoking afterPropertiesSet() on bean with name 'SampleService'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory  
- Finished creating instance of bean 'SampleService'
...
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory  
- Returning cached instance of singleton bean 'SampleService'
DEBUG org.springframework.ws.transport.http.MessageDispatcherServlet  
- Published [SimpleWsdl11Definition ServletContext resource 
[/WEB-INF/services/SampleService.wsdl]] as SampleService.wsdl
As can be seen the wsdl file was published directly to the context. So to access the wsdl the URL would be <Application Context>/SampleService.wsdl
The wsdl file can be accessed using the id of the bean. On accessing the wsdl file:
DEBUG org.springframework.ws.transport.http.MessageDispatcherServlet  - 
Bound request context to thread: org.apache.catalina.connector.RequestFacade@38d0a8
DEBUG org.springframework.ws.transport.http.WsdlDefinitionHandlerAdapter  - 
Transforming [/Service/ws-operations] to 
[http://localhost:8080/sampleWS/Service/ws-operations]
During startup the MessageDispatcherServlet detects the wsdlDefinition and exposes the file as a wsdl.
A similar step needs to be adopted to ensure that our xsd files are also available to the client.
<bean id="RandomService" class="org.springframework.xml.xsd.SimpleXsdSchema">
    <property name="xsd" value="/WEB-INF/services/xsd/RandomService.xsd" />
</bean>
The bean is similar to our SimpleWsdl11Definition bean but works in the context of XSDs. It internally uses a javax.xml.parsers.DocumentBuilder class to create a DOM Document instance from an XML document. The xsd parameter serves to identify the actual xsd resource. The start up logs indicate that the bean was setup successfully.
Now that we have exposed our SimpleXsdSchema bean with the name RandomService, the same can also be loaded via the URL http://localhost:8080/sampleWS/RandomService.xsd
So on accessing the URL:
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory  
- Returning cached instance of singleton bean 'RandomService'
DEBUG org.springframework.ws.transport.http.MessageDispatcherServlet  
- Published [SimpleXsdSchema{http://ws.com/Service/xsd/random-schema}] as RandomService.xsd
I then started the server and tried to view the WSDL file in a browser. This resulted in below display of the page:

To debug the issue further, I decided to execute the wsimport command on my wsdl url. The wsimport command will generate the necessary java code(request and response objects) that serve as the message parameters for my operations.
 The problem is the server totally failed to understand what to do with the wsdl request. Or more specifically the server needed to to to be informed as to which servlet to redirect our *.wsdl requests.
So I updated the web.xml file:
<servlet-mapping> <!-- for the wsdl -->
    <servlet-name>spring-ws</servlet-name>
    <url-pattern>*.wsdl</url-pattern>
</servlet-mapping>

<servlet-mapping> <!-- For the xsd -->
    <servlet-name>spring-ws</servlet-name>
    <url-pattern>*.xsd</url-pattern>
</servlet-mapping>
Now on hitting the url again we can see that the page was loaded succesfully:
I also executed the wsimport command successfully creating a jar of the generated java classes and naming it ws-files.jar. This was added to the classpath. In the next post we shall use this jar to start the actual implementation of the server code for processing this web service.

No comments:

Post a Comment