New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JSR356 Server OSGI Bundle-Activation #3543
Comments
Please add additional information (and what the actual issue or feature request is) and reopen if needed! |
Sorry, I submitted the issue inadvertently to early because of a typing mistake. Now I can not re-open it. |
@s-b-u interestingly the testcases for this (using paxexam) shows this as working. |
I should mention, that the Jetty-Server is bootstrapped by the bundle "org.eclipse.equinox.http.jetty" instead of "org.eclipse.jetty.osgi.boot" like in the paxexam tests cases. |
Here is some code to illustrate the issue @Component
public class Activator extends Endpoint {
private void addEndpoint(ServerContainer container) throws DeploymentException {
container.addEndpoint(ServerEndpointConfig.Builder.create(Activator.class, "/").build());
}
@Activate
protected void activate(BundleContext ctx) throws Exception {
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler();
ServerContainer container = WebSocketServerContainerInitializer.configureContext(context);
Bundle bundle = FrameworkUtil.getBundle(container.getClass());
System.out.println(bundle.getState());
// prints 4=RESOLVED
// prints 32=ACTIVE when Bundle-ActivationPolicy: lazy or startlevel=3 (Default=4) o.e.j.w.javax.websocket.server
try {
addEndpoint(container);
} catch (RuntimeException e) {
// in the case o.e.j.w.javax.websocket.server is still in RESOLVED State
e.printStackTrace();
// java.lang.RuntimeException: Cannot load platform configurator at
// javax.websocket.server.ServerEndpointConfig$Configurator.fetchContainerDefaultConfigurator(ServerEndpointConfig.java:123)
// @see org.apache.aries.spifly.BaseActivator#start() / providerBundleTracker stateMask=Bundle.ACTIVE
bundle.start();
addEndpoint(container);
}
server.setHandler(context);
server.start();
}
@Override
public void onOpen(Session session, EndpointConfig config) {
}
} |
@s-b-u how are you working around the fact that the javax.websocket-api bundle doesn't contain the correct osgi headers for being able to use the ServiceLoader? Also, can you spell out exactly how changing to lazy activation for the websocket server bundle works in your environment? I'm still struggling to see the difference with our test environment - take a look at the test case here for how we test it in paxexam: https://github.com/eclipse/jetty.project/blob/jetty-9.4.x/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJavaxWebSocket.java |
@janbartel, I use the same approche like within the test, with a fragment. |
@s-b-u I've been playing around with this in our test setup. I don't think I fully understand what is happening. What I see is that when the websocket.server bundle is started (even with lazy activation), the ServletContainerInitializers are registered as providers by spifly:
Then I see that jetty finds and runs these SCIs during startup:
So I'm not sure that it's true that providers are processed after activation? Moreover, our test works (with the explict websocket server start() call commented out), whether or not the websocket server bundle is lazy activation or not. So something is going on in your environment that I don't fully understand. I'm not opposed to make the change to lazy activation, but I don't want to do it unless I fully understand the reason, and am sure that it won't cause problems in other use cases. |
@janbartel I can only refer to The SPI Fly sources to verify the statement. package org.eclipse.jetty.osgi.embedded.test;
import static org.junit.Assert.assertNotNull;
import static org.ops4j.pax.exam.CoreOptions.bundleStartLevel;
import static org.ops4j.pax.exam.CoreOptions.junitBundles;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.streamBundle;
import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.Session;
import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpointConfig;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.tinybundles.core.TinyBundle;
import org.ops4j.pax.tinybundles.core.TinyBundles;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import aQute.bnd.osgi.Constants;
@RunWith(PaxExam.class)
public class TestJettyOSGiEmbeddedWithJavaxWebSocket {
public static class DummyEnpoint extends Endpoint {
@Override
public void onOpen(Session session, EndpointConfig config) {
}
}
public static class TestServer implements BundleActivator {
@Override
public void start(BundleContext bc) throws Exception {
try {
Server server = new Server(8080);
ServletContextHandler sc = new ServletContextHandler();
ServerContainer container = WebSocketServerContainerInitializer.configureContext(sc);
System.out.println(String.format("---------%s----------", FrameworkUtil.getBundle(container.getClass()).getState()));
container.addEndpoint(ServerEndpointConfig.Builder.create(DummyEnpoint.class, "/").build());
server.setHandler(sc);
server.start();
ServletContext servletContext = sc.getServletContext();
bc.registerService(ServletContext.class, servletContext, new Hashtable<>());
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
@Override
public void stop(BundleContext context) throws Exception {
}
}
@Inject
BundleContext bundleContext = null;
@Configuration
public Option[] config() {
TinyBundle patch = TinyBundles.bundle().set(Constants.FRAGMENT_HOST, "javax.websocket-api")
.set(Constants.REQUIRE_CAPABILITY,
"osgi.extender; filter:=\"(osgi.extender=osgi.serviceloader.processor)\"")
.set(Constants.BUNDLE_SYMBOLICNAME, "javax.websocket.api.fragment");
TinyBundle testserver = TinyBundles.bundle().add(TestServer.class).add(DummyEnpoint.class)
.set(Constants.BUNDLE_ACTIVATOR, TestServer.class.getName())
.set(Constants.BUNDLE_SYMBOLICNAME, "org.eclipse.jetty.osgi.embedded.test")
.set(Constants.EXPORT_PACKAGE, "org.eclipse.jetty.osgi.embedded.test");
List<Option> res = new ArrayList<>();
res.add(bundleStartLevel(4));
res.add(junitBundles());
res.add(streamBundle(patch.build()).noStart());
res.add(mavenBundle("org.ow2.asm", "asm").versionAsInProject());
res.add(mavenBundle("org.ow2.asm", "asm-commons").versionAsInProject());
res.add(mavenBundle("org.ow2.asm", "asm-tree").versionAsInProject());
res.add(mavenBundle("org.apache.aries.spifly", "org.apache.aries.spifly.dynamic.bundle").versionAsInProject()
.startLevel(1));
res.add(mavenBundle("org.eclipse.jetty.toolchain", "jetty-osgi-servlet-api").versionAsInProject());
res.add(mavenBundle("javax.annotation", "javax.annotation-api").versionAsInProject());
res.add(mavenBundle("org.apache.geronimo.specs", "geronimo-jta_1.1_spec").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-util").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-deploy").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-server").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-servlet").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-http").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-xml").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-webapp").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-io").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-continuation").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-security").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-client").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-jndi").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-plus").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty", "jetty-annotations").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty.websocket", "websocket-api").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty.websocket", "websocket-common").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty.websocket", "websocket-servlet").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty.websocket", "websocket-server").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty.websocket", "websocket-client").versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty.websocket", "javax-websocket-client-impl").versionAsInProject());
// change the order and startlevel of the following bundles to see the effect
res.add(streamBundle(testserver.build(withBnd())).startLevel(4));
res.add(mavenBundle("javax.websocket", "javax.websocket-api").startLevel(4).versionAsInProject());
res.add(mavenBundle("org.eclipse.jetty.websocket", "javax-websocket-server-impl").startLevel(3).versionAsInProject());
return res.toArray(new Option[res.size()]);
}
@Test
public void test() {
ServiceReference<ServletContext> serviceReference = bundleContext.getServiceReference(ServletContext.class);
ServletContext service = bundleContext.getService(serviceReference);
assertNotNull(service);
}
} |
@s-b-u thank you for the test case! I'm still struggling to see the difference between the jetty test case (TestJettyOSGiBootWithJavaxWebSocket) where it works without lazy activation, and your test case. Sure, you aren't using jetty's ability to use ServletContainerInitializers to init the websocket, but rather doing it explicitly in code, but I can't quite see why that is making a difference .... |
Hi @janbartel, even with the jetty test case, the bundle javax-websocket-server-impl bundle has to be started before jetty-osgi-boot and the web-app-bundle arrive the stage, but this is caused by the ServiceLoader approach and no ServiceContainer will be attached to the ServletContext otherwise. The issue I want to address, is that even if I have an already initialized ServiceContainer available, it still can't be used depending on its own load-order, which I hadn't expected. |
This issue has been automatically marked as stale because it has been a full year without activity. It will be closed if no further activity occurs. Thank you for your contributions. |
This issue has been closed due to it having no activity. |
We might be doing some work on the websocket stuff for osgi with #4797 so maybe we can take a look at this one too. |
This issue has been automatically marked as stale because it has been a full year without activity. It will be closed if no further activity occurs. Thank you for your contributions. |
This issue has been closed due to it having no activity. |
Because Apache Aries SPI Fly processes provider bundles after activation, the Websocket Endpoint registration fails for a newly created ServerContainer ( WebSocketServerContainerInitializer.configureContext ) within Equinox and Jetty 9.4.15.
If the Bundle-ActivationPolicy could be set to lazy within "org.eclipse.jetty.websocket.javax.websocket.server" then the serviceloader providers (especially javax.websocket.server.ServerEndpointConfig$Configurator ) will be picked up beforehand and the registration works as expected.
The text was updated successfully, but these errors were encountered: