Developing Jakarta Apps Via NSF File Server, Take 2

Sun Jun 21 15:18:48 EDT 2026

Just about a year ago today, I posted about some tinkering I was doing with the then-new support in the NSF File Server for live modifying the files in the virtual "WebContent" folder of an NSF.

Early Tinkering

With that post, I was going the route of developing a project with Maven and then SCP'ing up the build results. That worked for an initial push, but had some big caveats. For one, it took deploying the entire app with every change. The other, bigger problem was that it wouldn't delete files that were no longer part of the app, so old pages and classes would float around until you went in and deleted them.

If you're using a normal SFTP server, you would solve a lot of that with rsync (or could, until it started getting gunked up), but that would be a difficult thing to implement with the virtual filesystem I'm using in the server project.

I also looked a bit into using SSHFS via macFUSE, but hit some trouble where stored files would be truncated by a few bytes. It's possible that this has been fixed, and it could be worth another look, but it put me off of the idea.

File Providers

A couple weeks ago, I decided to look into it again, and found an interesting tack I hadn't thought about: apps using the Mac File Provider API, which is something designed for Dropbox-type apps. While a little indirect compared to mounting the SFTP endpoint via macFUSE, it actually has a nice advantage in that the files actually exist in the local filesystem, making it a bit more resilient to hiccups (hopefully).

There are a number of apps that do this. Panic's Transmit (my FTP client of choice for a long time) is adding this in version 6, but it seems like it's not quite solid yet. For now, I've been using Mountain Duck, which has been working really well. I may switch to Transmit when it settles, but I don't have any complaints about Mountain Duck so far.

Live Projects

Having these files sitting on the filesystem also made me think of another approach for working on the app: rather than building the project with Maven and then copying the build results up, I could work with it a bit more "live", similar to how Designer does it.

To do this, I've cobbled together a couple of old Eclipse techniques that I wouldn't normally use, but do the job here. I made just a plain old Java project in Eclipse and then dragged the root of the app from the now-filesystem-present app to the project to make a linked folder:

Screenshot of the process of linking a filesystem folder to a project in Eclipse

Then, in the project properties, I added a Source folder to the build path for the WEB-INF/src directory within the mapped WebContent folder ("Code/Java"-type Java files won't work with this share type, for reasons I may get in to later) and mapped its output to WEB-INF/classes:

Screenshot of the Java Build Path for my live-edit project

This added the Java source files from the NSF to my Eclipse project, but it had trouble building them: it had no idea about the project's dependencies. For the next step, I got a little hackier: I went to the "Project Natures" section of the project properties and explicitly added "Plug-in Development". As this page in the dialog warns you, you don't normally want to go about adding natures explicitly: other tools should normally do that for you. Here, though, it's fine.

Screenshot of Eclipse's Project Natures page

Then, I went into the app in Designer and copied the contents of the META-INF/MANIFEST.MF file from the Project Explorer pane and made a file at the top of my Eclipse project (which will not be synced to the NSF):

Screenshot of some of the project in Eclipse, showing MANIFEST.MF

With that in place, Eclipse will resolve dependencies from OSGi plugins in the same way as Designer does, so I just need to make sure they're in my Target Platform for the workspace.

While mucking around in there, I also enabled the Project Facets from the Web Tools Platform, though admittedly that doesn't buy me too much yet.

Anyway, with all this set, now I have a local Eclipse project that is a live representation of the project on the server (Designer on the left, Eclipse on the right):

Screenshot of Designer and Eclipse's views of the same NSF

What This Is Good For

For a specific type of app, this is wonderful. The main specific type of app that it's good for is what I'm using for this demonstration: apps like the new OpenNTF home app that are pureblood Jakarta applications. Other than a view or form here and there, pretty much all of the development of this app takes place in Java classes or WebContent resources like CSS, JS, and JSP. These files have natural filesystem representations and work perfectly when synced over SFTP.

I'm deriving a lot of benefits out of this. For one, I can use the Mac version of Eclipse, which is just inherently nicer than using a Windows app via RDP like I normally do (I could also use other tools, but I actually just like Eclipse). Additionally, unlike Designer, this is current Eclipse - specifically, the 2026-06 release that came out just this month. So, with this in place, I can work on a live NSF app the same way I do the various other Java projects I work on:

Screenshot of Eclipse working with an NSF-based web project

Beyond IDEs, this would also let me seamlessly use other tools like image editors or fancier CSS editors without any extra hurdles.

Even if you're not using JSP or JSF in NSFs, you could do this when writing Jakarta REST services and have a good experience. You could also presumably do this if you're writing REST services mounted in an XPage you make in Designer but then implemented in Java, but eh. It'd be better to switch to Jakarta REST in that case regardless.

This would also work pretty well if you're developing client JS apps or static HTML files, like a static blogging system. With complex JS projects, you'll probably want one of the toolchains that has browser integrations and auto-reload, but this still isn't bad and could be good if you want to write against live REST services.

Where This Falls Short

All that said, this is still a pretty limited-use tool. As I mentioned above, this is specifically for files in the WebContent virtual folder, and that rules out all of traditional Notes development and almost all XPages work. I've considered for a while making a filesystem type in the NSF File Server project that represents the rest of the NSF virtual filesystem in the way Designer does, but there are a lot of fiddly little details to doing that, particularly when also allowing for live editing of it. Just off the top of my head:

  • What happens when editing a DXL-type element like a view and you save invalid DXL? I guess there'd be an error, but how would that show up for the user across the SFTP client?
  • What about elements that are both file data and metadata, like image resources? I guess the .metadata file should be created automatically when missing, but it's weird to have "filesystem" operations with side effects.
  • Though presented similarly in Designer, Java in Code/Java is actually stored differently from custom source folders like WebContent/WEB-INF/src. While the latter are stored "filesystem-like" where the .java and .class files are separate notes, Code/Java notes store both the source and bytecode. This includes edge-case things like inner classes in separate class data items. This is not an insurmountable issue, but then that means that the server side starts to have to make all sorts of assumptions on the fly about incoming data beyond simple file operations.
  • XPages have those same problems and require executing proprietary code during the build process. While this is not an impossible task, it's a new hurdle on the client side that would need handling.

It'd be kind of neat if that was all implemented, but it'd be a lot of fiddly work to do and with really diminishing rewards. It'd just be more practical to use Nomad Designer for editing forms and views as needed for that part and then stick with normal Designer while you're still doing XPages. Never say never, I suppose.

New Release: XPages Jakarta EE 3.7.0

Sat Jun 20 12:16:24 EDT 2026

Tags: jakartaee

Yesterday, I released version 3.7.0 of the XPages JEE project, which is another incremental release that improves a number of things for the apps I've been making with it, as well as just generally bumping implementation versions to keep up to date.

gzip Support

I added implicit gzip compression for REST services (when the result content type is text/*, JSON, or XML) and for similarly-identified static resources when using Jakarta Modules. This is always a nice to have, and it had been on my list for a while. Keeps things nice and zippy without (hopefully) imposing any problems on the developer.

Welcome Pages

In the previous version, I added some basic support for welcome-file-list in web.xml for Jakarta Modules, letting you specify a static page or Servlet/JSP/JSF as the base landing page for your app. Admittedly, I don't use this much, as my new apps tend to be MVC-based and use a REST endpoint as the root, but it's nice for JSF apps or when you use a client-JS-based UI.

Anyway, when I implemented this, what I didn't do was read the spec (shame on me), and so I didn't implement it for subdirectories beyond just the app root. That's in there now, though, so it should be up to code for apps designed that way.

MIME Mapping

On a similar note, my quest to make Jakarta Module apps more "real WAR-y", I added support for specifying file-extension-to-MIME rules in web.xml in mime-mapping elements. The code will first consult your File Resource for a per-file MIME type, then check this list, and then finally fall back to a routine that tries to guess the file type by name. Usually, the last is what you'll want, but this is handy for new types not supported by the stock discovery scheme.

NoSQL Improvements

As usual, I found another spate of things I wanted to improve in the Data/NoSQL driver side.

One of these is that I improved the implicit behavior of using base Jakarta Data and NoSQL classes/annotations. This means that you can specify a repository using just the built-in CrudRepository type and either stock methods or annotated ones without using any Domino-specific code. For performance or capability needs, you'll usually want to use some Domino-specific code somewhere (say, to mark things as Reader fields), but it's always nice when you can make code that's completely portable without changes.

But back to Domino-isms, I added a couple more things. For one, when you use a NoSQLConfigurationBean in your app, you can now dynamically decide whether the DQL engine should be told to refresh views and FT indexes as it goes. While this may slow things down slightly (I assume it's smart about it internally when no work needs to be done), it's important for cases where you're creating new documents and then immediately doing DQL calls that find those documents view index views.

I also added support for specifying items as being stored as User Data (called "custom data" in Notes.jar). I imagine this isn't very common, but it comes up sometimes. Specifically, I did it because I want my NSF Maven Repository projects to be able to read and write custom file attributes in the same was as the NSF File Server project does. That one uses User Data because attributes are provided as byte arrays, and that's a clean match. In NoSQL entities, you can do this with String, byte[], ByteBuffer, and any type that implements Serializable. For large objects, using "MIMEBean" storage is your way to go, but maybe this will be handy for other people.

New Small Project: NSF Maven Repository

Thu Jun 11 13:39:13 EDT 2026

When you're developing with Maven, most of your dependencies will come from Maven Central, but there are plenty of reasons why you might want to run your own repository. That could be because you have proprietary components that you don't want publicly accessible or because it makes some organizational sense to host artifacts in your own environment outside of Central.

There are a couple projects that are commonly used for this purpose. Nexus and Artifactory are the big ones, and there used to be a decent truly-open option in Apache Archiva. For a good while, I've used Artifactory primarily, and it does fine, but it's always a bit of a hassle to have a separate server running just for this purpose. It's one more thing to manage, to update, and to troubleshoot when something goes awry.

The Maven repository format is really pretty simple, though, basically a file tree with XML files at each level to describe the children, followed by the actual JAR files and other artifacts. For example, a deployment of Domino's redistributable NCSO API JAR might look like this:

Screenshot of a deployed artifact in Maven

The base "protocol" as such used by the Maven Deploy Plugin is similarly simple, consisting of a handful of GETs to expected metadata files followed by PUT calls to create or update the appropriate files. The plugin will do the stitching of the metadata XML files together itself, as it will if you deploy to a local repository.

In practice, repository servers like Artifactory tend to add a lot on top of this: limiting the number of snapshots per version, enforcing role-based access, proxying artifacts from upstream, and so forth. However, those features aren't strictly required for a basic repository to work.

Anyway, as I often do, I decided to take a swing at solving this in an NSF. Since my needs are low - it's usually just me or maybe another person or two publishing to a repository - I don't need to add many of the features on top. Plus, some of it is taken care of for me: if the repository is in an NSF, there's implicit authentication and authorization support via Domino's HTTP auth and the database's ACL.

Thus, yesterday, I uploaded a new project: the NSF Maven Repository. It's in an early state currently, but it should be usable for basic needs. While I don't want to add all of the usual bells and whistles, I expect I'll want to at least cap the number of snapshots per version, and there are a couple other potential management features to add.

Since I get to piggyback on the XPages JEE project, the bulk of the code is in a single REST API class, which assumes good-faith use from an authenticated client. Then, the "filesystem" structure is done via a pair of NoSQL entity classes, which mostly contain path data and, in the case of RepositoryFile, the actual attachment.

While I was at it, I made the file structure compatible with the NSF File Server project, so the NSF can be used as a data store in there. Indeed, the screenshot above is from Panic's Transmit, listing the contents of the repository over SFTP.

I'm pleased with it in this basic state, and will probably polish it a bit and put it to use. In particular, I expect I'll replace OpenNTF's Artifactory server with this, since that will cut down on an entire server to run. I'll also be able to use it in internal proprietary cases, where otherwise I've historically run Archiva. In the mean time, if you have a need for this kind of thing, give it a look.