package org.openntf.domino.xsp.xots;
import java.io.FileNotFoundException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
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.exceptions.UserAccessException;
import org.openntf.domino.thread.AbstractDominoCallable;
import org.openntf.domino.thread.AbstractDominoRunnable;
import org.openntf.domino.utils.Factory;
import org.openntf.domino.utils.Factory.SessionType;
import org.openntf.domino.xots.ScheduleData;
import org.openntf.domino.xots.Tasklet;
import org.openntf.domino.xots.Xots;
import org.openntf.domino.xots.XotsUtil;
import com.ibm.domino.xsp.module.nsf.NSFComponentModule;
import com.ibm.domino.xsp.module.nsf.NotesContext;
import com.ibm.domino.xsp.module.nsf.RuntimeFileSystem;
import com.ibm.domino.xsp.module.nsf.RuntimeFileSystem.NSFResource;
import com.ibm.domino.xsp.module.nsf.RuntimeFileSystem.NSFXspClassResource;
// tell http osgi xots run bundle:org.openntf.domino.xsp org.openntf.domino.xsp.xots.XotsNsfScanner
@Tasklet(session = Tasklet.Session.NATIVE, // use server's session
scope = Tasklet.Scope.SERVER, // one scan per server may run concurrent
context = Tasklet.Context.PLUGIN, // in the context of a plugn
schedule = { "startup", "periodic:90m" }, // on Startup and every 90 minutes
onAllServers = true, // on all servers
threadConfig = Tasklet.ThreadConfig.STRICT // and strict thread config. BubbleExceptions = TRUE
)
/**
* 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 String serverName_;
public XotsNsfScanner() {
serverName_ = "";
}
public XotsNsfScanner(final String serverName) {
serverName_ = serverName;
}
public String getServerName() {
return serverName_;
}
@Override
public void run() {
// Factory.println(this, "Scan started");
// List<ScheduleData> ret = scan();
// Factory.println(this, "-------------------------------------------------");
// Factory.println(this, "Scan stopped. Found tasklets: ");
// for (ScheduleData sd : ret) {
// Factory.println(this, sd);
// }
}
/**
* Scans all databases on the specified server
*/
public List<ScheduleData> scan() {
Session session = Factory.getSession(SessionType.CURRENT); // Returns a XotsSessionType.NATIVE
DbDirectory dir = session.getDbDirectory(getServerName());
dir.setDirectoryType(DbDirectory.Type.DATABASE);
List<Future<List<ScheduleData>>> futures = new ArrayList<Future<List<ScheduleData>>>();
for (Database db : dir) {
try {
Future<List<ScheduleData>> future = scanDatabase(db);
if (future != null) {
futures.add(future);
}
} catch (Throwable t) {
t.printStackTrace();
}
}
List<ScheduleData> ret = new ArrayList<ScheduleData>();
for (Future<List<ScheduleData>> future : futures) {
try {
ret.addAll(future.get());
} catch (Exception e) {
// exceptions should already been logged
}
}
setChanged();
notifyObservers(null);
return ret;
}
// /**
// * 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);
// }
/**
* Scans the given database for xots enabled classes
*
* @author Roland Praml, FOCONIS AG
*
*/
private static class XotsClassScanner extends AbstractDominoCallable<List<ScheduleData>> {
private static final long serialVersionUID = 1L;
private String apiPath;
public XotsClassScanner(final String apiPath) {
super();
this.apiPath = apiPath;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return super.getDescription() + ":" + apiPath;
}
@Override
public List<ScheduleData> call() throws Exception {
NSFComponentModule module = ModuleLoader.loadModule(apiPath, true);
NotesContext ctx = new NotesContext(module);
NotesContext.initThread(ctx);
List<ScheduleData> ret = new ArrayList<ScheduleData>();
try {
ctx.initRequest(new FakeHttpRequest(Factory.getLocalServerName()));
RuntimeFileSystem vfs = module.getRuntimeFileSystem();
Map<String, NSFResource> resources = vfs.getAllResources();
ClassLoader mcl = module.getModuleClassLoader();
String dbPath = ctx.getCurrentDatabase().getFilePath();
for (NSFResource resource : resources.values()) {
if (resource instanceof NSFXspClassResource) {
String path = resource.getNSFPath();
// Check all classes, but not xsp.*
if (path.startsWith("WEB-INF/classes/") && path.endsWith(".class") && !path.startsWith("WEB-INF/classes/xsp/")) {
String className = path.substring(16, path.length() - 6).replace('/', '.');
try {
Class<?> clazz = mcl.loadClass(className);
ScheduleData data = XotsUtil.getSchedule(dbPath, clazz);
if (data != null) {
ret.add(data);
}
//if (effectiveSchedDefs != null) {
// ret.add(new ScheduleDataNSF(replicaID, className, apiPath, effectiveSchedDefs));
//}
} catch (Exception e) {
Factory.println(this, "Cannot load: " + className + ". " + e.getMessage());
}
}
}
//if (resource instanceof NSFXspClassResource) {
// NSFXspClassResource clResource = (NSFXspClassResource) resource;
// clResource.
// byte[] arrayOfByte = ((RuntimeFileSystem)localObject3).getFileContentAsByteArray(((NotesContext)localObject2).getNotesDatabase(), str);
//}
}
} finally {
NotesContext.termThread();
}
return ret;
}
}
/**
*
* @param session
* @param db
* @return true, if the database has XOTS-Classes
* @throws
* @throws ServletException
*/
protected Future<List<ScheduleData>> scanDatabase(final Database db) {
//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 {
Database template = db.getXPageSharedDesignTemplate();
DatabaseDesign design = template == null ? db.getDesign() : template.getDesign();
if (design.isAPIEnabled()) {
log_.info("ODA enabled database: " + db.getApiPath());
return Xots.getService().submit(new XotsClassScanner(db.getApiPath()));
}
//
//
//
//
//
// IconNote icon = design.getIconNote();
//
// if (icon != null) {
// String[] xotsClassNames = icon.getXotsClassNames();
// if (xotsClassNames != null && xotsClassNames.length > 0) {
// if (log_.isLoggable(Level.FINE)) {
// log_.fine("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) {
Factory.println(this, "WARNING: " + uae.getMessage());
// we don't log the warning in the log, as this may confuse admins.
log_.log(Level.INFO, uae.getMessage(), uae);
} catch (FileNotFoundException e) {
Factory.println(this, "WARNING: " + e.getMessage());
log_.log(Level.INFO, e.getMessage(), e);
}
return null;
}
}