Many of you may have noticed a gap in the documentation of Hana Cloud Platform development. There is a description of UI5 and how to build nice UIs with this HTML5 technology. And there is a description of how to build backend java based applications which starts with servlet technology?! Wouldn’t it be nice to have UI5 and let it communicate with the Java backend and not to build servlets anymore?

In fact if HCP would support Java EE 7 Web Profile instead of version 6 you would get JAX-RS support out of the box and can use the JSONModel in UI5 to communicate with your HCP backend. With version 6 you can still use JAX-RS but you have to include it yourself in your application.

I want to describe here as an overview whats need to get this done. As normal you need a dynamic Web project in your Eclipse as a start point. I have successfully used Jersey/Jackson as the implementation of the JAX-RS 2.0 standard. If you have a maven project inlude the dependencies as described on Jersey project page. If you don’t use maven just include the libs in WebContent/WEB-INF/lib as you would normally do.

So what do you need for JAX-RS to work for you? Lets assume you want to create one service class which responds to a HTTP GET on the relative path “/rest/ping” where “rest” shall be the path of all rest based calls and ping the specific part.

So you have to do some work in your web.xml first:


  <servlet>
    <servlet-name>com.sap.myapp.MyApplication</servlet-name>
    <init-param>
      <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
      <param-value>true</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>com.sap.myapp.MyApplication</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>

This defines a special servlet that you have to write later on and defines that all your REST based services are reachable under the path of “/rest/*” as we wanted to do.

So lets create the class com.sap.myapp.MyApplication which has to extend javax.ws.rs.core.Application, a standard class of JAX-RS. It should look like the following:


package com.sap.myapp;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;

/**
* JAX-RS Application
*/
public class MyApplication extends Application {

  public Set<Class<?>> getClasses() {
    Set<Class<?>> s = new HashSet<Class<?>>();
    s.add(PingService.class);
    return s;
  }
}

Here you have to add EVERY service class you write. Normally you would divide your services in several classes. We now have to write the PingService thats added there.


/**
* REST
*/
package com.sap.myapp;
import javax.servlet.ServletException;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
/**
* JAX-RS Service for ping
*/
@Path("/ping")
public class PingService {
  @GET
  @Path("/")
  @Produces(MediaType.TEXT_PLAIN)
  public Response ping() throws ServletException {
    return Response.ok().entity("pong").build();
  }
}

So this service listens on everything on the relative path “/ping”. Together with the declaration in web.xml the relative path is now: /rest/ping/*

It has one method that is called on a HTTP GET request and it produces plain text. Normally you would produce JSON but thats something I will keep for part two. Just a hint in the return you can add any object in the entity call instead of a static string that gets transformed to JSON automatically!

Thats it you created your first REST service.

In Part 2 we add salt to the soup – EJBs to access your Database as described in the other tutorials!

To report this post you need to login first.

5 Comments

You must be Logged on to comment or reply to a post.

  1. Chris Paine

    Thanks for sharing Frank.

    I’ve been using Spring MVC rather than JAX-RS, mainly because it fits nicely with the Spring Data JPA stuff I’m using, although I believe it is possible to mix and match.

    I’m wondering why you didn’t use jersey/spring to manage auto discovery of all your annotated classes and have instead built your own handler? Any particular efficiency gains?

    Cheers,

    Chris

    (0) 
    1. Frank Schulten Post author

      The main reason for that is just I haven’t  used spring so much 😉 By using JNDI I would not need to introduce spring and also using spring for this blog would maybe confuse more, as my focus is on Jersey for Rest services.

      But yes if you already use spring, then you can use the mentioned feature!

      (0) 
  2. Pankaj Bagul

    Hi Frank,

    I followed above steps but when I tried executing, got 404 error. Could you please explain how to create dynamic web project from scratch and what all jars/dependancies are required for this application?

    Regards,

    Pankaj

    (0) 
  3. saurabh raja

    Hi Frank,

     

    Executed the same…getting error 404.

    web.xml ->

    <servlet>
    <servlet-name>org.saurabh.rest.MyApplication</servlet-name>
    <servlet-class></servlet-class>
    <init-param>
    <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
    <param-value>true</param-value>
    </init-param>
    </servlet>
    <servlet-mapping>
    <servlet-name>org.saurabh.rest.MyApplication</servlet-name>
    <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

    Server log trace :

    java.lang.ClassCastException: Cannot cast class org.saurabh.rest.MyApplication to interface javax.servlet.Servlet
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1133)
    at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:853)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:134)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at com.sap.core.jpaas.security.auth.service.lib.AbstractAuthenticator.invoke(AbstractAuthenticator.java:170)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:958)
    at com.sap.core.tenant.valve.TenantValidationValve.invokeNextValve(TenantValidationValve.java:168)
    at com.sap.core.tenant.valve.TenantValidationValve.invoke(TenantValidationValve.java:94)
    at com.sap.js.statistics.tomcat.valve.RequestTracingValve.invoke(RequestTracingValve.java:38)
    at com.sap.core.js.monitoring.tomcat.valve.RequestTracingValve.invoke(RequestTracingValve.java:27)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:452)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1087)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1756)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1715)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:807)

     

     

     

    Could you please help on the same.Thanks

    (0) 

Leave a Reply