package org.openntf.domino.xsp.xots;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import org.openntf.domino.thread.TaskletWorker;
import org.openntf.domino.thread.WorkerExecutor;
import org.openntf.domino.xots.Xots;
import org.openntf.domino.xsp.xots.XotsDominoExecutor.XotsModuleTasklet;
import com.ibm.domino.xsp.module.nsf.NotesContext;
public class TaskletWorkerExecutor<T> extends XotsModuleTasklet implements WorkerExecutor<T> {
BlockingQueue<T> q = new LinkedBlockingQueue<T>();
private static final int NOT_RUNNING = 0;
private static final int RUNNING = 1;
//private static final int SHUTDOWN = 2;
private class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1L;
public void add(final T t) {
q.add(t);
start();
}
public void stop() {
for (;;) {
int i = getState();
if (i == NOT_RUNNING)
return;
if (i == RUNNING) {
if (compareAndSetState(i, NOT_RUNNING)) {
return;
}
}
}
}
// NOT_RUNNING => RUNNING
public void start() {
for (;;) {
int i = getState();
if (i == RUNNING)
return;
if (i == NOT_RUNNING) {
if (compareAndSetState(i, RUNNING)) {
Xots.getService().submit(TaskletWorkerExecutor.this);
return;
}
}
}
}
}
private T currentElement;
private Sync inner = new Sync();
public TaskletWorkerExecutor(final String moduleName, final String className, final Object... args) {
super(moduleName, className, args);
}
public TaskletWorkerExecutor(final Class<? extends TaskletWorker<T>> clazz, final Object... args) {
super(NotesContext.getCurrent().getModule().getDatabasePath(), clazz.getName(), args);
}
@Override
public void send(final T t) {
inner.add(t);
}
@Override
public Object call() throws Exception {
try {
return super.call();
} finally {
inner.stop();
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
protected Object invokeObject(final Object wrappedTask) throws Exception {
currentElement = q.poll(2000, TimeUnit.MILLISECONDS);
if (currentElement != null) {
TaskletWorker worker = (TaskletWorker) wrappedTask;
worker.startUp();
do {
worker.process(currentElement);
currentElement = q.poll(2000, TimeUnit.MILLISECONDS);
} while (currentElement != null);
worker.tearDown();
}
return null;
}
}