Introduction
Pax Web 8 was released on October 20th. While the main blog post summarizing all the changes is still work-in-progress, let me show you how it works with Karaf 4.4.
Here's a list of Karaf command invocations, where the commands are provided by two different bundles:
pax-web-karaf- this is the bundle that provides Karaf commands to check the information about installed Web Applications. This bundle is supposed to replace all the commands that were so far available in Karaf itself (see Karaf'sweb:listandhttp:listcommands)org.ops4j.pax.web.samples/showcase- this bundle providessample:hsandsample:whiteboardcommands that can be used to register/unregister various Web elements and contexts
Detailed presentation
First web:context-list presents the contexts
A context is very broad term. Contexts can be:
- implementations of
javax.servlet.ServletContext- these objects are identified by a context path path and in JavaEE sense, there's one such context per Java Web Application - objects that implement
org.osgi.service.http.HttpContextinterface (HttpService scenario) or extendorg.osgi.service.http.context.ServletContextHelperabstract class (Whiteboard scenario) - these contexts are the the objects that OSGi developers deal with directly (or reference directly during Whiteboard registration) - objects of
org.ops4j.pax.web.service.spi.model.OsgiContextModelclass - this is an internal Pax Web 8 class that's used to unify the experience related toorg.osgi.service.http.HttpContextandorg.osgi.service.http.context.ServletContextHelpercontexts. These objects are how the user-facing OSGi services (HttpContextandServletContextHelper) are tracked internally.
When Karaf starts with Pax Web 8, there's only one OSGi context:
karaf@root()> web:context-list
Bundle ID │ Symbolic Name │ Context Path │ Context Name │ Rank │ Service ID │ Type │ Scope │ Registration Properties
──────────┼───────────────────────────────────────────────┼──────────────┼──────────────┼──────┼────────────┼────────────┼─────────┼──────────────────────────────────────────
77 │ org.ops4j.pax.web.pax-web-extender-whiteboard │ / │ default │ 0 │ 0 │ Whiteboard │ static* │ osgi.http.whiteboard.context.name=default
│ │ │ │ │ │ │ │ osgi.http.whiteboard.context.path=/
*) This context is using ServletContextHelper/HttpContext without resolving an org.osgi.framework.ServiceReference.
There's quite a lot of information in this single line:
- The bundle that has registered this OSGi context is
pax-web-extender-whiteboardand that's the behavior defined in 140.2 The Servlet Context chapter of OSGi CMPN R7 specification. The context path is/and the name isdefault. - Service rank and Service ID are
0, so if one wants to override default Whiteboard context, it's enough to register aorg.osgi.service.http.context.ServletContextHelperwith higher ranking. - Type ==
Whiteboardmeans that the OSGi context comes from Whitboard part of Pax Web. It also means that there are other types of contexts (namely -HttpServiceandWAB). - Scope ==
static*effectively means that this OSGi context is special and treated as default in Pax Web. - Finally we can see (some) registration properties that can be used when targetting given OSGi context.
Quite low-level command shows how interesting bundles reference Pax Web services. The Usage Count is obtained via reflection (for now - Felix specific).
The purpose of this command is to verify if the bundles properly get and unget Pax Web services, so we have no resource leaks.
Initially, only two Pax Web extenders obtained an instance of org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer.
karaf@root()> web:meta --web-usage-count Registering Bundle: org.ops4j.pax.web.pax-web-runtime [71] Service ID: 109 Service Scope: bundle Usage Counts for bundles referencing the service: Bundle ID │ Symbolic Name │ Service ID │ Scope │ Service objectClass │ Usage Count ──────────┼───────────────────────────────────────────────┼────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────┼──────────── 75 │ org.ops4j.pax.web.pax-web-extender-war │ 90 │ singleton │ [org.ops4j.pax.web.service.spi.model.events.WebApplicationEventListener] │ 1 75 │ org.ops4j.pax.web.pax-web-extender-war │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 77 │ org.ops4j.pax.web.pax-web-extender-whiteboard │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 111 │ org.ops4j.pax.web.pax-web-karaf │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 0
Let's use sample command to Whiteboard-register a org.osgi.service.http.context.ServletContextHelper with custom name and non-default context path.
karaf@root()> sample:whiteboard context c1 /c1 >> Using context for bundle org.ops4j.pax.web.samples.showcase [110] >> Registering org.osgi.service.http.context.ServletContextHelper with "c1" name, "/c1" context path and for org.ops4j.pax.web.samples.showcase [110].
Let's register a javax.servlet.http.HttpServlet Whiteboard service, targetting the above context.
karaf@root()> sample:whiteboard servlet s1 /s1/* c1 >> Using context for bundle org.ops4j.pax.web.samples.showcase [110] >> Registering a servlet with "s1" name, "/s1/*" pattern, "(osgi.http.whiteboard.context.name=c1)" context selector and for org.ops4j.pax.web.samples.showcase [110]. >>>> Registered successfully. You can test it using `curl -i http://127.0.0.1:8181/c1/s1/anything`
The thing to highlight is that the servlet was registered with osgi.http.whiteboard.context.select=(osgi.http.whiteboard.context.name=c1) registration property. That's the Whiteboard-way to select a target OSGi context, where this servlet should be registered to.
This is exactly the reason why Pax Web 8 was started in the first place! A servlet may target more contexts and it should be available in all of them.
We can check that the servlet is working directly from Karaf
karaf@root()> exec curl -i http://127.0.0.1:8181/c1/s1/anything
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 225 0 225 0 0 5032 0 --:--:-- --:--:-- --:--:-- 5113
HTTP/1.1 200 OK
Date: Tue, 23 Nov 2021 14:27:06 GMT
Content-Type: text/plain;charset=utf-8
Transfer-Encoding: chunked
Servlet: s1
Servlet Config: org.ops4j.pax.web.service.spi.servlet.OsgiInitializedServlet$1@332abd96
Servlet Context: org.ops4j.pax.web.service.spi.servlet.OsgiScopedServletContext@34453e72
Configured name (Whiteboard): /s1/*
As expected, there are now more contexts
karaf@root()> context-list
Bundle ID │ Symbolic Name │ Context Path │ Context Name │ Rank │ Service ID │ Type │ Scope │ Registration Properties
──────────┼───────────────────────────────────────────────┼──────────────┼──────────────┼──────┼────────────┼────────────┼───────────┼──────────────────────────────────────────
77 │ org.ops4j.pax.web.pax-web-extender-whiteboard │ / │ default │ 0 │ 0 │ Whiteboard │ static* │ osgi.http.whiteboard.context.name=default
│ │ │ │ │ │ │ │ osgi.http.whiteboard.context.path=/
110 │ org.ops4j.pax.web.samples.showcase │ /c1 │ c1 │ 0 │ 117 │ Whiteboard │ singleton │ osgi.http.whiteboard.context.name=c1
│ │ │ │ │ │ │ │ osgi.http.whiteboard.context.path=/c1
*) This context is using ServletContextHelper/HttpContext without resolving an org.osgi.framework.ServiceReference.
And the usage count has changed
karaf@root()> web:meta --web-usage-count Registering Bundle: org.ops4j.pax.web.pax-web-runtime [71] Service ID: 109 Service Scope: bundle Usage Counts for bundles referencing the service: Bundle ID │ Symbolic Name │ Service ID │ Scope │ Service objectClass │ Usage Count ──────────┼───────────────────────────────────────────────┼────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────┼──────────── 75 │ org.ops4j.pax.web.pax-web-extender-war │ 90 │ singleton │ [org.ops4j.pax.web.service.spi.model.events.WebApplicationEventListener] │ 1 75 │ org.ops4j.pax.web.pax-web-extender-war │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 77 │ org.ops4j.pax.web.pax-web-extender-whiteboard │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 110 │ org.ops4j.pax.web.samples.showcase │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 110 │ org.ops4j.pax.web.samples.showcase │ 117 │ singleton │ [org.osgi.service.http.context.ServletContextHelper] │ 2 110 │ org.ops4j.pax.web.samples.showcase │ 119 │ singleton │ [javax.servlet.http.HttpServlet] │ 1 110 │ org.ops4j.pax.web.samples.showcase │ 111 │ singleton │ [org.osgi.service.http.runtime.HttpServiceRuntime] │ 0 111 │ org.ops4j.pax.web.pax-web-karaf │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 0
Now there's more to explain:
- The interesting rows are the ones related to bundle
org.ops4j.pax.web.samples.showcase, as it's the bundle that is used to register Whiteboard services. - The usage count for
org.osgi.service.http.HttpService/org.ops4j.pax.web.service.WebContaineris exactly1, as the instance of the service is cached for entire Whiteboard Web Application - The usage count for
javax.servlet.http.HttpServletOSGi service is exactly1. What's more, it was0before servletsinit()method was called. - The usage count for
org.osgi.service.http.context.ServletContextHelperOSGi service is2. That's because it was dereferenced twice:- To obtain default OSGi context for requests that do not use target servlet (for example - only a request chain containing filters)
- To obtain an OSGi context for the servlet. This is required, so the servlet (which may be registered by different bundle than the one registering the
ServletContextHelper) gets its own bundle-scoped instance, so Whiteboard specification is satisfied.
- The usage count for
org.osgi.service.http.runtime.HttpServiceRuntimeis0because it was only used by the command itself to provide user with examplecurlinvocation.
A Whiteboard Web Application is a collection of Whiteboard-registered Web elements and contexts, registered by single bundle. One bundle may register web elements targetting different context paths and one context path (equivalent of JavaEE Web Application) may be populated by web elements coming from different bundles.
Now let's unregister the context, which was targetted by the servlet.
karaf@root()> sample:whiteboard -d -s 117 context
>> Using context for bundle org.ops4j.pax.web.samples.showcase [110]
>> Unregistering org.osgi.service.http.context.ServletContextHelper with 117 service.id and for org.ops4j.pax.web.samples.showcase [110].
>>>> Unregistered org.apache.felix.framework.ServiceRegistrationImpl@5840e742 successfully.
karaf@root()> exec curl -i http://127.0.0.1:8181/c1/s1/anything
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 371 100 371 0 0 65443 0 --:--:-- --:--:-- --:--:-- 74200
HTTP/1.1 404 Not Found
Cache-Control: must-revalidate,no-cache,no-store
Content-Type: text/html;charset=iso-8859-1
Content-Length: 371
See? We've got expected 404
What's more, we can see this information in the logs:
(WhiteboardExtenderContext.java:446) : Unregistering ServletModel{id=ServletModel-5,name='s1',urlPatterns=[/s1/*],contexts=[{WB,OCM-3,c1,/c1}]} because its context selection filter doesn't match any context
No worries - when proper context is registered again, the servlet will move to this new context. We'll see it later.
context-list command shows again only one context
karaf@root()> context-list
Bundle ID │ Symbolic Name │ Context Path │ Context Name │ Rank │ Service ID │ Type │ Scope │ Registration Properties
──────────┼───────────────────────────────────────────────┼──────────────┼──────────────┼──────┼────────────┼────────────┼─────────┼──────────────────────────────────────────
77 │ org.ops4j.pax.web.pax-web-extender-whiteboard │ / │ default │ 0 │ 0 │ Whiteboard │ static* │ osgi.http.whiteboard.context.name=default
│ │ │ │ │ │ │ │ osgi.http.whiteboard.context.path=/
*) This context is using ServletContextHelper/HttpContext without resolving an org.osgi.framework.ServiceReference.
The usage counts has changed too
karaf@root()> web:meta --web-usage-count Registering Bundle: org.ops4j.pax.web.pax-web-runtime [71] Service ID: 109 Service Scope: bundle Usage Counts for bundles referencing the service: Bundle ID │ Symbolic Name │ Service ID │ Scope │ Service objectClass │ Usage Count ──────────┼───────────────────────────────────────────────┼────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────┼──────────── 75 │ org.ops4j.pax.web.pax-web-extender-war │ 90 │ singleton │ [org.ops4j.pax.web.service.spi.model.events.WebApplicationEventListener] │ 1 75 │ org.ops4j.pax.web.pax-web-extender-war │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 77 │ org.ops4j.pax.web.pax-web-extender-whiteboard │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 110 │ org.ops4j.pax.web.samples.showcase │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 110 │ org.ops4j.pax.web.samples.showcase │ 119 │ singleton │ [javax.servlet.http.HttpServlet] │ 0 110 │ org.ops4j.pax.web.samples.showcase │ 111 │ singleton │ [org.osgi.service.http.runtime.HttpServiceRuntime] │ 0 111 │ org.ops4j.pax.web.pax-web-karaf │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 0
Important observation:
- Usage count for
javax.servlet.http.HttpServletdropped to0, as the servlet has been stopped (destroy()was called on it). - There are no more references for
org.osgi.service.http.context.ServletContextHelper, because this service was unregistered completely. - There's still one usage for
org.osgi.service.http.HttpService/org.ops4j.pax.web.service.WebContainerbecause the Whiteboard Web Application is still there. It'll be removed completely when the bundle110is stopped.
Let's see Pax Web 8 magic in action. Registering new OSGi context that can satisfy already registered servlet, automatically redeploys the servlet to new matching context!
karaf@root()> sample:whiteboard context c1 /c2 >> Using context for bundle org.ops4j.pax.web.samples.showcase [110] >> Registering org.osgi.service.http.context.ServletContextHelper with "c1" name, "/c2" context path and for org.ops4j.pax.web.samples.showcase [110].
We've registered a c1 context (the name used before), but with different context path: /c2 instead of /c1.
Let's check the usage counts
karaf@root()> web:meta --web-usage-count Registering Bundle: org.ops4j.pax.web.pax-web-runtime [71] Service ID: 109 Service Scope: bundle Usage Counts for bundles referencing the service: Bundle ID │ Symbolic Name │ Service ID │ Scope │ Service objectClass │ Usage Count ──────────┼───────────────────────────────────────────────┼────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────┼──────────── 75 │ org.ops4j.pax.web.pax-web-extender-war │ 90 │ singleton │ [org.ops4j.pax.web.service.spi.model.events.WebApplicationEventListener] │ 1 75 │ org.ops4j.pax.web.pax-web-extender-war │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 77 │ org.ops4j.pax.web.pax-web-extender-whiteboard │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 110 │ org.ops4j.pax.web.samples.showcase │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 110 │ org.ops4j.pax.web.samples.showcase │ 119 │ singleton │ [javax.servlet.http.HttpServlet] │ 0 110 │ org.ops4j.pax.web.samples.showcase │ 111 │ singleton │ [org.osgi.service.http.runtime.HttpServiceRuntime] │ 0 110 │ org.ops4j.pax.web.samples.showcase │ 120 │ singleton │ [org.osgi.service.http.context.ServletContextHelper] │ 2 111 │ org.ops4j.pax.web.pax-web-karaf │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 0
The new org.osgi.service.http.context.ServletContextHelper is already referenced twice (the same reasons as above), but the javax.servlet.http.HttpServlet is referenced 0 times - because the servlet wasn't called yet (thus no init() was called on it).
Servlet is available in new context and not available in the old one
karaf@root()> exec curl -i http://127.0.0.1:8181/c1/s1/anything
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 371 100 371 0 0 201k 0 --:--:-- --:--:-- --:--:-- 362k
HTTP/1.1 404 Not Found
Cache-Control: must-revalidate,no-cache,no-store
Content-Type: text/html;charset=iso-8859-1
Content-Length: 371
karaf@root()> exec curl -i http://127.0.0.1:8181/c2/s1/anything
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 225 0 225 0 0 124k 0 --:--:-- --:--:-- --:--:-- 219k
HTTP/1.1 200 OK
Date: Tue, 23 Nov 2021 14:29:32 GMT
Content-Type: text/plain;charset=utf-8
Transfer-Encoding: chunked
Servlet: s1
Servlet Config: org.ops4j.pax.web.service.spi.servlet.OsgiInitializedServlet$1@2e0bd609
Servlet Context: org.ops4j.pax.web.service.spi.servlet.OsgiScopedServletContext@6b095dac
Configured name (Whiteboard): /s1/*
context-list at this stage
karaf@root()> context-list
Bundle ID │ Symbolic Name │ Context Path │ Context Name │ Rank │ Service ID │ Type │ Scope │ Registration Properties
──────────┼───────────────────────────────────────────────┼──────────────┼──────────────┼──────┼────────────┼────────────┼───────────┼──────────────────────────────────────────
77 │ org.ops4j.pax.web.pax-web-extender-whiteboard │ / │ default │ 0 │ 0 │ Whiteboard │ static* │ osgi.http.whiteboard.context.name=default
│ │ │ │ │ │ │ │ osgi.http.whiteboard.context.path=/
110 │ org.ops4j.pax.web.samples.showcase │ /c2 │ c1 │ 0 │ 120 │ Whiteboard │ singleton │ osgi.http.whiteboard.context.name=c1
│ │ │ │ │ │ │ │ osgi.http.whiteboard.context.path=/c2
*) This context is using ServletContextHelper/HttpContext without resolving an org.osgi.framework.ServiceReference.
Usage counts still shows no leakage
karaf@root()> web:meta --web-usage-count Registering Bundle: org.ops4j.pax.web.pax-web-runtime [71] Service ID: 109 Service Scope: bundle Usage Counts for bundles referencing the service: Bundle ID │ Symbolic Name │ Service ID │ Scope │ Service objectClass │ Usage Count ──────────┼───────────────────────────────────────────────┼────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────┼──────────── 75 │ org.ops4j.pax.web.pax-web-extender-war │ 90 │ singleton │ [org.ops4j.pax.web.service.spi.model.events.WebApplicationEventListener] │ 1 75 │ org.ops4j.pax.web.pax-web-extender-war │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 77 │ org.ops4j.pax.web.pax-web-extender-whiteboard │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 110 │ org.ops4j.pax.web.samples.showcase │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 110 │ org.ops4j.pax.web.samples.showcase │ 119 │ singleton │ [javax.servlet.http.HttpServlet] │ 1 110 │ org.ops4j.pax.web.samples.showcase │ 111 │ singleton │ [org.osgi.service.http.runtime.HttpServiceRuntime] │ 0 110 │ org.ops4j.pax.web.samples.showcase │ 120 │ singleton │ [org.osgi.service.http.context.ServletContextHelper] │ 2 111 │ org.ops4j.pax.web.pax-web-karaf │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 0
Let's unregister the servlet this time
karaf@root()> sample:whiteboard -d servlet s1 >> Using context for bundle org.ops4j.pax.web.samples.showcase [110] >>>> Unregistered org.apache.felix.framework.ServiceRegistrationImpl@68ed9dd9 successfully. karaf@root()> web:meta --web-usage-count Registering Bundle: org.ops4j.pax.web.pax-web-runtime [71] Service ID: 109 Service Scope: bundle Usage Counts for bundles referencing the service: Bundle ID │ Symbolic Name │ Service ID │ Scope │ Service objectClass │ Usage Count ──────────┼───────────────────────────────────────────────┼────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────┼──────────── 75 │ org.ops4j.pax.web.pax-web-extender-war │ 90 │ singleton │ [org.ops4j.pax.web.service.spi.model.events.WebApplicationEventListener] │ 1 75 │ org.ops4j.pax.web.pax-web-extender-war │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 77 │ org.ops4j.pax.web.pax-web-extender-whiteboard │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 110 │ org.ops4j.pax.web.samples.showcase │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 110 │ org.ops4j.pax.web.samples.showcase │ 111 │ singleton │ [org.osgi.service.http.runtime.HttpServiceRuntime] │ 0 110 │ org.ops4j.pax.web.samples.showcase │ 120 │ singleton │ [org.osgi.service.http.context.ServletContextHelper] │ 1 111 │ org.ops4j.pax.web.pax-web-karaf │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 0
See that the org.osgi.service.http.context.ServletContextHelper is now referenced only once - as the default OSGi context for /c2 context path.
Let's unregister the Whiteboard context
karaf@root()> sample:whiteboard -d -s 120 context
>> Using context for bundle org.ops4j.pax.web.samples.showcase [110]
>> Unregistering org.osgi.service.http.context.ServletContextHelper with 120 service.id and for org.ops4j.pax.web.samples.showcase [110].
>>>> Unregistered org.apache.felix.framework.ServiceRegistrationImpl@1ff977fd successfully.
karaf@root()> web:meta --web-usage-count
Registering Bundle: org.ops4j.pax.web.pax-web-runtime [71]
Service ID: 109
Service Scope: bundle
Usage Counts for bundles referencing the service:
Bundle ID │ Symbolic Name │ Service ID │ Scope │ Service objectClass │ Usage Count
──────────┼───────────────────────────────────────────────┼────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────┼────────────
75 │ org.ops4j.pax.web.pax-web-extender-war │ 90 │ singleton │ [org.ops4j.pax.web.service.spi.model.events.WebApplicationEventListener] │ 1
75 │ org.ops4j.pax.web.pax-web-extender-war │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1
77 │ org.ops4j.pax.web.pax-web-extender-whiteboard │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1
110 │ org.ops4j.pax.web.samples.showcase │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1
110 │ org.ops4j.pax.web.samples.showcase │ 111 │ singleton │ [org.osgi.service.http.runtime.HttpServiceRuntime] │ 0
111 │ org.ops4j.pax.web.pax-web-karaf │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 0
karaf@root()> context-list
Bundle ID │ Symbolic Name │ Context Path │ Context Name │ Rank │ Service ID │ Type │ Scope │ Registration Properties
──────────┼───────────────────────────────────────────────┼──────────────┼──────────────┼──────┼────────────┼────────────┼─────────┼──────────────────────────────────────────
77 │ org.ops4j.pax.web.pax-web-extender-whiteboard │ / │ default │ 0 │ 0 │ Whiteboard │ static* │ osgi.http.whiteboard.context.name=default
│ │ │ │ │ │ │ │ osgi.http.whiteboard.context.path=/
*) This context is using ServletContextHelper/HttpContext without resolving an org.osgi.framework.ServiceReference.
See - no more custom context and the usage counts show that there's only one extra reference for org.osgi.service.http.HttpService/org.ops4j.pax.web.service.WebContainer - kept by our showcase bundle.
The last reference should be gone when bundle 110 is stopped
karaf@root()> web:meta --web-usage-count Registering Bundle: org.ops4j.pax.web.pax-web-runtime [71] Service ID: 109 Service Scope: bundle Usage Counts for bundles referencing the service: Bundle ID │ Symbolic Name │ Service ID │ Scope │ Service objectClass │ Usage Count ──────────┼───────────────────────────────────────────────┼────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────┼──────────── 75 │ org.ops4j.pax.web.pax-web-extender-war │ 90 │ singleton │ [org.ops4j.pax.web.service.spi.model.events.WebApplicationEventListener] │ 1 75 │ org.ops4j.pax.web.pax-web-extender-war │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 77 │ org.ops4j.pax.web.pax-web-extender-whiteboard │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 1 111 │ org.ops4j.pax.web.pax-web-karaf │ 109 │ bundle │ [org.osgi.service.http.HttpService, org.ops4j.pax.web.service.WebContainer] │ 0Everything is nicely cleaned up!
Summary
I know I should've written much more about Pax Web 8, but the day will eventually come...