/**
* Constellio
* Copyright (C) 2010 DocuLibre inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.constellio.data.utils;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public abstract class TimeoutTask<T extends Object, E extends Exception> {
private long timeoutMilliseconds;
public TimeoutTask(long timeoutMilliseconds) {
this.timeoutMilliseconds = timeoutMilliseconds;
}
public long getTimeoutSecs() {
return timeoutMilliseconds;
}
public void setTimeoutSecs(long timeoutMilliseconds) {
this.timeoutMilliseconds = timeoutMilliseconds;
}
@SuppressWarnings("unchecked")
public T execute()
throws E, TimeoutException {
T result;
ExecutorService executor = Executors.newFixedThreadPool(1);
// set the executor thread working
final Future<T> future = executor.submit(new Callable<T>() {
@Override
public T call() {
try {
return doExecute();
} catch (Exception e) {
throw new TimeOutTaskRuntimeException.CannotDoExcute(e);
}
}
});
// check the outcome of the executor thread and limit the time allowed for it to complete
try {
result = future.get(timeoutMilliseconds == -1 ? Long.MAX_VALUE : timeoutMilliseconds, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
result = null;
// ExecutionException: deliverer threw exception
// TimeoutException: didn't complete within downloadTimeoutSecs
// InterruptedException: the executor thread was interrupted
// interrupts the worker thread if necessary
future.cancel(true);
onCancel();
throw e;
} catch (InterruptedException e) {
future.cancel(true);
onCancel();
throw new TimeOutTaskRuntimeException.Interrupted(e);
} catch (ExecutionException t) {
future.cancel(true);
onCancel();
Throwable cause1 = t.getCause();
Throwable cause2 = cause1.getCause();
// Cast is not checked, but it will only throw ExceptionType or RuntimeException
throw (E) cause2;
}
return result;
}
protected void onCancel() {
}
protected abstract T doExecute()
throws E;
}