REST API

Building a SOAP-Based WebService in the Nuxeo Platform

Updated: July 31, 2019

Let's take the example of a simple Nuxeo WebService that exposes a method to create a document in the default repository. The user credentials are passed to the method to log in and open a core session.

The code samples used for this example can be found on GitHub.

WebService Interface

First you have to define the interface of your WebService, answering the question: "Which methods do I want to expose?" If we take a look at NuxeoSampleWS, a standard signature defines the createDocument method.

DocumentDescriptor createDocument(String username, String password,
            String parentPath, String type, String name) throws LoginException,
            ClientException;

The different parameters are:

  • username: used to log in and open a core session
  • password: used to log in and open a core session
  • parentPath: document parent path
  • type: document type
  • name: doc name

The return type DocumentDescriptor is a simple POJO containing minimal information about a document.

Webservice Implementation

You just need a few annotations from the javax.jws package to implement your SOAP based WebService.

@WebService

Allows you to define the actual WebService. You need to provide the following parameters:

  • name: the name of the WebService, used as the name of the wsdl:portType when mapped to WSDL 1.1.
  • serviceName: the service name of the WebService, used as the name of the wsdl:service when mapped to WSDL 1.1.

@SOAPBinding

Specifies the mapping of the WebService onto the SOAP message protocol. You can provide the following parameters:

  • style: defines the encoding style for messages send to and from the WebService. Keep the default value Style.DOCUMENT.
  • use: defines the formatting style for messages sent to and from the WebService. Keep the default value Use.LITERAL.

@WebMethod

Exposes a method as a WebService operation. Such a method must be public.

@WebParam

Maps a method parameter to a WebService operation parameter. You need to provide the name of the parameter.

Take a look at NuxeoSampleWSImpl which uses all these annotations:

@WebService(name = "NuxeoSampleWebServiceInterface", serviceName = "NuxeoSampleWebService")
@SOAPBinding(style = Style.DOCUMENT)
public class NuxeoSampleWSImpl implements NuxeoSampleWS {

    /** The serialVersionUID. */
    private static final long serialVersionUID = 7220394261331723630L;

    /**
     * {@inheritDoc}
     */
    @WebMethod
    public DocumentDescriptor createDocument(@WebParam(name = "username")
    String username, @WebParam(name = "password")
    String password, @WebParam(name = "parentPath")
    String parentPath, @WebParam(name = "name")
    String name, @WebParam(name = "type")
    String type) throws LoginException, ClientException {
       ...
    }
    ...
}

WebService End Point and URL Mapping

Finally you have to define your WebService as an end point mapped to an URL of the Nuxeo server so it can be accessed in HTTP. This is done by adding a contribution to the endpoint extension point of the org.nuxeo.ecm.platform.ws.WSEndpointManager component in your Nuxeo project.

Tomcat and JBoss 4.x distributions

<extension target="org.nuxeo.ecm.platform.ws.WSEndpointManager" point="endpoint">
  <endpoint name="nuxeosample"
    implementor="org.nuxeo.ecm.samples.ws.server.NuxeoSampleWSImpl"
    address="/nuxeosample" />
</extension>

Once your plugin is deployed in the Nuxeo server, the Nuxeo sample WebService WSDL should be available at http://server:port/nuxeo/webservices/nuxeosample?wsdl.

Advanced Configuration Requiring a Configuration XML File

Since we moved to Apache CXF as a WebService provider, we encapsulate the service definition in our contribution model to prevent CXF Spring dependency. Sometimes, you'll need a specific configuration that will require a configuration XML file, as described in their documentation.

Here are the steps to do that in a Nuxeo way:

  1. Add the following dependencies spring-core, spring-beans, spring-context, spring-aop, spring-expression and  spring-asm. Ideally, using a Nuxeo Package.
  2. Deploy your cxf.xml file in nuxeo.war/WEB-INF/classes, using the deployment-fragment.xml. And the file will be taken into account.

About Code Factorization

If you take a closer look at the NuxeoSampleWSImpl#createDocument method, you can see that most of the code is not "business"-related and could be factorized. Indeed, each time one makes a remote call to a Nuxeo WebService method, the following pattern must be applied:

  • log in using the provided credentials,
  • start a transaction,
  • open a core session,
  • do the job,
  • manage transaction rollback if an exception occurs when doing the job,
  • close the core session,
  • commit or rollback the transaction,
  • log out.

Which can be implemented as so:

// Login
LoginContext loginContext = Framework.login(username, password);

// Start transaction
TransactionHelper.startTransaction();

CoreSession session = null;
try {
    // Open a core session
    session = openSession();

    // Do the job: create a doc with the given params
    DocumentModel doc = session.createDocumentModel(parentPath, name,
        type);
    doc = session.createDocument(doc);
    session.save();

    return new DocumentDescriptor(doc);

} catch (ClientException ce) {
    // Set transaction for rollback if an exception occurs
    TransactionHelper.setTransactionRollbackOnly();
    throw ce;
} finally {
    // Close the core session
    if (session != null) {
        closeSession(session);
    }
    // Commit or rollback transaction
    TransactionHelper.commitOrRollbackTransaction();
    // Logout
    loginContext.logout();
}

A way to solve this issue could be to define an abstract class holding this pattern in a generic method, which would call an abstract method responsible for the "business" part of the code, in the same way as for UnrestrictedSessionRunner.

You can learn how to build a client-side SOAP based WebService in the Nuxeo Platform on the page Building a SOAP-Based WebService Client in Nuxeo.

We'd love to hear your thoughts!

All fields required