vaadin / flow

Vaadin Flow is a Java framework binding Vaadin web components to Java. This is part of Vaadin 10+.
Apache License 2.0
618 stars 167 forks source link

Vaadin 20 demo application does not come up in Apache Karaf's Pax-Web feature #11178

Closed enver-haase closed 3 years ago

enver-haase commented 3 years ago

a) Download and unzip: http://www.apache.org/dyn/closer.lua/karaf/4.3.2/apache-karaf-4.3.2.tar.gz Note that this is the latest version of Karaf and that it comes with a feature that uses Jetty 9.4.40.v20210413 to run web applications.

b) Download and unzip: https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.4.40.v20210413/jetty-distribution-9.4.40.v20210413.tar.gz

c) git clone git@github.com:enver-haase/Playground.git cd Playground/vaadin20-base mvn -Pproduction clean package

d) cp target/vaadin20-base-1.0-SNAPSHOT.war /path/to/jetty/webapps/

e) Test in Jetty: cd /path/to/jetty java -jar start.jar Point browser to http://localhost:8080, find the application context and click http://localhost:8080/vaadin20-base-1.0-SNAPSHOT/ -- test the application.

f) Test in Karaf; cd /path/to/karaf

in etc/users.properties uncomment the lines karaf = karaf,g:admingroup g\:admingroup = group,admin,manager,viewer,systembundles,ssh

Execute ./bin/start Wait a second or two. Execute ./bin/client In the Karaf CLI execute feature:install war See web:list -- it is empty yet. Check the log with log:tail (break to CLI with CTRL-C)

Now use another shell to cp /path/to/jetty/webapps/vaadin20-base-1.0-SNAPSHOT.war /path/to/karaf/deploy/

Follow the logs (see above) and dry your tears after seeing:

11:25:42.523 ERROR [paxweb-extender-2-thread-1] Error deploying web application java.lang.IllegalStateException: Unable to find ServletContextHandler for provided ServletContext at org.eclipse.jetty.websocket.server.NativeWebSocketServletContainerInitializer.onStartup(NativeWebSocketServletContainerInitializer.java:120) ~[?:?] at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext$1.call(HttpServiceContext.java:219) ~[?:?] at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext$1.call(HttpServiceContext.java:214) ~[?:?] at org.ops4j.pax.swissbox.core.ContextClassLoaderUtils.doWithClassLoader(ContextClassLoaderUtils.java:60) ~[?:?]

Point browser to http://localhost:8181/vaadin20-base -- as expected after seeing the exception above, nothing here.

web:list also gives you the state "Failed".

Tried this in macOS and Linux Ubuntu, both latest stable. Browser does not matter.

mstahv commented 3 years ago

I checked your project and how you had changed your project to war packaging. I think it works by accident in jetty currently , probably not in different version. If you use war packaging, you should exclude jetty/tomcat (or mark as provided). Otherwise there will be server code, servlet implementation etc in your war file.

Check these instructions: https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.traditional-deployment

enver-haase commented 3 years ago

That's funny, as this is what I discussed with a customer yesterday, theoretically mulling over what should be right and what should not. Will correct that. But -- what we also found is that while it is now probably broken in that it is Jetty dependent, maybe even down to a specific range of Jetty versions: it does work in standalone Jetty but not in the Jetty in Karaf bearing the exact same version number. So I will fix the theoretical issue but I do practically expect nothing from it.

enver-haase commented 3 years ago

Demo application is now working in both standalone Jetty (9.4.40.v20210413) and Tomcat (8.5.66).

Error deploying to Karaf now looks a little differently:

11:18:47.736 ERROR [paxweb-extender-2-thread-1] Error deploying web application
java.lang.NullPointerException: null
    at com.vaadin.flow.server.startup.ApplicationConfiguration.lambda$get$0(ApplicationConfiguration.java:52) ~[?:?]
    at com.vaadin.flow.server.VaadinServletContext.getAttribute(VaadinServletContext.java:73) ~[?:?]
    at com.vaadin.flow.server.startup.ApplicationConfiguration.get(ApplicationConfiguration.java:49) ~[?:?]
    at com.vaadin.flow.server.DeploymentConfigurationFactory.createPropertyDeploymentConfiguration(DeploymentConfigurationFactory.java:82) ~[?:?]
    at com.vaadin.flow.server.startup.ServletDeployer$StubServletConfig.createDeploymentConfiguration(ServletDeployer.java:186) ~[?:?]
    at com.vaadin.flow.server.startup.ServletDeployer.lambda$getServletConfigurations$0(ServletDeployer.java:293) ~[?:?]
    at java.util.Optional.ifPresent(Optional.java:159) ~[?:1.8.0_291]
    at com.vaadin.flow.server.startup.ServletDeployer.getServletConfigurations(ServletDeployer.java:292) ~[?:?]
    at com.vaadin.flow.server.startup.ServletDeployer.contextInitialized(ServletDeployer.java:210) ~[?:?]
    at com.vaadin.flow.server.startup.ServletContextListeners.contextInitialized(ServletContextListeners.java:44) ~[?:?]
    at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext$3.call(HttpServiceContext.java:339) ~[?:?]
    at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext$3.call(HttpServiceContext.java:335) ~[?:?]
    at org.ops4j.pax.swissbox.core.ContextClassLoaderUtils.doWithClassLoader(ContextClassLoaderUtils.java:60) ~[?:?]
    at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.callContextInitialized(HttpServiceContext.java:334) ~[?:?]
    at org.eclipse.jetty.server.handler.ContextHandler.contextInitialized(ContextHandler.java:997) ~[?:?]
    at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:746) ~[?:?]
    at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:379) ~[?:?]
    at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.startContext(HttpServiceContext.java:392) ~[?:?]
    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:911) ~[?:?]
    at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:288) ~[?:?]
    at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doStart(HttpServiceContext.java:268) ~[?:?]
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73) ~[?:?]
    at org.ops4j.pax.web.service.jetty.internal.JettyServerImpl$1.start(JettyServerImpl.java:327) ~[?:?]
    at org.ops4j.pax.web.service.internal.HttpServiceStarted.end(HttpServiceStarted.java:1264) ~[?:?]
    at org.ops4j.pax.web.service.internal.HttpServiceProxy.end(HttpServiceProxy.java:456) ~[?:?]
    at org.ops4j.pax.web.extender.war.internal.RegisterWebAppVisitorWC.end(RegisterWebAppVisitorWC.java:405) ~[?:?]
    at org.ops4j.pax.web.extender.war.internal.model.WebApp.accept(WebApp.java:658) ~[?:?]
    at org.ops4j.pax.web.extender.war.internal.WebAppPublisher$WebAppDependencyListener.register(WebAppPublisher.java:228) ~[?:?]
    at org.ops4j.pax.web.extender.war.internal.WebAppPublisher$WebAppDependencyListener.addingService(WebAppPublisher.java:173) ~[?:?]
    at org.ops4j.pax.web.extender.war.internal.WebAppPublisher$WebAppDependencyListener.addingService(WebAppPublisher.java:129) ~[?:?]
    at org.osgi.util.tracker.ServiceTracker$Tracked.customizerAdding(ServiceTracker.java:943) ~[osgi.core-7.0.0.jar:?]
    at org.osgi.util.tracker.ServiceTracker$Tracked.customizerAdding(ServiceTracker.java:871) ~[osgi.core-7.0.0.jar:?]
    at org.osgi.util.tracker.AbstractTracked.trackAdding(AbstractTracked.java:256) ~[osgi.core-7.0.0.jar:?]
    at org.osgi.util.tracker.AbstractTracked.trackInitial(AbstractTracked.java:183) ~[osgi.core-7.0.0.jar:?]
    at org.osgi.util.tracker.ServiceTracker.open(ServiceTracker.java:321) ~[osgi.core-7.0.0.jar:?]
    at org.osgi.util.tracker.ServiceTracker.open(ServiceTracker.java:264) ~[osgi.core-7.0.0.jar:?]
    at org.ops4j.pax.web.extender.war.internal.WebAppPublisher.publish(WebAppPublisher.java:98) ~[?:?]
    at org.ops4j.pax.web.extender.war.internal.WebObserver.deploy(WebObserver.java:217) ~[?:?]
    at org.ops4j.pax.web.extender.war.internal.WebObserver$1.doStart(WebObserver.java:172) ~[?:?]
    at org.ops4j.pax.web.extender.war.internal.extender.SimpleExtension.start(SimpleExtension.java:59) ~[?:?]
    at org.ops4j.pax.web.extender.war.internal.extender.AbstractExtender.lambda$createExtension$0(AbstractExtender.java:277) ~[?:?]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_291]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_291]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_291]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [?:1.8.0_291]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_291]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_291]
    at java.lang.Thread.run(Thread.java:748) [?:1.8.0_291]
denis-anisimov commented 3 years ago

Karaf apparently has limited support of Servlet 3.0 specification.

ServletContainerInitializers are called but the scanned classes are not passed to the onStartup method as it's required by the Servlet 3.0 spec.

I cannot find the detailed documentation for the PAX-web version 7.0 but here http://ops4j.github.io/pax/web/5.x/ , "3.2. Servlet 3.0+ Capabilities"the limitation is mentioned:

Servlet container initializers are supported, but the @HandlesTypes annotation is currently ignored.

As a result : PAX-web (default HTTP support in Karaf) is not Servlet 3.0 compatible. So Vaadin app will not work in such servlet containers and we can't do anything with this: Servlet 3.0 spec is required.

You may try to workaround this via :

The exception in this report is a consequence of the LookupServletContainerInitializer execution. PAX-web passes only interfaces from the @HandlesTypes annotation and doesn't discover ANY class which is even inside the same flow-server. For WAR case at least LookupInitializer class has to be passed in the set. Then Lookup will be initialized at least. And there will be no exception.

But then there will be no ANY route registered e.g. because the same will happen with RouteRegistryInitializer which wil get ONLY two annotations from its @HandlesTypes and that's it. But i t should get all the annotated classes from the WAR. As a result : nothing will work because there is no any Route target. This specific issue may be fixed via registering routes programmatically in fact.

Anyway: it will be tricky to go through all nonworking ServletContainerInitializer and check what they do to be able to workaround them.

I close this issue since as I said: PAX-web is not Servlet 3.0 compatible and is not supported.

pleku commented 3 years ago

I don't know how common it is to use .war packaging with Karaf and PAX-web. We have already listed a limitation in the documentation:

The Karaf http feature along with war feature provides HTTP Whiteboard implementation which is in practice the standard in Karaf. This implementation is known as PAX Web (see HTTP feature details here). PAX Web is not fully compliant to HTTP Whiteboard OSGi Compendium 7 specification: there are some issues related to ServletContextListener support. Due to these issues the recommended VaadinServlet registration way described in generic Using Vaadin with OSGi tutorial doesn’t work in PAX Web.

It’s still possible to use Vaadin OSGi support with PAX Web though. But the OSGiVaadinServlet should be used as a base class for the servlet which is registered in an OSGi bundle: ...

Not sure what else we should add there ?

denis-anisimov commented 3 years ago

The problem with the documentation is : it's about OSGi and all limitations are listed in OSGi section.

WAR has nothing to do with OSGi and this feature is specific for Karaf: it's possible to deploy plain web application (WAR) as is into Karaf and Karaf should behave like Servlet container in this case (not as OSGi container). Karaf looks like Servlet 3.0 compatible container but in fact it's not: it doesn't support some things from the Servlet 3.0 spec (like ServletContainerInitializer e.g.). So Karaf should be mentioned in some sections where supported Servlet containers are listed instead OSGi.