Apache
Home » Documentation » Apache Felix Subproject Documentation

Apache Felix HTTP Service

This is an implementation of the HTTP Service Specification as described in chapter 102 of the OSGi Compendium. The goal is to provide a standard and simplified way to register servlets and resources in a Servlet container, and to associate them with URIs. It also implement a non-standard extension for registering servlet filters as well as a whiteboard implementation. Complete set of features:

Installing

The Apache Felix HTTP Service project includes several bundles.

So, in most cases you could just use org.apache.felix.http.bundle and forget about all the other ones.

Using the HttpService

The main components provided by the Apache Felix HTTP Service bundle are:

Servlets created for the OSGi HTTP service don't need to have any reference to the OSGi specification (they only need to conform to the Servlet specification), like in the example:

public class HelloWorld extends HttpServlet
{
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
  {
    resp.getWriter().write("Hello World");      
  } 
}

To register a Servlet and map it to a URI, you need to retrieve the HttpService and call its registerServlet method:

public class Activator implements BundleActivator
{
  public void start(BundleContext context) throws Exception 
  {
    ServiceReference sRef = context.getServiceReference(HttpService.class.getName());
    if (sRef != null)
    {
      HttpService service = (HttpService) context.getService(sRef);
      service.registerServlet("/hello", new HelloWorld(), null, null);
    }
  }
}

In the same way, you can unregister a Servlet (for instance, in the stop method of the Bundle Activator) calling the HttpService.unregister method.

As you notice in the example above, the registerServlet method accepts four parameters:

The Servlet alias must begin with a slash and must not end with a slash. When a request is processed, the HTTP Service will try to exact match the requested URI with a registered Servlet. If not existent, it will remove the last '/' in the URI and everything that follows, and try to match the remaining part, and so on.

An additional configuration Map can be optionally specified; if present, all the parameters contained will be copied in the ServletContext object.

Finally, an HttpContext object can be optionally specified to handle authentication, mime type and resource mapping. The HttpContext interface is quite simple:

public interface HttpContext
{
  String getMimeType(java.lang.String name); //Returns the mime type of the specified resource
  URL getResource(java.lang.String name);   //Returns the URL to retrieve the specified resource
  boolean handleSecurity(HttpServletRequest request, HttpServletResponse response); //Manages security for the specified request
}

The use of a custom HttpContext is typical when you want to serve static contents with the HTTP Service. Let's see first the simplest example of resource registration (without HttpContext)

public class Activator implements BundleActivator
{
  public void start(BundleContext context) throws Exception 
  {
    ServiceReference sRef = context.getServiceReference(HttpService.class.getName());
    if (sRef != null)
    {
      HttpService service = (HttpService) context.getService(sRef);
      service.registerResources("/static", "/etc/www", null);
    }
  }
}

As a result of the service.registerResources("/static", "/etc/www", null) code, all the files available under /etc/www will be exposed under /static (e.g. http://localhost:8080/static/001.jpg will render the /etc/www/001.jpg). However, the example above can be simplistic in practice; the HttpContext object is the solution to customize the resource handling.

For instance, you can set the define more complex URI to file mappings overriding the HttpContext.getResource method, or the correct mime type implementing the method HttpContext.getMimeType like in the example:

//....

public String getMimeType(String file) 
{  
  if (file.endsWith(".jpg")
  {  
    return "image/jpeg";  
  } 
  else if (file.endsWith(".png")) 
  {  
    return "image/png";  
  } 
  else 
  {  
    return "text/html";  
  }  
}

//....

If you implement a customized HttpContext object, don't forget to specify it as third parameter of the registerResources method invocation:

public class Activator implements BundleActivator
{
  public void start(BundleContext context) throws Exception 
  {
    ServiceReference sRef = context.getServiceReference(HttpService.class.getName());
    if (sRef != null)
    {
      HttpService service = (HttpService) context.getService(sRef);
      HttpContext myHttpContext = new MyHttpContext());
      service.registerResources("/static", "/etc/www", myHttpContext);
    }
  }
}

Using the ExtHttpService

To be able to register filters, it is possible to get hold of org.apache.felix.http.api.ExtHttpService. This is exported by both jetty and the bridged implementation. Let's see the simplest example of a filter registration.

public class Activator implements BundleActivator
{
  public void start(BundleContext context) throws Exception 
  {
    ServiceReference sRef = context.getServiceReference(ExtHttpService.class.getName());
    if (sRef != null)
    {
      ExtHttpService service = (ExtHttpService) context.getService(sRef);
      service.registerFilter(new HelloWorldFilter(), "/hello/.*", null, 0, null);
    }
  }
}

Using the Whiteboard

The whiteboard implementation simplifies the task of registering servlets and filters. A servlet (or filter) can be registered by exporting it as a service. The whiteboard implementation detects all javax.servlet.Servlet, javax.servlet.Filter and org.osgi.service.http.HttpContext services with the right service properties. Let us illustrate the usage by registering a servlet:

public class Activator implements BundleActivator
{
  private ServiceRegistration registration;

  public void start(BundleContext context) throws Exception 
  {
    Hashtable props = new Hashtable();
    props.put("alias", "/hello");
    props.put("init.message", "Hello World!");

    this.registration = context.registerService(Servlet.class.getName(), new HelloWorldServlet(), props);
  }

  public void stop(BundleContext context) throws Exception 
  {
    this.registration.unregister();
  }
}

Servlet service properties:

Filter service properties:

HttpContext service properties:

Using the Servlet Bridge

The servlet bridge is used if you want to use the HTTP service inside a WAR deployed on a 3rd part applicaiton server. A little setup is needed for this to work:

A detailed example can be found here.

Configuration Properties

The service can both be configured using OSGi environment properties and using Configuration Admin. The service PID for this service is "org.apache.felix.http". If you use both methods, Configuration Admin takes precedence. The following properties can be used (some legacy property names still exist but are not documented here on purpose):

Additionally, the all-in-one bundle uses the following environment properties:

The Jetty based implementation supports the following Jetty specific configuration as of Http Service Jetty Bundle 2.4:

Servlet API Events

The Servlet API defines a number of EventListener interfaces to catch Servlet API related events. As of HTTP Service 2.1.0 most events generated by the servlet container are forwarded to interested service. To be registered to receive events services must be registered with the respective EventListener interface:

Interface Description
javax.servlet.ServletContextAttributeListener Events on servlet context attribute addition, change and removal.
javax.servlet.ServletRequestAttributeListener Events on request attribute addition, change and removal.
javax.servlet.ServletRequestListener Events on request start and end.
javax.servlet.http.HttpSessionAttributeListener Events on session attribute addition, change and removal. To receive such events in a bridged environment, the ProxyLister must be registered with the servlet container. See the Using the Servlet Bridge section above.
javax.servlet.http.HttpSessionListener Events on session creation and destroyal. To receive such events in a bridged environment, the ProxyLister must be registered with the servlet container. See the Using the Servlet Bridge section above.

Of the defined EventListener interfaces in the Servlet API, the javax.servlet.ServletContextListener events are actually not support. For one thing they do not make much sense in an OSGi environment. On the other hand they are hard to capture and propagate. For example in a bridged environment the contextInitialized event may be sent before the framework and any of the contained bundles are actually ready to act. Likewise the contextDestroyed event may come to late.

Servlet Context Notes

ServletContext instances are managed internally by the Http Service implementation. For each HttpContext instance used to register one or more servlets and/or resources a corresponding ServletContext instance is created. These ServletContext instances is partly based on the single ServletContext instance received from the Servlet Container --- either embedded Jetty or some external Servlet Container when using the Http Service Bridge --- and partly based on the provided HttpContext instance:

Method(s) Based on ...
getContextPath, getContext, getMajorVersion, getMinorVersion, getServerInfo Servlet Containers ServletContext
getResourcePaths Bundle.getEntryPaths of the bundle using the Http Service
getResource, getResourceAsStream HttpContext.getResource
getMimeType HttpContext.getMimeType
getRequestDispatcher, getNamedDispatcher, getInitParameter, getServlet, getRealPath Always return null
getInitParameterNames, getServlets, getServletNames Always returns empty Enumeration
getAttribute, getAttributeNames, setAttribute, removeAttribute By default maintained for each ServletContext managed by the Http Service. If the org.apache.felix.http.shared*servlet*context_attributes framework property is set to true these methods are actually based on the ServletContext provided by the servlet container and thus attributes are shared amongst all ServlectContext instances, incl. the ServletContext provided by the servlet container

Examples

A set of simple examples illustrating the various features are available.

Maven Artifacts

<dependency>
  <groupId>org.apache.felix</groupId>
  <artifactId>org.apache.felix.http.api</artifactId>
  <version>2.0.4</version>
</dependency>
<dependency>
  <groupId>org.apache.felix</groupId>
  <artifactId>org.apache.felix.http.base</artifactId>
  <version>2.0.4</version>
</dependency>
<dependency>
  <groupId>org.apache.felix</groupId>
  <artifactId>org.apache.felix.http.bridge</artifactId>
  <version>2.0.4</version>
</dependency>
<dependency>
  <groupId>org.apache.felix</groupId>
  <artifactId>org.apache.felix.http.bundle</artifactId>
  <version>2.0.4</version>
</dependency>
<dependency>
  <groupId>org.apache.felix</groupId>
  <artifactId>org.apache.felix.http.jetty</artifactId>
  <version>2.0.4</version>
</dependency>
<dependency>
  <groupId>org.apache.felix</groupId>
  <artifactId>org.apache.felix.http.proxy</artifactId>
  <version>2.0.4</version>
</dependency>
<dependency>
  <groupId>org.apache.felix</groupId>
  <artifactId>org.apache.felix.http.whiteboard</artifactId>
  <version>2.0.4</version>
</dependency>
Rev. 1437617 by fmeschbe on Wed, 23 Jan 2013 18:41:19 +0000
Apache Felix, Felix, Apache, the Apache feather logo, and the Apache Felix project logo are trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners.