001: package dalma.endpoints.timer;
002:
003: import dalma.Condition;
004: import dalma.TimeUnit;
005: import dalma.impl.EndPointImpl;
006: import dalma.spi.ConversationSPI;
007: import dalma.spi.EngineSPI;
008: import dalma.spi.FiberSPI;
009:
010: import java.util.Date;
011: import java.util.Timer;
012: import java.util.TimerTask;
013: import java.util.ArrayList;
014: import java.util.List;
015:
016: /**
017: * EndPoint that waits for some time to pass.
018: *
019: * <p>
020: * The {@link #createDock(Date)} method can return a {@link Condition} of an
021: * arbitrary type, because it always return null. This works better when
022: * timer is used with other {@link Condition}s.
023: *
024: * @author Kohsuke Kawaguchi
025: */
026: public class TimerEndPoint extends EndPointImpl {
027:
028: private Timer timer;
029:
030: /**
031: * Timers that were queued while the endpoint is stopped.
032: */
033: private List<TimerCondition> queuedConditions = new ArrayList<TimerCondition>();
034:
035: public TimerEndPoint() {
036: super (TimerEndPoint.class.getName());
037: }
038:
039: private final class TimerCondition<T> extends Condition<T> {
040: /**
041: * The date when the conversation should be activated.
042: */
043: private final Date dt;
044:
045: /**
046: *
047: * Transient because this field is only used when the timer is in memory.
048: */
049: private transient TimerTaskImpl task;
050:
051: public TimerCondition(Date dt) {
052: assert dt != null;
053: this .dt = dt;
054: }
055:
056: public void onParked() {
057: assert task == null;
058: task = new TimerTaskImpl();
059: synchronized (TimerEndPoint.this ) {
060: if (timer == null)
061: queuedConditions.add(this );
062: else
063: timer.schedule(task, dt);
064: }
065: }
066:
067: public void onLoad() {
068: onParked();
069: }
070:
071: public void interrupt() {
072: assert task != null;
073: task.cancel();
074: task = null;
075: }
076:
077: private final class TimerTaskImpl extends TimerTask {
078: public void run() {
079: TimerCondition.this .activate(null);
080: }
081: }
082: }
083:
084: protected synchronized void start() {
085: timer = new Timer(true);
086: for (TimerCondition tc : queuedConditions)
087: timer.schedule(tc.task, tc.dt);
088: queuedConditions.clear();
089: }
090:
091: protected synchronized void stop() {
092: timer.cancel();
093: timer = null;
094: }
095:
096: /**
097: * Wait for an user input.
098: */
099: // this method is invoked from conversations
100: public static void waitFor(long delay, TimeUnit unit) {
101: FiberSPI.currentFiber(true).suspend(createDock(delay, unit));
102: }
103:
104: public static void waitFor(Date dt) {
105: FiberSPI.currentFiber(true).suspend(createDock(dt));
106: }
107:
108: public static <T> Condition<T> createDock(Date dt) {
109: EngineSPI engine = ConversationSPI.currentConversation()
110: .getEngine();
111:
112: TimerEndPoint ep = (TimerEndPoint) engine
113: .getEndPoint(TimerEndPoint.class.getName());
114: if (ep == null) {
115: throw new IllegalStateException(
116: "TimerEndPoint was not added to the engine");
117: }
118: return ep.new TimerCondition<T>(dt);
119: }
120:
121: public static <T> Condition<T> createDock(long delay, TimeUnit unit) {
122: return createDock(unit.fromNow(delay));
123: }
124: }
|