DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • JMeter Plugin HTTP Simple Table Server (STS) In-Depth
  • Optimizing Database Connectivity: A Comparative Analysis of Tomcat JDBC vs. HikariCP
  • How To Get Cell Data From an Excel Spreadsheet Using APIs in Java
  • Deployment of Spring MVC App on a Local Tomcat Server

Trending

  • Dropwizard vs. Micronaut: Unpacking the Best Framework for Microservices
  • Building Resilient Networks: Limiting the Risk and Scope of Cyber Attacks
  • Kullback–Leibler Divergence: Theory, Applications, and Implications
  • Ensuring Configuration Consistency Across Global Data Centers
  1. DZone
  2. Coding
  3. Languages
  4. Creating and Deploying JAX-WS Web Service on Tomcat 6

Creating and Deploying JAX-WS Web Service on Tomcat 6

By 
Munish Gogna user avatar
Munish Gogna
·
Dec. 01, 10 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
68.8K Views

Join the DZone community and get the full member experience.

Join For Free

Some years back I had to provide a wrapper around an EJB 3.0 remote service to come up with a simple web service project that would be deployed over Tomcat and accessed in a simple http way due to some accessibility issues. Now as I cannot reveal the actual requirement I implemented that time so here I am presenting a simple demo kind of service with following signature.


public AccountDetails getAccountDetails(String accountNo, SecurityToken token);


The service will return the account details of a particular account number, provided the token is valid (generated using some Security module of the application). In nutshell, the client will ask for a token from Security module and then invoke this method. The service will validate the token to see if the caller can invoke the method or not? In general you should use handlers (message interceptors that can be easily plugged in to the JAX-WS runtime to do additional processing of the inbound and outbound messages) to validate the stuff, freeing implementation class from that overhead, it is just an example exercise so our implementation class will check the security token also.Sounds good.. lets move ahead.


Libraries we are going to use include JAXB and JAX-WS, as both of them have sensible defaults, the number of annotations can be kept to the minimum. Also in my opinion, it is always best to develop WSDL and schemas by hand to ensure that the service contract is appropriately defined and also that the schema can be re-used (by other services) and extended if necessary. I do not prefer using annotations for automatically producing WSDL and schema at runtime so let's start with the definition, i am using inline schema as we have a very simple requirement here, though we should have schema definitions in separate xsd files.


accounts.wsdl:

<?xml version="1.0" encoding="UTF-8"?><definitions name="AccountDetails"  targetNamespace="http://gognamunish.com/accounts"         xmlns:tns="http://gognamunish.com/accounts"          xmlns="http://schemas.xmlsoap.org/wsdl/"         xmlns:xsd="http://www.w3.org/2001/XMLSchema"          xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"><types><xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"elementFormDefault="qualified" targetNamespace="http://gognamunish.com/accounts"><element name="geAccountDetails_INTO" type="tns:GeAccountDetails_INTO" /><element name="accountDetails_TO" type="tns:AccountDetails_TO" /><element name="accountDetailsFault" type="tns:AccountDetailsFault" /><element name="securityToken" type="tns:SecurityToken" /><complexType name="GeAccountDetails_INTO"><sequence><element name="accountNo" type="xsd:string" /></sequence></complexType><complexType name="AccountDetails_TO"><sequence><element name="accNo" type="xsd:string" /><element name="accType" type="xsd:string" /><element name="balance" type="xsd:decimal" /></sequence></complexType><complexType name="SecurityToken"><sequence><element name="token" type="xsd:string" /><element name="validTill" type="xsd:date" /></sequence></complexType><complexType name="AccountDetailsFault"><sequence><element name="faultInfo" type="xsd:string" /><element name="message" type="xsd:string" /></sequence></complexType></xsd:schema></types><!--  messages format --><message name="accountDetailsRequest"><part name="parameters" element="tns:geAccountDetails_INTO" /><part name="request_header" element="tns:securityToken"/></message><message name="accountDetailsResponse"><part name="parameters" element="tns:accountDetails_TO" /></message><message name="accountDetailsFault"><part name="faultInfo" element="tns:accountDetailsFault" /></message><!-- define getAccountDetails operation here --><portType name="AccountDetailsPortType"><operation name="getAccountDetails"><input message="tns:accountDetailsRequest" /><output message="tns:accountDetailsResponse" /><fault message="tns:accountDetailsFault" name="accountDetailsFault"/></operation></portType><!-- bind the operations --><binding name="AccountDetailsBinding" type="tns:AccountDetailsPortType"><soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /><operation name="getAccountDetails"><soap:operation soapAction="getAccountDetails" /><input><soap:body use="literal" parts="parameters"/><soap:header use="literal" part="request_header" message="tns:accountDetailsRequest"></soap:header></input><output><soap:body use="literal" /></output><fault name="accountDetailsFault"><soap:fault name="accountDetailsFault" use="literal" /></fault></operation></binding><!-- name and location of the service --><service name="AccountDetailsService"><port name="AccountDetailsPort" binding="tns:AccountDetailsBinding"><soap:address location="http://localhost:8080/account/details" /></port></service></definitions>


I am not going to explain the In and outs of this wsdl , in a nutshell it defines one operation 'getAccountDetails' which takes accountNo and returns back the account details like account type, balance etc. Please note that I have also added a security header token that will validate the caller (left to the implementation of the service).

Now as we are done with our wsdl and schema, let's generate the portable artifacts from our service definition. JAX-WS includes a tool that can do this for us, we will use this tool to generate portable artifacts like Service Endpoint Interface (SEI), Service and Exception classes.These artifacts can be packaged in a WAR file with the WSDL and schema documents along with the endpoint implementation to be deployed.


To generate the artifacts , we run following command:

 wsimport C:\devel\workspace\webservice\WebContent\WEB-INF\wsdl\accounts.wsdl -p com.mg.ws -keep -Xnocompile


This will create the following artifacts in com.mg.ws package.

  • AccountDetails.java
  • AccountDetailsFault.java
  • AccountDetailsFault_Exception.java
  • AccountDetailsPortType.java
  • AccountDetailsTO.java
  • GeAccountDetailsINTO.java
  • ObjectFactory.java
  • package-info.java
  • SecurityToken.java



Now as we have got all the artifacts we are ready to implement our service, the interface we need to implement is AccountDetailsPortType , so let's do it.


Here is our dummy implementation class:

package com.mg.ws.impl;import java.math.BigDecimal;import javax.jws.WebService;import com.mg.ws.AccountDetailsFault;import com.mg.ws.AccountDetailsFault_Exception;import com.mg.ws.AccountDetailsPortType;import com.mg.ws.AccountDetailsTO;import com.mg.ws.GeAccountDetailsINTO;import com.mg.ws.SecurityToken;@WebService(name = "AccountDetailsService",       portName = "AccountDetailsPort",       endpointInterface = "com.mg.ws.AccountDetailsPortType",       wsdlLocation = "WEB-INF/wsdl/accounts.wsdl",      targetNamespace="http://gognamunish.com/accounts")     public class AccountDetailsServiceImpl implements AccountDetailsPortType {public AccountDetailsTO getAccountDetails(GeAccountDetailsINTO parameters,   SecurityToken requestHeader) throws AccountDetailsFault_Exception {  AccountDetailsTO detailsTO = new AccountDetailsTO();  // validate token   validateToken(requestHeader);  // populate response  detailsTO = getDetailsFromSomewhere (parameters.getAccountNo());  return detailsTO; } private AccountDetailsTO getDetailsFromSomewhere(String accountNo) throws AccountDetailsFault_Exception {  if(accountNo == null || accountNo.trim().length()==0){   AccountDetailsFault faultInfo = new AccountDetailsFault();   faultInfo.setFaultInfo("missing account number");   faultInfo.setMessage("account number is required field");   throw new AccountDetailsFault_Exception("account no missing", faultInfo);  }  AccountDetailsTO detailsTO = new AccountDetailsTO();  detailsTO.setAccNo(accountNo);  detailsTO.setAccType("SAVING");  detailsTO.setBalance(new BigDecimal(10000));  return detailsTO; } private void validateToken(SecurityToken requestHeader) throws AccountDetailsFault_Exception {    if ("83711070".equals(requestHeader.getToken()) && requestHeader.getValidTill() != null){   System.out.println("token processed successfully...");  } else {   AccountDetailsFault faultInfo = new AccountDetailsFault();   faultInfo.setFaultInfo("Header token Invalid");   faultInfo.setMessage("can't help");   throw new AccountDetailsFault_Exception("invalid token", faultInfo);  } }}


This is just a dummy implementation for illustration purpose only. Now as our service implementation is done, we proceed to package this in a war and deploy it on tomcat.


Now we create a standard web.xml, which defines WSServletContextListener, WSServlet and structure of a web project.

<?xml version="1.0"?> <!DOCTYPE web-app PUBLIC   "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"   "http://java.sun.com/dtd/web-app_2_3.dtd"><web-app><listener><listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener        </listener-class></listener><servlet><servlet-name>AccountDetailsService</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>AccountDetailsService</servlet-name><url-pattern>/details</url-pattern></servlet-mapping></web-app>



Next we create a sun-jaxws.xml, defines the web service implementation class.

<?xml version="1.0" encoding="UTF-8"?><endpoints  xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"  version="2.0">  <endpoint name="AccountDetailsServiceEndPoint"    service ="{http://gognamunish.com/accounts}AccountDetailsService"      port="{http://gognamunish.com/accounts}AccountDetailsPort"      implementation="com.mg.ws.impl.AccountDetailsServiceImpl"      url-pattern="/details"      wsdl="WEB-INF/wsdl/accounts.wsdl"/></endpoints>


This file is required regardless of whether we publish our web service on tomcat, glassfish or any other server. OK so far so good , let's build our application and deploy it on tomcat, here is the ant script.

<project name="webservice" basedir="../" default="deploy"><!-- Project settings --><property name="project.distname" value="account" /><!-- Local system paths --><property file="${basedir}/ant/build.properties" /><property name="webroot.dir" value="${basedir}/WebContent" /><property name="webinf.dir" value="${webroot.dir}/WEB-INF" /><property name="build.dir" value="build" /><path id="compile.classpath"><!-- classpath for Jax WS related stuff --><pathelement path="${webinf.dir}/lib/activation.jar" /><pathelement path="${webinf.dir}/lib/jaxb-api.jar" /><pathelement path="${webinf.dir}/lib/jaxb-impl.jar" /><pathelement path="${webinf.dir}/lib/jaxp-api.jar" /><pathelement path="${webinf.dir}/lib/jaxws-api.jar" /><pathelement path="${webinf.dir}/lib/jaxws-rt.jar" /><pathelement path="${webinf.dir}/lib/jsr173_api.jar" /><pathelement path="${webinf.dir}/lib/jsr181_api.jar" /><pathelement path="${webinf.dir}/lib/resolver.jar" /><pathelement path="${webinf.dir}/lib/saaj-api.jar" /><pathelement path="${webinf.dir}/lib/saaj-impl.jar" /><pathelement path="${webinf.dir}/lib/sjsxp.jar" /><pathelement path="${webinf.dir}/lib/stax-ex.jar" /><pathelement path="${webinf.dir}/lib/streambuffer.jar" /><pathelement path="${webinf.dir}/classes" /><pathelement path="${classpath.external}" /><pathelement path="${classpath}" /></path><!-- define your folder for deployment --><property name="deploy.dir" value="deploy" /><!-- Local system paths --><property file="${basedir}/ant/build.properties" /><property name="webroot.dir" value="${basedir}/WebContent" /><property name="webinf.dir" value="${webroot.dir}/WEB-INF" /><property name="build.dir" value="build" /><!-- Check timestamp on files --><target name="prepare"><tstamp /></target><!-- Copy any resource or configuration files --><target name="resources"><copy todir="${webinf.dir}/classes" includeEmptyDirs="no"><fileset dir="JavaSource"><patternset><include name="**/*.conf" /><include name="**/*.properties" /><include name="**/*.xml" /></patternset></fileset></copy></target><!-- Normal build of application --><target name="compile" depends="prepare,resources"><javac srcdir="JavaSource" destdir="${webinf.dir}/classes"><classpath refid="compile.classpath" /></javac></target><!-- Remove classes directory for clean build --><target name="clean" description="Prepare for clean build"><delete dir="${webinf.dir}/classes" /><mkdir dir="${webinf.dir}/classes" /></target><!-- Build entire project --><target name="build" depends="prepare,compile" /><target name="rebuild" depends="clean,prepare,compile" /><!-- Create binary distribution --><target name="war" depends="build"><mkdir dir="${build.dir}" /><war basedir="${webroot.dir}" warfile="${build.dir}/${project.distname}.war" webxml="${webinf.dir}/web.xml"><exclude name="WEB-INF/${build.dir}/**" /><exclude name="WEB-INF/src/**" /><exclude name="WEB-INF/web.xml" /></war></target><!-- Create Client --><target name="jar"><jar destfile="${build.dir}/${project.distname}_client.jar" basedir="${webinf.dir}/classes" includes="com/mg/ws/*"/></target><!-- deploy on tomcat --><target name="deploy" depends="war,jar"><delete file="${deploy.dir}/${project.distname}.war" /><delete dir="${deploy.dir}/${project.distname}" /><copy file="${build.dir}/${project.distname}.war" todir="${TOMCAT_HOME}\webapps" /></target></project>

NOTE: jars in lib should be carefully chosen, otherwise it will make your life hell.


Now let's test the application, point your browser to http://localhost:8080/account/details , if you see something like this, it means you have successfully deployed the service.

Now let's test the service, we can use the client generated by the wsimport tool as :

public static void main(String[] args) throws Exception {  AccountDetails accountDetails = new AccountDetails();  AccountDetailsPortType port = accountDetails.getAccountDetailsPort();  AccountDetailsTO details = port.getAccountDetails(new GeAccountDetailsINTO(), new SecurityToken()); }


For those who want to invoke the service using soap stuff, they can use tool like soapUI (can be downloaded from www.soapui.org), lets make some soap calls now:


case: invalid security header


case: valid security header


By default, Tomcat does not comes with any JAX-WS dependencies, So, you have to include it manually.

  • Go here
  • Download JAX-WS RI distribution, you will find the wsimport tool in lib directory.


Please note for running this project you can just skip this step as I have already done this step for you and included the required libraries in the lib folder of the project.



I have included eclipse project for this demo, please get it from resource section. To deploy just change build.properties to point to TOMCAT_HOME and run ant build.


Thats all for now ... Please provide your valuable comments or any suggestion and DON'T forget to vote :)


It's Munish Gogna signing off now :)

Web Service Apache Tomcat

Opinions expressed by DZone contributors are their own.

Related

  • JMeter Plugin HTTP Simple Table Server (STS) In-Depth
  • Optimizing Database Connectivity: A Comparative Analysis of Tomcat JDBC vs. HikariCP
  • How To Get Cell Data From an Excel Spreadsheet Using APIs in Java
  • Deployment of Spring MVC App on a Local Tomcat Server

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!