Chapter 1. Create an SOAP web service in a servlet container

1.1.  Create a web service starting from a WSDL file using JAX-WS

1.1.1.  Use wsimport tool to generate artifacts from WSDL

JAX-WS provides the wsgen and wsimport command-line tools to generate portable artifacts for JAX-WS web services. When creating JAX-WS web services, you can start with either a WSDL file or an implementation bean class.

If you start with an implementation bean class, use the wsgen command-line tool to generate all the web services provider artifacts, including a WSDL file if requested.

If you start with a WSDL file, use the wsimport command-line tool to generate all the web services artifacts for either the server or the client. The wsimport command-line tool processes the WSDL file with schema definitions to generate the portable artifacts, which include the service class, the service endpoint interface class, and the JAXB 2.1 classes for the corresponding XML schema.

The wsimport tool generates JAX-WS portable artifacts, such as:

  • Service Endpoint Interface (SEI)

  • Service

  • Exception class mapped from wsdl:fault (if any)

  • Async Reponse Bean derived from response wsdl:message (if any)

  • JAXB generated value types (mapped Java classes from schema types)

Syntax:


wsimport [options] <wsdl>

						

Options:

  • -d <directory>

    Specify where to place generated output files

  • -b <path>

    Specify external JAX-WS or JAXB binding files or additional schema files (Each <file> must have its own -b)

  • -B <jaxbOption>

    Pass this option to JAXB schema compiler.

  • -keep

    Keep generated source code files. It is enabled when -s option.

  • -p

    Specifying a target package via this command-line option, overrides any wsdl and schema binding customization for package name and the default package name algorithm defined in the specification.

  • -s <directory>

    Specify where to place generated source code files. -keep is turned on with this option.

  • -wsdllocation <location>

    @WebServiceClient.wsdlLocation value.

Multiple JAX-WS and JAXB binding files can be specified using -b option and they can be used to customize various things like package names, bean names, etc.

Example:

wsimport -p stockquote http://java.boot.by/StockQuote?wsdl
						

This will generate the Java artifacts and compile them by importing the http://java.boot.by/StockQuote?wsdl

1.1.2.  Use external and embedded <jaxws:package>, <jaxws:enableWrapperStyle>, <jaxws:class> customizations

External Binding Declaration

External binding files are semantically equivalent to embedded binding declarations. When wsimport processes the WSDL document for which there is an external binding file, it internalizes the binding declarations defined in the external binding file on the nodes in the WSDL document they target using the wsdlLocation attribute. The embedded binding declarations can exist in a WSDL file and an external binding file targeting that WSDL, but wsimport may give an error if, upon embedding the binding declarations defined in the external binding files, the resulting WSDL document contains conflicting binding declarations.

Embedded Binding Declarations

Embedded binding declarations follow different rules compared to the binding declarations declared in the external binding file. Here are some important facts and rules as defined in the JAX-WS 2.0 specification:

  • An embedded binding declaration is specified by using the jaxws:bindings element as a WSDL extension.

  • When a jaxws:bindings element is used as a WSDL extension, it must not have a node attribute.

  • The binding declaration must not have a child element whose qualified name is jaxws:bindings.

  • A binding declaration embedded in a WSDL can only affect the WSDL element it extends.

Here's an example of embedded binding declarations in the WSDL:


<wsdl:portType name="AddNumbersImpl">

    <!-- wsdl:portType customizations -->
    <jaxws:bindings xmlns:jaxws="http://java.sun.com/xml/ns/jaxws">

        <!-- rename the generated SEI from AddNumbersImpl to MathUtil -->
        <jaxws:class name="MathUtil"/>
        ...
    </jaxws:bindings>
    <wsdl:operation name="addNumber">
    ...
</wsdl:portType>

						

The above WSDL file excerpt shows the wsdl:portType customization. jaxws:bindings appears as extension element of portType. It customizes the class name of the generated service endpoint interface. Without this customization, or by default, the service endpoint interface class is named after the wsdl:portType name. The binding declaration jaxws:class customizes the generated class to be named MathUtil instead of AddNumberImpl.

Package Customization

By default wscompile generates WSDL artifacts in a package computed from the WSDL targetNamespace. For example, a WSDL file with the targetNamespace http://java.boot.by without any package customization will be mapped to the by.boot.java package. To customize the default package mapping you would use a jaxws:package customization on the wsdl:definitions node or it can directly appear inside the top level bindings element.

An important thing to note is that -p option on command-line wsimport tool (package attribute on wsimport Ant task), overrides the jaxws:package customization, it also overrides the schema package customization specified using JAXB schema customization.

For example:


<bindings
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    wsdlLocation="http://localhost:8080/jaxws-external-customize/addnumbers?WSDL"
    xmlns="http://java.sun.com/xml/ns/jaxws">

        <package name="by.boot.java">
            <javadoc>Mathutil package</javadoc>
        </package>
		...
</bindings>

						

or:


<bindings
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    wsdlLocation="http://localhost:8080/jaxws-external-customize/addnumbers?WSDL"
    xmlns="http://java.sun.com/xml/ns/jaxws">

    <bindings node="wsdl:definitions">

        <package name="by.boot.java">
            <javadoc>Mathutil package</javadoc>
        </package>
        ...
    </bindings>
</bindings>


						

Wrapper Style

wsimport by default applies wrapper style rules to the abstract operation defined in the wsdl:portType, and if an operation qualifies the Java method signature is generated accordingly. Wrapper style Java method generation can be disabled by using jaxws:enableWrapperStyle.

jaxws:enableWrapperStyle can appear on the toplevel bindings element (with @wsdlLocation attribute), it can also appear on the following target nodes:

  • wsdl:definitions: global scope, applies to all the wsdl:operations of all wsdl:portType attributes.

  • wsdl:portType applies to all the wsdl:operations in the portType.

  • wsdl:operation applies to only this wsdl:operation.

For example:


<bindings
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    wsdlLocation="http://localhost:8080/jaxws-external-customize/addnumbers?WSDL"
    xmlns="http://java.sun.com/xml/ns/jaxws">

    <!-- applies to wsdl:definitions node, that would mean the entire wsdl -->
    <enableWrapperStyle>true</enableWrapperStyle>

    <!-- wsdl:portType operation customization -->
    <bindings node="wsdl:definitions/wsdl:portType[@name='AddNumbersImpl']/wsdl:operation[@name='addNumbers']">

        <!-- change java method name from addNumbers() to add() -->
        <enableWrapperStyle>false</enableWrapperStyle>

        ...
    </bindings>
</bindings>

						

In the example above the wrapper style is disabled for the addNumbers operation in AddNumbersImpl portType. This is because wsimport processes this binding in the following order: first wsdl:operation, then its parent wsdl:portType, and finally wsdl:definitions. Here wsdl:operation addNumbers has this customization disabled so this is what is applied by wsimport to generate a bare Java method signature.

Class Customization

The generated class for wsdl:portType, wsdl:fault, soap:headerfault, and wsdl:server can be customized using the jaxws:class binding declaration.

The Service Endpoint Interface Class

wscompile will generate the service endpoint interface class MathUtil instead of the default AddNumbersImpl in this example:


<!-- wsdl:portType customization -->
<bindings node="wsdl:definitions/wsdl:portType[@name='AddNumbersImpl']">

    <!-- change the generated SEI class -->
    <class name="MathUtil">
        <javadoc>Perform mathematical computations</javadoc>
    </class>
    ...
</bindings>

						

The Exception Class

wsimport will generate the MathUtilException class instead of the default AddNumbersExeption in this example:


<!-- change the generated exception class name -->
<bindings node="wsdl:definitions/wsdl:portType[@name='AddNumbersImpl']/wsdl:operation[@name='addNumbers']/wsdl:fault[@name='AddNumbersException']">

    <class name="MathUtilException">
        <javadoc>Exception generated during computation</javadoc>
    </class>

</bindings>

						

The Service Class

wsimport will generate MathUtilService instead of the default AddNumbersService in this example:


<!-- wsdl:service customization -->
<bindings node="wsdl:definitions/wsdl:service[@name='AddNumbersService']">

    <!-- change the generated service class -->
    <class name="MathUtilService">
        <javadoc>Service to perform mathematical computations</javadoc>
    </class>

</bindings>

						

1.1.3.  Use JAXB customizations to configure mapping.

Inline Customizations

Customizations to JAXB bindings made by means of inline binding declarations in an XML schema file take the form of <xsd:appinfo> elements embedded in schema <xsd:annotation> elements (xsd: is the XML schema namespace prefix, as defined in W3C XML Schema Part 1: Structures). The general form for inline customizations is shown below:


<xsd:annotation>
   <xsd:appinfo>
      .
      .
      binding declarations
      .
      .
   </xsd:appinfo>
</xsd:annotation>

						

Customizations are applied at the location at which they are declared in the schema. For example, a declaration at the level of a particular element would apply to that element only. Note that the XML Schema namespace prefix must be used with the <annotation> and <appinfo> declaration tags. In the example above, xsd: is used as the namespace prefix, so the declarations are tagged <xsd:annotation> and <xsd:appinfo>.

External Binding Customization Files

Customizations to JAXB bindings made by means of an external file containing binding declarations take the general form shown below:


<jxb:bindings schemaLocation = "xsd:anyURI">
   <jxb:bindings node = "xsd:string">*
      <binding declaration>
   <jxb:bindings>
</jxb:bindings>

						

  • schemaLocation is a URI reference to the remote schema.

  • node is an XPath 1.0 expression that identifies the schema node within schemaLocation to which the given binding declaration is associated.

For example, the first schemaLocation/node declaration in a JAXB binding declarations file specifies the schema name and the root schema node:


<jxb:bindings schemaLocation="po.xsd" node="/xsd:schema">

						

A subsequent schemaLocation/node declaration, say for a simpleType element named ZipCodeType in the above schema, would take the form:


<jxb:bindings node="//xsd:simpleType[@name='ZipCodeType']">

						

Customization files containing binding declarations are passed to the JAXB Binding compiler, xjc, using the following syntax:


xjc -b <file> <schema>

						

where <file> is the name of binding customization file, and <schema> is the name of the schema(s) you want to pass to the binding compiler.

You can have a single binding file that contains customizations for multiple schemas, or you can break the customizations into multiple bindings files:

xjc schema1.xsd schema2.xsd schema3.xsd -b bindings123.xjb
						

xjc schema1.xsd schema2.xsd schema3.xsd -b bindings1.xjb -b bindings2.xjb -b bindings3.xjb
						

Note that the ordering of schema files and binding files on the command line does not matter, although each binding customization file must be preceded by its own -b switch on the command line.

1.1.4.  Build the web service implementation using the above artifacts.

blah-blah

1.1.5.  Access MessageContext.SERVLET_CONTEXT from the injected @WebServiceContext

javax.xml.ws.WebServiceContext

The javax.xml.ws.WebServiceContext interface makes it possible for an endpoint implementation object and potentially any other objects that share its execution context to access information pertaining to the request being served.

The WebServiceContext is treated as an injectable resource that can be set at the time an endpoint is initialized. The WebServiceContext object will then use thread-local information to return the correct information regardless of how many threads are concurrently being used to serve requests addressed to the same endpoint object.

In Java SE, the resource injection denoted by the WebServiceContext annotation is REQUIRED to take place only when the annotated class is an endpoint implementation class.

The following code shows a simple endpoint implementation class which requests the injection of its WebServiceContext:

@WebService
public class Test {

    @Resource
    private WebServiceContext context;

    public String reverse(String inputString) {

        MessageContext mc = context.getMessageContext();
        ServletContext servletContext = (ServletContext) mc.get(MessageContext.SERVLET_CONTEXT);

        ...
    }
}
						

The @javax.annotation.Resource annotation defined by JSR-250 is used to request injection of the WebServiceContext. Then invoke the getMessageContext() method and work with the MessageContext object.

1.1.6.  Configure deployment descriptors (web.xml, webservices.xml) for URL patterns, HTTP security, container authorization, caller authentication, and message protection. JAX-WS runtime may also be configured to perform message layer authentication and protection.

URL patterns

The web.xml file contains information about the structure and external dependencies of web components in the module and describes how the components are used at run time. For Java API for XML-Based Web Services (JAX-WS) applications, you can customize the URL pattern in the web.xml file.

When you package a JAX-WS application as a web service, the web service is contained within a Web ARchive (WAR) file or a WAR module within an enterprise archive (EAR) file. A JAX-WS enabled WAR file contains the following items:

  • A WEB-INF/web.xml file that describes configuration and deployment information for the web components that comprise a web application.

  • Annotated classes that implement the web services contained in the application module including the service endpoint implementation class.

  • JAXB classes.

  • (Optional) Web Services Description Language (WSDL) documents that describe the web services contained in the application module.

  • (Optional) XML schema files.

  • (Optional) utility classes.

  • (Optional) web service clients.

The default URL pattern is defined by the @WebService.serviceName attribute that is contained in your web service implementation class. When the WSDL file that is associated with your service implementation class contains a single port definition, you can choose to use the default URL pattern or you can customize the URL pattern within the web.xml file. When the WSDL file that is associated with your service implementation class contains multiple port definitions within the same service definition, customized URL patterns are required. If you use the default URL pattern when the service implementation class contains multiple port definitions, then multiple service implementation classes are mapped to the same URL pattern which results in an error condition. You must edit the web.xml file and customize the URL patterns for each service definition. Each port maps to a web service implementation class and to its own custom URL pattern. By customizing the URL pattern in the web.xml file, you correct conflicting URL pattern definitions.

  1. Determine if custom URL patterns are required or desired. Custom URL patterns are only required when the WSDL file for your JAX-WS web service contains multiple port definitions within a single service. Otherwise, you may optionally define custom URL patterns.

  2. To customize the URL pattern for a service implementation class, edit the web.xml file and provide a <servlet> and corresponding <servlet-mapping> entry for each JAX-WS web service implementation class for which a custom URL pattern is desired. You must define the <url-pattern> value within the <servlet-mapping> entry.

The following example illustrates the required URL pattern customizations when the WSDL file associated with the service implementation class has multiple port definitions.

The following excerpt is from a sample web service implementation classes:

package by.boot.java;

@WebService(serviceName="EchoService", portName="SOAP11EchoServicePort")
public class EchoServiceSOAP11{
	...
}
						

package by.boot.java;

@WebService(serviceName="EchoService", portName="SOAP12EchoServicePort")
public class EchoServiceSOAP12{
	...
}
						

The following excerpt is from the WSDL file associated with the EchoServiceSOAP11 web service implementation class. Each port in the WSDL file maps to a portName in the web service implementation class:


<wsdl:service name="EchoService">
	<wsdl:port name="SOAP11EchoServicePort" tns:binding="..." >
		...
	</wsdl:port>
	<wsdl:port name="SOAP12EchoServicePort" tns:binding="..." >
		...
	</wsdl:port>
</wsdl:service>

						

In this scenario, because there are multiple port definitions within the WSDL file, you must customize the URL pattern by editing the web.xml file. Specify custom URL patterns for each service. The following excerpt is from a sample web.xml file that demonstrates setting up a servlet:


<servlet>
	<servlet-name>by.boot.java.EchoServiceSOAP11</servlet-name>
	<servlet-class>by.boot.java.EchoServiceSOAP11</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>by.boot.java.EchoServiceSOAP11</servlet-name>
	<url-pattern>/EchoServiceSOAP11</url-pattern>
</servlet-mapping>

<servlet>
	<servlet-name>by.boot.java.EchoServiceSOAP12</servlet-name>
	<servlet-class>by.boot.java.EchoServiceSOAP12</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>by.boot.java.EchoServiceSOAP12</servlet-name>
	<url-pattern>/EchoServiceSOAP12</url-pattern>
</servlet-mapping>

						

Basic Authentication with JAX-WS

When a service that is constrained by HTTP basic authentication is requested, the server requests a user name and password from the client and verifies that the user name and password are valid by comparing them against a database of authorized users.

  • Annotating the Service

    In this example, annotations are used to specify which users are authorized to access which methods of this service. In this simple example, the @RolesAllowed annotation is used to specify that users in the application role of basicUser are authorized access to the sayHello(String name) method. This application role must be linked to a group of users on the Application Server.

    The code snippet is as follows:

    import javax.jws.WebMethod;
    import javax.jws.WebService;
    import javax.annotation.security.RolesAllowed;
    
    @WebService()
    public class Hello {
    
        private String message = new String("Hello, ");
    
        @WebMethod()
        @RolesAllowed("basicUser")
        public String sayHello(String name) {
            return message + name + ".";
        }
    }
    									

    The @RolesAllowed annotation specifies that only users in the role of basicUser will be allowed to access the sayHello(String name) method. A @RolesAllowed annotation implicitly declares a role that will be referenced in the application, therefore, no @DeclareRoles annotation is required.

  • Adding Security Elements to the Deployment Descriptor

    To enable basic authentication for the service, add security elements to the application deployment descriptor, WEB-INF/web.xml. The security elements that need to be added to the deployment descriptor include the <security-constraint> and <login-config> elements:

    
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app>
    
        <listener>
            <listener-class>
                com.sun.xml.ws.transport.http.servlet.WSServletContextListener
            </listener-class>
        </listener>
    
        <servlet>
            <display-name>HelloService</display-name>
            <servlet-name>HelloService</servlet-name>
            <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>HelloService</servlet-name>
            <url-pattern>/hello</url-pattern>
        </servlet-mapping>
    
        <security-constraint>
            <display-name>SecurityConstraint</display-name>
            <web-resource-collection>
                <web-resource-name>WRCollection</web-resource-name>
                <url-pattern>/hello</url-pattern>
            </web-resource-collection>
            <auth-constraint>
                <role-name>basicUser</role-name>
            </auth-constraint>
            <user-data-constraint>
                <transport-guarantee>NONE</transport-guarantee>
            </user-data-constraint>
        </security-constraint>
    
        <login-config>
            <auth-constraint>BASIC</auth-constraint>
            <realm-name>file</realm-name>
        </login-config>
    
    </web-app>
    
    
    									

  • Linking Roles to Groups

    The role of basicUser has been defined for this application, but there is no group of basicUser defined for the Application Server. To map the role that is defined for the application (basicUser) to a group that is defined on the Application Server (user), add a <security-role-mapping> element to the runtime deployment descriptor, WEB-INF/sun-web.xml, as shown below:

    
    <?xml version="1.0" encoding="UTF-8"?>
    <sun-web-app error-url="">
        <context-root>/helloservice</context-root>
        <class-loader delegate="true"/>
        <security-role-mapping>
            <role-name>basicUser</role-name>
            <group-name>user</group-name>
        </security-role-mapping>
    </sun-web-app>
    
    									

  • Client

    Sample client against the secured web service:

    import javax.xml.ws.WebServiceRef;
    import javax.xml.ws.BindingProvider;
    
    public class HelloClient {
    
        @WebServiceRef(wsdlLocation="http://localhost:8080/helloservice/hello?wsdl")
        static HelloService service;
    
        public static void main(String[] args) {
            try {
                Hello port = service.getHelloPort();
    
                // Cast the proxy to a BindingProvider
                BindingProvider prov = (BindingProvider) port;
    
                prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "mikalai");
                prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "secret");
    
                String response = port.sayHello("Mikalai");
    
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }
    									

    There is one tricky aspect to the client: the use of the wsimport utility to generate the JAX-WS artifacts. The problem is that the web service's WSDL is also secured and therefore requires authentication for access. There are workarounds, of course. One option is to generate the WSDL locally by using the wsgen utility on the SIB. Another option is to get the WSDL from a nonsecure version of the service. The locally saved WSDL and its XSD are then fed into wsimport to generate the artifacts.

    The client application HelloClient uses the BindingProvider constants as keys for the username and password. JAX-WS runrime expects the lookup keys for the username and password to be the strings:

    javax.xml.ws.security.auth.username
    javax.xml.ws.security.auth.password
    									

    These are the values of the BindingProvider constant USERNAME_PROPERTY and the constant PASSWORD_PROPERTY, respectively.

1.1.7.  Compile and package the web service into a WAR file

blah-blah

1.1.8.  Deploy the web service into a Java EE servlet container

blah-blah

Professional hosting         'Oracle Certified Expert Web Services Developer 6' Quiz     Free SCDJWS 5.0 Guide


Hosting provided by PerfoHost: KVM VPS provider. See PefoHost's KVM VPS vs OpenVZ/Virtuozzo vs XEN VPS comparative chart.
CRM-exporter: Vehicle Database Script 1999-2011