2 // ========================================================================
3 // Copyright (c) 1995-2016 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.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.io;
21 import java.io.IOException;
22 import java.net.InetSocketAddress;
23 import java.nio.ByteBuffer;
24 import java.util.concurrent.TimeoutException;
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;
32 public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
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;
40 private final FillInterest _fillInterest = new FillInterest()
43 protected boolean needsFill() throws IOException
45 return AbstractEndPoint.this.needsFill();
49 private final WriteFlusher _writeFlusher = new WriteFlusher(this)
52 protected void onIncompleteFlushed()
54 AbstractEndPoint.this.onIncompleteFlush();
58 protected AbstractEndPoint(Scheduler scheduler,InetSocketAddress local,InetSocketAddress remote)
66 public long getCreatedTimeStamp()
72 public InetSocketAddress getLocalAddress()
78 public InetSocketAddress getRemoteAddress()
84 public Connection getConnection()
90 public void setConnection(Connection connection)
92 _connection = connection;
98 if (LOG.isDebugEnabled())
99 LOG.debug("onOpen {}",this);
104 public void onClose()
107 if (LOG.isDebugEnabled())
108 LOG.debug("onClose {}",this);
109 _writeFlusher.onClose();
110 _fillInterest.onClose();
120 public void fillInterested(Callback callback) throws IllegalStateException
123 _fillInterest.register(callback);
127 public void write(Callback callback, ByteBuffer... buffers) throws IllegalStateException
129 _writeFlusher.write(callback, buffers);
132 protected abstract void onIncompleteFlush();
134 protected abstract boolean needsFill() throws IOException;
136 protected FillInterest getFillInterest()
138 return _fillInterest;
141 protected WriteFlusher getWriteFlusher()
143 return _writeFlusher;
147 protected void onIdleExpired(TimeoutException timeout)
149 boolean output_shutdown=isOutputShutdown();
150 boolean input_shutdown=isInputShutdown();
151 boolean fillFailed = _fillInterest.onFail(timeout);
152 boolean writeFailed = _writeFlusher.onFail(timeout);
154 // If the endpoint is half closed and there was no fill/write handling, then close here.
155 // This handles the situation where the connection has completed its close handling
156 // and the endpoint is half closed, but the other party does not complete the close.
157 // This perhaps should not check for half closed, however the servlet spec case allows
158 // for a dispatched servlet or suspended request to extend beyond the connections idle
159 // time. So if this test would always close an idle endpoint that is not handled, then
160 // we would need a mode to ignore timeouts for some HTTP states
161 if (isOpen() && (output_shutdown || input_shutdown) && !(fillFailed || writeFailed))
164 LOG.debug("Ignored idle endpoint {}",this);
168 public void upgrade(Connection newConnection)
170 Connection old_connection = getConnection();
172 if (LOG.isDebugEnabled())
173 LOG.debug("{} upgrading from {} to {}", this, old_connection, newConnection);
175 ByteBuffer prefilled = (old_connection instanceof Connection.UpgradeFrom)
176 ?((Connection.UpgradeFrom)old_connection).onUpgradeFrom():null;
177 old_connection.onClose();
178 old_connection.getEndPoint().setConnection(newConnection);
180 if (newConnection instanceof Connection.UpgradeTo)
181 ((Connection.UpgradeTo)newConnection).onUpgradeTo(prefilled);
182 else if (BufferUtil.hasContent(prefilled))
183 throw new IllegalStateException();
185 newConnection.onOpen();
189 public String toString()
191 return String.format("%s@%x{%s<->%d,%s,%s,%s,%s,%s,%d/%d,%s}",
192 getClass().getSimpleName(),
195 getLocalAddress().getPort(),
196 isOpen()?"Open":"CLOSED",
197 isInputShutdown()?"ISHUT":"in",
198 isOutputShutdown()?"OSHUT":"out",
199 _fillInterest.isInterested()?"R":"-",
200 _writeFlusher.isInProgress()?"W":"-",
203 getConnection()==null?null:getConnection().getClass().getSimpleName());