package org.openntf.domino.thread;
import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.Callable;
import lotus.domino.NotesThread;
import org.openntf.domino.session.ISessionFactory;
import org.openntf.domino.utils.Factory;
import org.openntf.domino.utils.Factory.SessionType;
import org.openntf.domino.xots.Tasklet;
/**
* A Wrapper for callables and runnable that provides proper setup/teardown
*
* @author Roland Praml, FOCONIS AG
*
*/
public abstract class AbstractWrappedTask implements IWrappedTask {
private Object wrappedTask;
protected Tasklet.Scope scope;
protected Tasklet.Context context;
protected ISessionFactory sessionFactory;
protected Factory.ThreadConfig sourceThreadConfig;
/**
* Determines the sessionType under which the current runnable should run. The first non-null value of the following list is returned
* <ul>
* <li>If the runnable implements <code>IDominoRunnable</code>: result of <code>getSessionType</code></li>
* <li>the value of {@link SessionType} Annotation</li>
* <li>DominoSessionType.DEFAULT</li>
* </ul>
*
* @param task
* the runnable to determine the DominoSessionType
*/
protected synchronized void setWrappedTask(final Object task) {
wrappedTask = task;
if (task == null)
return;
// some security checks...
if (task instanceof NotesThread) {
// RPr: I'm not sure if this should be allowed anyway...
throw new IllegalArgumentException("Cannot wrap the NotesThread " + task.getClass().getName() + " into a DominoRunner");
}
// if (task instanceof DominoFutureTask) {
// // RPr: don't know if this is possible
// throw new IllegalArgumentException("Cannot wrap the WrappedCallable " + task.getClass().getName() + " into a DominoRunner");
// }
if (task instanceof AbstractWrappedTask) {
// RPr: don't know if this is possible
throw new IllegalArgumentException("Cannot wrap the WrappedCallable " + task.getClass().getName() + " into a DominoRunner");
}
if (task instanceof Tasklet.Interface) {
Tasklet.Interface dominoRunnable = (Tasklet.Interface) task;
sessionFactory = dominoRunnable.getSessionFactory();
scope = dominoRunnable.getScope();
context = dominoRunnable.getContext();
sourceThreadConfig = dominoRunnable.getThreadConfig();
}
Tasklet annot = task.getClass().getAnnotation(Tasklet.class);
if (annot != null) {
if (sessionFactory == null) {
switch (annot.session()) {
case CLONE:
sessionFactory = Factory.getSessionFactory(SessionType.CURRENT);
break;
case CLONE_FULL_ACCESS:
sessionFactory = Factory.getSessionFactory(SessionType.CURRENT_FULL_ACCESS);
break;
case FULL_ACCESS:
sessionFactory = Factory.getSessionFactory(SessionType.FULL_ACCESS);
break;
case NATIVE:
sessionFactory = Factory.getSessionFactory(SessionType.NATIVE);
break;
case NONE:
sessionFactory = null;
break;
case SIGNER:
sessionFactory = Factory.getSessionFactory(SessionType.SIGNER);
break;
case SIGNER_FULL_ACCESS:
sessionFactory = Factory.getSessionFactory(SessionType.SIGNER_FULL_ACCESS);
break;
case TRUSTED:
sessionFactory = Factory.getSessionFactory(SessionType.TRUSTED);
break;
default:
break;
}
if ((annot.session() != Tasklet.Session.NONE) && sessionFactory == null) {
throw new IllegalStateException("Could not create a Fatory for " + annot.session());
}
// 30.01.15/RPr: no longer neccessary
// if (sessionFactory != null) {
// Factory.setSessionFactory(sessionFactory, SessionType.CURRENT);
// }
}
if (context == null) {
context = annot.context();
}
if (context == null) {
context = Tasklet.Context.DEFAULT;
}
if (scope == null) {
scope = annot.scope();
}
if (scope == null) {
scope = Tasklet.Scope.NONE;
}
if (sourceThreadConfig == null) {
switch (annot.threadConfig()) {
case CLONE:
sourceThreadConfig = Factory.getThreadConfig();
break;
case PERMISSIVE:
sourceThreadConfig = Factory.PERMISSIVE_THREAD_CONFIG;
break;
case STRICT:
sourceThreadConfig = Factory.STRICT_THREAD_CONFIG;
break;
}
}
}
if (sourceThreadConfig == null)
sourceThreadConfig = Factory.getThreadConfig();
}
/**
* Returns the wrapped task
*
* @return
*/
protected synchronized Object getWrappedTask() {
return wrappedTask;
}
/**
* adds an observer to the wrapped task
*/
@Override
public void addObserver(final Observer o) {
Object task = getWrappedTask();
if (task instanceof Observable) {
((Observable) task).addObserver(o);
}
}
/**
* stops the wrapped task if it does implement {@link Tasklet.Interface}
*/
@Override
public void stop() {
Object task = getWrappedTask();
if (task instanceof Tasklet.Interface) {
((Tasklet.Interface) task).stop();
}
}
@Override
public String getDescription() {
Object task = getWrappedTask();
if (task instanceof Tasklet.Interface) {
return ((Tasklet.Interface) task).getDescription();
}
return task.getClass().getSimpleName();
}
/**
* Common method that does setUp/tearDown before executing the wrapped object
*
* @param callable
* @param runnable
* @return
* @throws Exception
*/
protected Object callOrRun() throws Exception {
NotesThread.sinitThread();
Factory.initThread(sourceThreadConfig);
try {
return invokeWrappedTask();
} finally {
Factory.termThread();
NotesThread.stermThread();
}
}
protected Object invokeWrappedTask() throws Exception {
Thread thread = Thread.currentThread();
ClassLoader oldCl = thread.getContextClassLoader();
Object wrappedTask = getWrappedTask();
ClassLoader runCl = wrappedTask.getClass().getClassLoader();
thread.setContextClassLoader(runCl);
if (sessionFactory != null) {
Factory.setSessionFactory(sessionFactory, SessionType.CURRENT);
}
try {
if (wrappedTask instanceof Callable) {
return ((Callable<?>) wrappedTask).call();
} else {
((Runnable) wrappedTask).run();
return null;
}
} finally {
thread.setContextClassLoader(oldCl);
}
}
}