Steps to integrate ODA with DOTS environment

The first part of the article is now outdated because a DOTS compatible ODA version has been released since (Non-XSP).

Once you start using ODA going back to dealing with object recycling isn’t an option – in other words you are pretty much spoiled for life.

Problem is, ODA isn’t automatically supporting all the environments where Domino Java code can be deployed. One of those unsupported environments is DOTS. For this reason I would like to document some basic wiring that can be done to make ODA usable under DOTS.

This post expands on what I had already wrote here.

ODA plugin composition considerations

ODA is organized in different plugins that fall under one single feature – org.openntf.domino.feature. However this sort of configuration is limiting. In fact, it’s worth mentioning that when you install OSGi plugins by means of a nsf update site, that very update site can also be read by the DOTS environment, thus simplifying the plugin deployment process because you do it only once. At the same time, though, you don’t want to load xsp-related plugins that have no reason to live under DOTS and that might cause some possible unwanted side effects. So, what can be done is singling out only some of the features that make up the XPages environment update site and use only those.

update site

I said features and not plugins. So, such approach can’t be taken with ODA because, as we said, everything falls under one single feature. If you insist and try to load the whole feature you will be met with DOTS console errors.

ODA plugin deployment

The workaround consists of finding and deploying only the necessary ODA plugins that behave nicely under DOTS environment. That means to copy the following jar plugins under the data\domino\workspace-dots\applications\eclipse\plugins directory.

  • com.tinkerpop

  • javassist

  • javolution

  • jsr305

  • org.openntf.domino

  • org.openntf.formula

  • com.google.guava

In addition to those it’s also necessary to copy the com.ibm.icu plugin from the XPages environment. ODA makes use of it but it’s not present under the DOTS environment out of the box.

Initializing ODA

ODA can’t work just yet, though. It needs some initialization (automatically performed behind the scenes under the XPages environment). To initialize ODA we therefore need to create a plugin that will work as its controller. Such plugin needs to start as early as possible and work as a singleton.

Early start

Early start is mandatory. We want ODA to be ready before any DOTS plugin requires for it. For that I took advantage of the com.ibm.dots.startup extension.

The class is just boilerplate code. What I really need to exploit is the early-start behavior.

package org.openntf.domino.dots;

import com.ibm.dots.startup.IStartup;

public class Startup implements IStartup {

	public Startup() {
		// Do nothing for the activator will take care of it
	}

	@Override
	public void earlyStartup() {
		// Do nothing for the activator will take care of it
	}

}

The Activator class sports just a few lines of code that take care of starting and stopping the ODAPlatform class whenever Domino starts and quits the DOTS task.

package org.openntf.domino.dots;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class Activator implements BundleActivator {

	private static BundleContext context;

	static BundleContext getContext() {
		return context;
	}

	/*
	 * (non-Javadoc)
	 * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
	 */
	public void start(BundleContext bundleContext) throws Exception {
		Activator.context = bundleContext;
		
		ODAPlatform.start();
	}

	/*
	 * (non-Javadoc)
	 * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
	 */
	public void stop(BundleContext bundleContext) throws Exception {
		ODAPlatform.stop();
		
		Activator.context = null;
	}

}

ODAPlatform

The ODAPlatform class is a simple enum (to enforce the singleton behaviour) that in turn takes care of starting and stopping the ODA session factory.

package org.openntf.domino.dots;

import org.openntf.domino.AutoMime;
import org.openntf.domino.Session;
import org.openntf.domino.utils.Factory;
import org.openntf.domino.utils.Factory.ThreadConfig;

public enum ODAPlatform {
	;
	
	private static boolean started;

	protected synchronized static boolean isStarted() {
		return started;
	}

	protected synchronized static void start() {
		if (!isStarted()) {			
			Factory.startup();
			
			started = true;
		}
	}

	protected synchronized static void stop() {
		if (isStarted()) {
			Factory.shutdown();
			
			started = false;
		}
	}
	
	public static ThreadConfig getThreadConfig() {
		return new ThreadConfig(Session.Fixes.values(), AutoMime.WRAP_32K, false);
	}

}

DotsSessionFactory

The last piece of the puzzle is to provide a helper class that wraps the lotus.domino.Session object provided by the DOTS enviroments into a org.openntf.domino.Session object.

package org.openntf.domino.dots.session;

import org.openntf.domino.AutoMime;
import org.openntf.domino.Session;
import org.openntf.domino.ext.Session.Fixes;
import org.openntf.domino.session.ISessionFactory;
import org.openntf.domino.utils.Factory;

import lotus.domino.NotesException;
import lotus.domino.NotesFactory;

public class DotsSessionFactory implements ISessionFactory {

	private static final long serialVersionUID = 1L;

	private static final String DOTS_ENVIRONMENT_PARAM_NAME = "OSGI_CONFIGURATION_DB";

	@Override
	public Session createSession() {
		try {
			return wrapSession(NotesFactory.createSession());
		} catch (NotesException e) {
			e.printStackTrace();
		}

		return null;
	}

	private Session wrapSession(final lotus.domino.Session raw) {
		Session sess = Factory.getWrapperFactory().fromLotus(raw, Session.SCHEMA, null);
		sess.setNoRecycle(true);

		Fixes[] fixes = Factory.getThreadConfig().fixes;

		if (fixes != null) {
			for (Fixes fix : fixes) {
				sess.setFixEnable(fix, true);
			}
		}

		sess.setAutoMime(AutoMime.WRAP_32K);
		sess.setConvertMIME(false);

		String dfp = sess.getEnvironmentString(DOTS_ENVIRONMENT_PARAM_NAME, true);

		if (dfp != null && dfp.length() > 0) {
			sess.setCurrentDatabase(sess.getDatabase(sess.getServerName(), dfp));

			return sess;
		} else {
			throw new IllegalStateException(DOTS_ENVIRONMENT_PARAM_NAME + " is not set");
		}
	}
}

Deployment

All we need to do, now, is to copy the plugin under the data\domino\workspace-dots\applications\eclipse\plugins directory.

Usage

In order to use ODA, in any DOTS plugin we now develop we need to declare that it depends on org.openntf.domino.dots (that’s how I called the plugin but it can be whatever name you want).

Lastly, the code to hook up the DotsSessionFactory class.

package com.matika.dots.demo;

import org.eclipse.core.runtime.IProgressMonitor;
import org.openntf.domino.dots.ODAPlatform;
import org.openntf.domino.dots.session.DotsSessionFactory;
import org.openntf.domino.utils.Factory;
import org.openntf.domino.utils.Factory.SessionType;

import com.ibm.dots.task.AbstractServerTask;
import com.ibm.dots.task.RunWhen;

import lotus.domino.NotesException;

public class Demo extends AbstractServerTask {
	/**
	 * AbstractServerTask.init should be overridden but ServerTaskInfo is not
	 * public therefore it can't be passed to the super method from here.
	 */
	@Override
	public void setSession(lotus.domino.Session s) {
		super.setSession(s);

		if (!Factory.isInitialized()) {
			Factory.initThread(ODAPlatform.getThreadConfig());
			Factory.setSessionFactory(new DotsSessionFactory(), SessionType.CURRENT);
		}

		Preferences.INSTANCE.setTask(this);
	}

	@Override
	public void run(RunWhen runWhen, String[] args, IProgressMonitor progressMonitor) throws NotesException {
		logMessage(Factory.getSession().toString());
	}

	@Override
	public void dispose() throws NotesException {
		if (Factory.isInitialized()) {
			Factory.termThread();
		}
	}
}

Final notes

I cut corners so the classes you see are quite spartan. Certainly they can be improved upon by making everything more flexible and customizable but this is not the goal of this post.

I have omitted part of the configuration that would complete the plugin but I don’t want to detail every single aspect of it. I’m counting on the understanding you should already have of the OSGi plugin enviroment. However, I don’t want to leave you in the cold so I’m making the source code and the plugin itself available for dowload, so that you have the chance to see everything in its entirety.

org.openntf.domino.dots.zip

org.openntf.domino.dots_1.0.0.201606201411.jar

Leave a Reply

Your email address will not be published.

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