ServletContextListener not notified in whiteboard

225 views
Skip to first unread message

Nhut Thai Le

unread,
Sep 24, 2018, 4:13:07 PM9/24/18
to OPS4J
Hello,

I tried to hook a servletContextListener to my custom ServletContextHelper but the contextInitialized method is not called.
-------------------Here is my ServletContextHelper:------------
@Component(
service = ServletContextHelper.class,
property = {
"osgi.http.whiteboard.context.name=ZkComponentsServletContextHelper",
"osgi.http.whiteboard.context.path=/components"
}
)
public class ZkComponentsServletContextHelper extends ServletContextHelper {...}
--------------------------------My ServletContextListener----------
@Component(
name="ZkListener",
service= {
ServletContextListener.class
},
property= {
"osgi.http.whiteboard.listener=true",
"osgi.http.whiteboard.context.select=(osgi.http.whiteboard.context.name=ZkComponentsServletContextHelper)"
}
)
public final class ZkSessionListener implements ServletContextListener {
private WebManager webManager;

@Override
public void contextInitialized(ServletContextEvent sce) {
final ServletContext ctx = sce.getServletContext();
if (WebManager.getWebManagerIfAny(ctx) == null) {
webManager = new WebManager(ctx, "/zkau");
} else {
throw new IllegalStateException("ZK WebManager already exists. Could not initialize via Spring Boot configuration.");
}
}
------------------------------Finally, my simple servlet-------------
@Component(
service = Servlet.class,
property= {
"osgi.http.whiteboard.servlet.pattern=*.zul",
"osgi.http.whiteboard.servlet.pattern=*.zhtml",
"osgi.http.whiteboard.context.select=(osgi.http.whiteboard.context.name=ZkComponentsServletContextHelper)"
}
)
public class ZulExtensionServlet extends HttpServlet{..}
---------------------equinox bundle info-------------
{org.osgi.service.http.context.ServletContextHelper}={service.id=95, osgi.http.whiteboard.context.name=ZkComponentsServletContextHelper, service.bundleid=59, service.scope=bundle, component.name=com.castortech.iris.zk.components.ZkComponentsServletContextHelper, osgi.http.whiteboard.context.path=/components, component.id=3}
    
{javax.servlet.Servlet}={service.id=97, service.bundleid=59, service.scope=bundle, osgi.http.whiteboard.servlet.pattern=[*.zul,*.zhtml], osgi.http.whiteboard.context.select=(osgi.http.whiteboard.context.name=ZkComponentsServletContextHelper), component.name=com.castortech.iris.zk.components.ZulExtensionServlet, component.id=5}
    
{javax.servlet.ServletContextListener}={service.id=98, service.bundleid=59, service.scope=bundle, osgi.http.whiteboard.context.select=(osgi.http.whiteboard.context.name=ZkComponentsServletContextHelper), osgi.http.whiteboard.listener=true, component.name=ZkListener, component.id=6}
    
{javax.servlet.ServletContext}={osgi.web.version=1.0.0.qualifier, osgi.web.contextpath=/components, service.id=124, osgi.web.symbolicname=com.castortech.iris.zk.components, service.bundleid=59, service.scope=singleton, osgi.web.contextname=ZkComponentsServletContextHelper}


As you can see, both the ServletContextListener and the servlet are bound to the same ServletContextHelper and there is a ServletContext created from the ServletContextHelper, however, the contextInitialized method was never called. Am I missing anything?

Thai

Grzegorz Grzybek

unread,
Oct 2, 2018, 4:19:22 AM10/2/18
to op...@googlegroups.com
Hello


It does exactly what you're trying to achieve, but without SCR - only by registering relevant services. You can run the test from within any of three container itest projects:

mvn clean verify -f pax-web-itest/pax-web-itest-container/pax-web-itest-container-jetty/ -Dit.test=WhiteboardR6IntegrationTest#testListenersWithHttpContext
mvn clean verify -f pax-web-itest/pax-web-itest-container/pax-web-itest-container-tomcat/ -Dit.test=WhiteboardR6IntegrationTest#testListenersWithHttpContext
mvn clean verify -f pax-web-itest/pax-web-itest-container/pax-web-itest-container-undertow/ -Dit.test=WhiteboardR6IntegrationTest#testListenersWithHttpContext

I'm not sure what may be your problem (maybe you'll share your maven project via github?) - but this may be related to some other bundles you have installed in your runtime (pure Equinox? pax-exam test? Karaf based on Equinox?) - which may cause problems with finding services you register by pax-web-extender-whiteboard.

best regards
Grzegorz Grzybek

--
--
------------------
OPS4J - http://www.ops4j.org - op...@googlegroups.com

---
You received this message because you are subscribed to the Google Groups "OPS4J" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ops4j+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Nhut Thai Le

unread,
Feb 14, 2019, 5:44:59 PM2/14/19
to op...@googlegroups.com
Hello again,
For some reason, i was able to get my ServletContextListener working for a while then now i need to added another one (for different app context) and i found that both the new and old one does not work anymore. My other HttpSessionListener is still working fine. Funny is that both the ServletContextListener and the HttpSessionListener is extended by the same class:

@Component(
service= {
javax.servlet.http.HttpSessionListener.class,
ServletContextListener.class
},
property= {
"osgi.http.whiteboard.listener=true",
"osgi.http.whiteboard.context.select=(osgi.http.whiteboard.context.name=WebviewerServletContextHelper)",
"listener.name=WebviewerServletContextListener"
}
)
public final class ZkListener implements javax.servlet.http.HttpSessionListener, ServletContextListener {}

Where should i start debugging this?

By the way, I tried to the command to run test on jetty that you suggested and i got:
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 19.390 s
[INFO] Finished at: 2019-02-14T17:32:16-05:00
[INFO] Final Memory: 24M/274M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal on project pax-web-itest-container-jetty: Could not resolve dependencies for project org.ops4j.pax.web.itest.container:pax-web-itest-container-jetty:jar:7.2.9-SNAPSHOT: Failed to collect dependencies at org.ops4j.pax.web.itest:pax-web-itest-base:jar:7.2.9-SNAPSHOT: Failed to read artifact descriptor for org.ops4j.pax.web.itest:pax-web-itest-base:jar:7.2.9-SNAPSHOT: Could not transfer artifact org.ops4j.pax.web.itest:pax-web-itest-base:pom:7.2.9-SNAPSHOT from/to prime-repo (http://repository.primefaces.org): sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target -> [Help 1]

Not sure what is wrong with my cert.
--
Castor Technologies Inc
460 rue St-Catherine St Ouest, Suite 613 
Montréal, Québec H3B-1A7

CONFIDENTIALITY NOTICE: The information contained in this e-mail is confidential and may be proprietary information intended only for the use of the individual or entity to whom it is addressed. If the reader of this message is not the intended recipient, you are hereby notified that any viewing, dissemination, distribution, disclosure, copy or use of the information contained in this e-mail message is strictly prohibited. If you have received and/or are viewing this e-mail in error, please immediately notify the sender by reply e-mail, and delete it from your system without reading, forwarding, copying or saving in any manner. Thank you.
AVIS DE CONFIDENTIALITE: L’information contenue dans ce message est confidentiel, peut être protégé par le secret professionnel et est réservé à l'usage exclusif du destinataire. Toute autre personne est par les présentes avisée qu'il lui est strictement interdit de diffuser, distribuer ou reproduire ce message. Si vous avez reçu cette communication par erreur, veuillez la détruire immédiatement et en aviser l'expéditeur. Merci.

Grzegorz Grzybek

unread,
Mar 5, 2019, 12:20:45 AM3/5/19
to op...@googlegroups.com
Hello

Did you try registering separate listeners instead of one with different interfaces?

I'm not sure about this ValidatorException. Try running mvn with -e option to show full stack traces.

regards
Grzegorz Grzybek

Denis Anisimov

unread,
Jan 21, 2021, 4:12:35 AM1/21/21
to OPS4J
Hi I have the same problem.

I'm trying to get it working in Karaf.
So I'm not sure whether this a Karaf issue or PAX-web.

I can provide steps to reproduce with Karaf:
- Download Karaf 4.3.0
- Extract it.
- Run it via ./bin/karaf
- invoke commands in the Karaf shell: "feature:install httpfeature:install war"
- install logger  via the Karaf shell: "bundle:install -s mvn:org.slf4j/slf4j-simple/1.7.25 bundle:install -s mvn:org.slf4j/slf4j-api/1.7.25"
- install the project locally
- install the attached project : "bundle:install -s mvn:org.example/simple-web/1.0.0"
- open the browser "http://localhost:8181/".
- the servlet is working : the message is shown in the browser.
- but the "TestServletContextListener::contextInitialized" is never invoked. Neither console not log contains expected message.

Is it a bug in PAX-web?  Karaf ?
Or am I doing somethig wrong ?
ServletContextListener works as expected in the felix-jetty .

By the way : how can I create an issue for PAX? Once I create an account to login to JIRA it says I don't have access to it. 
And I may not create a ticket.

Grzegorz Grzybek

unread,
Jan 21, 2021, 5:20:49 AM1/21/21
to op...@googlegroups.com
Hello

I've checked your project and you're nicely using SCRs to register a listener and a servlet.

But you can't be sure which SCR component registers its service first! And even if you could know it (there are tricks to add a @Reference from one @Component to a service of other @Component), you would STILL not be sure which will be first tracked by pax-web-extender-whiteboard!

I found this SCR problem which was never resolved in pax web 7 and earlier and I described it in my Pax Web 8 refactoring branch: https://github.com/ops4j/org.ops4j.pax.web/tree/master-improvements/samples/samples-whiteboard/whiteboard-ds

So I checked that Jetty's "context" is started immediately after your servlet is being registered. This is the thread trace that starts Jetty:

"pipe-start 109@10061" prio=5 tid=0x17f nid=NA runnable
  java.lang.Thread.State: RUNNABLE
 at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:348)
 at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.startContext(HttpServiceContext.java:392)
 at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:855)
 at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:275)
 at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doStart(HttpServiceContext.java:268)
 at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:72)
 - locked <0x283c> (a java.lang.Object)
 at org.ops4j.pax.web.service.jetty.internal.JettyServerImpl$1.start(JettyServerImpl.java:327)
 at org.ops4j.pax.web.service.internal.HttpServiceStarted.registerServlet(HttpServiceStarted.java:255)
...
 at org.ops4j.pax.web.extender.whiteboard.internal.element.ServletWebElement.register(ServletWebElement.java:102)
...
 at org.ops4j.pax.web.extender.whiteboard.internal.tracker.AbstractTracker.addingService(AbstractTracker.java:44)
...
 at org.apache.felix.framework.Felix.registerService(Felix.java:3804)
 at org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:328)
 at org.apache.felix.scr.impl.manager.AbstractComponentManager$3.register(AbstractComponentManager.java:929)
...
 at org.apache.karaf.bundle.command.BundlesCommand.execute(BundlesCommand.java:55)
 at org.apache.karaf.shell.impl.action.command.ActionCommand.execute(ActionCommand.java:84)

and when org.eclipse.jetty.servlet.ServletContextHandler starts, there's only one listener available - org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer$ContextDestroyListener.

org.eclipse.jetty.server.handler.ContextHandler#callContextInitialized() is called when the context is at org.eclipse.jetty.server.handler.ContextHandler.ContextStatus#NOTSET state and then switches to INITIALIZED.

Then when your listener is added (after the servlet), Pax Web 7 tries hard to unregister your first servlet (correctly) to register it again after registering the listener. org.eclipse.jetty.server.handler.ContextHandler#addEventListener() is properly called, then org.eclipse.jetty.servlet.ServletHandler#setServletMappings(), cache of mappings is invalidated.

And while org.eclipse.jetty.server.handler.ContextHandler#_servletContextListeners contains your org.example.TestServletContextListener, it is NOT called because org.eclipse.jetty.server.handler.ContextHandler#_contextStatus is not NOTSET, but INITIALIZED.

So that's the problem with Pax Web 7.

I'm really trying hard to handle all such cases in Pax Web 8, but I can't do it 8hrs a day ;) That's why it's still not ready yet.

And about Pax Web issues - please let me know the login/email you've used in ops4j JIRA and I'll give you proper permissions. I can't see de...@vaadin.com in OPS4j JIRA user list.

regards
Grzegorz Grzybek

Denis Anisimov

unread,
Jan 21, 2021, 6:03:29 AM1/21/21
to OPS4J
Thanks a lot for your reply.

Looks like you are talking about this issue: https://ops4j1.jira.com/browse/PAXWEB-62
But it's extremely old and it's closed so I though it's resolved.

In my example it's not known when the listener is registered: before the servlet is registered and servlet context is initialized or after.
You are right here.
But I've started from another example where the listener is declared via DS in a separate bundle.
And I had deployed this bundle first : so it's registered as a service by PAX.
Then I've deployed the web bundle and the listener has not been called anyway.

So personally for me regardless of the order of listener registration (before or after servlet) it's never called.

The related topic for this : it's possible to declare `ServletContexHelper`  with a given name. Then I can 
require to register a `Servlet` , any listener for the context identified by the name. But what happens if there
is no such context helper registered YET ? In the same way I may declare the helper in a different bundle and
it's not possible to say when it will be registered : before or after the servlet.
So what will happen in that case: will it wait until the context helper appear with the given name or just 
simply fails because there is no helper with this name ?
I expect that it won't fail and wait until the helper appears . Because otherwise I need to write boilerplate
code which waits for the appearance of the service which normally I should not even know about 
(via ServiceTracker or via @Reference). This is extremely inconvenient.
And the same situation is here with  `ServletContexListener`: I have to wait until it's registered and register the servlet
only after that.
By the way I will check that : whether this work at all or not.

But anyway: this looks like a bug because you may not rely on the order of listener registration: the listener should be called even if the servlet context 
of the web app "has been already initialized". As I understand this is exactly what https://ops4j1.jira.com/browse/PAXWEB-62 issue says.

Also this is exactly how felix-jetty work: the servlet may be already intialized (registered and then even initialized) but once the servlet context listener
is registered it's called anyway.
That's why the behavior was quite confusing for me.

But as I understand you confirmed that this does't work properly in pax web 7 and this is what you are working on for pax web 8.
Thank you .

>And about Pax Web issues - please let me know the login/email you've used in ops4j JIRA and I'll give you proper permissions. I can't see de...@vaadin.com in OPS4j JIRA user list.

I've been trying to login with my Google account de...@vaadin.com but then it immediately says that this account has no access to JIRA.
I've registered another account "den     @     admincomps   dot     ru"
At least I've received the e-mail which confirms the registration.
Could you please try that ?

Denis Anisimov

unread,
Jan 22, 2021, 1:15:56 AM1/22/21
to OPS4J
Intersting.....
I've modified the project so that the Servlet class requires the listener class.
Which means that at least the service should be registered before the servlet service.
But it doesn't help: listener is not called anyway.

The only thing which finally worked is: move the listener out of the Servlet project into a separate bundle.
Install and deploy it first.
Then install and deploy the project with Servlet.
Then I get the context initialization event finally.

Grzegorz Grzybek

unread,
Jan 22, 2021, 2:30:50 AM1/22/21
to op...@googlegroups.com
Hello

Yes - you found the problematic aspect of Pax Web... I'm really trying to handle such scenarios in consistent way in Pax Web 8. There's huge amount of changes coming (see https://github.com/ops4j/org.ops4j.pax.web/commits/master-improvements branch) and listeners, ServletContainerInitializers (which also are not handled properly in Pax Web 7) are among the refactored changes.

Pax Web 7 is the final (before version 8) step in evolution of the implementation which started simply as implementation of HttpService which had ... 3 methods - registration of servlets, registration of resources and unregistration of the two...
Then the whiteboard implementation came (and OSGi CMPN Whiteboard specification is actually inspired by Pax Web itself) and in parallel - WAR/WAB support.

For WAR/WAB purposes, a concept of "web applications" was introduced in Pax Web, but still based (underneath) on a WebContainer (an extension of HttpService). Ensuring that listeners start before servlets/filters is tricky, especially because lot of intermediary layers between the HttpService implementation and actual Jetty/Tomcat/Undertow.
On one side, Jetty (or other container) has to start immediately after the servlet is registered, but if "later" elements are registered the container has to be "restarted" (which is not full restart) and this is really not handled consistently (see my previous explanation of NOTSET vs INITIALIZED states).

The final argument for me to rewrite Pax Web was ... https://ops4j1.jira.com/browse/PAXWEB-1123 and:

osgi.http.whiteboard.context.select=(osgi.http.whiteboard.context.name=*)

context selector filter - this itself was a reason to fully refactor all the internal Pax Web models.

So for now I'm afraid you don't have much choice.

regards
Grzegorz Grzybek


Denis Anisimov

unread,
Jan 22, 2021, 2:36:29 AM1/22/21
to OPS4J
Yeah..........
Thank you for the link to the ticket.

This is exactly what I've just found.
That's the reason why nothing works for me even when I deploy the bundle with ServletContextListener BEFORE the bundle which registers Servlet.

The reason is: I have a filter in the service declaration:

@Component(immediate = true, property = {

        HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER + "=true",

        HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT + "=("

                + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME

                + "=*)" }, service = { ServletContextListener.class,

                        TestServletContextListener.class }, scope = ServiceScope.SINGLETON)


And exactly the same bundle with one single TestServletContextListener which worked (as I mentioned before) 
immediately stopped to work after this change.

So thank you for confirmation about that issue.

OK, I will have to find the ways to workaround these issues.
In the end there is always a choice to use felix-jetty impl for HTTP WHITEBOARD instead of PAX.

Grzegorz Grzybek

unread,
Jan 22, 2021, 2:53:05 AM1/22/21
to op...@googlegroups.com
Hello (see answers inline)

(I also invited you to OPS4J JIRA).

czw., 21 sty 2021 o 12:03 Denis Anisimov <de...@vaadin.com> napisał(a):
Thanks a lot for your reply.

Looks like you are talking about this issue: https://ops4j1.jira.com/browse/PAXWEB-62
But it's extremely old and it's closed so I though it's resolved.

Yes - it's not about this issue... It's about lifecycle mismatch between the container (like Jetty) and Pax Web Whiteboard.
 

In my example it's not known when the listener is registered: before the servlet is registered and servlet context is initialized or after.
You are right here.
But I've started from another example where the listener is declared via DS in a separate bundle.
And I had deployed this bundle first : so it's registered as a service by PAX.
Then I've deployed the web bundle and the listener has not been called anyway.

So personally for me regardless of the order of listener registration (before or after servlet) it's never called.

After reading your later email I think it works in some combination ;)
 

The related topic for this : it's possible to declare `ServletContexHelper`  with a given name. Then I can 
require to register a `Servlet` , any listener for the context identified by the name. But what happens if there
is no such context helper registered YET ? In the same way I may declare the helper in a different bundle and
it's not possible to say when it will be registered : before or after the servlet.


This test first registers a Servlet and only then a ServletContextHelper matching the servlet's osgi.http.whiteboard.context.select selector.
It is then handled by reRegisterWebElements() method.
 
So what will happen in that case: will it wait until the context helper appear with the given name or just 
simply fails because there is no helper with this name ?

It can't fail according to specification. What's even more confusing is this scenario:

1) you register a ServletContextHelper with name "x" and context path "/x"
2) you register a Servlet targetting "x" context with /s mapping - so it's available under /x/s
3) you register a ServletContextHelper with name "x" (so conflicting with the first one), "/x2" context path and higher service ranking - your servlet should automatically re-register itself to be available under /x2/s path

 
I expect that it won't fail and wait until the helper appears . Because otherwise I need to write boilerplate
code which waits for the appearance of the service which normally I should not even know about 
(via ServiceTracker or via @Reference). This is extremely inconvenient.

Yes - this is assured by proper Whiteboard implementation which I believe Pax Web 8 already is.
 
And the same situation is here with  `ServletContexListener`: I have to wait until it's registered and register the servlet
only after that.
By the way I will check that : whether this work at all or not.

But anyway: this looks like a bug because you may not rely on the order of listener registration: the listener should be called even if the servlet context 
of the web app "has been already initialized". As I understand this is exactly what https://ops4j1.jira.com/browse/PAXWEB-62 issue says.

PAXWEB-62 probably concerned something more fundamental and I think it was created even before OSGi CMPN Whiteboard spec was created.


Also this is exactly how felix-jetty work: the servlet may be already intialized (registered and then even initialized) but once the servlet context listener
is registered it's called anyway.

felix.http is good HttpService/Whiteboard implementation, but everything is implemented under/inside single "dispatcher servlet" registered ONCE to Jetty. Pax Web attempts to leverage as much as possible from the underlying container, which may be dynamically swapped.
 
That's why the behavior was quite confusing for me.

But as I understand you confirmed that this does't work properly in pax web 7 and this is what you are working on for pax web 8.

Yes. It takes so long, because in my daily work I'm a software maintainer and my usual practice is to code in conservative way to 1) not break anything, 2) anticipate all potential problems with the fix.

kind regards
Grzegorz Grzybek
 

Denis Anisimov

unread,
Jan 22, 2021, 3:08:22 AM1/22/21
to OPS4J
>Yes. It takes so long, because in my daily work I'm a software maintainer and my usual practice is to code in conservative way to 1) not break anything, 2) anticipate all potential problems with the fix.

Sure, thank you very much for your answers.

One last question which may be important for me:
is it possible to refer to the ServletContextHelper by the name (via the osgi.http.whiteboard.context.select  property) when I register web resources?
I mean @HttpWhiteboardResource and refer to 140.6 Registering Resources CMPN 7 specification ( or the same can be done via registerService programmatically).

In the example which you mentioned ServletContextHelper target the default context only.

My usecase is: I should register dynamically (programmatically) a couple of resources using ServletContextHelper for the same context path which Servlet uses :
I'm using some internal events when servlet becomes initialized and then register resources for the same context path.
I cannot use default context here because it refers to the root context path. So I have to use ServletContextHelper with the Servlet context path and register
resources via referring to this ServletContextHelper.

And related question: if filter select for context doesn't work then how may I register a servlet for a custom context ?
Or it doesn't work ONLY being used for ServletContextListener service ?

Grzegorz Grzybek

unread,
Jan 22, 2021, 3:37:01 AM1/22/21
to op...@googlegroups.com
Hello

Here you are: https://github.com/ops4j/org.ops4j.pax.web/blob/master-improvements/pax-web-itest/pax-web-itest-server/src/test/java/org/ops4j/pax/web/itest/server/whiteboard/WhiteboardResourcesTest.java#L122-L123 - it registers an Object.class OSGi service with "osgi.http.whiteboard.resource.pattern" property and also with osgi.http.whiteboard.context.select=(osgi.http.whiteboard.context.name=c1) property, so resources are properly available from different (than "/") context path.


Remember that welcome files are completely forgotten by Whiteboard specification, although they're very important from the point of view of resource access. Pax Web 7 had consistency problems to serve welcome files in the same manner for Tomcat, Jetty and Undertow. Also trailing slash (or lack of it) was handled differently. In Pax Web it's not.

regards
Grzegorz Grzybek

Denis Anisimov

unread,
Jan 22, 2021, 3:57:04 AM1/22/21
to OPS4J
Very good.
Thanks a lot !

Reply all
Reply to author
Forward
0 new messages