/** * Copyright 2008 Google 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.waveprotocol.wave.client.scheduler; import com.google.gwt.user.client.Command; import java.util.ArrayList; /** * This is execute deferred commands in time slices so that the UI is not blocked up. * * There is something similar in the package private class * com.google.gwt.user.client.CommandExecutor, but it's too much trouble to mess around with * that gwt internal class to make it public, configurable etc. * * @author zdwang@google.com (David Wang) * @deprecated Use Scheduler or TimerService instead */ @Deprecated public class TimeSlicedCommandQueue implements CommandQueue { private static final int DEFAULT_TIME_SLICE_MS = 10; // TODO(zdwang): Check if the LinkedList work in GWT. private final ArrayList<Command> queue = new ArrayList<Command>(); /** * The time when the time slice started. */ public long timeSliceStart; /** * The maximum time allowed to execute the commands in a single turn. */ public int timeSliceMs = DEFAULT_TIME_SLICE_MS; /** * Are we executing the queue. */ private boolean isExecutingQueue; private final TimerService timeService; private boolean isScheduled; /** * The timer that processes the queue. */ private final Scheduler.IncrementalTask task = new Scheduler.IncrementalTask() { public boolean execute() { timeSliceStart = System.currentTimeMillis(); executeQueue(); if (queue.size() == 0 && isScheduled) { cancel(); } timeSliceStart = 0; return true; // Run until canceled } }; /** * Force commands to run asynchronously. */ private final boolean forceAsync; /** * Create a TimeSlicedCommandQueue using the given time service * @param service */ public TimeSlicedCommandQueue(TimerService service, boolean forceAsync) { timeService = service; this.forceAsync = forceAsync; } /** * Create a time sliced command queue using the default time service, * and allowing commands to run in the same event loop. */ public TimeSlicedCommandQueue() { this(new SchedulerTimerService(SchedulerInstance.get()), false); } /** * Create a times sliced command using the default time service. * @param forceAsync */ public TimeSlicedCommandQueue(boolean forceAsync) { this(new SchedulerTimerService(SchedulerInstance.get()), forceAsync); } /** * Multiple calls to this method schedules only once. */ private void scheduleRepeating(int periodMillis) { if (!isScheduled) { timeService.scheduleRepeating(task, 0, periodMillis); isScheduled = true; } } /** * Cancel the schedule runnable */ private void cancel() { if (isScheduled) { timeService.cancel(task); isScheduled = false; } } private void executeQueue() { if (isExecutingQueue) { return; } isExecutingQueue = true; while (queue.size() > 0) { queue.remove(0).execute(); long end = System.currentTimeMillis(); if ((end - timeSliceStart) > timeSliceMs) { break; } } isExecutingQueue = false; } /** * Start execution immediately in the current thread. Calling this multiple * times in the same thread is the same as calling it once in that thread. * Any new commands added via addCommand() afterwards will be ran immediately * if we still have time left on the time slice. */ public void start() { if (timeSliceStart == 0) { timeSliceStart = System.currentTimeMillis(); executeQueue(); } } /** * Try to execute immediately if we have time left. If not, create a deferred executor. */ private void defer() { // Still has some time left in the current time slice if (!forceAsync && (System.currentTimeMillis() - timeSliceStart) < timeSliceMs) { executeQueue(); } scheduleRepeating(1); } /** * Add a command for the queue to execute at a free UI time slice. * @param c */ public void addCommand(Command c) { queue.add(c); defer(); } /** * Stop the execution. */ public void stop() { cancel(); queue.clear(); } /** * @param ms Time slice in millisecond to execute the commands in the queue * before giving the thread back to UI. */ public void setTimeSlice(int ms) { timeSliceMs = ms; } /** @return The size of the queue. */ public int queueSize() { return queue.size(); } }