package org.openntf.domino.config; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import javolution.util.FastMap; import javolution.util.FastSet; import org.openntf.domino.Database; import org.openntf.domino.Session; import org.openntf.domino.thread.DominoExecutor; import org.openntf.domino.utils.Factory; import org.openntf.domino.utils.Factory.SessionType; import org.openntf.domino.xots.Tasklet; import com.google.common.base.Charsets; import com.google.common.hash.Hashing; /** * This is the interface to the ODA-Database * * @author Roland Praml, FOCONIS AG * */ public enum Configuration { ; private static DominoExecutor executor_; private static Database odaDb_; private static boolean inititalized; public static String ODA_NSF = "oda.nsf"; // will be overriden by Notes.ini "ODA_NSF" entry protected static Set<ConfigurationObject> dirtyObjects = new FastSet<ConfigurationObject>(); private static Map<String, String> md5Cache_ = new FastMap<String, String>().atomic(); /** * The shutdown hook handles proper shutdown. */ private static Runnable SHUTDOWN_HOOK = new Runnable() { @Override public void run() { executor_ = null; Factory.removeShutdownHook(SHUTDOWN_HOOK); } }; /** * The object-flusher processes the dirtyObjects-set and saves the configurationObjects from time to time */ @Tasklet(session = Tasklet.Session.NATIVE, threadConfig = Tasklet.ThreadConfig.STRICT) private static class ObjectFlusher implements Runnable { @Override public void run() { synchronized (dirtyObjects) { for (ConfigurationObject obj : dirtyObjects) { obj.syncCache(); } dirtyObjects.clear(); } } }; /** * Adds a configuration Object to the dirty-set so that it can be flushed the next few seconds * */ public static void addDirty(final ConfigurationObject configurationObject) { synchronized (dirtyObjects) { dirtyObjects.add(configurationObject); } } /** * Sets up the executor, if no one exists * * @return */ protected static synchronized DominoExecutor getExecutor() { if (executor_ == null) { if (Factory.isStarted()) { executor_ = new DominoExecutor(2, "Config"); executor_.scheduleAtFixedRate(new ObjectFlusher(), 5, 5, TimeUnit.SECONDS); Factory.addShutdownHook(SHUTDOWN_HOOK); } } return executor_; } /** * returns the ODA.NSF Database * * @return the ODA.NSF Database */ protected static Database getOdaDb() { if (inititalized) return odaDb_; return initOdaDb(); } /** * Initialitzes the ODA.NSF. Tries to read "ODA_NSF" value from notes.ini. * * @return */ private synchronized static Database initOdaDb() { if (!inititalized) { inititalized = true; try { // ODA-DB is thread safe, so we may cache it :) Session sess = Factory.getSession(SessionType.CURRENT); String s = sess.getEnvironmentString("ODA_NSF"); if (!s.isEmpty()) { ODA_NSF = s; Factory.println("INFO", "Using notes.ini variable ODA_NSF=" + ODA_NSF); } Database db = sess.getDatabase(ODA_NSF); if (db == null) { Factory.println("WARNING", "cannot find " + ODA_NSF + " as user " + sess.getEffectiveUserName() + ". - using default values."); } else if (!db.isOpen()) { Factory.println("ERROR", "cannot open " + ODA_NSF + " as user " + sess.getEffectiveUserName() + ". - using default values."); } else { odaDb_ = db; Factory.println(Configuration.class, "Using " + db + " as configuration database."); } } catch (Exception e) { Factory.println("ERROR", "cannot open " + ODA_NSF + ": " + e.toString() + " - using default values."); } } return odaDb_; } public static ServerConfiguration getServerConfiguration(final String serverName) { return new ServerConfiguration(serverName); } public static ServerConfiguration getServerConfiguration() { return new ServerConfiguration(Factory.getLocalServerName()); } /** * Utility method, to compute MD5 sum of a string. * * @param input * The string to hash * @return The MD5 sum of the string */ public static String MD5(final String input) { String ret = md5Cache_.get(input); if (ret == null) { ret = Hashing.md5().newHasher().putString(input, Charsets.UTF_8).hash().toString(); md5Cache_.put(input, ret); } return ret; } public static String computeUNID(final String input, final Database db) { return MD5(input).substring(0, 16).concat(db.getReplicaID()); } /** * Return the XOTS configuration for the given tasklet in the given database. * * The lookup is done by computed UNID: MD5(taskletName).subString(0,16) + source.ReplicaID) This gives the document a readable creation * time and we use additional 64 bits for tasklet name. As replicaID is (or should!!! be) unique in Domino Installations, it is nearly * impossible to get a collision unless you have thousands of tasklets in your database * * @param source * the source DB * @param taskletName * the taskletName in this DB * @return the configurationProperties */ public static XotsConfiguration getXotsNSFConfiguration(final String dbPath, final String taskletName) { return new XotsConfiguration(dbPath, taskletName, true); } public static XotsConfiguration getXotsBundleConfiguration(final String bundle, final String taskletName) { return new XotsConfiguration(bundle, taskletName, false); } }