Finally I found some time to start experimenting with a webservice. I know I am not the first to write about creating your own webservice, still I think this is worth reading. I am writing a step by step creation of a webservice via maven2, axis 1.4 and spring 2.0RC1. Ofcourse you can use older versions, but I want to be ready for the future and keep on using this sample. For now I am working with a HelloWorld sample. I will make it more complicated when needed to show interesting things.

Download the sources here

Step 1 – Configuring your maven project environment
We create a new directory to store all projects : ~/WebservicePoc
Within this directory use the archetype of maven to create a structure for a web project:
The groupid is used within the create pom. The artifactId is used as project id and to create the folder to store all files in. The archetypeArtifactId defines the type of structure to create, in our case a web project.

mvn archetype:create 
          -DgroupId=com.coenradie.webservicespoc 
          -DartifactId=webservice-jaxrpc-style 
          -DarchetypeArtifactId=maven-archetype-webapp

Now it is time to create the pom in the root project directory. Beware if you create this pom first, the archetype:create won’t work. Execute the command in a temporary directory and copy the files into the sub-directory of the module we are creating.

...
	<groupId>com.coenradie.webservicespoc</groupId>
	<version>1.0-SNAPSHOT</version>
	<artifactId>WebservicePoc</artifactId>
	<packaging>pom</packaging>
	<name>Webservice proof of concept</name>
	<inceptionYear>2006</inceptionYear>
	<url>http://localhost:8080/webservicepoc</url>
...
	<modules>
		<module>webservice-jaxrpc-style</module>
	</modules>
...

For a complete look at the pom, have a look at the downloadable source code.

We also need to make some adjustments to the generated pom of the webservice-jaxrpc-style module. Again have a look at the sources. Time to try the first compile. Execute the following command in the root of the project:

~/WebservicePoc/mvn install

Step 2 – Decide upon the libraries that we are going to use
For the application we are going to create we are going to use some libraries. We do not want to code ourselves to much. We are going to use the spring library and axis. Add these to the module pom.

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring</artifactId>
      <version>2.0-RC1</version>
    </dependency>
    <dependency>
      <groupId>axis</groupId>
      <artifactId>axis</artifactId>
      <version>1.4</version>
    </dependency>
    <dependency>
      <groupId>axis</groupId>
      <artifactId>axis-jaxrpc</artifactId>
      <version>1.4</version>
    </dependency>

You will notice a problem with spring and maven 2 at the moment of writing. Maven provides the solution in the error message, we need to install the maven library manually. There aresome other options, but for now this is the easiest one. First download spring version 2.0 RC1, than issue the following command:

mvn install:install-file 
          -DgroupId=org.springframework 
          -DartifactId=spring 
          -Dversion=2.0-RC1 
          -Dpackaging=jar
          -Dfile=%PATH_TO_JAR%/spring.jar

Step 3 – Time to get the eclipse wtp to work
I want to deploy the webservice via tomcat and ofcourse I want a nice environment for debugging, deploying, and developing. I like to work with spring WebTools project, there is a pretty good integration with maven from the maven perspective. Lets use that. Fire up your eclipse (with wtp) and create a workspace. Do not create this workspace inside our projects, do it on another part of the disk. After creating this workspace, add the maven repository as a variable by using the following command:

mvn eclipse:add-maven-repo -Declipse.workspace=%PATH_TO_WORKSPACE%/WebservicePoc

Now let maven generate the eclipse project and classpath files, issue the following command:

mvn -Dwtpversion=1.0 eclipse:eclipse

You are ready to import the project into eclipse, “File > Import > Existing projects into workspace

step 4 – Lets publish a webservice
The webservice is deployed within a web container. Both axis and the spring container run in a servlet. There is a connection between the two via the servlet endpoint which will be discussed in a while. These servlets are configured in the web.xml file. The template for the file is generated by maven, lets add the servlets, servlet mappings and a spring specific parameter.

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath:/applicationContext.xml
		</param-value>
	</context-param>

This parameter specifies the locations where spring can find the configuration files for the container. The applicationContext.xml contains the definition of the beans in the Business service domain. There is another configuration file for spring thats needs to be present. This is the default spring config file based on the name of the servlet that configures the spring container. In our case this file does not contain any beans, but it must be available. It must be called action-servlet.xml since we have given the spring dispatcher servlet the name action. The file should reside next to the web.xml in the WEB-INF folder.

	<servlet>
		<servlet-name>action</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet>
		<servlet-name>axis</servlet-name>
		<servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class>
		<load-on-startup>2</load-on-startup>
	</servlet>

    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

	<servlet-mapping>
		<servlet-name>axis</servlet-name>
		<url-pattern>/services/*</url-pattern>
	</servlet-mapping>

Here you can see the spring dispatcher servlet and the axis servlet. Most important to notice is the load-on-startup parameter that tells the order of loading the servlets. The axis servlet connects to the loaded spring context via the special endpoint. Therefore the spring servlet needs to be loaded first. You do not need the dispatcher servlet if you plan to expose only webservices. If you also want to include spring mvc or the like, you do need the dispatcher servlet.

Next task is to configure the axis webservice, this is done via the server-config.wsdd file.

	<service name="JaxrpcwebserviceProvider" provider="java:RPC">
		<parameter name="className"
			value="com.coenradie.webservicepoc.server.jaxrpcstyle.ServiceProvider"/>
		<parameter name="allowedMethods" value="*"/>
		<beanMapping qname="webservicepoc:MessageBean" xmlns:webservicepoc="urn:MessageBean" 
			languageSpecificType="java:com.coenradie.webservicepoc.server.jaxrpcstyle.MessageBean"/>
	</service>

We are creating a jaxrpc style webservice with the name JaxrpcwebserviceProvider. Axis should redirect all calls to this service to the endpoint of type ServiceProvider. This is a subclass of a special spring implementation of the servletendpoint, this class is will be discussed later on. As you can see from the wsdd file, all public methods are exposed via the webservice. As a transport object we use the MessageBean.

Now all configuration is in place, time to do some real coding. We need to implement the following classes and interfaces.
MessageService and MessageServiceImpl – Business service interface and implementation
MessageBean – Object returned via the jaxrpc webservice
RemoteMessageService – Remote interface that is implemented by the service endpoint and therefore implemented by the webservice.
ServiceProvider – the special webservice endpoint that contains access to the laoded spring context. The endpoint contains the method that is called via axis.

public interface MessageService {
	String getMessage();
}

public class MessageServiceImpl implements MessageService {
	public String getMessage() {
		return "Message from my server";
	}
}

public interface RemoteMessageService extends Remote {
	public MessageBean getMessage() throws RemoteException;
}

public class MessageBean implements Serializable {
	private static final long serialVersionUID = -7014683074252469915L;
	private String message;
	private String createDate;
	
	public String getCreateDate() {
		return createDate;
	}
	public void setCreateDate(String createDate) {
		this.createDate = createDate;
	}
	public String getMessage() {
		return message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
}

The most important class is the endpoint, this is the class that gets called by axis. The spring superclass takes care of obtaining the spring web context. You can use this context to find spring wired beans. In our case we use it to find the Business service object MessageService.

public class ServiceProvider extends ServletEndpointSupport implements RemoteMessageService {
	private MessageService messageService;
	
	protected void onInit() {
		this.messageService = (MessageService)getWebApplicationContext().getBean("messageService");
	}
	
	public MessageBean getMessage() {
		MessageBean messageBean = new MessageBean();
		messageBean.setMessage(messageService.getMessage());
		messageBean.setCreateDate(new Date().toString());
		
		return messageBean;
	}
}

Time to fire up the server. You can use the run on server with a right mouse click on the project within eclipse wtp. Popup a browser and go to the following url:
http://localhost:8080/webservice-jaxrpc-style/services
That should give you an overview of all deployed services, probably only the JaxrpcwebserviceProvider.

Step 5 – Using xml spy to send a message via soap to the webservice
The webservice is deployed, you can have a look at the wsdl file, nice. Now we want to call the webservice. We can write a special java client. There is however an easier way with xmlspy. Since this blog item is all about exposing the webservice and not about creating a client, I will use xmlspy.

Fire up xmlspy and use the menu: SOAP > Create new soap request and enter the next url in the pop-up box:
http://localhost:8080/webservice-jaxrpc-style/services/JaxrpcwebserviceProvider?wsdl
After clicking oke, choose the getMessage() operating name, the following request is generated:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
	<SOAP-ENV:Body>
		<m:getMessage xmlns:m="http://jaxrpcstyle.server.webservicepoc.coenradie.com" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
	</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Then we can send the request over soap via xmlspy: SOAP > Send request to server

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<soapenv:Body>
		<ns1:getMessageResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://jaxrpcstyle.server.webservicepoc.coenradie.com">
			<getMessageReturn href="#id0"/>
		</ns1:getMessageResponse>
		<multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:MessageBean" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="urn:MessageBean">
			<createDate xsi:type="soapenc:string">Mon Jun 26 09:48:31 CEST 2006</createDate>
			<message xsi:type="soapenc:string">Message from my server</message>
		</multiRef>
	</soapenv:Body>
</soapenv:Envelope>

That concludes this article, I learned a lot while writing this item, hope you learned something while reading. The coming weeks I want to write about creating a client, doing document style webservices, using spring webservices component and security. Stay tuned.

Providing a webservice with Spring and axis