Search code examples
xsdwsdljax-ws

xsd schema not presented by wsdl


I'm developing WebService with JAX-WS(i'm using wsimport goal on jaxws-maven-plugin). I wrote a WSDL that imports a XSD schema.

WEB-INF/wsdl/service.wsdl
WEB-INF/wsdl/service.xsd

Also I generated web service classes and created endpoint and all. Everything worked great so far. When I ran my service on Tomcat 7 everything is ok. I can access a wsdl in my browser from:

http://localhost:8080/webService/servlet-url?wsdl

but I cannot get access to a xsd schema. The problem is in this wsdl:

<xsd:schema>
<xsd:import namespace="http://ws.service/domain/1.0" schemaLocation="service.xsd"/>
</xsd:schema>

Of course during generation of classes wsdl and xsd are on local path but i want them to be remotely accessible when web service is running. I know that schemaLocation should be something like this "http://localhost:8080/webService/servlet-url?xsd=1".

In wsdl presented in browser import schould look like:

<xsd:schema>
    <xsd:import namespace="http://ws.service/domain/1.0" schemaLocation="http://localhost:8080/webService/servlet-url?wsdl&resource=service.xsd"/>
    </xsd:schema>

localhost:8080/webService/servlet?wsdl gives me:

wsdl:definitions targetNamespace="http://ws.serv.com/Service/1.0" name="emuiaService">         
<wsdl:types>
    <xsd:schema>
        <xsd:import namespace="http://ws.serv.com/Service/domain/1.0" schemaLocation="schema.xsd"/>
    </xsd:schema>
</wsdl:types>
<wsdl:message name="halloMsg">
    <wsdl:part name="parameters" element="dom:halloRequest"/>
</wsdl:message>
<wsdl:message name="halloResponseMsg">
    <wsdl:part name="return" element="dom:halloResponse"/>
</wsdl:message>

and so on...


Solution

  • I almost can't believe that this was such a difficult problem to solve!

    I've been googling like mad to find a solution to exactly this problem! Then I've been struggling really hard to find a solution on my own. By debugger-stepping through the java-6-openjdk's default javax.xml.ws.spi.Provider implementation (the "factory" in the JRE that creates the javax.xml.ws.Endpoint objects that you use for publishing web services) I finally learnt some things, which helped me to craft a solution that at least works in Java SE, at least in my current JRE, which is:

    java version "1.6.0_33"
    OpenJDK Runtime Environment (IcedTea6 1.13.5) (6b33-1.13.5-1ubuntu0.12.04)
    OpenJDK Server VM (build 23.25-b01, mixed mode)
    

    Whether this solution is usable in Java EE I don't know yet.

    Here is how I solved it:

    package myservice;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.URL;
    import java.util.Arrays;
    import javax.xml.transform.Source;
    import javax.xml.transform.stream.StreamSource;
    import javax.xml.ws.Endpoint;
    
    public class App 
    {
        private static final String MY_SERVICE_XSD = "/wsdl/MyService.xsd";
    
        public static void main( String[] args )
        {
            Endpoint ep = Endpoint.create(new MyEndpointImpl());
    
            ep.setMetadata(Arrays.asList(sourceFromResource(MY_SERVICE_XSD)));
    
            ep.publish("http://localhost:8080/svc/hello");
        }
    
        private static Source sourceFromResource(String name) {
            URL resource = App.class.getResource(name);
            String systemId = resource.toExternalForm();
            InputStream inputStream;
            try {
                inputStream = resource.openStream();
            } catch (IOException e) {
                throw new RuntimeException("Failed to create InputStream from resource \""+ name +"\"", e);
            }
            return new StreamSource(inputStream, systemId);
        }
    }
    

    The crucial thing is that I first use method Endpoint#create (not Endpoint#publish) to get an unpublished Endpoint. Then I add the XSD-file as "meta data" to the (still unpublished) Endpoint (code "ep.setMetaData(...)"). Then I publish the endpoint (code "ep.publish(...)").

    Now when I access http://localhost:8080/svc/hello?wsdl I get:

        <definitions targetNamespace="http://somewhere.net/my/namespace" name="MyService">
            <types>
                <xsd:schema>
                    <xsd:import namespace="http://somewhere.net/my/namespace"
                                schemaLocation="http://localhost:8080/svc/hello?xsd=1"/>
                </xsd:schema>
            </types>
                      ...
        </definitions>
    

    and my XSD-file is available from http://localhost:8080/svc/hello?xsd=1!

    Note that my MyService.wsdl file on disk still contains:

                <xsd:schema>
                    <xsd:import namespace="http://somewhere.net/my/namespace"
                                schemaLocation="MyService.xsd"></xsd:import>
                </xsd:schema>