Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The URIs that take a parameter can be used directly from the browser or a HTML type form (this includes javascript).  On a slightly tangential note, I have marked the createUser() @Path("/cu/{param}") method with a GET, even though it's actually a POST under HTTP definitions, this because if you attempt to inoke this method from the browser's URL field, the browser will send a GET and not a POST command.  Marking the method as a POST will cause the server to return a HTTP 405 - method not allowed.

Using both <base url>/user/xx/{param} and <base url>/user/xx is not necessary.  I have done this so I can test the service's methods without having to write a Java client.  When I program the client side I will only be using the <base url>/user/xx URI form.

The URIs that don't have a parameter are used in service to service interactions passing JSON strings.  For each of these interactions, the simplest way to specify the contract is through a Java class.  For example the @POST /cu entry point has the following Java class

...

I know that under strict ReSTful architecture, there should be no hint of the service being provided in the URI naming (in other words avoid rpc style naming conventions), to this end I have mapped eah URI to one and only one HTTP command.

Under the hood

Let's exam the following service entry points

Info
titleExample code

@GET
@Path("/cu/{user}")
@Produces(MediaType.APPLICATION_JSON)
public Response createUser(@PathParam("user") String userId)
{
      User usr = new User(userId, genPassword());

      return __createUser(usr);
}

@POST
@Path("/cu")
@Consumes(MediaType.APPLICATION_JSON)
public Response createUserFromObject(User usr)
{
      return __createUser(usr);
}

Essentially I have created two entry points to the same service __createUser() on the same interface class UserRestService.  I am going to repeat this pattern for all the other services I want to expose.  This is a simple case of refactoring the interfaces methods.

The __createUser() method looks like this

Code Block
languagejava
titleCode Sample __createUser()
linenumberstrue
    private Response    __createUser( User usr )
    {
        Response resp;
        try
        {
            DBConnector connector = DBConnector.getConnector();
            connector.loadAndConnect();

            UserHandler.getLoader().addUser(connector.getConnection(), usr);
            
            resp = Response.status(200).entity(usr).build();
        } catch (IOException ex)
        {
            resp = Response.status(500).entity(new SimpleErrorMessage("CANNOT ADD USER - SERVER PROBLEM")).build();
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ResponseException ex)
        {
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
            resp = Response.status(500).entity(ex.getResponse()).build();
        } catch (SQLException ex)
        {
            resp = Response.status(409).entity(new SimpleErrorMessage(usr.getUserID() + " CANNOT BE ADDED - ALREADY EXIST")).build();
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
        }
        return resp;
    }

I didn't use Java 8 exception multi catch statements as I wanted to report different messages back to the client.

The call at line 6 is to a singleton.  We could have used non singleton implementation and this would have worked to, but backend implementation works in a non webservice context too, such as with JSPs.

Notice the error codes that I am returning in the reponse, see http://www.restapitutorial.com/httpstatuscodes.html for valid codes

Client Code

Here we present several examples of client side code 

Code Block
languagejava
titleCode Sample invoking a POST - to find a user
linenumberstrue
package com.celestial.jaxrs.client;

import com.celestial.dbankbusinessobjects.User;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.json.JSONConfiguration;

/**
 *
 * @author Selvyn
 */
public class TestServices
{
    public static void main(String[] args)
    {
        try
        {
            User usr = new User("David", "PP-WW-QQ");

            ClientConfig clientConfig = new DefaultClientConfig();

            clientConfig.getFeatures().put(
                    JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);

            Client client = Client.create(clientConfig);

            WebResource webResource = client
                    .resource("http://localhost:8084/dbwstier/dbrest/user/fu");

            ClientResponse response = webResource.accept("application/json")
                    .type("application/json").post(ClientResponse.class, usr);

            if (response.getStatus() != 201)
            {
                throw new RuntimeException("Failed : HTTP error code : "
                        + response.getStatus());
            }

            String output = response.getEntity(String.class);

            System.out.println("Server response .... \n");
            System.out.println(output);
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

The next examples only show the body changed code

Code Block
languagejava
firstline26
titleSample Code invoking a DELETE - to remove a user
linenumberstrue
            User us = new User("penny", "leonard");

            ClientConfig clientConfig = new DefaultClientConfig();

            clientConfig.getFeatures().put(
                    JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);

            Client client = Client.create(clientConfig);

            WebResource webResource = client
                    .resource("http://localhost:8084/dbwstier/dbrest/user/du");

            ClientResponse response = webResource.accept("application/json")
                    .type("application/json").delete(ClientResponse.class, us);

            if (response.getStatus() != 200)
            {
                throw new RuntimeException("Failed : HTTP error code : "
                        + response.getStatus());
            }

            String output = response.getEntity(String.class);

            System.out.println("Server response .... \n");
            System.out.println(output);


Code Block
languagejava
titleSample Code invoking a POST - add a user
linenumberstrue
            User us = new User("David", "");

            ClientConfig clientConfig = new DefaultClientConfig();

            clientConfig.getFeatures().put(
                    JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);

            Client client = Client.create(clientConfig);

            WebResource webResource = client
                    .resource("http://localhost:8084/dbwstier/dbrest/user/cu");

            ClientResponse response = webResource.accept("application/json")
                    .type("application/json").post(ClientResponse.class, us);

            if (response.getStatus() != 201)
            {
                throw new RuntimeException("Failed : HTTP error code : "
                        + response.getStatus());
            }

            String output = response.getEntity(String.class);

            System.out.println("Server response .... \n");
            System.out.println(output);

To update a record we are going to use HTTP PUT command

Code Block
languagejava
firstline26
titleSample Code invoking a PUT - update a user
linenumberstrue
            User oldUser = new User("David", "ppp");
            User newUser = new User("David", "PP-XX-YY");
            UserMap umap = new UserMap( oldUser, newUser );

            ClientConfig clientConfig = new DefaultClientConfig();

            clientConfig.getFeatures().put(
                    JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);

            Client client = Client.create(clientConfig);

            WebResource webResource = client
                    .resource("http://localhost:8084/dbwstier/dbrest/user/uu");

            ClientResponse response = webResource.accept("application/json")
                    .type("application/json").put(ClientResponse.class, umap);

            if (response.getStatus() != 200)
            {
                throw new RuntimeException("Failed : HTTP error code : "
                        + response.getStatus());
            }

            String output = response.getEntity(String.class);

            System.out.println("Server response .... \n");
            System.out.println(output);

Notice the new class UserMap at line 28

Code Block
languagejava
titleCode Sample - UserMap
public class UserMap
{
    public  User    oldUser;
    public  User    newUser;
    
    public  UserMap(){}
    
    public  UserMap( User oldU, User newU )
    {
        oldUser = oldU;
        newUser = newU;
    }
}

This will be a carrier object, holding two objects of type User.

Let's see the full server side service interface

Code Block
languagejava
titleCode Sample - UserRestService
linenumberstrue
collapsetrue
package dbk.webservices;

/**
 *
 * @author Selvyn
 */
import com.celestial.dbankbusinessobjects.User;
import com.celestial.dbankbusinessobjects.UserMap;
import com.celestial.util.objects.SimpleErrorMessage;
import dbk.dbutils.DBConnector;
import dbk.dbutils.ResponseException;
import dbk.dbutils.UserHandler;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
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;

@Path("/user")
public class UserRestServices
{

    private String genPassword()
    {
        String result = "";
        Random gen = new Random();

        for (int x = 0; x < 8; x++)
        {
            result += (char) (gen.nextInt(26) + 'A');
        }

        return result;
    }

    @GET
    @Path("/sayhello")
    @Produces(MediaType.TEXT_HTML)
    public String sayHtmlHelloTest()
    {
        return "<html> " + "<title>" + "Hello World" + "</title>"
                + "<body><h1>" + "Hello from the Deutsche Bank DB Tier" + "</h1></body>" + "</html> ";
    }

    @GET
    @Path("/cu/{user}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response createUser(@PathParam("user") String userId)
    {
        User usr = new User(userId, genPassword());
        
        return __createUser(usr);
    }

    @POST
    @Path("/cu")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response createUserFromObject(User usr)
    {
        usr.setUserPwd(genPassword());
        return __createUser(usr);
    }
    
    private Response    __createUser( User usr )
    {
        Response resp;
        try
        {
            DBConnector connector = DBConnector.getConnector();
            connector.loadAndConnect();

            UserHandler.getLoader().addUser(connector.getConnection(), usr);
            
            resp = Response.status(201).entity(usr).build();
        } catch (IOException ex)
        {
            resp = Response.status(500).entity(new SimpleErrorMessage("CANNOT ADD USER - SERVER PROBLEM")).build();
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ResponseException ex)
        {
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
            resp = Response.status(500).entity(ex.getResponse()).build();
        } catch (SQLException ex)
        {
            resp = Response.status(409).entity(new SimpleErrorMessage(usr.getUserID() + " CANNOT BE ADDED - ALREADY EXIST")).build();
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
        }
        return resp;
    }

    @DELETE
    @Path("/du")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response deleteUser(User usr)
    {
        Response resp;
        try
        {
            DBConnector connector = DBConnector.getConnector();
            connector.loadAndConnect();

            UserHandler.getLoader().deleteUser(connector.getConnection(), usr);
            resp = Response.status(200).entity( usr ).build();
        } catch (IOException ex)
        {
            resp = Response.status(500).entity(new SimpleErrorMessage("CANNOT DELETE USER - SERVER PROBLEM")).build();
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ResponseException ex)
        {
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
            resp = Response.status(200).entity(ex.getResponse()).build();
        } catch (SQLException ex)
        {
            resp = Response.status(409).entity(new SimpleErrorMessage(usr.getUserID() + " CANNOT BE DELETD - USER DOES NOT EXIST")).build();
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
        }
        return resp;
    }

    @PUT
    @Path("/uu")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response updateUserFromObject(UserMap umap)
    {
        return __updateUser( umap );
    }

    @GET
    @Path("/uu/{oldid}/{oldpwd}/{newid}/{newpwd}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response updateUser( @PathParam("oldid") String oldId, 
                                @PathParam("oldpwd") String oldpwd,
                                @PathParam("newid") String newId, 
                                @PathParam("newpwd") String newpwd)
    {
        User oldUser = new User( oldId, oldpwd );
        User newUser = new User( newId, newpwd );
        UserMap umap = new UserMap( oldUser, newUser );
        
        return __updateUser( umap );
    }
    
    private Response    __updateUser( UserMap umap )
    {
        Response resp;
        try
        {
            DBConnector connector = DBConnector.getConnector();
            connector.loadAndConnect();

            UserHandler.getLoader().updateUser(connector.getConnection(), umap.oldUser, umap.newUser);
            resp = Response.status(200).entity( umap ).build();
        } catch (IOException ex)
        {
            resp = Response.status(500).entity(new SimpleErrorMessage("CANNOT UPDATE USER - SERVER PROBLEM")).build();
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ResponseException ex)
        {
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
            resp = Response.status(200).entity(ex.getResponse()).build();
        } catch (SQLException ex)
        {
            resp = Response.status(409).entity(new SimpleErrorMessage(umap.oldUser.getUserID() + " CANNOT BE CHANGED - USER DOES NOT EXIST")).build();
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
        }
        return resp;
    }

    @POST
    @Path("/fu")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response findUser( User usr )
    {
        return __findUser( usr );
    }
    
    @GET
    @Path("/fu/{user}/{pwd}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response findUser(@PathParam("user") String userId, @PathParam("pwd") String pwd)
    {
        User usr = new User( userId, pwd );
        return __findUser( usr );
    }
    
    private Response    __findUser( User requsr )
    {
        User usr = null;
        try
        {
            DBConnector connector = DBConnector.getConnector();
            connector.loadAndConnect();

            usr = UserHandler.getLoader().loadFromDB(connector.getConnection(), requsr.getUserID(), requsr.getUserPwd());
            if (usr != null)
            {
                return Response.status(200).entity(usr).build();
            } else
            {
                SimpleErrorMessage msg = new SimpleErrorMessage("USER NOT FOUND");
                return Response.status(200).entity(msg).build();
            }
        } catch (IOException ex)
        {
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ResponseException ex)
        {
            Logger.getLogger(UserRestServices.class.getName()).log(Level.SEVERE, null, ex);
            return Response.status(200).entity(ex.getResponse()).build();
        }

        SimpleErrorMessage msg = new SimpleErrorMessage("ERROR IN DB TIER");
        return Response.status(200).entity(msg).build();
    }
}