vaadin / osgi

OSGi support for the latest Vaadin version
https://vaadin.com/docs/latest/flow/integrations/osgi/basic
Other
3 stars 1 forks source link

OSGi: Make sure that Push with Websocket transport works in OSGi #64

Open denis-anisimov opened 5 years ago

denis-anisimov commented 5 years ago

This ticket follows up https://github.com/vaadin/flow/issues/5081.

It's quite complicated even just describe the ticket.

The simplest description is:

Use base-starter-flow-osgi and add @Push annotation to MainView.java. Push won't work.

By default the transport is Websockets. And that's the reason why it doesn't work. It's possible to use Long polling as a transport.

Note that it's not clear whether this issue is a project configuration issue or it's an issue in our websocket support with OSGi.

First of all you should add websocket api dependency to the project :

<dependency>
    <groupId>javax.websocket</groupId>
    <artifactId>javax.websocket-api</artifactId>
    <version>1.1</version>
    <scope>provided</scope>
</dependency>

But this is not enough. Push with websockets won't work. The reason why it doesn't work is: ServerContainer is null in the org.atmosphere.container.JSR356AsyncSupport here:

public JSR356AsyncSupport(AtmosphereConfig config, ServletContext ctx) {
        super(config);
        ServerContainer container = (ServerContainer) ctx.getAttribute(ServerContainer.class.getName());

And that's the most complicated thing: it's totally unknown which bundle should set the attribute in the ServletContext. Apparently there should be some websocket implementation bundle for jetty which should set the attribute at the servlet initialization phase.

This is normally done either by a ServletContainerInitializer or ServletContextListener. The problem is : neither one nor another doesn't work in OSGi out of the box (at least they doesn't work in Felix jetty).

So the questions are:

It's not even clear whether it's possible to configure Felix Jetty at all to work properly with Atmosphere so that JSR356AsyncSupport doesn't fail. May be it's just not possible at all and we should use another OSGi container/ web container ?

If it's possible then what bundles should be deployed in addition to javax.websocket-api to enable websocket support (not a generic web sockets support but make JSR356AsyncSupport works as it should)?

If we find those bundles and deploy then then what's required from Flow to make websocket Push works ?

We have JSR356WebsocketInitializer which is aggregated by ServletContextListeners (which is @WebListener ) and it's not activated in OSGi out of the box. So this is one thing in addition to all other which we should take care.

Read also comments in another ticket starting from this one : https://github.com/vaadin/flow/issues/5081#issuecomment-467372123.

denis-anisimov commented 5 years ago

Some investigation notes:

Seems those dependencies have websocket impl for jetty:

<dependency>
            <groupId>org.eclipse.jetty.websocket</groupId>
            <artifactId>javax-websocket-server-impl</artifactId>
            <version>9.4.12.v20180830</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty.websocket</groupId>
            <artifactId>javax-websocket-client-impl</artifactId>
            <version>9.4.12.v20180830</version>
            <scope>provided</scope>
        </dependency>

BUT I have no idea whether they are those deps which we need to enable proper websocket support in Felix Jetty.

The functionality in those bundles heavily relies on ServletContainerInitializer (which doesn't work in Felix Jetty). E.g. there is class WebSocketServerContainerInitializer which sets javax.websocket.server.ServerContainer attribute value.

I've made a very very ugly hack in the test-root-context module: I've added the javax-websocket-server-impl dep to it and changed the Activator code to:

@VaadinServletConfiguration(productionMode = false)
    private static class FixedViewServlet extends ViewTestServlet {
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {
            ServletContext servletContext = servletConfig.getServletContext();
            ServletContext originalContext = servletContext.getContext("/");

            try {
                WebSocketServerContainerInitializer initializer = new WebSocketServerContainerInitializer();
                initializer.onStartup(Collections.emptySet(), originalContext);
            } catch (Exception e) {

            }

            String attr = javax.websocket.server.ServerContainer.class
                    .getName();
            servletContext.setAttribute(attr,
                    originalContext.getAttribute(attr));

            System.out.println(
                    "wwwwwwwwwww " + servletContext.getAttribute(attr));

            JSR356WebsocketInitializer jsr356Initializer = new JSR356WebsocketInitializer();
            jsr356Initializer.contextInitialized(
                    new ServletContextEvent(servletConfig.getServletContext()));
            super.init(servletConfig);

            getService().setClassLoader(getClass().getClassLoader());
        }
    }

This code shows how things are complicated : the servletContext is not the real instance which Jetty classes expects. Inside OSGi this is a proxy for a real servlet context. The real servlet context is originalContext. I pass it to WebSocketServerContainerInitializer and then it sets the requires attribute value. Then I need to transfer it to the servletContext and I have to call servletContext.getAttribute otherwise nothing will work (proxy implementation detail).

Then I initialize servlet context via JSR356WebsocketInitializer directly.

Also I had to register a servlet in this way:

Dictionary<String, String> params = new Hashtable<>();
                    params.put(
                            "org.atmosphere.container.JSR356AsyncSupport.mappingPath",
                            "/view/*");
                    httpService.registerServlet("/view/*",
                            new FixedViewServlet(), params, null);

Otherwise there will be an exception again related to the fact that in OSGi the servlet registered in the servlet context is a proxy for Jetty servlet (and there is some code which tries to find a servlet by its name which differs).

With this config I'm able at least get JSR356AsyncSupport somehow working. At least there is ServerContainer attribute value.

But Push with websockets still doesn't work.

So there are so many questions and the very basic questions are about proper project setup so that websocket works with web server in OSGi.

denis-anisimov commented 5 years ago

And final questions: what's needed from Flow to be able to support web sockets Push in OSGi.

It might be that we will need to make changes in the current impl just like we added route registration logic in OSGi.

And it's not clear whether we need to do anything in Flow at the moment: there are too many ways to go (and many wrong ways) in different areas (Felix Jetty issues? Websocket support in Jetty issues? Atmoshpere issues? Project config issues ? Our issues ?)

denis-anisimov commented 5 years ago

It's not clear whether there is a bug or not. The main question is how to make WenSockets work in OSGi overall and in Felix Jetty in particular (if it's possible at all). Or may be another OSGi container/web server should be used to make a test.

But also there is at least one issue: JSR356WebsocketInitializer should work and it doesn't since @WebListener doesn't work.

pleku commented 5 years ago

Apprently for Vaadin Framework 8.7, Push with web sockets works on Karaf 4.2.3 and the included Jetty 9.1.14

denis-anisimov commented 5 years ago

How it can be seen ? Do we have tests for this somewhere ? Karaf is based on Felix though it uses another web server.

pleku commented 5 years ago

Apparently it is working fine in a customer project using 8.7.1 and the recently released Karaf version linked ^.

denis-anisimov commented 5 years ago

Ah, OK. Would be good to see the config to understand which bundles are deployed. But I think it's because Karaf uses Pax as a web server. It might be that Pax supports ServletContainerInitializer , ServletContextListener and @WebListener.

Another question is : how do they deploy their web application into Karaf. If it's deployed as a WAR file then it works just because it's WAR and everything works in WAR in OSGi just because it's a war: it has all dependencies inside WEB-INF/lib folder deployed in one archive and not as standalone bundles.

We are trying to deploy a web application as a standalone bundle without any dep inside it. So there are still questions even about Karaf.

Sandared commented 5 years ago

Hi, as far as I understood your problem all you want to achieve is to register your JSR356WebsocketInitializer as a ServletContextListener, do you?

If so this can be achieved in OSGi by either annotating it with the right annotations as described here

@Component
@HttpWhiteboardListener   
public class JSR356WebsocketInitializer implements ServletContextListener {...}

Unfortunately with the shift from plain properties to ComponentPropertyTypes , i.e., the @HttpWhiteboardListener annotation, there was a bug introduced in Felix Jetty, which prevented the registration of ServletContextListeners declared in this way. I've filed a bug report here. This should be fixed when you use http.jetty-4.0.8, http.base-4.0.6 and http.bridge-4.0.6 instead of 4.0.6/4.0.4/4.0.4 respectively.

If you are unable to make this version shift then you just can declare the property by hand instead of using ComponentPropertyTypes like this:

@Component(property= {HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER + "=true"})
public class JSR356WebsocketInitializer implements ServletContextListener {...}

This solution also works with the old versions of felix.

As I understand it from reading your code in ServletContextListeners you need to enforce a specific starting order for your ServletContextListeners. This can be achieved in OSgi by setting a @ServiceRanking. The higher the service ranking the earlier the repsective ServletContextListener is called if using the same service and ServletContext as another ServletContextListener.

I did this in my old sketch for a Vaadin OSGi integration: https://github.com/Sandared/flow-osgi/blob/master/flow.osgi.integration/src/main/java/io/jatoms/flow/osgi/integration/FlowOsgiRouteRegistryInitializer.java

Kind regards, Thomas

Sandared commented 5 years ago

An additional note regarding Karaf: Karaf is not a pure OSGi runtime. It is a polyglot apllication container that is based on an OSGi runtime. Polyglot means you can not only deploy OSGi applications into it, but also standard wars or Spring applications and Karaf knows how to handle them. This might also be the reason why your code works in Karaf but not with Felix Jetty. Karaf might be able to understand annotations like @WebListener, wheras Felix does not understand them.

Karaf is a very powerful application container, but might not be the best choice to verify an OSGi integration of Flow, because of the aforementioned points.

Kind regards, Thomas

denis-anisimov commented 5 years ago

as far as I understood your problem all you want to achieve is to register your JSR356WebsocketInitializer as a ServletContextListener, do you?

That's only one part of the problem. The main problem : it's not clear how to make Push works with felix-jetty.

I didn't know about @HttpWhiteboardListener annotation but it's just a shorthand for add a service with property HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER + "=true".

In your case you are adding a service via DS , I've been trying to add it programatically.

It doesn't work because of this: http://felix.apache.org/documentation/subprojects/apache-felix-http-service.html#servlet-api-events. It says that at the moment javax.servlet.ServletContextListener is just not supported at all. See my comment here about this: https://github.com/vaadin/flow/issues/5081#issuecomment-467007295

Sandared commented 5 years ago

The reason your programmatically registered service is not registered is the same as why my service with @HttpWhiteboardListener is not registerd: the mentioned bug.

Try to change the value of the property to be a String instead of a boolean, i.e.,

Dictionary<String, Object> props = new Hashtable<String, Object>();
        props.put("osgi.http.whiteboard.listener", "true");

        context.registerService(ServletContextListener.class,
                new ServletContextListener() {

                    @Override
                    public void contextInitialized(ServletContextEvent sce) {
                        System.out.println("Init");
                    }

                    @Override
                    public void contextDestroyed(ServletContextEvent sce) {
                    }
                }, props);

This should work with the older versions of Felix too.

denis-anisimov commented 5 years ago

We don't use Karaf in Flow in our tests. So there is no any uncertainty about OSGi support in Flow. But any statement about working something in OSGi (like here about WebSockets) should be clarified, that's true. Because it's not clear how the application is deployed : as a WAR or as a separate standalone real OSGi bundle.

denis-anisimov commented 5 years ago

The reason your programmatically registered service is not registered is the same as why my service with @HttpWhiteboardListener is not registerd: the mentioned bug.

Ah, alright. Thanks for the info. I will try.

cosbadescu commented 5 years ago

We face the same issue with Equinox 4.7, VAADIN 8.6.4, Jetty 9.4.14/Tomcat 8.5.37, Atmosphere 2.4.30 (VAADIN1), when we try to use Vaadin UI w/ Push and WebSocket transport distributed as OSGi component. The PUSH always fallback to LONG_POOLING no matter if we registered the VaadinServlet to a Felix Jetty HttpService provider, Equinox Jetty HttpService provider or Equinox ServletBridge HttpService provider.

Our application is a VAADIN gateway in front of a micro-service ecosystem where PUSH plays quite a important role. It is required for gateway to run in any web-container as long as an HTTPService is available in OSGi runtime via native support or bridges, therefore we can not limit ourselves just to support Jetty as HttpService provider.

Even we knew it is not enough, we want to see if PUSH runs with Jetty and WebSocket ServerContainer enabled. For that we registered a ServletContextListener via DS, where on contextInitialized we did: ctx.setAttribute(ServerContainer.class.getName(), WebSocketServerContainerInitializer.configureContext(handler))

This was not enough, by first attempt, JSR365 async support does not start because it can not find a servlet-path to map to. Afterwards we force path mapping by manually providing the mapping: args.put("org.atmosphere.container.JSR356AsyncSupport.mappingPath", root);

Using Equinox HttpService provider, we were not able to start JSR365 async support:

2019.03.07 20:23:54 INFO [org.atmosphere.cpr.AtmosphereFramework::addAtmosphereHandler] Installed AtmosphereHandler com.vaadin.server.communication.PushAtmosphereHandler mapped to context-path: /* 2019.03.07 20:23:54 INFO [org.atmosphere.cpr.AtmosphereFramework::addAtmosphereHandler] Installed the following AtmosphereInterceptor mapped to AtmosphereHandler com.vaadin.server.communication.PushAtmosphereHandler 2019.03.07 20:23:54 ERROR [org.atmosphere.cpr.DefaultAsyncSupportResolver::newCometSupport] Failed to create AsyncSupport class: org.atmosphere.container.JSR356AsyncSupport, error: java.lang.reflect.InvocationTargetException 2019.03.07 20:23:54 ERROR [org.atmosphere.cpr.DefaultAsyncSupportResolver::newCometSupport] Real error: Unable to configure jsr356 at that stage. ServerContainer is null

Using Felix HttpService provider, we were able to start JSR365 async support:

2019.03.07 20:08:05 INFO [org.atmosphere.cpr.AtmosphereFramework::info] Atmosphere is using org.atmosphere.inject.InjectableObjectFactory for dependency injection and object creation 2019.03.07 20:08:05 INFO [org.atmosphere.cpr.AtmosphereFramework::info] Atmosphere is using async support: org.atmosphere.container.JSR356AsyncSupport running under container: jetty/9.4.15.v20190215 using javax.servlet/3.0 and jsr356/WebSocket API 2019.03.07 20:08:05 INFO [org.atmosphere.cpr.AtmosphereFramework::info] Atmosphere Framework 2.4.30.vaadin1 started. 2019.03.07 20:08:05 INFO [org.atmosphere.cpr.AtmosphereFramework::addInterceptorToAllWrappers] Installed AtmosphereInterceptor Track Message Size Interceptor using | with priority BEFORE_DEFAULT

Nevertheless we were not able to use VAADIN PUSH due to client side error:

WebSocket connection to 'ws://localhost:8082/main/PUSH?v-uiId=0&v-pushId=bd8aeef6-0956-4f3a-9b21-afd1fa87dba9&X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.3.2.vaadin1-javascript&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&Content-Type=application/json;%20charset=UTF-8&X-atmo-protocol=true' failed: Error during WebSocket handshake: Unexpected response code: 200

Maurice-Betzel commented 5 years ago

Looking into Vaadin 13 this would be a showstopper for my projects. On Vaadin 8 i got push working on Karaf with SCR and pax-web HTTP-Whiteboard and these settings on the Vaadin-Servlet: @WebServlet(urlPatterns = "/*", name = "RiaUI", asyncSupported = true, initParams = { @WebInitParam(name = "org.atmosphere.websocket.suppressJSR356", value = "true"), @WebInitParam(name = "org.atmosphere.websocket.maxIdleTime", value = "600000") } ) @VaadinServletConfiguration(ui = RiaUI.class, productionMode = false, heartbeatInterval = 120) @Component(immediate = true, service = VaadinServlet.class) public class RiaServlet extends OsgiVaadinServlet {...

and the UI class: @PushStateNavigation @Push(PushMode.MANUAL) @Component(service = UI.class, scope = ServiceScope.PROTOTYPE) public class RiaUI extends UI {...

and using following Vaadin bundles:

`mvn:com.vaadin.external.slf4j/vaadin-slf4j-jdk14/${vaadin.slf4j.jdk14.version}

mvn:com.vaadin.external.atmosphere/atmosphere-runtime/${vaadin.atmosphere.version}
    <bundle start-level="80">mvn:com.vaadin.external/gentyref/${vaadin.gentyref.version}</bundle>
    <bundle start-level="80">mvn:com.vaadin/vaadin-shared/${vaadin.version}</bundle>
    <bundle start-level="90">mvn:com.vaadin/vaadin-server/${vaadin.version}</bundle>
    <bundle start-level="90">mvn:com.vaadin/vaadin-client-compiled/${vaadin.version}</bundle>
    <bundle start-level="90">mvn:com.vaadin/vaadin-themes/${vaadin.version}</bundle>
    <bundle start-level="90">mvn:com.vaadin/vaadin-push/${vaadin.version}</bundle>`
Maurice-Betzel commented 5 years ago

Deployed on Karaf 4.2.4, using Apache ServiceMix :: Bundles :: javax.websocket-api:

45 │ Active │ 80 │ 9.3.1 │ ph-commons 46 │ Active │ 80 │ 6.1.2 │ ph-css 47 │ Active │ 80 │ 2.4.30.vaadin1 │ atmosphere-runtime 48 │ Active │ 80 │ 1.2.0.vaadin1 │ GenTyRef 49 │ Active │ 80 │ 2.8.2.vaadin2 │ Vaadin GWT Elemental 50 │ Active │ 80 │ 1.6.1 │ vaadin-slf4j-jdk14 51 │ Active │ 80 │ 1.4.2 │ Flow Client Engine 52 │ Active │ 80 │ 1.4.2 │ Vaadin Flow Html Components 53 │ Active │ 80 │ 1.4.2 │ Vaadin Flow OSGi Support 54 │ Active │ 80 │ 1.4.2 │ Vaadin Flow Push 55 │ Active │ 80 │ 1.4.2 │ Vaadin Flow Server 56 │ Active │ 80 │ 1.4.2 │ Vaadin Flow Lumo Theme 57 │ Active │ 30 │ 1.3 │ javax.annotation API 58 │ Active │ 30 │ 3.0.0 │ Expression Language 3.0 API 59 │ Active │ 30 │ 1.4.7 │ JavaMail API (compat) 60 │ Active │ 30 │ 3.1.0 │ Java Servlet API 61 │ Active │ 80 │ 2.0.1.Final │ Bean Validation API 62 │ Active │ 30 │ 1.1 │ WebSocket server API 63 │ Active │ 80 │ 1.9.10 │ Byte Buddy (without dependencies) 64 │ Active │ 30 │ 1.2.0 │ Apache Aries SPI Fly Dynamic Weaving Bundle 65 │ Active │ 80 │ 1.4.0 │ Apache Commons FileUpload 66 │ Active │ 80 │ 2.6.0 │ Apache Commons IO 67 │ Active │ 30 │ 2.1.16 │ Apache Felix Declarative Services 68 │ Active │ 30 │ 1.1 │ Java Authentication SPI for Containers 69 │ Active │ 30 │ 1.1.1 │ geronimo-jta_1.1_spec 70 │ Active │ 30 │ 4.2.4 │ Apache Karaf :: HTTP :: Core 71 │ Active │ 30 │ 4.2.4 │ Apache Karaf :: SCR :: Management MBeans 72 │ Active │ 30 │ 4.2.4 │ Apache Karaf :: SCR :: Bundle State 73 │ Active │ 80 │ 4.12.0 │ Apache XBean OSGI Bundle Utilities 74 │ Active │ 80 │ 4.12.0 │ Apache XBean :: Classpath Resource Finder 75 │ Active │ 30 │ 3.11.1.v20150902-1521 │ Eclipse Compiler for Java(TM) 76 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Asynchronous HTTP Client 77 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Continuation 78 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Deployers 79 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Http Utility 80 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: IO Utility 81 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: JAAS 82 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: JMX Management 83 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: JNDI Naming 84 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Plus 85 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Rewrite Handler 86 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Security 87 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: JASPI Security 88 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Server Core 89 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Servlet Handling 90 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Utility Servlets and Filters 91 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Utilities 92 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Utilities :: Ajax(JSON) 93 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Webapp Application Support 94 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Websocket :: API 95 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Websocket :: Client 96 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Websocket :: Common 97 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Websocket :: javax.websocket :: Client Implementation 98 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Websocket :: javax.websocket.server :: Server Implementation 99 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Websocket :: Server 100 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: Websocket :: Servlet Interface 101 │ Active │ 30 │ 9.4.12.v20180830 │ Jetty :: XML utilities 102 │ Active │ 80 │ 1.11.3 │ jsoup Java HTML Parser 103 │ Active │ 80 │ 7.0.0 │ org.objectweb.asm 104 │ Active │ 80 │ 7.0.0 │ org.objectweb.asm.commons 105 │ Active │ 80 │ 7.0.0 │ org.objectweb.asm.tree 106 │ Active │ 30 │ 7.2.8 │ OPS4J Pax Web - API 107 │ Active │ 30 │ 7.2.8 │ OPS4J Pax Web - Extender - Whiteboard 108 │ Active │ 30 │ 7.2.8 │ OPS4J Pax Web - Jetty 109 │ Active │ 30 │ 7.2.8 │ OPS4J Pax Web - Jsp Support 110 │ Active │ 30 │ 7.2.8 │ OPS4J Pax Web - Runtime 111 │ Active │ 30 │ 7.2.8 │ OPS4J Pax Web - Service SPI 112 │ Active │ 30 │ 1.0.0.201505202023 │ org.osgi:org.osgi.util.function 113 │ Active │ 30 │ 1.0.0.201505202023 │ org.osgi:org.osgi.util.promise 114 │ Active │ 80 │ 1.1.0.1 │ Apache ServiceMix :: Bundles :: javax.websocket-api 115 │ Active │ 80 │ 1.4.2 │ Vaadin Flow Data 116 │ Active │ 80 │ 1.3.0 │ vaadin-ordered-layout-flow 117 │ Active │ 80 │ 1.3.0 │ vaadin-notification-flow 118 │ Active │ 80 │ 1.3.1 │ vaadin-button-flow 119 │ Active │ 80 │ 1.0.0 │ Base Starter for Vaadin Flow and OSGi

Maurice-Betzel commented 5 years ago

The log is displaying 2 warnings and push is not working:

2019-03-22T10:56:06,406 | WARN | paxweb-config-1-thread-1 | ServletContainerInitializerScanner | 106 - org.ops4j.pax.web.pax-web-api - 7.2.8 | failed to parse and instantiate of javax.servlet.ServletContainerInitializer in classpath

2019-03-22T10:56:06,516 | WARN | paxweb-config-1-thread-1 | ServletContainerInitializerScanner | 106 - org.ops4j.pax.web.pax-web-api - 7.2.8 | failed to parse and instantiate of javax.servlet.ServletContainerInitializer in classpath

After opening the webpage it is reloading if the frequency of my server-side updates and displaying errors in the webpage:

Cookies disabled This application requires cookies to function. Please enable cookies in your browser and click here or press ESC to try again.

...and in the Karaf log:

2019-03-22T11:45:39,866 | WARN | qtp1194084166-125 | HttpChannel | 91 - org.eclipse.jetty.util - 9.4.12.v20180830 | / java.lang.RuntimeException: Cannot load platform configurator at javax.websocket.server.ServerEndpointConfig$Configurator.fetchContainerDefaultConfigurator(ServerEndpointConfig.java:123) ~[?:?] at javax.websocket.server.ServerEndpointConfig$Configurator.getContainerDefaultConfigurator(ServerEndpointConfig.java:128) ~[?:?] at javax.websocket.server.ServerEndpointConfig$Configurator.checkOrigin(ServerEndpointConfig.java:192) ~[?:?] at org.eclipse.jetty.websocket.jsr356.server.JsrCreator.createWebSocket(JsrCreator.java:88) ~[?:?] at org.eclipse.jetty.websocket.server.WebSocketServerFactory.acceptWebSocket(WebSocketServerFactory.java:217) ~[?:?] at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:247) ~[?:?] at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642) ~[?:?] at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533) ~[?:?] at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) ~[?:?] at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548) ~[?:?] at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1340) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:293) ~[?:?] at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473) ~[?:?]

Maurice-Betzel commented 5 years ago

OK, got manual push working now with the following settings on the project-base-osgi project:

Main view:

@Route("") @Push(value = PushMode.MANUAL, transport = Transport.WEBSOCKET) @Theme(Lumo.class) @PWA(name = "Project Base for Vaadin Flow", shortName = "Project Base")

FixedVaadinServlet:

@WebServlet(asyncSupported = true)

Only the following exception keeps popping up in the logs:

2019-03-22T12:22:20,721 | INFO | activator-1-thread-2 | CommandExtension | 35 - org.apache.karaf.shell.core - 4.2.4 | Registering commands for bundle org.apache.karaf.http.core/4.2.4 2019-03-22T12:22:23,529 | WARN | qtp1012809459-149 | HttpChannel | 91 - org.eclipse.jetty.util - 9.4.12.v20180830 | / java.lang.RuntimeException: Cannot load platform configurator at javax.websocket.server.ServerEndpointConfig$Configurator.fetchContainerDefaultConfigurator(ServerEndpointConfig.java:123) ~[?:?] at javax.websocket.server.ServerEndpointConfig$Configurator.getContainerDefaultConfigurator(ServerEndpointConfig.java:128) ~[?:?] at javax.websocket.server.ServerEndpointConfig$Configurator.checkOrigin(ServerEndpointConfig.java:192) ~[?:?] at org.eclipse.jetty.websocket.jsr356.server.JsrCreator.createWebSocket(JsrCreator.java:88) ~[?:?] at org.eclipse.jetty.websocket.server.WebSocketServerFactory.acceptWebSocket(WebSocketServerFactory.java:217) ~[?:?] at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:247) ~[?:?] at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642) ~[?:?] at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533) ~[?:?] at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) ~[?:?] at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548) ~[?:?] at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1340) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:293) ~[?:?] at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203) ~[88:org.eclipse.jetty.server:9.4.12.v20180830] at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473) ~[?:?]

Maurice-Betzel commented 5 years ago

Client side:

Request URL:http://localhost:8181/?v-r=push&v-uiId=5&v-pushId=b13a6930-8591-4721-a42e-1b5a31df9dde&X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.3.2.vaadin1-javascript&X-Atmosphere-Transport=websocket&Content-Type=application/json; charset=UTF-8&X-atmo-protocol=true Request method:GET Remote address:127.0.0.1:8181 Status code: 500 Version:HTTP/1.1 Referrer Policy:no-referrer-when-downgrade

Maurice-Betzel commented 5 years ago

Great, after a redeploy of the Servicemix web-socket bundle this exception disapears, it seems that Karaf did not do a complete reload of these classes and kept using the default javax.websocket classes. On Karaf Vaadin push is working.

Maurice-Betzel commented 5 years ago

Oh, i forgot to mention i changed the VaadinServletRegistration class:

@WebServlet(asyncSupported = true, urlPatterns = "/*") @Component(immediate = true, service = Servlet.class) public class VaadinServletRegistration extends VaadinServlet {

// @WebServlet(asyncSupported = true, urlPatterns = "/*") // private static class FixedVaadinServlet extends VaadinServlet { // @Override // public void init(ServletConfig servletConfig) throws ServletException { // super.init(servletConfig); // // getService().setClassLoader(getClass().getClassLoader()); // } // }

// @Activate // void activate(BundleContext ctx) { // Hashtable<String, Object> properties = new Hashtable<>(); // properties.put( // HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED, // true); // properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, // "/*"); // ctx.registerService(Servlet.class, new FixedVaadinServlet(), // properties); // } }

mpetzold commented 4 years ago

I am using OSGi, Jetty, and Vaadin with Push. However, I am not using Whiteboard Pattern. I prefer to have Jetty jars embedded in a bundle because I require further deep integrations.

I also needed to handle some trouble with Push. In my case the solution was a patch in the Manifest of the "jakarta.websocket-api-1.1.2.jar" (and maybe - I am not sure anymore - using spifly [1]). Add the following header to jakarta.websocket-api, also explained in [2]:

Require-Capability: osgi.serviceloader;filter:="(osgi.serviceloader=javax.websocket.server.ServerEndpointConfig$Configurator)";cardinality:=multiple,osgi.extender;filter:="(osgi.extender=osgi.serviceloader.processor)",osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.6))"

I also had to add the following header to my bundle embedding the Jetty jars:

Provide-Capability:osgi.serviceloader;osgi.serviceloader="javax.servlet.ServletContainerInitializer",osgi.serviceloader;osgi.serviceloader="javax.websocket.server.ServerEndpointConfig$Configurator" Require-Capability: osgi.extender;filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional,osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"

[1] https://aries.apache.org/modules/spi-fly.html [2] https://stackoverflow.com/questions/39740531/jetty-websocket-java-lang-runtimeexception-cannot-load-platform-configurator

denis-anisimov commented 3 years ago

Here are also comments about WS in Karaf: https://github.com/vaadin/osgi/issues/63#issuecomment-841981103

denis-anisimov commented 3 years ago

Moving this ticket into OSGi repo.