Japod's blog
Archives
« November 2009
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
Click me to subscribe
Search

Links
 

View My Stats
Main | Next page »
Tuesday Jul 21, 2009
Jersey 1.1.1-ea Packages Available At GlassFish Update Center Repositories

Jersey version 1.1.1-ea was released a week ago. Paul described what's new at the released version at his blog.

Corresponding packages are now available to all GlassFish v2 users. The Jersey 1.1.1-ea packages were also published for selected GlassFish v3 based distributions and integrated into the v3 main trunk for those, who rely on the nightly builds. Enjoy!

Posted at 06:40PM Jul 21, 2009 by Jakub Podlesak in REST  |  Comments[3]

Monday Apr 27, 2009
Jersey 1.0.3 GlassFish V3 packages split up

Jersey version 1.0.3 is now available also to GlassFish V3 Prelude users via GFv3 update center. I am writing this, because several changes happened about how things work there.

As you can see at the snapshot, the first big change relates to number of Jersey packages. Started from the 1.0.3 version, we are providing two separate packages.

We are going to integrate with GlassFish V3 bits, so that people would not need to install Jersey separately. And as we wanted to lower the Jersey footprint in GlassFish V3, we have broken the original Jersey package down into two separate modules:

The "Jersey Core" package contains OSGI modules for jersey-bundle, jettison, and jackson-asl libraries. This should be sufficient for you to deploy Jersey based web applications to GlassFish V3 Prelude without a need to bundle any Jersey related jars with your application WAR file and should be good for production.

"Jersey Examples and Documentation" package contains Jersey API javadocs and some examples. This package should be useful especially for developers, who want to learn Jersey, and see how it works before developing their own RESTful web applications. If you choose this package, the UC client will automatically install also the "Jersey core" module, and you will get installed everything you need to start up.

A rather cosmetic change happened to location, where jersey subdirectory gets installed into. It has moved from $AS_HOME/jersey to $AS_HOME/glassfish/jersey.

When upgrading from earlier versions of Jersey, you could be a bit confused with consequences of the above described changes. So if you upgraded into a newer Jersey version and try to figure out, where all Jersey examples and docs went, just install "Jersey Examples and Documentation" in addition and it should re-appear in $AS_HOME/glassfish/jersey.

Posted at 11:52AM Apr 27, 2009 by Jakub Podlesak in REST  |  Comments[0]

Wednesday Apr 22, 2009
Jersey aplication sharing Grizzly with static content and servlets

I was asked the question some time ago by one of my colleges here at SUN, and the same question was asked again recently at our user mailing list: "I want to run Jersey based application on Grizzly web server, but i want to also run another servlet from there, and possibly also serve some static content using the very same Grizzly sever instance. How do i do that?"

The answer is as simple as follows. Having imported

import com.sun.grizzly.http.embed.GrizzlyWebServer;
import com.sun.grizzly.http.servlet.ServletAdapter;
import com.sun.jersey.spi.container.servlet.ServletContainer;

You can just use:

        // static content is linked from here
        GrizzlyWebServer gws = new GrizzlyWebServer(8080, "/var/www");

        // Jersey web resources
        ServletAdapter jerseyAdapter = new ServletAdapter();
        jerseyAdapter.addInitParameter("com.sun.jersey.config.property.packages",
                "com.example");
        jerseyAdapter.setContextPath("/jersey");
        jerseyAdapter.setServletInstance(new ServletContainer());
        
        // Another non-Jersey servlet
        ServletAdapter simpleServletAdapter = new ServletAdapter();
        simpleServletAdapter.setContextPath("/simple");
        simpleServletAdapter.setServletInstance(new SimpleServlet());

        // register all above defined adapters
        gws.addGrizzlyAdapter(jerseyAdapter, new String[] {"/jersey"});
        gws.addGrizzlyAdapter(simpleServletAdapter, new String[] {"/simple"});

        // let Grizzly run
        gws.start();

Your Jersey resource classes are placed in com.example package, and will become accessible at http://localhost:8080/jersey base. Your static content for http://localhost:8080/ is taken from /var/www directory and a SimpleServlet will become available at http://localhost:8080/simple.

The only dependency you will need to include other than Jersey dependencies itself is

        <dependency>
            <groupId>com.sun.grizzly</groupId>
            <artifactId>grizzly-servlet-webserver</artifactId>
            <version>1.9.10</version>
        </dependency>

If you are interested in some more advanced scenarios, you can get inspired at Jean-Francois Arcand's blog post

Posted at 12:04PM Apr 22, 2009 by Jakub Podlesak in REST  |  Comments[3]

Friday Feb 13, 2009
Configuring JSON for RESTful Web Services in Jersey 1.0.2

This is an update for a tech tip on configuring JSON in Jersey, which i wrote in October 2008. The way of JSON configuration, suggested in the tech tip, is now deprecated (but still functioning). Here i would like to describe the new API, which will hopefully last (and be supported) a way longer.

Notice: you will need to bundle jaxb-impl-2.1.10.jar with your application in order to take advantage of the recently added JSON NATURAL convention

Deprecated Configuration

Configuring JSON format, as described in the tech tip, meant to implement a JAXBContext resolver class returning an instance of JSONJAXBContext. This principle have not changed. What changed is a way, how the JSONJAXBContext itself is being configured. Lets look at the sample code below (using the deprecated API):

   @Provider
   public class MyJAXBContextResolver implements ContextResolver<JAXBContext> {

       private JAXBContext context;
       private Class[] types = {StatusInfoBean.class, JobInfoBean.class};

       public MyJAXBContextResolver() throws Exception {
           Map props = new HashMap<String, Object>();
           props.put(JSONJAXBContext.JSON_NOTATION, JSONJAXBContext.JSONNotation.MAPPED);
           props.put(JSONJAXBContext.JSON_ROOT_UNWRAPPING, Boolean.TRUE);
           props.put(JSONJAXBContext.JSON_ARRAYS, new HashSet<String>(1){{add("jobs");}});
           props.put(JSONJAXBContext.JSON_NON_STRINGS, new HashSet<String>(1){{add("pages"); add("tonerRemaining");}});
           this.context = new JSONJAXBContext(types, props);
       }

       public JAXBContext getContext(Class<?> objectType) {
           return (types[0].equals(objectType)) ? context : null;
       }
   }

There you needed to create a property bag, put appropriate configuration options into it, and then pass it to the JSONJAXBContext constructor.

Jersey 1.0.2 JSON Configuration

In the currently available 1.0.2 Jersey version, a new JSONConfiguration class was introduced to became a central point for JSON configuration options. For creating a new JSONConfiguration instance, a builder pattern is employed. It is not only more user friendly, but also ensures only meaningful JSON options could be combined together. You can compare the following code, with the deprecated example above:

   @Provider
   public class MyJAXBContextResolver implements ContextResolver<JAXBContext> {

       private JAXBContext context;
       private Class[] types = {StatusInfoBean.class, JobInfoBean.class};

       public MyJAXBContextResolver() throws Exception {
           this.context = new JSONJAXBContext(
                   JSONConfiguration.mapped()
                                      .rootUnwrapping(true)
                                      .arrays("jobs")
                                      .nonStrings("pages", "tonerRemaining")
                                      .build(),
                   types);
       }

       public JAXBContext getContext(Class<?> objectType) {
           return (types[0].equals(objectType)) ? context : null;
       }
   }

You can look at JSONConfiguration javadoc for detailed information on various configuration options.

Further Simplification

If you go a bit further, you can ask if the configuration could be simplified even more. Imagine you have much bigger number of JAXB beans in your model, and they are more complex. It could easily become unmanageable to maintain a reasonable JSON configuration as described so far. Then if you happen to have conflicting non-string/string values and/or arrays/non-arrays elements in your set, you could easily run out of options there.

A natural way to overcome above mentioned issues, is to simply use recently introduced Jersey NATURAL JSON notation. Then you need only to:

   @Provider
   public class MyJAXBContextResolver implements ContextResolver<JAXBContext> {

       private JAXBContext context;
       private Class[] types = {StatusInfoBean.class, JobInfoBean.class};

       public MyJAXBContextResolver() throws Exception {
           this.context = new JSONJAXBContext(
                   JSONConfiguration.natural().build(),
                   types);
       }

       public JAXBContext getContext(Class<?> objectType) {
           return (types[0].equals(objectType)) ? context : null;
       }
   }

Such configuration is simple from user point of view, but yet very powerful. You do not need to keep various configuration options in sync with your actual JAXB beans, and be worried what options to actually use (what exact names, etc.). Jersey will automatically take care about serializing Java collections/arrays as JSON arrays, Java booleans as JSON booleans, Java ints as JSON integers,and so on.

Posted at 03:30PM Feb 13, 2009 by Jakub Podlesak in REST  |  Comments[11]

Wednesday Jan 28, 2009
Jersey Based Java Client Talking to SmugMug

Jersey provides a great, easy-to-use REST client API. Recently someone wrote to our mailing list the opposite. We probably need to advertise better.

Paul initially introduced the API in this blog post almost a year ago. But it is, of course, not the only place to look at. Javadoc for Jersey Client API could be found here.

The Jersey Client API could be used pretty easily. However, instead of describing the API in detail, i would just like to present here a real life example. A Jersey based client talking to a 3rd party server application. The server application happens to be SmugMug. A photo sharing service application. I wrote the client application during the last Xmas break, because what was provided by SmugMug did not work well for me. I am happy with my Solaris, but sometimes i wish i have chosen another OS for my laptop ;-)

Putting together a functional prototype took me only a couple of hours, and this was mainly thanks to user friendliness of the Jersey Client API designed by Paul. Following is a screenshot of the main screen of the client.

I promised not to dig into details, but just for your curiosity. Only the very last statement of the java code below has anything to do with actual invocation of SmugMug API from java using Jersey Client API. All the rest is only about computing a digest for the file being sent, as SmugMug API requires it sent in a special HTTP request header.

MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
File picFile = new File(picDir, pic);
fis = new FileInputStream(picFile);
byte[] buf = new byte[8196];
int l;
while ((l = fis.read(buf)) > -1) {
  digest.update(buf, 0, l);
}
String md5hash = asHex(digest.digest());

cr = uploadWebResource
         .path(pic)
         .header("Content-MD5", md5hash)
         .header("X-Smug-SessionID", sessionId)
         .header("X-Smug-Version", "1.2.0")
         .header("X-Smug-ResponseType", "JSON")
         .header("X-Smug-AlbumID", car.album.id)
         .put(ClientResponse.class, picFile);
Posted at 06:48PM Jan 28, 2009 by Jakub Podlesak in REST  |  Comments[2]

Friday Jan 23, 2009
Christmas present folow-up

In December, Paul described a way to easily obtain Jersey jar files from web. It was mainly focused on non-maven users. Then Ben asked for a zip file containing the jars.

From now on, everybody can obtain such a zip archive at http://download.java.net/maven/2/com/sun/jersey/jersey-archive. You just need to select a version of Jersey and your preferred archive format. Zip archive of current snapshot is available at http://download.java.net/maven/2/com/sun/jersey/jersey-archive/1.0.2-SNAPSHOT/jersey-archive-1.0.2-SNAPSHOT.zip. Gzipped and bzipped tar archives are available as well, with smaller footprints.

The archive contains 3 directories:

jersey
contains core jersey jars and it's dependencies
contribs
contains jersey modules contributed by community. You will need to download possible dependencies separately
apidocs
contains javadocs for JSR-311 and Jersey
Posted at 04:30PM Jan 23, 2009 by Jakub Podlesak in REST  |  Comments[0]