001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.mina.core.session;
021
022import java.net.SocketAddress;
023import java.util.Set;
024
025import org.apache.mina.core.filterchain.IoFilter;
026import org.apache.mina.core.filterchain.IoFilterChain;
027import org.apache.mina.core.future.CloseFuture;
028import org.apache.mina.core.future.ReadFuture;
029import org.apache.mina.core.future.WriteFuture;
030import org.apache.mina.core.service.IoAcceptor;
031import org.apache.mina.core.service.IoConnector;
032import org.apache.mina.core.service.IoHandler;
033import org.apache.mina.core.service.IoService;
034import org.apache.mina.core.service.TransportMetadata;
035import org.apache.mina.core.write.WriteRequest;
036import org.apache.mina.core.write.WriteRequestQueue;
037
038/**
039 * <p>
040 *   A handle which represents connection between two end-points regardless of
041 *   transport types.
042 * </p>
043 * <p>
044 *   {@link IoSession} provides user-defined attributes.  User-defined attributes
045 *   are application-specific data which are associated with a session.
046 *   It often contains objects that represents the state of a higher-level protocol
047 *   and becomes a way to exchange data between filters and handlers.
048 * </p>
049 * <h3>Adjusting Transport Type Specific Properties</h3>
050 * <p>
051 *   You can simply downcast the session to an appropriate subclass.
052 * </p>
053 * <h3>Thread Safety</h3>
054 * <p>
055 *   {@link IoSession} is thread-safe.  But please note that performing
056 *   more than one {@link #write(Object)} calls at the same time will
057 *   cause the {@link IoFilter#filterWrite(IoFilter.NextFilter,IoSession,WriteRequest)}
058 *   to be executed simultaneously, and therefore you have to make sure the
059 *   {@link IoFilter} implementations you're using are thread-safe, too.
060 * </p>
061 * <h3>Equality of Sessions</h3>
062 * TODO : The getId() method is totally wrong. We can't base
063 * a method which is designed to create a unique ID on the hashCode method.
064 * {@link Object#equals(Object)} and {@link Object#hashCode()} shall not be overriden
065 * to the default behavior that is defined in {@link Object}.
066 *
067 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
068 */
069public interface IoSession {
070    /**
071     * @return a unique identifier for this session.  Every session has its own
072     * ID which is different from each other.
073     * 
074     * TODO : The way it's implemented does not guarantee that the contract is
075     * respected. It uses the HashCode() method which don't guarantee the key
076     * unicity.
077     */
078    long getId();
079
080    /**
081     * @return the {@link IoService} which provides I/O service to this session.
082     */
083    IoService getService();
084
085    /**
086     * @return the {@link IoHandler} which handles this session.
087     */
088    IoHandler getHandler();
089
090    /**
091     * @return the configuration of this session.
092     */
093    IoSessionConfig getConfig();
094
095    /**
096     * @return the filter chain that only affects this session.
097     */
098    IoFilterChain getFilterChain();
099
100    /**
101     * Get the queue that contains the message waiting for being written.
102     * As the reader might not be ready, it's frequent that the messages
103     * aren't written completely, or that some older messages are waiting
104     * to be written when a new message arrives. This queue is used to manage
105     * the backlog of messages.
106     * 
107     * @return The queue containing the pending messages.
108     */
109    WriteRequestQueue getWriteRequestQueue();
110
111    /**
112     * @return the {@link TransportMetadata} that this session runs on.
113     */
114    TransportMetadata getTransportMetadata();
115
116    /**
117     * TODO This javadoc is wrong. The return tag should be short.
118     * 
119     * @return a {@link ReadFuture} which is notified when a new message is
120     * received, the connection is closed or an exception is caught.  This
121     * operation is especially useful when you implement a client application.
122     * TODO : Describe here how we enable this feature.
123     * However, please note that this operation is disabled by default and
124     * throw {@link IllegalStateException} because all received events must be
125     * queued somewhere to support this operation, possibly leading to memory
126     * leak.  This means you have to keep calling {@link #read()} once you
127     * enabled this operation.  To enable this operation, please call
128     * {@link IoSessionConfig#setUseReadOperation(boolean)} with <tt>true</tt>.
129     *
130     * @throws IllegalStateException if
131     * {@link IoSessionConfig#setUseReadOperation(boolean) useReadOperation}
132     * option has not been enabled.
133     */
134    ReadFuture read();
135
136    /**
137     * Writes the specified <code>message</code> to remote peer.  This
138     * operation is asynchronous; {@link IoHandler#messageSent(IoSession,Object)}
139     * will be invoked when the message is actually sent to remote peer.
140     * You can also wait for the returned {@link WriteFuture} if you want
141     * to wait for the message actually written.
142     * 
143     * @param message The message to write
144     * @return The associated WriteFuture
145     */
146    WriteFuture write(Object message);
147
148    /**
149     * (Optional) Writes the specified <tt>message</tt> to the specified <tt>destination</tt>.
150     * This operation is asynchronous; {@link IoHandler#messageSent(IoSession, Object)}
151     * will be invoked when the message is actually sent to remote peer. You can
152     * also wait for the returned {@link WriteFuture} if you want to wait for
153     * the message actually written.
154     * <p>
155     * When you implement a client that receives a broadcast message from a server
156     * such as DHCP server, the client might need to send a response message for the
157     * broadcast message the server sent.  Because the remote address of the session
158     * is not the address of the server in case of broadcasting, there should be a
159     * way to specify the destination when you write the response message.
160     * This interface provides {@link #write(Object, SocketAddress)} method so you
161     * can specify the destination.
162     * 
163     * @param message The message to write
164     * @param destination <tt>null</tt> if you want the message sent to the
165     *                    default remote address
166     * @return The associated WriteFuture
167     */
168    WriteFuture write(Object message, SocketAddress destination);
169
170    /**
171     * Closes this session immediately or after all queued write requests
172     * are flushed.  This operation is asynchronous.  Wait for the returned
173     * {@link CloseFuture} if you want to wait for the session actually closed.
174     *
175     * @param immediately {@code true} to close this session immediately
176     *                    . The pending write requests
177     *                    will simply be discarded.
178     *                    {@code false} to close this session after all queued
179     *                    write requests are flushed.
180     * @return The associated CloseFuture
181     * @deprecated Use either the closeNow() or the flushAndClose() methods
182     */
183    CloseFuture close(boolean immediately);
184
185    /**
186     * Closes this session immediately.  This operation is asynchronous, it 
187     * returns a {@link CloseFuture}.
188     * 
189     * @return The {@link CloseFuture} that can be use to wait for the completion of this operation
190     */
191    CloseFuture closeNow();
192
193    /**
194     * Closes this session after all queued write requests are flushed.  This operation 
195     * is asynchronous.  Wait for the returned {@link CloseFuture} if you want to wait 
196     * for the session actually closed.
197     *
198     * @return The associated CloseFuture
199     */
200    CloseFuture closeOnFlush();
201
202    /**
203     * Closes this session after all queued write requests
204     * are flushed. This operation is asynchronous.  Wait for the returned
205     * {@link CloseFuture} if you want to wait for the session actually closed.
206     * @deprecated use {@link #close(boolean)}
207     * 
208     * @return The associated CloseFuture
209     */
210    @Deprecated
211    CloseFuture close();
212
213    /**
214     * Returns an attachment of this session.
215     * This method is identical with <tt>getAttribute( "" )</tt>.
216     *
217     * @return The attachment
218     * @deprecated Use {@link #getAttribute(Object)} instead.
219     */
220    @Deprecated
221    Object getAttachment();
222
223    /**
224     * Sets an attachment of this session.
225     * This method is identical with <tt>setAttribute( "", attachment )</tt>.
226     *
227     * @param attachment The attachment
228     * @return Old attachment. <tt>null</tt> if it is new.
229     * @deprecated Use {@link #setAttribute(Object, Object)} instead.
230     */
231    @Deprecated
232    Object setAttachment(Object attachment);
233
234    /**
235     * Returns the value of the user-defined attribute of this session.
236     *
237     * @param key the key of the attribute
238     * @return <tt>null</tt> if there is no attribute with the specified key
239     */
240    Object getAttribute(Object key);
241
242    /**
243     * Returns the value of user defined attribute associated with the
244     * specified key.  If there's no such attribute, the specified default
245     * value is associated with the specified key, and the default value is
246     * returned.  This method is same with the following code except that the
247     * operation is performed atomically.
248     * <pre>
249     * if (containsAttribute(key)) {
250     *     return getAttribute(key);
251     * } else {
252     *     setAttribute(key, defaultValue);
253     *     return defaultValue;
254     * }
255     * </pre>
256     * 
257     * @param key the key of the attribute we want to retreive
258     * @param defaultValue the default value of the attribute
259     * @return The retrieved attribute or <tt>null</tt> if not found
260     */
261    Object getAttribute(Object key, Object defaultValue);
262
263    /**
264     * Sets a user-defined attribute.
265     *
266     * @param key the key of the attribute
267     * @param value the value of the attribute
268     * @return The old value of the attribute.  <tt>null</tt> if it is new.
269     */
270    Object setAttribute(Object key, Object value);
271
272    /**
273     * Sets a user defined attribute without a value.  This is useful when
274     * you just want to put a 'mark' attribute.  Its value is set to
275     * {@link Boolean#TRUE}.
276     *
277     * @param key the key of the attribute
278     * @return The old value of the attribute.  <tt>null</tt> if it is new.
279     */
280    Object setAttribute(Object key);
281
282    /**
283     * Sets a user defined attribute if the attribute with the specified key
284     * is not set yet.  This method is same with the following code except
285     * that the operation is performed atomically.
286     * <pre>
287     * if (containsAttribute(key)) {
288     *     return getAttribute(key);
289     * } else {
290     *     return setAttribute(key, value);
291     * }
292     * </pre>
293     * 
294     * @param key The key of the attribute we want to set
295     * @param value The value we want to set
296     * @return The old value of the attribute.  <tt>null</tt> if not found.
297     */
298    Object setAttributeIfAbsent(Object key, Object value);
299
300    /**
301     * Sets a user defined attribute without a value if the attribute with
302     * the specified key is not set yet.  This is useful when you just want to
303     * put a 'mark' attribute.  Its value is set to {@link Boolean#TRUE}.
304     * This method is same with the following code except that the operation
305     * is performed atomically.
306     * <pre>
307     * if (containsAttribute(key)) {
308     *     return getAttribute(key);  // might not always be Boolean.TRUE.
309     * } else {
310     *     return setAttribute(key);
311     * }
312     * </pre>
313     * 
314     * @param key The key of the attribute we want to set
315     * @return The old value of the attribute.  <tt>null</tt> if not found.
316     */
317    Object setAttributeIfAbsent(Object key);
318
319    /**
320     * Removes a user-defined attribute with the specified key.
321     *
322     * @param key The key of the attribute we want to remove
323     * @return The old value of the attribute.  <tt>null</tt> if not found.
324     */
325    Object removeAttribute(Object key);
326
327    /**
328     * Removes a user defined attribute with the specified key if the current
329     * attribute value is equal to the specified value.  This method is same
330     * with the following code except that the operation is performed
331     * atomically.
332     * <pre>
333     * if (containsAttribute(key) &amp;&amp; getAttribute(key).equals(value)) {
334     *     removeAttribute(key);
335     *     return true;
336     * } else {
337     *     return false;
338     * }
339     * </pre>
340     * 
341     * @param key The key we want to remove
342     * @param value The value we want to remove
343     * @return <tt>true</tt> if the removal was successful
344     */
345    boolean removeAttribute(Object key, Object value);
346
347    /**
348     * Replaces a user defined attribute with the specified key if the
349     * value of the attribute is equals to the specified old value.
350     * This method is same with the following code except that the operation
351     * is performed atomically.
352     * <pre>
353     * if (containsAttribute(key) &amp;&amp; getAttribute(key).equals(oldValue)) {
354     *     setAttribute(key, newValue);
355     *     return true;
356     * } else {
357     *     return false;
358     * }
359     * </pre>
360     * 
361     * @param key The key we want to replace
362     * @param oldValue The previous value
363     * @param newValue The new value
364     * @return <tt>true</tt> if the replacement was successful
365     */
366    boolean replaceAttribute(Object key, Object oldValue, Object newValue);
367
368    /**
369     * @param key The key of the attribute we are looking for in the session 
370     * @return <tt>true</tt> if this session contains the attribute with
371     * the specified <tt>key</tt>.
372     */
373    boolean containsAttribute(Object key);
374
375    /**
376     * @return the set of keys of all user-defined attributes.
377     */
378    Set<Object> getAttributeKeys();
379
380    /**
381     * @return <tt>true</tt> if this session is connected with remote peer.
382     */
383    boolean isConnected();
384    
385    /**
386     * @return <tt>true</tt> if this session is active.
387     */
388    boolean isActive();
389
390    /**
391     * @return <tt>true</tt> if and only if this session is being closed
392     * (but not disconnected yet) or is closed.
393     */
394    boolean isClosing();
395    
396    /**
397     * @return <tt>true</tt> if the session has started and initialized a SslEngine,
398     * <tt>false</tt> if the session is not yet secured (the handshake is not completed)
399     * or if SSL is not set for this session, or if SSL is not even an option.
400     */
401    boolean isSecured();
402
403    /**
404     * @return the {@link CloseFuture} of this session.  This method returns
405     * the same instance whenever user calls it.
406     */
407    CloseFuture getCloseFuture();
408
409    /**
410     * @return the socket address of remote peer.
411     */
412    SocketAddress getRemoteAddress();
413
414    /**
415     * @return the socket address of local machine which is associated with this
416     * session.
417     */
418    SocketAddress getLocalAddress();
419
420    /**
421     * @return the socket address of the {@link IoService} listens to to manage
422     * this session.  If this session is managed by {@link IoAcceptor}, it
423     * returns the {@link SocketAddress} which is specified as a parameter of
424     * {@link IoAcceptor#bind()}.  If this session is managed by
425     * {@link IoConnector}, this method returns the same address with
426     * that of {@link #getRemoteAddress()}.
427     */
428    SocketAddress getServiceAddress();
429
430    /**
431     * 
432     * Associate the current write request with the session
433     *
434     * @param currentWriteRequest the current write request to associate
435     */
436    void setCurrentWriteRequest(WriteRequest currentWriteRequest);
437
438    /**
439     * Suspends read operations for this session.
440     */
441    void suspendRead();
442
443    /**
444     * Suspends write operations for this session.
445     */
446    void suspendWrite();
447
448    /**
449     * Resumes read operations for this session.
450     */
451    void resumeRead();
452
453    /**
454     * Resumes write operations for this session.
455     */
456    void resumeWrite();
457
458    /**
459     * Is read operation is suspended for this session. 
460     * 
461     * @return <tt>true</tt> if suspended
462     */
463    boolean isReadSuspended();
464
465    /**
466     * Is write operation is suspended for this session.
467     * 
468     * @return <tt>true</tt> if suspended
469     */
470    boolean isWriteSuspended();
471
472    /**
473     * Update all statistical properties related with throughput assuming
474     * the specified time is the current time.  By default this method returns
475     * silently without updating the throughput properties if they were
476     * calculated already within last
477     * {@link IoSessionConfig#getThroughputCalculationInterval() calculation interval}.
478     * If, however, <tt>force</tt> is specified as <tt>true</tt>, this method
479     * updates the throughput properties immediately.
480
481     * @param currentTime the current time in milliseconds
482     * @param force Force the update if <tt>true</tt>
483     */
484    void updateThroughput(long currentTime, boolean force);
485
486    /**
487     * @return the total number of bytes which were read from this session.
488     */
489    long getReadBytes();
490
491    /**
492     * @return the total number of bytes which were written to this session.
493     */
494    long getWrittenBytes();
495
496    /**
497     * @return the total number of messages which were read and decoded from this session.
498     */
499    long getReadMessages();
500
501    /**
502     * @return the total number of messages which were written and encoded by this session.
503     */
504    long getWrittenMessages();
505
506    /**
507     * @return the number of read bytes per second.
508     */
509    double getReadBytesThroughput();
510
511    /**
512     * @return the number of written bytes per second.
513     */
514    double getWrittenBytesThroughput();
515
516    /**
517     * @return the number of read messages per second.
518     */
519    double getReadMessagesThroughput();
520
521    /**
522     * @return the number of written messages per second.
523     */
524    double getWrittenMessagesThroughput();
525
526    /**
527     * @return the number of messages which are scheduled to be written to this session.
528     */
529    int getScheduledWriteMessages();
530
531    /**
532     * @return the number of bytes which are scheduled to be written to this
533     * session.
534     */
535    long getScheduledWriteBytes();
536
537    /**
538     * Returns the message which is being written by {@link IoService}.
539     * @return <tt>null</tt> if and if only no message is being written
540     */
541    Object getCurrentWriteMessage();
542
543    /**
544     * Returns the {@link WriteRequest} which is being processed by
545     * {@link IoService}.
546     *
547     * @return <tt>null</tt> if and if only no message is being written
548     */
549    WriteRequest getCurrentWriteRequest();
550
551    /**
552     * @return the session's creation time in milliseconds
553     */
554    long getCreationTime();
555
556    /**
557     * @return the time in millis when I/O occurred lastly.
558     */
559    long getLastIoTime();
560
561    /**
562     * @return the time in millis when read operation occurred lastly.
563     */
564    long getLastReadTime();
565
566    /**
567     * @return the time in millis when write operation occurred lastly.
568     */
569    long getLastWriteTime();
570
571    /**
572     * @param status The researched idle status
573     * @return <tt>true</tt> if this session is idle for the specified
574     * {@link IdleStatus}.
575     */
576    boolean isIdle(IdleStatus status);
577
578    /**
579     * @return <tt>true</tt> if this session is {@link IdleStatus#READER_IDLE}.
580     * @see #isIdle(IdleStatus)
581     */
582    boolean isReaderIdle();
583
584    /**
585     * @return <tt>true</tt> if this session is {@link IdleStatus#WRITER_IDLE}.
586     * @see #isIdle(IdleStatus)
587     */
588    boolean isWriterIdle();
589
590    /**
591     * @return <tt>true</tt> if this session is {@link IdleStatus#BOTH_IDLE}.
592     * @see #isIdle(IdleStatus)
593     */
594    boolean isBothIdle();
595
596    /**
597     * @param status The researched idle status
598     * @return the number of the fired continuous <tt>sessionIdle</tt> events
599     * for the specified {@link IdleStatus}.
600     * <p>
601     * If <tt>sessionIdle</tt> event is fired first after some time after I/O,
602     * <tt>idleCount</tt> becomes <tt>1</tt>.  <tt>idleCount</tt> resets to
603     * <tt>0</tt> if any I/O occurs again, otherwise it increases to
604     * <tt>2</tt> and so on if <tt>sessionIdle</tt> event is fired again without
605     * any I/O between two (or more) <tt>sessionIdle</tt> events.
606     */
607    int getIdleCount(IdleStatus status);
608
609    /**
610     * @return the number of the fired continuous <tt>sessionIdle</tt> events
611     * for {@link IdleStatus#READER_IDLE}.
612     * @see #getIdleCount(IdleStatus)
613     */
614    int getReaderIdleCount();
615
616    /**
617     * @return the number of the fired continuous <tt>sessionIdle</tt> events
618     * for {@link IdleStatus#WRITER_IDLE}.
619     * @see #getIdleCount(IdleStatus)
620     */
621    int getWriterIdleCount();
622
623    /**
624     * @return the number of the fired continuous <tt>sessionIdle</tt> events
625     * for {@link IdleStatus#BOTH_IDLE}.
626     * @see #getIdleCount(IdleStatus)
627     */
628    int getBothIdleCount();
629
630    /**
631     * @param status The researched idle status
632     * @return the time in milliseconds when the last <tt>sessionIdle</tt> event
633     * is fired for the specified {@link IdleStatus}.
634     */
635    long getLastIdleTime(IdleStatus status);
636
637    /**
638     * @return the time in milliseconds when the last <tt>sessionIdle</tt> event
639     * is fired for {@link IdleStatus#READER_IDLE}.
640     * @see #getLastIdleTime(IdleStatus)
641     */
642    long getLastReaderIdleTime();
643
644    /**
645     * @return the time in milliseconds when the last <tt>sessionIdle</tt> event
646     * is fired for {@link IdleStatus#WRITER_IDLE}.
647     * @see #getLastIdleTime(IdleStatus)
648     */
649    long getLastWriterIdleTime();
650
651    /**
652     * @return the time in milliseconds when the last <tt>sessionIdle</tt> event
653     * is fired for {@link IdleStatus#BOTH_IDLE}.
654     * @see #getLastIdleTime(IdleStatus)
655     */
656    long getLastBothIdleTime();
657}