Wednesday, February 6, 2008

Return of the Jetty (embedded OSGi Server)

Summary This post builds on the project created in my last post, Open Your Eyes to OSGi, in which we created a simple OSGi project using Eclipse Equinox. In this post you convert that project into a server application bundle and run it on Jetty, embedded in Eclipse Equinox. First, we'll define a directory for static web content using an extension point and test it, and then we'll write a Servlet and use an extention point to register it too.

In my last post you learned that I needed to create a server application bundle that could be deployed to an Arcom Zeus device running embedded Linux and Equinox.



Instead of deploying a web application to an application server, like most Java developers are used to, the bundle is deployed to Equinox along side an application server, as shown above. In other words, Jetty is just another bundle running on Equinox.

Creating a OSGi Server Application

Web enabling the application involves creating a document root in which to place the static site content and adding Servlets. First, we create a new folder for the static content and then we declare its location using an extension point. The org.eclipse.equinox.http.registry bundle has an extension point named "resources" that can be used for declaring static content. We need to add that extension to our project and configure it to point to the directory containing the static content. Later in the project we will use the "servlets" extension point of the same bundle to register a Servlet.

  1. Create a folder at the root of your project to hold your static content. I called mine "WebContent."
  2. Add a simple index.html page to the new folder.
  3. Enable Extension configuration in the Manifests Wizard by opening the Overview tab and clicking Extensions.

  4. Click OK to display the Extensions page. This will add an Extensions tab the Manifests wizard that will automatically open.
  5. Click the Add button and then type "org.eclipse.equinox.http.registry.resources" in the Extension Point Filter field. Be to sure to uncheck "Show only extension points from the required plug-ins" to get the bundle to appear in the filtered list. Select the bundle and then click finish.
  6. The Manifests wizard will prompt whether to add a dependency to your project for this bundle. Click Yes.
  7. Add an ID and Name for this extension in your project. I called mine "staticContent" to indicate what I was using putting in the resources directory. You can name yours something else if you like. Save your changes.
  8. Now you are ready to add a resource definition to the extension. Right click on the bundle and select New --> Resource.
  9. Now you need to set the Alias (the resource path in the URL), and Base-name, which in our case is the directory "WebContent." Don't worry about Http Context Id. That requires the org.eclipse.equinox.http.registry.httpcontexts extension point, which is outside the scope of this post.
  10. Display the plugin.xml contents to see what the Manifests Wizard did:
     <?xml version="1.0" encoding="UTF-8"?>
    <?eclipse version="3.2"?>
    <plugin>
    <extension
    id="staticContent"
    name="StaticContent"
    point="org.eclipse.equinox.http.registry.resources">
    <resource
    alias="/">
    base-name="WebContent">
    </resource>
    </extension>
    </plugin>
  11. To better understand the extension values, return to the Extension tab and click the "Open extension point schema" link, and the open the Example tab on the resource.exsd page.

Progress Check - Serving Static HTML

Let's validate that our bundle can serve static HTML content from our OSGi bundle before moving on to Servlets. To do that we need to make some environment changes. We'll create a copy of the OSGi configuration file from my last post first.

TIP Now is a good time to point out that Eclipse 3.3.x ships differently than Eclipse 3.2.x. Equinox (3.3.x) is bundled with Jetty. Older, or minimal, OSGi distributions may not have a HTTP service at all, or they will include the org.eclipse.equinox.http bundle instead of Jetty. You may have to add Jetty yourself as explained in Embedding an HTTP server in Equinox.

  1. Select Run --> Open Run Dialog...
  2. Highlight the Simple OSGi Configuration that you created in my last post, click the right mouse, and choose Duplicate.
  3. Change the name to Simple OSGi Servlet Configuration.
  4. (optional) Select the arguments tab and add -Dorg.osgi.service.http.port to assign the port number. I chose port 8081 for OSGi.



    Return to the Bundles tab so that we can select the Jetty dependencies


  5. In addition to selecting your project, select the following bundles:
    • javax.servlet
    • org.apache.commons.logging
    • org.apache.xerces
    • org.apache.xml.resolver
    • org.eclipse.core.jobs
    • org.eclipse.core.runtime.compatibility.registry
    • org.eclipse.equinox.common
    • org.eclipse.equinox.http.jetty
    • org.eclipse.equinox.http.registry
    • org.eclipse.equinox.http.servlet
    • org.eclipse.equinox.registry
    • org.eclipse.osgi.services
    • org.mortbay.jetty

You can now click the run button to launch your OSGi bundle with an embedded Jetty server. There may be some errors to work through depending on your JVM/compiler settings and Equinox runtime settings. The version of Jetty shipping with Europa is not backward compatible with Java 1.3.1, so I had to change my JVM library to 1.4.2 and rebuild my project. If you have to build for a 1.3.1 environment, as I have to, you can pull down the source code you need from CVS and re-compile those plug-ins. I had to do a lot of that on Linux to build for the Java 1.3.1 environment. In fact, on my Linux machine I checked out and re-compiled many of the bundles listed above.

Once your bundle, compiled code, and Equinox OSGi runtime environment are compatible you should see something like this:
 osgi> Feb 5, 2008 11:32:01 PM org.mortbay.http.HttpServer doStart
INFO: Version Jetty/5.1.x
Feb 5, 2008 11:32:01 PM org.mortbay.util.Container start
INFO: Started org.mortbay.jetty.servlet.ServletHandler@1a626f
Feb 5, 2008 11:32:01 PM org.mortbay.util.Container start INFO: Started HttpContext[/,/]
Feb 5, 2008 11:32:01 PM org.mortbay.http.SocketListener start
INFO: Started SocketListener on 0.0.0.0:8081
Feb 5, 2008 11:32:01 PM org.mortbay.util.Container start
INFO: Started org.mortbay.http.HttpServer@291aff

MyFirstActivator is starting. Hello.

Now try hitting your URL: http://localhost:8081/index.html. You should now see the contents of the index.html page in your web browser. If not, spend some time troubleshooting before continuing.


Type "close," or click the OSGi stop button on OSGi console view, when you are done.

Adding a Servlet

Start by adding javax.servlet to your dependencies.

  1. Go to the Manifests Wizard (double click on META-INF/MANIFEST.MF if it is not open) and select the dependencies tab.
  2. Click Add button under Automated Management of Dependencies and choose javax.servlet from the list of bundles.
  3. Click the Add button next to Imported Packages and add the javax.servlet and javax.servlet.http JARs.
  4. Click the right mouse and choose Save (or do CNTL-S).
  5. Create a new class named MyServlet in the com.myfirst.osgi package that extends javax.servlet.http.HttpServlet.
  6. Add your own Servlet code. The code I used is below.
     package com.myfirst.osgi;

    import java.io.IOException;
    import java.io.PrintWriter;

    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    public class MyServlet extends HttpServlet {

    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {

    resp.setContentType("text/html");
    PrintWriter pw = new PrintWriter (resp.getOutputStream());
    pw.println("<html>");
    pw.println("<head><title>Servlet Demo</title></head>");
    pw.println("<body>");
    pw.println("<h2>This servlet is running in an embedded Servlet container on OSGi.</h2>");
    pw.println("</body></html>");
    pw.close();
    }
    }
  7. We will again use an extension to register the Servlet. Return to the Extension tab, click the Add button and set the filter to "org.eclipse.equinox.http.registry.servlets." Remember to uncheck the check box.
  8. Enter the name of your Servlet class and give it an alias and save your changes.
  9. The plugin.xml file should now appear as follows:
     <plugin>
    <extension point="org.eclipse.equinox.http.registry.resources">
    <resource
    alias="/"
    base-name="/WebContent"/>
    </extension>
    <extension point="org.eclipse.equinox.http.registry.servlets">
    <servlet
    alias="/MyServlet"
    class="com.myfirst.osgi.MyServlet"/>
    </extension>
    </plugin>
  10. Select Run --> Open Run Dialog...
  11. You configuration already includes all the bundles you need, so just click Run.
  12. OSGi should start normal, as before.
  13. Re-test your static page by typing http://localhost:8081/index.html
  14. Test your new Servlet by typing http://localhost:8081/MyServlet

Summary

In this post you extended the project created in my last post to be a Web application bundle. You added a folder for static content and registered the folder's location with Equinox. Next, you cloned your simple Equinox execution environment and added the necessary bundles to run the Jetty embedded application server. This allowed you to accessed some static content from a browser. Finally, you added a Servlet, registered it with Equinox by adding an extension point, and accessed it from a browser.

In my next post I will discuss expanding the Equinox execution environment yet again in order to run JSPs and Struts.


12 comments:

Stefan said...

Excellent introduction, thanks a lot! In the minimal run environment, my Jetty server never started, I had to hit "Add required bundles" first, which however results in about 200 bundles listed in a "ss" output... Any ideas?

Mkris said...

Hi,
That was an excellent introduction.
I have a small query.
Now how do we deploy the same web application on to a servlet container like tomcat.The usecase is deploying equinox on to servlet container.
How do we that?

Thomas Joseph said...

Cool! Good intro for beginners about kick-starting plug-in development.

Will be waiting eagerly for your next blog on the subject.

ouertani said...

Really very interesting!!!

I am waiting for your incoming posts.

Have you tested JEE applications on OSGI framework like easybeans, springDM or others?

ceespi said...

Hi,

Very good introduction! I am trying to use org.eclipse.equinox.http.jetty as a server, but I would like to add a few objects to the context programmatically in another plugin.
Is there any way I can achive this?

Thanks

Kees

Link said...

I waitting for you next post to talk about using JSP and Struct....

Steve said...

Link - Thanks for the post. I got JSPs running on my laptop, but it was not compatible with my client's embedded Linux device. My next series of posts will be on Amazon EC2. I may not return to the topic of OSGi. That depends on my client's needs.

aleksovska said...

Did I missed your Post about expanding the Equinox execution environment in order to run JSPs and Struts?
Please send me a link, I can't find it.

Steve said...

aleksovska - No, you didn't miss it. Although I got JSPs running in my local JSP environment, they were not compatibly with my client's embedded Linux platform. Since I had to stick with Servlets I never wrote that post.

aleksovska said...

Can you please give me just an idea what to do with my jsp files. I can not add them as an extension (org.eclipse.equinox.http.registry....?). Should I do something in Activator class? Thank you.

Jinlin said...

Best OSGi+WebApp intro so far.
I've got everything working, but I had some workaround.
May be there were some recent updates on Extensions.
When I was step #8, I doesn't have
the option of "Resource", instead it has "Generic" under "New".
So I go ahead and edit the plugin.xml file, but it seems that
the static resource aliasing
doesn't have any effect, i still need to include WebContent in the URL to locate index.html.

Could you help me out here a bit.
Thanks in advance.

Vijayabaskar said...

Hi.. i am fresh for osgi.. any one can help me to develop servlet container using osgi.. i eagrely waiting for u reply..