Wednesday, July 30, 2008

Using Jersey for exposing REST services

I just started integrating Jersey in Artifactory and I have to say: I'm impressed!
Like the XFire (still crying on its death :( ) I really like the process of: Write a simple annotated POJO, compile and run, that's it.

Anyway, since I encountered a couple of issues, and implemented some nice extra (XStream adapter and Spring beans injection) here are my findings.
First thanks to getting started entry and getting started with jersey that convinced me Jersey is the way to go.

Getting started


I'm using Maven and Jetty and so running the HelloWorld example got this bug 70. Setting up the Annotation scanner per Java packages solves the problem, and anyway sounds a lot more manageable to me. So here is my web.xml (for 0.8):
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.artifactory.rest.servlet.ArtifactoryRestServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
<param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>org.artifactory.rest</param-value>
</init-param>
<!-- Usable only in 0.9 version of Jersey
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>org.artifactory.rest.common.AuthorizationContainerRequestFilter</param-value>
</init-param>
-->
<load-on-startup>1</load-on-startup>
</
servlet>
<
servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/api/*</url-pattern>
</
servlet-mapping>

So now the annotations scanner reads correctly my classes, and I needed only 2 dependencies in my pom.xml:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</
dependency>
<
dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey</artifactId>
<version>${jersey.version}</version>
</
dependency>

XStream Message Reader and Writer


Most of my object model classes are using XStream, so I wanted Jersey to marshall/unmarshall automatically any XStream class. It was amazingly easy, here is my XStream message reader provider class:
@ProduceMime({"application/xml", "text/xml", "*/*"})
@ConsumeMime({"application/xml", "text/xml", "*/*"})
@Provider
public class XStreamAliasProvider extends AbstractMessageReaderWriterProvider<Object> {
private static final Set<Class> processed = new HashSet<Class>();
private static final XStream xstream = new XStream();
private static final String DEFAULT_ENCODING = "utf-8";

public boolean isReadable(Class<?> type, Type genericType, Annotation annotations[]) {
return type.getAnnotation(XStreamAlias.class) != null;
}

public boolean isWriteable(Class<?> type, Type genericType, Annotation annotations[]) {
return type.getAnnotation(XStreamAlias.class) != null;
}

protected static String getCharsetAsString(MediaType m) {
if (m == null) {
return DEFAULT_ENCODING;
}
String result = m.getParameters().get(
"charset");
return (result == null) ? DEFAULT_ENCODING : result;
}

protected XStream getXStream(Class type) {
synchronized (processed) {
if (!processed.contains(type)) {
xstream.processAnnotations(type);
processed.add(type);
}
}
return xstream;
}

public Object readFrom(Class<Object> aClass, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, String> map, InputStream stream)
throws IOException, WebApplicationException {
String encoding =
getCharsetAsString(mediaType);
XStream xStream = getXStream(aClass);
return xStream.fromXML(new InputStreamReader(stream, encoding));
}

public void writeTo(Object o, Class<?> aClass, Type type, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, Object> map, OutputStream stream)
throws IOException, WebApplicationException {
String encoding =
getCharsetAsString(mediaType);
XStream xStream = getXStream(o.getClass());
xStream.toXML(o,
new OutputStreamWriter(stream, encoding));
}
}

Spring integration


All my backend objects are Spring service bean, so I wanted autowired injection of Spring beans. Here again it was really nice. I defined my own annotation @SpringAutowired, and created a SpringBeanInjector for it that was fetching my context for a bean of the type of the injected field. Here I'm adding manually the list of "injectable" interfaces, because: I don't have an annotation to identify them :) With EJB3 it should be a lot cleaner to use @Stateless.
Here is my annotation:
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SpringAutowired {
}


And here the bean injector class as inner class of my Servlet:
public class ArtifactoryRestServlet extends ServletContainer {
@Override
protected void configure(ServletConfig config, ResourceConfig rc,
WebApplication application) {
super.configure(config, rc, application);

Set<Object> pi = rc.getProviderInstances();
pi.add(
getSpringBeanInjector(AuthorizationService.class));
pi.add(
getSpringBeanInjector(CentralConfigService.class));
pi.add(
getSpringBeanInjector(UserGroupService.class));
pi.add(
getSpringBeanInjector(AclService.class));
pi.add(
getSpringBeanInjector(RepositoryService.class));
pi.add(
getSpringBeanInjector(ArtifactoryContext.class));
pi.add(
getSpringBeanInjector(SecurityService.class));
}

public static <T> SpringBeanInjector<T> getSpringBeanInjector(Class<T> beanInterface) {
return new SpringBeanInjector<T>(beanInterface);
}

public static class SpringBeanInjector<T>
implements InjectableProvider<SpringAutowired, Type>, Injectable<T> {
private Class<T> type;

public SpringBeanInjector(Class<T> t) {
this.type = t;
}

public ComponentProvider.Scope getScope() {
return ComponentProvider.Scope.PerRequest;
}

public Injectable getInjectable(ComponentContext ic,
SpringAutowired autowired, Type type) {
if (type.equals(this.type)) {
return this;
}
else {
return null;
}
}

public T getValue(HttpContext context) {
/*
(ArtifactoryContext) context
.getAttribute("org.springframework.web.context.ROOT");
*/
ArtifactoryContext springContext = ContextHelper.get();
if (springContext == null) {
return null;
}
return springContext.beanForType(type);
}
}
}

Conclusion


I really liked the WebBeans consept and the Guice injection, but actually working with these nice modern Framework architecture on a real case proved that's the way to go.
Morale: "Chapeau bas for Paul Sandoz at Sun"

Friday, February 29, 2008

Stellarium For Java Alpha release!

After a lot of ups and downs, we (Jerome Beau and myself) are really happy to release an alpha version of Stellarium For Java (S4J in short).
This project is a migration of the very successful C++ project Stellarium created by Fabien Chereau.
For the record, I really like this C++ version but I am missing a lot of features:
  1. Ability to add stars catalogs like in Celestia
  2. Loading data on demand from the web instead of the resources in the installation
  3. Resizable window (I have a Widescreen and need to play with config file)
So, as a open source minded guy, I looked inside the code... And I got flashbacks! I found myself, back in time, when I was doing C++ for Video servers, and MFC applications.
I laughed, and then tried to find a Java version of any Astronomy software. I found Stellarium4Java.
The project had started a year before with Jerome and Arnaud Barre. At the time, it was in the middle of the pure code migration from Stellarium C++ to Java.
It looked like a small decision at the time, so I joined the project! Today I can say: It took time and energy to get were we are today.
But, thanks to the great work of the JOGL team in Sun, and all the Java open source projects, here or here is the alpha version loading with Web Start. I'm still working on the web distribution of resources, so for the moment you will have to wait for 13Mo of download :(
There is a Wiki page on jfrog with the jnlp links (they are still a moving target ;-) and the bug report access (be nice it's still alpha:-).
The most interesting part is that we got selected for a presentation at JavaOne this year to present this application. We will show how Java and the open source projects really helped us doing this, and what features we got for free from Java!

Side note: This project makes me love Java, every time I'm freeing myself for it.

Monday, February 18, 2008

Closure Campaign 2008

After many discussion, it is election time (year) for closure.
I voted for the readable, easy to grasp, and "almost" complete implementation of closure: FCM.
The posts of Stephen on the differences are very instructive:
  1. Closures - Comparing the core of BGGA, CICE and FCM

  2. Closures - Comparing control structures of BGGA, ARM and JCA

  3. Closures - Comparing closure type inference


I hope this vote will have an influence on the JCP...