View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.core.service;
21  
22  import org.apache.mina.core.session.IdleStatus;
23  
24  /**
25   * Provides the idle state information associated with an {@link AbstractIoService}.
26   * 
27   * @author The Apache MINA Project (dev@mina.apache.org)
28   * @version $Rev$, $Date$
29   * @since 2.0.0-M3
30   */
31  public class IoServiceIdleState {
32  
33      private AbstractIoService service;
34      
35      private int idleTimeForRead;
36      private int idleTimeForWrite;
37      private int idleTimeForBoth;
38  
39      private int idleCountForBoth;
40      private int idleCountForRead;
41      private int idleCountForWrite;
42  
43      private long lastIdleTimeForBoth;
44      private long lastIdleTimeForRead;
45      private long lastIdleTimeForWrite;
46  
47      private final Object idlenessCheckLock = new Object();
48  
49      public IoServiceIdleState(AbstractIoService service) {
50          this.service = service;
51      }
52  
53      /**
54       * Returns <code>true</code> if this service is idle for the specified
55       * {@link IdleStatus}.
56       */
57      public final boolean isIdle(IdleStatus status) {
58          if (status == IdleStatus.BOTH_IDLE) {
59              return idleCountForBoth > 0;
60          }
61  
62          if (status == IdleStatus.READER_IDLE) {
63              return idleCountForRead > 0;
64          }
65  
66          if (status == IdleStatus.WRITER_IDLE) {
67              return idleCountForWrite > 0;
68          }
69  
70          throw new IllegalArgumentException("Unknown idle status: " + status);
71      }
72  
73      /**
74       * Returns <code>true</code> if this service is {@link IdleStatus#READER_IDLE}.
75       * @see #isIdle(IdleStatus)
76       */
77      public final boolean isReaderIdle() {
78          return isIdle(IdleStatus.READER_IDLE);
79      }
80  
81      /**
82       * Returns <code>true</code> if this service is {@link IdleStatus#WRITER_IDLE}.
83       * @see #isIdle(IdleStatus)
84       */
85      public final boolean isWriterIdle() {
86          return isIdle(IdleStatus.WRITER_IDLE);
87      }
88  
89      /**
90       * Returns <code>true</code> if this service is {@link IdleStatus#BOTH_IDLE}.
91       * @see #isIdle(IdleStatus)
92       */
93      public final boolean isBothIdle() {
94          return isIdle(IdleStatus.BOTH_IDLE);
95      }
96  
97      /**
98       * Returns the number of the fired continuous <tt>serviceIdle</tt> events
99       * for the specified {@link IdleStatus}.
100      * <p/>
101      * If <tt>serviceIdle</tt> event is fired first after some time after I/O,
102      * <tt>idleCount</tt> becomes <tt>1</tt>.  <tt>idleCount</tt> resets to
103      * <tt>0</tt> if any I/O occurs again, otherwise it increases to
104      * <tt>2</tt> and so on if <tt>serviceIdle</tt> event is fired again without
105      * any I/O between two (or more) <tt>serviceIdle</tt> events.
106      */
107     public final int getIdleCount(IdleStatus status) {
108         if (status == IdleStatus.BOTH_IDLE) {
109             return idleCountForBoth;
110         }
111 
112         if (status == IdleStatus.READER_IDLE) {
113             return idleCountForRead;
114         }
115 
116         if (status == IdleStatus.WRITER_IDLE) {
117             return idleCountForWrite;
118         }
119 
120         throw new IllegalArgumentException("Unknown idle status: " + status);
121     }
122 
123     /**
124      * Returns the number of the fired continuous <tt>serviceIdle</tt> events
125      * for {@link IdleStatus#READER_IDLE}.
126      * @see #getIdleCount(IdleStatus)
127      */
128     public final int getReaderIdleCount() {
129         return getIdleCount(IdleStatus.READER_IDLE);
130     }
131 
132     /**
133      * Returns the number of the fired continuous <tt>serviceIdle</tt> events
134      * for {@link IdleStatus#WRITER_IDLE}.
135      * @see #getIdleCount(IdleStatus)
136      */
137     public final int getWriterIdleCount() {
138         return getIdleCount(IdleStatus.WRITER_IDLE);
139     }
140 
141     /**
142      * Returns the number of the fired continuous <tt>serviceIdle</tt> events
143      * for {@link IdleStatus#BOTH_IDLE}.
144      * @see #getIdleCount(IdleStatus)
145      */
146     public final int getBothIdleCount() {
147         return getIdleCount(IdleStatus.BOTH_IDLE);
148     }
149 
150     /**
151      * Returns the time in milliseconds when the last <tt>serviceIdle</tt> event
152      * is fired for the specified {@link IdleStatus}.
153      */
154     public final long getLastIdleTime(IdleStatus status) {
155         if (status == IdleStatus.BOTH_IDLE) {
156             return lastIdleTimeForBoth;
157         }
158 
159         if (status == IdleStatus.READER_IDLE) {
160             return lastIdleTimeForRead;
161         }
162 
163         if (status == IdleStatus.WRITER_IDLE) {
164             return lastIdleTimeForWrite;
165         }
166 
167         throw new IllegalArgumentException("Unknown idle status: " + status);
168     }
169 
170     /**
171      * Returns the time in milliseconds when the last <tt>serviceIdle</tt> event
172      * is fired for {@link IdleStatus#READER_IDLE}.
173      * @see #getLastIdleTime(IdleStatus)
174      */
175     public final long getLastReaderIdleTime() {
176         return getLastIdleTime(IdleStatus.READER_IDLE);
177     }
178 
179     /**
180      * Returns the time in milliseconds when the last <tt>serviceIdle</tt> event
181      * is fired for {@link IdleStatus#WRITER_IDLE}.
182      * @see #getLastIdleTime(IdleStatus)
183      */
184     public final long getLastWriterIdleTime() {
185         return getLastIdleTime(IdleStatus.WRITER_IDLE);
186     }
187 
188     /**
189      * Returns the time in milliseconds when the last <tt>serviceIdle</tt> event
190      * is fired for {@link IdleStatus#BOTH_IDLE}.
191      * @see #getLastIdleTime(IdleStatus)
192      */
193     public final long getLastBothIdleTime() {
194         return getLastIdleTime(IdleStatus.BOTH_IDLE);
195     }
196 
197     /**
198      * Returns idle time for the specified type of idleness in seconds.
199      */
200     public final int getIdleTime(IdleStatus status) {
201         if (status == IdleStatus.BOTH_IDLE) {
202             return idleTimeForBoth;
203         }
204 
205         if (status == IdleStatus.READER_IDLE) {
206             return idleTimeForRead;
207         }
208 
209         if (status == IdleStatus.WRITER_IDLE) {
210             return idleTimeForWrite;
211         }
212 
213         throw new IllegalArgumentException("Unknown idle status: " + status);
214     }
215 
216     /**
217      * Returns idle time for the specified type of idleness in milliseconds.
218      */
219     public final long getIdleTimeInMillis(IdleStatus status) {
220         return getIdleTime(status) * 1000L;
221     }
222 
223     /**
224      * Sets idle time for the specified type of idleness in seconds.
225      */
226     public final void setIdleTime(IdleStatus status, int idleTime) {
227         if (idleTime < 0) {
228             throw new IllegalArgumentException("Illegal idle time: " + idleTime);
229         }
230 
231         if (status == IdleStatus.BOTH_IDLE) {
232             idleTimeForBoth = idleTime;
233         } else if (status == IdleStatus.READER_IDLE) {
234             idleTimeForRead = idleTime;
235         } else if (status == IdleStatus.WRITER_IDLE) {
236             idleTimeForWrite = idleTime;
237         } else {
238             throw new IllegalArgumentException("Unknown idle status: " + status);
239         }
240 
241         if (idleTime == 0) {
242             if (status == IdleStatus.BOTH_IDLE) {
243                 idleCountForBoth = 0;
244             } else if (status == IdleStatus.READER_IDLE) {
245                 idleCountForRead = 0;
246             } else if (status == IdleStatus.WRITER_IDLE) {
247                 idleCountForWrite = 0;
248             }
249         }
250     }
251 
252     /**
253      * Returns idle time for {@link IdleStatus#READER_IDLE} in seconds.
254      */
255     public final int getReaderIdleTime() {
256         return getIdleTime(IdleStatus.READER_IDLE);
257     }
258 
259     /**
260      * Returns idle time for {@link IdleStatus#READER_IDLE} in milliseconds.
261      */
262     public final long getReaderIdleTimeInMillis() {
263         return getIdleTimeInMillis(IdleStatus.READER_IDLE);
264     }
265 
266     /**
267      * Sets idle time for {@link IdleStatus#READER_IDLE} in seconds.
268      */
269     public final void setReaderIdleTime(int idleTime) {
270         setIdleTime(IdleStatus.READER_IDLE, idleTime);
271     }
272 
273     /**
274      * Returns idle time for {@link IdleStatus#WRITER_IDLE} in seconds.
275      */
276     public final int getWriterIdleTime() {
277         return getIdleTime(IdleStatus.WRITER_IDLE);
278     }
279 
280     /**
281      * Returns idle time for {@link IdleStatus#WRITER_IDLE} in milliseconds.
282      */
283     public final long getWriterIdleTimeInMillis() {
284         return getIdleTimeInMillis(IdleStatus.WRITER_IDLE);
285     }
286 
287     /**
288      * Sets idle time for {@link IdleStatus#WRITER_IDLE} in seconds.
289      */
290     public final void setWriterIdleTime(int idleTime) {
291         setIdleTime(IdleStatus.WRITER_IDLE, idleTime);
292     }
293 
294     /**
295      * Returns idle time for {@link IdleStatus#BOTH_IDLE} in seconds.
296      */
297     public final int getBothIdleTime() {
298         return getIdleTime(IdleStatus.BOTH_IDLE);
299     }
300 
301     /**
302      * Returns idle time for {@link IdleStatus#BOTH_IDLE} in milliseconds.
303      */
304     public final long getBothIdleTimeInMillis() {
305         return getIdleTimeInMillis(IdleStatus.BOTH_IDLE);
306     }
307 
308     /**
309      * Sets idle time for {@link IdleStatus#WRITER_IDLE} in seconds.
310      */
311     public final void setBothIdleTime(int idleTime) {
312         setIdleTime(IdleStatus.BOTH_IDLE, idleTime);
313     }
314 
315     /**
316      * TODO add documentation
317      */
318     private void increaseIdleCount(IdleStatus status, long currentTime) {
319         if (status == IdleStatus.BOTH_IDLE) {
320             idleCountForBoth++;
321             lastIdleTimeForBoth = currentTime;
322         } else if (status == IdleStatus.READER_IDLE) {
323             idleCountForRead++;
324             lastIdleTimeForRead = currentTime;
325         } else if (status == IdleStatus.WRITER_IDLE) {
326             idleCountForWrite++;
327             lastIdleTimeForWrite = currentTime;
328         } else {
329             throw new IllegalArgumentException("Unknown idle status: " + status);
330         }
331     }
332 
333     /**
334      * TODO add documentation
335      */
336     public final void notifyIdleness(long currentTime) {
337         IoServiceStatistics stats = (IoServiceStatistics) service.getStatistics();
338         stats.updateThroughput(currentTime);
339 
340         synchronized (idlenessCheckLock) {
341             notifyIdleness(currentTime,
342                     getIdleTimeInMillis(IdleStatus.BOTH_IDLE),
343                     IdleStatus.BOTH_IDLE, Math.max(stats.getLastIoTime(),
344                             getLastIdleTime(IdleStatus.BOTH_IDLE)));
345 
346             notifyIdleness(currentTime,
347                     getIdleTimeInMillis(IdleStatus.READER_IDLE),
348                     IdleStatus.READER_IDLE, Math.max(stats.getLastReadTime(),
349                             getLastIdleTime(IdleStatus.READER_IDLE)));
350 
351             notifyIdleness(currentTime,
352                     getIdleTimeInMillis(IdleStatus.WRITER_IDLE),
353                     IdleStatus.WRITER_IDLE, Math.max(stats.getLastWriteTime(),
354                             getLastIdleTime(IdleStatus.WRITER_IDLE)));
355         }
356     }
357 
358     /**
359      * TODO add documentation
360      */
361     private void notifyIdleness(long currentTime, long idleTime,
362             IdleStatus status, long lastIoTime) {
363         if (idleTime > 0 && lastIoTime != 0
364                 && currentTime - lastIoTime >= idleTime) {
365             increaseIdleCount(status, currentTime);
366             service.getListeners().fireServiceIdle(status);
367         }
368     }
369 
370     /**
371      * TODO add documentation
372      */
373     protected void resetIdleCountForRead() {
374         idleCountForBoth = 0;
375         idleCountForRead = 0;
376     }
377 
378     /**
379      * TODO add documentation
380      */
381     protected void resetIdleCountForWrite() {
382         idleCountForBoth = 0;
383         idleCountForWrite = 0;
384     }
385 }