This is an automated email from the ASF dual-hosted git repository.
cziegeler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/felix-dev.git
The following commit(s) were added to refs/heads/master by this push:
new 14000ae131 Add a short info for running the TCK
14000ae131 is described below
commit 14000ae131ab3f24d61ab18b92d79096e38907b1
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Fri May 29 09:21:44 2026 +0200
Add a short info for running the TCK
---
http/README.md | 403 +++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 333 insertions(+), 70 deletions(-)
diff --git a/http/README.md b/http/README.md
index f493c834db..be25c4b67a 100644
--- a/http/README.md
+++ b/http/README.md
@@ -2,34 +2,36 @@
This is an implementation of the [R8.1 Whiteboard Specification for Jakarta
Servlet](https://docs.osgi.org/specification/osgi.cmpn/8.1.0/service.servlet.html),
[HTTP Whiteboard Service as described in chapter
140](https://osgi.org/specification/osgi.cmpn/7.0.0/service.http.whiteboard.html)
of the OSGi Compendium (R7) in combination with an implementation of the [HTTP
Service Specification as described in chapter
102](https://osgi.org/specification/osgi.cmpn/7.0.0/service.http.html) of th
[...]
- * Standard OSGi Http Service implementation
- * Standard OSGi Http Whiteboard implementation
- * Run either with Jetty (version 11 or 12) bundle or inside your own
application server using the servlet bridge
- * [Felix HTTP Jetty
12](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.jetty12)
is the preferred bundle of choice as it supports JakartaEE10 (1.1.x range) and
JakartaEE11 (2.x range).
- * [Jetty WebSocket
support](https://github.com/apache/felix-dev/pull/310), see example code
[here](https://github.com/apache/felix-dev/blob/master/http/samples/whiteboard/src/main/java/org/apache/felix/http/samples/whiteboard/TestWebSocketServlet.java).
- * [Felix HTTP Jetty
11](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.jetty)
is the predecessor of the Jetty 12 bundle, which shipped with [Jetty
9.4.x](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.jetty/4.2.26)
in the 4.x range (JavaEE8), [Jetty
11.x](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.jetty/5.1.10)
in the 5.x range (JakartaEE9).
- * [Jetty WebSocket
support](https://github.com/apache/felix-dev/pull/309), see example code
[here](https://github.com/apache/felix-dev/blob/master/http/samples/whiteboard/src/main/java/org/apache/felix/http/samples/whiteboard/TestWebSocketServlet.java).
- * Correctly versioned Servlet API.
+* Standard OSGi Http Service implementation
+* Standard OSGi Http Whiteboard implementation
+* Run either with Jetty (version 11 or 12) bundle or inside your own
application server using the servlet bridge
+ * [Felix HTTP Jetty
12](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.jetty12)
is the preferred bundle of choice as it supports JakartaEE10 (1.1.x range) and
JakartaEE11 (2.x range).
+ * [Jetty WebSocket support](https://github.com/apache/felix-dev/pull/310),
see example code
[here](https://github.com/apache/felix-dev/blob/master/http/samples/whiteboard/src/main/java/org/apache/felix/http/samples/whiteboard/TestWebSocketServlet.java).
+ * [Felix HTTP Jetty
11](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.jetty)
is the predecessor of the Jetty 12 bundle, which shipped with [Jetty
9.4.x](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.jetty/4.2.26)
in the 4.x range (JavaEE8), [Jetty
11.x](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.jetty/5.1.10)
in the 5.x range (JakartaEE9).
+ * [Jetty WebSocket support](https://github.com/apache/felix-dev/pull/309),
see example code
[here](https://github.com/apache/felix-dev/blob/master/http/samples/whiteboard/src/main/java/org/apache/felix/http/samples/whiteboard/TestWebSocketServlet.java).
+* Correctly versioned Servlet API.
-## Installing
+## Installing
The Apache Felix HTTP Service project includes several bundles.
- *
[`org.apache.felix.http.servlet-api`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.servlet-api)
- Provides the Servlet API (versions 2.6, 3.0, 3.1, 4.0, 5.0, 6.0 and 6.1 of
the Servlet specification)
- *
[`org.apache.felix.http.api`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.api)
- Provides the OSGi APIs for the Http Whiteboard and Http Service.
- *
[`org.apache.felix.http.jetty12`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.jetty12)
- Implementation that is embedding Jetty server (currently Jetty 12.1.x,
requiring Java 17). This bundle includes the http.api bundle. It's the
preferred Felix Jetty bundle to use, as Jetty 11 has been [EoL since January
2025](https://github.com/jetty/jetty.project/issues/10485).
- *
[`org.apache.felix.http.jetty`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.jetty)
- Predecessor implementation that is embedding Jetty server (currently Jetty
11.x, requiring Java 11). This bundle includes the http.api bundle.
- *
[`org.apache.felix.http.sslfilter`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.sslfilter)
- Servlet filter for handling SSL termination.
- *
[`org.apache.felix.http.bridge`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.bridge)
- Implementation that uses the host application server (bridged mode). Must be
used with the proxy (see below)
- *
[`org.apache.felix.http.proxy`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.proxy)
- Proxy that is needed inside WAR when deployed inside an application server.
- *
[`org.apache.felix.http.wrappers`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.wrappers)
offers wrapper classes that can be used when transitioning to the `jakarta`
namespace, while having libraries that don't offer a jakartified version yet.
+*
[`org.apache.felix.http.servlet-api`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.servlet-api)
- Provides the Servlet API (versions 2.6, 3.0, 3.1, 4.0, 5.0, 6.0 and 6.1 of
the Servlet specification)
+*
[`org.apache.felix.http.api`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.api)
- Provides the OSGi APIs for the Http Whiteboard and Http Service.
+*
[`org.apache.felix.http.jetty12`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.jetty12)
- Implementation that is embedding Jetty server (currently Jetty 12.1.x,
requiring Java 17). This bundle includes the http.api bundle. It's the
preferred Felix Jetty bundle to use, as Jetty 11 has been [EoL since January
2025](https://github.com/jetty/jetty.project/issues/10485).
+*
[`org.apache.felix.http.jetty`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.jetty)
- Predecessor implementation that is embedding Jetty server (currently Jetty
11.x, requiring Java 11). This bundle includes the http.api bundle.
+*
[`org.apache.felix.http.sslfilter`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.sslfilter)
- Servlet filter for handling SSL termination.
+*
[`org.apache.felix.http.bridge`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.bridge)
- Implementation that uses the host application server (bridged mode). Must be
used with the proxy (see below)
+*
[`org.apache.felix.http.proxy`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.proxy)
- Proxy that is needed inside WAR when deployed inside an application server.
+*
[`org.apache.felix.http.wrappers`](https://mvnrepository.com/artifact/org.apache.felix/org.apache.felix.http.wrappers)
offers wrapper classes that can be used when transitioning to the `jakarta`
namespace, while having libraries that don't offer a jakartified version yet.
Note that as of version **3.x**, the Servlet APIs are **no longer** packaged
with the implementation bundles! If you are migrating from lower versions, be
sure to add the
`org.apache.felix.http.servlet-api` (or any other compatible Serlvet API
bundle) to your
classpath and deployment!
### Using classifiers: `light`, `with-jetty-websockets` and
`with-jakarta-websockets` bundle
+
If you would like to use your own Jetty jars instead of the one packaged with
the Felix Jetty bundles, you can use the variants with the following
classifiers:
+
* `light` - A light version of the bundle that does not include the Jetty
classes. This is useful when you want to use your own Jetty jars. Available for
both Jetty bundles.
* `with-jetty-websockets` - A bundle that includes the classes required for
Jetty WebSocket support for Jakarta EE10 (1.1.x) and Jakarta EE11 (2.x).
Jetty12 bundle only.
* `with-jakarta-websockets` - A bundle that includes the classes required for
Jakarta WebSocket support for Jakarta EE10 (1.1.x) and Jakarta EE11 (2.x).
Jetty12 bundle only.
@@ -38,8 +40,9 @@ When building the Felix Jetty bundle with Maven (`mvn clean
install`), the addit
This jar can be deployed to your Felix OSGi environment, along with a
compatible Jetty jars.
See the unit tests for the required bundles and versions that need to be
deployed.
-Or just use maven to include the dependency with the proper classifier.
-```
+Or just use maven to include the dependency with the proper classifier.
+
+```xml
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.http.jetty12</artifactId>
@@ -57,15 +60,16 @@ The Jetty implementation uses the OSGi ServiceLoader
mediator technique to find
Deploying the following set of bundles would be one way to enable the
ServiceLoader mediator support:
- *
[`org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle:1.3.7`](https://mvnrepository.com/artifact/org.apache.aries.spifly/org.apache.aries.spifly.dynamic.bundle)
- * [`org.ow2.asm:asm:9.7`](https://mvnrepository.com/artifact/org.ow2.asm/asm)
- *
[`org.ow2.asm:asm-analysis:9.7`](https://mvnrepository.com/artifact/org.ow2.asm/asm-analysis)
- *
[`org.ow2.asm:asm-commons:9.7`](https://mvnrepository.com/artifact/org.ow2.asm/asm-commons)
- *
[`org.ow2.asm:asm-tree:9.7`](https://mvnrepository.com/artifact/org.ow2.asm/asm-tree)
- *
[`org.ow2.asm:asm-util:9.7`](https://mvnrepository.com/artifact/org.ow2.asm/asm-util)
+*
[`org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle:1.3.7`](https://mvnrepository.com/artifact/org.apache.aries.spifly/org.apache.aries.spifly.dynamic.bundle)
+* [`org.ow2.asm:asm:9.7`](https://mvnrepository.com/artifact/org.ow2.asm/asm)
+*
[`org.ow2.asm:asm-analysis:9.7`](https://mvnrepository.com/artifact/org.ow2.asm/asm-analysis)
+*
[`org.ow2.asm:asm-commons:9.7`](https://mvnrepository.com/artifact/org.ow2.asm/asm-commons)
+*
[`org.ow2.asm:asm-tree:9.7`](https://mvnrepository.com/artifact/org.ow2.asm/asm-tree)
+*
[`org.ow2.asm:asm-util:9.7`](https://mvnrepository.com/artifact/org.ow2.asm/asm-util)
### Jetty 12 bundle
-For the Jetty 12 bundle, start the following set of bundles _before_ the Jetty
12 bundle, but after the beforementioned ServiceLoader bundles (the order is
important and can be configured in `felix.auto.start.1`).
+
+For the Jetty 12 bundle, start the following set of bundles _before_ the Jetty
12 bundle, but after the beforementioned ServiceLoader bundles (the order is
important and can be configured in `felix.auto.start.1`).
The Jetty version should correspond with the version used in the [Jetty 12
bundle](https://github.com/apache/felix-dev/blob/master/http/jetty12/pom.xml#L44).
*
[`jetty-alpn-server-${jetty.version}`](https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-alpn-server)
@@ -89,7 +93,6 @@ of additional bundles to deploy [as described in the jetty
documentation](https:
* For java 8 version 1.8.0_252 or later skip the bootclasspath argument
and deploy the following bundle instead:
* `org.eclipse.jetty.alpn:alpn-api:1.1.3.v20160715`
-
## Using the OSGi Http Whiteboard
The OSGi whiteboard implementation simplifies the task of registering
servlets, filters, resources, listeners, and servlet contexts. For a complete
introduction, please refer to the OSGi R7 Compendium or Enterprise
specification.
@@ -124,52 +127,52 @@ public class Activator implements BundleActivator {
}
}
```
+
An implementation note for when using the Felix HTTP Jetty 12 bundle: only
registering a filter without a servlet, will not work. Make sure that there is
a servlet registered (on the same path as the filter) when registering a
filter, even when that servlet is not hit eventually.
To ensure the HTTP whiteboard service picks up your servlet and filter
correctly, your service
-registration *must* provide several service properties.
-
+registration _must_ provide several service properties.
### Servlet service properties
See full reference in the [OSGi
specification](https://docs.osgi.org/specification/osgi.cmpn/8.1.0/service.servlet.html#service.servlet-i21223311).
The most important properties are:
- * `osgi.http.whiteboard.servlet.pattern` - defines the servlet pattern to
register the servlet under, should be a path as defined in the Servlet
specification.
- * `osgi.http.whiteboard.context.select` - Filter expression to select the
servlet context (optional).
- * `osgi.http.whiteboard.servlet.asyncSupported` - Declares whether the
servlet supports the asynchronous operation mode. Allowed values are true and
false independent of case. Defaults to false. (optional)
- * `osgi.http.whiteboard.servlet.multipart.enable` - Enables support for
multipart configuration on the servlet. Allowed values are true and false
independent of case. Defaults to false. (optional)
- * `servlet.init.*` - these properties (sans the `servlet.init.` prefix) are
made available throught the `ServletConfig` object of your servlet. This allows
you to supply your servlet initialization parameters as you would normally do
in the web descriptor (web.xml).
+* `osgi.http.whiteboard.servlet.pattern` - defines the servlet pattern to
register the servlet under, should be a path as defined in the Servlet
specification.
+* `osgi.http.whiteboard.context.select` - Filter expression to select the
servlet context (optional).
+* `osgi.http.whiteboard.servlet.asyncSupported` - Declares whether the servlet
supports the asynchronous operation mode. Allowed values are true and false
independent of case. Defaults to false. (optional)
+* `osgi.http.whiteboard.servlet.multipart.enable` - Enables support for
multipart configuration on the servlet. Allowed values are true and false
independent of case. Defaults to false. (optional)
+* `servlet.init.*` - these properties (sans the `servlet.init.` prefix) are
made available throught the `ServletConfig` object of your servlet. This allows
you to supply your servlet initialization parameters as you would normally do
in the web descriptor (web.xml).
### Filter service properties
See full reference in the [OSGi
specification](https://docs.osgi.org/specification/osgi.cmpn/8.1.0/service.servlet.html#d0e87922)
.
The most important properties are:
- * `osgi.http.whiteboard.filter.regex` - The regular expression pattern to
register filter with.
- * `osgi.http.whiteboard.context.select` - Filter expression to select the
servlet context (optional).
- * `osgi.http.whiteboard.filter.pattern` - Apply this servlet filter to the
specified URL path patterns. The format of the patterns is specified in the
servlet specification.
- * `osgi.http.whiteboard.filter.asyncSupported` - Declares whether the
servlet filter supports asynchronous operation mode. Allowed values are true
and false independent of case. Defaults to false. (optional)
- * `filter.init.*` - these properties (sans the `filter.init.` prefix) are
made available throught the `FilterConfig` object of your filter. This allows
you to supply your filter initialization parameters as you would normally do in
the web descriptor (web.xml).
+* `osgi.http.whiteboard.filter.regex` - The regular expression pattern to
register filter with.
+* `osgi.http.whiteboard.context.select` - Filter expression to select the
servlet context (optional).
+* `osgi.http.whiteboard.filter.pattern` - Apply this servlet filter to the
specified URL path patterns. The format of the patterns is specified in the
servlet specification.
+* `osgi.http.whiteboard.filter.asyncSupported` - Declares whether the servlet
filter supports asynchronous operation mode. Allowed values are true and false
independent of case. Defaults to false. (optional)
+* `filter.init.*` - these properties (sans the `filter.init.` prefix) are made
available throught the `FilterConfig` object of your filter. This allows you to
supply your filter initialization parameters as you would normally do in the
web descriptor (web.xml).
-The order of filters is no longer managed by the `service.ranking` property,
but by implementing the `compareTo` method.
+The order of filters is no longer managed by the `service.ranking` property,
but by implementing the `compareTo` method.
Multiple servlet filters can process the same servlet request/response. If
more than one Filter matches, they are processed in ranking order, as specified
in `ServiceReference.compareTo`. The servlet filter with the highest ranking is
processed first in the filter chain, while the servlet filter with the lowest
ranking is processed last, before the Servlet.service method is called. After
the servlet completes its service method the filter chain is unwound in reverse
order.
### ServletContextHelper service properties
-See full reference in the [OSGi
specification](https://docs.osgi.org/specification/osgi.cmpn/8.1.0/service.servlet.html#service.http.whiteboard.servletcontext).
+See full reference in the [OSGi
specification](https://docs.osgi.org/specification/osgi.cmpn/8.1.0/service.servlet.html#service.http.whiteboard.servletcontext).
The most important properties are:
- * `osgi.http.whiteboard.context.name` - the identifier of the registered
HTTP context to be referenced by a servlet or filter service
- * `osgi.http.whiteboard.context.path` - The path of the servlet context.
- * `context.init.*` - Properties starting with this prefix are provided as
init parameters through the ServletContext.getInitParameter and
ServletContext.getInitParameterNames methods. The context.init. prefix is
removed from the parameter name.
+* `osgi.http.whiteboard.context.name` - the identifier of the registered HTTP
context to be referenced by a servlet or filter service
+* `osgi.http.whiteboard.context.path` - The path of the servlet context.
+* `context.init.*` - Properties starting with this prefix are provided as init
parameters through the ServletContext.getInitParameter and
ServletContext.getInitParameterNames methods. The context.init. prefix is
removed from the parameter name.
## Using the HttpService
In general the Http Service is regarded legacy and the OSGi Http Whiteboard
should be used instead. If you still want to use the Http Service, this is a
brief introduction. The main components provided by the Apache Felix HTTP
Service bundle are:
- * `HttpService` - Service used to dynamically register resources and servlets;
- * `HttpContext` - Additional (optional) component to handle authentication,
resource and mime type mappings.
+* `HttpService` - Service used to dynamically register resources and servlets;
+* `HttpContext` - Additional (optional) component to handle authentication,
resource and mime type mappings.
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:
@@ -178,7 +181,7 @@ 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");
+ resp.getWriter().write("Hello World");
}
}
```
@@ -231,10 +234,10 @@ calling the `HttpService.unregister` method.
As you notice in the example above, the `registerServlet` method accepts four
parameters:
- * the servlet alias;
- * the `Servlet` instance;
- * an additional configuration `Dictionary`;
- * a `HttpContext`.
+* the servlet alias;
+* the `Servlet` instance;
+* an additional configuration `Dictionary`;
+* a `HttpContext`.
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
@@ -311,11 +314,11 @@ or the correct MIME type implementing the method
`HttpContext.getMimeType` like
//....
public String getMimeType(String file) {
if (file.endsWith(".jpg") {
- return "image/jpeg";
+ return "image/jpeg";
} else if (file.endsWith(".png")) {
- return "image/png";
- } else {
- return "text/html";
+ return "image/png";
+ } else {
+ return "text/html";
}
}
//....
@@ -353,11 +356,10 @@ little setup is needed for this to work:
A detailed example can be found
[here](https://github.com/apache/felix-dev/blob/master/http/samples/bridge).
-
## Using the SSL filter
This filter provides you means to transparently handle [SSL termination
proxies](https://en.wikipedia.org/wiki/SSL_termination_proxy),
-allowing your servlets and filters to work *like they were accessed directly
through HTTPS*. This filter is useful when
+allowing your servlets and filters to work _like they were accessed directly
through HTTPS_. This filter is useful when
deploying applications in large datacenters where frontend load-balancers
distribute the load among several servers in
the same datacenter by stripping the SSL encryption.
@@ -464,21 +466,20 @@ The SSL-filter bundle supports the following
configuration options, using the PI
| `ssl-forward.value` | Defines what HTTP header value to look for in a
request to determine whether a request is a forwarded SSL request in a request.
The default is `on`. |
| `ssl-forward-cert.header` | Defines what HTTP header to look for in a
request to obtain the forwarded client certificate. The default is
`X-Forwarded-SSL-Certificate`. |
-
### HTTP port settings
As of HTTP Jetty version 2.2.2, it is possible to assign a free port for HTTP
or HTTPS automatically, based on certain
rules, for example, a range between 8000 and 9000. The syntax is based on the
version ranges, as described in the OSGi
specification. The following forms are supported:
- * `*` or `0`: binds to the first available port;
- * `8000`: binds to port `8000`, failing if this port is already taken;
- * `[8000,9000]`: binds to a free port in the range 8000 (inclusive) and 9000
(inclusive);
- * `[8000,9000)`: binds to a free port in the range 8000 (inclusive) and 9000
(exclusive);
- * `(8000,9000]`: binds to a free port in the range 8000 (exclusive) and 9000
(inclusive);
- * `(8000,9000)`: binds to a free port in the range 8000 (exclusive) and 9000
(exclusive);
- * `[,9000)`: binds to a free port in the range 1 (inclusive) and 9000
(exclusive);
- * `[8000,)`: binds to a free port in the range 8000 (inclusive) and 65535
(exclusive).
+* `*` or `0`: binds to the first available port;
+* `8000`: binds to port `8000`, failing if this port is already taken;
+* `[8000,9000]`: binds to a free port in the range 8000 (inclusive) and 9000
(inclusive);
+* `[8000,9000)`: binds to a free port in the range 8000 (inclusive) and 9000
(exclusive);
+* `(8000,9000]`: binds to a free port in the range 8000 (exclusive) and 9000
(inclusive);
+* `(8000,9000)`: binds to a free port in the range 8000 (exclusive) and 9000
(exclusive);
+* `[,9000)`: binds to a free port in the range 1 (inclusive) and 9000
(exclusive);
+* `[8000,)`: binds to a free port in the range 8000 (inclusive) and 65535
(exclusive).
Note that picking a port is *not* performed atomically and multiple instances
can try to bind to the same port at the
same time.
@@ -503,7 +504,6 @@ environment. On the other hand they are hard to capture and
propagate. For examp
`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
@@ -522,13 +522,12 @@ the provided `HttpContext` instance:
| `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.
- * Whiteboard sample:
<https://github.com/apache/felix-dev/tree/master/http/samples/whiteboard>
- * Servlet bridge sample:
<https://github.com/apache/felix-dev/tree/master/http/samples/bridge/>
+* Whiteboard sample:
<https://github.com/apache/felix-dev/tree/master/http/samples/whiteboard>
+* Servlet bridge sample:
<https://github.com/apache/felix-dev/tree/master/http/samples/bridge/>
## Maven Artifacts
@@ -566,3 +565,267 @@ This is a list of the most recent artifacts at the time
of writing this document
<version>2.0.2</version>
</dependency>
```
+
+## The OSGi TCK
+
+The implementation passes all updated tests for these specifications:
+
+* [OSGi Http Service
R8](https://github.com/osgi/osgi/tree/r8-cmpn-final/org.osgi.test.cases.http)
+* [OSGi Http Whiteboard
R8](https://github.com/osgi/osgi/tree/r8-cmpn-final/org.osgi.test.cases.http.whiteboard)
+* [OSGi Http Servlet Whiteboard
R8.1](https://github.com/osgi/osgi/tree/8.1.0.cmpn/org.osgi.test.cases.servlet)
+
+However, as there were clarifications and fixes of those tests afterwards for
running the tests, it needs:
+
+* [This fix for the servlet
whiteboard](https://github.com/osgi/osgi/commit/f38f8b32a720ab9a513a20d67240d7f4c8b863ed)
+* The below patch to the http whiteboard tests:
+
+```txt
+diff --git
a/org.osgi.test.cases.http.whiteboard/src/org/osgi/test/cases/http/whiteboard/junit/HttpServiceRuntimeTestCase.java
b/org.osgi.test.cases.http.whiteboard/src/org/osgi/test/cases/http/whiteboard/junit/HttpServiceRuntimeTestCase.java
+index 469d7c1f70..4b8a07e1ce 100644
+---
a/org.osgi.test.cases.http.whiteboard/src/org/osgi/test/cases/http/whiteboard/junit/HttpServiceRuntimeTestCase.java
++++
b/org.osgi.test.cases.http.whiteboard/src/org/osgi/test/cases/http/whiteboard/junit/HttpServiceRuntimeTestCase.java
+@@ -552,26 +552,26 @@ public class HttpServiceRuntimeTestCase extends
BaseHttpWhiteboardTestCase {
+
+ String name = (String)
attributes.get(ContractNamespace.CONTRACT_NAMESPACE);
+
+- if (name != null) {
++ if ("JavaServlet".equals(name)) {
+ Collection<Version> versions =
Versions.plus(attributes
+
.get(ContractNamespace.CAPABILITY_VERSION_ATTRIBUTE));
+
+- if (name.equals("JavaServlet")
&& !versions.isEmpty()
+- &&
versions.iterator()
+-
.next()
+-
.equals(new Version("3.1.0"))) {
+- Map<String, String>
directives = capability.getDirectives();
++ for (Version v : versions) {
++ if (v.equals(new
Version("3.1.0"))) {
++
Map<String,String> directives = capability
++
.getDirectives();
+
+- String uses =
directives.get(Namespace.CAPABILITY_USES_DIRECTIVE);
++ String uses =
directives.get(Namespace.CAPABILITY_USES_DIRECTIVE);
+
+- List<String> packages =
Arrays.asList(uses.split("\\s*,\\s*"));
++ List<String>
packages = Arrays.asList(uses.split("\\s*,\\s*"));
+
+-
assertTrue(packages.contains("javax.servlet"));
+-
assertTrue(packages.contains("javax.servlet.annotation"));
+-
assertTrue(packages.contains("javax.servlet.descriptor"));
+-
assertTrue(packages.contains("javax.servlet.http"));
++
assertTrue(packages.contains("javax.servlet"));
++
assertTrue(packages.contains("javax.servlet.annotation"));
++
assertTrue(packages.contains("javax.servlet.descriptor"));
++
assertTrue(packages.contains("javax.servlet.http"));
+
+- foundContract = true;
++ foundContract =
true;
++ }
+ }
+ }
+ }
+diff --git
a/org.osgi.test.cases.http.whiteboard/src/org/osgi/test/cases/http/whiteboard/junit/ServletContextHelperTestCase.java
b/org.osgi.test.cases.http.whiteboard/src/org/osgi/test/cases/http/whiteboard/junit/ServletContextHelperTestCase.java
+index ab1ed531e1..fb70551cc0 100644
+---
a/org.osgi.test.cases.http.whiteboard/src/org/osgi/test/cases/http/whiteboard/junit/ServletContextHelperTestCase.java
++++
b/org.osgi.test.cases.http.whiteboard/src/org/osgi/test/cases/http/whiteboard/junit/ServletContextHelperTestCase.java
+@@ -154,17 +154,6 @@ public class ServletContextHelperTestCase extends
BaseHttpWhiteboardTestCase {
+ }
+ }
+
+- public void test_140_2_13to14() throws Exception {
+- BundleContext context = getContext();
+- ServiceReference<ServletContextHelper> serviceReference =
context.getServiceReference(ServletContextHelper.class);
+-
+- assertNotNull(serviceReference);
+- assertEquals(Constants.SCOPE_BUNDLE,
serviceReference.getProperty(Constants.SERVICE_SCOPE));
+- assertEquals(
+- DEFAULT,
+-
serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME));
+- }
+-
+ public void test_140_2_15to16() throws Exception {
+ BundleContext context = getContext();
+
+@@ -179,6 +168,12 @@ public class ServletContextHelperTestCase extends
BaseHttpWhiteboardTestCase {
+ public void test_140_2_17to22() throws Exception {
+ final BundleContext context = getContext();
+
++ Dictionary<String, Object> contextProperties = new
Hashtable<String, Object>();
++
contextProperties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME,
"mycontext");
++
contextProperties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH,
"/");
++
++
serviceRegistrations.add(context.registerService(ServletContextHelper.class,
new ServletContextHelper(context.getBundle()) {}, contextProperties));
++
+ FindHook findHook = new FindHook() {
+
+ @Override
+@@ -190,11 +185,11 @@ public class ServletContextHelperTestCase extends
BaseHttpWhiteboardTestCase {
+ return;
+ }
+
+- // don't show default ServletContextHelper
++ // don't show custom context
+ for (Iterator<ServiceReference<?>> iterator =
references.iterator(); iterator.hasNext();) {
+ ServiceReference<?> sr =
iterator.next();
+
+- if
(DEFAULT.equals(sr.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME)))
{
++ if
("mycontext".equals(sr.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME)))
{
+ iterator.remove();
+ }
+ }
+@@ -205,13 +200,22 @@ public class ServletContextHelperTestCase extends
BaseHttpWhiteboardTestCase {
+
serviceRegistrations.add(context.registerService(FindHook.class, findHook,
null));
+
+ AtomicReference<ServletContext> sc1 = new
AtomicReference<ServletContext>();
++ AtomicReference<ServletContext> sc2 = new
AtomicReference<ServletContext>();
+
+ Dictionary<String, Object> properties = new Hashtable<String,
Object>();
+
properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER, "true");
++
properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT,
++ "(" +
HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + "=mycontext)");
+ ServiceRegistration<ServletContextListener> serviceRegistration
= context.registerService(ServletContextListener.class, new MockSCL(sc1),
properties);
+ serviceRegistrations.add(serviceRegistration);
+
+ assertNull(sc1.get());
++
++ properties = new Hashtable<String, Object>();
++
properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER, "true");
++
serviceRegistrations.add(context.registerService(ServletContextListener.class,
new MockSCL(sc2), properties));
++
++ assertNotNull(sc2.get());
+ }
+
+ public void test_table_140_1_HTTP_WHITEBOARD_CONTEXT_NAME_type() throws
Exception {
+@@ -295,17 +299,6 @@ public class ServletContextHelperTestCase extends
BaseHttpWhiteboardTestCase {
+ assertEquals(contextName, sc1.get().getServletContextName());
+ }
+
+- public void test_table_140_1_HTTP_WHITEBOARD_CONTEXT_NAME_default()
throws Exception {
+- BundleContext context = getContext();
+- ServiceReference<ServletContextHelper> serviceReference =
context.getServiceReference(ServletContextHelper.class);
+-
+- assertNotNull(serviceReference);
+- assertEquals(Constants.SCOPE_BUNDLE,
serviceReference.getProperty(Constants.SERVICE_SCOPE));
+- assertEquals(
+- DEFAULT,
+-
serviceReference.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME));
+- }
+-
+ public void
test_table_140_1_HTTP_WHITEBOARD_CONTEXT_NAME_overrideDefault() throws
Exception {
+ BundleContext context = getContext();
+ String contextPath = "/context1";
+@@ -740,67 +733,61 @@ public class ServletContextHelperTestCase extends
BaseHttpWhiteboardTestCase {
+
+ public void test_140_2_1() throws Exception {
+ BundleContext context = getContext();
+- ServiceReference<ServletContextHelper> serviceReference =
context.getServiceReference(ServletContextHelper.class);
++ AtomicReference<ServletContext> sc1 = new
AtomicReference<ServletContext>();
+
+- assertNotNull(serviceReference);
++ Dictionary<String, Object> properties = new Hashtable<String,
Object>();
++
properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER, "true");
++
serviceRegistrations.add(context.registerService(ServletContextListener.class,
new MockSCL(sc1), properties));
+
+- ServletContextHelper servletContextHelper =
context.getService(serviceReference);
++ ServletContext servletContext = sc1.get();
+
+- assertNotNull(servletContextHelper);
++ assertNotNull(servletContext);
+
+- assertNull(servletContextHelper.getMimeType("index.html"));
++ assertNull(servletContext.getMimeType("index.html"));
+ }
+
+ public void test_140_2_2() throws Exception {
+ BundleContext context = getContext();
+- ServiceReference<ServletContextHelper> serviceReference =
context.getServiceReference(ServletContextHelper.class);
+-
+- assertNotNull(serviceReference);
+-
+- ServletContextHelper servletContextHelper =
context.getService(serviceReference);
+-
+- assertNotNull(servletContextHelper);
++ AtomicReference<ServletContext> sc1 = new
AtomicReference<ServletContext>();
+
+-
assertNull(servletContextHelper.getRealPath("META-INF/MANIFEST.MF"));
++ Dictionary<String, Object> properties = new Hashtable<String,
Object>();
++
properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER, "true");
++
serviceRegistrations.add(context.registerService(ServletContextListener.class,
new MockSCL(sc1), properties));
++ ServletContext servletContext = sc1.get();
++
++ assertNotNull(servletContext);
++
++ assertNull(servletContext.getRealPath("META-INF/MANIFEST.MF"));
+ }
+
+ public void test_140_2_3() throws Exception {
+ BundleContext context = getContext();
+- ServiceReference<ServletContextHelper> serviceReference =
context.getServiceReference(ServletContextHelper.class);
+-
+- assertNotNull(serviceReference);
++ AtomicReference<ServletContext> sc1 = new
AtomicReference<ServletContext>();
+
+- ServletContextHelper servletContextHelper =
context.getService(serviceReference);
++ Dictionary<String, Object> properties = new Hashtable<String,
Object>();
++
properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER, "true");
++
serviceRegistrations.add(context.registerService(ServletContextListener.class,
new MockSCL(sc1), properties));
++
++ ServletContext servletContext = sc1.get();
+
+- assertNotNull(servletContextHelper);
++ assertNotNull(servletContext);
+
+-
assertNotNull(servletContextHelper.getResource("META-INF/MANIFEST.MF"));
++
assertNotNull(servletContext.getResource("META-INF/MANIFEST.MF"));
+ }
+
+ public void test_140_2_4() throws Exception {
+ BundleContext context = getContext();
+- ServiceReference<ServletContextHelper> serviceReference =
context.getServiceReference(ServletContextHelper.class);
+-
+- assertNotNull(serviceReference);
+-
+- ServletContextHelper servletContextHelper =
context.getService(serviceReference);
+-
+- assertNotNull(servletContextHelper);
+-
+-
assertNotNull(servletContextHelper.getResourcePaths("META-INF/"));
+- }
+-
+- public void test_140_2_5() throws Exception {
+- BundleContext context = getContext();
+- ServiceReference<ServletContextHelper> serviceReference =
context.getServiceReference(ServletContextHelper.class);
++ AtomicReference<ServletContext> sc1 = new
AtomicReference<ServletContext>();
+
+- assertNotNull(serviceReference);
++ Dictionary<String, Object> properties = new Hashtable<String,
Object>();
++
properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER, "true");
++
serviceRegistrations.add(context.registerService(ServletContextListener.class,
new MockSCL(sc1), properties));
+
+- ServletContextHelper servletContextHelper =
context.getService(serviceReference);
++ ServletContext servletContext = sc1.get();
+
+- assertNotNull(servletContextHelper);
++ assertNotNull(servletContext);
+
+- assertTrue(servletContextHelper.handleSecurity(null, null));
++ assertNotNull(servletContext.getResourcePaths("META-INF/"));
+ }
+
+ public void test_140_2_6_addFilter() throws Exception {
+diff --git
a/org.osgi.test.cases.http.whiteboard/src/org/osgi/test/cases/http/whiteboard/junit/ServletTestCase.java
b/org.osgi.test.cases.http.whiteboard/src/org/osgi/test/cases/http/whiteboard/junit/ServletTestCase.java
+index 14d0bf7ac6..b72a406030 100644
+---
a/org.osgi.test.cases.http.whiteboard/src/org/osgi/test/cases/http/whiteboard/junit/ServletTestCase.java
++++
b/org.osgi.test.cases.http.whiteboard/src/org/osgi/test/cases/http/whiteboard/junit/ServletTestCase.java
+@@ -910,8 +910,8 @@ public class ServletTestCase extends
BaseHttpWhiteboardTestCase {
+ @Override
+ protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
+ invoked.set(true);
+- String exception = (String)
request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE);
+- response.getWriter().write((exception == null)
? "" : exception);
++ Class<?> exception = (Class<?>)
request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE);
++ response.getWriter().write((exception == null)
? "" : exception.getName());
+ }
+
+ }
+```