Thursday, April 9, 2009

Bookmark and Share

JAX-WS based web services normally run on a JEE web container or application server. That's great for production purposes, as those servers provide a very high level of scalability, security infrastructure, monitoring facilities etc.

But during development repeated deployments to a JEE container can be rather time consuming. JAX-WS' Endpoint class provides an interesting alternative here, as it allows to host JAX-WS web services within plain Java SE applications.

A web service hosted that way can very easily be launched and debugged from within your IDE for instance, which is great for development and testing purposes.

If you go with the code-first approach for web service development, things are really straight-forward:

1
2
3
4
5
6
7
8
9
10
11
public class SimpleServer {

    public static void main(String[] args) throws Exception {

        Endpoint endpoint = Endpoint.create(new ExamplePort());
        endpoint.publish("http://localhost:8080/example_app/ExampleService");

        System.out.println("Published service at http://localhost:8080/example_app/ExampleService");
    }

}

All you have to do is to create the end point by passing an instance of the port to be published (a class annotated with @WebService) and call the end point's publish() method.

Things are slightly more complicated if you prefer the contract-first web service style, meaning you start building your service with a WSDL file describing the service's interface and then generate service/port classes for it. In that case you have to specify the service's WSDL file as well as the QNames of the service and port to be published:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class SimpleServer {

    public static void main(String[] args) throws Exception {

        URL wsdlResource = 
            SimpleServer.class.getResource("/WEB-INF/wsdl/example.wsdl");

        List<Source> metadata = new ArrayList<Source>();

        Source source = new StreamSource(wsdlResource.openStream());
        source.setSystemId(wsdlResource.toExternalForm());
        metadata.add(source);

        Map<String, Object> properties = new HashMap<String, Object>();

        properties.put(
            Endpoint.WSDL_PORT, 
            new QName(
                "http://www.yournamespace.com/example",
                "ExamplePort"));
        properties.put(
            Endpoint.WSDL_SERVICE, 
            new QName(
                "http://www.yournamespace.com/example",
                "ExampleService"));

        Endpoint endpoint = Endpoint.create(new ExamplePort());
        endpoint.setMetadata(metadata);
        endpoint.setProperties(properties);

        endpoint.publish("http://localhost:8080/example_app/ExampleService");

        System.out.println("Published service at http://localhost:8080/example_app/ExampleService");
    }

}

Having launched the service it's a good idea to inspect the WSDL published by the JAX-WS runtime (e.g. at http://localhost:8080/example_app/ExampleService?WSDL). When using the JAX-WS reference implementation (RI) the file always starts with the comment "Published by JAX-WS RI ...", but in the contract-first scenario this shouldn't be followed by "Generated by JAX-WS RI ...".

JAX-WS RI is rather picky with its configuration, and if something is wrong, the runtime silently switches over to code-first mode, meaning the WSDL file is not the original one but was dynamically created from the port class. A common reason for this is not specifying the service and port QNames properly.

Here it would be great to have some kind of "force contract-first mode" option, which prevents the service from starting at all, if something is wrong with the configuration.

3 comments:

Gerry Kaplan said...

Do you have an end-to-end example that I could follow. I try this out, but can't get it to work. It says it can't find the WSDL, even though I have verified the URL is correct.

Kirill Malyshev said...

Thanks for the sample! really helped me with similar (though more complicated) case

Anonymous said...

thank you very much for your snippet code that enabled us to publish the original hand crafted schemas (with restrictions)

it tooke me many hours (>10) of googling here and there uselessly

God bless you!