You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@karaf.apache.org by "Grzegorz Grzybek (Jira)" <ji...@apache.org> on 2023/10/18 16:16:00 UTC

[jira] [Commented] (KARAF-7773) Servlet Filter init invoked (for 2nd time) during undeploy with wrong context

    [ https://issues.apache.org/jira/browse/KARAF-7773?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17776774#comment-17776774 ] 

Grzegorz Grzybek commented on KARAF-7773:
-----------------------------------------

[Whiteboard Specification warns|https://docs.osgi.org/specification/osgi.cmpn/8.0.0/service.http.whiteboard.html#d0e89744]:
{quote}
To deal with the dynamicity of the Whiteboard service lifecycle, it is recommended to implement a servlet filter as Prototype Service Factory service. This will ensure that one single servlet filter instance only receives one init and one destroy call. Otherwise a single servlet filter instance can receive multiple such calls. This is similar to the behavior recommended for Servlet Whiteboard services. 
{quote}

So please set DEBUG level to {{org.ops4j.pax.web}} logger and you'll see a lot of information about deployment/undeployment of elements and contexts - trust me, I spent >3 years implementing it and I'm 94% sure I got it right ;)

See for example [this test's comment|https://github.com/ops4j/org.ops4j.pax.web/blob/web-8.0.22/pax-web-itest/pax-web-itest-server/src/test/java/org/ops4j/pax/web/itest/server/whiteboard/WhiteboardBasicTest.java#L178-L214]:
{code:java}
// Filters are a bit problematic. When new filter is registered, it has to be added to server's internal
// structures in correct order (web.xml order in JavaEE and service rank order in OSGi Whiteboard).
// If simply new filter is registered, ONLY if this filter should be added last, we can attempt optimized
// registration. Otherwise, we have to recreate the filter list, which SHOULD lead to destroy() + init()
// of these filters again.
// Additionally, in Undertow we can't simply remove existing filters without recreating entire "context"
// (ServletContext) created in DeploymentManagerImpl.deploy() and put into DeploymentImpl. So even when
// adding single servlet, we have to recreate everything which usually leads to destroy() + init() for
// each servlet of the context
// In Tomcat and Jetty, we can freely and independently operate on servlets and filters and nothing in any
// specification prevents us from doing so
//
//  - In Jetty, reinitialization is done in org.eclipse.jetty.servlet.ServletHandler.updateMappings() called
//    from org.eclipse.jetty.servlet.ServletHandler.setFilterMappings()

/*
 * 2020-06-01 (no destroy() for filters in Jetty, Undertow is less flexible (!) than Jetty and Tomcat)
 * Jetty:
 * [reg(s1), s1.init(), reg(f1),               f1.init(), reg(f2),               f1.init(), f2.init(),            unreg(f2),                                           f1.init(),            unreg(s1), s1.destroy(),                          unreg(f1)              ]
 * Tomcat:
 * [reg(s1), s1.init(), reg(f1),               f1.init(), reg(f2), f1.destroy(), f1.init(), f2.init(),            unreg(f2), f1.destroy(), f2.destroy(),               f1.init(),            unreg(s1), s1.destroy(),                          unreg(f1), f1.destroy()]
 * Undertow:
 * [reg(s1), s1.init(), reg(f1), s1.destroy(), f1.init(), reg(f2), f1.destroy(), f1.init(), f2.init(), s1.init(), unreg(f2), s1.destroy(), f1.destroy(), f2.destroy(), f1.init(), s1.init(), unreg(s1), s1.destroy(), f1.destroy(), f1.init(), unreg(f1), f1.destroy()]
 */

/*
 * 2020-06-02 (Jetty filters are destroyed, optimization for filter addition)
 * Jetty:
 *  - non optimized: [reg(s1), s1.init(), reg(f1),               f1.init(), reg(f2), f1.destroy(), f1.init(), f2.init(),            unreg(f2), f1.destroy(), f2.destroy(),               f1.init(),            unreg(s1), s1.destroy(),                          unreg(f1), f1.destroy()]
 *  - optimized:     [reg(s1), s1.init(), reg(f1),               f1.init(), reg(f2),                          f2.init(),            unreg(f2), f1.destroy(), f2.destroy(),               f1.init(),            unreg(s1), s1.destroy(),                          unreg(f1), f1.destroy()]
 * Tomcat:
 *  - non optimized: [reg(s1), s1.init(), reg(f1),               f1.init(), reg(f2), f1.destroy(), f1.init(), f2.init(),            unreg(f2), f1.destroy(), f2.destroy(),               f1.init(),            unreg(s1), s1.destroy(),                          unreg(f1), f1.destroy()]
 *  - no optimization possible
 * Undertow:
 *  - non optimized: [reg(s1), s1.init(), reg(f1), s1.destroy(), f1.init(), reg(f2), f1.destroy(), f1.init(), f2.init(), s1.init(), unreg(f2), s1.destroy(), f1.destroy(), f2.destroy(), f1.init(), s1.init(), unreg(s1), s1.destroy(), f1.destroy(), f1.init(), unreg(f1), f1.destroy()]
 *  - optimized:     [reg(s1), s1.init(), reg(f1),               f1.init(), reg(f2),                          f2.init(),            unreg(f2), s1.destroy(), f1.destroy(), f2.destroy(), f1.init(), s1.init(), unreg(s1), s1.destroy(), f1.destroy(), f1.init(), unreg(f1), f1.destroy()]
 */
{code}


> Servlet Filter init invoked (for 2nd time) during undeploy with wrong context
> -----------------------------------------------------------------------------
>
>                 Key: KARAF-7773
>                 URL: https://issues.apache.org/jira/browse/KARAF-7773
>             Project: Karaf
>          Issue Type: Bug
>          Components: karaf
>    Affects Versions: 4.4.3
>            Reporter: Amichai Rothman
>            Priority: Major
>
> When touching a WAB bundle with a context listener as described belower, the undeploy/deploy cycle, instead of just invoking destroy on the old context and initialize on the new one, seems to destroy the old one, re-initialize the old one (with the wrong "whiteboard extender" context), destroy it again, initialize the new one (with correct context), and initialize the old one once more (but without the filter init).
> I'll describe my full scenario, even though it's possible the issue can be reproduced with a simpler setup:
> I have an application consisting of multiple bundles in the karaf deploy folder. One of them is a WAB. It's web.xml only contains display-name and listener-class with a ServletContextListener. The listener contextInitialized implementation instantiates a custom Filter, whose class is imported from a different app bundle:
> {code:java}
> Filter filter = new MyFilter();
> context.addFilter("MyFilter", filter)
>     .addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD), true, "/*");
> {code}
> The filter's init method is invoked successfully and all is good.
> Then, I update/touch the WAB bundle in the deploy folder.
> This causes a thread named "paxweb-config-3-thread-1 (undeploy /)" to call the listener's  contextDestroyed method as expected, but then it also immediately calls the contextInitialized method again (still from the undeploy thread, and still the same old listener instance), this time with the servlet context of the pax-web-extender-whiteboard rather than the WAB bundle. It creates another filter instance, whose init method gets invoked with the pax-web-extender-whiteboard context as well (my init implementation throws an exception at this point when the context is wrong, resources aren't found etc.).
> Then a thread named "paxweb-config-3-thread-1 (deploy /)" (notice undeploy changed to deploy) calls contextDestroyed, still with the extender context. Finally, a new listener instance is craeted, contextInitialized is invoked again, this time with the correct WAB context, followed by the filter's init method. In addition, the old listener instance (which should be dead by now) contextInitialized also gets invoked again, but not followed by the filter init (maybe because it previously threw an exception on it? just guessing).



--
This message was sent by Atlassian Jira
(v8.20.10#820010)