The Source for Java Technology Collaboration
User: Password:



Vivek Pandey

Vivek Pandey's Blog

Portable client application with locally packaged WSDL

Posted by vivekp on June 28, 2007 at 09:01 PM | Comments (4)

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.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Hi..I am dealing with a similiar situation right now..where I want the runtime to access the local wsdl. I wonder what is the difference between the catalog way and the wsdllocation way..the wsdllocation seems straightforward enough..

    Posted by: diippi on July 02, 2007 at 08:00 AM

  • See details on catalog at https://jax-ws.dev.java.net/nonav/2.1.2m1/docs/catalog-support.html. With wsdlLocation switch on wsimport, you can specify the relative path of your packaged wsdl, it goes in @WebServiceClient(wsdlLocation="...").

    Posted by: vivekp on July 03, 2007 at 08:23 AM

  • Hi, vivek. Great tech blog, BTW!

    Here's a problem for you to think about. Maybe you know the solution. I've downloaded the WSDL from the service provider and stored it as whatever.wsdl. The WSDL is not available from the service provider in my deployment environment, so I figure I'll just use "-wsdllocation whatever.wsdl" in wsimport to point the generated code at the WSDL. The generated *Service and *PortType get placed into the com.provider.whatever package. The *Service code wants whatever.wsdl also in the com.provider.whatever package.

    So, standalone, I am able to generate client calls. The code properly looks into my classpath at com/provider/whateer/whatever.wsdl, and all is happy.

    Then I jar all the client code up, including whatever.wsdl. I put it on my deployment environment (Tomcat 4), and set it up so that when I access some web page on my server, the client code gets run.

    Surprise! I get an exception:

    javax.xml.ws.WebServiceException: Failed to access the WSDL at: file:/C:/WINNT/system32/whatever.wsdl. It failed with:
    C:\WINNT\system32\whatever.wsdl (The system cannot find the file specified).

    So why didn't the system look into the jar file?

    Thanks,

    --Rob

    Posted by: autophile on July 23, 2007 at 11:19 AM

  • I've found that using the -wsdllocation path can be tricky when running inside a servlet container (Tomcat 5.5/6.0 for example) and trying to act as a client invoking a web service.

    The -wsdllocation is relative to the working directory you started Tomcat in.

    So if you start Tomcat from CATALINA_HOME\bin -wsdllocation needs to be:
    ../webapps/app_name/WEB-INF

    if your wsdl is packaged locally in your application's WEB-INF directory.

    Using a stand-alone client this is not an issue since you are controlling the working directory when the application starts up. But the dependency on the working directory makes this solution less than desirable when deploying to a servlet container. I am currently looking into using catalog files instead, but have had problems using them as well inside of a servlet container.

    Posted by: scottrobey on April 29, 2008 at 04:05 PM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds