--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/jvms/cldc_1.1.1/javasrc/java/util/Timer.java Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,681 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/**
+ * Timer implementation adapted to Java ME from Apache Harmony (Open Source Java SE)
+ * Main changes:
+ * - Java ME finalizer used
+ * - signature test related changes (API to Java 1.3 level)
+ * - some methods made private
+ * - some unsupported method calls commented out
+ * - exception strings hardcoded instead of properties
+ */
+
+package java.util;
+
+import com.nokia.mj.impl.rt.support.Finalizer;
+
+
+/**
+ * {@code Timer}s are used to schedule jobs for execution in a background process. A
+ * single thread is used for the scheduling and this thread has the option of
+ * being a daemon thread. By calling {@code cancel} you can terminate a
+ * {@code Timer} and its associated thread. All tasks which are scheduled to run after
+ * this point are cancelled. Tasks are executed sequentially but are subject to
+ * the delays from other tasks run methods. If a specific task takes an
+ * excessive amount of time to run it may impact the time at which subsequent
+ * tasks may run.
+ * <p>
+ *
+ * The {@code TimerTask} does not offer any guarantees about the real-time nature of
+ * scheduling tasks as its underlying implementation relies on the
+ * {@code Object.wait(long)} method.
+ * <p>
+ * Multiple threads can share a single {@code Timer} without the need for their own
+ * synchronization.
+ * <p>
+ * A {@code Timer} can be set to schedule tasks either at a fixed rate or
+ * with a fixed period. Fixed-period execution is the default.
+ * <p>
+ * The difference between fixed-rate and fixed-period execution
+ * is the following: With fixed-rate execution, the start time of each
+ * successive run of the task is scheduled in absolute terms without regard for when the previous
+ * task run actually took place. This can result in a series of bunched-up runs
+ * (one launched immediately after another) if busy resources or other
+ * system delays prevent the {@code Timer} from firing for an extended time.
+ * With fixed-period execution, each successive run of the
+ * task is scheduled relative to the start time of the previous run of the
+ * task, so two runs of the task are never fired closer together in time than
+ * the specified {@code period}.
+ *
+ * @see TimerTask
+ * @see java.lang.Object#wait(long)
+ */
+public class Timer
+{
+
+ private static final class TimerImpl extends Thread
+ {
+
+ private static final class TimerHeap
+ {
+ private int DEFAULT_HEAP_SIZE = 256;
+
+ private TimerTask[] timers = new TimerTask[DEFAULT_HEAP_SIZE];
+
+ private int size = 0;
+
+ private int deletedCancelledNumber = 0;
+
+ public TimerTask minimum()
+ {
+ return timers[0];
+ }
+
+ public boolean isEmpty()
+ {
+ return size == 0;
+ }
+
+ public void insert(TimerTask task)
+ {
+ if (timers.length == size)
+ {
+ TimerTask[] appendedTimers = new TimerTask[size * 2];
+ System.arraycopy(timers, 0, appendedTimers, 0, size);
+ timers = appendedTimers;
+ }
+ timers[size++] = task;
+ upHeap();
+ }
+
+ public void delete(int pos)
+ {
+ // posible to delete any position of the heap
+ if (pos >= 0 && pos < size)
+ {
+ timers[pos] = timers[--size];
+ timers[size] = null;
+ downHeap(pos);
+ }
+ }
+
+ private void upHeap()
+ {
+ int current = size - 1;
+ int parent = (current - 1) / 2;
+
+ while (timers[current].when < timers[parent].when)
+ {
+ // swap the two
+ TimerTask tmp = timers[current];
+ timers[current] = timers[parent];
+ timers[parent] = tmp;
+
+ // update pos and current
+ current = parent;
+ parent = (current - 1) / 2;
+ }
+ }
+
+ private void downHeap(int pos)
+ {
+ int current = pos;
+ int child = 2 * current + 1;
+
+ while (child < size && size > 0)
+ {
+ // compare the children if they exist
+ if (child + 1 < size
+ && timers[child + 1].when < timers[child].when)
+ {
+ child++;
+ }
+
+ // compare selected child with parent
+ if (timers[current].when < timers[child].when)
+ {
+ break;
+ }
+
+ // swap the two
+ TimerTask tmp = timers[current];
+ timers[current] = timers[child];
+ timers[child] = tmp;
+
+ // update pos and current
+ current = child;
+ child = 2 * current + 1;
+ }
+ }
+
+ public void reset()
+ {
+ timers = new TimerTask[DEFAULT_HEAP_SIZE];
+ size = 0;
+ }
+
+ public void adjustMinimum()
+ {
+ downHeap(0);
+ }
+
+ public void deleteIfCancelled()
+ {
+ for (int i = 0; i < size; i++)
+ {
+ if (timers[i].cancelled)
+ {
+ deletedCancelledNumber++;
+ delete(i);
+ // re-try this point
+ i--;
+ }
+ }
+ }
+
+ private int getTask(TimerTask task)
+ {
+ for (int i = 0; i < timers.length; i++)
+ {
+ if (timers[i] == task)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ }
+
+ /**
+ * True if the method cancel() of the Timer was called or the !!!stop()
+ * method was invoked
+ */
+ private boolean cancelled;
+
+ /**
+ * True if the Timer has become garbage
+ */
+ private boolean finished;
+
+ /**
+ * Vector consists of scheduled events, sorted according to
+ * {@code when} field of TaskScheduled object.
+ */
+ private TimerHeap tasks = new TimerHeap();
+
+ /**
+ * Starts a new timer.
+ *
+ * @param name thread's name
+ * @param isDaemon daemon thread or not
+ */
+ TimerImpl(String name, boolean isDaemon)
+ {
+ // not supported in Java ME
+ /*
+ this.setName(name);
+ this.setDaemon(isDaemon);
+ */
+ this.start();
+ }
+
+ /**
+ * This method will be launched on separate thread for each Timer
+ * object.
+ */
+ //@Override
+ public void run()
+ {
+ while (true)
+ {
+ TimerTask task;
+ synchronized (this)
+ {
+ // need to check cancelled inside the synchronized block
+ if (cancelled)
+ {
+ return;
+ }
+ if (tasks.isEmpty())
+ {
+ if (finished)
+ {
+ return;
+ }
+ // no tasks scheduled -- sleep until any task appear
+ try
+ {
+ this.wait();
+ }
+ catch (InterruptedException e)
+ {
+ }
+ continue;
+ }
+
+ long currentTime = System.currentTimeMillis();
+
+ task = tasks.minimum();
+ long timeToSleep;
+
+ synchronized (task.lock)
+ {
+ if (task.cancelled)
+ {
+ tasks.delete(0);
+ continue;
+ }
+
+ // check the time to sleep for the first task scheduled
+ timeToSleep = task.when - currentTime;
+ }
+
+ if (timeToSleep > 0)
+ {
+ // sleep!
+ try
+ {
+ this.wait(timeToSleep);
+ }
+ catch (InterruptedException e)
+ {
+ // Ignored
+ }
+ continue;
+ }
+
+ // no sleep is necessary before launching the task
+
+ synchronized (task.lock)
+ {
+ int pos = 0;
+ if (tasks.minimum().when != task.when)
+ {
+ pos = tasks.getTask(task);
+ }
+ if (task.cancelled)
+ {
+ tasks.delete(tasks.getTask(task));
+ continue;
+ }
+
+ // set time to schedule
+ task.setScheduledTime(task.when);
+
+ // remove task from queue
+ tasks.delete(pos);
+
+ // set when the next task should be launched
+ if (task.period >= 0)
+ {
+ // this is a repeating task,
+ if (task.fixedRate)
+ {
+ // task is scheduled at fixed rate
+ task.when = task.when + task.period;
+ }
+ else
+ {
+ // task is scheduled at fixed delay
+ task.when = System.currentTimeMillis()
+ + task.period;
+ }
+
+ // insert this task into queue
+ insertTask(task);
+ }
+ else
+ {
+ task.when = 0;
+ }
+ }
+ }
+
+ // run the task
+ task.run(); // we want that unhandled exception goes through
+ /*
+ try {
+ task.run();
+ } catch (Exception e) {
+ // Ignored
+ }
+ */
+ }
+ }
+
+ private void insertTask(TimerTask newTask)
+ {
+ // callers are synchronized
+ tasks.insert(newTask);
+ this.notify();
+ }
+
+ /**
+ * Cancels timer.
+ */
+ public synchronized void cancel()
+ {
+ cancelled = true;
+ tasks.reset();
+ this.notify();
+ }
+
+ public int purge()
+ {
+ if (tasks.isEmpty())
+ {
+ return 0;
+ }
+ // callers are synchronized
+ tasks.deletedCancelledNumber = 0;
+ tasks.deleteIfCancelled();
+ return tasks.deletedCancelledNumber;
+ }
+
+ }
+
+ // Used to finalize thread
+ private Finalizer finalizer = new Finalizer()
+ {
+ public void finalizeImpl()
+ {
+ doFinalize();
+ }
+ };
+ private void doFinalize()
+ {
+ synchronized (impl)
+ {
+ impl.finished = true;
+ impl.notify();
+ }
+ }
+
+ private static long timerId;
+
+ private synchronized static long nextId()
+ {
+ return timerId++;
+ }
+
+ /* This object will be used in synchronization purposes */
+ private final TimerImpl impl;
+
+ /**
+ * Creates a new named {@code Timer} which may be specified to be run as a
+ * daemon thread.
+ *
+ * @param name the name of the {@code Timer}.
+ * @param isDaemon true if {@code Timer}'s thread should be a daemon thread.
+ * @throws NullPointerException is {@code name} is {@code null}
+ */
+ private Timer(String name, boolean isDaemon)
+ {
+ super();
+ if (name == null)
+ {
+ throw new NullPointerException("name is null");
+ }
+ this.impl = new TimerImpl(name, isDaemon);
+ }
+
+ /**
+ * Creates a new named {@code Timer} which does not run as a daemon thread.
+ *
+ * @param name the name of the Timer.
+ * @throws NullPointerException is {@code name} is {@code null}
+ */
+ private Timer(String name)
+ {
+ this(name, false);
+ }
+
+ /**
+ * Creates a new {@code Timer} which may be specified to be run as a daemon thread.
+ *
+ * @param isDaemon {@code true} if the {@code Timer}'s thread should be a daemon thread.
+ */
+ private Timer(boolean isDaemon)
+ {
+ this("Timer-" + Timer.nextId(), isDaemon);
+ }
+
+ /**
+ * Creates a new non-daemon {@code Timer}.
+ */
+ public Timer()
+ {
+ this(false);
+ }
+
+ /**
+ * Cancels the {@code Timer} and removes any scheduled tasks. If there is a
+ * currently running task it is not affected. No more tasks may be scheduled
+ * on this {@code Timer}. Subsequent calls do nothing.
+ */
+ public void cancel()
+ {
+ impl.cancel();
+ }
+
+ /**
+ * Removes all canceled tasks from the task queue. If there are no
+ * other references on the tasks, then after this call they are free
+ * to be garbage collected.
+ *
+ * @return the number of canceled tasks that were removed from the task
+ * queue.
+ */
+ private int purge()
+ {
+ synchronized (impl)
+ {
+ return impl.purge();
+ }
+ }
+
+ /**
+ * Schedule a task for single execution. If {@code when} is less than the
+ * current time, it will be scheduled to be executed as soon as possible.
+ *
+ * @param task
+ * the task to schedule.
+ * @param when
+ * time of execution.
+ * @throws IllegalArgumentException
+ * if {@code when.getTime() < 0}.
+ * @throws IllegalStateException
+ * if the {@code Timer} has been canceled, or if the task has been
+ * scheduled or canceled.
+ */
+ public void schedule(TimerTask task, Date when)
+ {
+ if (when.getTime() < 0)
+ {
+ throw new IllegalArgumentException();
+ }
+ long delay = when.getTime() - System.currentTimeMillis();
+ scheduleImpl(task, delay < 0 ? 0 : delay, -1, false);
+ }
+
+ /**
+ * Schedule a task for single execution after a specified delay.
+ *
+ * @param task
+ * the task to schedule.
+ * @param delay
+ * amount of time in milliseconds before execution.
+ * @throws IllegalArgumentException
+ * if {@code delay < 0}.
+ * @throws IllegalStateException
+ * if the {@code Timer} has been canceled, or if the task has been
+ * scheduled or canceled.
+ */
+ public void schedule(TimerTask task, long delay)
+ {
+ if (delay < 0)
+ {
+ throw new IllegalArgumentException();
+ }
+ scheduleImpl(task, delay, -1, false);
+ }
+
+ /**
+ * Schedule a task for repeated fixed-delay execution after a specific delay.
+ *
+ * @param task
+ * the task to schedule.
+ * @param delay
+ * amount of time in milliseconds before first execution.
+ * @param period
+ * amount of time in milliseconds between subsequent executions.
+ * @throws IllegalArgumentException
+ * if {@code delay < 0} or {@code period < 0}.
+ * @throws IllegalStateException
+ * if the {@code Timer} has been canceled, or if the task has been
+ * scheduled or canceled.
+ */
+ public void schedule(TimerTask task, long delay, long period)
+ {
+ if (delay < 0 || period <= 0)
+ {
+ throw new IllegalArgumentException();
+ }
+ scheduleImpl(task, delay, period, false);
+ }
+
+ /**
+ * Schedule a task for repeated fixed-delay execution after a specific time
+ * has been reached.
+ *
+ * @param task
+ * the task to schedule.
+ * @param when
+ * time of first execution.
+ * @param period
+ * amount of time in milliseconds between subsequent executions.
+ * @throws IllegalArgumentException
+ * if {@code when.getTime() < 0} or {@code period < 0}.
+ * @throws IllegalStateException
+ * if the {@code Timer} has been canceled, or if the task has been
+ * scheduled or canceled.
+ */
+ public void schedule(TimerTask task, Date when, long period)
+ {
+ if (period <= 0 || when.getTime() < 0)
+ {
+ throw new IllegalArgumentException();
+ }
+ long delay = when.getTime() - System.currentTimeMillis();
+ scheduleImpl(task, delay < 0 ? 0 : delay, period, false);
+ }
+
+ /**
+ * Schedule a task for repeated fixed-rate execution after a specific delay
+ * has passed.
+ *
+ * @param task
+ * the task to schedule.
+ * @param delay
+ * amount of time in milliseconds before first execution.
+ * @param period
+ * amount of time in milliseconds between subsequent executions.
+ * @throws IllegalArgumentException
+ * if {@code delay < 0} or {@code period < 0}.
+ * @throws IllegalStateException
+ * if the {@code Timer} has been canceled, or if the task has been
+ * scheduled or canceled.
+ */
+ public void scheduleAtFixedRate(TimerTask task, long delay, long period)
+ {
+ if (delay < 0 || period <= 0)
+ {
+ throw new IllegalArgumentException();
+ }
+ scheduleImpl(task, delay, period, true);
+ }
+
+ /**
+ * Schedule a task for repeated fixed-rate execution after a specific time
+ * has been reached.
+ *
+ * @param task
+ * the task to schedule.
+ * @param when
+ * time of first execution.
+ * @param period
+ * amount of time in milliseconds between subsequent executions.
+ * @throws IllegalArgumentException
+ * if {@code when.getTime() < 0} or {@code period < 0}.
+ * @throws IllegalStateException
+ * if the {@code Timer} has been canceled, or if the task has been
+ * scheduled or canceled.
+ */
+ public void scheduleAtFixedRate(TimerTask task, Date when, long period)
+ {
+ if (period <= 0 || when.getTime() < 0)
+ {
+ throw new IllegalArgumentException();
+ }
+ long delay = when.getTime() - System.currentTimeMillis();
+ scheduleImpl(task, delay < 0 ? 0 : delay, period, true);
+ }
+
+ /*
+ * Schedule a task.
+ */
+ private void scheduleImpl(TimerTask task, long delay, long period,
+ boolean fixed)
+ {
+ synchronized (impl)
+ {
+ if (impl.cancelled)
+ {
+ throw new IllegalStateException("Timer is cancelled");
+ }
+
+ long when = delay + System.currentTimeMillis();
+
+ if (when < 0)
+ {
+ throw new IllegalArgumentException("Illegal delay to start TimerTask");
+ }
+
+ synchronized (task.lock)
+ {
+ if (task.isScheduled())
+ {
+ throw new IllegalStateException("TimerTask is already scheduled");
+ }
+
+ if (task.cancelled)
+ {
+ throw new IllegalStateException("TimerTask is cancelled");
+ }
+
+ task.when = when;
+ task.period = period;
+ task.fixedRate = fixed;
+ }
+
+ // insert the newTask into queue
+ impl.insertTask(task);
+ }
+ }
+}