We learned how to use JAX-WS to create SOAP web services and publish it using javax.xml.ws.Endpoint
but most of the times we want to deploy our services on a servlet container. So today we will learn how to create a web service and deploy it on Apache Tomcat server and then test it out with the client application.
For this, our first step is to create a Dynamic Web Project to write our business logic. Our final project will look like below image.
For JAX-WS web service deployment on a servlet container, we need to add some jar files into it. There are two ways to do this.
- Download jar files from https://jax-ws.java.net/ and include it in the dynamic web project.
- Convert Dynamic web project into Maven and add below dependencies.
<dependency> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-rt</artifactId> <version>2.2.10</version> </dependency>
This will automatically download all the required jar files as maven dependencies shown in the below image. I like this approach because I can upgrade the versions easily and it will also make sure none of the jars are getting missed.
Now let’s go through the business logic. First, we will create a model bean class.
package com.journaldev.jaxws.beans;
import java.io.Serializable;
public class Person implements Serializable{
private static final long serialVersionUID = -5577579081118070434L;
private String name;
private int age;
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString(){
return id+"::"+name+"::"+age;
}
}
Now we will create our service interface and implementation classes.
package com.journaldev.jaxws.service;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import com.journaldev.jaxws.beans.Person;
@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface PersonService {
@WebMethod
public boolean addPerson(Person p);
@WebMethod
public boolean deletePerson(int id);
@WebMethod
public Person getPerson(int id);
@WebMethod
public Person[] getAllPersons();
}
package com.journaldev.jaxws.service;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.jws.WebService;
import com.journaldev.jaxws.beans.Person;
@WebService(endpointInterface = "com.journaldev.jaxws.service.PersonService")
public class PersonServiceImpl implements PersonService {
private static Map<Integer,Person> persons = new HashMap<Integer,Person>();
@Override
public boolean addPerson(Person p) {
if(persons.get(p.getId()) != null) return false;
persons.put(p.getId(), p);
return true;
}
@Override
public boolean deletePerson(int id) {
if(persons.get(id) == null) return false;
persons.remove(id);
return true;
}
@Override
public Person getPerson(int id) {
return persons.get(id);
}
@Override
public Person[] getAllPersons() {
Set<Integer> ids = persons.keySet();
Person[] p = new Person[ids.size()];
int i=0;
for(Integer id : ids){
p[i] = persons.get(id);
i++;
}
return p;
}
}
Our web service code is ready, next steps are required to create it as a web archive that we can deploy in the servlet container.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns="https://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="https://xmlns.jcp.org/xml/ns/javaee https://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>JAXWS-Tomcat</display-name>
<listener>
<listener-class>
com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
<servlet>
<servlet-name>JAXWSServlet</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JAXWSServlet</servlet-name>
<url-pattern>/personWS</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
There is nothing project-specific, these are generic changes to add listener class and front servlet class for web service.
Next step is to create sun-jaxws.xml
file inside WEB-INF directory where we will provide endpoint details. URL-pattern should be same as defined in the web.xml file.
sun-jaxws.xml
<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="https://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
<endpoint
name="PersonServiceImpl"
implementation="com.journaldev.jaxws.service.PersonServiceImpl"
url-pattern="/personWS"/>
</endpoints>
That’s it, we are done. Just export project as a WAR file and deploy it into tomcat container. Access the web service URL as shown in below image.
Access the WSDL URL and take note of targetNamespace and name attributes, we will use them in the client side program.
Below is a simple test program to use our web service and run some tests.
package com.journaldev.jaxws.test;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import com.journaldev.jaxws.beans.Person;
import com.journaldev.jaxws.service.PersonService;
public class SOAPPublisherClient {
public static void main(String[] args) throws MalformedURLException {
URL wsdlURL = new URL("https://localhost:8080/JAXWS-Tomcat/personWS?wsdl");
//check above URL in browser, you should see WSDL file
//creating QName using targetNamespace and name
QName qname = new QName("https://service.jaxws.journaldev.com/", "PersonServiceImplService");
Service service = Service.create(wsdlURL, qname);
//We need to pass interface and model beans to client
PersonService ps = service.getPort(PersonService.class);
Person p1 = new Person(); p1.setName("Pankaj"); p1.setId(1); p1.setAge(30);
Person p2 = new Person(); p2.setName("Meghna"); p2.setId(2); p2.setAge(25);
//add person
System.out.println("Add Person Status="+ps.addPerson(p1));
System.out.println("Add Person Status="+ps.addPerson(p2));
//get person
System.out.println(ps.getPerson(1));
//get all persons
System.out.println(Arrays.asList(ps.getAllPersons()));
//delete person
System.out.println("Delete Person Status="+ps.deletePerson(2));
//get all persons
System.out.println(Arrays.asList(ps.getAllPersons()));
}
}
As explained in previous tutorial, we can use wsimport utility to generate client stubs and use it. When we run above program, we get output as shown in below image.
That’s all for now, I hope you liked the tutorial and it will help you in deploying web services in Tomcat container.
Is there any way to disable the wsdl while accessing with URL.
https://localhost:8080/LearnWS/personWS
I’m able to open the above URL and can see the list of API’s
But
https://localhost:8080/LearnWS/personWS?wsdl
If I try to open this, I’m getting page cannot be displayed and I’m getting an error in the console as below
SEVERE: caught throwable
java.io.IOException: Trying to write END_DOCUMENT when the document has no root (ie. trying to output empty document).
at com.sun.xml.ws.server.SDDocumentImpl.writeTo(SDDocumentImpl.java:299)
at com.sun.xml.ws.transport.http.HttpAdapter.publishWSDL(HttpAdapter.java:931)
at com.sun.xml.ws.transport.http.HttpAdapter.handleGet(HttpAdapter.java:440)
at com.sun.xml.ws.transport.http.servlet.ServletAdapter.invokeAsync(ServletAdapter.java:193)
at com.sun.xml.ws.transport.http.servlet.WSServletDelegate.doGet(WSServletDelegate.java:161)
at com.sun.xml.ws.transport.http.servlet.WSServlet.doGet(WSServlet.java:89)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.xml.stream.XMLStreamException: Trying to write END_DOCUMENT when document has no root (ie. trying to output empty document).
at com.ctc.wstx.sw.BaseStreamWriter.throwOutputError(BaseStreamWriter.java:1518)
at com.ctc.wstx.sw.BaseStreamWriter.reportNwfStructure(BaseStreamWriter.java:1547)
at com.ctc.wstx.sw.BaseStreamWriter._finishDocument(BaseStreamWriter.java:1373)
at com.ctc.wstx.sw.BaseStreamWriter.close(BaseStreamWriter.java:243)
at com.sun.xml.ws.util.xml.XMLStreamWriterFilter.close(XMLStreamWriterFilter.java:67)
at com.sun.xml.ws.server.SDDocumentImpl.writeTo(SDDocumentImpl.java:297)
… 29 more
hi,How did you publish the webservice in tomcat? can you please guide
After a lot of other tutorials trials, this one had been perfect in terms of getting the service up and running in tomcat, as it shows precisely the dependencies we need.
Please let me know how to deploy the same for JBOSS or Weblogic
hopefully you had a repository to see project details like the POM.
Thanks for your examples.
Hi Pankaj, your tutorials are very helpful, please can you send me the pom.xml . thanks in advance