2 // ========================================================================
3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.io;
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.TimeoutException;
23 import java.util.concurrent.atomic.AtomicReference;
25 import org.eclipse.jetty.util.log.Log;
26 import org.eclipse.jetty.util.log.Logger;
27 import org.eclipse.jetty.util.thread.Scheduler;
30 * An Abstract implementation of an Idle Timeout.
32 * This implementation is optimised that timeout operations are not cancelled on
33 * every operation. Rather timeout are allowed to expire and a check is then made
34 * to see when the last operation took place. If the idle timeout has not expired,
35 * the timeout is rescheduled for the earliest possible time a timeout could occur.
37 public abstract class IdleTimeout
39 private static final Logger LOG = Log.getLogger(IdleTimeout.class);
40 private final Scheduler _scheduler;
41 private final AtomicReference<Scheduler.Task> _timeout = new AtomicReference<>();
42 private volatile long _idleTimeout;
43 private volatile long _idleTimestamp = System.currentTimeMillis();
45 private final Runnable _idleTask = new Runnable()
50 long idleLeft = checkIdleTimeout();
52 scheduleIdleTimeout(idleLeft > 0 ? idleLeft : getIdleTimeout());
57 * @param scheduler A scheduler used to schedule checks for the idle timeout.
59 public IdleTimeout(Scheduler scheduler)
61 _scheduler = scheduler;
64 public long getIdleTimestamp()
66 return _idleTimestamp;
69 public long getIdleTimeout()
74 public void setIdleTimeout(long idleTimeout)
76 long old = _idleTimeout;
77 _idleTimeout = idleTimeout;
79 // Do we have an old timeout
82 // if the old was less than or equal to the new timeout, then nothing more to do
83 if (old <= idleTimeout)
86 // old timeout is too long, so cancel it.
90 // If we have a new timeout, then check and reschedule
96 * This method should be called when non-idle activity has taken place.
100 _idleTimestamp = System.currentTimeMillis();
103 private void scheduleIdleTimeout(long delay)
105 Scheduler.Task newTimeout = null;
106 if (isOpen() && delay > 0 && _scheduler != null)
107 newTimeout = _scheduler.schedule(_idleTask, delay, TimeUnit.MILLISECONDS);
108 Scheduler.Task oldTimeout = _timeout.getAndSet(newTimeout);
109 if (oldTimeout != null)
118 private void activate()
120 if (_idleTimeout > 0)
124 public void onClose()
129 private void deactivate()
131 Scheduler.Task oldTimeout = _timeout.getAndSet(null);
132 if (oldTimeout != null)
136 protected long checkIdleTimeout()
140 long idleTimestamp = getIdleTimestamp();
141 long idleTimeout = getIdleTimeout();
142 long idleElapsed = System.currentTimeMillis() - idleTimestamp;
143 long idleLeft = idleTimeout - idleElapsed;
145 LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft);
147 if (idleTimestamp != 0 && idleTimeout > 0)
151 LOG.debug("{} idle timeout expired", this);
154 onIdleExpired(new TimeoutException("Idle timeout expired: " + idleElapsed + "/" + idleTimeout + " ms"));
163 return idleLeft >= 0 ? idleLeft : 0;
169 * This abstract method is called when the idle timeout has expired.
171 * @param timeout a TimeoutException
173 protected abstract void onIdleExpired(TimeoutException timeout);
176 * This abstract method should be called to check if idle timeouts
177 * should still be checked.
179 * @return True if the entity monitored should still be checked for idle timeouts
181 public abstract boolean isOpen();