Developing Jakarta Apps Via NSF File Server
Wed Jun 25 16:42:37 EDT 2025
In my previous post, I made an offhanded comment towards the end about how the tool was really for static files and, while it'd be technically possible to deploy Java code this way, it'd be awkward and weird.
But that got me thinking: just how awkward and weird are we talking here? So I set out to trying to see. An app that is all-in on Jakarta EE is basically a normal old webapp housed in an NSF, and the structure of the "WebContent" directory is the same as a WAR: visible files go in the top level, JARs go in "WEB-INF/lib", and compiled classes go in "WEB-INF/classes". Normally, the Code/Java design notes in an NSF are those compiled class files, doing double duty to hold the source and the bytecode in the same note, but that's not the only way. If you have a file resource that calls itself "WEB-INF/classes/foo/Bar.class", it'll count as a class in the app. This is how the pre-8.5.3 method of adding Java classes worked: Designer would make one file resource for the source file and another for the bytecode.
Trying It Out
So, since a running app doesn't care about the source, in theory the presence of just the .class files in the right place should suffice for deploying an app. I decided to put the theory to the test and, lo and behold, it worked:

Those are the classes from the Jakarta EE starter project, which gives you a Maven project with a JAX-RS resource that emits JSON. The XPages JEE project creates an environment pretty comparable to a normal Jakarta EE server, so the compiled classes work just the same when copied around.
So far, so good, but what about a more-complicated example? A real app will have non-class Java resources (translation properties files, for example), web resource files (HTML, CSS, JS), and dependency JARs. So I added commonmark
as a dependency to my project via Maven and built the project. I found that, with a Maven project, the entire structure of your result WAR is present in "target/your-artifact-id", and thus I switched to copying that up:

This actually scratches an itch I've had for a long time: I've considered the notion of having a mode in the NSF ODP Tooling project that takes a WAR and makes an NSF out of it in this format. As it turns out, the result of that would be the same as this, and this allows for faster iteration on testing changes.
Some Caveats
One major limitation not so much of the tools but of the underlying protocol is that "recursive delete" isn't inherently a thing in SFTP, but it's necessary to make sure that any files from an old build not in new builds (renamed classes, etc.) are deleted when deploying a new version. Since rsync would take a lot of work, I've been looking at lftp
, which may fill the gap, but it'll take some fiddling. Dedicated file-transfer GUI tools like Transmit could help too.
Additionally, while it's possible to create a compatible classpath in a Maven project by including the core JEE APIs and some Domino-specific things like the NoSQL driver as dependencies, this route wouldn't help you for things like creating or modifying views. Those don't change as frequently as app code, though, so it'd probably be fine to have Designer (or Nomad Designer) around for that task in much the same way as one might use a database management app in other environments.
It's also a longer cycle between making a change and seeing it than when using Designer, since you'd have to make sure to do a local build and then copy the files up, which will scale in time with the complexity of your project. That may be a fair price to pay to have your choice of IDEs and the ability to use Maven for dependencies and processing, though.
Anyway, this is all pretty neat. I've really gotten into a good groove of app dev with the JEE project lately, but I won't pretend I wouldn't mind a nicer development environment. I think I'll have to try using this for some of my projects for a bit to find out if it'll work in general.