Getting started with a Java client for TeamMentor Web Services

The first step in getting BDD-Security to test TeamMentor Web Services, is of course to create a Java WS client.  One of the reasons for Java’s awesomeness is all the libraries 🙂  For WS, there are three main contenders: Apache Axis2, Metro (the reference implementation) and Apache CXF.  I went with CXF since it seems to offer the most flexibility and tooling without being overly complicated… in fact it was really easy to get started:

Step 1: Download the WSDL for TeamMentor and save it in src/main/resources

wget http://172.16.1.128:8008/Aspx_Pages/TM_WebServices.asmx?wsdl -O src/main/resources/TM_WebServices.wsdl
--2012-05-11 09:07:09-- http://172.16.1.128:8008/Aspx_Pages/TM_WebServices.asmx?wsdl
Connecting to 172.16.1.128:8008... connected.
HTTP request sent, awaiting response... 200 OK
Length: 225475 (220K) [text/xml]
Saving to: `src/main/resources/TM_WebServices.wsdl'
100%[=================================================================================================================================================================>] 225,475 1.33M/s in 0.2s

2012-05-11 09:07:09 (1.33 MB/s) - `src/main/resources/TM_WebServices.wsdl' saved [225475/225475]

Step 2: Add Apache CXF capabilities and configuration to maven pom.xml
Dependencies:

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
    <version>${cxf.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http</artifactId>
    <version>${cxf.version}</version>
</dependency>

Code generation plugin (this will generate Java from the WSDL):

<plugin>
     <groupId>org.apache.cxf</groupId>
     <artifactId>cxf-codegen-plugin</artifactId>
     <version>${cxf.version}</version>
     <executions>
         <execution>
             <goals>
                 <goal>wsdl2java</goal>
             </goals>
             <configuration>
                 <sourceRoot>${basedir}/target/generated-sources/cxf</sourceRoot>
                 <wsdlOptions>
                     <wsdlOption>
                         <wsdl>
                             ${basedir}/src/main/resources/TM_WebServices.wsdl
                         </wsdl>
                     </wsdlOption>
                 </wsdlOptions>
             </configuration>
         </execution>
     </executions>
 </plugin>

Step 3: Generate Java from WSDL

mvn clean generate-sources compile

We now have Java classes that represent all the web service types and services. For the young new hipsters who thing statically typed languages are boring, code hinting of the API in an IDE is just one of the reasons it’s not 😉

Step 4: Write a simple JUnit test to prove we can connect

public class TeamMentorWSTest {
    private static final QName SERVICE_NAME = new QName("http://tempuri.org/", "TM_WebServices");
    TMWebServicesSoap port;
    TMUser currentUser;

    @Before
    public void setup() {
        URL wsdlURL = TMWebServices.WSDL_LOCATION;
        TMWebServices ss = new TMWebServices(wsdlURL, SERVICE_NAME);
        port = ss.getTMWebServicesSoap();
        ((BindingProvider)port).getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true);
    }

    public void printDetails() {
        currentUser = port.currentUser();
        System.out.println(currentUser.getFirstName() + " " + currentUser.getLastName());
        System.out.println("Group ID: " + currentUser.getGroupID());
        System.out.println(port.currentSessionID());
    }

    @Test
    public void testLoginOk() {
        port.loginPwdInClearText("admin", "!!tmadmin");
        printDetails();
        assertEquals("John",currentUser.getFirstName());
        port.logout();

        port.loginPwdInClearText("reader", "!!tmreader");
        printDetails();
        assertEquals("Peter",currentUser.getFirstName());
        port.logout();

        port.loginPwdInClearText("editor", "!!tmeditor");
        printDetails();
        assertEquals("Joe",currentUser.getFirstName());
        port.logout();
    }
}

Running the test produces:

May 11, 2012 9:34:25 AM org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL
INFO: Creating Service {http://tempuri.org/}TM_WebServices from WSDL: file:/Users/stephen/data/src/bdd-teammentor/src/main/resources/TM_WebServices.wsdl
John Smith
Group ID: 1
4b78cfe0-315e-4ab1-9d13-05e0c9b824f6
Peter Smith
Group ID: 2
38d9c658-6025-4eea-b751-59e5eb11df53
Joe Jones
Group ID: 3
3d36833a-d17c-495f-8fc8-9a5f800559a6

The JUnit code is all pretty much standard CXF setup stuff, with the exception of:

 ((BindingProvider)port).getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true);

TeamMentor uses cookies to maintain a session for the web services, this just enables this functionality in the client.

So we now have a strongly typed client that can interact with the TeamMentor web services, pretty good for a few lines of code. Next up, will be integration into BDD-Security.

Update on adding CSRF tokens

Setting the CSRFToken turned out to be straightforward: Grab it from the currentUser() and set it before calling protected requests:

private void setCSRFToken() {
    Map<String, List<String>> headers = new HashMap<String, List<String>>();
    headers.put("CSRF_Token", Arrays.asList(port.currentUser().getCSRFToken()));
    ClientProxy.getClient(port).getRequestContext().put(Message.PROTOCOL_HEADERS, headers);
}

@Test
public void testGetUserByName() {
    port.loginPwdInClearText("admin", "!!tmadmin");
    setCSRFToken();
    TMUser user = port.getUserByName("reader");
    assertEquals("Peter",user.getFirstName());

    user = port.getUserByName("editor");
    assertEquals("Joe",user.getFirstName());

    port.logout();
}
Advertisements
This entry was posted in UnitTests, WebServices and tagged , , . Bookmark the permalink.

5 Responses to Getting started with a Java client for TeamMentor Web Services

  1. Dinis Cruz says:

    Great start , but there are still a couple curve-balls in there 🙂

    For example you will need to add the CSRF token to the web requests, or you won’t be able to invoke any authenticated services.

    • stephendv says:

      Ah! Good to know, that’ll save me some swearing when I try to make requests that don’t work. I’ll check Arvind’s code for some examples.

  2. stephendv says:

    Either MS can’t create WSDLs or Apache CXF can’t parse them. Had to write an interceptor for CXF to strip out the SOAPAction header, else you can’t perform more than one operation on the same service 😦
    It’s a nasty solution hopefully someone comes up with something more elegant: https://issues.apache.org/jira/browse/CXF-4046

  3. Pingback: Configuring BDD-Security to test TeamMentor Web Services | TeamMentor Development and Testing

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s