Skip to main content

Portable client application with locally packaged WSDL

Posted by vivekp on June 28, 2007 at 9:01 PM PDT

In the JAX-WS programming model to develop a web services client you would
compile the deployed WSDL using
wsimport and then at runtime the same WSDL is used to determine binding
information. The runtime accesses the WSDL over the
network, but sometimes because of the size of the WSDL or for whatever reason
(such as you want to edit it to fix workaround some bug, dangerous but we do it
sometimes) you may like to keep the WSDL locally and would expect the runtime to access the
local wsdl. It does not happen automatically.

There are the different ways in which you can provide the local WSDL information
to the JAX-WS runtime:

Use Service API to pass the WSDL information

Sample service creation using local WSDL

        URL baseUrl = client.MtomService.class.getResource(".");
        URL url = new URL(baseUrl, "../Soap11MtomUtf8.svc.xml");
        MtomService service = new MtomService(url, new QName("http://tempuri.org/", "MtomService"));
        IMtomTest proxy = service.getBasicHttpBindingIMtomTest();
        String input="Hello World";
        byte[] response = proxy.echoStringAsBinary(input);
   

Xml Catalog

  • Create a catalog file
  • META-INF/jax-ws-catalog.xml
  •         <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system">
                <system systemId="http://131.107.72.15/MTOM_Service_Indigo/Soap11MtomUtf8.svc?wsdl"
                        uri="Soap11MtomUtf8.svc.xml"/>
            </catalog>
           
       
  • For details see the details on
    using catalog
    scheme

This works well but requires some work, such as composing the right catalog file then package it
appropriately.

Using -wsdlLocation switch

There is another easy way to do it - just run wsimport with -wsdlLocation switch and provide the
WSDL location value which is relative to the generated Service class and you need to put this WSDL file at this relative location.

Let us try to create a client for the
NET 3.0
MTOM endpoint
. I am using Metro
1.0 M5
.

First I save the .NET 3.0 MTOM
WSDL locally then run
wsimport giving
the
relative location to where you will package the wsdl with your application

Sample wsimport command

        wsimport -keep -d build/classes -p client etc/Soap11MtomUtf8.svc.xml -wsdlLocation ../Soap11MtomUtf8.svc.xml
   
tip.png Why is the relative location is ../Soap11MtomUtf8.svc.xml? Basically the generated Service will be at
build/classes/client location and I would copy this WSDL at build/classes, see option -d and -p.

Here is excerpt from the generated MtomService class. You can see how the wsdlLocation value is generated inside
it and is used
internally to create the Service.

        /**
        * This class was generated by the JAX-WS RI.
        * JAX-WS RI 2.1.2-hudson-53-SNAPSHOT
        * Generated source version: 2.1
        *
        */
        @WebServiceClient(name = "MtomService", targetNamespace = "http://tempuri.org/", ../Soap11MtomUtf8.svc.xml")
        public class MtomService
        extends Service{

            private final static URL MTOMSERVICE_WSDL_LOCATION;
            private final static Logger logger = Logger.getLogger(client.MtomService.class.getName());

            static {
                URL url = null;
                try {
                    URL baseUrl;

                    baseUrl = client.MtomService.class.getResource(".");
                    url = new URL(baseUrl, "../Soap11MtomUtf8.svc.xml");
                } catch (MalformedURLException e) {
                    logger.warning("Failed to create URL for the wsdl Location: ../Soap11MtomUtf8.svc.xml");
                    logger.warning(e.getMessage());
                }
                MTOMSERVICE_WSDL_LOCATION = url;
            }

            public MtomService() {
                super(MTOMSERVICE_WSDL_LOCATION, new QName("http://tempuri.org/", "MtomService"));
            }

            ...
   

See Client.java below it invokes the .NET 3.0 service. You may notice here that you
dont need to enable MTOM explicitly. Metro bring in .NET 3.0 interop thru WSIT and due to this the MTOM policy assertions in
the .NET 3.0 WSDL, it correctly interpreted and the IMtomTest port is configured with
MTOM enabled.

package client;

import com.sun.xml.ws.transport.http.client.HttpTransportPipe;

/**
* Client that invokes .NET 3.0 MTOM endpoint using a local wsdl
*/
public class Client {

    public static void main(String[] args) {

        //enble SOAP Message logging
        HttpTransportPipe.dump = true;

        //Create IMtomTest proxy to invoke .NET 3.0 MTOM service
        IMtomTest proxy = new MtomService().getBasicHttpBindingIMtomTest();
        String input="Hello World";
        byte[] response = proxy.echoStringAsBinary(input);
        System.out.println("Sent: "+input+", Received: "+new String(response));
    }
}

Get the complete client bundle from
here
and see the enclosed Readme.txt for instructions on how to run it.

Related Topics >>

Comments

wsdllocation

The problem with JAX-WS RI 2.1.x was that when you use the wsdllocation flag, the Client default constructor failed when it was packaged in a jar file. Not sure why, but getResource(".") returns null from within a jar file, but a valid path when on the file system, even when the directory is included in the jar file.
JAX-WS RI 2.2 addresses this issue, and generates code that can live happily in a jar file with wsdllocation is used.