Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [jetty-users] WAR overlays in Jetty 9.1?

Hi Klaus,

There's something pretty funky going on in your environment ;)  The
@WebListener handler has code in there to check to see if the class
that it is on has already been defined somewhere else (eg web.xml) and
it does not create another instance if so (see
https://github.com/eclipse/jetty.project/blob/master/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java#L89).
 In my own testing by modifying your cditest webapp, I have kept the
@WebListener annotation on test.ContextListener and also the
definition in web.xml and I only see 1 output of the @PostConstruct (I
added a debug line in the @WebListener handler that shows the check
for the duplicate class name, which in this case is found in web.xml):

janb@smidge: ~/src/jetty-eclipse/jetty-9/jetty-distribution/target/distribution/demo-base
(master)
[2139] java -jar ../start.jar
2013-12-13 09:24:26.203:WARN::main: demo test-realm is deployed. DO
NOT USE IN PRODUCTION!
2013-12-13 09:24:26.207:INFO:oejs.Server:main: jetty-9.1.1-SNAPSHOT
2013-12-13 09:24:26.227:INFO:oejdp.ScanningAppProvider:main:
Deployment monitor
[file:/home/janb/src/jetty-eclipse/jetty-9/jetty-distribution/target/distribution/demo-base/webapps/]
at interval 1
Dec 13, 2013 9:24:26 AM org.jboss.weld.bootstrap.WeldStartup <clinit>
INFO: WELD-000900: 2.1.0 (Final)
@WebListener checking for existing definition for test.ContextListener:WebXml
POST CONSTRUCT ON LISTENER CALLED test.ContextListener@42538425
Dec 13, 2013 9:24:27 AM
org.jboss.weld.environment.servlet.BeanManagerResourceBindingListener
contextInitialized
INFO: BeanManager reference bound to java:comp/env/BeanManager
Dec 13, 2013 9:24:27 AM org.jboss.weld.bootstrap.WeldStartup startContainer
INFO: WELD-000101: Transactional services not available. Injection of
@Inject UserTransaction not available. Transactional observers will be
invoked synchronously.
Dec 13, 2013 9:24:27 AM
org.jboss.weld.environment.jetty.JettyContainer initialize
INFO: Jetty 7.2+ detected, CDI injection will be available in
Listeners, Servlets and Filters.
Dec 13, 2013 9:24:27 AM
org.jboss.weld.interceptor.util.InterceptionTypeRegistry <clinit>
WARN: WELD-001700: Interceptor annotation class javax.ejb.PostActivate
not found, interception based on it is not enabled
Dec 13, 2013 9:24:27 AM
org.jboss.weld.interceptor.util.InterceptionTypeRegistry <clinit>
WARN: WELD-001700: Interceptor annotation class javax.ejb.PrePassivate
not found, interception based on it is not enabled
ugh! injection into test.ContextListener failed!
2013-12-13 09:24:27.738:WARN:oejuc.AbstractLifeCycle:main: FAILED
o.e.j.w.WebAppContext@11de0733{/cditest,file:/tmp/jetty-0.0.0.0-8080-cditest.war-_cditest-any-5944617847214306307.dir/webapp/,STARTING}{/cditest.war}:
java.lang.AbstractMethodError:
org.jboss.weld.environment.jetty.WeldDecorator.decorate(Ljava/lang/Object;)Ljava/lang/Object;


So I don't know how there could be 2 instances of the same listener,
one from the @WebListener and one from web.xml. Maybe add a new
Throwable().printStackTrace() in a constructor for the
test.ContextListener class and see who is calling it?

Similarly, I couldn't immediately see how there could be 2
PostConstruct callbacks for the same instance - then I added 2 methods
annotated with @PostConstruct to see if that made a difference. I
confirmed that Jetty will only call one of them if there are 2 methods
in the same class annotated with @PostConstruct. Then I noticed this:

org.jboss.weld.exceptions.DefinitionException: WELD-000805: Cannot
have more than one post construct method annotated with @PostConstruct
for [EnhancedAnnotatedTypeImpl] public @WebListener class
test.ContextListener

So it looks like Weld might be responsible for the 2nd calling of the
@PostConstruct callback you are experiencing - again, could you add a
new Throwable().printStackTrace() into that method call so we can see
who is calling it? If you can confirm that for me, then the Jetty/Weld
integration will need to be more fine-grained that it is at the
moment.

In any case, the Jetty/Weld integration needs work. The changes that I
made to Jetty ensure that
org.eclipse.jetty.servlet.ServletContextHandler.Decorator instances
are called on all Listeners just before any methods on any listeners
are called. Before, the Decorators were called immediately the
Listener was discovered, so my changes have had the effect of delaying
the application of the Decorators, allowing a lot more scope for extra
Decorators to be added etc. I must admit I got so focussed on getting
this delayed call to the Decorators working that I forgot the
observation I made 6 days ago about Weld's integration with Jetty:

>However, I have to say that weld's current jetty integration isn't
>going to be able to inject a Listener because they are hooking into
>the deployment lifecycle too late. Their implementation sets up a
>ServletContextListener that decides which container it has been
>deployed into on the call to contextInitialized(), and then goes on to
>do some container-specific setup. That's too late to be able to inject
>a listener, as the listeners are clearly already being called back
>during their startup sequence!  Jetty injects listeners just after
>they are created.

So, even though I've delayed the injection of listeners until just
before they will be called back,  the basic problem still stands: once
the ServletContextListeners have started to be called back, it is way
too late to try to execute code that should affect listeners (ie
inject them).

The approach that will work is to make the Weld/jetty integration a
ServletContainerInitializer. They are guaranteed to be called back
before any application code, and can thus do whatever setup is
necessary. Even better, with Jetty we can guarantee the order that
ServletContainerInitializers are called - which is not something the
spec addresses - so we can ensure that the Weld SCI is the first to be
called. I will look into the existing
org.jboss.weld.environment.servlet.Listener and see if I can come up
with some code as a SCI instead.

So to sum up, can you do a fresh git pull on the jetty repo and full
build to make sure you've got the latest code, and then put in those
new Throwable().printStackTrace() calls where I suggested and report
back your findings? Meanwhile, I'll investigate turning the Weld
Listener in to a Weld ServletContainerInitializer.

cheers
Jan

On 13 December 2013 00:59, Klaus Brunner <klaus.brunner@xxxxxxxxx> wrote:
> 2013/12/12 Jan Bartel <janb@xxxxxxxxxxx>:
>> The method annotated with @PostConstruct will be called back by the
>> org.eclipse.jetty.plus.webapp.PlusDecorator.  If you see the output,
>> then jetty's Decorator mechanism is working fine for  listeners. As I
>> understand it, Weld adds in another Decorator to do its magic, so this
>> test will at least confirm that Decorators are being called. If you
>> see the output, then there must be something else in Weld that is not
>> working for listeners.
>
> The postConstruct is duly called, but that's before the whole
> Jetty/Weld integration code is ever run (which is bootstrapped using
> their own listeners):
>
> klaus@klaus-dellnb:/opt/jetty-distribution-9.1.1-SNAPSHOT$ java -jar start.jar
> 2013-12-12 14:38:43.418:INFO:oejs.Server:main: jetty-9.1.1-SNAPSHOT
> 2013-12-12 14:38:43.446:INFO:oejdp.ScanningAppProvider:main:
> Deployment monitor
> [file:/opt/jetty-distribution-9.1.1-SNAPSHOT/webapps/] at interval 1
> Dec 12, 2013 2:38:43 PM org.jboss.weld.bootstrap.WeldStartup <clinit>
> INFO: WELD-000900: 2.2.0 (2013-12-05 14:19)
> POST CONSTRUCT ON LISTENER CALLED test.ContextListener@744f45c
> Dec 12, 2013 2:38:44 PM
> org.jboss.weld.environment.servlet.BeanManagerResourceBindingListener
> contextInitialized
> INFO: BeanManager reference bound to java:comp/env/BeanManager
> Dec 12, 2013 2:38:44 PM org.jboss.weld.bootstrap.WeldStartup startContainer
> INFO: WELD-000101: Transactional services not available. Injection of
> @Inject UserTransaction not available. Transactional observers will be
> invoked synchronously.
> Dec 12, 2013 2:38:44 PM
> org.jboss.weld.environment.jetty.JettyContainer initialize
> INFO: Jetty 7.2+ detected, CDI injection will be available in
> Listeners, Servlets and Filters.
> Dec 12, 2013 2:38:45 PM
> org.jboss.weld.interceptor.util.InterceptionTypeRegistry <clinit>
> WARN: WELD-001700: Interceptor annotation class javax.ejb.PostActivate
> not found, interception based on it is not enabled
> Dec 12, 2013 2:38:45 PM
> org.jboss.weld.interceptor.util.InterceptionTypeRegistry <clinit>
> WARN: WELD-001700: Interceptor annotation class javax.ejb.PrePassivate
> not found, interception based on it is not enabled
> ugh! injection into test.ContextListener failed!
>
> My understanding is that the Weld bootstrapping code should be
> executed before my own Listener is even instantiated (or at least
> immediately after that) so that injection can take place, but I have
> no idea how such ordering could be ensured in Jetty.
>
> BTW, I noticed that if I have my ContextListener both annotated as a
> WebListener *and* referenced in the web.xml, postConstruct is called
> several times (twice on the same instance apparently, and once on
> another instance). This seems to be a bug, or at least it's not what
> I'd expect:
>
> 2013-12-12 13:12:43.300:INFO:oejdp.ScanningAppProvider:main:
> Deployment monitor
> [file:/opt/jetty-distribution-9.1.1-SNAPSHOT/webapps/] at interval 1
> Dec 12, 2013 1:12:43 PM org.jboss.weld.bootstrap.WeldStartup <clinit>
> INFO: WELD-000900: 2.2.0 (2013-12-05 14:19)
> POST CONSTRUCT ON LISTENER CALLED test.ContextListener@4bd38cb3
> POST CONSTRUCT ON LISTENER CALLED test.ContextListener@744f45c
> POST CONSTRUCT ON LISTENER CALLED test.ContextListener@744f45c
> Dec 12, 2013 1:12:44 PM
> org.jboss.weld.environment.servlet.BeanManagerResourceBindingListener
> contextInitialized
> INFO: BeanManager reference bound to java:comp/env/BeanManager
> Dec 12, 2013 1:12:44 PM org.jboss.weld.bootstrap.WeldStartup startContainer
> INFO: WELD-000101: Transactional services not available. Injection of
> @Inject UserTransaction not available. Transactional observers will be
> invoked synchronously.
> Dec 12, 2013 1:12:44 PM
> org.jboss.weld.environment.jetty.JettyContainer initialize
> INFO: Jetty 7.2+ detected, CDI injection will be available in
> Listeners, Servlets and Filters.
> Dec 12, 2013 1:12:44 PM
> org.jboss.weld.interceptor.util.InterceptionTypeRegistry <clinit>
> WARN: WELD-001700: Interceptor annotation class javax.ejb.PostActivate
> not found, interception based on it is not enabled
> Dec 12, 2013 1:12:44 PM
> org.jboss.weld.interceptor.util.InterceptionTypeRegistry <clinit>
> WARN: WELD-001700: Interceptor annotation class javax.ejb.PrePassivate
> not found, interception based on it is not enabled
> ugh! injection into test.ContextListener failed!
>
>
> Klaus
> _______________________________________________
> jetty-users mailing list
> jetty-users@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/jetty-users



-- 
Jan Bartel <janb@xxxxxxxxxxx>
www.webtide.com
'Expert Jetty/CometD developer,production,operations advice'


Back to the top