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