2021-11-23

Pax Web 8 - Whiteboard services and Karaf commands

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's web:list and http:list commands)
  • org.ops4j.pax.web.samples/showcase - this bundle provides sample:hs and sample:whiteboard commands 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.HttpContext interface (HttpService scenario) or extend org.osgi.service.http.context.ServletContextHelper abstract 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.OsgiContextModel class - this is an internal Pax Web 8 class that's used to unify the experience related to org.osgi.service.http.HttpContext and org.osgi.service.http.context.ServletContextHelper contexts. These objects are how the user-facing OSGi services (HttpContext and ServletContextHelper) 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-whiteboard and that's the behavior defined in 140.2 The Servlet Context chapter of OSGi CMPN R7 specification. The context path is / and the name is default.
  • Service rank and Service ID are 0, so if one wants to override default Whiteboard context, it's enough to register a org.osgi.service.http.context.ServletContextHelper with higher ranking.
  • Type == Whiteboard means that the OSGi context comes from Whitboard part of Pax Web. It also means that there are other types of contexts (namely - HttpService and WAB).
  • 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.WebContainer is exactly 1, as the instance of the service is cached for entire Whiteboard Web Application
  • The usage count for javax.servlet.http.HttpServlet OSGi service is exactly 1. What's more, it was 0 before servlets init() method was called.
  • The usage count for org.osgi.service.http.context.ServletContextHelper OSGi service is 2. That's because it was dereferenced twice:
    1. To obtain default OSGi context for requests that do not use target servlet (for example - only a request chain containing filters)
    2. 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.HttpServiceRuntime is 0 because it was only used by the command itself to provide user with example curl invocation.

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.HttpServlet dropped to 0, 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.WebContainer because the Whiteboard Web Application is still there. It'll be removed completely when the bundle 110 is 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] │ 0
Everything is nicely cleaned up!

Summary

I know I should've written much more about Pax Web 8, but the day will eventually come...

No comments:

Post a Comment