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.Collections;
24  import java.util.HashMap;
25  import java.util.HashSet;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import org.apache.mina.common.CloseFuture;
30  import org.apache.mina.common.IdleStatus;
31  import org.apache.mina.common.IoService;
32  import org.apache.mina.common.IoSession;
33  import org.apache.mina.common.TrafficMask;
34  import org.apache.mina.common.WriteFuture;
35  import org.apache.mina.common.IoFilter.WriteRequest;
36  
37  /**
38   * Base implementation of {@link IoSession}.
39   *
40   * @author The Apache Directory Project (mina-dev@directory.apache.org)
41   * @version $Rev: 555855 $, $Date: 2007-07-13 12:19:00 +0900 (금, 13  7월 2007) $
42   */
43  public abstract class BaseIoSession implements IoSession {
44      private final Object lock = new Object();
45  
46      private final Map<String, Object> attributes = Collections
47              .synchronizedMap(new HashMap<String, Object>(8));
48  
49      private final long creationTime;
50  
51      /**
52       * A future that will be set 'closed' when the connection is closed.
53       */
54      private final CloseFuture closeFuture = new DefaultCloseFuture(this);
55  
56      private boolean closing;
57  
58      // Configuration variables
59      private int idleTimeForRead;
60  
61      private int idleTimeForWrite;
62  
63      private int idleTimeForBoth;
64  
65      private int writeTimeout;
66  
67      private TrafficMask trafficMask = TrafficMask.ALL;
68  
69      // Status variables
70      private long readBytes;
71  
72      private long writtenBytes;
73  
74      private long readMessages;
75  
76      private long writtenMessages;
77  
78      private long lastReadTime;
79  
80      private long lastWriteTime;
81  
82      private int idleCountForBoth;
83  
84      private int idleCountForRead;
85  
86      private int idleCountForWrite;
87  
88      private long lastIdleTimeForBoth;
89  
90      private long lastIdleTimeForRead;
91  
92      private long lastIdleTimeForWrite;
93  
94      protected BaseIoSession() {
95          creationTime = lastReadTime = lastWriteTime = lastIdleTimeForBoth = lastIdleTimeForRead = lastIdleTimeForWrite = System
96                  .currentTimeMillis();
97      }
98  
99      public boolean isConnected() {
100         return !closeFuture.isClosed();
101     }
102 
103     public boolean isClosing() {
104         synchronized (lock) {
105             return closing || closeFuture.isClosed();
106         }
107     }
108 
109     public CloseFuture getCloseFuture() {
110         return closeFuture;
111     }
112 
113     public CloseFuture close() {
114         synchronized (lock) {
115             if (isClosing()) {
116                 return closeFuture;
117             } else {
118                 closing = true;
119             }
120         }
121 
122         close0();
123         return closeFuture;
124     }
125 
126     /**
127      * Implement this method to perform real close operation.
128      * By default, this method is implemented to set the future to
129      * 'closed' immediately.
130      */
131     protected void close0() {
132         closeFuture.setClosed();
133     }
134 
135     public WriteFuture write(Object message) {
136         return write(message, null);
137     }
138 
139     public WriteFuture write(Object message, SocketAddress remoteAddress) {
140         synchronized (lock) {
141             if (isClosing() || !isConnected()) {
142                 return DefaultWriteFuture.newNotWrittenFuture(this);
143             }
144         }
145 
146         WriteFuture future = new DefaultWriteFuture(this);
147         write0(new WriteRequest(message, future, remoteAddress));
148 
149         return future;
150     }
151 
152     /**
153      * Implement this method to perform real write operation with
154      * the specified <code>writeRequest</code>.
155      *
156      * By default, this method is implemented to set the future to
157      * 'not written' immediately.
158      */
159     protected void write0(WriteRequest writeRequest) {
160         writeRequest.getFuture().setWritten(false);
161     }
162 
163     public Object getAttachment() {
164         return getAttribute("");
165     }
166 
167     public Object setAttachment(Object attachment) {
168         return setAttribute("", attachment);
169     }
170 
171     public Object getAttribute(String key) {
172         return attributes.get(key);
173     }
174 
175     public Object setAttribute(String key, Object value) {
176         if (value == null) {
177             return removeAttribute(key);
178         } else {
179             return attributes.put(key, value);
180         }
181     }
182 
183     public Object setAttribute(String key) {
184         return setAttribute(key, Boolean.TRUE);
185     }
186 
187     public Object removeAttribute(String key) {
188         return attributes.remove(key);
189     }
190 
191     public boolean containsAttribute(String key) {
192         return getAttribute(key) != null;
193     }
194 
195     public Set<String> getAttributeKeys() {
196         synchronized (attributes) {
197             return new HashSet<String>(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     @Override
398     public String toString() {
399         return "(" + getTransportType() + ", R: " + getRemoteAddress()
400                 + ", L: " + getLocalAddress() + ", S: " + getServiceAddress()
401                 + ')';
402     }
403 }