Earthly Powers
- All
- Fast Infoset
- General
- Java
- REST
Jersey 0.9 is released
We have just released version 0.9 of Jersey. This aligns with the 0.9 release of the JAX-RS
API
and the editors draft.
For this and further releases the mechanism to obtain Jersey is different. There is no longer one zip file to download. Jersey is now modularized and mavenized thanks to the hard work of Jakub. Jars, source, JavaDoc and samples are all available from the Java.Net maven repo at the following base URI:
All the samples can be obtained individually or as one zip file.
Now it is much easier for maven developers to use Jersey. But as a consequence it is a little harder for non-maven developers to use Jersey. To aid such developers we provide a detailed dependencies document and a bundled jar containing all jersey-related functionality that was previously available in the 0.8 release.
In this release i managed to add support for generic server-side filters and a specific filter to support the "X-HTTP-Method-Override" HTTP header for clients that do not support HTTP PUT and DELETE. Martin has integrated JavaDoclet WADL support. See the example here for more details.
In the past week we have been doing things in parallel and i have been working on the 0.10 implementation before 0.9 is released. We need to step up the pace as the 1.0 finishing line is just a few weeks away.
Posted at 06:08PM Aug 22, 2008 by Paul Sandoz in REST | Comments[0]
Integrating Jersey and Spring: Take 3
Just in case it got hidden in the message of the 0.8 release Jersey now supplies Spring support via the spring maven module that was contributed by Martin.
So, rather than copying some code from my blog, you can depend on this module and reference the Spring servlet:
com.sun.jersey.spi.spring.container.servlet.SpringServlet
in the web.xml. That is it. Martin describes this in more detail here. Note that after this was written some changes were made to the package names as Martin describes here.
I am quite happy with it as we managed to solve a knotty issue of referencing Spring beans in constructor/method parameters that Jersey is responsible for invoking, thus JAX-RS/Jersey-based annotated parameters can be intermixed with Spring-based annotated or referenced parameters. Having said that i think we may be able to make the integration even smoother in two areas when using Spring-based annotation configuration: 1) inferring the life-cycle Jersey requires; and 2) reusing @Autowired for constructor/method parameters.
The mechanisms by which Jersey integrates with Spring can equally apply to Guice or WebBeans or a more specialized integration.
Posted at 08:48AM Aug 18, 2008 by Paul Sandoz in REST | Comments[0]
Parameter beans
In the JAX-RS EG we modified the target of the @Query/Path/MatrixParam annotations so that fields can be annotated on resource classes or on Java beans in general. I was skeptical at first that this would be a good idea (mainly around the life-cycle aspects of resource classes), but Bill Burke convinced me and the EG it would be a good idea. For example, consider a large set of query parameters that keep repeating, having to duplicate that set as method parameters is not ideal.
I finally started experimenting with the idea of supporting such beans in Jersey. To my pleasant surprise there proved to be a rather simple and elegant solution: treat such beans as resource classes.
An InjectableProvider can operate on an annotation, say ResourceParam as follows:
@Provider public static class ResourceParamInjector implements InjectableProvider<ResourceParam, Type> { @Context ResourceContext rc; public Scope getScope() { return Scope.PerRequest; } public Injectable getInjectable(ComponentContext ic, ResourceParam a, Type t) { if (!(t instanceof Class)) return null;final Class c = (Class)t; if (c.isPrimitive()) return null; return new Injectable<Object>() { public Object getValue(HttpContext context) { return rc.getResource(c); } }; } }
Essentially the injected ResourceContext instance is created to obtain the resource class instance.
A resource class could look like this:
@Path("/") public static class Resource { public static class QueryBean { @DefaultValue("abcd") @QueryParam("foo") String foo; @DefaultValue("9999") @QueryParam("bar") int bar; }@GET public String get(@ResourceParam QueryBean qb) { return qb.foo + qb.bar; } }
The fields foo and bar on the QueryBean class behave in the same manner as if they were parameters on the method get or fields on the class Resource.
A side effect of this approach is that the QueryBean class has the same life-cycle rules of a resource class, thus one could annotate it with say @Singleton, which i am not sure is very useful (since @*Param annotations are not allowed on fields of singletons).
Posted at 05:06PM Aug 07, 2008 by Paul Sandoz in REST | Comments[0]
Modularizing Jersey
Jakub (who is now taking a well-deserved holiday) converted the Jersey project over to maven and modularized code. Converting from ant to maven is not easy, the barrier to understanding maven and its idiosyncrasies is rather high in my opinion. Once things are in place and stable i can see the benefit in terms of the build process and what it brings to developers in terms of a network-based dependency system.
We have modularize Jersey functionality into the following modules:
- jersey-core: common code shared between client and server.
- jersey-client: client-side support.
- jersey-server: server-side support.
- jersey-atom: Atom de/serialization using Rome.
- jersey-json: JSON de/serialization using Jettison and JAXB.
- jersey-bundle: contains all the above as one jar (the maven plugin has some bugs that stop the source jar and pom being correctly generated).
Further more the contributions module provides the following sub-modules:
- jersey-spring: spring support for Jersey. In your WebApp use the SpringServlet provided by this module.
- maven-wadl-plugin: improved WADL support, including recognition of JAXB and embedding JavaDoc into WADL to have full documentation associated with the code and provided by the service.
In addition the tests are available and we are converting the examples over to maven projects. There is still more modularization work to do, and as a result the boundaries between modules (mainly between jersey-core and jersey-client/server need to be improved).
Some developers may now be confused as there are two unstable versions of 0.9. The old unstable unmodularized 0.9 is available on java.net as a zip file and also from the maven repo. We have kept this around for developers that do not wish to be affected by maven issues with the new unstable modularized 0.9. The old 0.9 will be removed once we are satisfied with the functionality and stability of the new 0.9.
We have set up Hudson to continuously push 0.9 SNAPSHOT modules to the java.net maven repo when source-code changes occur. However, i have been informed that this is backed by a subversion repository so a history will be kept of all the binary files. So we probably need to switch to the Glassfish maven repo for SNAPSHOT builds as this is not subversion controlled, while using the java.net repo for stable releases.
Posted at 12:23PM Aug 06, 2008 by Paul Sandoz in REST | Comments[0]
EHCache using Jersey
Ehcache is a general purpose distributed caching framework and server written in Java. Greg Luck has reported in a blog entry that the newly released Ehcache 0.3 now supports a RESTful interface using Jersey. Very nice! Greg provides more details on the interface in the blog entry.
Greg also goes into details on how to use this from the client-side. Using the Jersey client API makes it very easy to use the service, for example creating or updating a new cache entry:
String xmlDocument = "...";Client c = Client.create(); WebResource r = c.resource("http://localhost:8080/ehcache/rest/sampleCache2/2"); r.type("application/xml").put(xmlDocument);
Anything other than a 2xx response will result in an UniformInterfaceException being thrown. This makes it easier to manage errors returned from services.
Retrieving the cached entry as a DOM object can be performed as follows:
Node n = r.accept("application/xml").get(DOMSource.class).getNode();
Again, anything other than a 2xx response will result in an exception being thrown. Alternatively it is possible to check more details of the response:
ClientRespone cr = r.get(ClientResponse.class);
if (cr.getStatus() < 300 &&
cr.getType().isCompatibleWith(MediaType.APPLICATION_XML_TYPE)) {
Node n = cr.getEntity(DOMSource.class).getNode();
}
Notice that in the above two cases the WebResource instance r is reused.
Caching can be performed on the client side too, so i am wondering if the Jersey client API could reuse Ehcache for a caching solution, embedded (file or in-memory) or networked. Jersey client filters could written and installed to check the cache first.
Posted at 11:32AM Aug 06, 2008 by Paul Sandoz in Fast Infoset | Comments[0]
BBC using Jersey
A recent comment on a blog entry from Jon, a developer at the BBC, says:
Thought you might be interested to hear that here at the BBC we now have a RESTFul JSR311 compliant webservice implemented using Jersey running with Jetty.
It is currently for internal use only but is part of an editorial toolset that Sports Journalists are using.
Nice, great news Jon! Maybe in some modest way Jersey will be contributing to the reporting of the Olympics :-)
Posted at 11:01AM Aug 06, 2008 by Paul Sandoz in REST | Comments[0]
Services are clients too
RESTful services can also be clients that make RESTful requests to other services. Jersey has a client API and resource classes can use that to efficiently make such requests.
Following on from my last blog entry on injection i can combine injection with a client API to make things a little easier. So i can have a resource class that does the following:
@Path("/") public static class Resource { @GET public String get( @WebResourceRef("http://localhost:9999/one") AsyncWebResource r1, @WebResourceRef("http://localhost:9999/two") AsyncWebResource r2) throws InterruptedException, ExecutionException { Future<String> c1 = r1.path("foo").get(String.class); Future<String> c2 = r2.path("bar").get(String.class);return c1.get() + c2.get(); }@GET @Path("one/{stuff}") public String getOne(@PathParam("stuff") String stuff) { return stuff; }@GET @Path("two/{stuff}") public String getTwo(@PathParam("stuff") String stuff) { return stuff; } }
The get method has two parameters that are annotated with @WebResourceRef that declares client-based URIs. I wrote an InjectableProvider for that annotation that creates instances of AsyncWebResource or WebResource (see end of this entry for complete source that should work with Jersey 0.8) based on the URI. When that method is invoked it makes two asynchronous requests, to sub-resource methods of the same resource class, and returns the result.
I think this is interesting enough to include support for this in Jersey.
import com.sun.grizzly.http.SelectorThread;
import com.sun.jersey.api.client.AsyncWebResource;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.container.grizzly.GrizzlyServerFactory;
import com.sun.jersey.api.core.HttpContext;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
import com.sun.jersey.spi.service.ComponentContext;
import com.sun.jersey.spi.service.ComponentProvider.Scope;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Type;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.ext.Provider;
public class Main {
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public static @interface WebResourceRef {
String value();
}
@Provider
public static class WebResourceProvider implements InjectableProvider<WebResourceRef, Type> {
private final Client client;
public WebResourceProvider() {
this.client = Client.create();
}
public Scope getScope() {
return Scope.PerRequest;
}
public Injectable getInjectable(ComponentContext cc, final WebResourceRef wrr, Type t) {
if (!(t instanceof Class)) return null;
Class c = (Class)t;
if (WebResource.class == t) {
return new Injectable<WebResource>() {
public WebResource getValue(HttpContext c) {
return client.resource(wrr.value());
}
};
} else if (AsyncWebResource.class == t) {
return new Injectable<AsyncWebResource>() {
public AsyncWebResource getValue(HttpContext c) {
return client.asyncResource(wrr.value());
}
};
} else {
return null;
}
}
}
@Path("/")
public static class Resource {
@GET
public String get(
@WebResourceRef("http://localhost:9999/one") AsyncWebResource r1,
@WebResourceRef("http://localhost:9999/two") AsyncWebResource r2)
throws InterruptedException, ExecutionException {
Future<String> c1 = r1.path("foo").get(String.class);
Future<String> c2 = r2.path("bar").get(String.class);
return c1.get() + c2.get();
}
@GET
@Path("one/{stuff}")
public String getOne(@PathParam("stuff") String stuff) {
return stuff;
}
@GET
@Path("two/{stuff}")
public String getTwo(@PathParam("stuff") String stuff) {
return stuff;
}
}
public static void main(String[] args) throws Exception {
SelectorThread st = GrizzlyServerFactory.create("http://localhost:9999/");
try {
Client c = Client.create();
WebResource r = c.resource("http://localhost:9999/");
String s = r.get(String.class);
System.out.println(s);
} catch (UniformInterfaceException e) {
System.out.println(e.getResponse().getStatus());
e.printStackTrace();
} finally {
st.stopEndpoint();
System.exit(0);
}
}
}
Posted at 05:33PM Jun 27, 2008 by Paul Sandoz in REST | Comments[9]
@EJB injection
Jersey has a simple injection provider SPI for injecting instances for annotated fields, method/constructor parameters or setter methods. So it is possible to plug-in your own injection functionality.
Out of the box there is currently no EE-based functionality supported in Jersey but using the injection provider SPI it is very easy to have basic support for @EJB in one small class.
If you have the following resource:
@Path("foo")
public class FooResource {
@EJB private FooSessionRemote fooSessionRemoteBean;
@GET
@ProduceMime("text/plain")
public String get() throws Exception {
return fooSessionRemoteBean.fooMethod();
}
}
then the field fooSessionRemoteBean should get injected with an instance of the remote EJB interface.
The following provider class supports this behaviour:
@Provider
public class EJBProvider implements InjectableProvider<EJB, Type> {
public Scope getScope() {
return Scope.Singleton;
}
public Injectable getInjectable(ComponentContext cc, EJB ejb, Type t) {
if (!(t instanceof Class)) return null;
try {
Class c = (Class)t;
Context ic = new InitialContext();
final Object o = ic.lookup(c.getName());
return new Injectable<Object>() {
public Object getValue(HttpContext c) {
return o;
}
};
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
The EJB reference is looked up using JNDI then an Injectable instance is returned with that reference. This is efficient for per-request resources as the JNDI look up is only performed once. Since the above class is annotated with @Provider it will get picked up and treated like any other provider.
Obviously this could do with some polish to fully implement @EJB injection functionality but i think this example is instructive how one could support other annotations.
Posted at 02:16PM Jun 26, 2008 by Paul Sandoz in REST | Comments[14]
Jersey 0.8 is released
We have just released version 0.8 of Jersey (see the stable
download directory). This aligns with the 0.8 release of the JAX-RS
API
and the public review draft.
We made excellent progress in this time trial and we are releasing at least a week earlier than expected. This is good as it lets me show off 0.8 at Jazoon next week and lets us concentrate on the 0.9 etape over the summer period.
This version will be available soon from the Glassfish v2 and v3 update centers, and will be making it's way into NetBeans 6.5.
Thanks to the work of Jakub, Martin, Doug and others we are now pushing snapshot releases to here in the java.net maven 2 repository. This occurs automatically thanks to Hudson. Jakub shows how easy it is to use embedded Glassfish with Jersey from the maven 2 repository. The stable version has also been pushed, but as of writing there is an issue with the java.net maven repository infrastructure causing things to be delayed. When it appears we will send out another blog.
Martin has contributed Spring-based servlet support that is here in java.net maven 2 repository. This is great, now developers don't have to copy old code from mine and Marc's blog entries. Anybody willing to contribute support for Guice?
I refactored the container SPIs. Now it is much cleaner and easier, but more importantly it provides the basis for better Comet support and filtering that i hope to progress in 0.9. I also managed to unify the injection framework, make it more pluggable, and much more efficient for per-request resources.
It is a significant effort to transform a project from ant to maven and we are currently in an "interesting" transitional phase we hope to complete for the 0.9 release. As part of this we plan to split Jersey up into components as well as providing bundles, just like Grizzly does. So, hopefully, a developer can reduce the overall size of the jars required. For example, if a developer wants to use just the client API they are currently required to use the jar with all the unused server-side functionality. I believe this may also be advantageous for those wanting a smaller footprint for embedded servers.
After the successful Spring integration Martin is now working on a very interesting development combining JavaDoc doclets and WADL. The upshot of this work is that JavaDoc comments in resource classes will be pulled into the generated WADL document meaning that a developer does not have to separate documentation from the code of their RESTful Web services. See here for more details. I want to get this functionality merged into snapshot builds as soon as possible!
Posted at 05:38PM Jun 20, 2008 by Paul Sandoz in REST | Comments[6]
JavaOneDemo in Scala
For some light entertainment I converted the JavaOneDemo over to a Scala-based version, see here. It is by no means complete, there is still some Java code (which shows how one can mix the two in the same project) and i know it can be improved by using Scala's native XML support.
I am getting increasingly grumpy with the verbosity of Java and the reduction that Scala offers is good (i wish i could write Jersey completely in Scala, i would be more productive and i think the code would be better, but the downside is it would limit adoption for those wishing to mess around with the code base).
Here is a bit of the Java code:
@ProduceMime("application/xhtml+xml") public class SystemProperty { Properties properties; String name; String value;SystemProperty(Properties properties, String name) { this.properties = properties; this.name = name; this.value = properties.getProperty(name); if (value == null) throw new WebApplicationException(Response.Status.NOT_FOUND); }@GET public Property getProperty() { return new Property(name, value); }@PUT @ConsumeMime("text/plain") public void updateProperty(String newValue) { properties.setProperty(name, newValue); }@DELETE public void deleteProperty() { properties.remove(name); } }
Now compare that with the equivalent Scala code:
@ProduceMime(Array("application/xhtml+xml")) class SystemProperty(properties : Properties, name : String) { val value = properties.getProperty(name) if (value == null) throw new WebApplicationException(Response.Status.NOT_FOUND)@GET def getProperty = new Property(name, value)@PUT @ConsumeMime(Array("text/plain")) def updateProperty(newValue : String) : unit = properties.setProperty(name, newValue)@DELETE def deleteProperty() : unit = properties.remove(name) }
This class uses Scala concise constructors and the Scala compiler is smart enough to know whether the constructor parameters need to be fields on the class. Unfortunately Scala does not perform auto-boxing of arrays, which is
why you see Array("application/xhtml+xml") in the
@ProduceMime annotation (this gets more annoying when using the JAX-RS builder-related methods). Notice how you can write the equivalent constructor logic directly in the class.
For first @GET method Scala does not require that you declare the return type, it works it out. So this can be written concisely in one line.
I would like to write some "Scala-sugar" for classes like UriInfo and Response to improve EOU in Scala in addition to further investigating use of Scala features like closures as experimented with previously.
Posted at 01:47PM Jun 06, 2008 by Paul Sandoz in REST | Comments[8]
@FormParam
I have been unifying the injection mechanism in Jersey, making it more modular and improving the performance of injection (now it is possible to plug-in your own injectable behavior for injecting on to fields, constructors and resource methods, including overriding or augmenting existing behavior... more later in another entry perhaps...).
As a serendipitous consequence of those changes it was so easy to implement the support for form parameters i could not resist (in fact the implementation is pluggable so i could have provided the functionality as a separate jar if so desired). In less than 2 hours it was in the main trunk :-)
So by popular request (many have requested this on the users list) I introduce @FormParam.
You can write a resource as follows:
@Path("/")
public class Resource {
@POST
@ConsumeMime(MediaType.APPLICATION_FORM_URLENCODED)
public String post(
@FormParam("a") String a,
@FormParam("b") String b) {
return a + b;
}
}
and test it with the client API:
WebResource r = Client.create().resource("/")'
Form form = new Form();
form.add("a", "foo");
form.add("b", "bar");
String s = r.post(String.class, form);
Form parameters will only work with resource methods where each parameter is annotated and at least one parameter is annotated with @FormParam. The same rules apply as for the other parameters, such as @QueryParam (with the exception that the encoded form is not currently supported).
Posted at 03:57PM May 27, 2008 by Paul Sandoz in REST | Comments[0]
JavaOne slides and demo
Here are the JavaOne slides Marc and I presented.
Here is the zip of the completed demo written in Java as a NetBeans project.
Posted at 02:20PM May 26, 2008 by Paul Sandoz in REST | Comments[2]
MVCJ
Or Model, View, Controller and Jersey
Perhaps a little know fact (i should have blogged about it sooner) is that Jersey has support for the MVC paradigm and pluggable template processing.
A Controller is a resource class, a model is returned by a resource method, and a view is a template (which is processed by an associated template processor) that operates on the model.
The MVC approach taken by Jersey was inspired by the mechanism in Hudson and it's underlying framework, Stapler.
Jersey supports two types of MVC: explicit; and implicit.
Explcit MVC
A resource method can explicitly return a reference to a template and a model. For example, given the following resource class:
package com.foo;
@Path("foo")
public class Foo {
@GET
public Viewable get() {
return new Viewable("index", "FOO");
}
}
Foo is the controller, and when the method get is invoked, it returns the model "FOO" and a reference to the view (the template) "index", both of which are encapsulated in the Viewable instance.
The template reference "index" is a relative so Jersey will resolve it to an absolute template reference, using the fully qualified class name of Foo, to the following:
"/com/foo/Foo/index"
Then Jersey will search the registered template processors (more detail on this later) to find a template processor that can resolve it further to a processable template reference. If a template processor is found then the processable template is processed using the model.
If instead the get method is as follows:
@GET
public Viewable get() {
return new Viewable("/index", "FOO")
}
Jersey will not resolve the template reference as it is considered resolved, since it begins with "/". The reference will however be resolved to a processable template reference as previously described.
All HTTP methods may return Viewable instances. Thus a POST method may return a template reference to a template that produces a view that is the result of processing a form.
Implicit MVC
A resource class can have templates implicitly associated (this is the style used by Hudson). For example, given the following resource class:
@Path("foo")
public class Foo {
public String getFoo() {
return "FOO";
}
}if there exists a template reference "index" that resolves to an absolute template reference "/com/foo/Foo/index" that in turn resolves to a processable template reference then a @GET method will be implicitly added to the Foo controller that performs the equivalent of the following explicit resource method:
@GET
public Viewable get() {
return new Viewable("index", this)
}
Notice that the model is the controller. In this case the template reference "index" is special, it is the template reference associated with the controller itself.
Implicit sub-resources are also allowed, for example, if there is a template reference "bar" that resolves to an absolute template reference "/com/foo/Foo/bar" that in turn resolves to a processable template reference then a @GET method will be implicitly added to the Foo controller that performs the equivalent of the following explicit sub-resource method:
@Path("bar") @GET
public Viewable get() {
return new Viewable("bar", this);
}This all works dynamically (as is the case for explicit MVC) so it is possible (if the deployment system is configured correctly) to add or modify templates while the application is running.
To enable implicit MVC it is necessary to set the following configuration feature to true:
"com.sun.jersey.config.feature.ImplicitViewables"
Furthermore this only works for HTTP GET requests and only if there are no equivalent explicit @GET resource methods (namely explicit resource methods take precedence over implicit resource methods).
The Bookstore example in the Jersey distribution contains a working example using implicit MVC with JSP pages.
JSP support
Jersey provides MVC support for JSP pages. There is a JSP template processor that resolves absolute template references to processable template references that are JSP pages as follows:
- if the absolute template reference does not end in ".jsp" append it to the reference; and
- if Servlet.getResource returns a non-null value for the appended reference then return the appended reference as the processable template reference otherwise return null.
Thus the absolute template reference "/com/foo/Foo/index" would be resolved to "/com/foo/Foo/index.jsp" if there exists the JSP page "/com/foo/Foo/index.jsp" in web the application.
Jersey will assign the model instance to the attribute named "it". So in the case of the implicit example it is possible to access the foo property on the Foo controller as follows:
<h1>${it.foo}</h1> Pluggable template processors
Template processors are providers so it is possible to implement a processor as follows:
@Provider
public MyTemplateProcessor implements TemplateProcessor {
String resolve(String path) { ... }
void writeTo(String resolvedPath, Object model, OutputStream out)
throws IOException { ... }
}
If using the class or package scanning techniques then such a provider will get automatically registered. In addition such a component can be managed by a registered IoC framework and injection of standard JAX-RS and Jersey components is possible.
If i recall correctly (from the Jersey users list) a developer successfully plugged in Freemarker support in a couple lines in addition to supporting JAXB to XSLT translations. One interesting aspect of using template engines such as Freemarker or Velocity is it is possible to write a set of resource classes that provide their own templates, thus potentially allowing easy way to plug-in extensions to a web application (ala the Hudson style).
When writing template processors it is recommend that you use an appropriate unique suffix for the processable
template references. Then it is possible to easily intermix multiple template processors without any conflict.
The implementation of the JSP template processor is presented at the end of this blog entry.
public class JSPTemplateProcessor implements TemplateProcessor {@Context ServletContext servletContext;
public JSPTemplateProcessor() {
Class<?> c = ServletContext.class;
}
public String resolve(String path) {
if (servletContext == null)
return null;
if (!path.endsWith(".jsp"))
path = path + ".jsp";
try {
if (servletContext.getResource(path) == null) {
// TODO log
return null;
}
} catch (MalformedURLException ex) {
// TODO log
return null;
}
return path;
}
@Context HttpContext hca;
public void writeTo(String resolvedPath, Object model, OutputStream out) throws IOException {
HttpResponseContext response = hca.getResponse();
((HttpResponseAdaptor)response).forwardTo(resolvedPath, model);
}
}
Posted at 01:45PM May 26, 2008 by Paul Sandoz in REST | Comments[3]
Jersey 0.7 is released

We have just released version 0.7 of Jersey (see the stable download directory). This aligns with the 0.7 release of the JAX-RS API and the March editors draft.
This version will be available soon from the Glassfish Update Centre.
Phew! this was a tough one. There were many additions and clarifications to the API. The email statistics for the 311 EG list looks like a climb profile (maybe up Alpe D'Huez like Lance if you squint your eyes).
So most of our time was spent on API aspects.
However, Jakub got some good feedback on the JSON support and fixed related bugs.
Martin Grotzke has been working on improving Spring, and in general IoC integration, support in a branch. The plan is to make this part of the 0.8 distribution, and hopefully we will manage to solve some difficult issues w.r.t. mixing IoC-based and Jersey-based components when injecting parameters of constructor/methods that Jersey is responsible for invoking.
I finally managed to play around with the latest JavaRebel and SDK and formalize the reloading of the Jersey runtime when resource classes are added, modified or removed.
As a nice bonus Jean Francois kindly visited Grenoble for a day and we hashed out a Grizzly/Comet/Jersey prototype. I think we may have a very interesting and simple way of integrating Comet functionality with resource classes. Jean Francois has created a branch and we will work from that to progress such support. Unfortunately i did not have time to move to Grizzly 1.7.3 but i am very excited about prospects for 1.8.0 and an asynchronous client-side API based on Grizzly as i can make good use of that with the Jersey client-side API.
Now it is time to prepare for JavaOne. Marc and I have a technical session on JAX-RS @ Tuesday 12:10. Jakub and I have a BOF on Jersey @ Tuesday 20:30. I should be around for the GF unconference on the Sunday before, and will be partially around for the CommunityOne event on the Monday before (Marc and I have to prepare for the session so we cannot attend for the whole day).
I am thinking of two possible dates for the 0.8 release, 20th June or the 25th of July. The reason being is the Jazoon conference is at the end of June, we need to relax a bit (i go on holiday a week after Jazoon for 2 weeks), and there are more API changes to implement although not of Alpe D'Huez proportions.
Posted at 01:49PM Apr 18, 2008 by Paul Sandoz in REST | Comments[4]
JavaRebel and Jersey: Take 2
Since i last played with JavaRebel it has been through one or more updates and now has an SDK. It is also been a while since i blogged, from the graph generated by Marc you should be able to determine why.
Finally i managed to get some time to revisit JavaRebel (many thanks to Jevgeni Kabanov for updating me on the progress of JavaRebel and sending pointers to relevant information). This entry explains how to dynamically reload the Jersey deployed web application in response to callbacks from JavaRebel when in detects changes to class files. Because Jersey caches runtime information about classes, for performance reasons, it needs to be informed to update information about classes that have changed. So adding a new HTTP method or a new resource class can be detected.
The code at the end of the blog shows a complete example that can work with the latest build of Jersey 0.7, JavaRebel 1.1 M3 and the JavaRebel SDK 1.1 M3.
To connect JavaRebel to Jersey we need to implement two interfaces, the JavaRebel inteterface ReloadListener and the Jersey interface ContainerNotifier:
01 private static class Reloader implements ContainerNotifier,
02 ReloadListener {
03 private final List<ContainerListener> ls;
04
05 private final ClasspathResourceConfig rc;
06
07 public Reloader(ClasspathResourceConfig rc) {
08 ls = new ArrayList<ContainerListener>();
09 this.rc = rc;
10 }
11
12 public void addListener(ContainerListener l) {
13 ls.add(l);
14 }
15
16 public void reloaded(Class arg0) {
17 rc.reload();
18 for (ContainerListener l : ls) {
19 l.onReload();
20 }
21 }
22 }
The method reloaded on line 16 will get invoked every time JavaRebel detects a change to a Java class. The method addListener will get called by a Jersey container that wants to listen to container-based notifications. All containers shipped with Jersey will add a ContainerListener to a ContainerNotifier (if one is present, see later). When the reloaded method is invoked the class path is rescanned for classes then each listener registered with the container notifier will notified by an invocation of the onReload method (see line 19).
Next the ReloadListener and the ContainerNotifier need to be registered:
01 ClasspathResourceConfig rc = new ClasspathResourceConfig();
02 Reloader r = new Reloader(rc);
03
04 rc.getProperties().put(
05 ResourceConfig.PROPERTY_CONTAINER_NOTIFIER, r);
06 ReloaderFactory.getInstance().addReloadListener(r);
07
08 HttpServer s = HttpServerFactory.create("http://localhost:9999/",
09 ContainerFactory.createContainer(HttpHandler.class, rc));
10 s.start();
Lines 1 and 2 create the resource configuration (that scans class paths) and creates the reloader as previously shown. Lines 4 and 5 register the ContainerNotifier with Jersey by adding a property to the resource configuration. Line 6 registers the ReloadListener with JavaRebel. Finally lines 8, 9 and 10 start the Light Weight HTTP Server.
So if we configure to use JavaRebal, build and run the app, then change the code of the simple web application, recompile while still running, then Jersey will update accordingly.
I think the general concept works OK but it does require some finessing as currently it could be described as a rather brutish approach. A reload will occur for every class that has changed so Jersey will perform unnecessary reloads. I don't know how JavaRebel works but it may be useful to provide reloading within an a scope of "startReload" and "endReload". Furthermore Jersey needs to know about classes that have been removed and not just those that have been modified or added (i have not tested what JavaRebel does when classes are removed). On the Jersey side i think we can refine this to support add/update or deletion of classes. For resource classes this is probably fairly easy. For provider classes it is a little more work.
I could imagine such reloading capability might be useful not just for rapid development but for dynamic deployment of additional root resource classes as and when they are required.
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.ws.rest.api.container.ContainerFactory;
import com.sun.ws.rest.api.container.httpserver.HttpServerFactory;
import com.sun.ws.rest.api.core.ClasspathResourceConfig;
import com.sun.ws.rest.api.core.ResourceConfig;
import com.sun.ws.rest.spi.container.ContainerListener;
import com.sun.ws.rest.spi.container.ContainerNotifier;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.zeroturnaround.javarebel.ReloadListener;
import org.zeroturnaround.javarebel.ReloaderFactory;
public class Main {
@Path("/{id}")
public static class RebelResource {
@GET
public String getOne(@PathParam("id") int id) {
return Integer.toString(id) + "x";
}
}
private static class Reloader implements ContainerNotifier,
ReloadListener {
private final List<ContainerListener> ls;
private final ClasspathResourceConfig rc;
public Reloader(ClasspathResourceConfig rc) {
ls = new ArrayList<ContainerListener>();
this.rc = rc;
}
public void addListener(ContainerListener l) {
ls.add(l);
}
public void reloaded(Class arg0) {
rc.reload();
for (ContainerListener l : ls) {
l.onReload();
}
}
}
public static void main(String[] args) throws Exception {
ClasspathResourceConfig rc = new ClasspathResourceConfig();
Reloader r = new Reloader(rc);
rc.getProperties().put(
ResourceConfig.PROPERTY_CONTAINER_NOTIFIER, r);
ReloaderFactory.getInstance().addReloadListener(r);
HttpServer s = HttpServerFactory.create("http://localhost:9999/",
ContainerFactory.createContainer(HttpHandler.class, rc));
s.start();
try {
System.in.read();
} finally {
s.stop(0);
}
}
}
Posted at 06:07PM Apr 16, 2008 by Paul Sandoz in REST | Comments[2]