Some thoughts about OSGi and Java EE 6

28 06 2011

Last week, I played around with the new features of Java EE 6, especially with the Servlet 3.0 API. Because developing Java Enterprise applications with the OSGi application programming model is pretty attractive for me, I had a focus on the comparison of concepts that both “worlds” introduced and how to use them in a conflated environment.

Servlet Annotations

@WebServlet(value = "/control", name="Controller Servlet", initParams = { 
  @WebInitParam(name = "param1", value = "value1"), 
  @WebInitParam(name = "param2", value = "value2") 
})
public class ControllerServlet extends HttpServlet {
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    // implement request processing
  }
}

Okay, it’s a nice feature that servlets can now be declared using annotations to replace the web deployment descriptor and to have all metadata within the Java code. This fits common concepts of modern frameworks. But the Servlet API is still invasive, i.e. you have to implement a Servlet interface and you are dependent from a request and a response object which makes testing difficult. I would expect to change this in the future, but it does not seem to matter in the next release. So you have to extract your controller logic from the Servlet API by yourself or use frameworks like Spring Web furthermore.

Pluggability

Since Servlet API 3.0, it is possible to split a web module into (a web module and) multiple web fragments. Web applications can be divided by special functionality, and web frameworks can configure the web application by itself instead of writing manuals how to install the framework into the web application. In addition, servlets, filters and listeners can be installed into the web application programmatically (in a very dynamic way).

final Dynamic servlet = getServletContext()
  .addServlet("Controller Servlet", new ControllerServlet());
servlet.addMapping("/control");
servlet.setInitParameter("param1", "value1");
servlet.setInitParameter("param2", "value2");

With regard to OSGi, the concepts of web fragments and OSGi bundle fragments are very similar, because both extend web modules and OSGi bundles respectively. But the devil is in the details, because

  • OSGi bundle fragments have a dependency to a single host bundle, whereas web fragments are published into the WEB-INF/lib folder of the web app (any desired web app!) – so we have reverse dependencies
  • Servlets, filters and listeners can only be registered during application startup within a ServletContextListener (and cannot be removed) – so in comparison to the lifecycle of OSGi bundles, it does not provide such a dynamic behaviour. If you want to register and remove servlets at runtime without restarting the web application, you should use the OSGi HttpService that only provides a Servlet 2.x API. (see my notes on “Using the OSGi Http Service on IBM WebSphere Application Server”)

Upload Support

@WebServlet("/upload.html")
@MultipartConfig(
  location = "/upload-files", 
  fileSizeThreshold = 1024 * 1024, 
  maxFileSize = 1024 * 1024 * 5, 
  maxRequestSize = 1024 * 1024 * 5 * 5
)
public class FileUploadServlet extends HttpServlet {

  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    resp.setContentType("text/plain");
    final PrintWriter out = resp.getWriter();
    try {
      final Collection<Part> parts = req.getParts();
      out.println("Total parts : " + parts.size());
      for (Part part : parts) {
        out.println();
        out.println("Name : " + part.getName());
        out.println("Content-Type : " + part.getContentType());
        //part.getInputStream();
      }
    } finally {
      out.close();
    }
  }
	
}

Nice feature. The location attribute of the @MultipartConfig is used as temporary directory to store uploaded files on the server. You can specify both an absolute and relative (to the app server’s temp) directory.

Be aware that WebSphere Application Server uses the web app’s installation directory as the temporary directory and does not prevent that the location attribute has the value “/WEB-INF“. 😕

Asynchronous Request Processing

final AsyncContext ctx = request.startAsync();
executor.execute(new Runnable() {
			
  @Override
  public void run() {
    // Asynchronous processing
    // Write response
    // Complete request processing
    ctx.complete();
  }
});

Okay, I understood that I can use it for “COMET”, “Reverse Ajax” or however they call it. For me, it sounds like the possibility to shift the problems that occur within the request processing thread to another thread. 😉
The risk is that the web container’s thread limitation is bypassed. This should only be used for managing custom queues or any other algorithm that does not slow down performance when it is invoked 100 times in parallel.

Contexts and Dependency Injection (CDI)

This is the greatest new feature of Java EE 6 for me. It allows to simplify application code by using annotations to manage beans and replace lookups. CDI also introduces Interceptors and Decorators for cross-cutting concerns (e.g. logging, dealing with transactions) and to extend the business logic by separate components.
Concerning OSGi, it would be helpful to get OSGi services injected into a servlet or EJB. Apache Aries declares such a possibility with the usage of the @Resource annotation.

@Resource(lookup = "osgi:service/de.ars.demo.helloworld.api.HelloWorldService")
private HelloWorldService hw;

This should also be possible using the @Inject annotation with a qualifier to avoid the usage of JNDI namespaces. GlassFish provides such a mechanism:

@Inject @OSGiService
private HelloWorldService hw;

Wouldn’t it be nice to have such dependency injection within (non-JavaEE) OSGi environments too? I guess this could be a good alternative to declarative services. I know that OSGi core does not use annotations to support (all) mobile devices (that do not run a Java 5 JVM), but it could be part of OSGi enterprise. Eclipse 4.x also uses these annotations for dependency injection. So CDI has the potential to provide an application model for multiple environments (because it is independent from the environment).

CDI interceptors can be used for cross-cutting concerns.

@AroundInvoke
private Object log(InvocationContext ctx) throws Exception {
  final long d1 = System.currentTimeMillis();
  try {
    return ctx.proceed();
  } finally {
    final long d2 = System.currentTimeMillis();
    log("Method " + ctx.getMethod().getName() + " invoked (" + (d2 - d1) + "ms)");
  }

This is a simple example for an interceptor within a single class. Interceptors can also be written as separate classes and bound to other classes or single methods using a custom annotation.
OSGi 4.3 introduced a Weaving Hook mechanism for bytecode instruction. The developer has to use frameworks like Javassist or ASM to add concerns. But CDI interceptors are much easier to use…

Bean Validation API

The Bean Validation API also uses annotations to declare constraints. Within the Java EE environment, managed beans are validated automatically at some layers, but validation can also be done programmatically.

This could be the code of a servlet class (maybe a little bit dirty to change instance variables during request processing):

@Inject
private Validator validator;
@Inject
private Person person;

protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {
  person.setFirstName(request.getParameter("firstName"));
  person.setLastName(request.getParameter("lastName"));
  person.setEmail(request.getParameter("email"));
  final Set<ConstraintViolation<Person>> result = validator.validate(person);
  // continue...
}

Bean validation is automatically invoked when using JSF. But it’s a cool thing that can also be used out-of-the-box.

Conclusion

Java EE 6 introduces some nice features. Especially CDI for resolving OSGi service instances would be very cool. I have a dream… 😛 that the whole CDI framework is part of the Eclipse 4 application programming model.
There are still some stumbling blocks like the “web fragment vs. OSGi bundle fragment” comparison.

Advertisements

Actions

Information

2 responses

19 04 2013
Rosa

I’m really impressed together with your writing talents and also with the layout for your blog. Is this a paid subject matter or did you customize it yourself? Either way keep up the nice quality writing, it’s
uncommon to peer a great weblog like this one nowadays.
.

6 05 2013
taco bell prices

Hello there, just became aware of your blog through Google, and found
that it’s really informative. I’m going to watch out for
brussels. I will be grateful if you continue this in future.

A lot of people will be benefited from your writing. Cheers!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: