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.
Hi,
What I don’t understand is how can a servlet call the bridgeservlet to start an OSGi bundle.
I mean I know how to do it manually by using the OSGi prompt inside the server console. But, what if I need to call the bundle from my servlet.
Thanks in advance,
Well, basically the Equinox framework will start it for you.
Inside the bridge installation you can find the config.ini file where you can specify all sorts of info such as which bundles to load, start, the order in which they do (watch the dependencies!), etc.
I will try to describe what I neeed to do :
– I got a servlet getting an information ( integers) from an HTML form.
– I forward that info to the BridgeServlet.
– I need the BridgeServlet to start a specific bundle that can “handle” the info (doing basic calculation). –> starting the bundle is not a problem (as you said it’s done by the framework). However, the problem is how to transmit the info (integer) from the servlet to the bundle.