001/*
002 * This file is part of the Kompics component model runtime.
003 * <p>
004 * Copyright (C) 2009 Swedish Institute of Computer Science (SICS)
005 * Copyright (C) 2009 Royal Institute of Technology (KTH)
006 *
007 * Kompics is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU General Public License
009 * as published by the Free Software Foundation; either version 2
010 * of the License, or (at your option) any later version.
011 *
012 * This program is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with this program; if not, write to the Free Software
019 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020 */
021package se.sics.kompics.timer.java;
022
023import java.util.HashMap;
024import java.util.UUID;
025import org.slf4j.Logger;
026import se.sics.kompics.ComponentDefinition;
027import se.sics.kompics.Handler;
028import se.sics.kompics.Negative;
029import se.sics.kompics.timer.CancelPeriodicTimeout;
030import se.sics.kompics.timer.CancelTimeout;
031import se.sics.kompics.timer.SchedulePeriodicTimeout;
032import se.sics.kompics.timer.ScheduleTimeout;
033import se.sics.kompics.timer.Timeout;
034import se.sics.kompics.timer.Timer;
035
036/**
037 * The <code>JavaTimer</code> class.
038 * <p>
039 * 
040 * @author Cosmin Arad {@literal <[email protected]>}
041 * @author Jim Dowling {@literal <[email protected]>}
042 * @version $Id$
043 */
044public final class JavaTimer extends ComponentDefinition {
045
046    Negative<Timer> timer = negative(Timer.class);
047
048    final Logger extLogger = this.logger;
049
050    // set of active timers
051    private final HashMap<UUID, TimerSignalTask> activeTimers;
052
053    // set of active periodic timers
054    private final HashMap<UUID, PeriodicTimerSignalTask> activePeriodicTimers;
055
056    private final java.util.Timer javaTimer;
057    private final JavaTimer timerComponent;
058
059    /**
060     * Instantiates a new java timer.
061     */
062    public JavaTimer() {
063        this.activeTimers = new HashMap<UUID, TimerSignalTask>();
064        this.activePeriodicTimers = new HashMap<UUID, PeriodicTimerSignalTask>();
065        this.javaTimer = new java.util.Timer("JavaTimer@" + Integer.toHexString(this.hashCode()), true);
066        timerComponent = this;
067
068        subscribe(handleST, timer);
069        subscribe(handleSPT, timer);
070        subscribe(handleCT, timer);
071        subscribe(handleCPT, timer);
072    }
073
074    Handler<ScheduleTimeout> handleST = new Handler<ScheduleTimeout>() {
075        public void handle(ScheduleTimeout event) {
076            UUID id = event.getTimeoutEvent().getTimeoutId();
077
078            TimerSignalTask timeOutTask = new TimerSignalTask(timerComponent, event.getTimeoutEvent(), id);
079
080            synchronized (activeTimers) {
081                activeTimers.put(id, timeOutTask);
082            }
083            try {
084                javaTimer.schedule(timeOutTask, event.getDelay());
085                logger.debug("scheduled timer({}) {}", event.getDelay(), timeOutTask.timeout);
086            } catch (IllegalStateException e) {
087                logger.error("Could not schedule timer {}.", event.getDelay(), timeOutTask.timeout);
088                e.printStackTrace();
089            }
090        }
091    };
092
093    Handler<SchedulePeriodicTimeout> handleSPT = new Handler<SchedulePeriodicTimeout>() {
094        public void handle(SchedulePeriodicTimeout event) {
095            UUID id = event.getTimeoutEvent().getTimeoutId();
096
097            PeriodicTimerSignalTask timeOutTask = new PeriodicTimerSignalTask(event.getTimeoutEvent(), timerComponent);
098
099            synchronized (activePeriodicTimers) {
100                activePeriodicTimers.put(id, timeOutTask);
101            }
102            javaTimer.scheduleAtFixedRate(timeOutTask, event.getDelay(), event.getPeriod());
103            logger.debug("scheduled periodic timer({}, {}) {}",
104                    new Object[] { event.getDelay(), event.getPeriod(), timeOutTask.timeout });
105        }
106    };
107
108    Handler<CancelTimeout> handleCT = new Handler<CancelTimeout>() {
109        public void handle(CancelTimeout event) {
110            UUID id = event.getTimeoutId();
111
112            TimerSignalTask task = null;
113            synchronized (activeTimers) {
114                task = activeTimers.get(id);
115                if (task != null) {
116                    task.cancel();
117                    activeTimers.remove(id);
118                    logger.debug("canceled timer {}", task.timeout);
119                }
120            }
121        }
122    };
123
124    Handler<CancelPeriodicTimeout> handleCPT = new Handler<CancelPeriodicTimeout>() {
125        public void handle(CancelPeriodicTimeout event) {
126            UUID id = event.getTimeoutId();
127
128            PeriodicTimerSignalTask task = null;
129            task = activePeriodicTimers.get(id);
130            if (task != null) {
131                task.cancel();
132                activePeriodicTimers.remove(id);
133                logger.debug("canceled periodic timer {}", task.timeout);
134            }
135
136        }
137    };
138
139    // called by the timeout task
140    /**
141     * Timeout.
142     * <p>
143     * 
144     * @param timerId
145     *            the timer id
146     * @param timeout
147     *            the timeout
148     */
149    final void timeout(UUID timerId, Timeout timeout) {
150        synchronized (activeTimers) {
151            activeTimers.remove(timerId);
152        }
153        logger.debug("trigger timeout {}", timeout);
154        trigger(timeout, timer);
155    }
156
157    // called by the periodic timeout task
158    /**
159     * Periodic timeout.
160     * <p>
161     * 
162     * @param timeout
163     *            the timeout
164     */
165    final void periodicTimeout(Timeout timeout) {
166        logger.debug("trigger periodic timeout {}", timeout);
167        trigger(timeout, timer);
168    }
169
170    @Override
171    public void tearDown() {
172        synchronized (activeTimers) {
173            for (TimerSignalTask tst : activeTimers.values()) {
174                tst.cancel();
175            }
176            activeTimers.clear();
177        }
178        for (PeriodicTimerSignalTask ptst : activePeriodicTimers.values()) {
179            ptst.cancel();
180        }
181        activePeriodicTimers.clear();
182        javaTimer.cancel();
183    }
184}