2 // ========================================================================
3 // Copyright (c) 1995-2016 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 getIdleFor()
71 return System.currentTimeMillis() - getIdleTimestamp();
74 public long getIdleTimeout()
79 public void setIdleTimeout(long idleTimeout)
81 long old = _idleTimeout;
82 _idleTimeout = idleTimeout;
84 // Do we have an old timeout
87 // if the old was less than or equal to the new timeout, then nothing more to do
88 if (old <= idleTimeout)
91 // old timeout is too long, so cancel it.
95 // If we have a new timeout, then check and reschedule
101 * This method should be called when non-idle activity has taken place.
103 public void notIdle()
105 _idleTimestamp = System.currentTimeMillis();
108 private void scheduleIdleTimeout(long delay)
110 Scheduler.Task newTimeout = null;
111 if (isOpen() && delay > 0 && _scheduler != null)
112 newTimeout = _scheduler.schedule(_idleTask, delay, TimeUnit.MILLISECONDS);
113 Scheduler.Task oldTimeout = _timeout.getAndSet(newTimeout);
114 if (oldTimeout != null)
123 private void activate()
125 if (_idleTimeout > 0)
129 public void onClose()
134 private void deactivate()
136 Scheduler.Task oldTimeout = _timeout.getAndSet(null);
137 if (oldTimeout != null)
141 protected long checkIdleTimeout()
145 long idleTimestamp = getIdleTimestamp();
146 long idleTimeout = getIdleTimeout();
147 long idleElapsed = System.currentTimeMillis() - idleTimestamp;
148 long idleLeft = idleTimeout - idleElapsed;
150 if (LOG.isDebugEnabled())
151 LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft);
153 if (idleTimestamp != 0 && idleTimeout > 0)
157 if (LOG.isDebugEnabled())
158 LOG.debug("{} idle timeout expired", this);
161 onIdleExpired(new TimeoutException("Idle timeout expired: " + idleElapsed + "/" + idleTimeout + " ms"));
170 return idleLeft >= 0 ? idleLeft : 0;
176 * This abstract method is called when the idle timeout has expired.
178 * @param timeout a TimeoutException
180 protected abstract void onIdleExpired(TimeoutException timeout);
183 * This abstract method should be called to check if idle timeouts
184 * should still be checked.
186 * @return True if the entity monitored should still be checked for idle timeouts
188 public abstract boolean isOpen();