package org.openntf.domino.xots.builtin; import java.io.Serializable; import java.util.HashSet; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; import javax.servlet.ServletException; import org.openntf.domino.Database; import org.openntf.domino.DbDirectory; import org.openntf.domino.Session; import org.openntf.domino.design.DatabaseDesign; import org.openntf.domino.design.IconNote; import org.openntf.domino.exceptions.UserAccessException; import org.openntf.domino.thread.AbstractDominoRunnable; import org.openntf.domino.thread.model.Context; import org.openntf.domino.thread.model.Schedule; import org.openntf.domino.thread.model.Scope; import org.openntf.domino.thread.model.SessionType; import org.openntf.domino.thread.model.XotsTasklet; import org.openntf.domino.utils.Factory; import org.openntf.domino.xots.IRunsInModule; import org.openntf.domino.xots.TaskletDefinition; import org.openntf.domino.xots.XotsDaemon; import org.openntf.domino.xots.XotsScheduler; import org.openntf.domino.xsp.adapter.OpenntfHttpService; import com.ibm.commons.util.StringUtil; import com.ibm.domino.xsp.module.nsf.NSFComponentModule; import com.ibm.domino.xsp.module.nsf.NSFService; @Schedule(frequency = 4, timeunit = TimeUnit.HOURS) @XotsTasklet(session = SessionType.NATIVE, scope = Scope.NONE, context = Context.XOTS) /** * A Runnable that scans for tasklet classes on a specified server * * @author Nathan T. Freeman * @author Roland Praml, FOCONIS AG */ public class XotsNsfScanner extends AbstractDominoRunnable implements Serializable { private static final long serialVersionUID = 1L; private static final Logger log_ = Logger.getLogger(XotsNsfScanner.class.getName()); private final boolean TRACE = false; private final String serverName_; public XotsNsfScanner(final String serverName) { serverName_ = serverName; } public String getServerName() { return serverName_; } @Override public void run() { scan(); System.out.println("Current XOTS Classes:"); System.out.println(XotsScheduler.INSTANCE); } /** * Scans all databases on the specified server */ public void scan() { Session session = Factory.getSession(); DbDirectory dir = session.getDbDirectory(getServerName()); dir.setDirectoryType(DbDirectory.Type.DATABASE); for (Database db : dir) { try { if (!scanDatabase(db)) { XotsScheduler.INSTANCE.unregisterTasklets(db.getApiPath()); } } catch (Throwable t) { t.printStackTrace(); } } setChanged(); notifyObservers(null); } /** * Scan the specified database * * @param db */ public void scan(final Database db) { try { if (!scanDatabase(db)) { XotsScheduler.INSTANCE.unregisterTasklets(db.getApiPath()); } } catch (Throwable t) { t.printStackTrace(); } setChanged(); notifyObservers(null); } /** * * @param session * @param db * @return true, if the database has XOTS-Classes * @throws ServletException */ protected boolean scanDatabase(final Database db) throws ServletException { //NTF Keeping JG's implementation since he made an enhancement to the IconNote class for it! :) log_.finest("Scanning database " + db.getApiPath() + " for Xots Tasklets"); try { DatabaseDesign design = db.getDesign(); IconNote icon = design.getIconNote(); if (icon != null) { String[] xotsClassNames = icon.getXotsClassNames(); if (xotsClassNames != null && xotsClassNames.length > 0) { if (TRACE) { System.out.println("TRACE: Adding Xots Tasklets for database " + db.getApiPath()); } String dbPath = db.getFilePath().replace('\\', '/'); dbPath = NSFService.FILE_CASE_INSENSITIVE ? dbPath.toLowerCase() : dbPath; if (!StringUtil.isEmpty(db.getServer())) { dbPath = db.getServer() + "!!" + dbPath; } NSFComponentModule module = OpenntfHttpService.sGetNsfService().loadModule(dbPath); Runnable loader = new LoaderRunnable(db.getApiPath(), xotsClassNames, module); XotsDaemon.addToQueue(loader); return true; } } } catch (UserAccessException uae) { log_.warning("XotsNsfScanner: Database " + db.getFilePath() + " cannot be opened by " + db.getAncestorSession().getEffectiveUserName()); } return false; } /** * * @author Roland Praml, FOCONIS AG * */ @XotsTasklet(session = SessionType.NATIVE, scope = Scope.NONE, context = Context.XOTS) public class LoaderRunnable implements Runnable, IRunsInModule { private String apiPath_; private String[] classNames_; private NSFComponentModule module_; public LoaderRunnable(final String apiPath, final String[] classNames, final NSFComponentModule module) { apiPath_ = apiPath; classNames_ = classNames; module_ = module; } @Override public NSFComponentModule getRunModule() { return module_; } @Override public void run() { try { //NotesContext ctxContext = new NotesContext(module_); //NotesContext.initThread(ctxContext); // TODO RPR use NotesSession.getLastNonDataModificationDateByName(arg0, arg1) Set<TaskletDefinition> taskletDefinitions = new HashSet<TaskletDefinition>(); ClassLoader mcl = Thread.currentThread().getContextClassLoader(); for (String className : classNames_) { String[] classDefBits = className.split(";"); // There may be ";boolean" at the end boolean enabled = classDefBits.length < 2 || "true".equals(classDefBits[1]); if (enabled) { try { Class cls = mcl.loadClass(classDefBits[0]); if (Runnable.class.isAssignableFrom(cls)) { TaskletDefinition def = new TaskletDefinition(cls); taskletDefinitions.add(def); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } } XotsScheduler.INSTANCE.registerTasklets(apiPath_, taskletDefinitions); } catch (Throwable t) { t.printStackTrace(); } finally { //NotesContext.termThread(); } } } }