]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/io/IdleTimeout.java
updating jetty to jetty-9.2.16.v2016040
[gigi.git] / lib / jetty / org / eclipse / jetty / io / IdleTimeout.java
1 //
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.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.io;
20
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.TimeoutException;
23 import java.util.concurrent.atomic.AtomicReference;
24
25 import org.eclipse.jetty.util.log.Log;
26 import org.eclipse.jetty.util.log.Logger;
27 import org.eclipse.jetty.util.thread.Scheduler;
28
29 /**
30  * An Abstract implementation of an Idle Timeout.
31  * <p/>
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.
36  */
37 public abstract class IdleTimeout
38 {
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();
44
45     private final Runnable _idleTask = new Runnable()
46     {
47         @Override
48         public void run()
49         {
50             long idleLeft = checkIdleTimeout();
51             if (idleLeft >= 0)
52                 scheduleIdleTimeout(idleLeft > 0 ? idleLeft : getIdleTimeout());
53         }
54     };
55
56     /**
57      * @param scheduler A scheduler used to schedule checks for the idle timeout.
58      */
59     public IdleTimeout(Scheduler scheduler)
60     {
61         _scheduler = scheduler;
62     }
63
64     public long getIdleTimestamp()
65     {
66         return _idleTimestamp;
67     }
68
69     public long getIdleFor()
70     {
71         return System.currentTimeMillis() - getIdleTimestamp();
72     }
73
74     public long getIdleTimeout()
75     {
76         return _idleTimeout;
77     }
78
79     public void setIdleTimeout(long idleTimeout)
80     {
81         long old = _idleTimeout;
82         _idleTimeout = idleTimeout;
83
84         // Do we have an old timeout
85         if (old > 0)
86         {
87             // if the old was less than or equal to the new timeout, then nothing more to do
88             if (old <= idleTimeout)
89                 return;
90
91             // old timeout is too long, so cancel it.
92             deactivate();
93         }
94
95         // If we have a new timeout, then check and reschedule
96         if (isOpen())
97             activate();
98     }
99
100     /**
101      * This method should be called when non-idle activity has taken place.
102      */
103     public void notIdle()
104     {
105         _idleTimestamp = System.currentTimeMillis();
106     }
107
108     private void scheduleIdleTimeout(long delay)
109     {
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)
115             oldTimeout.cancel();
116     }
117
118     public void onOpen()
119     {
120         activate();
121     }
122
123     private void activate()
124     {
125         if (_idleTimeout > 0)
126             _idleTask.run();
127     }
128
129     public void onClose()
130     {
131         deactivate();
132     }
133
134     private void deactivate()
135     {
136         Scheduler.Task oldTimeout = _timeout.getAndSet(null);
137         if (oldTimeout != null)
138             oldTimeout.cancel();
139     }
140
141     protected long checkIdleTimeout()
142     {
143         if (isOpen())
144         {
145             long idleTimestamp = getIdleTimestamp();
146             long idleTimeout = getIdleTimeout();
147             long idleElapsed = System.currentTimeMillis() - idleTimestamp;
148             long idleLeft = idleTimeout - idleElapsed;
149
150             if (LOG.isDebugEnabled())
151                 LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft);
152
153             if (idleTimestamp != 0 && idleTimeout > 0)
154             {
155                 if (idleLeft <= 0)
156                 {
157                     if (LOG.isDebugEnabled())
158                         LOG.debug("{} idle timeout expired", this);
159                     try
160                     {
161                         onIdleExpired(new TimeoutException("Idle timeout expired: " + idleElapsed + "/" + idleTimeout + " ms"));
162                     }
163                     finally
164                     {
165                         notIdle();
166                     }
167                 }
168             }
169
170             return idleLeft >= 0 ? idleLeft : 0;
171         }
172         return -1;
173     }
174
175     /**
176      * This abstract method is called when the idle timeout has expired.
177      *
178      * @param timeout a TimeoutException
179      */
180     protected abstract void onIdleExpired(TimeoutException timeout);
181
182     /**
183      * This abstract method should be called to check if idle timeouts
184      * should still be checked.
185      *
186      * @return True if the entity monitored should still be checked for idle timeouts
187      */
188     public abstract boolean isOpen();
189 }