Tuesday Jul 23, 2013

JSON Binding with JAX-RS - Moxy, JSON-P, Jackson, Jettison (TOTD #214)


One of the typical questions asked during presentations is how do I enable JSON support in JAX-RS ?

There are three basic approaches and four different modules in Jersey that enable them. Here is a quick summary:


MOXy
JSON-P
Jackson
Jettison
POJO-based JSON Binding
Yes
No
Yes
No
JAXB-based JSON Binding
Yes
No
Yes
Yes
Low-level JSON parsing & processing
No
Yes
No
Yes

MOXy is the default and preferred way of supporting JSON binding in your Jersey applications. A new sample is now added at:

https://github.com/arun-gupta/javaee7-samples/tree/master/jaxrs/moxy

The resource definition is:

@Path("endpoint")
public class MyResource {
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public MyObject echoObject(MyObject mo) {
        return mo;
    }
}


POJO is defined as:

public class MyObject {

    private String name;
    private int age;

    public MyObject() {
    }

    public MyObject(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Application class is:

@ApplicationPath("webresources")
public class MyApplication extends Application {
}

And the client code is:

Client client = ClientBuilder.newClient();

WebTarget target = client.target("http://"
        + request.getServerName()
        + ":"
        + request.getServerPort()
        + request.getContextPath()
        + "/webresources/endpoint");
System.out.println("POST request");
MyObject mo = target
        .request()
        .post(Entity.entity(new MyObject("Duke", 18), MediaType.APPLICATION_JSON), MyObject.class);
out.println("Received response: " + mo.getName() + ", " + mo.getAge() + "<br><br>");

JSON MOXy module (jersey-media-moxy.jar) is in your classpath then Jersey automatically discovers the module and enable JSON binding support via MOXy.

jersey.java.net/documentation/latest/media.html provide more details on all the approaches and modules.

Monday Mar 04, 2013

Consuming and Producing JSON using JAX-RS Entity Providers and JSR 353 Streaming API (TOTD# 210)


TOTD #193 explained how JAX-RS Entity Providers can be used to provide mapping between on-the-wire representations and their associated Java types. This blog shows how you can use Java API for JSON Processing (JSR 353), already integrated in GlassFish 4 promoted builds, to produce and consume JSON payload using Entity Providers.

The source code in this blog can be downloaded here and runs on GlassFish b76.

Lets say your domain object is defined as:

public class MyObject {

  private String name;
  private int age;

  //. . .
}

And your resource endpoint is defined as:

@Path("endpoint")
public class MyResource {
  @POST
  @Consumes(MediaType.APPLICATION_JSON)
  public MyObject echoObject(MyObject mo) {
    return mo;
  }
}

This is just echoing the domain object but I suspect your domain logic would be more complex than that ;-)

Using JAX-RS Client API, this endpoint can be invoked as:

WebTarget target = client.target(".../endpoint");
MyObject mo = target
               .request()
               .post(
                 Entity.entity(new MyObject("Duke", 18), MediaType.APPLICATION_JSON),
                 MyObject.class);
System.out.println("Received response: " + mo.getName() + ", " + mo.getAge() + "<br><br>");

The MessageBodyWriter.writeTo method, that writes MyObject to the underlying OutputStream, uses Streaming API from JSR 353 and looks like:

@Override
public void writeTo(MyObject t,
                    Class<?> type,
                    Type type1,
                    Annotation[] antns,
                    MediaType mt,
                    MultivaluedMap<String, Object> mm,
                    OutputStream out)
            throws IOException, WebApplicationException {
  JsonGeneratorFactory factory = Json.createGeneratorFactory();
  JsonGenerator gen = factory.createGenerator(out);
  gen.writeStartObject()
     .write("name", t.getName())
     .write("age", t.getAge())
     .writeEnd();
  gen.flush();
}

Similarly MessageBodyReader.readFrom method, that reads MyObject from the underlying InputStream, uses Streaming API from JSR 353 and looks like:

@Override
public MyObject readFrom(Class<MyObject> type,
                         Type type1,
                         Annotation[] antns,
                         MediaType mt,
                         MultivaluedMap<String, String> mm,
                         InputStream in)
                throws IOException, WebApplicationException {
  MyObject mo = new MyObject();
  JsonParser parser = Json.createParser(in);
  while (parser.hasNext()) {
    switch (parser.next()) {
      case KEY_NAME:
        String key = parser.getString();
        parser.next();
        switch (key) {
          case "name":
            mo.setName(parser.getString());
            break;
          case "age":
            mo.setAge(parser.getIntValue());
            break;
          default:
            break;
        }
        break;
      default:
        break;
    }
  }
  return mo;
}

The code is pretty straight forward and refer to Java API for JSON Processing javadocs if you need help in understanding the code.

Download the source code and enjoy!

Friday Jan 11, 2013

JAX-RS Client API and GlassFish 4 - Logging HTTP messages (TOTD #194)


One of the main features added in JAX-RS 2 is Client API. This API is used to access Web resources and provides integration with JAX-RS Providers. Without this API, the users need to use a low-level HttpUrlConnection to access the REST endpoint.

If the resource looks like:

@Path("/fruit")
public class MyResource {

@GET
public String get() {

then, before this API, the endpoint can be accessed as:

URL url = new URL("http://. . ./webresources/fruit");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.setDoOutput(false);
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
    //. . .
}
With this newly introduced API, the endpoint can be accessed as:

Client client = ClientFactory.newClient();
WebTarget target = client.target("http://. . ./webresources/fruit");
String response = target.request().get(String.class);
Client is the entry point to the Client API and is used to build and execute client requests and consume responses returned. The default instance of Client can be obtained by calling ClientFactory.newClient. Using this we can create a WebTarget by specifying URI of the web resource. These targets are then used to prepare client request invocation by specifying additional query or matrix parameters and resolving the URI template for different names. Finally, one of the HTTP methods is invoked on the prepared client.

The fluency of the API hides the complexity but a better understanding of the flow allows to write better code.

All the classes introduced in the specification are available in javax.ws.rs.client package.

Lets take a look at a complete sample. The complete source code can be downloaded here.

For a resource defined as:

@Path("/fruit")
public class MyResource {

@GET
public String get() {
return Database.getAll();
}

@GET
@Path("{name}")
public String get(@PathParam("name")String payload) {
return Database.get(payload);
}

@POST
public void post(String payload) {
Database.add(payload);
}

@PUT
public void put(String payload) {
Database.add(payload);
}

@DELETE
public void delete(String payload) {
Database.delete(payload);
}
}

A Client invoking all the HTTP methods look like:

Client client = ClientFactory.newClient();
WebTarget target = client.target("http://"
+ request.getServerName()
+ ":"
+ request.getServerPort()
+ request.getContextPath()
+ "/webresources/fruit");

// POST
target.request().post(Entity.text("apple"));

// PUT
target.request().put(Entity.text("banana"));

// GET (all)
String r = target.request().get(String.class);

// GET (one)
r = target.path("apple").request().get(String.class);

// DELETE
target.path("banana").request().delete();

// GET (all)
r = target.request().get(String.class);

And here are the message dumps:

INFO: 1 * LoggingFilter - Request received on thread http-listener-1(5)
1 > POST http://localhost:8080/endpoint/webresources/fruit
1 > Content-Type: text/plain
apple

INFO: 2 * LoggingFilter - Response received on thread http-listener-1(5)
2 < 204
2 < Date: Fri, 11 Jan 2013 22:21:23 GMT
2 < Server: GlassFish Server Open Source Edition 4.0
2 < X-Powered-By: Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)

INFO: 3 * LoggingFilter - Request received on thread http-listener-1(5)
3 > PUT http://localhost:8080/endpoint/webresources/fruit
3 > Content-Type: text/plain
banana

INFO: 4 * LoggingFilter - Response received on thread http-listener-1(5)
4 < 204
4 < Date: Fri, 11 Jan 2013 22:21:23 GMT
4 < Server: GlassFish Server Open Source Edition 4.0
4 < X-Powered-By: Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)

INFO: 5 * LoggingFilter - Request received on thread http-listener-1(5)
5 > GET http://localhost:8080/endpoint/webresources/fruit

INFO: 6 * LoggingFilter - Response received on thread http-listener-1(5)
6 < 200
6 < Date: Fri, 11 Jan 2013 22:21:23 GMT
6 < Content-Length: 15
6 < Content-Type: text/html
6 < Server: GlassFish Server Open Source Edition 4.0
6 < X-Powered-By: Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)
[apple, banana]

INFO: 7 * LoggingFilter - Request received on thread http-listener-1(5)
7 > GET http://localhost:8080/endpoint/webresources/fruit/apple

INFO: 8 * LoggingFilter - Response received on thread http-listener-1(5)
8 < 200
8 < Date: Fri, 11 Jan 2013 22:21:23 GMT
8 < Content-Length: 5
8 < Content-Type: text/html
8 < Server: GlassFish Server Open Source Edition 4.0
8 < X-Powered-By: Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)
apple

INFO: 9 * LoggingFilter - Request received on thread http-listener-1(5)
9 > DELETE http://localhost:8080/endpoint/webresources/fruit/banana

INFO: 10 * LoggingFilter - Response received on thread http-listener-1(5)
10 < 204
10 < Date: Fri, 11 Jan 2013 22:21:23 GMT
10 < Server: GlassFish Server Open Source Edition 4.0
10 < X-Powered-By: Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)

INFO: 11 * LoggingFilter - Request received on thread http-listener-1(5)
11 > GET http://localhost:8080/endpoint/webresources/fruit

INFO: 12 * LoggingFilter - Response received on thread http-listener-1(5)
12 < 200
12 < Date: Fri, 11 Jan 2013 22:21:23 GMT
12 < Content-Length: 7
12 < Content-Type: text/html
12 < Server: GlassFish Server Open Source Edition 4.0
12 < X-Powered-By: Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)
[apple]

This has been tested on GlassFish 4 build 70 with the following dependencies:

<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0-m10</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
<version>2.0-m10</version>
<type>jar</type>
</dependency>

Here are some more pointers to follow:

Provide feedback on Jersey 2 to users@jersey.java.net and JAX-RS specification to users@jax-rs-spec.java.net.


Monday Jan 07, 2013

JAX-RS Custom Entity Providers (TOTD #193)


JAX-RS defines Entity Providers that supply mapping services between on-the-wire representations and their associated Java types. The entities, also known as "message payload" or "payload" represent the main part of an HTTP message. These are specified as method parameters and return types of resource methods. Several standard Java types such as String, byte[], javax.xml.bind.JAXBElement, java.io.InputStream, java.io.File, and others have a pre-defined mapping and is required by the specification. Applications may provide their own mapping to custom types using MessageBodyReader and MessageBodyWriter interfaces. This allows to extend the JAX-RS runtime easily to support your own custom entity providers.

The MessageBodyReader interface defines the contract for a provider that supports the conversion of a stream to a Java type. The MessageBodyWriter interface defines the contract for a provider that supports the conversion of a Java type to a stream. This Tip Of The Day (TOTD) will explain how to write these custom entity providers.

Note, this functionality was defined in JAX-RS 1.0 as opposed to Client API, Client- and Server-side async, Hypermedia, and many other features. The complete source code for this sample application can be downloaded here and will work on GlassFish 4.0 b70.

Here is a simple resource that returns name of the fruit based upon the index passed as parameter:

@Path("fruits")
public class MyResource {
private String[] response = { "apple", "banana", "mango" };

@POST
public String getFruit(int index) {
return response[index % 3];
}
}
This resource can be invoked using the newly introduced Client API as:

Client client = ClientFactory.newClient();
WebTarget target = client.target("http://"
+ request.getServerName()
+ ":"
+ request.getServerPort()
+ request.getContextPath()
+ "/webresources/fruits");
String fruit = target
.request()
.post(Entity.text("1"), String.class);

If we update the resource such that the index parameter is passed as the following object:

public class MyObject implements Serializable {
public static final String MIME_TYPE = "application/myType";

private int index;

public MyObject() {
}

public MyObject(int index) {
this.index = index;
}

public int getIndex() {
return index;
}

public void setIndex(int index) {
this.index = index;
}
}

Then the resource method would look like:

@POST
@Consumes(value=MyObject.MIME_TYPE)
public String getFruit(MyObject mo) {
return response[Integer.valueOf(mo.getIndex()) % 3];
}

The additional @Consumes annotation defines the media type that the method can accept. The following custom entity providers are defined to support this custom type. The first one, MyReader, defines the conversion of on-the-wire representation to MyObject Java type.

@Provider
@Consumes(MyObject.MIME_TYPE)
public class MyReader implements MessageBodyReader<MyObject> {

@Override
public boolean isReadable(Class<?> type, Type type1, Annotation[] antns, MediaType mt) {
return MyObject.class.isAssignableFrom(type);
}

@Override
public MyObject readFrom(Class<MyObject> type,
Type type1,
Annotation[] antns,
MediaType mt, MultivaluedMap<String, String> mm,
InputStream in) throws IOException, WebApplicationException {
try {
ObjectInputStream ois = new ObjectInputStream(in);
return (MyObject)ois.readObject();
} catch (ClassNotFoundException ex) {
Logger.getLogger(MyReader.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}

The interface require two methods, isReadable and readFrom, to be implemented. The implementation has @Consumes annotation restricting the media type supported by this entity provider.

The second one, MyWriter, defines the conversion from MyObject Java type to on-the-wire representation.

@Provider
@Produces(MyObject.MIME_TYPE)
public class MyWriter implements MessageBodyWriter<MyObject> {

@Override
public boolean isWriteable(Class<?> type, Type type1, Annotation[] antns, MediaType mt) {
return MyObject.class.isAssignableFrom(type);
}

@Override
public long getSize(MyObject t, Class<?> type, Type type1, Annotation[] antns, MediaType mt) {
// As of JAX-RS 2.0, the method has been deprecated and the
// value returned by the method is ignored by a JAX-RS runtime.
// All MessageBodyWriter implementations are advised to return -1 from
// the method.

return -1;
}

@Override
public void writeTo(MyObject t,
Class<?> type,
Type type1,
Annotation[] antns,
MediaType mt,
MultivaluedMap<String, Object> mm,
OutputStream out) throws IOException, WebApplicationException {
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(t);
}
}
The interface require three methods isWriteable, getSize, writeTo to be implemented. The implementation of getSize method is recommended to return -1 as JAX-RS runtime is required to compute the actual Content-Length header value. The implementation has @Produces annotation restricting the media type supported by this entity provider.

The reader and writer entity providers are marked with @Provider and are thus automatically discovered at runtime on the server-side. But until JERSEY-1634 is fixed, they need to be explicitly specified in the Application class as:

@ApplicationPath("webresources")
public class MyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
resources.add(MyResource.class);
resources.add(MyReader.class);
resources.add(MyWriter.class);
return resources;
}
}

On the client-side, the providers need to be explicitly registered as shown:

Client client = ClientFactory.newClient();
client
.configuration()
.register(MyReader.class)
.register(MyWriter.class);
String fruit = target
.request()
.post(Entity.entity(new MyObject(1), MyObject.MIME_TYPE), String.class);

Notice, how invoking the endpoint requires to specify the media type as part of post method invocation.

The complete source code for this sample application can be downloaded here and will work on GlassFish 4.0 b70.

Here are some more pointers to follow

Provide feedback on Jersey 2 to users@jersey.java.net and JAX-RS specification to users@jax-rs-spec.java.net.


Thursday Jul 05, 2012

Jersey 2 in GlassFish 4 - First Java EE 7 Implementation Now Integrated (TOTD #182)


The JAX-RS 2.0 specification released their Early Draft 3 recently. One of my earlier blogs explained as the features were first introduced in the very first draft of the JAX-RS 2.0 specification. Last week was another milestone when the first Java EE 7 specification implementation was added to GlassFish 4 builds.

Jakub blogged about Jersey 2 integration in GlassFish 4 builds. Most of the basic functionality is working but EJB, CDI, and Validation are still a TBD. Here is a simple Tip Of The Day (TOTD) sample to get you started with using that functionality.
  1. Create a Java EE 6-style Maven project

    mvn archetype:generate
    -DarchetypeGroupId=org.codehaus.mojo.archetypes
    -DarchetypeArtifactId=webapp-javaee6 -DgroupId=example
    -DartifactId=jersey2-helloworld -DarchetypeVersion=1.5
    -DinteractiveMode=false

    Note, this is still a Java EE 6 archetype, at least for now.
  2. Open the project in NetBeans IDE as it makes it much easier to edit/add the files. Add the following <repositories>

    <repositories>
    <repository>
    <id>snapshot-repository.java.net</id>
    <name>Java.net Snapshot Repository for Maven</name>
    <url>https://maven.java.net/content/repositories/snapshots/</url>
    <layout>default</layout>
    </repository>
    </repositories>

  3. Add the following <dependency>s

    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.10</version>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>javax.ws.rs</groupId>
    <artifactId>javax.ws.rs-api</artifactId>
    <version>2.0-m09</version>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-client</artifactId>
    <version>2.0-m05</version>
    <scope>test</scope>
    </dependency>
    The complete list of Maven coordinates for Jersey2 are available here. An up-to-date status of Jersey 2 can always be obtained from here.
  4. Here is a simple resource class:

    @Path("movies")
    public class MoviesResource {

    @GET
    @Path("list")
    public List<Movie> getMovies() {
    List<Movie> movies = new ArrayList<Movie>();

    movies.add(new Movie("Million Dollar Baby", "Hillary Swank"));
    movies.add(new Movie("Toy Story", "Buzz Light Year"));
    movies.add(new Movie("Hunger Games", "Jennifer Lawrence"));

    return movies;
    }
    }
    This resource publishes a list of movies and is accessible at "movies/list" path with HTTP GET. The project is using the standard JAX-RS APIs.

    Of course, you need the trivial "Movie" and the "Application" class as well. They are available in the downloadable project anyway.
  5. Build the project

    mvn package

    And deploy to GlassFish 4.0 promoted build 43 (download, unzip, and start as "bin/asadmin start-domain") as

    asadmin deploy --force=true target/jersey2-helloworld.war

  6. Add a simple test case by right-clicking on the MoviesResource class, select "Tools", "Create Tests", and take defaults. Replace the function "testGetMovies" to
    @Test
    public void testGetMovies() {
    System.out.println("getMovies");
    Client client = ClientFactory.newClient();
    List<Movie> movieList = client.target("http://localhost:8080/jersey2-helloworld/webresources/movies/list")
    .request()
    .get(new GenericType<List<Movie>>() {});
    assertEquals(3, movieList.size());
    }

    This test uses the newly defined JAX-RS 2 client APIs to access the RESTful resource.
  7. Run the test by giving the command "mvn test" and see the output as

    -------------------------------------------------------
    T E S T S
    -------------------------------------------------------
    Running example.MoviesResourceTest
    getMovies
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.561 sec

    Results :

    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

GlassFish 4 contains Jersey 2 as the JAX-RS implementation. If you want to use Jersey 1.1 functionality, then Martin's blog provide more details on that. All JAX-RS 1.x functionality will be supported using standard APIs anyway. This workaround is only required if Jersey 1.x functionality needs to be accessed.

The complete source code explained in this project can be downloaded from here.

Here are some pointers to follow

Provide feedback on Jersey 2 to users@jersey.java.net and JAX-RS specification to users@jax-rs-spec.java.net.

Sunday Apr 22, 2012

Chennai Java Summit 2012 Trip Report




I attended my first Chennai Java Summit last weekend. The one-day conference had two parallel tracks. The conference was organized as part of AIOUG (All India Oracle User Group) and so there was a parallel track covering Oracle technologies as well. Nagaraj Paduvare from Oracle talked about what User Groups. The title of the presentation "User Groups - Are you a member yet ?" clearly conveyed the urge for the community to join the local User Groups - be it Java . Oracle's vision is to promote a world-class user group community where community and customers realize outstanding value from participation and experience constant and healthy dialogue with one another and Oracle at all levels. There are 870+ independent Oracle user groups related by interests and location. You can find all the information about them at iouc.org.

I gave two presentations and the slides are available.


There were about 40+ attendees in this talk. Some of the audience were not even aware of Java EE 6 so I started the talk with a NetBeans-driven introduction to the platform. A more comprehensive video of Java EE 6 tooling with NetBeans is available at screencast #36. The screencast #37 covers the same with Eclipse. And then I explained how Java EE 7 platform is embracing cloud by providing support for  dynamic service provisioning, metrics-driven elasticity, and multi-tenancy. Its important to remember that Java EE 7 will offer lot more than cloud as several specifications such as Java Message Service 2.0, Java API for RESTful Web Service 2.0, and Expression Language 3.0. Several other specifications are getting a minor update as well. You can get all the latest updates at javaee-spec.java.net.

The demonstration of taking a Java EE 6 application and deploying it to GlassFish 4 showing service provisioning hit the point home. The complete instructions to download and build the sample are available at glassfish.org/javaone2011.


This talk gave a brief overview of REST Architecture, how JAX-RS provides support for RESTful Web services, and a complete overview of the new features coming in JAX-RS 2.0. I also demonstrated how NetBeans wizards make life simple for generating RESTful Web services from JPA Entity classes. The working JAX-RS 2.0 sample codes convey the point that an early implementation is already available. You can get all the latest updates at jax-rs-spec.java.net.

It was certainly good to spend some time with Venkat Subramaniam and Scott Davis.

On a personal side, I enjoyed Dal-Baati-Churma at a Rajasthani restaurant in the hotel. For me, enjoying the local cuisine is definitely one of the joys of staying in India. However the humidity was very high and so that prevented me from running in the morning. In times like this, the Spartacus Workout from Men's Health Magazine has been really helping me recently. If you have not tried this workout, you must!

Here are some pictures captured from the event:






And the complete video album:



Thank you Raj Mahendra for holding the Java flag strong and leading the community in Chennai. Only Bangalore, Nagpur, Chennai, and Pune has an active JUG. The JUG community in India is in its infancy and I hope more cities start planning activities like this.

Next stop JavaOne India ...

Great Indian Developer Summit 2012 Trip Report


I attended the fifth, and my first, Great Indian Developer Summit in the Silicon Valley of India, Bangalore. The conference is spread over 4 days with each day covering .NET, Web, Java, and Workshops respectively. The Java track had 800+ attendees (roughly based on a cursory headcount for the opening keynote) and the hall was packed. The theater style seating allowed the attendees to enjoy the wide screen presentations.

Another unique and cool thing about the conference is that they create life size posters of all the speakers and display them outside the speakers' room. This not only help you identify your room easily but also makes you feel like a celebrity ;-) Here are some pictures of the posters:






Venkat's opening keynote is always fun. He talked about "Refactor your Language Knowledge Portfolio: We're What We Can Code In". His entertaining presentation style keeps the audience engaged and laughing. His Essence vs Ceremony analogy was particularly impressive and I recommend reading that blog.

I gave three presentations and a hands-on workshop and the slides are now available.


This presentation gave an overview of JMS 2.0 and the new features coming there. This presentation had 200+ attendees and 50% of the audience were existing users of JMS. There was a lot interactivity during/after the session. Do you know JMS 2.0 Early Draft is already available ?

The primary goal of this specification is to provide a simplified API and clarify the ambiguities discovered over the past few years. Check out this blog for a quick comparison between the existing and the simplified API. If you have any feature request then its highly recommended to file a JIRA issue at jms-spec.java.net.



This presentation gave an overview of JAX-RS 2.0. Do you know that Early Draft 2 is already available ? Check out this blog for a brief overview of the new features coming in JAX-RS 2.0. You can find the latest updates at jax-rs-spec.java.net and also follow @gf_jersey.



This presentation explained the key concepts of how GlassFish PaaS-enable your Java EE application. The talk also showed how a Java EE application can be deployed where all he services required by the application are dynamically provisioned. A working version of the application, along with instructions, are available at glassfish.org/javaone2011. A video of the application in action is shown below:



The video also shows how the cluster dynamically adjusts to meet the elasticity constraints pre-defined for the application.

The Java EE 6 hands-on lab had about 20 attendees. The self-pace instructions can be downloaded here. I was pretty amazed by the level of interaction. There was one particular guy who who came from the PHP land, was taking notes on a paper notebook, and was asking the most intelligent questions. There were other experienced J2EE/Java EE users who also enjoyed the simplicity introduced in the platform.

And somehow for the past few days the question of Java EE 6 over Spring has come up during each such engagement. My views are clearly expressed at Why Java EE 6 is better than Spring. And do read the interesting discussion in the comments, all the way to the end.

The conference was well organized with a personal introduction of each speaker. The rooms were well marked and the projectors worked very well. The conference crew was very helpful and prompt in reminding about the time remaining. However a 45 minute session is a few minutes too short and so had to tweak my existing slide deck to meet the time requirements.

Multiple conflicting talks were arranged such as Mike's Java EE 7 and mine JMS 2.0, Venkat's "Java 8: A Sneak Peak" and Simon's "Java SE 8 & Beyond". This feedback was conveyed to the organizers. Hopefully they'll be able to do a better job of this next time around.

On a personal side, I enjoyed a team dinner at BBQ Nation and is definitely worth visiting once at least. And could also manage to enjoy a lunch at MTR with Vivek. The ITC Windsor is a nice hotel with a decent fitness center and a great restaurant. The breakfast buffet had a great variety and very scrumptious.

Here are some pictures captured from the event:










And now the complete album:


The Java EE 7 platform will be much more mature by this time next year and who knows I might even submit a Java EE 7 hands-on lab!

Thank you Salt March Media for putting up a great show and providing me an opportunity to present. Looking forward to my participation again next year!

Tuesday Feb 07, 2012

JAX-RS 2.0 Early Draft Explained - Java EE 7 Making Progress


JAX-RS 2.0 Early Draft has been available for about 3 months now. JAX-RS 2.0, just like JPA 2.1, was one one of the first JSRs to be filed as part of Java EE 7. Several other specifications in Java EE 7 have released early drafts as well (JavaServer Faces 2.2CDI 1.1, EJB 3.2, and more coming as well) and I'll cover them in later blogs.

Here are the topics covered so far:
JAX-RS 2.0 is a brand new specification and here are the main highlights so far:
  • Client API: The HTTPUrlConnection is too low level and is not RESTful-oriented. Invoking a RESTful resource using this class would look like:

    URL url = new URL("http://.../atm/balance");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("GET");
    conn.setDoInput(true);
    conn.setDoOutput(false);
               
    BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String line;
    while ((line = br.readLine()) != null) {
        out.println(line);
    }


    Notice, how much code has to be written and its brittle. Some JAX-RS 1.0/1.1 implementations already provide a higher-level client-side API to access the Web resources. For example, read TOTD #57 for more details about Jersey Client API. A slightly more advanced sample to access Twitter timeline using Jersey Client API is described in TOTD #143.

    JAX-RS 2.0 introduces a standard Client API to in javax.ws.rs.client package to access the Web resource. It also share features with JAX-RS server API (readers/writers).

    A simple usage looks like:

    Client client = ClientFactory.newClient();
    String balance = client.target("http://.../atm/balance")
                           .request("text/plain")
                           .get(String.class);


    Instead of Client client = ClientFactory.newClient(), would you like @Inject Client client then vote for JAX_RS_SPEC-170.

    Path and query parameters can be easily specified using the builder pattern as shown below:

    Client client = ClientFactory.newClient();
    String balance = client.target("http://.../atm/{card}/balance")
                           .pathParam("card", "1111222233334444")
                           .queryParam("pin", "1234")
                           .request("text/plain")
                           .get(String.class);


    See how the template in the target path is automatically substituted with the correct value. The request type is specified to be "text/plain" and GET method of this web resource is invoked. This will be translated to:

    http://.../atm/1111222233334444/balance?pin=1234

    A POST request will look like:

    Money balance = client.target("http://.../atm/{card}/withdraw")
                          .pathParam("card", "1111222233334444")
                          .queryParam("pin", "1234")
                          .request("application/json")
                          .post(text("50.0"), Money.class);

    There is also generic command pattern that enables separation of concern between the creator and submitteruseful for batch processing using Invocation. And the code would look like:

    Invocation inv1 = client.target("http://.../atm/{card}/balance")
                            .pathParam("card", "1111222233334444")
                            .queryParam("pin", "1234")
                            .request("text/plain")
                            .buildGet();


    Invocation inv2 = client.target("http://.../atm/{card}/withdraw")
                            .pathParam("card", "1111222233334444")
                            .queryParam("pin", "1234")
                            .request("application/json")
                            .buildPost(text("50.0"));

    And once the Invocations are ready then they can be invoked.

  • Filters and Handlers: The filters and handlers allow app developers to perform message request pre-processing and response post-processing via well-defined extension points on the client- and server-side. This is yet another feature that was supported by several JAX-RS 1.0/1.1 implementations with each using slightly different semantics and now getting standardized in JAX-RS 2.0.

    Filters are non-wrapping extension points, allow pre-processing without modifying the request itself. A filter implements interface RequestFilter or ResponseFilter or both and is annotated with @Provider. A logging filter that simply logs the message may look like:

    @Provider
    class LoggingFilter implements RequestFilter, ResponseFilter {

        @Override
        public FilterAction preFilter(FilterContext ctx) throws IOException {
            logRequest(ctx.getRequest());
            return FilterAction.NEXT;
        }

        @Override
        public FilterAction postFilter(FilterContext ctx) throws IOException {
            logResponse(ctx.getResponse());
            return FilterAction.NEXT;
        }
    }

    Multiple filters are grouped in filter chains. The response from preFilter and postFilter indicate whether the next filter in the chain need to be executed (FilterAction.NEXT) or stopped (FilterAction.STOP).

    Handlers provide wrapping extension points. A handler implements interface ReadFromHandler or WriteToHandler or both and is annotated with @Provider. A GZIP filter that provides deflate and inflate capabilities may look like:

    @Provider
    class GzipHandler implements ReadFromHandler, WriteToHandler {
        @Override
        public Object readFrom(ReadFromHandlerContext ctx) throws IOException {
            InputStream old = ctx.getInputStream();
            ctx.setInputStream(new GZIPInputStream(old));
            try {
                return ctx.proceed();
            } finally {
                ctx.setInputStream(old);
            }
        }

        @Override
        public Object writeTo(WriteToHandlerContext ctx) throws IOException {
            OutputStream old = ctx.getOutputStream();
            GZIPOutputStream gzipOutputStream =
    new GZIPOutputStream(old);
            ctx.setInputStream(gzipOutputStream);
            try {
                return ctx.proceed();
            } finally {
                gzipOutputStream.finish();
                ctx.setOutputStream(old);
            }
        }
    }

    Multiple handlers are grouped in handler chains. The proceed method must be explicitly called in order for the next handler in the chain to be invoked.

    In the direction of flow the filters always executed before handlers. The following diagram shows the exact execution order on client and server-side:



    The handlers and filters can be associated to each method of a resource specifically using @NameBinding. The specification defines @GlobalBinding to associate handlers and filters to all methods of a resource but the recent version of the specification removes it and makes it a default. Also look at JAX_RS_SPEC-146 that asks for a mechanism to override the global filters/handlers.

    The dynamic binding, enabled by implementing DynamicBinding, provide more control on the association with resources and methods.
  • Hypermedia: Linking resources together is one of the main RESTful principles. There are structural links that are used to avoid sending a complete representation of a resource and enable lazy loading. The clients can follow these type of links to retrieve the "pieces" they need. A transitional link is used to update the state of a resource and is typically identified by a "rel" attribute. Structural links are normally in the entity; transitional links could be in link headers or the entity.

    JAX-RS 2.0 will only support transitional links in headers using newly added Link and LinkBuilder classes. The proposed Client API can also create a target from a link. The code may look like:

    Response r = client.target("/product").request("application/json").get();
    ResponseHeaders rh = r.getHeaders();
    if (rh.hasLink("ship")) {
        client.invocation(rh.getLink("ship")).invoke();
    }


    On the server side, ResponseBuilder has support for adding one or more link headers. The code may look like:

    @Path("/products")
    public class MyResponse {

        @GET
        @Path("{id}")
        @Produces({"application/json", "application/xml"})
        public Response getProduct(@PathParam("id")int id) {
            Product product = new Product(id);
            return Response
                    .ok(product)
                    .link("http://.../orders/" + id + "/ship", "ship")
                    .build();
        }
    }


  • Validation: Web resources must validate data received in query or header parameters or entity bodies. Currently this validation has to be performed in the application code. The Bean Validation specification already defines a extensible mechanism to specify validation constraints on a bean. So the JAX-RS specification leverages that and introduces support for declarative validation. The constraint annotations can be specified in public constructor parameters, method parameters, fields and bean properties. In addition, they can also decorate resource classes, entity parameters and resource methods. Here is a sample class augmented with constraint annotations:

    @Path("/")
    class ProductResource {

        @POST
        @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
        public void addProduct(@NotNull @FormParam("productName") String name,
                               @NotNull @Category @FormParam("category") String category) {
            . . .
        }
    }


    The @NotNull is a pre-defined constraint in the Bean Validation API and ensures that the target parameters are not null. The @Category is a user-defined constraint using the extensible mechanism provided by the Bean Validation API. If the constraints are violated then the resource method is not invoked and instead a response with status code 400 (Bad Request) and an entity that describe the violations is returned to the client.

    Here is a sample code of how to validate request entity bodies when they are mapped to resource method parameters:

    @CheckProduct
    class Product { . . . }

    @Path("/")
    class ProductResource {

        @POST
        @Consumes(MediaType.APPLICATION_JSON)
        public void addProduct(@Valid Product product) {
            . . .
        }
    }


    The presence of @Valid (a pre-defined annotation in Bean Validation API) next to the method parameter ensures that the @CheckProduct constraint is called to verify the mapped entity.

    The JAX-RS specification also defines the sequence to validate root resource class instances. The recommendation is to return as many violations as possible instead of aborting after the first violation is encountered.
  • Asynchronous Processing: JAX-RS 2.0 introduces asynchronous processing on server- and client-side APIs for the usual reasons. The server-side code will look like:

    @Path("/async")
    class ProductResource {
        @Context ExecutionContext ctx;

        @GET
        @Suspend
        public Product longOp() {
            Executors.newSingleThreadExecutor().submit(
                new Runnable() {
                    public void run() {
                        Proruct product = longQueryFromDatabase();
                        ctx.resume(product);
                    }
                }
            );
        }
    }

    The longOp method is invoked when this resource is accessed using GET, forks a new thread, and returns immediately without producing the result. Once longQueryFromDatabase returns the product then the connection is resumed and the response is returned by calling ctx.resume and setting the value.

    ExecutionContext also provide suspend() that allows to override the values, such as timeout, specified in the annotation based upon the runtime state.

    On the client-side, the code will look like:

    Client client = ClientFactory.newClient();
    Future<String> future = client.target("http://.../atm/{card}/balance")
                                  .pathParam("card", "1111222233334444")
                                  .queryParam("pin", "1234")
           
                           .request("text/plain")
                  
                    .async()
                         
             .get();

    The async() is called during building the client request. The return Future<String> can be used to query/cancel the status of execution on the server-side using isDone and cancel. Once the response is ready then Future<T>.get() is invoked to receive an instance of T if the response was successful or null if the invocation failed.

    Optionally an InvocationCallback<T> may be registered during the request invocation. The completed method is called when the invocation completes successfully and a response is available and failed method is called when the invocation fails. The code looks like:

    Future<String> future = client.target("http://.../atm/{card}/balance")
                                  .pathParam("card", "1111222233334444")
                                  .queryParam("pin", "1234")
           
                           .request("text/plain")
                  
                    .async()
                         
             .get(
                                      new InvocationCallback<String>() {
                                          @Override
                                          public void completed(String result) {
                                              // got the correct result
                                              System.out.println(result);
                                          }

                                          @Override
                                          public void failed(InvocationException error) {
                                              // ouch, got an error!
                                              System.err.println(error.getCause());
                                          }
                                      }
                                   );


    Notice, the type of the result is specified as type parameter to InvocationCallback.

    Client and server developers optimize their resources (threads) depending upon their needs and are independent of each other. A client really can't tell if a resource is implemented asynchronously or not and shouldn't even need to know.

  • Improved connection negotiation: This would allow a server to specify a preferred MIME type if the client does not care about it. This can be easily specified using the "qs" qualifier as shown below:

    @Path("/")
    class ProductResource {

        @GET
        @Produces({ "text/xml
    ;qs=0.75", "application/json"})
        public Product[] getProducts() {
            . . .
        }
    }


    The default server-side qs-value and the final order of server-side served types preferences follow the same rules as those specified for HTTP Accept Header. Per those rules an unspecified value takes the default value of 1. So the above @Produces rule says "application/json" will be served as the preferred type if there is no Accept header from the client. The section 3.5 talks more about qs parameter and the section 3.8 in the specification provide complete details about how media type of the response is chosen by a JAX-RS runtime.

The Appendix D in the specification provide a comprehensive list of changes from the previous version of the specification.

Here are some final set of references for you:

And of course, it'll all be delivered as part of GlassFish 4.0!

Learn the latest and greatest about JAX-RS 2.0 from Marek Potociar's talk on JAX-RS at Devoxx 2011:

Tuesday Jan 11, 2011

JAX-RS 2.0 and JPA 2.1 JSRs filed ... Java EE 7 moves forward!

JSR 338 (JPA 2.1) and JSR 339 (JAX-RS 2.0) are the first formal steps in moving Java EE 7 platform forward!

The key features considered in scope of JPA 2.1 are:

  • Support for the use of custom types and transformation methods in object/relational mapping.
  • Support for the use of "fetch groups" and/or "fetch plans" to provide further control over data that is fetched, detached, copied, and/or used in merging.
  • Support for the specification of immutable attributes and readonly entities.
  • Support for user-configurable naming strategies for use in O/R mapping and metamodel generation.
  • More flexibility in the use of generated values; support for UUID generator type.
  • Additional mapping metadata to provide better standardization for schema generation.
  • Support for multitenancy.
  • Additional event listeners and callback methods; availability of entity manager to callbacks.
  • Methods for dirty detection.
  • Improved ability to control persistence context synchronization.
  • Additional unwrap methods to support use of vendor extensions.
  • Support for dynamic definition of persistence unit, including object/relational mapping information.
  • Extension of metamodel API to object/relational mapping information.
  • Improvements to the Java Persistence query language and criteria APIs

More details in JSR 338. Click here if you are interested in joining this Expert Group.

The key features considered in scope of JAX-RS 2.0 are:

  • Client API - a low-level using a builder pattern and a higher level leveraging the former one
  • Hypermedia processing on client and server
  • MVC architecture compatible with JAX-RS programming model
  • Integration with Bean Validation for parameter validation
  • Tighter integration with JSR 330 annotations, such as @Inject
  • Asynchronous request processing
  • Sophisiticated server-side content negotiation
  • More ease-of-development following DRY principles

More details in JSR 339. Click here if you are interested in joining this Expert Group. This Expert Group will have a public observer alias to monitor discussions.

The JSR ballot closes on Jan 24, 2011. After the JSRs are approved the Expert Groups start discussion on each and every item of the proposal. And you'll start seeing the promoted builds and integrations into GlassFish after that.

Stay tuned to hear details as Java EE 7 continues its march forward. In the meanwhile, you can download GlassFish 3.1 promoted build (soon to be final) that provides full Java EE 6 functionality along with centralized administration and high availability.

Technorati: javaee7 glassfish jaxrs jpa restful persistence

Wednesday Aug 04, 2010

TOTD #143: Retrieve Twitter user timeline using using Jersey and OAuth

The Basic Authentication for authorizing with Twitter API will be turned off on Aug 16th. After that OAuth will be the only way to invoke the API.

Beginner's guide to OAuth provide an excellent explanation to OAuth. The typical analogy for OAuth is a "valet key" to the car which is a stripped down version of your regular key. These keys are meant for valet drivers who don't need to open trunk or glove compartment and don't need to drive the car for longer distance. So even though they have access to the entire car but are restricted to the limited functionality.

OAuth is used to share your resources (photos, videos, bank accounts, etc) stored on one site with another site without having to share your username and password. The site storing the resources is "Service Provider", the site requesting the access is "Consumer", you are the "User", "Tokens" are "valet key" that provide required access to the resources.

This Tip Of The Day (TOTD) explains how Jersey, the Reference Implementation for JAX-RS, provides seamless support for OAuth by creating a simple desktop application that retrieves user timeline on Twitter using OAuth. This blog is going to combine the instructions outlined in Understanding the guts of Twitter's OAuth for client apps and Using Jersey client OAuth support with Smugmug to achieve that.

Lets get started!

  1. Create a Maven project as:
    mvn -DarchetypeVersion=1.0 -DgroupId=org.glassfish.samples -DarchetypeArtifactId=maven-archetype-quickstart -Dversion=1.0-SNAPSHOT -DarchetypeGroupId=org.apache.maven.archetypes -Dpackage=org.glassfish.samples.twitter -DartifactId=twitter
    
  2. Update the generated "pom.xml" with the following fragments:
    <repositories>
      <repository>
        <id>glassfish-repository</id>
        <name>Java.net Repository for Glassfish</name>
        <url>http://download.java.net/maven/2/</url>
      </repository>
    </repositories>
    <dependencies>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
      </dependency>
      <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-client</artifactId>
        <version>1.1.3-SNAPSHOT</version>
      </dependency>
      <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>1.1.3-SNAPSHOT</version>
      </dependency>
      <dependency>
        <groupId>com.sun.jersey.oauth</groupId>
        <artifactId>oauth-signature</artifactId>
        <version>1.1.2-ea-SNAPSHOT</version>
      </dependency>
      <dependency>
        <groupId>com.sun.jersey.oauth</groupId>
        <artifactId>oauth-client</artifactId>
        <version>1.1.2-ea-SNAPSHOT</version>
       </dependency>
    </dependencies>
    <build>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>2.0.2</version>
          <configuration>
            <source>1.6</source>
            <target>1.6</target>
          </configuration>
        </plugin>
      </plugins>
     </build>
    

    The Jersey dependencies add the core Jersey libraries and OAuth functionality in Jersey.
  3. Register your app with Twitter - Register your application with Twitter by clicking on Register a new application >>. The complete list of registered applications can be seen at Applications using Twitter. Select "Client" as the app type, select "Yes, use Twitter for login" and leave the "Callback URL" empty. The registration gives you "consumer key" and "consumer secret". These are used to obtain temporary credentials (or request tokens) from Twitter.
  4. Obtain Twitter OAuth credentials - Each OAuth request is an HTTP request with "Authorization" header specifying the information by OAuth service provider. Jersey provides a OAuthClientFilter to add this header to the outbound client request. Twitter API Wiki explains the authentication as multiple step process for desktop applications. Each step involves sending some parameters to twitter and getting a result back and the intent of each method/request is clearly explained in Understanding the guts of Twitter's OAuth for client apps. In our case, each request is created by using Jersey Client API and attaching OAuthClientFilter and is explained next.
    1. Request temporary credentials, a.k.a request token, from Twitter using oauth/request_token.
      1. In "App.java", create an instance of Jersey client in the constructor and attach a LoggingFilter to dump inbound/outbound messages as:
        public App() {
            // Create a Jersey client
            client = Client.create();
        
            client.addFilter(new LoggingFilter());
        }
        
      2. Request temporary credentials by adding the following method:
        public void getRequestToken() {
            client.removeAllFilters();
        
            // Create a resource to be used to make Twitter API calls
            WebResource resource = client.resource(REQUEST_TOKEN_URL);
        
            // Set the OAuth parameters
            OAuthSecrets secrets = new OAuthSecrets().consumerSecret(CONSUMER_SECRET);
            OAuthParameters params = new OAuthParameters().consumerKey(CONSUMER_KEY).
                    signatureMethod("HMAC-SHA1").version("1.0");
            // Create the OAuth client filter
            OAuthClientFilter oauthFilter =
                    new OAuthClientFilter(client.getProviders(), params, secrets);
        
            // Add the filter to the resource
            resource.addFilter(oauthFilter);
        
            // make the request and print out the result
            System.out.println(resource.get(String.class));
        }
        
        
        Note, "OAuthClientFilter" is used to populate the "Authorization" header instead of handcrafting it. The REQUEST_TOKEN_URL is "http://twitter.com/oauth/request_token", CONSUMER_SECRET and CONSUMER_KEY are the values obtained from registering your application.
      3. Edit "AppTest.java" and change "testApp" method such that it looks like:
        public void testApp() {
            App app = new App();
            app.getRequestToken();
        }
        
      4. Obtain the temporary credentials by running this application as:
        mvn test
        

        and see an output as:
        oauth_token=REQUEST_OAUTH_TOKEN&oauth_token_secret=REQUEST_OAUTH_TOKEN_SECRET&oauth_callback_confirmed=true
        

        REQUEST_OAUTH_TOKEN, a temporary token, is used to authorize on twitter.com.
    2. Authorize the user and obtain PIN
      1. Go to "https://twitter.com/oauth/authorize?oauth_token=REQUEST_OAUTH_TOKEN" in a browser window.
      2. If not already logged in, enter your twitter credentials and click "Allow".
      3. Copy the PIN.
    3. Request permanent credentials, a.k.a access token, from Twitter using oauth/access_token.
      1. Request permanent credentials by adding the following method in "App.java"
        public void getAccessToken() {
                client.removeAllFilters();
        
                // Set the OAuth parameters
                OAuthSecrets secrets = new OAuthSecrets().consumerSecret(CONSUMER_SECRET);
                OAuthParameters params = new OAuthParameters().consumerKey(CONSUMER_KEY).
                        signatureMethod("HMAC-SHA1").
                        version("1.0").
                        token(REQUEST_OAUTH_TOKEN).
                        verifier(PIN);
                // Create the OAuth client filter
                OAuthClientFilter oauthFilter =
                        new OAuthClientFilter(client.getProviders(), params, secrets);
        
                // Create a resource to be used to make Twitter API calls
                WebResource resource = client.resource(ACCESS_TOKEN_URL);
        
                // Add the filter to the resource
                resource.addFilter(oauthFilter);
        
                // make the request and print out the result
                System.out.println(resource.get(String.class));
            }
        
        REQUEST_OAUTH_TOKEN is the temporary token obtained earlier, ACCESS_TOKEN_URL is "https://twitter.com/oauth/access_token".

        Notice, REQUEST_OAUTH_TOKEN and PIN are now added to the OAuthClientFilter.
      2. Invoke this method by editing "AppTest.java" as:
        public void testApp() {
             App app = new App();
        //     app.getRequestToken();
             app.getAccessToken();
        }
        
      3. Obtain the permanent credentials by running this application as:
        mvn test
        

        and see an output as:
        oauth_token=ACCESS_OAUTH_TOKEN&oauth_token_secret=ACCESS_OAUTH_TOKEN_SECRET&user_id=USER_ID&screen_name=USER_NAME
        

        ACCESS_OAUTH_TOKEN is the authorized token that can be used for making any future requests, USER_ID and USER_NAME are identifiers for the user who signed in on twitter.com. 
  5. Get the last 20 status messages for the user from Twitter
    1. Add the following method in "App.java:
      public void getUserTimeline() {
          client.removeAllFilters();
      
          // Set the OAuth parameters
          OAuthSecrets secrets = new OAuthSecrets().consumerSecret(CONSUMER_SECRET);
          OAuthParameters params = new OAuthParameters().consumerKey(CONSUMER_KEY).
                  signatureMethod("HMAC-SHA1").
                  version("1.0").
                  token(ACCESS_OAUTH_TOKEN);
          // Create the OAuth client filter
          OAuthClientFilter oauthFilter =
                  new OAuthClientFilter(client.getProviders(), params, secrets);
      
          // Create a resource to be used to make Twitter API calls
          WebResource resource = client.resource(USER_TIMELINE_URL);
      
          // Add the filter to the resource
          resource.addFilter(oauthFilter);
      
         // Parse the JSON array
          JSONArray jsonArray = resource.get(JSONArray.class);
          List<String> statuses = new ArrayList<String>();
      
          try {
              for (int i = 0; i < jsonArray.length(); i++) {
                  JSONObject jsonObject = (JSONObject) jsonArray.get(i);
                  StringBuilder builder = new StringBuilder();
                  builder.append(jsonObject.getString("text")).
                          append(jsonObject.getString("created_at"));
                  statuses.add(builder.toString());
              }
          } catch (JSONException ex) {
              Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
          }
      } 
      USER_TIMELINE_URL is "http://api.twitter.com/1/statuses/user_timeline.json". The "getTimelineElements" method can be updated to pick other elements from the return JSON object. The complete JSON schema for the response is described here.
    2. Edit "AppTest.java" as:
      public void testApp() {
          App app = new App();
      //    app.getRequestToken();
      //    app.getAccessToken();
          app.getUserTimeline();
      }
      
    3. Finally get the last 20 status updates by giving the command:

      mvn test
      


      and see the output similar to:
      Running org.glassfish.samples.twitter.AppTest
      [Developing OSGi-Enabled Java EE Applications- http://bit.ly/aOim34 (via 
      @JavaOneConf) #javaone10Wed Aug 04 23:53:13 +0000 2010, Google Wave goes
       bye bye (via @google:)Update on Google Wave http://bit.ly/bIoDWAWed Aug
       04 21:16:07 +0000 2010, @gdaniels Yeah, I expected #wave to bye bye as
       well, but this is fairly quick!Wed Aug 04 21:15:41 +0000 2010,
      

And that's it!

This Tip Of The Day explained how to use Jersey to retrieve last 20 status messages that a user posted on twitter. Here are some other future possible additions:

  • POST status update
  • Integrate Search API using OAuth (is it possible ?)
  • Integrate Streaming API (need more investigation)
  • Create a web-base client that automatically redirects the user from application to twitter.com and then back to the application.

Jersey and OAuth wiki provides more details about how to use OAuth with Jersey.

Technorati: totd jaxrs jersey restful webservices oauth twitter glassfish

About

profile image
Arun Gupta is a technology enthusiast, a passionate runner, author, and a community guy who works for Oracle Corp.


Java EE 7 Samples

Stay Connected

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today