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.common.support;
21  
22  import java.net.SocketAddress;
23  import java.util.HashMap;
24  import java.util.HashSet;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import org.apache.mina.common.CloseFuture;
29  import org.apache.mina.common.IdleStatus;
30  import org.apache.mina.common.IoFuture;
31  import org.apache.mina.common.IoFutureListener;
32  import org.apache.mina.common.IoService;
33  import org.apache.mina.common.IoSession;
34  import org.apache.mina.common.TrafficMask;
35  import org.apache.mina.common.WriteFuture;
36  import org.apache.mina.common.IoFilter.WriteRequest;
37  
38  import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
39  import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger;
40  
41  /**
42   * Base implementation of {@link IoSession}.
43   * 
44   * @author The Apache Directory Project (mina-dev@directory.apache.org)
45   * @version $Rev: 575603 $, $Date: 2007-09-14 19:04:45 +0900 (금, 14  9월 2007) $
46   */
47  public abstract class BaseIoSession implements IoSession {
48      
49      private static final IoFutureListener SCHEDULED_COUNTER_RESETTER =
50          new IoFutureListener() {
51              public void operationComplete(IoFuture future) {
52                  BaseIoSession s = (BaseIoSession) future.getSession();
53                  s.scheduledWriteBytes.set(0);
54                  s.scheduledWriteRequests.set(0);
55              }
56          };
57  
58      private final Map attributes = new HashMap(8);
59  
60      private final long creationTime;
61  
62      /** 
63       * A future that will be set 'closed' when the connection is closed.
64       */
65      private final CloseFuture closeFuture = new DefaultCloseFuture(this);
66  
67      private final AtomicBoolean scheduledForFlush = new AtomicBoolean();
68      
69      private final AtomicInteger scheduledWriteBytes = new AtomicInteger();
70  
71      private final AtomicInteger scheduledWriteRequests = new AtomicInteger();
72  
73      private boolean closing;
74  
75      // Configuration variables
76      private int idleTimeForRead;
77  
78      private int idleTimeForWrite;
79  
80      private int idleTimeForBoth;
81  
82      private int writeTimeout;
83  
84      private TrafficMask trafficMask = TrafficMask.ALL;
85  
86      // Status variables
87      private long readBytes;
88  
89      private long writtenBytes;
90  
91      private long readMessages;
92  
93      private long writtenMessages;
94  
95      private long lastReadTime;
96  
97      private long lastWriteTime;
98  
99      private int idleCountForBoth;
100 
101     private int idleCountForRead;
102 
103     private int idleCountForWrite;
104 
105     private long lastIdleTimeForBoth;
106 
107     private long lastIdleTimeForRead;
108 
109     private long lastIdleTimeForWrite;
110 
111     protected BaseIoSession() {
112         creationTime = lastReadTime = lastWriteTime = lastIdleTimeForBoth = lastIdleTimeForRead = lastIdleTimeForWrite = System
113                 .currentTimeMillis();
114         closeFuture.addListener(SCHEDULED_COUNTER_RESETTER);
115     }
116 
117     public boolean isConnected() {
118         return !closeFuture.isClosed();
119     }
120 
121     public synchronized boolean isClosing() {
122         return closing || closeFuture.isClosed();
123     }
124 
125     public CloseFuture getCloseFuture() {
126         return closeFuture;
127     }
128     
129     public boolean isScheduledForFlush() {
130         return scheduledForFlush.get();
131     }
132     
133     public boolean setScheduledForFlush(boolean flag) {
134         if (flag) {
135             return scheduledForFlush.compareAndSet(false, true);
136         } else {
137             scheduledForFlush.set(false);
138             return true;
139         }
140     }
141 
142     public CloseFuture close() {
143         synchronized (this) {
144             if (isClosing()) {
145                 return closeFuture;
146             } else {
147                 closing = true;
148             }
149         }
150 
151         close0();
152         return closeFuture;
153     }
154 
155     /**
156      * Implement this method to perform real close operation.
157      * By default, this method is implemented to set the future to
158      * 'closed' immediately.
159      */
160     protected void close0() {
161         closeFuture.setClosed();
162     }
163 
164     public WriteFuture write(Object message) {
165         return write(message, null);
166     }
167 
168     public WriteFuture write(Object message, SocketAddress remoteAddress) {
169         synchronized (this) {
170             if (isClosing() || !isConnected()) {
171                 return DefaultWriteFuture.newNotWrittenFuture(this);
172             }
173         }
174 
175         WriteFuture future = new DefaultWriteFuture(this);
176         write0(new WriteRequest(message, future, remoteAddress));
177 
178         return future;
179     }
180 
181     /**
182      * Implement this method to perform real write operation with
183      * the specified <code>writeRequest</code>.
184      * 
185      * By default, this method is implemented to set the future to
186      * 'not written' immediately.
187      */
188     protected void write0(WriteRequest writeRequest) {
189         writeRequest.getFuture().setWritten(false);
190     }
191 
192     public Object getAttachment() {
193         synchronized (attributes) {
194             return attributes.get("");
195         }
196     }
197 
198     public Object setAttachment(Object attachment) {
199         synchronized (attributes) {
200             return attributes.put("", attachment);
201         }
202     }
203 
204     public Object getAttribute(String key) {
205         synchronized (attributes) {
206             return attributes.get(key);
207         }
208     }
209 
210     public Object setAttribute(String key, Object value) {
211         synchronized (attributes) {
212             return attributes.put(key, value);
213         }
214     }
215 
216     public Object setAttribute(String key) {
217         return setAttribute(key, Boolean.TRUE);
218     }
219 
220     public Object removeAttribute(String key) {
221         synchronized (attributes) {
222             return attributes.remove(key);
223         }
224     }
225 
226     public boolean containsAttribute(String key) {
227         return getAttribute(key) != null;
228     }
229 
230     public Set getAttributeKeys() {
231         synchronized (attributes) {
232             return new HashSet(attributes.keySet());
233         }
234     }
235 
236     public int getIdleTime(IdleStatus status) {
237         if (status == IdleStatus.BOTH_IDLE)
238             return idleTimeForBoth;
239 
240         if (status == IdleStatus.READER_IDLE)
241             return idleTimeForRead;
242 
243         if (status == IdleStatus.WRITER_IDLE)
244             return idleTimeForWrite;
245 
246         throw new IllegalArgumentException("Unknown idle status: " + status);
247     }
248 
249     public long getIdleTimeInMillis(IdleStatus status) {
250         return getIdleTime(status) * 1000L;
251     }
252 
253     public void setIdleTime(IdleStatus status, int idleTime) {
254         if (idleTime < 0)
255             throw new IllegalArgumentException("Illegal idle time: " + idleTime);
256 
257         if (status == IdleStatus.BOTH_IDLE)
258             idleTimeForBoth = idleTime;
259         else if (status == IdleStatus.READER_IDLE)
260             idleTimeForRead = idleTime;
261         else if (status == IdleStatus.WRITER_IDLE)
262             idleTimeForWrite = idleTime;
263         else
264             throw new IllegalArgumentException("Unknown idle status: " + status);
265     }
266 
267     public int getWriteTimeout() {
268         return writeTimeout;
269     }
270 
271     public long getWriteTimeoutInMillis() {
272         return writeTimeout * 1000L;
273     }
274 
275     public void setWriteTimeout(int writeTimeout) {
276         if (writeTimeout < 0)
277             throw new IllegalArgumentException("Illegal write timeout: "
278                     + writeTimeout);
279         this.writeTimeout = writeTimeout;
280     }
281 
282     public TrafficMask getTrafficMask() {
283         return trafficMask;
284     }
285 
286     public void setTrafficMask(TrafficMask trafficMask) {
287         if (trafficMask == null) {
288             throw new NullPointerException("trafficMask");
289         }
290 
291         if (this.trafficMask == trafficMask) {
292             return;
293         }
294 
295         this.trafficMask = trafficMask;
296         updateTrafficMask();
297     }
298 
299     public void suspendRead() {
300         setTrafficMask(getTrafficMask().and(TrafficMask.READ.not()));
301     }
302 
303     public void suspendWrite() {
304         setTrafficMask(getTrafficMask().and(TrafficMask.WRITE.not()));
305     }
306 
307     public void resumeRead() {
308         setTrafficMask(getTrafficMask().or(TrafficMask.READ));
309     }
310 
311     public void resumeWrite() {
312         setTrafficMask(getTrafficMask().or(TrafficMask.WRITE));
313     }
314 
315     /**
316      * Signals the {@link IoService} that the {@link TrafficMask} of this
317      * session has been changed.
318      */
319     protected abstract void updateTrafficMask();
320 
321     public long getReadBytes() {
322         return readBytes;
323     }
324 
325     public long getWrittenBytes() {
326         return writtenBytes;
327     }
328 
329     public long getWrittenWriteRequests() {
330         return writtenMessages;
331     }
332 
333     public long getReadMessages() {
334         return readMessages;
335     }
336 
337     public long getWrittenMessages() {
338         return writtenMessages;
339     }
340     
341     public int getScheduledWriteBytes() {
342         return scheduledWriteBytes.get();
343     }
344     
345     public int getScheduledWriteRequests() {
346         return scheduledWriteRequests.get();
347     }
348 
349     public void increaseReadBytes(int increment) {
350         if (increment > 0) {
351             readBytes += increment;
352             lastReadTime = System.currentTimeMillis();
353             idleCountForBoth = 0;
354             idleCountForRead = 0;
355         }
356     }
357 
358     public void increaseWrittenBytes(int increment) {
359         if (increment > 0) {
360             writtenBytes += increment;
361             lastWriteTime = System.currentTimeMillis();
362             idleCountForBoth = 0;
363             idleCountForWrite = 0;
364             
365             scheduledWriteBytes.addAndGet(-increment);
366         }
367     }
368     
369     public void increaseReadMessages() {
370         readMessages++;
371     }
372 
373     public void increaseWrittenMessages() {
374         writtenMessages++;
375         scheduledWriteRequests.decrementAndGet();
376     }
377     
378     public void increaseScheduledWriteBytes(int increment) {
379         scheduledWriteBytes.addAndGet(increment);
380     }
381 
382     public void increaseScheduledWriteRequests() {
383         scheduledWriteRequests.incrementAndGet();
384     }
385 
386     public long getCreationTime() {
387         return creationTime;
388     }
389 
390     public long getLastIoTime() {
391         return Math.max(lastReadTime, lastWriteTime);
392     }
393 
394     public long getLastReadTime() {
395         return lastReadTime;
396     }
397 
398     public long getLastWriteTime() {
399         return lastWriteTime;
400     }
401 
402     public boolean isIdle(IdleStatus status) {
403         if (status == IdleStatus.BOTH_IDLE)
404             return idleCountForBoth > 0;
405 
406         if (status == IdleStatus.READER_IDLE)
407             return idleCountForRead > 0;
408 
409         if (status == IdleStatus.WRITER_IDLE)
410             return idleCountForWrite > 0;
411 
412         throw new IllegalArgumentException("Unknown idle status: " + status);
413     }
414 
415     public int getIdleCount(IdleStatus status) {
416         if (status == IdleStatus.BOTH_IDLE)
417             return idleCountForBoth;
418 
419         if (status == IdleStatus.READER_IDLE)
420             return idleCountForRead;
421 
422         if (status == IdleStatus.WRITER_IDLE)
423             return idleCountForWrite;
424 
425         throw new IllegalArgumentException("Unknown idle status: " + status);
426     }
427 
428     public long getLastIdleTime(IdleStatus status) {
429         if (status == IdleStatus.BOTH_IDLE)
430             return lastIdleTimeForBoth;
431 
432         if (status == IdleStatus.READER_IDLE)
433             return lastIdleTimeForRead;
434 
435         if (status == IdleStatus.WRITER_IDLE)
436             return lastIdleTimeForWrite;
437 
438         throw new IllegalArgumentException("Unknown idle status: " + status);
439     }
440 
441     public void increaseIdleCount(IdleStatus status) {
442         if (status == IdleStatus.BOTH_IDLE) {
443             idleCountForBoth++;
444             lastIdleTimeForBoth = System.currentTimeMillis();
445         } else if (status == IdleStatus.READER_IDLE) {
446             idleCountForRead++;
447             lastIdleTimeForRead = System.currentTimeMillis();
448         } else if (status == IdleStatus.WRITER_IDLE) {
449             idleCountForWrite++;
450             lastIdleTimeForWrite = System.currentTimeMillis();
451         } else
452             throw new IllegalArgumentException("Unknown idle status: " + status);
453     }
454 
455     public String toString() {
456         return "(" + getTransportType() + ", R: " + getRemoteAddress()
457                 + ", L: " + getLocalAddress() + ", S: " + getServiceAddress()
458                 + ')';
459     }
460 }