Showing posts with label restful. Show all posts
Showing posts with label restful. Show all posts

Friday, February 19, 2010

JSON RESTfull Service Using Jersey with Hibernate Persistence on Glassfish

Tips:
  • to setup Hibernate to use a datasource defined under Glassfish, see my other post.
  • usefull Jersey annotations:
    • for the resource class: @Path("/person/")
    • for a method: @GET @Path("{personId}/") @Produces("application/json"). Then, you can use public Person getUser(@PathParam("personId") int personId) for method declaration.
    • add @Consumes("application/json") with public Person post(Person person) method declaration. Jersey takes care of unmarshaling the Json into Person object.
  • to return an error code from the restfull webservice, throw a new WebApplicationException(Response.Status.NOT_FOUND), for example. This one would return 404 error. No Need to declare the jersey handler method as "throws ...".
  • to unit test the service, use com.sun.jersey.api.client.Client:
    Person result = Client.create().resource("http://localhost:8080/myapp/person")
       .type("application/json")
       .post(Person.class,new Person("Jon Smith",133));
    Assert.assertEquals("Jon Smith", result.getName()); 
  • To pass an object retrieved via Hibernate as a response from a webservice, it needs to be serializable. But objects retrieved this way have additional members and so they need to be converted to a pure entity object (Person, in my case). I have used the Dozer library for this purpose (see the code below).
  • The entity classes (Person and PersonCollection, in my example)need to be annotated with @XmlRootElement.

Code:
Complete web service implementation class code (in RESTfull, call a resource):
package olcc.jersey.service;

import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import olcc.entity.HibernateUtil;
import olcc.entity.Person;
import olcc.entity.PersonCollection;
import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;

@Path("/person/")
public class PersonResource {
 
 @GET @Path("{personId}/") @Produces("application/json")
 public Person getPerson(@PathParam("personId") int personId) {
  Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  Transaction tx = null;
  Person personClean;
  
  try{
   tx = session.beginTransaction();
   Person person = (Person) session.load(Person.class,personId);
   
   Mapper mapper = new DozerBeanMapper();
   personClean = mapper.map(person,Person.class);

   session.getTransaction().commit();

  } catch( Exception ex) {
   if( tx != null ) tx.rollback();
         throw new WebApplicationException(Response.Status.NOT_FOUND);
  }
  return personClean;
 }
 
 @GET @Produces("application/json")
 public PersonCollection get() {
  Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    session.beginTransaction();
  List<person> result = session.createQuery("from Person").list();

  Mapper mapper = new DozerBeanMapper();
  PersonCollection persons = new PersonCollection();
        
  for( Person person : result ) {
    persons.add(mapper.map(person,Person.class));
  }
  session.getTransaction().commit();
        
  return persons;
 }
 
 @POST @Consumes("application/json")
 @Produces("application/json")
 public Person post(Person person) {
  Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  session.beginTransaction();
  
  session.save(person);
  
  session.getTransaction().commit();
  return person;
 }

 @GET @Path("delete/{personId}/") @Produces("application/json")
 public Person deleteOne(@PathParam("personId") int personId) {
  Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  session.beginTransaction();
  Transaction tx = null;
        Person personClean;
  
  try{
   tx = session.beginTransaction();
   Person person = (Person) session.load(Person.class,personId);
   session.delete(person);
   
   Mapper mapper = new DozerBeanMapper();
   personClean = mapper.map(person,Person.class);

   session.getTransaction().commit();

  } catch( Exception ex) {
   if( tx != null ) tx.rollback();
         throw new WebApplicationException(Response.Status.NOT_FOUND);
  }

  return personClean;
 }
}

Open Questions:
  • I'm not sure where the Hibernate session should be closed. I don't think this can be done at the end of each handler method.
  • How to use JTA for transaction management instead of direct JDBC transaction management?
  • Most of the Hibernate-specific code should go into a DAO, with most of it into a generic DAO. But the recommended by Hibernate documentation generic DAO is defined in terms of state-oriented data access API (makePersistent() and makeTransient() methods), which are less intuitive for me. What is the advantage of using them and how to use them from CRUD operations?

Monday, December 14, 2009

Using JSON RESTfull Web Services in A Flex Application

Choice of JSON Library for Flex
After a few hours of googling, I have decided that the strongest candidate is the corelib library, which for ActionScript 3 is called as3corelib. It's hosted on Google code, although there are multiple references to it on Adobe website. However, none of these references pointed me to any trace of corelib on Adobe website. I wasn't able to figure out why. Leave a comment if you know the story behind.

It seems, that Flash Builder 4 comes with a HTTPService Wizard, which can import a JSON webservice, among other formats.

Limitations of Flash HttpService for RESTfull Webservices
The problem is that because FlashPlayer uses the browser for all networking operations, and Safari browser supports only Post and Get operations, HttpService doesn't support Put, Delete, Headers and Options operations. As a workaround, there is a library hosted on Google Code called RestHttpService, that can be used.

Tuesday, December 8, 2009

RESTfull Webservices Using Java with Introduction to JSON

Introduction
What are RESTfull or Rest web services and how can they be implemented in with Java? Also what is JSON and how to make a webservice that returns a JSON object?  This is what this blog is about. Specifically, first, about installing and running a sample RESTfull application available from Jersey project.

What are RESTfull webservices? See this article. Or any other; there are many.

Approach 1

This approach uses one of the samples provided by the Jersey project and uses Maven to install the libraries. It's a bit heavy approach, but it works. Approach 2 below also uses Jersey, but is way lighter and simpler.


Server Side
I'm using Eclipse IDE with Glassfish Application Server. The steps for this configuration are:
  • Add Jersey and Jersey Documentation and Examples components to Glassfish using its admin console. Note, use GlassFish v3 Prelude version.  When I used GlassFish v3 Promoted Build, the Examples module was not showing in its Update Tool.
  • Restart the GF server.
  • Find the Jersey samples in GF_Home/glassfish/jersey folder.  Go into helloworld-webapp folder. You should see a .pom file there, that is used by maven. From that folder, run "mvn clean package" command. Install maven if needed.
  • Maven installs many files, and for me it ended with an error saying it can't read the glassfish-embedded-all-3.0-Prelude-Embedded-b10.jar file.  I have located this file in the maven repository (Documents and Settings/user/.m2/...) and found that it was broken.  I had to download it manually from internet (search by the file name).
  • Rerun the mvn command. It finished successfully and created a war file in the target directory.
  • Open GF console, and from Web Applications do a deploy. Point to the above war file and click OK. That did it.
  • Point your browser to http://localhost:8080/helloworld-webapp/helloworld. The string "Hello World" appeared.
Analyzing the Sample
After I had the sample running, I have exploded and analyzed the contents of the generated war file. The file had a class file implementing the resource plus two more short config files.

sun-web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 Servlet 2.5//EN" "http://www.sun.com/software/appserver/dtds/sun-web-app_2_5-0.dtd">
<sun-web-app error-url="">
  <context-root>/helloworld-webapp</context-root>
  <class-loader delegate="true"/>
  <jsp-config>
    <property name="keepgenerated" value="true">
      <description>Keep a copy of the generated servlet class' java code.</description>
    </property>
  </jsp-config>
</sun-web-app> 

web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <servlet>
        <servlet-name>Jersey Web Application</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.sun.jersey.samples.helloworld.resources</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app> 

Approach 2
Approach 1 worked OK, but I wasn't able to apply the sample to deploy an application of my own. And so I searched for a tutorial that uses Eclipse and possibly no Maven. I have run into this mini tutorial which worked great. I was able to drop this application into a Tomcat 6.0 and GlassFish 3 Prelude containers and it worked in both fine.
Also, this example illustrates how the service can be implemented for different response formats, leaving to the requestor to decide which one to use.

JSON
 JSON is simply a format, in a way an alternative to XML, that is especially useful for (de-)serializing objects, for example in order to send them over internet. The format is derived from JavaScript native format, but it became language neutral.  Here's a sample:
{"name":"Alfred Alfredo","age":"47"}
A nice and concise description of JSON syntax is on JSON website. To have your RESTfull webservice return a JSON object, download and add to the project jettison.jar that Jersey uses to create a JSON object. Now, for the sake of the demonstration, say that the webservice need to return a Person object:

@XmlRootElement
public class Person {
 public String name;
 public int age;
 
 public Person() {} // required by JAXB
 
 public Person(String name, int age) {
  this.name = name;
  this.age = age;
 }
}

Thanks to the annotations in this class, in order to return a JSON object we just need to define a method:

@Path("/person")
public class PersonResource {
  @GET  @Produces("application/json")
  public Person get() {
   return new Person("Alfred Alfredo",47);
  }
}

The JSON object as specified above, in the first part of this section will be returned. You can test it using a browser by pointing it to http://localhost:8080/jersey1/rest/person, where jersey1 is the context of my web app, rest is my servlet mapping and person is what I defined with @Path in my RESTful resource class.