Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

SMILA/Documentation/JettyHttpServer

< SMILA‎ | Documentation
Revision as of 11:42, 1 March 2011 by Juergen.schumacher.attensity.com (Talk | contribs) (WebappContextService)

Configuration and Usage of the Jetty HTTP server embedded in SMILA

Overview

The embedding of the Jetty server is implemented in bundle org.eclipse.smila.http.server. When the bundle is activated it starts an OSGi service org.eclipse.smila.http.server.HttpService that creates a Jetty server from a configuration files, adds request handlers provided by other OSGi services and starts the server.

Configuration

To configure the embedded Jetty server, place a file named jetty.xml in the configuration directory org.eclipse.smila.http.server. If the configuration area does not contain such a file, a default file provided by the HTTP server bundle itself is used. It's probably the most simple file possible:

<Configure id="Server" class="org.eclipse.jetty.server.Server">
 
    <!-- =========================================================== -->
    <!-- Server Thread Pool                                          -->
    <!-- =========================================================== -->
    <Set name="ThreadPool">
      <!-- Default queued blocking threadpool -->
      <New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
        <Set name="minThreads">10</Set>
        <Set name="maxThreads">200</Set>
        <Set name="detailedDump">false</Set>
      </New>
    </Set>
 
    <!-- =========================================================== -->
    <!-- Set connectors                                              -->
    <!-- =========================================================== -->
 
    <Call name="addConnector">
      <Arg>
          <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
            <Set name="host"><Property name="jetty.host" /></Set>
            <Set name="port"><Property name="jetty.port" default="8080"/></Set>
            <Set name="maxIdleTime">300000</Set>
            <Set name="Acceptors">2</Set>
            <Set name="statsOn">false</Set>
            <Set name="confidentialPort">8443</Set>
	    <Set name="lowResourcesConnections">20000</Set>
	    <Set name="lowResourcesMaxIdleTime">5000</Set>
          </New>
      </Arg>
    </Call>
 
    <!-- =========================================================== -->
    <!-- Set handler Collection Structure                            --> 
    <!-- =========================================================== -->
    <Set name="handler">
      <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
    </Set>
 
    <!-- =========================================================== -->
    <!-- extra options                                               -->
    <!-- =========================================================== -->
    <Set name="stopAtShutdown">true</Set>
    <Set name="sendServerVersion">true</Set>
    <Set name="sendDateHeader">true</Set>
    <Set name="gracefulShutdown">1000</Set>
    <Set name="dumpAfterStart">false</Set>
    <Set name="dumpBeforeStop">false</Set>
</Configure>

For more details on all the configuration properties used here refer to the Jetty documentation next door.

It basically configures the server to listen at port 8080 and adds a default handler that responses with HTTP status 404 (NOT FOUND) if no other handler was found to handle the request, and it lists the available handlers, so it's not especially useful by itself.

Usage

Handlers can be added by two different approaches: Either by extending the jetty.xml file, or by registering different kinds of OSGi services that are references by the HTTP server service and registered at startup.

Before we dive into the details, here are some important advices:

  • To implement functionality you will probably write classes in an own bundle. If the HTTP server needs to instantiate these classes (e.g. servlets used by a web application) you must register your bundle as a "buddy" to the server bundle. So if you have problems deploying your own code and get class loading related errors, first check if your MANIFEST.MF contains this line:
Eclipse-RegisterBuddy: org.eclipse.smila.http.server
  • The Jetty server must be stopped and restarted to register additional handlers. Therefore if you use OSGi services to register functionality in the server, you should take care that the HTTP server bundle is started in a higher run level than all bundles providing handler services. This is the reason that in the SMILA application the HTTP server is started on the highest run level of all bundles. A nice side effect of this is that you can check from outside if the startup if SMILA has finished: If you can connect to the HTTP server, SMILA is up and running:
..., \
org.eclipse.smila.http.server@5:start
  • You should also not add handler services to the HTTP server bundle itself using Declarative Services, because the start order of DS services in a single bundle is not deterministic.

Deployment via jetty.xml

The straight forward way is to use the jetty.xml configuration file itself to add handlers for different URL contexts. In theory it should be possible to do everything you can normally do in this configuration file, see the Jetty documentation for details. However, there may be some classloading fun ahead.

The default configuration file used in the SMILA application replaces the "handler" section of the default configuration to deploy a simple Web application for search at http://localhost:8080/SMILA/search:

<!-- =========================================================== -->
<!-- Set handler Collection Structure                            --> 
<!-- =========================================================== -->
<Set name="handler">
  <New class="org.eclipse.jetty.server.handler.HandlerList">
    <Set name="handlers">
      <Array type="org.eclipse.jetty.server.Handler">
        <Item>
          <New class="org.eclipse.jetty.webapp.WebAppContext">
            <Set name="contextPath">/SMILA</Set>
            <Set name="resourceBase">configuration/org.eclipse.smila.search.servlet/webapp</Set>
            <Set name="descriptor">configuration/org.eclipse.smila.search.servlet/webapp/WEB-INF/web.xml</Set>
            <Set name="defaultsDescriptor">configuration/org.eclipse.smila.http.server/webdefault.xml</Set>
            <Set name="parentLoaderPriority">true</Set>
          </New>
        </Item>
        <Item>
          <New class="org.eclipse.jetty.server.handler.DefaultHandler"/>
        </Item>
      </Array>
    </Set>
  </New>
</Set>

It registeres a standard web application located at configuration/org.eclipse.smila.search.servlet/webapp. Note that you must also specify the "defaultsDescriptor" property because the embedded Jetty cannot find one at the default location.

HttpHandler services

org.eclipse.smila.http.server.HttpHandler is the most primitive SMILA specific interface for OSGi services that want to handle HTTP requests. It defines two methods:

  • String getRootContextPath(): return the context path (i.e. the part of the URL after the "http://<host>:<port>" stuff) for which this handler should be invoked. This is used by the HTTP server to select an appropriate handler for a request. The value must be a valid Jetty context path: The handler should be invoked for all requests to URI paths that start with this value.
  • void handle(final HttpExchange exchange) throws IOException: Actually handle the request. The HttpExchange object gives access to the HTTP method, request URI, request headers and input stream and response headers and output stream.

See org.eclipse.smila.http.server.test.MockHttpHandler in the HTTP server test bundle for the most simple implementation of this services. OSGI-INF/httphandler.xml shows how to start such a server using DS.

RequestDispatcher and RequestHandler services

The org.eclipse.smila.http.server.util.RequestDispatcher is a HttpHandler implementation that uses org.eclipse.smila.http.server.util.RequestHandler services to handle requests for its root context. RequestHandlers are HttpHandlers, but they cannot register for handling URIs using prefixes, but the dispatcher calls a matches(String requestUri) and the RequestHandler can check programmatically if it should handle this request. Also, the dispatcher can add and remove request handlers without having to restart the complete HTTP server. To use a RequestDispatcher, you must start it using a DS descriptor. E.g. see the example in the ...http.server.test bundle in OSGI-INF/requestdispatcher.xml:

<?xml version="1.0" encoding="UTF-8"?>
<component name="org.eclipse.smila.http.server.util.RequestDispatcher" immediate="true">
    <implementation class="org.eclipse.smila.http.server.util.RequestDispatcher" />
    <service>
       <provide interface="org.eclipse.smila.http.server.HttpHandler"/>
    </service>
    <reference
      name="RequestHandlers"
      interface="org.eclipse.smila.http.server.util.RequestHandler"
      bind="addRequestHandler"
      unbind="removeRequestHandler"
      cardinality="0..n"
      policy="dynamic"
      target="(rootContextPath=/dispatch)" 
      />    
</component>

This starts a dispatcher for the root context "/dispatch", i.e. it tries to handle all requests to http://host:port/dispatch... and uses all RequestHandler services that have a property "rootContextPath" set to "/dispatch". You can add this description to your own bundles to start several dispatchers for different root contexts, just be sure to import the bundles org.eclipse.smila.http.server.util and org.eclipse.smila.http.server.util even if they are not needed by the actual code.

We provide also a base class for RequestHandlers named org.eclipse.smila.http.server.util.ARequestHandler that implements the matches() method matching the URI part after the root context path using a regular expression string read from its own component properties specified in the DS file. E.g. in the test bundle we have OSGI-INF/requesthandler.xml:

<?xml version="1.0" encoding="UTF-8"?>
<component name="org.eclipse.smila.http.server.test.MockRequestHandler" immediate="true">
    <implementation class="org.eclipse.smila.http.server.test.MockRequestHandler" />    
    <service>
       <provide interface="org.eclipse.smila.http.server.util.RequestHandler"/>
    </service>
    <property name="rootContextPath" type="String" value="/dispatch"/>
    <property name="uriPattern" type="String" value="/handle/([^/]+)/?$"/>    
</component>

This starts a simple RequestHandler service that is managed by the dispatcher described above, and reacts on requests to http://host:port/dispatch/handle/<string-without-further-slashes>. The base class provides also methods to extract the parts of the request URI matched by the groups in the regular expression.

JettyHandler services

An OSGi service providing org.eclipse.smila.http.JettyHandler<tt> can be used to inject original Jetty handlers programmatically into the server. A JettyHandler must implement two methods:

  • <tt>org.eclipse.jetty.server.Handler getHandler(): the initialized Jetty handler. If it's not already a ContextHandler, it is wrapped inside one automatically by the HttpService.
  • String getRootContextPath(): the URI path prefix to be handled by this handler.

There is also a base class org.eclipse.smila.http.AJettyHandlerService that implements reading the context path value from the DS component context, and can determine paths into the configuration area, if the component context contains a bundle name to use for accessing the configuration space.

We have already created three (partly prototypipcal) implementation of this service. They provide only rather limited means to configure the Jetty handler themselves, if you need to do more configuration, you will have to create an own variant of these services or resort to deploying the handler using jetty.xml. You find them all in org.eclipse.smila.http.server.util:

ResourceHandlerService

Creates a Jetty ResourceHandler that can serve files from the configuration area. The test bundle shows how to use this one in OSGI-INF/resourcehandler.xml:

<?xml version="1.0" encoding="UTF-8"?>
<component name="org.eclipse.smila.http.server.util.ResourceHandlerService" immediate="true">
    <implementation class="org.eclipse.smila.http.server.util.ResourceHandlerService" />
    <service>
       <provide interface="org.eclipse.smila.http.server.JettyHandler"/>
    </service>
    <property name="rootContextPath" type="String" value="/resources"/>
    <property name="configBundle" type="String" value="org.eclipse.smila.http.server.test" />
    <property name="resourceBase" type="String" value="resources"/>    
    <property name="welcomeFiles" type="String" value="index.html"/>
</component>

This creates a ResourceHandler that provides the files from configuration/org.eclipse.smila.http.server.test/resources under http://.../resources/..., and returns "index.html" for requests containing only a directory name and no explicit filename.

ServletContextService

Creates and registers a ServletContextHandler with a single javax.servlet instance already created (so it may be helpful in case of classloading problems, because the servlet instance can be created inside its own bundle context). Again, you can find a simple example in the test bundle in OSGI-INF/servlethandler.xml:

<?xml version="1.0" encoding="UTF-8"?>
<component name="org.eclipse.smila.http.server.util.ServletContextService" immediate="true">
    <implementation class="org.eclipse.smila.http.server.util.ServletContextService" />
    <service>
       <provide interface="org.eclipse.smila.http.server.JettyHandler"/>
    </service>
    <property name="rootContextPath" type="String" value="/servlet"/>
    <property name="servletClassName" type="String" value="org.eclipse.smila.http.server.test.MockServlet" />
    <property name="servletPath" type="String" value="/mock"/>    
</component>

This registers an instance of the named class as a servlet that can be invoked using http://.../servlet/mock</tt>.

WebappContextService

Creates a handler for a web application. The example from the test bundle goes like this:

<?xml version="1.0" encoding="UTF-8"?>
<component name="org.eclipse.smila.http.server.util.WebappContextService" immediate="true">
    <implementation class="org.eclipse.smila.http.server.util.WebappContextService" />
    <service>
       <provide interface="org.eclipse.smila.http.server.JettyHandler"/>
    </service>
    <property name="rootContextPath" type="String" value="/webapp"/>
    <property name="configBundle" type="String" value="org.eclipse.smila.http.server.test" />
    <property name="webappDir" type="String" value="webapp"/>    
</component>

This makes the web application in directory <tt>webapp in the configuration area for bundle org.eclipse.smila.http.server.test available as http://.../webapp. The web application must not be assembled into a WAR file, the descriptor file must be at WEB-INF/web.xml and the configuration directory for the named bundle must also contain a file webdefault.xml with default values for the web.xml. An override-web.xml is not supported. See configuration/org.eclipse.smila.http.server.test/ for an exemplary simple setup.

Back to the top