/*
* Copyright 2011 JBoss, by Red Hat, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.errai.common.client.api.tasks;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.user.client.Timer;
import org.jboss.errai.common.client.util.TimeUnit;
/**
* The client-side implementation of {@link TaskManager}.
*/
public class ClientTaskManager implements TaskManager {
@Override
public void execute(final Runnable task) {
GWT.runAsync(new RunAsyncCallback() {
@Override
public void onFailure(Throwable reason) {
GWT.log("failed async execution", reason);
}
@Override
public void onSuccess() {
task.run();
}
});
}
@Override
public AsyncTask scheduleRepeating(TimeUnit unit, int interval, final Runnable userTask) {
final TaskManagerTimer timer = new TaskManagerTimer(userTask);
timer.scheduleRepeating((int) unit.convert(interval, TimeUnit.MILLISECONDS));
return timer.asyncTask;
}
@Override
public AsyncTask schedule(TimeUnit unit, int interval, final Runnable userTask) {
final TaskManagerTimer timer = new TaskManagerTimer(userTask);
timer.schedule((int) unit.convert(interval, TimeUnit.MILLISECONDS));
return timer.asyncTask;
}
/**
* An AsyncTask implementation that is meant to be created and used by the
* {@link TaskManagerTimer}.
*
* @author Jonathan Fuerth <jfuerth@gmail.com>
*/
private static class ClientAsyncTask implements Runnable, AsyncTask {
private final Runnable task;
private final TaskManagerTimer timer;
private Runnable exitHandler;
/**
* True if and only if the task will never run again.
*/
private boolean finished;
private boolean isCancelled;
/**
* Don't call this. Use {@link #create(Runnable, Timer)}.
*
* @param task
* @param timer
*/
private ClientAsyncTask(final Runnable task, final TaskManagerTimer timer) {
this.task = task;
this.timer = timer;
}
@Override
public void run() {
try {
task.run();
} catch (Throwable t) {
GWT.log("Async Task Execution Failed. Future executions (if any) are cancelled.", t);
timer.cancel();
}
}
/**
* Creates a new async task for the client, injecting the reference into
* {@code task} if it is an instance of {@link HasAsyncTaskRef}.
*
* @param task The code to execute. Not null.
* @param timer The timer that will execute class. Not null.
* @return A new AsyncTask that relates to {@code task}.
*/
public static ClientAsyncTask create(Runnable task, TaskManagerTimer timer) {
ClientAsyncTask t = new ClientAsyncTask(task, timer);
if (task instanceof HasAsyncTaskRef) {
((HasAsyncTaskRef) task).setAsyncTask(t);
}
return t;
}
@Override
public void cancel(boolean interrupt) {
timer.cancel();
finishUp();
}
@Override
public void setExitHandler(Runnable runnable) {
if (exitHandler != null) {
throw new IllegalStateException("Exit handler is already set to " + exitHandler);
}
this.exitHandler = runnable;
if (isFinished()) {
exitHandler.run();
}
}
@Override
public boolean isCancelled() {
return timer.isCancelled();
}
private boolean isFinished() {
return finished;
}
public void finishUp() {
if (finished) {
throw new IllegalStateException("Already finished");
}
finished = true;
if (exitHandler != null) {
exitHandler.run();
}
}
}
private enum SchedulingMode { ONE_TIME, REPEATING }
/**
* A GWT Timer implementation that has a public flag indicating if
* {@link #cancel(boolean)} has been called.
* <p>
* This Timer class only allows a single call to either {@link #schedule(int)}
* or {@link #scheduleRepeating(int)}. Further attempts to schedule the call
* will result in {@link IllegalStateException}.
*
* @author Jonathan Fuerth <jfuerth@gmail.com>
*/
private final class TaskManagerTimer extends Timer {
private SchedulingMode mode;
private ClientAsyncTask asyncTask;
TaskManagerTimer(Runnable userTask) {
asyncTask = ClientAsyncTask.create(userTask, this);
}
@Override
public void schedule(int delayMillis) {
if (mode != null) {
throw new IllegalStateException("This timer has already been scheduled.");
}
mode = SchedulingMode.ONE_TIME;
super.schedule(delayMillis);
}
@Override
public void scheduleRepeating(int periodMillis) {
if (mode != null) {
throw new IllegalStateException("This timer has already been scheduled.");
}
mode = SchedulingMode.REPEATING;
super.scheduleRepeating(periodMillis);
}
@Override
public void run() {
asyncTask.run();
if (mode == SchedulingMode.ONE_TIME) {
asyncTask.finishUp();
}
}
@Override
public void cancel() {
super.cancel();
asyncTask.isCancelled = true;
}
public boolean isCancelled() {
return asyncTask.isCancelled;
}
}
@Override
public void requestStop() {
}
}