[ 
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)

Reply via email to