Yesterday I blogged introducing where we are with XOTS in OpenNTF Domino API, plus a short example about how to create a tasklet and call it. The example was a bit “hello world” – why would you want to call a tasklet to get the current username, when it’s possible and much easier to do that directly in your XPages code?

But it gave the basics of creating a background tasklet and accessing the outcome immediately. So let’s go further with an example that runs a background tasklet but doesn’t wait for the result. Instead the background tasklet posts the result to sessionScope, ready to be picked up, for example, next time the user accesses the page or is displayed on the top of any page.

The code to call the XOTS tasklet is much simpler, because we just want to kick it off. We don’t want to wait for it to complete. It’s just one line of code:

Xots.getService().submit(new UserOutput(ExtLibUtil.getSessionScope()));

We create a new instance of the UserOutput tasklet and submit it to the service. We’re not interested in the result, so we don’t pass the result to any variable (as you’ll see, there is not result). The only difference here is we’re passing the sessionScope object into the constructor. As I mentioned yesterday, the only annotation currently enabled for tasklets is to denote the session type, so it’s currently just like running back-end code. So we currently need to pass in any other objects from the XPages runtime, like sessionScope, XspContext etc.

Now let’s look at the code for the tasklet class itself:

  1. @Tasklet(session = Tasklet.Session.CLONE)
  2. private static class UserOutput implements Runnable {
  3.   private Map<String, Object> sessScope;
  4.   public UserOutput(Map<String, Object> scopeObj) {
  5.     sessScope = scopeObj;
  6.   }
  7.   public void run() {
  8.     try {
  9.       if (sessScope.containsKey(“javaXotsOutput”)) {
  10.         sessScope.put(“javaXotsOutput”, null);
  11.       }
  12.       StringBuilder sb = new StringBuilder();
  13.       Database currDb = Factory.getSession(SessionType.CURRENT).getCurrentDatabase();
  14.       View states = currDb.getView(“AllStates”);
  15.       View people = currDb.getView(“AllContactsByState”);
  16.       for (Document state : states.getAllDocuments()) {
  17.         String name = state.getItemValueString(“Name”);
  18.         String key = state.getItemValueString(“Key”);
  19.         sb.append(“Processing “ + name + “….<br/>”);
  20.         StringBuilder names = new StringBuilder();
  21.         for (Document doc : people.getAllDocumentsByKey(key, true)) {
  22.           String personName = doc.getItemValueString(“FirstName”) + ” “
  23. + doc.getItemValueString(“LastName”);
  24.           names.append(personName);
  25. names.append(“, “);
  26.         }
  27.         if (names.length() > 2) {
  28.         sb.append(names.substring(0, names.length()2) + “<br/>”);
  29.         } else {
  30.           sb.append(“No names found.<br/>”);
  31.         }
  32.       }
  33.       sessScope.put(“javaXotsOutput”, sb.toString());
  34.     } catch (Throwable t) {
  35.       t.printStackTrace();
  36.     }
  37.   }
  38. }

The first thing to notice is the class extends Runnable instead of Callable. That’s because we don’t care about the result, we just want to run the code. So it has a run() method instead of a call() method, whose return value is void.

The next point to notice is on line 6, the constructor takes that sessionScope object and passes it to a private variable in the class, so we can interact with it from the run() method.

The code in the run() method itself is not rocket science. It clears the sessionScope variable, if it exists. Then it gets the AllStates view in the current database and iterates over it, getting the contacts for each state and building a string with their names. Finally it loads that into sessionScope.

This means when the user clicks the button to trigger the tasklet, they can continue their work with the database. This is a basic example, so when the page is accessed after it completes (not very long, in this example), the list of contacts will be presented. But hopefully it gives an idea of what could be done.

Longer term, the context annotation will allow the developer to define whether the current XSP context should be passed, a “clean” XSP context, or no context. The XOTS code will then automatically instantiate sessionScope etc, as if it was a normal XPages request, and you’ll be able to access them as normal. (Currently I got around this by adding a utility method, getSessionScope, which tries to get the XPages sessionScope, which will work in most code; else gets the current instance of my tasklet (or tasklets), and if they’re not null, gets the relevant sessionScope object; I can then call the same helper method from throughout my application, and a quick Find / Replace allowed me to update all references in my Java code – obviously I don’t have to worry about SSJS code).

3 thoughts on “XOTS: Background and MultiThreaded Tasks the OpenNTF Domino API Way (Part Two)”

  1. Good work and good blog. When is it stable enough to get started with it. The only missing part is the trigger of the tasklet as you described in your previous blog post.
    When that is in place I think it opens a whole bunch of new opportunities

    1. The tasklet code itself is, I believe, stable enough. I’ve used it for a recent project that’s going live, so I have a vested interest in things not gettig broken. Unfortunately at the moment I don’t have enough understanding to write the scheduler code.

  2. Pingback: Access FacesContext in xAgent (in new Thread) - dex page

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.

Scroll to Top