Quick Tip: Deploying Static Resources As A Webapp
Sun Jun 29 13:38:14 EDT 2025
The other day, I had occasion to deploy a newer Dojo version to Domino than what was present - a later version fixed some layout problems in a chart, but the client isn't ready to update to Domino 14.5. Since this wasn't an XPages app, I didn't need to worry about incompatibilities or the XPages-specific extensions, but there was still the matter of getting Dojo's giant file tree served up by Domino.
Normally, this isn't a big deal - a JavaScript library can usually be plunked in to the NSF without issue. But Dojo's tree is still big enough that it will break the DB's design. I could probably fix that by pruning the directory, but I didn't want to spend that much time on the task. It'd also have the disadvantage that Domino would complain about any "?" URLs that don't start with "?Open", which is a drag.
The next option is to copy the files to the data/domino/html directory. That would work, but it kind of sucks: now you have files not represented in NSFs, and one more thing for admins to keep track of and for developers to forget. So that's an option of last resort.
Another approach I've taken in the past is to make an OSGi plugin that contributes an ExtLibLoaderExtension
. That lets your plugin contribute resources to the ExtLib's own resource provider. The big advantage here is that, if you write your code right, they can participate in the minifier. However, since this isn't an XPages app, that won't realistically do me any good, and it'd also involve writing some fiddly custom code that we'd have to know about forever.
Wrapper App
But then I came up with another route: I could make a tiny little web app using the com.ibm.pvc.webcontainer.application
extension point solely to host these files. Normally, you'd use that point to make a complicated (ancient) Java EE web app, but this use doesn't even involve any Java code. I made mine in Maven, but even that is technically optional: the result just has to be a JAR (which is a ZIP file) with a couple files in it, plus whatever resources you want to serve. I'll use it here, though, since it takes care of some fiddly bits for us.
First up, you should have a "src/main/resources/plugin.xml" file with contents like:
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="UTF-8"?> <?eclipse version="3.4"?> <plugin> <extension point="com.ibm.pvc.webcontainer.application"> <contextRoot>/dojo-1.17.3</contextRoot> <contentLocation>WebContent</contentLocation> </extension> </plugin> |
Here, "/dojo-1.17.3" is the path on the web server it'll be accessible as, while "WebContent" is where we'll be storing the files within our JAR.
Next up, we want a file named "src/main/resources/WebContent/WEB-INF/web.xml". This would normally list Servlets and other configuration for the web app, but we don't have any of that - it's just here as a stub:
1 2 3 4 | <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> </web-app> |
Then, put any files you want to serve up in "src/main/resources/WebContent". We don't need to configure anything else to point at these, so they can be anything. Here, I put the "dojo", "dijit", and "dojox" directories there:

Finally, we'll have the "pom.xml" file at the root of our project to tell it how to build. This has a couple custom steps to the build, but mostly it could be copy-and-pasted into your own project, just changing the groupId, artifactId, and name to suit your needs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>com.example.dojo</artifactId> <version>1.17.3</version> <name>Dojo Assets Wrapper</name> <packaging>bundle</packaging> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.release>8</maven.compiler.release> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <osgi.qualifier>${maven.build.timestamp}</osgi.qualifier> </properties> <repositories> <repository> <id>artifactory.openntf.org</id> <name>artifactory.openntf.org</name> <url>https://artifactory.openntf.org/openntf</url> </repository> </repositories> <build> <plugins> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>5.1.2</version> <extensions>true</extensions> <configuration> <excludeDependencies>false</excludeDependencies> <instructions> <Bundle-SymbolicName>${project.artifactId};singleton:=true</Bundle-SymbolicName> <Automatic-Module-Name>${project.artifactId}</Automatic-Module-Name> <Export-Package /> <Require-Bundle /> <Import-Package /> <Bundle-RequiredExecutionEnvironment>JavaSE-1.8</Bundle-RequiredExecutionEnvironment> </instructions> </configuration> </plugin> <plugin> <groupId>org.openntf.maven</groupId> <artifactId>p2-maven-plugin</artifactId> <version>2.2.0</version> <executions> <execution> <id>generate-site</id> <phase>install</phase> <goals> <goal>site</goal> </goals> <configuration> <featureDefinitions> <feature> <id>${project.artifactId}.feature</id> <version>${project.version}</version> <label>${project.name}</label> <providerName>${project.groupId}</providerName> <description>${project.name}</description> <artifacts> <artifact> <id>${project.groupId}:${project.artifactId}:${project.version}</id> <transitive>false</transitive> </artifact> </artifacts> </feature> </featureDefinitions> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.darwino</groupId> <artifactId>p2sitexml-maven-plugin</artifactId> <version>1.2.0</version> <executions> <execution> <phase>install</phase> <goals> <goal>generate-site-xml</goal> </goals> <configuration> <category>${project.name}</category> </configuration> </execution> </executions> </plugin> </plugins> </build> </project> |
Once you do a mvn install
for that, you'll end up with a repository in "target/repository" with a "site.xml" file suitable for importing into an update site NSF.
This need doesn't come up too frequently, since it's rare that I have to deploy this many files at once, but I'm pleased with this technique. That update site can be replicated around, and the presence of it in the notes.ini means that it's much more self-documenting than dropping the files on the filesystem. Plus, the fact that involves no custom executable code or weird Domino dependencies makes it very portable to build anywhere. It's something for me to keep in my back pocket for the future.