package com.link_intersystems.swing;
import java.awt.event.ActionEvent;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
public abstract class AsyncProgressAction<I, V, O> extends ProgressAction {
private static final int TYPE_PARAM_ACTION_INPUT = 0;
private static final long serialVersionUID = 7131523498822927047L;
private ActionInputSource<I> actionInputSource = NullActionInputSource
.getInstance();
@Override
public final void doActionPerformed(ActionEvent e,
ProgressMonitor progressMonitor) {
I actionInput = getInput(e);
if (isActionInputValid(actionInput)) {
execute(new ExecutionContext<I>(progressMonitor, actionInput));
}
}
protected void execute(ExecutionContext<I> executionContext) {
SwingWorkerAdapter swingWorkerAdapter = new SwingWorkerAdapter(
executionContext);
swingWorkerAdapter.execute();
}
protected boolean isActionInputValid(I actionInput) {
Class<?> clazz = getClass();
ParameterizedType parameterizedType = (ParameterizedType) clazz
.getGenericSuperclass();
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
Type actionInputType = actualTypeArguments[TYPE_PARAM_ACTION_INPUT];
if (Void.class.equals(actionInputType) && actionInput == null) {
return true;
}
return actionInput != null;
}
public void setActionInputSource(ActionInputSource<I> actionInputSource) {
if (actionInputSource == null) {
actionInputSource = NullActionInputSource.getInstance();
}
this.actionInputSource = actionInputSource;
}
protected I getInput(ActionEvent e) {
return actionInputSource.getActionInput(e);
}
protected abstract O doInBackground(I actionInput,
ProgressMonitor progressMonitor) throws Exception;
protected void process(List<V> chunks) {
}
protected void processResult(ResultRef<O, I> resultRef) {
try {
O t = resultRef.get();
done(t);
} catch (InterruptedException ignore) {
} catch (ExecutionException executionException) {
Throwable cause = executionException.getCause();
processException(cause, resultRef.getExecutionContext());
}
}
protected void processException(Throwable cause,
ExecutionContext<I> executionContext) {
String msg = String
.format("Unexpected exception: %s", cause.toString());
JOptionPane.showMessageDialog(null, msg, "Error",
JOptionPane.ERROR_MESSAGE);
}
protected void done(O result) {
}
private class SwingWorkerAdapter extends SwingWorker<O, V> {
private ExecutionContext<I> executionContext;
public SwingWorkerAdapter(ExecutionContext<I> executionContext) {
this.executionContext = executionContext;
}
@Override
protected O doInBackground() throws Exception {
I actionInput = executionContext.getActionInput();
ProgressMonitor progressMonitor = executionContext
.getProgressMonitor();
return AsyncProgressAction.this.doInBackground(actionInput,
progressMonitor);
}
@Override
protected void process(List<V> chunks) {
AsyncProgressAction.this.process(chunks);
}
@Override
protected void done() {
AsyncProgressAction.this.processResult(new ResultRef<O, I>() {
@Override
public O get() throws InterruptedException, ExecutionException {
return SwingWorkerAdapter.this.get();
}
@Override
public ExecutionContext<I> getExecutionContext() {
return SwingWorkerAdapter.this.executionContext;
}
});
}
}
protected interface ResultRef<T, I> {
public T get() throws InterruptedException, ExecutionException;
public ExecutionContext<I> getExecutionContext();
}
protected static class ExecutionContext<I> {
private ProgressMonitor progressMonitor;
private I actionInput;
public ExecutionContext(ProgressMonitor progressMonitor, I actionInput) {
this.progressMonitor = progressMonitor;
// TODO Auto-generated constructor stub
this.actionInput = actionInput;
}
public ProgressMonitor getProgressMonitor() {
return progressMonitor;
}
public I getActionInput() {
return actionInput;
}
}
private static class NullActionInputSource<I> implements
ActionInputSource<I> {
@SuppressWarnings("rawtypes")
private static final NullActionInputSource INSTANCE = new NullActionInputSource();
@SuppressWarnings("unchecked")
private static <I> NullActionInputSource<I> getInstance() {
return INSTANCE;
}
@Override
public I getActionInput(ActionEvent e) {
return null;
}
}
}