View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.io;
20  
21  import java.io.IOException;
22  import java.net.InetSocketAddress;
23  import java.nio.ByteBuffer;
24  import java.util.concurrent.TimeoutException;
25  
26  import org.eclipse.jetty.util.Callback;
27  import org.eclipse.jetty.util.log.Log;
28  import org.eclipse.jetty.util.log.Logger;
29  import org.eclipse.jetty.util.thread.Scheduler;
30  
31  public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
32  {
33      private static final Logger LOG = Log.getLogger(AbstractEndPoint.class);
34      private final long _created=System.currentTimeMillis();
35      private final InetSocketAddress _local;
36      private final InetSocketAddress _remote;
37      private volatile Connection _connection;
38  
39      private final FillInterest _fillInterest = new FillInterest()
40      {
41          @Override
42          protected boolean needsFill() throws IOException
43          {
44              return AbstractEndPoint.this.needsFill();
45          }
46      };
47      
48      private final WriteFlusher _writeFlusher = new WriteFlusher(this)
49      {
50          @Override
51          protected void onIncompleteFlushed()
52          {
53              AbstractEndPoint.this.onIncompleteFlush();
54          }
55      };
56  
57      protected AbstractEndPoint(Scheduler scheduler,InetSocketAddress local,InetSocketAddress remote)
58      {
59          super(scheduler);
60          _local=local;
61          _remote=remote;
62      }
63  
64      @Override
65      public long getCreatedTimeStamp()
66      {
67          return _created;
68      }
69  
70      @Override
71      public InetSocketAddress getLocalAddress()
72      {
73          return _local;
74      }
75  
76      @Override
77      public InetSocketAddress getRemoteAddress()
78      {
79          return _remote;
80      }
81      
82      @Override
83      public Connection getConnection()
84      {
85          return _connection;
86      }
87  
88      @Override
89      public void setConnection(Connection connection)
90      {
91          _connection = connection;
92      }
93  
94      @Override
95      public void onOpen()
96      {
97          LOG.debug("onOpen {}",this);
98          super.onOpen();
99      }
100 
101     @Override
102     public void onClose()
103     {
104         super.onClose();
105         LOG.debug("onClose {}",this);
106         _writeFlusher.onClose();
107         _fillInterest.onClose();
108     }
109     
110     @Override
111     public void close()
112     {
113         onClose();
114     }
115 
116     @Override
117     public void fillInterested(Callback callback) throws IllegalStateException
118     {
119         notIdle();
120         _fillInterest.register(callback);
121     }
122 
123     @Override
124     public void write(Callback callback, ByteBuffer... buffers) throws IllegalStateException
125     {
126         _writeFlusher.write(callback, buffers);
127     }
128 
129     protected abstract void onIncompleteFlush();
130 
131     protected abstract boolean needsFill() throws IOException;
132 
133     protected FillInterest getFillInterest()
134     {
135         return _fillInterest;
136     }
137 
138     protected WriteFlusher getWriteFlusher()
139     {
140         return _writeFlusher;
141     }
142 
143     @Override
144     protected void onIdleExpired(TimeoutException timeout)
145     {
146         boolean output_shutdown=isOutputShutdown();
147         boolean input_shutdown=isInputShutdown();
148         boolean fillFailed = _fillInterest.onFail(timeout);
149         boolean writeFailed = _writeFlusher.onFail(timeout);
150         
151         // If the endpoint is half closed and there was no onFail handling, the close here
152         // This handles the situation where the connection has completed its close handling 
153         // and the endpoint is half closed, but the other party does not complete the close.
154         // This perhaps should not check for half closed, however the servlet spec case allows
155         // for a dispatched servlet or suspended request to extend beyond the connections idle 
156         // time.  So if this test would always close an idle endpoint that is not handled, then 
157         // we would need a mode to ignore timeouts for some HTTP states
158         if (isOpen() && (output_shutdown || input_shutdown) && !(fillFailed || writeFailed))
159             close();
160         else 
161             LOG.debug("Ignored idle endpoint {}",this);
162     }
163 
164     @Override
165     public String toString()
166     {
167         return String.format("%s@%x{%s<->%d,%s,%s,%s,%s,%s,%d,%s}",
168                 getClass().getSimpleName(),
169                 hashCode(),
170                 getRemoteAddress(),
171                 getLocalAddress().getPort(),
172                 isOpen()?"Open":"CLOSED",
173                 isInputShutdown()?"ISHUT":"in",
174                 isOutputShutdown()?"OSHUT":"out",
175                 _fillInterest.isInterested()?"R":"-",
176                 _writeFlusher.isInProgress()?"W":"-",
177                 getIdleTimeout(),
178                 getConnection()==null?null:getConnection().getClass().getSimpleName());
179     }
180 }