Last week I had an email from Mat Newman passing on a query for a REST servlet plugin. The person was noting that when sending a tell http osgi ss command to the server, the plugin was showing as “<<LAZY>>” and only changed to “<<ACTIVE>>” after the first call, when the code in the Activator runs. This is standard behaviour and as XPages developers move from SSJS to Java and start to gain more experience of Java, lazy loading becomes a natural performance optimisation approach. So a plugin that’s lazy-loaded starts to make a lot of sense.

But I suspected that what might be required was to run code immediately, maybe to preload some cached content into the plugin. I don’t think I’ve blogged about that explicitly before, but it’s something I’d already provided code for in ODA Starter Servlet.

It’s something that’s not as straightforward in an NSF – you can load something into applicationScope, but it’s not straightforward to cache it earlier than the first call. John Dalsgaard has done a lot of work in that area, encountering issues with different ClassLoaders that mean it’s stored in a “different” applicationScope. And once cached, applicationScope gets dumped periodically, which also makes sense to help manage memory.

But pre-caching content is something I’m doing for my session with John Jardin at IBM Think. In terms of running code straightaway, that can be achieved by checking the “Activate this plug-in when one of it’s classes are loaded” checkbox on the plugin.xml.

But, as I found in previous projects, this means the code runs before ODA starts up, so you can’t kick of a Xots task at this point. The alternative approach I use is an HttpService. Steps are:

  1. Add another extension in the plugin.xml, point="com.ibm.commons.Extension", type="com.ibm.xsp.adapter.serviceFactory". This points to a class that extends HttpServiceFactory (which manages one or more HttpService). Here’s the plugin.xml of the ODA Starter Servlet.
  2. The getServices() method of the HttpServiceFactory takes an array of HttpService classes. That’s commented out of the HttpServiceFactory class the ODA Starter Servlet. Note, again this code runs immediately, so before ODA gets initialised, so I can’t schedule a Xots task here.
  3. The HttpService has a static createInstance() method which initialises it. The checkTimeout() method then runs after 30 seconds and thereafter every 30 seconds afterwards. This is where the magic happens. In my real-world examples, like my demo at IBM Think, I use a hasRun variable to know if I should kick it off or not, so this code only runs once. Note, I immediately set hasRun to true, because if there’s a critical issue, there’s no point trying again. And if it takes more than 30 seconds to complete (unlikely with what I’m running), checkTimeout() would get triggered again and run the code again.
  4. This is where the Xots task gets kicked off. In my demo, I’m loading a ConcurrentHashMap of all ToDo database instances (stores) into memory, for easy access. It’s using Xots to run this as a background task, just for convenience and streamlining. There’s then the potential for a call to the REST service before the server has been up for 30 seconds, so before this task has run. So the code is aborting if stores is not null. My getStores() method, through which everything is running to integrate with this map of stores, is also calling loadStores() if stores has not yet been initialised. So I’m covering both bases.

I’m using a ConcurrentHashMap for the demo there aren’t intended to be lost of stores and it’s only intended for dev servers, so there are no memory issues. When you start using this approach on a production application, where the cached data could get larger, you need a more scalable approach. Bear in mind we’re now outside the XPages runtime which has mechanisms for managing memory size, garbage collection and leakage. The challenges and approaches are standard Java development ones. So if I had concerns about the size and memory usage, I’d change it to use Google Guava and a LoadingCache so the size or duration could be managed. Google Guava has documentation about that and the GraphNSF functionality in ODA uses it extensively to manage the entries held in the in-memory graph.

5 thoughts on “Domino REST Service Plugins and Pre-Loading Caches”

  1. For preloading of data I am using a memcached Server. This allows to preload a lot of data, ans is accesible from Java Agents and/or other applications.

    Also it allows to use the whole memory of the server without using resources of the XPages JVM.

    1. That’s very interesting and increases flexibility by having a separate Java server for caching. It looks like memcache isn’t available on Windows, but I see there’s a Docker image. Ehcache seems an alternative option. Stepping beyond proprietary code options like LotusScript and Server-Side JavaScript certainly opens up a lot of options.

  2. Nice one Paul. Love it.

    On the cache side:
    – You can use Redis nicely, it has a Java HashMap drop-in replacement
    – When you on Linux only Aerospike is worth a look
    – When you don’t want to install anything extra: I’d recommend Google’s Guava cache – unless something big changed – it has been available on Domino since VoP 1.0 (I smuggled it in, with the official “IBM approved OpenSource” seal of approval)

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.