Howto create your own webservice clients for PTV xServers

Some time ago the PTV xServer development team was asked whether it was possible to create a web service client without our provided java clients and the bundled cxf framework.
The simple answer is: Yes! Those who would like to take the adventure and try it themselves should read on…

What you need for this

The prerequisites for this little sample are the following:

  • A JDK 6, or newer,
  • A Maven2 or Maven3 installation,
  • PTV xRoute Server (the sample runs with xRoute 1.16 but it should work with older versions too)

Create a Maven project

First of all we create a new directory and set up a Maven project file named pom.xml with this content:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ptvag.xserver.xroute</groupId>
<artifactId>xRouteJAXWSClient</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>xRouteJAXWSClient</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>wsimport</id>
<phase>generate-sources</phase>
<configuration>
<tasks>
<mkdir dir="${basedir}/target/classes" />
<mkdir dir="${basedir}/target/generated-sources" />
<exec executable="wsimport" failonerror="true" dir="${basedir}">
<arg value="-quiet" />
<arg value="-d" />
<arg value="${basedir}/target/classes" />
<arg value="-s" />
<arg value="${basedir}/target/generated-sources" />
<arg value="http://localhost:50030/xroute/ws/XRoute?WSDL" />
</exec>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

This configuration expects to find your xRoute installation on localhost, but you can adjust the value in line 36 to your needs. Running maven in the new directory with

mvn clean install

will generate client classes for xRoute based on its WSDL. The wsimport plugin will take care of that conversion. The client classes will be generated to the directory target/generated-sources. So how can we test these client classes?
The pom has one dependency to JUnit which we can use to build a simple test.

Setup a simple Java test case

Create a new Java source file in src/test/java/com/ptvag/xserver/xroute named JAXWSTest.java. You can of course use another package structure but make sure you set up the folder structure src/test/java because Maven will look for test classes in this sub folder.
Here’s the content for our test:

package com.ptvag.xserver.xroute;

import java.net.URL;

import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;

import junit.framework.TestCase;

import org.junit.Test;

import com.ptvag.jabba.service.baseservices.ArrayOfCallerContextProperty;
import com.ptvag.jabba.service.baseservices.CallerContext;
import com.ptvag.jabba.service.baseservices.CallerContextProperty;
import com.ptvag.xserver.common.ArrayOfPoint;
import com.ptvag.xserver.common.PlainPoint;
import com.ptvag.xserver.common.Point;
import com.ptvag.xserver.xroute.jwsdp.XRouteWS;

public class JAXWSTest extends TestCase {

private static final String XROUTE_WSDL_LOCATION = "http://localhost:50030/xroute/ws/XRoute?WSDL";

public JAXWSTest(String name) {
super(name);
}

@Test
public void testSimpleCall() throws Exception {
WaypointDesc[] waypoints = new WaypointDesc[2];
waypoints[0] = new WaypointDesc();
PlainPoint pp = new PlainPoint();
pp.setX(685903);
pp.setY(6372958);
Point point = new Point();
point = new Point();
QName _plainPoint_QNAME = new QName("http://common.xserver.ptvag.com","point");
point.setPoint(new JAXBElement(_plainPoint_QNAME, PlainPoint.class, pp));
ArrayOfPoint arrayOfPoint = new ArrayOfPoint();
arrayOfPoint.getPoint().add(point);
waypoints[0].setWrappedCoords(arrayOfPoint);
waypoints[1] = new WaypointDesc();
PlainPoint pp1 = new PlainPoint();
pp1.setX(681013);
pp1.setY(6371680);
Point point1 = new Point();
point1 = new Point();
point1.setPoint(new JAXBElement(_plainPoint_QNAME, PlainPoint.class, pp1));
ArrayOfPoint arrayOfPoint1 = new ArrayOfPoint();
arrayOfPoint1.getPoint().add(point1);
waypoints[1].setWrappedCoords(arrayOfPoint1);
ResultListOptions details = new ResultListOptions();
details.setBinaryPathDesc(false);
details.setPolygon(true);
CallerContext cc = new CallerContext();
CallerContextProperty prop = new CallerContextProperty();
prop.setKey("CoordFormat");
prop.setValue("PTV_MERCATOR");
CallerContextProperty prop1 = new CallerContextProperty();
prop1.setKey("Profile");
prop1.setValue("carfast");
ArrayOfCallerContextProperty arrayOfCallerContextProperty = new ArrayOfCallerContextProperty();
arrayOfCallerContextProperty.getCallerContextProperty().add(prop);
arrayOfCallerContextProperty.getCallerContextProperty().add(prop1);
cc.setWrappedProperties(arrayOfCallerContextProperty);
ArrayOfWaypointDesc arrayOfWayPoints = new ArrayOfWaypointDesc();
arrayOfWayPoints.getWaypointDesc().add(waypoints[0]);
arrayOfWayPoints.getWaypointDesc().add(waypoints[1]);

URL url = new URL(XROUTE_WSDL_LOCATION);
QName qname = new QName("http://jwsdp.xroute.xserver.ptvag.com", "XRouteWSService");
QName xRouteWSPort = new QName("http://jwsdp.xroute.xserver.ptvag.com", "XRouteWSPort");
Service service = Service.create(url, qname);
XRouteWS xroute = service.getPort(xRouteWSPort, XRouteWS.class);
Route route = xroute.calculateRoute(arrayOfWayPoints, null, null, details, cc);
int distance = route.getInfo().getValue().getDistance();
assertEquals(4350, distance);
}

}

Again you can adjust the location of your xRoute installation by changing the value of the variable XROUTE_WSDL_LOCATION. The remainder of the code contains a test method which creates a simple request on the Luxembourg map. The request is actually based on a sample request which you can find in the raw request runner for xRoute.

The handling of arrays is a bit cumbersome. Arrays are always wrapped in classes with the prefix ArrayOf and ArrayOfArrayOf (for 2-dimensions). The setter and getter methods for arrays are prefixed with wrapped, for example setWrappedCoords. You do not see these classes and methods in the client classes provided by PTV because we hide this boilerplate code.

The last 8 lines of the test method set up the service interface XRouteWS and then the method calculateRoute is called. At the end the distance of the route is used to make an assertion.

Do I need this?

To be honest: No! Or to be more precise: You don’t need this in most cases. The client classes that we provide for our xServers should fit your needs. But in some cases our clients might run into dependency conflicts, especially if you are running in an environment with lots of provided dependencies such as an application server, or within a servlet container. Here, the JAX-WS clients are a good workaround as they only need a JDK and no other dependencies.

What’s next?

This was just a simple example. But it can easily be extended to all other PTV xServers. Just replace the WSDL in the pom file with a WSDL of PTV xLocate, PTV xTour or any other PTV xServer. Then run maven and start to write a new test case.

[ratings]