Dynamically registering a WAB

26 views
Skip to first unread message

Andrew Lienhard

unread,
Feb 12, 2023, 5:29:46 PM2/12/23
to OPS4J
I have a WAB in a karaf container that I need to deploy using a context path based on environment variables (k8s helm). Currently its web-ContextPath is hardcoded in a pom.xml, so it's compile-time only which won't work for our deployments. 

I'm wondering if it's possible to register this WAB dynamically as one would a servlet using HttpService and/or pax-web. I've been digging through the documentation and examples but so far I haven't been able to work it out. Is this doable? If so, are there any examples of this? Ultimately, I don't care what form the service takes as long as it can serve static files from a directory.

clip from the pom.xml
      <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <_wab>src/main/webapp</_wab>
                        <Include-Resource>{maven-resources},OSGI-INF/blueprint/blueprint.xml=${project.build.directory}/classes/OSGI-INF/blueprint/blueprint.xml</Include-Resource>
                        <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
                        <Embed-Directory>WEB-INF/lib</Embed-Directory>
                        <Web-ContextPath>/</Web-ContextPath> 
                    </instructions>
                </configuration>
            </plugin> 

Andrew Lienhard

unread,
Feb 12, 2023, 10:49:52 PM2/12/23
to op...@googlegroups.com

This seems to be the most promising approach. Repackage the WAB as a WAR then deploy it at runtime as shown below. The URL parameters will assist the OSGI Web URL Handler in automagically producing a WAB + MANIFEST.MF with the correct web-contextpath header. Only I need to do it using the bundleContext.installBundle(String location) API instead of in the console. I also need to sort out the URL of the built war itself. Does this sound correct?

 

karaf@root()> bundle:install -s "webbundle:http://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/sample.war?Bundle-SymbolicName=tomcat-sample&Web-ContextPath=/sample"

 

From <https://karaf.apache.org/manual/latest/webcontainer>

https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.war.html#i3100445




 


--
--
------------------
OPS4J - http://www.ops4j.org - op...@googlegroups.com

---
You received this message because you are subscribed to the Google Groups "OPS4J" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ops4j+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ops4j/2e75aacf-be77-4753-a05c-126df2b7f487n%40googlegroups.com.

Grzegorz Grzybek

unread,
Feb 13, 2023, 1:58:58 AM2/13/23
to op...@googlegroups.com
Hello

If you need only static resources, maybe you should simply register Whiteboard-based resources? Something like this:

register a context to "get" a context path:

Dictionary<String, Object> properties = new Hashtable<>();
properties.put("osgi.http.whiteboard.context.name", "my-context");
properties.put("osgi.http.whiteboard.context.path", "/sample");

ServiceRegistration<ServletContextHelper> reg = context.registerService(ServletContextHelper.class, new ServletContextHelper() {}, properties);

register resources into this context path:

Dictionary<String, Object> properties = new Hashtable<>();
properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN, new String[] { "/static/*" });
properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX, "/resources");
properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, String.format("(%s=my-context)",
HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME));

ServiceRegistration<Object> resReg = context.registerService(Object.class, new Object(), properties);

Then you'll be able to get resources from bundle's "/resources" directory using URI's like "/sample/static/*"

But sure - your WAR approach should work too.

regards
Grzegorz Grzybek

Andrew Lienhard

unread,
Feb 13, 2023, 8:54:08 PM2/13/23
to op...@googlegroups.com
Hi. Thanks for taking the time to respond. I managed to get it working using the API example you provided. I had a problem with the context aspect though so I just mapped the path of the resources to include what would have been the new context path. It looks like it always runs under the default "/" context setup in the unomi wab. In the end, I just needed the path, not anything specific to a servlet context since it's just a static website.

I'm including some logs/code to show the issue with attaching the context, if you have any ideas. But the good news is that I was able to get the path stuff sorted out for the static files by simply not using it.

Code:

private static final String MY_CONTEXT_NAME = "my-context";

 /**
   * Registers a custom web context for use with this endpoint.
   *
   * @param context
   */
  private void registerCustomContext(BundleContext context) {
    Dictionary<String, String> contextProps = new Hashtable<>();
    contextProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME,  MY_CONTEXT_NAME);
    contextProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH,  "/test"  );
    context.registerService(ServletContextHelper.class, new  ServletContextHelper () {}, contextProps);
    log.info("ContextInitializer registered a new context {}", contextProps);
  }

  /**
   * Registers a static resource service.
   *
   * @param context
   */
  private void registerCustomResource(BundleContext context) {
    Dictionary<String, Object> resourceProps = new Hashtable<>();
    resourceProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN, new String[] {"/static/*"});
    resourceProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX, "/webapp/files");
    resourceProps.put(
        HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT,
        String.format("(%s=%s)", HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME,  MY_CONTEXT_NAME   ));

    context.registerService(Object.class, new Object(), resourceProps);
    log.info("ContextInitializer registered a new resource {}", resourceProps);
  }

  // blueprint.xml init-method="initConfig"
  public void initConfig() {
    BundleContext bundleContext = FrameworkUtil.getBundle(ContextInitializer.class).getBundleContext();
    this.registerCustomContext(bundleContext);
    this.registerCustomResource(bundleContext);
  }

Custom context: /test
Resource mapping: /static/* -> /webapp/files
Request: /test/static/hello.txt

Logs:

          | 2023-02-13T21:15:08,785 | DEBUG | qtp707116334-265 | ServerModel                      | 251 - org.ops4j.pax.web.pax-web-spi - 7.2.14 | Matching [/test/static/hello.txt]...
          | 2023-02-13T21:15:08,785 | DEBUG | qtp707116334-265 | ServerModel                      | 251 - org.ops4j.pax.web.pax-web-spi - 7.2.14 | Path [ /test/static/hello.txt] does not match any context
          | 2023-02-13T21:15:08,785 | DEBUG | qtp707116334-265 | HttpServiceContext               | 248 - org.ops4j.pax.web.pax-web-jetty - 7.2.14 | Handling request for [ /test/static/hello.txt] using http context [DefaultHttpContext [bundle=org.apache.cxf.cxf-rt-transports-http [112], contextID=default]]
         | 2023-02-13T21:15:08,785 | DEBUG | qtp707116334-265 | HttpServiceServletHandler        | 248 - org.ops4j.pax.web.pax-web-jetty - 7.2.14 | handling request org.ops4j.pax.web.service.jetty.internal.HttpServiceRequestWrapper@3d9340e9, org.ops4j.pax.web.service.jetty.internal.HttpServiceResponseWrapper@6f53a229
         | 2023-02-13T21:15:08,786 | DEBUG | qtp707116334-265 | DefaultHttpContext               | 250 - org.ops4j.pax.web.pax-web-runtime - 7.2.14 | Searching bundle [org.apache.cxf.cxf-rt-transports-http [112]] for resource [ test/static/hello.txt]

In the system console (Felix) I see the  ServletContextHelper and the resource registered accordingly

[org.osgi.service.http.context.ServletContextHelper]
osgi.http.whiteboard.context.namemy-context
osgi.http.whiteboard.context.path/test
service.bundleid56
service.scopesingleton


[Object]
osgi.http.whiteboard.context.select(osgi.http.whiteboard.context.name=my-context)
osgi.http.whiteboard.resource.pattern/static/*
osgi.http.whiteboard.resource.prefix/webapp/files
service.bundleid56
service.scopesingleton
Using Bundlesorg.ops4j.pax.web.pax-web-extender-whiteboard (247)


Grzegorz Grzybek

unread,
Feb 14, 2023, 1:40:37 AM2/14/23
to op...@googlegroups.com
Hello

Somehow I thought you're using Pax Web 8 which actually has working context selection. Problems with context registration/selection were the MAIN reason I started refactoring of Pax Web 7 into Pax Web 8.

Your example is _canonical_ example of Whiteboard usage and should work perfectly fine with Pax Web 8 (included in Karaf 4.4.3).

regards
Grzegorz Grzybek

Reply all
Reply to author
Forward
0 new messages