OSGI: Issues when deploying a webapp using WebAppContext
Jetty version(s) Migrating from Jetty version 10.0.6 to 12.0.3
Jetty Environment ee8
Java version/vendor (use: java -version)
17
OS type/version Windows
Description Background I'm trying to migrate some legacy code from Jetty 10 to Jetty 12. I want to deploy a webapp using the WebAppContext class as shown in your example: https://github.com/jetty/jetty.project/blob/jetty-10.0.6/jetty-osgi/test-jetty-osgi-webapp/src/main/java/com/acme/osgi/Activator.java This example is missing in Jetty version 12.0.3: https://github.com/jetty/jetty.project/tree/jetty-12.0.3/jetty-ee8/jetty-ee8-osgi
Unfortunately, after migrating the code to Jetty 12 with EE8 the code can be compiled but does not run anymore.
I am getting the following exception:
java.lang.NullPointerException: Cannot invoke "org.eclipse.jetty.ee8.webapp.WebAppContext.toString()" because the return value of "org.eclipse.jetty.ee8.webapp.WebAppContext.getCurrentWebAppContext()" is null
Could you provide me an example how this works with Jetty 12, EE8?
The Jetty ee8 tree is derived from the ee9 tree at build time. There's little to no code checked into the ee8 tree. It's mostly metadata, build details, dependencies, etc...
Start by looking at the ee9 tree for examples. Pretty much everything you see in the ee9 tree is converted to ee8.
For example: https://github.com/jetty/jetty.project/blob/jetty-12.0.x/jetty-ee9/jetty-ee9-osgi/test-jetty-ee9-osgi-server/src/main/java/com/acme/osgi/Activator.java That is Activator for both ee9 and ee8.
Also, please pay attention to the META-INF/MANIFEST.MF bundle details with regards to the environment.
https://github.com/jetty/jetty.project/blob/2584eb0429c3de1b05722337f3787859c9551eff/jetty-ee9/jetty-ee9-demos/jetty-ee9-demo-spec/jetty-ee9-demo-spec-webapp/pom.xml#L85-L105
Such as <Jetty-Environment> and <Jetty-ContextFilePath> entries.
The context file contents/syntax is also using the new namespaces.
https://github.com/jetty/jetty.project/blob/jetty-12.0.x/jetty-ee9/jetty-ee9-demos/jetty-ee9-demo-spec/jetty-ee9-demo-spec-webapp/src/main/templates/plugin-context.xml
@jkoch70 a full stack trace on that exception would be nice.
Sure, here it is:
java.lang.NullPointerException: Cannot invoke "org.eclipse.jetty.ee8.webapp.WebAppContext.toString()" because the return value of "org.eclipse.jetty.ee8.webapp.WebAppContext.getCurrentWebAppContext()" is null
at com.csc.dip.styler.oc.gen.ui.OmnichannelStylerGenerator$OmnichannelWebAppTracker.addingService(OmnichannelStylerGenerator.java:83)
at com.csc.dip.styler.oc.gen.ui.OmnichannelStylerGenerator$OmnichannelWebAppTracker.addingService(OmnichannelStylerGenerator.java:1)
at org.osgi.util.tracker.ServiceTracker$Tracked.customizerAdding(ServiceTracker.java:947)
at org.osgi.util.tracker.ServiceTracker$Tracked.customizerAdding(ServiceTracker.java:1)
at org.osgi.util.tracker.AbstractTracked.trackAdding(AbstractTracked.java:258)
at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:231)
at org.osgi.util.tracker.ServiceTracker$Tracked.serviceChanged(ServiceTracker.java:907)
at org.eclipse.osgi.internal.serviceregistry.FilteredServiceListener.serviceChanged(FilteredServiceListener.java:123)
at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:961)
at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:234)
at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:151)
at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEventPrivileged(ServiceRegistry.java:945)
at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEvent(ServiceRegistry.java:882)
at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.register(ServiceRegistrationImpl.java:144)
at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.registerService(ServiceRegistry.java:270)
at org.eclipse.osgi.internal.framework.BundleContextImpl.registerService(BundleContextImpl.java:500)
at org.eclipse.osgi.internal.framework.BundleContextImpl.registerService(BundleContextImpl.java:519)
at org.eclipse.osgi.internal.framework.BundleContextImpl.registerService(BundleContextImpl.java:1047)
at com.csc.dip.styler.jetty.StylerWebAppDeployer.deployWebApp(StylerWebAppDeployer.java:81)
at com.csc.dip.styler.oc.gen.ui.OmnichannelStylerGenerator.deployToJetty(OmnichannelStylerGenerator.java:397)
at com.csc.dip.styler.oc.gen.ui.OmnichannelStylerGenerator.generate(OmnichannelStylerGenerator.java:221)
at com.csc.dip.styler.gen.ui.AbstractGeneratorStarter.doStartStylerGeneration(AbstractGeneratorStarter.java:161)
at com.csc.dip.styler.gen.ui.GeneratorStarterWithUI$1.execute(GeneratorStarterWithUI.java:43)
at org.eclipse.ui.actions.WorkspaceModifyOperation.lambda$0(WorkspaceModifyOperation.java:110)
at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2453)
at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2478)
at org.eclipse.ui.actions.WorkspaceModifyOperation.run(WorkspaceModifyOperation.java:131)
at org.eclipse.jface.operation.ModalContext.runInCurrentThread(ModalContext.java:436)
at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:352)
at org.eclipse.jface.dialogs.ProgressMonitorDialog.run(ProgressMonitorDialog.java:470)
at com.csc.dip.styler.gen.ui.GeneratorStarterWithUI.execute(GeneratorStarterWithUI.java:31)
at com.csc.dip.styler.gen.ui.GeneratorRegistryImpl.consume(GeneratorRegistryImpl.java:23)
at com.csc.dip.styler.core.model.data.service.impl.StylerDocumentProviderImpl.provide(StylerDocumentProviderImpl.java:52)
at com.csc.dip.styler.ui.model.editor.editor.handlers.GeneratorHandler.execute(GeneratorHandler.java:41)
at org.eclipse.ui.internal.handlers.HandlerProxy.execute(HandlerProxy.java:283)
at org.eclipse.ui.internal.handlers.E4HandlerProxy.execute(E4HandlerProxy.java:99)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:58)
at org.eclipse.e4.core.internal.di.InjectorImpl.invokeUsingClass(InjectorImpl.java:298)
at org.eclipse.e4.core.internal.di.InjectorImpl.invoke(InjectorImpl.java:232)
at org.eclipse.e4.core.contexts.ContextInjectionFactory.invoke(ContextInjectionFactory.java:174)
at org.eclipse.e4.core.commands.internal.HandlerServiceHandler.execute(HandlerServiceHandler.java:165)
at org.eclipse.core.commands.Command.executeWithChecks(Command.java:488)
at org.eclipse.core.commands.ParameterizedCommand.executeWithChecks(ParameterizedCommand.java:485)
at org.eclipse.e4.core.commands.internal.HandlerServiceImpl.executeHandler(HandlerServiceImpl.java:213)
at org.eclipse.e4.ui.workbench.renderers.swt.HandledContributionItem.executeItem(HandledContributionItem.java:438)
at org.eclipse.e4.ui.workbench.renderers.swt.AbstractContributionItem.handleWidgetSelection(AbstractContributionItem.java:449)
at org.eclipse.e4.ui.workbench.renderers.swt.AbstractContributionItem.lambda$2(AbstractContributionItem.java:475)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4273)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1066)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:4071)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3659)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1155)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:342)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1046)
at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:155)
at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:648)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:342)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:555)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:173)
at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:152)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:208)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:136)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:402)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:255)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:651)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:588)
at org.eclipse.equinox.launcher.Main.run(Main.java:1459)
at org.eclipse.equinox.launcher.Main.main(Main.java:1432)
Are you able to deploy a simple static web app like suggested in the 10.x documentation in Jetty 12.x? That is exactly what we want to do. We have a Javascript web app and want to deploy it with a context path and a resource path (location of the web app on disk).
//Create a second webappB as a Service and target it at a custom Server
//deployed by another bundle
final WebAppContext webappB = new WebAppContext();
Dictionary propsB = new Hashtable();
propsB.put("Jetty-WarResourcePath", "webappB");
propsB.put("Web-ContextPath", "/acme");
propsB.put("managedServerName", "fooServer");
_srB = context.registerService(WebAppContext.class.getName(), webappB, propsB);
You're going to need the Jetty-Environment property defined to ee8 too.
Yes, sure, I have it. My dictionary looks like this:
dic.put(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH, contextPath);
dic.put(OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH, location);
dic.put("managedServerName", "defaultJettyServer");
dic.put(OSGiWebappConstants.JETTY_ENVIRONMENT, "ee8");
As this doesn't work, my question would be if you are able to deploy a simple web app on your end with Jetty 12.x?
@jkoch70 so I think I removed the ability to deploy webapps as services, and only supported their deployment as bundles in jetty-12. Is there any way you can port to deploying as a bundle instead of a service?
Will you re-add the ability to deploy webapps as services in a later release of Jetty again?
Our Eclipse application generates web applications and deploys them on the fly to Jetty to show them in a browser. On the fly means in this case, during the lifecycle of a running Jetty instance in an Eclipse based application. So, our requirements for a workaround would be to
- deploy a webapp with a "Web-ContextPath" and a "Jetty-WarResourcePath" on the fly (both are unknown at Jetty startup)
- remove a former deployed webapp on the fly
- redeploy a webapp with an updated "Web-ContextPath" or "Jetty-WarResourcePath" on the fly (this may be superfluous if the former two work in combination in that way)
Would you be able to provide us an example how we can deploy a webapp as a bundle programmatically on the fly?
@jkoch70 I'll take a look at restoring deployment of webapps as a service, but it might take me some time.
In the meanwhile, what I have used to build and deploy bundles on the fly is TinyBundles: https://github.com/ops4j/org.ops4j.pax.tinybundles
Here's some code I use in some jetty osgi tests:
TinyBundle bundle = TinyBundles.bundle();
bundle.add(SomeCustomBean.class);
bundle.set(Constants.BUNDLE_SYMBOLICNAME, TEST_JETTY_HOME_BUNDLE);
File etcFolder = new File("src/test/config/etc");
bundle.add("jettyhome/etc/jetty-http-boot-with-bundle.xml", new FileInputStream(new File(etcFolder, "jetty-http-boot-with-bundle.xml")));
bundle.add("jettyhome/etc/jetty-with-custom-class.xml", new FileInputStream(new File(etcFolder, "jetty-with-custom-class.xml")));
Then I believe you could deploy it with something along the lines of:
BundleContext bundleContext = ..... ;
bundleContext.installBundle(url, bundle.build());
where you'd need to obtain a BundleContext (maybe from the current class?) and the url param is some identifier for the bundle. The TinyBundles site has some more examples that may be helpful.
@jkoch70 were you able to give the TinyBundles approach a go?
No, we haven't tried it, so far.