Implementing the JAX-RS service of the adapter

To implement the JAX-RS service of the adapter, you must first implement the JAX-RS application class, then implement the JAX-RS resources classes.

Implementing the JAX-RS application class

About this task

The JAX-RS application class tells the JAX-RS framework which resources are included in the application. Any resource can have a separate set of URLs. Traditionally the application class should extend javax.ws.rs.core.Application and implement the method getClasses or getSingletons that will be called by the JAX-RS framework to get information about this application. In the following example, a JAX-RS application defines three resources: Resource1, UsersResource, and MyResourceSingleton. The first two are provided by the getClasses method, while the last is provided by getSingletons:
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
  
public class MyApplication extends Application{
      
    @Override
    public Set<Class<?>> getClasses() {
        HashSet<Class<?>> classes = new HashSet<Class<?>>();
        classes.add(Resource1.class);
        classes.add(UsersResource.class);
        return classes;
    }
      
    @Override
    public Set<Object> getSingletons() {
        Set<Object> singletons = new HashSet<Object>();
        singletons.add(MyResourceSingleton.getInstance());
        return singletons;
    }
}

An alternative to using the javax.ws.rs.core.Application is to use com.worklight.wink.extensions.MFPJAXRSApplication. In the following example, it is not necessary to put all the resources classes (or singletons) in a list, because MFPJAXRSApplication scans the package that is returned by the getPackageToScan method for JAX-RS resources and creates the list automatically. Additionally, its init method is called by IBM MobileFirst™ Platform Server as soon as the adapter is deployed (before serving has begun) and when the MobileFirst runtime starts up:

import com.worklight.wink.extensions.MFPJAXRSApplication;
public class MyApplication2 extends MFPJAXRSApplication{
    @Override
    protected void init() throws Exception {
        //Perform initialization
    }
      
    @Override
    protected String getPackageToScan() {
        return getClass().getPackage().getName();
    }
}

Implementing a JAX-RS resource

About this task

A JAX-RS resource is a POJO (plain old Java object) which is mapped to a root URL and has Java methods for serving requests to this root URL and its sub-URLs. For example:
import java.util.ArrayList;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
 
@Path("/users")
//This is the root URL of the resource ("/users")
public class UsersResource {
    //Instead of this static field, it could be a users DAO that works with Database or cloud storage
    static ArrayList<User> users = new ArrayList<User>();
     
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    //This will serve: GET /users
    public ArrayList<User> getUsers(){
        return users;
    }
     
    @Path("/{userId}")
    @Produces(MediaType.APPLICATION_JSON)
    //This will serve: GET /users/{userId}
    public User getUser(@PathParam("userId") String userId){
        return findUserById(userId);
    }
 
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    //This will serve: POST /users
    public void addUser(User u) {
        users.add(u);
    }
 
    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    //This will serve: PUT /users
    public Response updateUser(User u) {
        User user = findUserById(u.getId());
        if (user == null){
            return Response.status(Status.NOT_FOUND)
                           .entity("User with ID: "+u.getId()+" not found")
                           .build();
        }
        users.remove(user);
        users.add(u);
        return Response.ok().build();
    }
 
    @DELETE
    @Path("/{userId}")
    //This will serve: DELETE /users/{userId}
    public void deleteUser(@PathParam("userId") String userId){
        User user = findUserById(userId);
        users.remove(user);
    }
     
    private User findUserById(String userId) {
        //TODO implement...
        return null;
    }
}
The resource just shown is mapped to the URL /users and serves the following requests:
Table 1. Resource requests
Request Description
GET /users Gets all users list
POST /user Adds a new user
GET /users/{id} Gets a specific user with id id
PUT /users Updates an existing user
DELETE /users/{id} Deletes a user with id id

The JAX-RS framework does the mapping from the simple Java object User to a JSON object and conversely, making it easier for the service developer to use without taking care of repeating conversion-related code. The implementation also helps in extracting parameter values from the URL and from the query string without having to parse it manually.

Security configuration of a JAX-RS resource

About this task

A JAX-RS adapter resource is protected by default by the MobileFirst security framework, meaning that access to the resource requires a valid OAuth access token. You can configure the resource protection by using the @OAuthSecurity annotation of the MobileFirst Java server-side com.worklight.core.auth package to assign a custom security scope, or to disable resource protection. The annotation can be applied either to a specific resource method or to an entire resource class. For detailed usage instructions, see the annotation's API reference.
Examples
Using @OAuthSecurity at the resource class level
To disable the default protection of the UsersResource class that was used in the previous examples, and make all resource procedures in this class unprotected, add the OAuthSecurity annotation to the class definition, and set the annotation's enabled element to false:
@OAuthSecurity(enabled=false)
The annotation should be added above the class definition, as shown in the following example:
@Path("/users")
@OAuthSecurity(enabled=false)
//This is the root URL of the resource ("/users")
public class UsersResource {
...
Using @OAuthSecurity at the method level
Suppose that you want to disable protection of the user's resource for read operations, but protect the add, edit, and delete user operations. To do so, add the @OAuthSecurity annotation with the enabled element set to false at the class level, and then add the annotation to the methods that you want to protect to override the class annotation. In the following example, the addUser, updateUser, and deleteUser methods are protected by an adminRealm scope:
@Path("/users")
@OAuthSecurity(enabled=false)
//This is the root URL of the resource ("/users")
public class UsersResource {
      
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    //This will serve: GET /users
    public ArrayList<User> getUsers(){
        ...
    }
      
    @Path("/{userId}")
    @Produces(MediaType.APPLICATION_JSON)
    //This will serve: GET /users/{userId}
    public User getUser(@PathParam("userId") String userId){
       ...
    }
  
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @OAuthSecurity(scope="adminRealm")
    //This will serve: POST /users
    public void addUser(User u) {
       ...
    }
  
    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    @OAuthSecurity(scope="adminRealm")
    //This will serve: PUT /users
    public Response updateUser(User u) {
        ...
    }
  
    @DELETE
    @Path("/{userId}")
    @OAuthSecurity(scope="adminRealm")
    //This will serve: DELETE /users/{userId}
    public void deleteUser(@PathParam("userId") String userId){
        ...
    }
      
    ...
}