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.

Tuesday, April 7, 2009

Bookmark and Share

When using the JUnit task for Apache Ant I recently came across the following error:

1
2
3
4
5
6
7
8
9
10
...
[junit] Error occurred during initialization of VM
[junit] Could not reserve enough space for object heap
[junit] Could not create the Java virtual machine.
[junit] java.io.FileNotFoundException: /home/.../junitvmwatcher995964737.properties (No such file or directory)
[junit]     at java.io.FileInputStream.open(Native Method)
[junit]     at java.io.FileInputStream.(FileInputStream.java:106)
[junit]     at java.io.FileReader.(FileReader.java:55)
[junit]     at org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.executeAsForked(JUnitTask.java:1028)
...

At first I was rather distracted by the FileNotFoundException, but then I recognized that the message "Could not reserve enough space for object heap" might be a pointer to the actual problem.

My build file contained a target for the execution of JUnit tests roughly looking as follows:

1
2
3
4
5
6
7
8
9
10
11
12
...
<target name="junit" depends="jar">
    <junit printsummary="true" fork="true" forkmode="perTest" maxmemory="2048m">

        <classpath>...</classpath>

        <batchtest>
            <fileset dir="${src.dir}" includes="*Test.java"/>
        </batchtest>
    </junit>
</target>
...

When I decreased the value for the maxmemory attribute the error went away. I thought a rather large value here wouldn't do any harm, as I expected that only the actually required amount of memory would be allocated.

But obviously the JUnit task tries to allocate the total amount of memory up-front, causing the test to fail on my system, which only has 2 GB of RAM altogether.