001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Michael Danilov
019: * @version $Revision$
020: */package org.apache.harmony.awt;
021:
022: import java.util.Iterator;
023: import java.util.LinkedList;
024:
025: import org.apache.harmony.awt.internal.nls.Messages;
026:
027: /**
028: * Relative timer class. Basic class for PeriodicTimer and SingleShotTimer.
029: * "Relative" means that there is no binding with absolute time.
030: * All future events are planned relative to current time.
031: * All timers live on one thread.
032: */
033: public abstract class RelativeTimer {
034:
035: private static final DeltaList deltaList = new DeltaList();
036:
037: final long interval;
038: final Runnable handler;
039:
040: private DeltaListEntry deltaEntry;
041:
042: RelativeTimer(long interval, Runnable handler) {
043: if (interval <= 0) {
044: // awt.52=Time interval can't be <= 0
045: throw new IllegalArgumentException(Messages
046: .getString("awt.52")); //$NON-NLS-1$
047: }
048: if (handler == null) {
049: // awt.53=Handler can't be null
050: throw new IllegalArgumentException(Messages
051: .getString("awt.53")); //$NON-NLS-1$
052: }
053:
054: this .interval = interval;
055: this .handler = handler;
056: deltaEntry = null;
057: }
058:
059: /**
060: * Gets handler for this timer's events.
061: *
062: * @return this timer's handler.
063: */
064: public Runnable getHandler() {
065: return handler;
066: }
067:
068: /**
069: * Starts ticking of this timer.
070: * Time when timer's handler is invoked first time is following:
071: * current_time + interval.
072: */
073: public void start() {
074: synchronized (deltaList) {
075: if (isRunning()) {
076: return;
077: }
078:
079: deltaEntry = new DeltaListEntry();
080: deltaList.add(deltaEntry);
081: }
082: }
083:
084: /**
085: * Stops ticking of this timer.
086: */
087: public void stop() {
088: synchronized (deltaList) {
089: if (!isRunning()) {
090: return;
091: }
092:
093: deltaList.remove(deltaEntry);
094: deltaEntry = null;
095: }
096: }
097:
098: /**
099: * Returns true if this timer is ticking.
100: */
101: public boolean isRunning() {
102: return (deltaEntry != null);
103: }
104:
105: void handle() {
106: handler.run();
107: }
108:
109: private class DeltaListEntry {
110:
111: long time;
112: boolean stopped;
113:
114: DeltaListEntry() {
115: charge();
116: stopped = false;
117: }
118:
119: void handle() {
120: RelativeTimer.this .handle();
121: if (!stopped) {
122: charge();
123: }
124: }
125:
126: private void charge() {
127: time = System.currentTimeMillis() + interval;
128: }
129:
130: }
131:
132: private static class DeltaList {
133:
134: private final LinkedList<DeltaListEntry> list;
135: private DeltaThread thread;
136: private long time;
137:
138: DeltaList() {
139: list = new LinkedList<DeltaListEntry>();
140: time = 0;
141: thread = null;
142: }
143:
144: void add(DeltaListEntry entry) {
145: if (list.isEmpty()) {
146: time = Long.MAX_VALUE;
147: insert(entry, false);
148: thread = new DeltaThread();
149: thread.setName("Relative Timer"); //$NON-NLS-1$
150: thread.setDaemon(true);
151: thread.start();
152: } else {
153: insert(entry, true);
154: }
155: }
156:
157: void remove(DeltaListEntry entry) {
158: if (Thread.currentThread() == thread) {
159: if (list.contains(entry)) {
160: removeNotLast(entry);
161: } else {
162: entry.stopped = true;
163: }
164: } else {
165: if (list.size() == 1) {
166: list.clear();
167: thread.interrupt();
168: } else {
169: removeNotLast(entry);
170: }
171: }
172: }
173:
174: private void removeNotLast(DeltaListEntry entry) {
175: int index = list.indexOf(entry);
176:
177: list.remove(entry);
178: if (index != list.size()) {
179: if (index == 0) {
180: firstRemoved();
181: } else {
182: list.get(index).time += entry.time;
183: }
184: }
185: }
186:
187: private void loop() {
188: synchronized (this ) {
189: while (!list.isEmpty()) {
190: long delay = time - System.currentTimeMillis();
191:
192: if (delay > 0) {
193: try {
194: wait(delay);
195: } catch (InterruptedException e) {
196: if (list.isEmpty()) {
197: break;
198: }
199: }
200: }
201:
202: handle();
203: }
204: }
205: time = 0;
206: thread = null;
207: }
208:
209: private void handle() {
210: long curTime = System.currentTimeMillis();
211:
212: if (time <= curTime) {
213: while (list.getFirst().time <= curTime) {
214: DeltaListEntry first = list.removeFirst();
215:
216: if (!list.isEmpty()) {
217: firstRemoved();
218: }
219: try {
220: first.handle();
221: } catch (Throwable t) {
222: t.printStackTrace();
223: }
224: if (!first.stopped) {
225: insert(first, false);
226: } else if (list.isEmpty()) {
227: break;
228: }
229: }
230: }
231: }
232:
233: private void firstRemoved() {
234: DeltaListEntry nextFirst = list.getFirst();
235:
236: time += nextFirst.time;
237: nextFirst.time = time;
238: }
239:
240: private void insert(DeltaListEntry entry, boolean interrupt) {
241: long oldTime = list.isEmpty() ? Long.MAX_VALUE : time;
242: Iterator<DeltaListEntry> i = list.iterator();
243:
244: do {
245: if (!i.hasNext()) {
246: list.addLast(entry);
247: break;
248: }
249: DeltaListEntry next = i.next();
250:
251: if (next.time <= entry.time) {
252: entry.time -= next.time;
253: } else {
254: next.time -= entry.time;
255: list.add(list.indexOf(next), entry);
256: break;
257: }
258: } while (true);
259:
260: time = list.getFirst().time;
261: if ((time < oldTime) && interrupt) {
262: thread.interrupt();
263: }
264: }
265:
266: private class DeltaThread extends Thread {
267: @Override
268: public void run() {
269: loop();
270: }
271: };
272: }
273: }
|