1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.BufferUtil;
27 import org.eclipse.jetty.util.Callback;
28 import org.eclipse.jetty.util.log.Log;
29 import org.eclipse.jetty.util.log.Logger;
30 import org.eclipse.jetty.util.thread.Scheduler;
31
32 public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
33 {
34 private static final Logger LOG = Log.getLogger(AbstractEndPoint.class);
35 private final long _created=System.currentTimeMillis();
36 private final InetSocketAddress _local;
37 private final InetSocketAddress _remote;
38 private volatile Connection _connection;
39
40 private final FillInterest _fillInterest = new FillInterest()
41 {
42 @Override
43 protected void needsFillInterest() throws IOException
44 {
45 AbstractEndPoint.this.needsFillInterest();
46 }
47 };
48
49 private final WriteFlusher _writeFlusher = new WriteFlusher(this)
50 {
51 @Override
52 protected void onIncompleteFlush()
53 {
54 AbstractEndPoint.this.onIncompleteFlush();
55 }
56 };
57
58 protected AbstractEndPoint(Scheduler scheduler,InetSocketAddress local,InetSocketAddress remote)
59 {
60 super(scheduler);
61 _local=local;
62 _remote=remote;
63 }
64
65 @Override
66 public long getCreatedTimeStamp()
67 {
68 return _created;
69 }
70
71 @Override
72 public InetSocketAddress getLocalAddress()
73 {
74 return _local;
75 }
76
77 @Override
78 public InetSocketAddress getRemoteAddress()
79 {
80 return _remote;
81 }
82
83 @Override
84 public Connection getConnection()
85 {
86 return _connection;
87 }
88
89 @Override
90 public void setConnection(Connection connection)
91 {
92 _connection = connection;
93 }
94
95 @Override
96 public boolean isOptimizedForDirectBuffers()
97 {
98 return false;
99 }
100
101 @Override
102 public void onOpen()
103 {
104 if (LOG.isDebugEnabled())
105 LOG.debug("onOpen {}",this);
106 super.onOpen();
107 }
108
109 @Override
110 public void close()
111 {
112 onClose();
113 _writeFlusher.onClose();
114 _fillInterest.onClose();
115 }
116
117 protected void close(Throwable failure)
118 {
119 onClose();
120 _writeFlusher.onFail(failure);
121 _fillInterest.onFail(failure);
122 }
123
124 @Override
125 public void fillInterested(Callback callback)
126 {
127 notIdle();
128 _fillInterest.register(callback);
129 }
130
131 @Override
132 public boolean tryFillInterested(Callback callback)
133 {
134 notIdle();
135 return _fillInterest.tryRegister(callback);
136 }
137
138 @Override
139 public boolean isFillInterested()
140 {
141 return _fillInterest.isInterested();
142 }
143
144 @Override
145 public void write(Callback callback, ByteBuffer... buffers) throws IllegalStateException
146 {
147 _writeFlusher.write(callback, buffers);
148 }
149
150 protected abstract void onIncompleteFlush();
151
152 protected abstract void needsFillInterest() throws IOException;
153
154 public FillInterest getFillInterest()
155 {
156 return _fillInterest;
157 }
158
159 protected WriteFlusher getWriteFlusher()
160 {
161 return _writeFlusher;
162 }
163
164 @Override
165 protected void onIdleExpired(TimeoutException timeout)
166 {
167 Connection connection = _connection;
168 if (connection != null && !connection.onIdleExpired())
169 return;
170
171 boolean output_shutdown=isOutputShutdown();
172 boolean input_shutdown=isInputShutdown();
173 boolean fillFailed = _fillInterest.onFail(timeout);
174 boolean writeFailed = _writeFlusher.onFail(timeout);
175
176
177
178
179
180
181
182
183 if (isOpen() && (output_shutdown || input_shutdown) && !(fillFailed || writeFailed))
184 close();
185 else
186 LOG.debug("Ignored idle endpoint {}",this);
187 }
188
189 @Override
190 public void upgrade(Connection newConnection)
191 {
192 Connection old_connection = getConnection();
193
194 if (LOG.isDebugEnabled())
195 LOG.debug("{} upgrading from {} to {}", this, old_connection, newConnection);
196
197 ByteBuffer prefilled = (old_connection instanceof Connection.UpgradeFrom)
198 ?((Connection.UpgradeFrom)old_connection).onUpgradeFrom():null;
199 old_connection.onClose();
200 old_connection.getEndPoint().setConnection(newConnection);
201
202 if (newConnection instanceof Connection.UpgradeTo)
203 ((Connection.UpgradeTo)newConnection).onUpgradeTo(prefilled);
204 else if (BufferUtil.hasContent(prefilled))
205 throw new IllegalStateException();
206
207 newConnection.onOpen();
208 }
209
210 @Override
211 public String toString()
212 {
213 Class<?> c=getClass();
214 String name=c.getSimpleName();
215 while (name.length()==0 && c.getSuperclass()!=null)
216 {
217 c=c.getSuperclass();
218 name=c.getSimpleName();
219 }
220
221 Connection connection = getConnection();
222 return String.format("%s@%x{%s<->%d,%s,%s,%s,%s,%s,%d/%d,%s@%x}",
223 name,
224 hashCode(),
225 getRemoteAddress(),
226 getLocalAddress().getPort(),
227 isOpen()?"Open":"CLOSED",
228 isInputShutdown()?"ISHUT":"in",
229 isOutputShutdown()?"OSHUT":"out",
230 _fillInterest.toStateString(),
231 _writeFlusher.toStateString(),
232 getIdleFor(),
233 getIdleTimeout(),
234 connection == null ? null : connection.getClass().getSimpleName(),
235 connection == null ? 0 : connection.hashCode());
236 }
237 }