Skip to Content
Author's profile photo Christian Loos

Make your CAF service web-ready by giving it a RESTful façade

Modern client-side web frameworks and libraries like SAPUI5 are using REST services to load data from a server. If you want to consume existing business logic from these new web applications, you first need to make them REST-enabled.

For standard SAP applications, you can use SAP NetWeaver Gateway. But what about your own composite services built e.g. using the Composite Application Framework (CAF)?

In this blog, we will use the Apache Jersey library to expose a CAF Business Object as a RESTful web service.

Deploying Jersey

For a description on how to package and deploy the Jersey libraries to the SAP NetWeaver Application Server, please refer to this excellent blog by Werner Steyn.

It is recommended to wrap the External Library into its own Enterprise Application, and have it packaged in a separate Software Component so that it can be reused from multiple applications.

Don’t forget to remove the access restrictions to the DCs and its public parts, in order to make it available to other applications.

Creating a web module DC

The Jersey servlet needs a web.xml to be configured and deployed. Create a new web module DC in the software component which holds your CAF project.

Add a DC dependency from the CAF EAR DC to the new web DC so that it is included with the CAF application.

Enabling access to the CAF project

Since you want to reuse the existing CAF service, you need to be able to reference it from your new web module DC.

In the component properties of the CAF EAR DC, switch to the “Public Parts” tab, select the “client” public part and add permission for your web DC. Repeat this for all other public parts.

PP.png

Next, switch to the “Permissions” tab and again add permission for the web DC.

/wp-content/uploads/2013/05/permissions_214359.png

Setting DC dependencies

Now, switch to the component properties of your web DC and add the following DC dependencies:

  • caf/core/ear
  • caf/runtime/ear
  • jersey/ear (from the Software Component which contains the Jersey libraries)
  • tc/bl/exception/lib

You can test if everything works by building the CAF application. If the build is failing, check the build log for error messages.

Implementing the resource class

Now it’s time to actually implement the REST service. All you need is a plain Java class with some annotations. The JNDI name to look up the CAF EJB can be retrieved via the JNDI Browser in NWA.

The GET method simply all employees stored in the respective CAF table. Since Jersey supports POJOs, we can return the Employee object as-is and don’t need to create any wrapper objects.

package com.sap.demo.cafrest.employee;
import java.util.List;
import javax.naming.InitialContext;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.sap.demo.employee.modeled.Employee;
import com.sap.demo.employee.modeled.bonode.employee.employee.EmployeeServiceLocal;
@Path("/employees")
public class EmployeeResource {
      EmployeeServiceLocal employeeService;
      final String JNDI_NAME = "demo.sap.com/employee~ear/LOCAL/com.sap.demo.employee.modeled.bonode.employee.employee.Employee/com.sap.demo.employee.modeled.bonode.employee.employee.EmployeeServiceLocal";
      @GET
      @Produces(MediaType.APPLICATION_JSON)
      public List<Employee> getAllEmployees() {
            try {
                  InitialContext jndiContext = new javax.naming.InitialContext();
                  employeeService = (EmployeeServiceLocal) jndiContext.lookup(JNDI_NAME);
                  List<Employee> result = employeeService.findAll();
                  return result;
            } catch (Exception e) {
                  throw new RuntimeException(e);
            }
      }
}

In the code sample above, we only implement the method to get all objects. You can easily implement all CRUD and finder methods in a similar way using the respective annotations for GET, PUT, POST and DELETE. Check the Jersey documentation for more details.

This example uses a CAF business object service, but the same approach also works for application services.

Configuring the Jersey servlet

Finally, we need to configure the servlet container for Jersey. Open the web.xml of your web DC and add the following lines:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
      id="WebApp_ID" version="2.5">
      <display-name>CAF REST demo</display-name>
      <servlet>
            <servlet-name>Jersey REST Service</servlet-name>
            <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
            <init-param>
                  <param-name>com.sun.jersey.config.property.packages</param-name>
                  <param-value>org.codehaus.jackson.jaxrs;com.sap.demo.employee.modeled;com.sap.demo.cafrest.employee</param-value>
            </init-param>
            <init-param>
                  <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
                  <param-value>true</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
            <servlet-name>Jersey REST Service</servlet-name>
            <url-pattern>/rest/*</url-pattern>
      </servlet-mapping>
</web-app>

Via the parameter com.sun.jersey.api.json.POJOMappingFeature, we tell Jersey to use POJO mapping instead of JAXB annotations.

In the value for com.sun.jersey.config.property.packages, you need to add all Java packages containing the POJOs used in your CAF services. Otherwise the POJO to JSON mapping will not work.

Testing the service

Deploy the whole CAF application to the server. After deployment, you should be able to call the service from your browser:

/wp-content/uploads/2013/05/result_214360.png

If you get an error message, check the dev traces in the NWA Log Viewer.

Summary

Exposing a CAF service via REST requires only a few lines of code. The trickiest part is to make sure you have set all the right permissions and dependencies between the various DCs.

Assigned Tags

      5 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Bernd Speckmann
      Bernd Speckmann

      Great blog. Thank you!

      Author's profile photo Harald Schubert
      Harald Schubert

      Thanks for this post -- easy to follow and down to the point!

      -Harald

      Author's profile photo Bobu George Putheeckal
      Bobu George Putheeckal

      I think there is missing step, please correct me if i am wrong.

      We need to add the ejb module as a dependency in the web module.

      -Bobu

      Author's profile photo Christian Loos
      Christian Loos
      Blog Post Author

      Hi Bobu,

      I can't verify this right now, but isn't this implicitly handled when you add the dependency to the ear module?

      Regards,

      Christian

      Author's profile photo Biroj Patro
      Biroj Patro

      Hi Christian,

      Nice blog....

      I followed your instructions and added my web module to cafmodule/ear and deployed the file. When I run the URL for REST, I get the service not found/404 status error. Where am I going wrong ?

      Biroj