/*
* ThreadedTaskController.java 29 sept. 2008
*
* Sweet Home 3D, Copyright (c) 2008 Emmanuel PUYBARET / eTeks <info@eteks.com>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.eteks.sweethome3d.viewcontroller;
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.FutureTask;
import com.eteks.sweethome3d.model.UserPreferences;
/**
* A MVC controller used to execute a particular task in a separated thread.
* @author Emmanuel Puybaret
*/
public class ThreadedTaskController implements Controller {
private static ExecutorService tasksExecutor;
private final UserPreferences preferences;
private final ViewFactory viewFactory;
private final Callable<Void> threadedTask;
private final String taskMessage;
private final ExceptionHandler exceptionHandler;
private ThreadedTaskView view;
private Future<?> task;
/**
* Creates a controller that will execute in a separated thread the given task.
* This task shouldn't modify any model objects and should be able to handle
* interruptions with <code>Thread</code> methods that the user may provoke
* when he wants to cancel a threaded task.
*/
public ThreadedTaskController(Callable<Void> threadedTask,
String taskMessage,
ExceptionHandler exceptionHandler,
UserPreferences preferences,
ViewFactory viewFactory) {
this.preferences = preferences;
this.viewFactory = viewFactory;
this.threadedTask = threadedTask;
this.taskMessage = taskMessage;
this.exceptionHandler = exceptionHandler;
}
/**
* Returns the view controlled by this controller.
*/
public ThreadedTaskView getView() {
// Create view lazily only once it's needed
if (this.view == null) {
this.view = this.viewFactory.createThreadedTaskView(this.taskMessage, this.preferences, this);
}
return this.view;
}
/**
* Executes in a separated thread the task given in constructor. This task shouldn't
* modify any model objects shared with other threads.
*/
public void executeTask(final View executingView) {
if (tasksExecutor == null) {
tasksExecutor = Executors.newSingleThreadExecutor();
}
this.task = tasksExecutor.submit(new FutureTask<Void>(this.threadedTask) {
@Override
public void run() {
// Update running status in view
getView().invokeLater(new Runnable() {
public void run() {
getView().setTaskRunning(true, executingView);
}
});
super.run();
}
@Override
protected void done() {
// Update running status in view
getView().invokeLater(new Runnable() {
public void run() {
getView().setTaskRunning(false, executingView);
task = null;
}
});
try {
get();
} catch (ExecutionException ex) {
// Handle exceptions with handler
final Throwable throwable = ex.getCause();
if (throwable instanceof Exception) {
getView().invokeLater(new Runnable() {
public void run() {
exceptionHandler.handleException((Exception)throwable);
}
});
} else {
throwable.printStackTrace();
}
} catch (final InterruptedException ex) {
// Handle exception with handler
getView().invokeLater(new Runnable() {
public void run() {
exceptionHandler.handleException(ex);
}
});
}
}
});
}
/**
* Cancels the threaded task if it's running.
*/
public void cancelTask() {
if (this.task != null) {
this.task.cancel(true);
}
}
/**
* Returns <code>true</code> if the threaded task is running.
*/
public boolean isTaskRunning() {
return this.task != null && !this.task.isDone();
}
/**
* Handles exception that may happen during the execution of a threaded task.
*/
public static interface ExceptionHandler {
public void handleException(Exception ex);
}
}