There is currently a lot of buzz about the OSGi java component technology, also server-side. I have been playing -and working- with this interesting technology recently, mainly the Equinox server-side bundles that allow deployment of an OSGi environment in a java servlet environment.
A fundamental problem that this technology solves is being able to load an OSGi environment on a servlet server. That is a relatively costly operation that needs to be done only once and be persistent on the server in between client requests. After that point, state is maintained and bundles can be deployed and managed as needed. Creating, loading and destroying the environment for each request would just be unacceptable. One interesting functionality is then being able to serve client requests, specially HTTP requests, uploads, provide REST interfaces, etc.
Eclipse provides a number of projects to load the environment, register servlets, handle http requests, etc. Of particular interest is the ‘org.eclipse.equinox.servletbridge’ project, which initally starts the framework, loads the appropriate framework bundles, etc.
Looking at the code, you can start by checking out the main class, which has a number of interesting responsabilities:
/** * The BridgeServlet provides a means to bridge the servlet and OSGi runtimes. This class has 3 main responsibilities: * 1) Control the lifecycle of the associated FrameworkLauncher in line with its own lifecycle * 2) Provide a servlet "hook" that allows all servlet requests to be delegated to the registered servlet * 3) Provide means to manually control the framework lifecycle */
I personally like classes that have a small set of responsabilities, but one can argue that the three are so related that they are expressions of the same one. The first responsability described is actually managing the lifecycle of the OSGi framework FrameworkLauncher class.
Basically, the Servlet Container will load the bridge web application, create an instance of ServletBridge and call its init method (defined by the HttpServlet interface which it implements). In that method the OSGi environment will be created and loaded by the following code:
framework.init(getServletConfig()); framework.deploy(); framework.start(); frameworkStarted = true;
The attribute ‘framework’ is an instance of the ‘FrameworkLauncher’ class, which encapsulates the OSGi environment management logic. The ‘init’ method pulls information from the servlet configuration (such as the name of the ‘WEB-INF’ folder) and calls an overloaded empty init method that could be exploited by specialised subclasses (more on this later).
After that, the framework is “deployed”. The method in question declares the following contract:
/** * deploy is used to move the OSGi framework libraries into a location suitable for execution. * The default behavior is to copy the contents of the webapp's WEB-INF/eclipse directory to the webapp's temp directory. */
And that’s right, the code is quite straightforward and goes along the lines of:
File servletTemp = (File) context.getAttribute("javax.servlet.context.tempdir"); platformDirectory = new File(servletTemp, "eclipse"); if (!platformDirectory.exists()) { platformDirectory.mkdirs(); } File plugins = new File(platformDirectory, "plugins"); copyResource(resourceBase + "plugins/", plugins);
Which copies the bundles you want to deploy onto the OSGi environment onto the Servlet Container temporary folder (the ‘work’ folder in the case of Apache Tomcat).
After that the framework is started, reading .ini configuration options, command line switches, bundle list, run levels and so forth. We have not been able to get bundles started automatically unless we specify the bundle filename, complete with ‘.jar’ extension and all. One interesting option is the ability to fire up a standard OSGi console that uses the STDIN/OUT of the Servlet Container process.
Using the very same servlet bridge, there are a number of URLs that can be hit do control the framework, start, stop, undeploy, etc.
After that, one can register servlets as extension points or listen for services named “org.osgi.service.http.HttpService” and adding servlets with code going along these lines:
public Object addingService(ServiceReference reference) { HttpService httpService = (HttpService) context.getService(reference); httpService.registerServlet(url, servlet, null, null); }
All is well and good. However, in working with the bridge code we have found a glitch in the startup code. Whenever the bridge app is started anew, it does the framework deployment and startup as expected but if there are any bundles that have any changes they will not be read by the environment unless the redeploy url is hit. This is fine in development environments but not on production, where you want to keep things as smooth as possible.
Behold the power of OSS, we took a look at the code and submitted a bug entry complete with a working patch that fixes the problem. It is not pretty but it works (it has some code duplication).
Server-side OSGi is proving to be the place to be, or at least it is quite promising. Give it a try.