Showing posts with label jaxrs. Show all posts
Showing posts with label jaxrs. Show all posts

Calling a HTTP POST using Worklight REST adapter

I am trying to build Contact Management application using WorkLight that uses REST service as back end. You can take a look and download the REST service from Returning JSON response from JAXRS service This is how the insertContact() method of my JAXRS service looks like, the insertContact() method consumes MediaType.APPLICATION_FORM_URLENCODED

@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
public void insertContact(@FormParam("contactId") int contactId,
      @FormParam("firstName") String firstName,
      @FormParam("lastName") String lastName,
      @FormParam("email") String email) {
    Contact contact = new Contact();
    contact.setContactId(contactId);
    contact.setFirstName(firstName);
    contact.setLastName(lastName);
    contact.setEmail(email);
    ContactDAO contactDAO = new ContactDAOImpl();
    contactDAO.insertContact(contact);
}
This is how the insertContact() method in my REST adapter looks like. The method for this request is POST and the contentType is application/x-www-form-urlencoded i have to create the string representing the formBody and submit it in content.

function insertContact(firstName,lastName,email){
  WL.Logger.debug("Entering ContactRESTService1.insertContact()");
  var input = {
      method : 'post',
      returnedContentType : 'json',
      path : '/ManageContact/rest/contact',
      body:{
      contentType:'application/x-www-form-urlencoded',
      content:"firstName="+firstName+"&lastName="+lastName+"&email="+email
      } 
  };
  WL.Logger.debug("Exiting ContactRESTService1.insertContact()");
  return WL.Server.invokeHttp(input);
}

Returning JSON response from JAXRS service

If your using JAXB for Java to XML conversion in the JAXRS service then changing it to support JSON becomes very easy, i wanted to try this option so built this application that can return response in application/xml and application/JSON type, you can download the sample application from here The sample service that i built in this case is ManageContact service, which supports call to return all the contacts, or contact for given contactId and also allows you to search a contact based on last name, in all these cases it returns a Contact object, i did mark the Contact.java class with @XmlRootElement annotation so that JAXBt knows that it is root element.

package com.javaworld.memcache;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Contact {
  private int contactId;
  private String firstName;
  private String lastName;
  private String email;
  
  public int getContactId() {
    return contactId;
  }
  public void setContactId(int contactId) {
    this.contactId = contactId;
  }
  public String getFirstName() {
    return firstName;
  }
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  public String getLastName() {
    return lastName;
  }
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  public String getEmail() {
    return email;
  }
  public void setEmail(String email) {
    this.email = email;
  }
  @Override
  public String toString() {
    return "Contact [contactId=" + contactId + ", firstName=" + firstName
        + ", lastName=" + lastName + ", email=" + email + "]";
  }
}
Then i did create this ContactService class that uses JAXRS annotation to define what are the input types as well as what would be the content type of the output, my service looks like this

package com.javaworld.memcache;

import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
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.QueryParam;
import javax.ws.rs.core.MediaType;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;

@Path("/contact")
public class ContactService {
  Logger logger = Logger.getLogger(ContactService.class);
  public ContactService(){
    logger.debug("Inside ContactService constructor");
    BasicConfigurator.configure();
  }

  @GET
  @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
  public List getContactList() {
    logger.debug("Entering ContactService.getContactList()");
    ContactDAO contactDAO = new ContactDAOImpl();
    List contactList = contactDAO.getContacts();
    logger.debug("Exiting ContactService.getContactList()");
    return contactList;
  }

  @POST
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
  public void insertContact(@FormParam("contactId") int contactId,
      @FormParam("firstName") String firstName,
      @FormParam("lastName") String lastName,
      @FormParam("email") String email) {
    Contact contact = new Contact();
    contact.setContactId(contactId);
    contact.setFirstName(firstName);
    contact.setLastName(lastName);
    contact.setEmail(email);
    ContactDAO contactDAO = new ContactDAOImpl();
    contactDAO.insertContact(contact);
  }

  @GET
  @Path("/{contactId}")
  @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
  public Contact getContact(@PathParam("contactId") int contactId) {
    ContactDAO contactDAO = new ContactDAOImpl();
    return contactDAO.getContact(contactId);

  }

  @DELETE
  @Path("/{contactId}")
  public void deleteContact(@PathParam("contactId") int contactId) {
    ContactDAO contactDAO = new ContactDAOImpl();
    contactDAO.deleteContact(contactId);
  }

  @PUT
  @Path("/{contactId}")
  @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  public void updateContact(@PathParam("contactId") int contactId,
      @FormParam("firstName") String firstName,
      @FormParam("lastName") String lastName,
      @FormParam("email") String email) {
    Contact contact = new Contact();
    contact.setContactId(contactId);
    contact.setFirstName(firstName);
    contact.setLastName(lastName);
    contact.setEmail(email);
    ContactDAO contactDAO = new ContactDAOImpl();
    contactDAO.updateContact(contact);
  }
  
  @GET
  @Path("/search")
  @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
  public List searchContact(@QueryParam("lastName") String lastName) {
    ContactDAO contactDAO = new ContactDAOImpl();
    return contactDAO.searchContact(lastName);

  }

}
My rest methods declare that they produce both MediaType.APPLICATION_JSON and MediaType.APPLICATION_XML content type. Now the next question would be which content type should it return when it gets request. So the rule is since MediaType.APPLICATION_JSON is first content type it becomes the default content type, so if you dont set content type it returns JSON, if you set content type to XML in request it returns XML like this Response when i did not set Accept header, so it returns JSON which is default content type
But if i want XML as response type i can set Accept header with value equal to application/xml and it returns XML
In Jersey configuration all you have to do to support JSON is make sure that you add jesey-json related jars in the classpath, which has JSON message writer which takes over when request has accept equal to JSON and returns JSON response

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.javaworld.memcache</groupId>
  <artifactId>ManageContact</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>ManageContact Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
      <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.4.2</version>

    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.4.2</version>

    </dependency>

    
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>3.4.0.GA</version>
    </dependency>
    <dependency>
      <groupId>org.apache.derby</groupId>
      <artifactId>derbyclient</artifactId>
      <version>10.7.1.1</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>commons-beanutils</groupId>
      <artifactId>commons-beanutils</artifactId>
      <version>1.8.0</version>
    </dependency>
    <dependency>
      <groupId>commons-beanutils</groupId>
      <artifactId>commons-beanutils</artifactId>
      <version>1.8.0</version>
    </dependency>
    <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-servlet</artifactId>
            <version>1.12</version>
        </dependency> 
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-json</artifactId>
            <version>1.12</version>
        </dependency> 
  </dependencies>
 
</project>

Createing Hello JAXRS service for deployment using Sun Jersey

If you want to build a REST service and deploy it in one of the Java EE 5 compliant containers for example WebSphere APplication Server 7.0, then you will have to use one of the external JAXRS containers such as Jersey, which is very popular among REST service developers.

I wanted to try this option out so i built a HelloJersey application that you can download from here. I followed these steps for building my sample application

  • First create a Dynamic Web APplication project called HelloJersey

  • Download following .jar files and add it to the WEB-INF/lib folder of your web application

    1. asm-3.1.jar

    2. jersey-core-1.5.jar

    3. jersey-server-1.5.jar

    4. jsr311-api-1.1.1.jar




  • Next create a HelloJerseyRESTService.java file like this

    package com.webspherenotes.rest;

    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.QueryParam;
    import javax.ws.rs.core.MediaType;

    @Path("/hellojersey")
    public class HelloJerseyRESTService {

    @GET
    @Produces(MediaType.TEXT_HTML)
    public String sayHello(@QueryParam("name") String name ){
    return "Hello " + name;
    }
    }

    The HelloJerseyRESTService only handles GET request and returns HTML markup


  • Next declare the Jersey servlet in the web.xml and create servlet mapping

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app id="WebApp_ID" version="2.5"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>DynaCacheSample1</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>com.webspherenotes.rest</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>
    <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
    </web-app>



  • After you deploy the application in container you should see that when the server is starting it will scan all the resource and in our case it should find only com.webspherenotes.rest.HelloJerseyRESTService

    [10/16/11 17:17:47:250 PDT] 0000000e ApplicationMg I WSVR0228I: User initiated module stop operation request completed on Module, HelloJersey.war, of application, DynaCacheSample1EAR
    [10/16/11 17:17:49:932 PDT] 0000000e ApplicationMg I WSVR0225I: User initiated module start operation requested on Module, HelloJersey.war, of application, DynaCacheSample1EAR
    [10/16/11 17:17:50:466 PDT] 0000000e webapp I com.ibm.ws.webcontainer.webapp.WebGroupImpl WebGroup SRVE0169I: Loading Web Module: HelloJersey.
    [10/16/11 17:17:50:521 PDT] 0000000e WASSessionCor I SessionContextRegistry getSessionContext SESN0176I: Will create a new session context for application key default_host/HelloJersey

    [10/16/11 17:17:50:602 PDT] 0000000e PackagesResou I Scanning for root resource and provider classes in the packages:
    com.webspherenotes.rest
    [10/16/11 17:17:50:666 PDT] 0000000e ScanningResou I Root resource classes found:
    class com.webspherenotes.rest.HelloJerseyRESTService

    [10/16/11 17:17:50:667 PDT] 0000000e ScanningResou I No provider classes found.
    [10/16/11 17:17:50:850 PDT] 0000000e WebApplicatio I Initiating Jersey application, version 'Jersey: 1.5 01/14/2011 12:36 PM'
    [10/16/11 17:17:51:816 PDT] 0000000e servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [DynaCacheSample1EAR] [/HelloJersey] [Jersey REST Service]: Initialization successful.
    [10/16/11 17:17:51:817 PDT] 0000000e webcontainer I com.ibm.ws.wswebcontainer.VirtualHost addWebApplication SRVE0250I: Web Module HelloJersey has been bound to default_host[*:9080,*:80,*:9443,*:5060,*:5061,*:443].
    [10/16/11 17:17:51:824 PDT] 0000000e ApplicationMg I WSVR0226I: User initiated module start operation request completed on Module, HelloJersey.war, of application, DynaCacheSample1EAR
    [10/16/11 17:17:51:825 PDT] 0000000e AppBinaryProc I ADMA7021I: Distribution of application DynaCacheSample1EAR completed successfully.




You can test the service by either directly going to the http://localhost:9080/HelloJersey/rest/hellojersey?name=sunil URL or using the REST client