394854 Implemented Promise

This commit is contained in:
Greg Wilkins 2012-11-22 15:22:57 +11:00
parent 3393108950
commit 7737dc8c76
88 changed files with 950 additions and 824 deletions

View File

@ -58,6 +58,7 @@ import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -340,7 +341,7 @@ public class HttpClient extends ContainerLifeCycle
destination.send(request, listeners);
}
protected void newConnection(HttpDestination destination, Callback<Connection> callback)
protected void newConnection(HttpDestination destination, Promise<Connection> promise)
{
SocketChannel channel = null;
try
@ -353,14 +354,14 @@ public class HttpClient extends ContainerLifeCycle
channel.configureBlocking(false);
channel.connect(destination.getConnectAddress());
Future<Connection> result = new ConnectionCallback(destination, callback);
Future<Connection> result = new ConnectionCallback(destination, promise);
selectorManager.connect(channel, result);
}
catch (IOException x)
{
if (channel != null)
close(channel);
callback.failed(null, x);
callback.failed(x);
}
}
@ -643,7 +644,7 @@ public class HttpClient extends ContainerLifeCycle
if (sslContextFactory == null)
{
IOException failure = new ConnectException("Missing " + SslContextFactory.class.getSimpleName() + " for " + destination.getScheme() + " requests");
callback.failed(null, failure);
callback.failed(failure);
throw failure;
}
else
@ -659,7 +660,7 @@ public class HttpClient extends ContainerLifeCycle
// TODO: configureConnection, see above
appEndPoint.setConnection(connection);
callback.callback.completed(connection);
callback.callback.succeeded();
return sslConnection;
}
@ -668,7 +669,7 @@ public class HttpClient extends ContainerLifeCycle
{
HttpConnection connection = new HttpConnection(HttpClient.this, endPoint, destination);
// TODO: configureConnection, see above
callback.callback.completed(connection);
callback.callback.succeeded();
return connection;
}
}
@ -677,7 +678,7 @@ public class HttpClient extends ContainerLifeCycle
protected void connectionFailed(SocketChannel channel, Throwable ex, Object attachment)
{
ConnectionCallback callback = (ConnectionCallback)attachment;
callback.callback.failed(null, ex);
callback.callback.failed(ex);
}
}

View File

@ -43,6 +43,8 @@ import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.log.Log;
@ -158,14 +160,14 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
public Future<Connection> newConnection()
{
FutureCallback<Connection> result = new FutureCallback<>();
FuturePromise<Connection> result = new FuturePromise<>();
newConnection(new CONNECTCallback(result));
return result;
}
protected void newConnection(Callback<Connection> callback)
protected void newConnection(Promise<Connection> promise)
{
client.newConnection(this, callback);
client.newConnection(this, promise);
}
protected Connection acquire()
@ -194,13 +196,13 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
CONNECTCallback connectCallback = new CONNECTCallback(new Callback<Connection>()
{
@Override
public void completed(Connection connection)
public void succeeded()
{
process(connection, true);
}
@Override
public void failed(final Connection connection, final Throwable x)
public void failed(final Throwable x)
{
client.getExecutor().execute(new Runnable()
{
@ -214,7 +216,7 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
});
}
});
newConnection(new TCPCallback(next, maxConnections, connectCallback));
newConnection(new TCPPromise(next, maxConnections, connectCallback));
// Try again the idle connections
return idleConnections.poll();
}
@ -425,13 +427,13 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
}
}
private class TCPCallback implements Callback<Connection>
private class TCPPromise implements Promise<Connection>
{
private final int current;
private final int max;
private final Callback<Connection> delegate;
private final Promise<Connection> delegate;
private TCPCallback(int current, int max, Callback<Connection> delegate)
private TCPPromise(int current, int max, Promise<Connection> delegate)
{
this.current = current;
this.max = max;
@ -439,32 +441,32 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
}
@Override
public void completed(Connection connection)
public void succeeded(Connection connection)
{
LOG.debug("Created connection {}/{} {} for {}", current, max, connection, HttpDestination.this);
delegate.completed(connection);
delegate.succeeded(connection);
}
@Override
public void failed(Connection connection, Throwable x)
public void failed(Throwable x)
{
LOG.debug("Connection failed {} for {}", x, HttpDestination.this);
connectionCount.decrementAndGet();
delegate.failed(connection, x);
delegate.failed(x);
}
}
private class CONNECTCallback implements Callback<Connection>
private class CONNECTCallback implements Promise<Connection>
{
private final Callback<Connection> delegate;
private final Promise<Connection> delegate;
private CONNECTCallback(Callback<Connection> delegate)
private CONNECTCallback(Promise<Connection> delegate)
{
this.delegate = delegate;
}
@Override
public void completed(Connection connection)
public void succeeded(Connection connection)
{
boolean tunnel = isProxied() &&
"https".equalsIgnoreCase(getScheme()) &&
@ -472,13 +474,13 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
if (tunnel)
tunnel(connection);
else
delegate.completed(connection);
delegate.succeeded(connection);
}
@Override
public void failed(Connection connection, Throwable x)
public void failed(Throwable x)
{
delegate.failed(connection, x);
delegate.failed(x);
}
private void tunnel(final Connection connection)
@ -496,15 +498,15 @@ public class HttpDestination implements Destination, AutoCloseable, Dumpable
{
if (result.isFailed())
{
failed(connection, result.getFailure());
failed(result.getFailure());
}
else
{
Response response = result.getResponse();
if (response.getStatus() == 200)
delegate.completed(connection);
delegate.succeeded(connection);
else
failed(connection, new HttpResponseException("Received " + response + " for " + result.getRequest(), response));
failed(new HttpResponseException("Received " + response + " for " + result.getRequest(), response));
}
}
}));

View File

@ -201,7 +201,7 @@ public class HttpSender
}
@Override
protected void failed(Throwable x)
protected void onFailed(Throwable x)
{
fail(x);
}
@ -215,13 +215,13 @@ public class HttpSender
write(callback, header, chunk, expect100 ? null : contentInfo.content);
if (callback.pending())
if (callback.isPending())
{
LOG.debug("Write pending for {}", request);
return;
}
if (callback.completed())
if (callback.isSucceeded())
{
if (!commit(request))
return;
@ -274,7 +274,7 @@ public class HttpSender
}
}
private void write(Callback<Void> callback, ByteBuffer header, ByteBuffer chunk, ByteBuffer content)
private void write(Callback callback, ByteBuffer header, ByteBuffer chunk, ByteBuffer content)
{
int mask = 0;
if (header != null)
@ -288,28 +288,28 @@ public class HttpSender
switch (mask)
{
case 0:
endPoint.write(null, callback, BufferUtil.EMPTY_BUFFER);
endPoint.write(callback, BufferUtil.EMPTY_BUFFER);
break;
case 1:
endPoint.write(null, callback, header);
endPoint.write(callback, header);
break;
case 2:
endPoint.write(null, callback, chunk);
endPoint.write(callback, chunk);
break;
case 3:
endPoint.write(null, callback, header, chunk);
endPoint.write(callback, header, chunk);
break;
case 4:
endPoint.write(null, callback, content);
endPoint.write(callback, content);
break;
case 5:
endPoint.write(null, callback, header, content);
endPoint.write(callback, header, content);
break;
case 6:
endPoint.write(null, callback, chunk, content);
endPoint.write(callback, chunk, content);
break;
case 7:
endPoint.write(null, callback, header, chunk, content);
endPoint.write(callback, header, chunk, content);
break;
default:
throw new IllegalStateException();
@ -448,7 +448,7 @@ public class HttpSender
IDLE, SEND, COMMIT, FAILURE
}
private static abstract class StatefulExecutorCallback implements Callback<Void>, Runnable
private static abstract class StatefulExecutorCallback implements Callback, Runnable
{
private final AtomicReference<State> state = new AtomicReference<>(State.INCOMPLETE);
private final Executor executor;
@ -459,7 +459,7 @@ public class HttpSender
}
@Override
public final void completed(final Void context)
public final void succeeded()
{
State previous = state.get();
while (true)
@ -481,7 +481,7 @@ public class HttpSender
protected abstract void pendingCompleted();
@Override
public final void failed(Void context, final Throwable x)
public final void failed(final Throwable x)
{
State previous = state.get();
while (true)
@ -507,19 +507,19 @@ public class HttpSender
}
}
protected abstract void failed(Throwable x);
protected abstract void onFailed(Throwable x);
public boolean pending()
public boolean isPending()
{
return state.compareAndSet(State.INCOMPLETE, State.PENDING);
}
public boolean completed()
public boolean isSucceeded()
{
return state.get() == State.COMPLETE;
}
public boolean failed()
public boolean isFailed()
{
return state.get() == State.FAILED;
}

View File

@ -45,7 +45,7 @@ public abstract class AbstractConnection implements Connection
private final long _created=System.currentTimeMillis();
private final EndPoint _endPoint;
private final Executor _executor;
private final Callback<Void> _readCallback;
private final Callback _readCallback;
private int _inputBufferSize=2048;
public AbstractConnection(EndPoint endp, Executor executor)
@ -59,19 +59,19 @@ public abstract class AbstractConnection implements Connection
throw new IllegalArgumentException("Executor must not be null!");
_endPoint = endp;
_executor = executor;
_readCallback = new ExecutorCallback<Void>(executor,0)
_readCallback = new ExecutorCallback(executor,0)
{
@Override
public void completed(Void context)
public void succeeded()
{
if (executeOnfillable)
super.completed(context);
super.succeeded();
else
onCompleted(context);
onCompleted();
}
@Override
protected void onCompleted(Void context)
protected void onCompleted()
{
if (_state.compareAndSet(State.INTERESTED,State.FILLING))
{
@ -97,7 +97,7 @@ public abstract class AbstractConnection implements Connection
case FILLING_INTERESTED:
if (_state.compareAndSet(State.FILLING_INTERESTED,State.INTERESTED))
{
getEndPoint().fillInterested(null, _readCallback);
getEndPoint().fillInterested(_readCallback);
break loop;
}
break;
@ -111,7 +111,7 @@ public abstract class AbstractConnection implements Connection
}
@Override
protected void onFailed(Void context, Throwable x)
protected void onFailed(Throwable x)
{
onFillInterestedFailed(x);
}
@ -162,7 +162,7 @@ public abstract class AbstractConnection implements Connection
case IDLE:
if (_state.compareAndSet(State.IDLE,State.INTERESTED))
{
getEndPoint().fillInterested(null, _readCallback);
getEndPoint().fillInterested(_readCallback);
break loop;
}
break;

View File

@ -111,16 +111,16 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
}
@Override
public <C> void fillInterested(C context, Callback<C> callback) throws IllegalStateException
public void fillInterested(Callback callback) throws IllegalStateException
{
notIdle();
_fillInterest.register(context, callback);
_fillInterest.register(callback);
}
@Override
public <C> void write(C context, Callback<C> callback, ByteBuffer... buffers) throws IllegalStateException
public void write(Callback callback, ByteBuffer... buffers) throws IllegalStateException
{
_writeFlusher.write(context, callback, buffers);
_writeFlusher.write(callback, buffers);
}
protected abstract void onIncompleteFlush();

View File

@ -24,7 +24,7 @@ import org.eclipse.jetty.util.Callback;
* <p>A {@link Connection} is associated to an {@link EndPoint} so that I/O events
* happening on the {@link EndPoint} can be processed by the {@link Connection}.</p>
* <p>A typical implementation of {@link Connection} overrides {@link #onOpen()} to
* {@link EndPoint#fillInterested(Object, Callback) set read interest} on the {@link EndPoint},
* {@link EndPoint#fillInterested(Callback) set read interest} on the {@link EndPoint},
* and when the {@link EndPoint} signals read readyness, this {@link Connection} can
* read bytes from the network and interpret them.</p>
*/

View File

@ -150,6 +150,7 @@ public interface EndPoint extends Closeable
/**
* Close any backing stream associated with the endpoint
*/
@Override
void close();
/**
@ -201,22 +202,20 @@ public interface EndPoint extends Closeable
/**
* <p>Requests callback methods to be invoked when a call to {@link #fill(ByteBuffer)} would return data or EOF.</p>
*
* @param context the context to return via the callback
* @param callback the callback to call when an error occurs or we are readable.
* @throws ReadPendingException if another read operation is concurrent.
*/
<C> void fillInterested(C context, Callback<C> callback) throws ReadPendingException;
void fillInterested(Callback callback) throws ReadPendingException;
/**
* <p>Writes the given buffers via {@link #flush(ByteBuffer...)} and invokes callback methods when either
* all the data has been flushed or an error occurs.</p>
*
* @param context the context to return via the callback
* @param callback the callback to call when an error occurs or the write completed.
* @param buffers one or more {@link ByteBuffer}s that will be flushed.
* @throws WritePendingException if another write operation is concurrent.
*/
<C> void write(C context, Callback<C> callback, ByteBuffer... buffers) throws WritePendingException;
void write(Callback callback, ByteBuffer... buffers) throws WritePendingException;
/**
* @return the {@link Connection} associated with this {@link EndPoint}

View File

@ -28,15 +28,14 @@ import org.eclipse.jetty.util.Callback;
/* ------------------------------------------------------------ */
/**
* A Utility class to help implement {@link EndPoint#fillInterested(Object, Callback)}
* A Utility class to help implement {@link EndPoint#fillInterested(Callback)}
* by keeping state and calling the context and callback objects.
*
*/
public abstract class FillInterest
{
private final AtomicBoolean _interested = new AtomicBoolean(false);
private volatile Callback<Object> _callback;
private Object _context;
private volatile Callback _callback;
/* ------------------------------------------------------------ */
protected FillInterest()
@ -51,12 +50,11 @@ public abstract class FillInterest
* @param callback
* @throws ReadPendingException
*/
public <C> void register(C context, Callback<C> callback) throws ReadPendingException
public <C> void register(Callback callback) throws ReadPendingException
{
if (!_interested.compareAndSet(false,true))
throw new ReadPendingException();
_context=context;
_callback=(Callback<Object>)callback;
_callback=callback;
try
{
if (needsFill())
@ -75,11 +73,9 @@ public abstract class FillInterest
{
if (_interested.compareAndSet(true,false))
{
Callback<Object> callback=_callback;
Object context=_context;
Callback callback=_callback;
_callback=null;
_context=null;
callback.completed(context);
callback.succeeded();
}
}
@ -99,11 +95,9 @@ public abstract class FillInterest
{
if (_interested.compareAndSet(true,false))
{
Callback<Object> callback=_callback;
Object context=_context;
Callback callback=_callback;
_callback=null;
_context=null;
callback.failed(context,cause);
callback.failed(cause);
}
}
@ -112,11 +106,9 @@ public abstract class FillInterest
{
if (_interested.compareAndSet(true,false))
{
Callback<Object> callback=_callback;
Object context=_context;
Callback callback=_callback;
_callback=null;
_context=null;
callback.failed(context,new ClosedChannelException());
callback.failed(new ClosedChannelException());
}
}
@ -124,7 +116,7 @@ public abstract class FillInterest
@Override
public String toString()
{
return String.format("FillInterest@%x{%b,%s,%s}",hashCode(),_interested.get(),_callback,_context);
return String.format("FillInterest@%x{%b,%s}",hashCode(),_interested.get(),_callback);
}
/* ------------------------------------------------------------ */

View File

@ -342,10 +342,10 @@ public class FilterConnection extends AbstractConnection
/* ------------------------------------------------------------ */
public class FilteredEndPoint extends AbstractEndPoint
{
private final Callback<Void> _writeCB = new Callback<Void>()
private final Callback _writeCB = new Callback()
{
@Override
public void completed(Void context)
public void succeeded()
{
if (BufferUtil.isEmpty(_outBuffer))
{
@ -356,7 +356,7 @@ public class FilterConnection extends AbstractConnection
}
@Override
public void failed(Void context, Throwable x)
public void failed(Throwable x)
{
if (BufferUtil.isEmpty(_outBuffer))
{
@ -392,7 +392,7 @@ public class FilterConnection extends AbstractConnection
getWriteFlusher().completeWrite();
}
else
getEndPoint().write(null,_writeCB,_outBuffer);
getEndPoint().write(_writeCB,_outBuffer);
}
@Override

View File

@ -117,7 +117,7 @@ abstract public class WriteFlusher
return updated;
}
private void fail(PendingState<?> pending)
private void fail(PendingState pending)
{
State current = _state.get();
if (current.getType()==StateType.FAILED)
@ -237,17 +237,15 @@ abstract public class WriteFlusher
*
* @param <C>
*/
private class PendingState<C> extends State
private class PendingState extends State
{
private final C _context;
private final Callback<C> _callback;
private final Callback _callback;
private final ByteBuffer[] _buffers;
private PendingState(ByteBuffer[] buffers, C context, Callback<C> callback)
private PendingState(ByteBuffer[] buffers, Callback callback)
{
super(StateType.PENDING);
_buffers = buffers;
_context = context;
_callback = callback;
}
@ -259,13 +257,13 @@ abstract public class WriteFlusher
protected void fail(Throwable cause)
{
if (_callback!=null)
_callback.failed(_context, cause);
_callback.failed(cause);
}
protected void complete()
{
if (_callback!=null)
_callback.completed(_context);
_callback.succeeded();
}
}
@ -289,7 +287,7 @@ abstract public class WriteFlusher
* @param buffers the buffers to flush to the endpoint
* @param <C> type of the context
*/
public <C> void write(C context, Callback<C> callback, ByteBuffer... buffers) throws WritePendingException
public void write(Callback callback, ByteBuffer... buffers) throws WritePendingException
{
if (DEBUG)
LOG.debug("write: {} {}", this, BufferUtil.toDetailString(buffers));
@ -308,11 +306,11 @@ abstract public class WriteFlusher
{
if (!flushed||BufferUtil.hasContent(b))
{
PendingState<?> pending=new PendingState<>(buffers, context, callback);
PendingState pending=new PendingState(buffers, callback);
if (updateState(__WRITING,pending))
onIncompleteFlushed();
else
fail(new PendingState<>(buffers, context, callback));
fail(new PendingState(buffers, callback));
return;
}
}
@ -321,7 +319,7 @@ abstract public class WriteFlusher
if (!updateState(__WRITING,__IDLE))
ignoreFail();
if (callback!=null)
callback.completed(context);
callback.succeeded();
}
catch (IOException e)
{
@ -330,10 +328,10 @@ abstract public class WriteFlusher
if (updateState(__WRITING,__IDLE))
{
if (callback!=null)
callback.failed(context, e);
callback.failed(e);
}
else
fail(new PendingState<>(buffers, context, callback));
fail(new PendingState(buffers, callback));
}
}
@ -356,7 +354,7 @@ abstract public class WriteFlusher
if (previous.getType()!=StateType.PENDING)
return; // failure already handled.
PendingState<?> pending = (PendingState<?>)previous;
PendingState pending = (PendingState)previous;
if (!updateState(pending,__COMPLETING))
return; // failure already handled.
@ -413,7 +411,7 @@ abstract public class WriteFlusher
return;
case PENDING:
PendingState<?> pending = (PendingState<?>)current;
PendingState pending = (PendingState)current;
if (updateState(pending,__IDLE))
{
pending.fail(cause);

View File

@ -64,11 +64,11 @@ import org.eclipse.jetty.util.log.Logger;
* methods. They will never block nor schedule any readInterest or write callbacks. If a fill/flush cannot progress either because
* of network congestion or waiting for an SSL handshake message, then the fill/flush will simply return with zero bytes filled/flushed.
* Specifically, if a flush cannot proceed because it needs to receive a handshake message, then the flush will attempt to fill bytes from the
* encrypted endpoint, but if insufficient bytes are read it will NOT call {@link EndPoint#fillInterested(Object, Callback)}.
* encrypted endpoint, but if insufficient bytes are read it will NOT call {@link EndPoint#fillInterested(Callback)}.
* <p>
* It is only the active methods : {@link DecryptedEndPoint#fillInterested(Object, Callback)} and
* It is only the active methods : {@link DecryptedEndPoint#fillInterested(Callback)} and
* {@link DecryptedEndPoint#write(Object, Callback, ByteBuffer...)} that may schedule callbacks by calling the encrypted
* {@link EndPoint#fillInterested(Object, Callback)} and {@link EndPoint#write(Object, Callback, ByteBuffer...)}
* {@link EndPoint#fillInterested(Callback)} and {@link EndPoint#write(Object, Callback, ByteBuffer...)}
* methods. For normal data handling, the decrypted fillInterest method will result in an encrypted fillInterest and a decrypted
* write will result in an encrypted write. However, due to SSL handshaking requirements, it is also possible for a decrypted fill
* to call the encrypted write and for the decrypted flush to call the encrypted fillInterested methods.
@ -259,10 +259,10 @@ public class SslConnection extends AbstractConnection
private boolean _cannotAcceptMoreAppDataToFlush;
private boolean _underFlown;
private final Callback<Void> _writeCallback = new Callback<Void>()
private final Callback _writeCallback = new Callback()
{
@Override
public void completed(Void context)
public void succeeded()
{
// This means that a write of encrypted data has completed. Writes are done
// only if there is a pending writeflusher or a read needed to write
@ -287,7 +287,7 @@ public class SslConnection extends AbstractConnection
}
@Override
public void failed(Void context, Throwable x)
public void failed(Throwable x)
{
// This means that a write of data has failed. Writes are done
// only if there is an active writeflusher or a read needed to write
@ -354,7 +354,7 @@ public class SslConnection extends AbstractConnection
{
// write it
_cannotAcceptMoreAppDataToFlush = true;
getEndPoint().write(null, _writeCallback, _encryptedOutput);
getEndPoint().write(_writeCallback, _encryptedOutput);
}
// TODO: use _fillRequiresFlushToProgress ?
else if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP)
@ -404,7 +404,7 @@ public class SslConnection extends AbstractConnection
{
// write it
_cannotAcceptMoreAppDataToFlush = true;
getEndPoint().write(null, _writeCallback, _encryptedOutput);
getEndPoint().write(_writeCallback, _encryptedOutput);
}
else
{

View File

@ -157,45 +157,45 @@ public class ByteArrayEndPointTest
endp.setInput("test input");
ByteBuffer buffer = BufferUtil.allocate(1024);
FutureCallback<String> fcb = new FutureCallback<>();
FutureCallback fcb = new FutureCallback();
endp.fillInterested("CTX", fcb);
endp.fillInterested(fcb);
assertTrue(fcb.isDone());
assertEquals("CTX", fcb.get());
assertEquals(null, fcb.get());
assertEquals(10, endp.fill(buffer));
assertEquals("test input", BufferUtil.toString(buffer));
fcb = new FutureCallback<>();
endp.fillInterested("CTX", fcb);
fcb = new FutureCallback();
endp.fillInterested(fcb);
assertFalse(fcb.isDone());
assertEquals(0, endp.fill(buffer));
endp.setInput(" more");
assertTrue(fcb.isDone());
assertEquals("CTX", fcb.get());
assertEquals(null, fcb.get());
assertEquals(5, endp.fill(buffer));
assertEquals("test input more", BufferUtil.toString(buffer));
fcb = new FutureCallback<>();
endp.fillInterested("CTX", fcb);
fcb = new FutureCallback();
endp.fillInterested(fcb);
assertFalse(fcb.isDone());
assertEquals(0, endp.fill(buffer));
endp.setInput((ByteBuffer)null);
assertTrue(fcb.isDone());
assertEquals("CTX", fcb.get());
assertEquals(null, fcb.get());
assertEquals(-1, endp.fill(buffer));
fcb = new FutureCallback<>();
endp.fillInterested("CTX", fcb);
fcb = new FutureCallback();
endp.fillInterested(fcb);
assertTrue(fcb.isDone());
assertEquals("CTX", fcb.get());
assertEquals(null, fcb.get());
assertEquals(-1, endp.fill(buffer));
endp.close();
fcb = new FutureCallback<>();
endp.fillInterested("CTX", fcb);
fcb = new FutureCallback();
endp.fillInterested(fcb);
assertTrue(fcb.isDone());
try
{
@ -218,21 +218,21 @@ public class ByteArrayEndPointTest
ByteBuffer data = BufferUtil.toBuffer("Data.");
ByteBuffer more = BufferUtil.toBuffer(" Some more.");
FutureCallback<String> fcb = new FutureCallback<>();
endp.write("CTX", fcb, data);
FutureCallback fcb = new FutureCallback();
endp.write( fcb, data);
assertTrue(fcb.isDone());
assertEquals("CTX", fcb.get());
assertEquals(null, fcb.get());
assertEquals("Data.", endp.getOutputString());
fcb = new FutureCallback<>();
endp.write("CTX", fcb, more);
fcb = new FutureCallback();
endp.write(fcb, more);
assertFalse(fcb.isDone());
assertEquals("Data. Some", endp.getOutputString());
assertEquals("Data. Some", endp.takeOutputString());
assertTrue(fcb.isDone());
assertEquals("CTX", fcb.get());
assertEquals(null, fcb.get());
assertEquals(" more.", endp.getOutputString());
}
@ -253,17 +253,17 @@ public class ByteArrayEndPointTest
// normal read
ByteBuffer buffer = BufferUtil.allocate(1024);
FutureCallback<Void> fcb = new FutureCallback<>();
FutureCallback fcb = new FutureCallback();
endp.fillInterested(null, fcb);
endp.fillInterested(fcb);
assertTrue(fcb.isDone());
assertEquals(null, fcb.get());
assertEquals(4, endp.fill(buffer));
assertEquals("test", BufferUtil.toString(buffer));
// read timeout
fcb = new FutureCallback<>();
endp.fillInterested(null, fcb);
fcb = new FutureCallback();
endp.fillInterested(fcb);
long start = System.currentTimeMillis();
try
{
@ -285,8 +285,8 @@ public class ByteArrayEndPointTest
Thread.sleep(idleTimeout / 2);
// write timeout
fcb = new FutureCallback<>();
endp.write(null, fcb, BufferUtil.toBuffer("This is too long"));
fcb = new FutureCallback();
endp.write(fcb, BufferUtil.toBuffer("This is too long"));
start = System.currentTimeMillis();
try
{

View File

@ -136,7 +136,7 @@ public class SelectChannelEndPointInterestsTest
connection.fillInterested();
ByteBuffer output = ByteBuffer.allocate(size.get());
endPoint.write(null, new Callback.Empty<>(), output);
endPoint.write(new Callback.Adapter(), output);
latch1.countDown();
}

View File

@ -154,8 +154,8 @@ public class SelectChannelEndPointTest
// If the tests wants to block, then block
while (_blockAt > 0 && _endp.isOpen() && _in.remaining() < _blockAt)
{
FutureCallback<Void> blockingRead = new FutureCallback<>();
_endp.fillInterested(null, blockingRead);
FutureCallback blockingRead = new FutureCallback();
_endp.fillInterested(blockingRead);
blockingRead.get();
filled = _endp.fill(_in);
progress |= filled > 0;
@ -172,8 +172,8 @@ public class SelectChannelEndPointTest
BufferUtil.clear(_out);
for (int i = 0; i < _writeCount; i++)
{
FutureCallback<Void> blockingWrite = new FutureCallback<>();
_endp.write(null, blockingWrite, out.asReadOnlyBuffer());
FutureCallback blockingWrite = new FutureCallback();
_endp.write(blockingWrite, out.asReadOnlyBuffer());
blockingWrite.get();
}
progress = true;
@ -189,8 +189,8 @@ public class SelectChannelEndPointTest
// Timeout does not close, so echo exception then shutdown
try
{
FutureCallback<Void> blockingWrite = new FutureCallback<>();
_endp.write(null, blockingWrite, BufferUtil.toBuffer("EE: " + BufferUtil.toString(_in)));
FutureCallback blockingWrite = new FutureCallback();
_endp.write(blockingWrite, BufferUtil.toBuffer("EE: " + BufferUtil.toString(_in)));
blockingWrite.get();
_endp.shutdownOutput();
}

View File

@ -105,7 +105,7 @@ public class SelectorManagerTest
@Override
protected void connectionFailed(SocketChannel channel, Throwable ex, Object attachment)
{
((Callback<Void>)attachment).failed(null, ex);
((Callback)attachment).failed(ex);
}
};
selectorManager.setConnectTimeout(connectTimeout);
@ -114,10 +114,10 @@ public class SelectorManagerTest
try
{
final CountDownLatch latch = new CountDownLatch(1);
selectorManager.connect(client, new Callback.Empty<Void>()
selectorManager.connect(client, new Callback.Adapter()
{
@Override
public void failed(Void context, Throwable x)
public void failed(Throwable x)
{
latch.countDown();
}

View File

@ -56,7 +56,7 @@ public class SslConnectionTest
protected volatile EndPoint _lastEndp;
private volatile boolean _testFill=true;
private volatile FutureCallback<Void> _writeCallback;
private volatile FutureCallback _writeCallback;
protected ServerSocketChannel _connector;
final AtomicInteger _dispatches = new AtomicInteger();
protected QueuedThreadPool _threadPool = new QueuedThreadPool()
@ -156,7 +156,7 @@ public class SslConnectionTest
@Override
public void run()
{
getEndPoint().write(null,_writeCallback,BufferUtil.toBuffer("Hello Client"));
getEndPoint().write(_writeCallback,BufferUtil.toBuffer("Hello Client"));
}
});
}
@ -191,8 +191,8 @@ public class SslConnectionTest
int l=_in.remaining();
if (l>0)
{
FutureCallback<Void> blockingWrite= new FutureCallback<>();
endp.write(null,blockingWrite,_in);
FutureCallback blockingWrite= new FutureCallback();
endp.write(blockingWrite,_in);
blockingWrite.get();
}
@ -257,7 +257,7 @@ public class SslConnectionTest
{
_testFill=false;
_writeCallback = new FutureCallback<>();
_writeCallback = new FutureCallback();
Socket client = newClient();
client.setSoTimeout(10000);

View File

@ -63,7 +63,6 @@ public class WriteFlusherTest
private WriteFlusher _flusher;
private final AtomicBoolean _flushIncomplete = new AtomicBoolean(false);
private final String _context = "Context";
private final ExecutorService executor = Executors.newFixedThreadPool(16);
private ByteArrayEndPoint _endp;
@ -87,12 +86,12 @@ public class WriteFlusherTest
{
_endp.setGrowOutput(true);
FutureCallback<String> callback = new FutureCallback<>();
FutureCallback callback = new FutureCallback();
_flusher.onFail(new IOException("Ignored because no operation in progress"));
_flusher.write(_context, callback, BufferUtil.toBuffer("How "), BufferUtil.toBuffer("now "), BufferUtil.toBuffer("brown "), BufferUtil.toBuffer("cow!"));
_flusher.write(callback, BufferUtil.toBuffer("How "), BufferUtil.toBuffer("now "), BufferUtil.toBuffer("brown "), BufferUtil.toBuffer("cow!"));
assertCallbackIsDone(callback);
assertFlushIsComplete();
assertThat("context and callback.get() are equal", _context, equalTo(callback.get()));
assertThat("context and callback.get() are equal",callback.get() , equalTo(null));
assertThat("string in endpoint matches expected string", "How now brown cow!",
equalTo(_endp.takeOutputString()));
assertTrue(_flusher.isIdle());
@ -103,11 +102,11 @@ public class WriteFlusherTest
{
_endp.setGrowOutput(true);
FutureCallback<String> callback = new FutureCallback<>();
_flusher.write(_context, callback, BufferUtil.toBuffer("How "), BufferUtil.toBuffer("now "), BufferUtil.toBuffer("brown "), BufferUtil.toBuffer("cow!"));
FutureCallback callback = new FutureCallback();
_flusher.write(callback, BufferUtil.toBuffer("How "), BufferUtil.toBuffer("now "), BufferUtil.toBuffer("brown "), BufferUtil.toBuffer("cow!"));
assertCallbackIsDone(callback);
assertFlushIsComplete();
assertThat("context and callback.get() are equal", _context, equalTo(callback.get()));
assertThat("context and callback.get() are equal", callback.get(), equalTo(null));
assertThat("string in endpoint matches expected string", "How now brown cow!",
equalTo(_endp.takeOutputString()));
assertTrue(_flusher.isIdle());
@ -118,7 +117,7 @@ public class WriteFlusherTest
assertThat("flush is complete", _flushIncomplete.get(), is(false));
}
private void assertCallbackIsDone(FutureCallback<String> callback)
private void assertCallbackIsDone(FutureCallback callback)
{
assertThat("callback is done", callback.isDone(), is(true));
}
@ -128,13 +127,13 @@ public class WriteFlusherTest
{
_endp.close();
FutureCallback<String> callback = new FutureCallback<>();
_flusher.write(_context, callback, BufferUtil.toBuffer("How "), BufferUtil.toBuffer("now "), BufferUtil.toBuffer("brown "), BufferUtil.toBuffer("cow!"));
FutureCallback callback = new FutureCallback();
_flusher.write(callback, BufferUtil.toBuffer("How "), BufferUtil.toBuffer("now "), BufferUtil.toBuffer("brown "), BufferUtil.toBuffer("cow!"));
assertCallbackIsDone(callback);
assertFlushIsComplete();
try
{
assertEquals(_context, callback.get());
assertEquals(callback.get(),null);
Assert.fail();
}
catch (ExecutionException e)
@ -151,15 +150,15 @@ public class WriteFlusherTest
@Test
public void testCompleteBlocking() throws Exception
{
FutureCallback<String> callback = new FutureCallback<>();
_flusher.write(_context, callback, BufferUtil.toBuffer("How "), BufferUtil.toBuffer("now "), BufferUtil.toBuffer("brown "), BufferUtil.toBuffer("cow!"));
FutureCallback callback = new FutureCallback();
_flusher.write(callback, BufferUtil.toBuffer("How "), BufferUtil.toBuffer("now "), BufferUtil.toBuffer("brown "), BufferUtil.toBuffer("cow!"));
assertFalse(callback.isDone());
assertFalse(callback.isCancelled());
assertTrue(_flushIncomplete.get());
try
{
assertEquals(_context, callback.get(10, TimeUnit.MILLISECONDS));
assertEquals(callback.get(10, TimeUnit.MILLISECONDS),null);
Assert.fail();
}
catch (TimeoutException to)
@ -170,7 +169,7 @@ public class WriteFlusherTest
assertEquals("How now br", _endp.takeOutputString());
_flusher.completeWrite();
assertCallbackIsDone(callback);
assertEquals(_context, callback.get());
assertEquals(callback.get(),null);
assertEquals("own cow!", _endp.takeOutputString());
assertFlushIsComplete();
assertTrue(_flusher.isIdle());
@ -179,8 +178,8 @@ public class WriteFlusherTest
@Test
public void testCloseWhileBlocking() throws Exception
{
FutureCallback<String> callback = new FutureCallback<>();
_flusher.write(_context, callback, BufferUtil.toBuffer("How "), BufferUtil.toBuffer("now "), BufferUtil.toBuffer("brown "), BufferUtil.toBuffer("cow!"));
FutureCallback callback = new FutureCallback();
_flusher.write(callback, BufferUtil.toBuffer("How "), BufferUtil.toBuffer("now "), BufferUtil.toBuffer("brown "), BufferUtil.toBuffer("cow!"));
assertFalse(callback.isDone());
assertFalse(callback.isCancelled());
@ -188,7 +187,7 @@ public class WriteFlusherTest
assertTrue(_flushIncomplete.get());
try
{
assertEquals(_context, callback.get(10, TimeUnit.MILLISECONDS));
assertEquals(callback.get(10, TimeUnit.MILLISECONDS),null);
Assert.fail();
}
catch (TimeoutException to)
@ -203,7 +202,7 @@ public class WriteFlusherTest
assertFlushIsComplete();
try
{
assertEquals(_context, callback.get());
assertEquals(callback.get(),null);
Assert.fail();
}
catch (ExecutionException e)
@ -219,8 +218,8 @@ public class WriteFlusherTest
@Test
public void testFailWhileBlocking() throws Exception
{
FutureCallback<String> callback = new FutureCallback<>();
_flusher.write(_context, callback, BufferUtil.toBuffer("How "), BufferUtil.toBuffer("now "), BufferUtil.toBuffer("brown "), BufferUtil.toBuffer("cow!"));
FutureCallback callback = new FutureCallback();
_flusher.write(callback, BufferUtil.toBuffer("How "), BufferUtil.toBuffer("now "), BufferUtil.toBuffer("brown "), BufferUtil.toBuffer("cow!"));
assertFalse(callback.isDone());
assertFalse(callback.isCancelled());
@ -228,7 +227,7 @@ public class WriteFlusherTest
assertTrue(_flushIncomplete.get());
try
{
assertEquals(_context, callback.get(10, TimeUnit.MILLISECONDS));
assertEquals(callback.get(10, TimeUnit.MILLISECONDS),null);
Assert.fail();
}
catch (TimeoutException to)
@ -243,7 +242,7 @@ public class WriteFlusherTest
assertFlushIsComplete();
try
{
assertEquals(_context, callback.get());
assertEquals(callback.get(),null);
Assert.fail();
}
catch (ExecutionException e)
@ -301,7 +300,7 @@ public class WriteFlusherTest
ConcurrentFlusher[] flushers = new ConcurrentFlusher[50000];
FutureCallback<?>[] futures = new FutureCallback<?>[flushers.length];
FutureCallback[] futures = new FutureCallback[flushers.length];
for (int i = 0; i < flushers.length; i++)
{
int size = 5 + random.nextInt(15);
@ -309,7 +308,7 @@ public class WriteFlusherTest
final ConcurrentFlusher flusher = new ConcurrentFlusher(endp, random, scheduler);
flushers[i] = flusher;
final FutureCallback<String> callback = new FutureCallback<>();
final FutureCallback callback = new FutureCallback();
futures[i] = callback;
scheduler.schedule(new Runnable()
{
@ -320,7 +319,7 @@ public class WriteFlusherTest
}
}
, random.nextInt(75) + 1, TimeUnit.MILLISECONDS);
flusher.write(_context, callback, BufferUtil.toBuffer("How Now Brown Cow."), BufferUtil.toBuffer(" The quick brown fox jumped over the lazy dog!"));
flusher.write(callback, BufferUtil.toBuffer("How Now Brown Cow."), BufferUtil.toBuffer(" The quick brown fox jumped over the lazy dog!"));
}
int completed = 0;
@ -359,9 +358,9 @@ public class WriteFlusherTest
final WriteFlusher writeFlusher = new WriteFlusher(_endPointMock)
{
@Override
public <C> void write(C context, Callback<C> callback, ByteBuffer... buffers)
public void write(Callback callback, ByteBuffer... buffers)
{
super.write(context, callback, buffers);
super.write(callback, buffers);
writeCompleteLatch.countDown();
}
@ -407,17 +406,17 @@ public class WriteFlusherTest
private boolean completed = false;
@Override
public void completed(Object context)
public void succeeded()
{
completed = true;
super.completed(context);
super.succeeded();
}
@Override
public void failed(Object context, Throwable cause)
public void failed(Throwable cause)
{
failed = true;
super.failed(context, cause);
super.failed(cause);
}
public boolean isFailed()
@ -457,7 +456,7 @@ public class WriteFlusherTest
}
});
executor.submit(new Writer(writeFlusher, new FutureCallback<String>()));
executor.submit(new Writer(writeFlusher, new FutureCallback()));
// make sure that we call .get() on the write that executed second by waiting on this latch
assertThat("Flush has been called once", flushCalledLatch.await(5, TimeUnit.SECONDS), is(true));
try
@ -475,12 +474,9 @@ public class WriteFlusherTest
{
when(_endPointMock.flush(any(ByteBuffer[].class))).thenAnswer(new Answer<Object>()
{
int called = 0;
@Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
called++;
Object[] arguments = invocation.getArguments();
ByteBuffer byteBuffer = (ByteBuffer)arguments[0];
BufferUtil.flipToFill(byteBuffer); // pretend everything has been written
@ -492,8 +488,7 @@ public class WriteFlusherTest
}
@Test
public void testConcurrentAccessToIncompleteWriteAndOnFail() throws IOException, InterruptedException,
ExecutionException, TimeoutException
public void testConcurrentAccessToIncompleteWriteAndOnFail() throws Exception
{
final CountDownLatch failedCalledLatch = new CountDownLatch(1);
final CountDownLatch onIncompleteFlushedCalledLatch = new CountDownLatch(1);
@ -502,6 +497,7 @@ public class WriteFlusherTest
final WriteFlusher writeFlusher = new WriteFlusher(new EndPointMock(writeCalledLatch, failedCalledLatch))
{
@Override
protected void onIncompleteFlushed()
{
onIncompleteFlushedCalledLatch.countDown();
@ -578,7 +574,7 @@ public class WriteFlusherTest
}
}
private static class FailedCaller implements Callable
private static class FailedCaller implements Callable<FutureCallback>
{
private final WriteFlusher writeFlusher;
private CountDownLatch failedCalledLatch;
@ -598,12 +594,12 @@ public class WriteFlusherTest
}
}
private class Writer implements Callable
private class Writer implements Callable<FutureCallback>
{
private final WriteFlusher writeFlusher;
private FutureCallback<String> callback;
private FutureCallback callback;
public Writer(WriteFlusher writeFlusher, FutureCallback<String> callback)
public Writer(WriteFlusher writeFlusher, FutureCallback callback)
{
this.writeFlusher = writeFlusher;
this.callback = callback;
@ -612,7 +608,7 @@ public class WriteFlusherTest
@Override
public FutureCallback call()
{
writeFlusher.write(_context, callback, BufferUtil.toBuffer("foo"));
writeFlusher.write(callback, BufferUtil.toBuffer("foo"));
return callback;
}
}

View File

@ -264,9 +264,9 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
}
@Override
public <C> Future<C> shutdown(C c)
public Future<Void> shutdown()
{
return new FutureCallback<C>(c);
return new FutureCallback(true);
}
@Override

View File

@ -102,10 +102,10 @@ public abstract class AbstractNetworkConnector extends AbstractConnector impleme
@Override
public <C> Future<C> shutdown(C c)
public Future<Void> shutdown()
{
close();
return super.shutdown(c);
return super.shutdown();
}
@Override

View File

@ -413,16 +413,16 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
}
@Override
public <C> void send(ResponseInfo info, ByteBuffer content, boolean lastContent, C context, Callback<C> callback)
public void send(ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback)
{
try
{
send(info,content,lastContent);
callback.completed(context);
callback.succeeded();
}
catch (IOException e)
{
callback.failed(context,e);
callback.failed(e);
}
}
@ -430,7 +430,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
{
try
{
getEndPoint().write(_writeBlocker.getPhase(), _writeBlocker, bytes);
getEndPoint().write(_writeBlocker, bytes);
_writeBlocker.block();
}
catch (InterruptedException x)
@ -557,7 +557,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
}
// Wait until we can read
getEndPoint().fillInterested(_readBlocker.getPhase(),_readBlocker);
getEndPoint().fillInterested(_readBlocker);
LOG.debug("{} block readable on {}",this,_readBlocker);
_readBlocker.block();

View File

@ -28,7 +28,7 @@ public interface HttpTransport
{
void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent) throws IOException;
<C> void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, C context, Callback<C> callback);
void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback);
void completed();
}

View File

@ -62,7 +62,7 @@ public class LocalConnector extends AbstractConnector
public LocalConnector(Server server, ConnectionFactory connectionFactory, SslContextFactory sslContextFactory)
{
this(server, null, null, null, 0,AbstractConnectionFactory.getFactories(sslContextFactory,connectionFactory));
this(server, null, null, null, 0, AbstractConnectionFactory.getFactories(sslContextFactory,connectionFactory));
}
@Override

View File

@ -321,12 +321,12 @@ public class Server extends HandlerWrapper implements Attributes
// First close the network connectors to stop accepting new connections
for (Connector connector : _connectors)
futures.add(connector.shutdown((Void)null));
futures.add(connector.shutdown());
// Then tell the contexts that we are shutting down
Handler[] contexts = getChildHandlersByClass(Graceful.class);
for (Handler context : contexts)
futures.add(((Graceful)context).shutdown((Void)null));
futures.add(((Graceful)context).shutdown());
// Shall we gracefully wait for zero connections?
long stopTimeout = getStopTimeout();

View File

@ -66,7 +66,7 @@ import org.eclipse.jetty.util.thread.Scheduler;
* The connector will use the {@link Executor} service to execute a number of Selector Tasks,
* which are implemented to each use a NIO {@link Selector} instance to asynchronously
* schedule a set of accepted connections. It is the selector thread that will call the
* {@link Callback} instances passed in the {@link EndPoint#fillInterested(Object, Callback)} or
* {@link Callback} instances passed in the {@link EndPoint#fillInterested(Callback)} or
* {@link EndPoint#write(Object, Callback, java.nio.ByteBuffer...)} methods. It is expected
* that these callbacks may do some non-blocking IO work, but will always dispatch to the
* {@link Executor} service any blocking, long running or application tasks.
@ -242,10 +242,10 @@ public class ServerConnector extends AbstractNetworkConnector
}
@Override
public <C> Future<C> shutdown(C c)
public Future<Void> shutdown()
{
// TODO shutdown all the connections
return super.shutdown(c);
return super.shutdown();
}
@Override

View File

@ -360,12 +360,11 @@ public class ConnectHandler extends HandlerWrapper
*
* @param endPoint the endPoint to read from
* @param buffer the buffer to read data into
* @param context the context information related to the connection
* @return the number of bytes read (possibly 0 since the read is non-blocking)
* or -1 if the channel has been closed remotely
* @throws IOException if the endPoint cannot be read
*/
protected int read(EndPoint endPoint, ByteBuffer buffer, ConcurrentMap<String, Object> context) throws IOException
protected int read(EndPoint endPoint, ByteBuffer buffer) throws IOException
{
return endPoint.fill(buffer);
}
@ -375,13 +374,12 @@ public class ConnectHandler extends HandlerWrapper
*
* @param endPoint the endPoint to write to
* @param buffer the buffer to write
* @param context the context information related to the connection
* @param callback the completion callback to invoke
*/
protected void write(EndPoint endPoint, ByteBuffer buffer, ConcurrentMap<String, Object> context, Callback<Void> callback)
protected void write(EndPoint endPoint, ByteBuffer buffer, Callback callback)
{
LOG.debug("{} writing {} bytes", this, buffer.remaining());
endPoint.write(null, callback, buffer);
endPoint.write(callback, buffer);
}
public Set<String> getWhiteListHosts()
@ -523,15 +521,15 @@ public class ConnectHandler extends HandlerWrapper
}
@Override
protected int read(EndPoint endPoint, ByteBuffer buffer, ConcurrentMap<String, Object> context) throws IOException
protected int read(EndPoint endPoint, ByteBuffer buffer) throws IOException
{
return ConnectHandler.this.read(endPoint, buffer, context);
return ConnectHandler.this.read(endPoint, buffer);
}
@Override
protected void write(EndPoint endPoint, ByteBuffer buffer, ConcurrentMap<String, Object> context, Callback<Void> callback)
protected void write(EndPoint endPoint, ByteBuffer buffer,Callback callback)
{
ConnectHandler.this.write(endPoint, buffer, context, callback);
ConnectHandler.this.write(endPoint, buffer, callback);
}
}
@ -550,17 +548,17 @@ public class ConnectHandler extends HandlerWrapper
{
super.onOpen();
final int remaining = buffer.remaining();
write(getConnection().getEndPoint(), buffer, getContext(), new Callback<Void>()
write(getConnection().getEndPoint(), buffer, new Callback()
{
@Override
public void completed(Void context)
public void succeeded()
{
LOG.debug("{} wrote initial {} bytes to server", DownstreamConnection.this, remaining);
fillInterested();
}
@Override
public void failed(Void context, Throwable x)
public void failed(Throwable x)
{
LOG.debug(this + " failed to write initial " + remaining + " bytes to server", x);
close();
@ -570,15 +568,15 @@ public class ConnectHandler extends HandlerWrapper
}
@Override
protected int read(EndPoint endPoint, ByteBuffer buffer, ConcurrentMap<String, Object> context) throws IOException
protected int read(EndPoint endPoint, ByteBuffer buffer) throws IOException
{
return ConnectHandler.this.read(endPoint, buffer, context);
return ConnectHandler.this.read(endPoint, buffer);
}
@Override
protected void write(EndPoint endPoint, ByteBuffer buffer, ConcurrentMap<String, Object> context, Callback<Void> callback)
protected void write(EndPoint endPoint, ByteBuffer buffer, Callback callback)
{
ConnectHandler.this.write(endPoint, buffer, context, callback);
ConnectHandler.this.write(endPoint, buffer, callback);
}
}
}

View File

@ -626,11 +626,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
*
*/
@Override
public <C> Future<C> shutdown(final C c)
public Future<Void> shutdown()
{
_availability = isRunning() ? Availability.SHUTDOWN : Availability.UNAVAILABLE;
return new FutureCallback<>(c);
return new FutureCallback(true);
}
/* ------------------------------------------------------------ */

View File

@ -34,7 +34,7 @@ import org.eclipse.jetty.util.log.Logger;
public abstract class ProxyConnection extends AbstractConnection
{
protected static final Logger LOG = ConnectHandler.LOG;
private final ForkInvoker<ByteBuffer> invoker = new ProxyForkInvoker();
private final ForkInvoker<Void> invoker = new ProxyForkInvoker();
private final ByteBufferPool bufferPool;
private final ConcurrentMap<String, Object> context;
private Connection connection;
@ -69,30 +69,25 @@ public abstract class ProxyConnection extends AbstractConnection
@Override
public void onFillable()
{
ByteBuffer buffer = getByteBufferPool().acquire(getInputBufferSize(), true);
fill(buffer);
}
private void fill(final ByteBuffer buffer)
{
final ByteBuffer buffer = getByteBufferPool().acquire(getInputBufferSize(), true);
try
{
final int filled = read(getEndPoint(), buffer, getContext());
final int filled = read(getEndPoint(), buffer);
LOG.debug("{} filled {} bytes", this, filled);
if (filled > 0)
{
write(getConnection().getEndPoint(), buffer, getContext(), new Callback<Void>()
write(getConnection().getEndPoint(), buffer, new Callback()
{
@Override
public void completed(Void context)
public void succeeded()
{
LOG.debug("{} wrote {} bytes", this, filled);
buffer.clear();
invoker.invoke(buffer);
bufferPool.release(buffer);
invoker.invoke(null);
}
@Override
public void failed(Void context, Throwable x)
public void failed(Throwable x)
{
LOG.debug(this + " failed to write " + filled + " bytes", x);
bufferPool.release(buffer);
@ -120,9 +115,9 @@ public abstract class ProxyConnection extends AbstractConnection
}
}
protected abstract int read(EndPoint endPoint, ByteBuffer buffer, ConcurrentMap<String, Object> context) throws IOException;
protected abstract int read(EndPoint endPoint, ByteBuffer buffer) throws IOException;
protected abstract void write(EndPoint endPoint, ByteBuffer buffer, ConcurrentMap<String, Object> context, Callback<Void> callback);
protected abstract void write(EndPoint endPoint, ByteBuffer buffer, Callback callback);
@Override
public String toString()
@ -133,7 +128,7 @@ public abstract class ProxyConnection extends AbstractConnection
getEndPoint().getRemoteAddress().getPort());
}
private class ProxyForkInvoker extends ForkInvoker<ByteBuffer>
private class ProxyForkInvoker extends ForkInvoker<Void> implements Runnable
{
private ProxyForkInvoker()
{
@ -141,22 +136,21 @@ public abstract class ProxyConnection extends AbstractConnection
}
@Override
public void fork(final ByteBuffer buffer)
public void fork(Void arg)
{
getExecutor().execute(new Runnable()
{
@Override
public void run()
{
call(buffer);
}
});
getExecutor().execute(this);
}
@Override
public void run()
{
onFillable();
}
@Override
public void call(ByteBuffer buffer)
public void call(Void arg)
{
fill(buffer);
onFillable();
}
}
}

View File

@ -111,7 +111,7 @@ public class CheckReverseProxyHeadersTest
try
{
server.start();
connector.getResponses("GET / HTTP/1.1\n" + headers + "\n\n");
connector.getResponses("GET / HTTP/1.1\r\n" +"Connection: close\r\n" + headers + "\r\n\r\n");
Error error = validationHandler.getError();

View File

@ -77,6 +77,7 @@ public class LocalConnectorTest
_connector.getResponses("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Connection: close\r\n" +
"\r\n");
assertTrue(openLatch.await(5, TimeUnit.SECONDS));

View File

@ -612,7 +612,8 @@ public class RequestTest
response=_connector.getResponses(
"GET / HTTP/1.1\n"+
"Host: whatever\n"+
"\n"
"\n",
200, TimeUnit.MILLISECONDS
);
assertTrue(response.indexOf("200")>0);
assertFalse(response.indexOf("Connection: close")>0);
@ -661,7 +662,8 @@ public class RequestTest
"GET / HTTP/1.0\n"+
"Host: whatever\n"+
"Connection: Other,,keep-alive\n"+
"\n"
"\n",
200, TimeUnit.MILLISECONDS
);
assertTrue(response.indexOf("200")>0);
assertTrue(response.indexOf("Connection: keep-alive")>0);
@ -682,7 +684,8 @@ public class RequestTest
response=_connector.getResponses(
"GET / HTTP/1.1\n"+
"Host: whatever\n"+
"\n"
"\n",
200, TimeUnit.MILLISECONDS
);
assertTrue(response.indexOf("200")>0);
assertTrue(response.indexOf("Connection: TE,Other")>0);

View File

@ -88,7 +88,7 @@ public class ResponseTest
}
@Override
public <C> void send(ResponseInfo info, ByteBuffer content, boolean lastContent, C context, Callback<C> callback)
public void send(ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback)
{
}

View File

@ -637,20 +637,6 @@ public class ConnectHandlerTest extends AbstractConnectHandlerTest
Assert.assertEquals(contextValue, request.getAttribute(contextKey));
context.put(contextKey, request.getAttribute(contextKey));
}
@Override
protected int read(EndPoint endPoint, ByteBuffer buffer, ConcurrentMap<String, Object> context) throws IOException
{
Assert.assertEquals(contextValue, context.get(contextKey));
return super.read(endPoint, buffer, context);
}
@Override
protected void write(EndPoint endPoint, ByteBuffer buffer, ConcurrentMap<String, Object> context, Callback<Void> callback)
{
Assert.assertEquals(contextValue, context.get(contextKey));
super.write(endPoint, buffer, context, callback);
}
});
proxy.start();

View File

@ -71,7 +71,7 @@ public class ContextHandlerCollectionTest
try
{
server.start();
connector.getResponses("GET / HTTP/1.1\n" + "Host: www.example.com.\n\n");
connector.getResponses("GET / HTTP/1.0\n" + "Host: www.example.com.\n\n");
assertTrue(handlerA.isHandled());
assertFalse(handlerB.isHandled());
@ -81,7 +81,7 @@ public class ContextHandlerCollectionTest
handlerB.reset();
handlerC.reset();
connector.getResponses("GET / HTTP/1.1\n" + "Host: www.example2.com\n\n");
connector.getResponses("GET / HTTP/1.0\n" + "Host: www.example2.com\n\n");
assertFalse(handlerA.isHandled());
assertTrue(handlerB.isHandled());
@ -149,7 +149,7 @@ public class ContextHandlerCollectionTest
for(String host : requestHosts)
{
connector.getResponses("GET / HTTP/1.1\n" + "Host: "+host+"\nConnection:close\n\n");
connector.getResponses("GET / HTTP/1.0\n" + "Host: "+host+"\nConnection:close\n\n");
if(succeed)
assertTrue("'"+host+"' should have been handled.",handler.isHandled());
else

View File

@ -95,7 +95,7 @@ public class ContextHandlerTest
try
{
server.start();
connector.getResponses("GET / HTTP/1.1\n" + "Host: www.example.com.\n\n");
connector.getResponses("GET / HTTP/1.0\n" + "Host: www.example.com.\n\n");
assertTrue(handlerA.isHandled());
assertFalse(handlerB.isHandled());
@ -105,7 +105,7 @@ public class ContextHandlerTest
handlerB.reset();
handlerC.reset();
connector.getResponses("GET / HTTP/1.1\n" + "Host: www.example2.com\n\n");
connector.getResponses("GET / HTTP/1.0\n" + "Host: www.example2.com\n\n");
assertFalse(handlerA.isHandled());
assertTrue(handlerB.isHandled());
@ -180,7 +180,7 @@ public class ContextHandlerTest
assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"),Matchers.containsString("ctx='/foo'"));
// If we shutdown foo then requests will be 503'd
foo.shutdown(null).get();
foo.shutdown().get();
assertThat(connector.getResponses("GET / HTTP/1.0\n\n"),Matchers.containsString("ctx=''"));
assertThat(connector.getResponses("GET /foo/xxx HTTP/1.0\n\n"),Matchers.containsString("503"));
assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"),Matchers.containsString("503"));

View File

@ -585,7 +585,7 @@ public class SslBytesServerTest extends SslBytesTest
// Client Hello
TLSRecord record = proxy.readFromClient();
for (byte b : record.getBytes())
proxy.flushToServer(50, b);
proxy.flushToServer(5, b);
// Server Hello + Certificate + Server Done
record = proxy.readFromServer();
@ -594,17 +594,17 @@ public class SslBytesServerTest extends SslBytesTest
// Client Key Exchange
record = proxy.readFromClient();
for (byte b : record.getBytes())
proxy.flushToServer(50, b);
proxy.flushToServer(5,b);
// Change Cipher Spec
record = proxy.readFromClient();
for (byte b : record.getBytes())
proxy.flushToServer(50, b);
proxy.flushToServer(5, b);
// Client Done
record = proxy.readFromClient();
for (byte b : record.getBytes())
proxy.flushToServer(50, b);
proxy.flushToServer(5, b);
// Change Cipher Spec
record = proxy.readFromServer();
@ -614,7 +614,7 @@ public class SslBytesServerTest extends SslBytesTest
record = proxy.readFromServer();
proxy.flushToClient(record);
Assert.assertNull(handshake.get(5, TimeUnit.SECONDS));
Assert.assertNull(handshake.get(1, TimeUnit.SECONDS));
Future<Object> request = threadPool.submit(new Callable<Object>()
{
@ -634,8 +634,8 @@ public class SslBytesServerTest extends SslBytesTest
// Application data
record = proxy.readFromClient();
for (byte b : record.getBytes())
proxy.flushToServer(50, b);
Assert.assertNull(request.get(5, TimeUnit.SECONDS));
proxy.flushToServer(5, b);
Assert.assertNull(request.get(1, TimeUnit.SECONDS));
// Application data
record = proxy.readFromServer();
@ -665,7 +665,7 @@ public class SslBytesServerTest extends SslBytesTest
// Close Alert
record = proxy.readFromClient();
for (byte b : record.getBytes())
proxy.flushToServer(50, b);
proxy.flushToServer(5, b);
// Socket close
record = proxy.readFromClient();
Assert.assertNull(String.valueOf(record), record);

View File

@ -41,9 +41,9 @@ import org.eclipse.jetty.io.SelectorManager;
import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
import org.eclipse.jetty.spdy.FlowControlStrategy;
import org.eclipse.jetty.spdy.Promise;
import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.SessionFrameListener;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
@ -316,14 +316,14 @@ public class SPDYClient
}
catch (RuntimeException x)
{
sessionPromise.failed(null,x);
sessionPromise.failed(x);
throw x;
}
}
}
}
static class SessionPromise extends Promise<Session>
static class SessionPromise extends FuturePromise<Session>
{
private final SocketChannel channel;
final SPDYClient client;

View File

@ -52,7 +52,7 @@ public class SPDYClientConnectionFactory
StandardSession session = new StandardSession(client.version, bufferPool, factory.getExecutor(), factory.getScheduler(), connection, connection, 1, sessionPromise.listener, generator, flowControlStrategy);
session.setWindowSize(client.getInitialWindowSize());
parser.addListener(session);
sessionPromise.completed(session);
sessionPromise.succeeded(session);
connection.setSession(session);
factory.sessionOpened(session);

View File

@ -35,7 +35,7 @@ import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class SPDYConnection extends AbstractConnection implements Controller<StandardSession.FrameBytes>, IdleListener
public class SPDYConnection extends AbstractConnection implements Controller, IdleListener
{
private static final Logger LOG = Log.getLogger(SPDYConnection.class);
private final ByteBufferPool bufferPool;
@ -116,12 +116,10 @@ public class SPDYConnection extends AbstractConnection implements Controller<Sta
}
@Override
public int write(ByteBuffer buffer, final Callback<StandardSession.FrameBytes> callback, StandardSession.FrameBytes context)
public void write(ByteBuffer buffer, final Callback callback)
{
EndPoint endPoint = getEndPoint();
int remaining = buffer.remaining();
endPoint.write(context, callback, buffer);
return remaining - buffer.remaining();
endPoint.write(callback, buffer);
}
@Override

View File

@ -22,9 +22,9 @@ import java.nio.ByteBuffer;
import org.eclipse.jetty.util.Callback;
public interface Controller<T>
public interface Controller
{
public int write(ByteBuffer buffer, Callback<T> callback, T context);
public void write(ByteBuffer buffer, Callback callback);
public void close(boolean onlyOutput);
}

View File

@ -34,9 +34,9 @@ public interface ISession extends Session
*/
public void flush();
public <C> void control(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback<C> callback, C context);
public void control(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback callback);
public <C> void data(IStream stream, DataInfo dataInfo, long timeout, TimeUnit unit, Callback<C> callback, C context);
public void data(IStream stream, DataInfo dataInfo, long timeout, TimeUnit unit, Callback callback);
/**
* <p>Gracefully shuts down this session.</p>

View File

@ -1,26 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.spdy;
import org.eclipse.jetty.util.FutureCallback;
@Deprecated
public class Promise<T> extends FutureCallback<T>
{
}

View File

@ -83,7 +83,7 @@ public class SPDYv3FlowControlStrategy implements FlowControlStrategy
if (dataInfo.consumed() == length && !stream.isClosed() && length > 0)
{
WindowUpdateFrame windowUpdateFrame = new WindowUpdateFrame(session.getVersion(), stream.getId(), length);
session.control(stream, windowUpdateFrame, 0, TimeUnit.MILLISECONDS, null, null);
session.control(stream, windowUpdateFrame, 0, TimeUnit.MILLISECONDS, null);
}
}
}

View File

@ -71,17 +71,21 @@ import org.eclipse.jetty.util.Atomics;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.ForkInvoker;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.PromisingCallback;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.Scheduler;
public class StandardSession implements ISession, Parser.Listener, Callback<StandardSession.FrameBytes>, Dumpable
public class StandardSession implements ISession, Parser.Listener, Dumpable
{
private static final Logger logger = Log.getLogger(Session.class);
private final ForkInvoker<Runnable> invoker = new SessionInvoker();
private final ForkInvoker<Callback> invoker = new SessionInvoker();
private final Map<String, Object> attributes = new ConcurrentHashMap<>();
private final List<Listener> listeners = new CopyOnWriteArrayList<>();
private final ConcurrentMap<Integer, IStream> streams = new ConcurrentHashMap<>();
@ -90,7 +94,7 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
private final Executor threadPool;
private final Scheduler scheduler;
private final short version;
private final Controller<FrameBytes> controller;
private final Controller controller;
private final IdleListener idleListener;
private final AtomicInteger streamIds;
private final AtomicInteger pingIds;
@ -104,7 +108,7 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
private Throwable failure;
public StandardSession(short version, ByteBufferPool bufferPool, Executor threadPool, Scheduler scheduler,
Controller<FrameBytes> controller, IdleListener idleListener, int initialStreamId, SessionFrameListener listener,
Controller controller, IdleListener idleListener, int initialStreamId, SessionFrameListener listener,
Generator generator, FlowControlStrategy flowControlStrategy)
{
// TODO this should probably be an aggregate lifecycle
@ -143,13 +147,13 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
@Override
public Future<Stream> syn(SynInfo synInfo, StreamFrameListener listener)
{
Promise<Stream> result = new Promise<>();
FuturePromise<Stream> result = new FuturePromise<>();
syn(synInfo,listener,0,TimeUnit.MILLISECONDS,result);
return result;
}
@Override
public void syn(SynInfo synInfo, StreamFrameListener listener, long timeout, TimeUnit unit, Callback<Stream> callback)
public void syn(SynInfo synInfo, StreamFrameListener listener, long timeout, TimeUnit unit, Promise<Stream> promise)
{
// Synchronization is necessary.
// SPEC v3, 2.3.1 requires that the stream creation be monotonically crescent
@ -167,7 +171,7 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
// TODO: for SPDYv3 we need to support the "slot" argument
SynStreamFrame synStream = new SynStreamFrame(version, synInfo.getFlags(), streamId, associatedStreamId, synInfo.getPriority(), (short)0, synInfo.getHeaders());
IStream stream = createStream(synStream, listener, true);
generateAndEnqueueControlFrame(stream, synStream, timeout, unit, callback, stream);
generateAndEnqueueControlFrame(stream, synStream, timeout, unit, new PromisingCallback<Stream>(promise,stream));
}
flush();
}
@ -175,25 +179,25 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
@Override
public Future<Void> rst(RstInfo rstInfo)
{
Promise<Void> result = new Promise<>();
FutureCallback result = new FutureCallback();
rst(rstInfo,0,TimeUnit.MILLISECONDS,result);
return result;
}
@Override
public void rst(RstInfo rstInfo, long timeout, TimeUnit unit, Callback<Void> callback)
public void rst(RstInfo rstInfo, long timeout, TimeUnit unit, Callback callback)
{
// SPEC v3, 2.2.2
if (goAwaySent.get())
{
complete(callback,null);
complete(callback);
}
else
{
int streamId = rstInfo.getStreamId();
IStream stream = streams.get(streamId);
RstStreamFrame frame = new RstStreamFrame(version,streamId,rstInfo.getStreamStatus().getCode(version));
control(stream,frame,timeout,unit,callback,null);
control(stream,frame,timeout,unit,callback);
if (stream != null)
{
stream.process(frame);
@ -205,33 +209,33 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
@Override
public Future<Void> settings(SettingsInfo settingsInfo)
{
Promise<Void> result = new Promise<>();
FutureCallback result = new FutureCallback();
settings(settingsInfo,0,TimeUnit.MILLISECONDS,result);
return result;
}
@Override
public void settings(SettingsInfo settingsInfo, long timeout, TimeUnit unit, Callback<Void> callback)
public void settings(SettingsInfo settingsInfo, long timeout, TimeUnit unit, Callback callback)
{
SettingsFrame frame = new SettingsFrame(version,settingsInfo.getFlags(),settingsInfo.getSettings());
control(null, frame, timeout, unit, callback, null);
control(null, frame, timeout, unit, callback);
}
@Override
public Future<PingInfo> ping()
{
Promise<PingInfo> result = new Promise<>();
FuturePromise<PingInfo> result = new FuturePromise<>();
ping(0, TimeUnit.MILLISECONDS, result);
return result;
}
@Override
public void ping(long timeout, TimeUnit unit, Callback<PingInfo> callback)
public void ping(long timeout, TimeUnit unit, Promise<PingInfo> promise)
{
int pingId = pingIds.getAndAdd(2);
PingInfo pingInfo = new PingInfo(pingId);
PingFrame frame = new PingFrame(version,pingId);
control(null,frame,timeout,unit,callback,pingInfo);
control(null,frame,timeout,unit,new PromisingCallback<PingInfo>(promise,pingInfo));
}
@Override
@ -242,29 +246,29 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
private Future<Void> goAway(SessionStatus sessionStatus)
{
Promise<Void> result = new Promise<>();
FutureCallback result = new FutureCallback();
goAway(sessionStatus, 0, TimeUnit.MILLISECONDS, result);
return result;
}
@Override
public void goAway(long timeout, TimeUnit unit, Callback<Void> callback)
public void goAway(long timeout, TimeUnit unit, Callback callback)
{
goAway(SessionStatus.OK, timeout, unit, callback);
}
private void goAway(SessionStatus sessionStatus, long timeout, TimeUnit unit, Callback<Void> callback)
private void goAway(SessionStatus sessionStatus, long timeout, TimeUnit unit, Callback callback)
{
if (goAwaySent.compareAndSet(false,true))
{
if (!goAwayReceived.get())
{
GoAwayFrame frame = new GoAwayFrame(version,lastStreamId.get(),sessionStatus.getCode());
control(null,frame,timeout,unit,callback,null);
control(null,frame,timeout,unit,callback);
return;
}
}
complete(callback, null);
complete(callback);
}
@Override
@ -632,7 +636,7 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
}
else
{
control(null, frame, 0, TimeUnit.MILLISECONDS, null, null);
control(null, frame, 0, TimeUnit.MILLISECONDS, null);
}
}
@ -821,13 +825,13 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
@Override
public <C> void control(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback<C> callback, C context)
public void control(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback callback)
{
generateAndEnqueueControlFrame(stream,frame,timeout,unit,callback,context);
generateAndEnqueueControlFrame(stream,frame,timeout,unit,callback);
flush();
}
private <C> void generateAndEnqueueControlFrame(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback<C> callback, C context)
private void generateAndEnqueueControlFrame(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback callback)
{
try
{
@ -838,7 +842,7 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
{
ByteBuffer buffer = generator.control(frame);
logger.debug("Queuing {} on {}", frame, stream);
ControlFrameBytes<C> frameBytes = new ControlFrameBytes<>(stream, callback, context, frame, buffer);
ControlFrameBytes frameBytes = new ControlFrameBytes(stream, callback, frame, buffer);
if (timeout > 0)
frameBytes.task = scheduler.schedule(frameBytes, timeout, unit);
@ -851,7 +855,7 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
}
catch (Exception x)
{
notifyCallbackFailed(callback, context, x);
notifyCallbackFailed(callback, x);
}
}
@ -863,10 +867,10 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
}
@Override
public <C> void data(IStream stream, DataInfo dataInfo, long timeout, TimeUnit unit, Callback<C> callback, C context)
public void data(IStream stream, DataInfo dataInfo, long timeout, TimeUnit unit, Callback callback)
{
logger.debug("Queuing {} on {}",dataInfo,stream);
DataFrameBytes<C> frameBytes = new DataFrameBytes<>(stream,callback,context,dataInfo);
DataFrameBytes frameBytes = new DataFrameBytes(stream,callback,dataInfo);
if (timeout > 0)
frameBytes.task = scheduler.schedule(frameBytes,timeout,unit);
append(frameBytes);
@ -932,7 +936,7 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
flushing = true;
logger.debug("Flushing {}, {} frame(s) in queue",frameBytes,queue.size());
}
write(buffer,this,frameBytes);
write(buffer,new SessionWrite(frameBytes));
}
private void append(FrameBytes frameBytes)
@ -983,87 +987,73 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
frameBytes.fail(new SPDYException(failure));
}
@Override
public void completed(FrameBytes frameBytes)
private class SessionWrite implements Callback
{
synchronized (queue)
final FrameBytes frameBytes;
SessionWrite(FrameBytes frameBytes)
{
logger.debug("Completed write of {}, {} frame(s) in queue",frameBytes,queue.size());
flushing = false;
}
frameBytes.complete();
}
@Override
public void failed(FrameBytes frameBytes, Throwable x)
{
List<FrameBytes> frameBytesToFail = new ArrayList<>();
frameBytesToFail.add(frameBytes);
synchronized (queue)
{
failure = x;
String logMessage = String.format("Failed write of %s, failing all %d frame(s) in queue",frameBytes,queue.size());
logger.debug(logMessage,x);
frameBytesToFail.addAll(queue);
queue.clear();
flushing = false;
this.frameBytes=frameBytes;
}
for (FrameBytes fb : frameBytesToFail)
fb.fail(x);
@Override
public void succeeded()
{
synchronized (queue)
{
logger.debug("Completed write of {}, {} frame(s) in queue",frameBytes,queue.size());
flushing = false;
}
frameBytes.complete();
}
@Override
public void failed(Throwable x)
{
// TODO because this is using frameBytes here, then it is not really a Promise.
// frameBytes is not a result, but is something known before the operation is attempted!
List<FrameBytes> frameBytesToFail = new ArrayList<>();
frameBytesToFail.add(frameBytes);
synchronized (queue)
{
failure = x;
String logMessage = String.format("Failed write of %s, failing all %d frame(s) in queue",frameBytes,queue.size());
logger.debug(logMessage,x);
frameBytesToFail.addAll(queue);
queue.clear();
flushing = false;
}
for (FrameBytes fb : frameBytesToFail)
fb.fail(x);
}
}
protected void write(ByteBuffer buffer, Callback<FrameBytes> callback, FrameBytes frameBytes)
protected void write(ByteBuffer buffer, Callback callback)
{
if (controller != null)
{
logger.debug("Writing {} frame bytes of {}",buffer.remaining(),frameBytes);
controller.write(buffer,callback,frameBytes);
logger.debug("Writing {} frame bytes of {}",buffer.remaining());
controller.write(buffer,callback);
}
}
private <C> void complete(final Callback<C> callback, final C context)
private void complete(final Callback callback)
{
// Applications may send and queue up a lot of frames and
// if we call Callback.completed() only synchronously we risk
// starvation (for the last frames sent) and stack overflow.
// Therefore every some invocation, we dispatch to a new thread
invoker.invoke(new Runnable()
{
@Override
public void run()
{
if (callback != null)
notifyCallbackCompleted(callback, context);
flush();
}
});
invoker.invoke(callback);
}
private <C> void notifyCallbackCompleted(Callback<C> callback, C context)
{
try
{
callback.completed(context);
}
catch (Exception x)
{
logger.info("Exception while notifying callback " + callback, x);
}
catch (Error x)
{
logger.info("Exception while notifying callback " + callback, x);
throw x;
}
}
private <C> void notifyCallbackFailed(Callback<C> callback, C context, Throwable x)
private void notifyCallbackFailed(Callback callback, Throwable x)
{
try
{
if (callback != null)
callback.failed(context, x);
callback.failed(x);
}
catch (Exception xx)
{
@ -1086,6 +1076,7 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
flowControlStrategy.setWindowSize(this, initialWindowSize);
}
@Override
public String toString()
{
return String.format("%s@%x{v%d,queuSize=%d,windowSize=%d,streams=%d}", getClass().getSimpleName(), hashCode(), version, queue.size(), getWindowSize(), streams.size());
@ -1104,7 +1095,7 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
ContainerLifeCycle.dump(out,indent,Collections.singletonList(controller),streams.values());
}
private class SessionInvoker extends ForkInvoker<Runnable>
private class SessionInvoker extends ForkInvoker<Callback>
{
private SessionInvoker()
{
@ -1112,15 +1103,20 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
}
@Override
public void fork(Runnable task)
public void fork(final Callback callback)
{
execute(task);
execute(new Runnable()
{
@Override
public void run() { callback.succeeded() ; }
});
}
@Override
public void call(Runnable task)
public void call(Callback callback)
{
task.run();
callback.succeeded();
}
}
@ -1135,18 +1131,18 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
public abstract void fail(Throwable throwable);
}
private abstract class AbstractFrameBytes<C> implements FrameBytes, Runnable
private abstract class AbstractFrameBytes implements FrameBytes, Runnable
{
private final IStream stream;
private final Callback<C> callback;
private final C context;
private final Callback callback;
protected volatile Scheduler.Task task;
protected AbstractFrameBytes(IStream stream, Callback<C> callback, C context)
protected AbstractFrameBytes(IStream stream, Callback callback)
{
if (callback==null)
throw new IllegalStateException();
this.stream = stream;
this.callback = callback;
this.context = context;
}
@Override
@ -1174,14 +1170,14 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
public void complete()
{
cancelTask();
StandardSession.this.complete(callback,context);
StandardSession.this.complete(callback);
}
@Override
public void fail(Throwable x)
{
cancelTask();
notifyCallbackFailed(callback, context, x);
notifyCallbackFailed(callback, x);
StandardSession.this.flush();
}
@ -1200,14 +1196,14 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
}
}
private class ControlFrameBytes<C> extends AbstractFrameBytes<C>
private class ControlFrameBytes extends AbstractFrameBytes
{
private final ControlFrame frame;
private final ByteBuffer buffer;
private ControlFrameBytes(IStream stream, Callback<C> callback, C context, ControlFrame frame, ByteBuffer buffer)
private ControlFrameBytes(IStream stream, Callback callback, ControlFrame frame, ByteBuffer buffer)
{
super(stream,callback,context);
super(stream,callback);
this.frame = frame;
this.buffer = buffer;
}
@ -1243,15 +1239,15 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
}
}
private class DataFrameBytes<C> extends AbstractFrameBytes<C>
private class DataFrameBytes extends AbstractFrameBytes
{
private final DataInfo dataInfo;
private int size;
private volatile ByteBuffer buffer;
private DataFrameBytes(IStream stream, Callback<C> handler, C context, DataInfo dataInfo)
private DataFrameBytes(IStream stream, Callback handler, DataInfo dataInfo)
{
super(stream,handler,context);
super(stream,handler);
this.dataInfo = dataInfo;
}
@ -1309,11 +1305,11 @@ public class StandardSession implements ISession, Parser.Listener, Callback<Stan
}
}
private class CloseFrameBytes extends AbstractFrameBytes<Void>
private class CloseFrameBytes extends AbstractFrameBytes
{
private CloseFrameBytes()
{
super(null, new Empty<Void>(), null);
super(null, new Callback.Adapter());
}
@Override

View File

@ -39,6 +39,8 @@ import org.eclipse.jetty.spdy.frames.HeadersFrame;
import org.eclipse.jetty.spdy.frames.SynReplyFrame;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -319,17 +321,17 @@ public class StandardStream implements IStream
@Override
public Future<Stream> syn(SynInfo synInfo)
{
Promise<Stream> result = new Promise<>();
FuturePromise<Stream> result = new FuturePromise<>();
syn(synInfo,0,TimeUnit.MILLISECONDS,result);
return result;
}
@Override
public void syn(SynInfo synInfo, long timeout, TimeUnit unit, Callback<Stream> callback)
public void syn(SynInfo synInfo, long timeout, TimeUnit unit, Promise<Stream> callback)
{
if (isClosed() || isReset())
{
callback.failed(this, new StreamException(getId(), StreamStatus.STREAM_ALREADY_CLOSED,
callback.failed(new StreamException(getId(), StreamStatus.STREAM_ALREADY_CLOSED,
"Stream: " + this + " already closed or reset!"));
return;
}
@ -340,32 +342,32 @@ public class StandardStream implements IStream
@Override
public Future<Void> reply(ReplyInfo replyInfo)
{
Promise<Void> result = new Promise<>();
FutureCallback result = new FutureCallback();
reply(replyInfo,0,TimeUnit.MILLISECONDS,result);
return result;
}
@Override
public void reply(ReplyInfo replyInfo, long timeout, TimeUnit unit, Callback<Void> callback)
public void reply(ReplyInfo replyInfo, long timeout, TimeUnit unit, Callback callback)
{
if (isUnidirectional())
throw new IllegalStateException("Protocol violation: cannot send SYN_REPLY frames in unidirectional streams");
openState = OpenState.REPLY_SENT;
updateCloseState(replyInfo.isClose(), true);
SynReplyFrame frame = new SynReplyFrame(session.getVersion(), replyInfo.getFlags(), getId(), replyInfo.getHeaders());
session.control(this, frame, timeout, unit, callback, null);
session.control(this, frame, timeout, unit, callback);
}
@Override
public Future<Void> data(DataInfo dataInfo)
{
FutureCallback<Void> fcb = new FutureCallback<>();
data(dataInfo,0,TimeUnit.MILLISECONDS,null,fcb);
FutureCallback fcb = new FutureCallback();
data(dataInfo,0,TimeUnit.MILLISECONDS,fcb);
return fcb;
}
@Override
public <C> void data(DataInfo dataInfo, long timeout, TimeUnit unit, C context, Callback<C> callback)
public void data(DataInfo dataInfo, long timeout, TimeUnit unit, Callback callback)
{
if (!canSend())
{
@ -380,19 +382,19 @@ public class StandardStream implements IStream
// Cannot update the close state here, because the data that we send may
// be flow controlled, so we need the stream to update the window size.
session.data(this, dataInfo, timeout, unit, callback, context);
session.data(this, dataInfo, timeout, unit, callback);
}
@Override
public Future<Void> headers(HeadersInfo headersInfo)
{
FutureCallback<Void> fcb = new FutureCallback<>();
FutureCallback fcb = new FutureCallback();
headers(headersInfo,0,TimeUnit.MILLISECONDS,fcb);
return fcb;
}
@Override
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Callback<Void> callback)
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Callback callback)
{
if (!canSend())
{
@ -407,7 +409,7 @@ public class StandardStream implements IStream
updateCloseState(headersInfo.isClose(), true);
HeadersFrame frame = new HeadersFrame(session.getVersion(), headersInfo.getFlags(), getId(), headersInfo.getHeaders());
session.control(this, frame, timeout, unit, callback, null);
session.control(this, frame, timeout, unit, callback);
}
@Override

View File

@ -24,6 +24,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise;
/**
* <p>A {@link Session} represents the client-side endpoint of a SPDY connection to a single origin server.</p>
@ -92,7 +93,7 @@ public interface Session
* @param callback the completion callback that gets notified of stream creation
* @see #syn(SynInfo, StreamFrameListener)
*/
public void syn(SynInfo synInfo, StreamFrameListener listener, long timeout, TimeUnit unit, Callback<Stream> callback);
public void syn(SynInfo synInfo, StreamFrameListener listener, long timeout, TimeUnit unit, Promise<Stream> callback);
/**
@ -116,7 +117,7 @@ public interface Session
* @param callback the completion callback that gets notified of reset's send
* @see #rst(RstInfo)
*/
public void rst(RstInfo rstInfo, long timeout, TimeUnit unit, Callback<Void> callback);
public void rst(RstInfo rstInfo, long timeout, TimeUnit unit, Callback callback);
/**
* <p>Sends asynchronously a SETTINGS to configure the SPDY connection.</p>
@ -139,7 +140,7 @@ public interface Session
* @param callback the completion callback that gets notified of settings' send
* @see #settings(SettingsInfo)
*/
public void settings(SettingsInfo settingsInfo, long timeout, TimeUnit unit, Callback<Void> callback);
public void settings(SettingsInfo settingsInfo, long timeout, TimeUnit unit, Callback callback);
/**
* <p>Sends asynchronously a PING, normally to measure round-trip time.</p>
@ -160,7 +161,7 @@ public interface Session
* @param callback the completion callback that gets notified of ping's send
* @see #ping()
*/
public void ping(long timeout, TimeUnit unit, Callback<PingInfo> callback);
public void ping(long timeout, TimeUnit unit, Promise<PingInfo> callback);
/**
* <p>Closes gracefully this session, sending a GO_AWAY frame and then closing the TCP connection.</p>
@ -181,7 +182,7 @@ public interface Session
* @param callback the completion callback that gets notified of go away's send
* @see #goAway()
*/
public void goAway(long timeout, TimeUnit unit, Callback<Void> callback);
public void goAway(long timeout, TimeUnit unit, Callback callback);
/**
* @return a snapshot of the streams currently active in this session

View File

@ -24,6 +24,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise;
/**
* <p>A {@link Stream} represents a bidirectional exchange of data on top of a {@link Session}.</p>
@ -111,7 +112,7 @@ public interface Stream
* @param callback the completion callback that gets notified once the pushstream is established
* @see #syn(SynInfo)
*/
public void syn(SynInfo synInfo, long timeout, TimeUnit unit, Callback<Stream> callback);
public void syn(SynInfo synInfo, long timeout, TimeUnit unit, Promise<Stream> callback);
/**
* <p>Sends asynchronously a SYN_REPLY frame in response to a SYN_STREAM frame.</p>
@ -135,7 +136,7 @@ public interface Stream
* @param callback the completion callback that gets notified of reply sent
* @see #reply(ReplyInfo)
*/
public void reply(ReplyInfo replyInfo, long timeout, TimeUnit unit, Callback<Void> callback);
public void reply(ReplyInfo replyInfo, long timeout, TimeUnit unit, Callback callback);
/**
* <p>Sends asynchronously a DATA frame on this stream.</p>
@ -162,7 +163,7 @@ public interface Stream
* @param callback the completion callback that gets notified of data sent
* @see #data(DataInfo)
*/
public <C> void data(DataInfo dataInfo, long timeout, TimeUnit unit, C context, Callback<C> callback);
public void data(DataInfo dataInfo, long timeout, TimeUnit unit, Callback callback);
/**
* <p>Sends asynchronously a HEADER frame on this stream.</p>
@ -188,7 +189,7 @@ public interface Stream
* @param callback the completion callback that gets notified of headers sent
* @see #headers(HeadersInfo)
*/
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Callback<Void> callback);
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Callback callback);
/**
* @return whether this stream is unidirectional or not

View File

@ -36,6 +36,7 @@ import org.eclipse.jetty.spdy.generator.Generator;
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
import org.eclipse.jetty.toolchain.test.annotation.Slow;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.thread.Scheduler;
import org.eclipse.jetty.util.thread.TimerScheduler;
import org.junit.Assert;
@ -75,15 +76,10 @@ public class AsyncTimeoutTest
};
final CountDownLatch failedLatch = new CountDownLatch(1);
session.syn(new SynInfo(true), null, timeout, unit, new Callback<Stream>()
session.syn(new SynInfo(true), null, timeout, unit, new Promise.Adapter<Stream>()
{
@Override
public void completed(Stream stream)
{
}
@Override
public void failed(Stream stream, Throwable x)
public void failed(Throwable x)
{
failedLatch.countDown();
}
@ -107,14 +103,14 @@ public class AsyncTimeoutTest
Session session = new StandardSession(SPDY.V2, bufferPool, threadPool, scheduler, new TestController(), null, 1, null, generator, new FlowControlStrategy.None())
{
@Override
protected void write(ByteBuffer buffer, Callback<FrameBytes> callback, FrameBytes frameBytes)
protected void write(ByteBuffer buffer, Callback callback)
{
try
{
// Wait if we're writing the data frame (control frame's first byte is 0x80)
if (buffer.get(0) == 0)
unit.sleep(2 * timeout);
super.write(buffer, callback, frameBytes);
super.write(buffer, callback);
}
catch (InterruptedException x)
{
@ -125,10 +121,10 @@ public class AsyncTimeoutTest
Stream stream = session.syn(new SynInfo(false), null).get(5, TimeUnit.SECONDS);
final CountDownLatch failedLatch = new CountDownLatch(1);
stream.data(new StringDataInfo("data", true), timeout, unit, null,new Callback.Empty<Void>()
stream.data(new StringDataInfo("data", true), timeout, unit, new Callback.Adapter()
{
@Override
public void failed(Void context, Throwable x)
public void failed(Throwable x)
{
failedLatch.countDown();
}
@ -137,13 +133,12 @@ public class AsyncTimeoutTest
Assert.assertTrue(failedLatch.await(2 * timeout, unit));
}
private static class TestController implements Controller<StandardSession.FrameBytes>
private static class TestController implements Controller
{
@Override
public int write(ByteBuffer buffer, Callback<StandardSession.FrameBytes> callback, StandardSession.FrameBytes context)
public void write(ByteBuffer buffer, Callback callback)
{
callback.completed(context);
return buffer.remaining();
callback.succeeded();
}
@Override

View File

@ -47,6 +47,7 @@ import org.eclipse.jetty.spdy.frames.SynStreamFrame;
import org.eclipse.jetty.spdy.generator.Generator;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.thread.Scheduler;
import org.eclipse.jetty.util.thread.TimerScheduler;
import org.junit.After;
@ -67,12 +68,13 @@ import static org.mockito.Matchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.doAnswer;
@RunWith(MockitoJUnitRunner.class)
public class StandardSessionTest
{
@Mock
private Controller<FrameBytes> controller;
private Controller controller;
private ByteBufferPool bufferPool;
private Executor threadPool;
@ -102,22 +104,17 @@ public class StandardSessionTest
@SuppressWarnings("unchecked")
private void setControllerWriteExpectationToFail(final boolean fail)
{
when(controller.write(any(ByteBuffer.class),any(Callback.class),any(StandardSession.FrameBytes.class))).thenAnswer(new Answer<Integer>()
{
public Integer answer(InvocationOnMock invocation)
{
Object[] args = invocation.getArguments();
Callback<StandardSession.FrameBytes> callback = (Callback<FrameBytes>)args[1];
FrameBytes context = (FrameBytes)args[2];
if (fail)
callback.failed(context,new ClosedChannelException());
else
callback.completed(context);
return 0;
}
});
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Callback callback = (Callback)args[1];
if (fail)
callback.failed(new ClosedChannelException());
else
callback.succeeded();
return null;
}})
.when(controller).write(any(ByteBuffer.class),any(Callback.class));
}
@Test
@ -221,10 +218,10 @@ public class StandardSessionTest
{
final CountDownLatch failedLatch = new CountDownLatch(1);
SynInfo synInfo = new SynInfo(headers,false,stream.getPriority());
stream.syn(synInfo,5,TimeUnit.SECONDS,new Callback.Empty<Stream>()
stream.syn(synInfo,5,TimeUnit.SECONDS,new Promise.Adapter<Stream>()
{
@Override
public void failed(Stream stream, Throwable x)
public void failed(Throwable x)
{
failedLatch.countDown();
}
@ -242,7 +239,7 @@ public class StandardSessionTest
assertThatPushStreamIsHalfClosed(pushStream);
assertThatPushStreamIsInSession(pushStream);
assertThatStreamIsAssociatedWithPushStream(stream,pushStream);
session.data(pushStream,new StringDataInfo("close",true),5,TimeUnit.SECONDS,null,null);
session.data(pushStream,new StringDataInfo("close",true),5,TimeUnit.SECONDS,null);
assertThatPushStreamIsClosed(pushStream);
assertThatPushStreamIsNotInSession(pushStream);
assertThatStreamIsNotAssociatedWithPushStream(stream,pushStream);
@ -331,7 +328,7 @@ public class StandardSessionTest
session.addListener(new TestStreamListener(createdListenerCalledLatch,closedListenerCalledLatch));
IStream stream = createStream();
IStream pushStream = createPushStream(stream);
session.data(pushStream,new StringDataInfo("close",true),5,TimeUnit.SECONDS,null,null);
session.data(pushStream,new StringDataInfo("close",true),5,TimeUnit.SECONDS,null);
assertThat("onStreamCreated listener has been called twice. Once for the stream and once for the pushStream",
createdListenerCalledLatch.await(5,TimeUnit.SECONDS),is(true));
assertThatOnStreamClosedListenerHasBeenCalled(closedListenerCalledLatch);
@ -420,21 +417,21 @@ public class StandardSessionTest
SynStreamFrame synStreamFrame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, null);
IStream stream = new StandardStream(synStreamFrame.getStreamId(), synStreamFrame.getPriority(), session, null);
stream.updateWindowSize(8192);
Callback.Empty<Void> callback = new Callback.Empty()
Callback.Adapter callback = new Callback.Adapter()
{
@Override
public void failed(Object context, Throwable x)
public void failed(Throwable x)
{
failedCalledLatch.countDown();
}
};
// first data frame should fail on controller.write()
stream.data(new StringDataInfo("data", false), 5, TimeUnit.SECONDS, null,callback);
stream.data(new StringDataInfo("data", false), 5, TimeUnit.SECONDS, callback);
// second data frame should fail without controller.writer() as the connection is expected to be broken after first controller.write() call failed.
stream.data(new StringDataInfo("data", false), 5, TimeUnit.SECONDS, null,callback);
stream.data(new StringDataInfo("data", false), 5, TimeUnit.SECONDS, callback);
verify(controller, times(1)).write(any(ByteBuffer.class), any(Callback.class), any(FrameBytes.class));
verify(controller, times(1)).write(any(ByteBuffer.class), any(Callback.class));
assertThat("Callback.failed has been called twice", failedCalledLatch.await(5, TimeUnit.SECONDS), is(true));
}

View File

@ -33,6 +33,7 @@ import org.eclipse.jetty.spdy.api.StringDataInfo;
import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.frames.SynStreamFrame;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
@ -72,7 +73,7 @@ public class StandardStreamTest
SynInfo synInfo = new SynInfo(false);
when(session.getStreams()).thenReturn(streams);
stream.syn(synInfo);
verify(session).syn(argThat(new PushSynInfoMatcher(stream.getId(), synInfo)), any(StreamFrameListener.class), anyLong(), any(TimeUnit.class), any(Callback.class));
verify(session).syn(argThat(new PushSynInfoMatcher(stream.getId(), synInfo)), any(StreamFrameListener.class), anyLong(), any(TimeUnit.class), any(Promise.class));
}
private class PushSynInfoMatcher extends ArgumentMatcher<PushSynInfo>
@ -104,10 +105,10 @@ public class StandardStreamTest
stream.updateCloseState(true, false);
assertThat("stream expected to be closed", stream.isClosed(), is(true));
final CountDownLatch failedLatch = new CountDownLatch(1);
stream.syn(new SynInfo(false), 1, TimeUnit.SECONDS, new Callback.Empty<Stream>()
stream.syn(new SynInfo(false), 1, TimeUnit.SECONDS, new Promise.Adapter<Stream>()
{
@Override
public void failed(Stream stream, Throwable x)
public void failed(Throwable x)
{
failedLatch.countDown();
}
@ -125,6 +126,6 @@ public class StandardStreamTest
stream.updateCloseState(synStreamFrame.isClose(), true);
assertThat("stream is half closed", stream.isHalfClosed(), is(true));
stream.data(new StringDataInfo("data on half closed stream", true));
verify(session, never()).data(any(IStream.class), any(DataInfo.class), anyInt(), any(TimeUnit.class), any(Callback.class), any(void.class));
verify(session, never()).data(any(IStream.class), any(DataInfo.class), anyInt(), any(TimeUnit.class), any(Callback.class));
}
}

View File

@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.spdy.StandardSession;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise;
import org.junit.Ignore;
import org.junit.Test;
@ -87,10 +88,10 @@ public class ClientUsageTest
// Then issue another similar request
stream.getSession().syn(new SynInfo(true), this);
}
}, 0, TimeUnit.MILLISECONDS, new Callback.Empty<Stream>()
}, 0, TimeUnit.MILLISECONDS, new Promise.Adapter<Stream>()
{
@Override
public void completed(Stream stream)
public void succeeded(Stream stream)
{
// Differently from JDK 7 AIO, there is no need to
// have an explicit parameter for the context since
@ -142,10 +143,10 @@ public class ClientUsageTest
}
}
}, 0, TimeUnit.MILLISECONDS, new Callback.Empty<Stream>()
}, 0, TimeUnit.MILLISECONDS, new Promise.Adapter<Stream>()
{
@Override
public void completed(Stream stream)
public void succeeded(Stream stream)
{
stream.data(new BytesDataInfo("wee".getBytes(Charset.forName("UTF-8")), false));
stream.data(new StringDataInfo("foo", false));

View File

@ -20,9 +20,12 @@ package org.eclipse.jetty.spdy.api;
import java.util.concurrent.TimeUnit;
import junit.framework.Assert;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise;
import org.junit.Ignore;
import org.junit.Test;
@ -32,7 +35,7 @@ public class ServerUsageTest
@Test
public void testServerSynAndReplyWithData() throws Exception
{
new ServerSessionFrameListener.Adapter()
ServerSessionFrameListener ssfl = new ServerSessionFrameListener.Adapter()
{
@Override
public StreamFrameListener onSyn(Stream stream, SynInfo streamInfo)
@ -54,12 +57,13 @@ public class ServerUsageTest
return null;
}
};
Assert.assertTrue(ssfl!=null);
}
@Test
public void testServerInitiatesStreamAndPushesData() throws Exception
{
new ServerSessionFrameListener.Adapter()
ServerSessionFrameListener ssfl = new ServerSessionFrameListener.Adapter()
{
@Override
public void onConnect(Session session)
@ -73,10 +77,10 @@ public class ServerUsageTest
//
// However, the API may allow to initiate the stream
session.syn(new SynInfo(false), null, 0, TimeUnit.MILLISECONDS, new Callback.Empty<Stream>()
session.syn(new SynInfo(false), null, 0, TimeUnit.MILLISECONDS, new Promise.Adapter<Stream>()
{
@Override
public void completed(Stream stream)
public void succeeded(Stream stream)
{
// The point here is that we have no idea if the client accepted our stream
// So we return a stream, we may be able to send the headers frame, but later
@ -88,12 +92,13 @@ public class ServerUsageTest
});
}
};
Assert.assertTrue(ssfl!=null);
}
@Test
public void testServerPush() throws Exception
{
new ServerSessionFrameListener.Adapter()
ServerSessionFrameListener ssfl = new ServerSessionFrameListener.Adapter()
{
@Override
public StreamFrameListener onSyn(Stream stream, SynInfo streamInfo)
@ -103,10 +108,10 @@ public class ServerUsageTest
Session session = stream.getSession();
// Since it's unidirectional, no need to pass the listener
session.syn(new SynInfo(new Fields(), false, (byte)0), null, 0, TimeUnit.MILLISECONDS, new Callback.Empty<Stream>()
session.syn(new SynInfo(new Fields(), false, (byte)0), null, 0, TimeUnit.MILLISECONDS, new Promise.Adapter<Stream>()
{
@Override
public void completed(Stream pushStream)
public void succeeded(Stream pushStream)
{
pushStream.data(new StringDataInfo("foo", false));
}
@ -114,5 +119,6 @@ public class ServerUsageTest
return null;
}
};
Assert.assertTrue(ssfl!=null);
}
}

View File

@ -41,6 +41,7 @@ import org.eclipse.jetty.util.BlockingCallback;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -67,14 +68,14 @@ public class HttpTransportOverSPDY implements HttpTransport
}
@Override
public <C> void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, C context, Callback<C> callback)
public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback)
{
if (LOG.isDebugEnabled())
LOG.debug("send {} {} {} {} last={}%n",this,stream,info,BufferUtil.toDetailString(content),lastContent);
if (stream.isClosed() || stream.isReset() )
{
callback.failed(context,new EofException("stream closed"));
callback.failed(new EofException("stream closed"));
return;
}
// new Throwable().printStackTrace();
@ -133,10 +134,10 @@ public class HttpTransportOverSPDY implements HttpTransport
// Is the stream still open?
if (stream.isClosed()|| stream.isReset())
// tell the callback about the EOF
callback.failed(context,new EofException("stream closed"));
callback.failed(new EofException("stream closed"));
else
// send the data and let it call the callback
stream.data(new ByteBufferDataInfo(content, lastContent),endPoint.getIdleTimeout(),TimeUnit.MILLISECONDS,context,callback);
stream.data(new ByteBufferDataInfo(content, lastContent),endPoint.getIdleTimeout(),TimeUnit.MILLISECONDS,callback);
}
// else do we need to close
else if (lastContent)
@ -144,21 +145,21 @@ public class HttpTransportOverSPDY implements HttpTransport
// Are we closed ?
if (stream.isClosed()|| stream.isReset())
// already closed by reply, so just tell callback we are complete
callback.completed(context);
callback.succeeded();
else
// send empty data to close and let the send call the callback
stream.data(new ByteBufferDataInfo(BufferUtil.EMPTY_BUFFER, lastContent),endPoint.getIdleTimeout(),TimeUnit.MILLISECONDS,context,callback);
stream.data(new ByteBufferDataInfo(BufferUtil.EMPTY_BUFFER, lastContent),endPoint.getIdleTimeout(),TimeUnit.MILLISECONDS,callback);
}
else
// No data and no close so tell callback we are completed
callback.completed(context);
callback.succeeded();
}
@Override
public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent) throws IOException
{
send(info,content,lastContent,streamBlocker.getPhase(),streamBlocker);
send(info,content,lastContent,streamBlocker);
try
{
streamBlocker.block();
@ -201,10 +202,10 @@ public class HttpTransportOverSPDY implements HttpTransport
final Fields pushRequestHeaders = createRequestHeaders(scheme, host, uri, pushResource);
// TODO: handle the timeout better
stream.syn(new SynInfo(pushHeaders, false), 0, TimeUnit.MILLISECONDS, new Callback.Empty<Stream>()
stream.syn(new SynInfo(pushHeaders, false), 0, TimeUnit.MILLISECONDS, new Promise.Adapter<Stream>()
{
@Override
public void completed(Stream pushStream)
public void succeeded(Stream pushStream)
{
HttpChannelOverSPDY pushChannel = newHttpChannelOverSPDY(pushStream, pushRequestHeaders);
pushChannel.requestStart(pushRequestHeaders, true);

View File

@ -53,6 +53,7 @@ import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.server.http.HTTPSPDYHeader;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise;
public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParser.RequestHandler<ByteBuffer>
{
@ -187,17 +188,17 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
}
@Override
public void rst(RstInfo rstInfo, long timeout, TimeUnit unit, Callback<Void> handler)
public void rst(RstInfo rstInfo, long timeout, TimeUnit unit, Callback handler)
{
// Not much we can do in HTTP land: just close the connection
goAway(timeout, unit, handler);
}
@Override
public void goAway(long timeout, TimeUnit unit, Callback<Void> handler)
public void goAway(long timeout, TimeUnit unit, Callback handler)
{
getEndPoint().close();
handler.completed(null);
handler.succeeded();
}
}
@ -214,21 +215,22 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
}
@Override
public void syn(SynInfo synInfo, long timeout, TimeUnit unit, Callback<Stream> handler)
public void syn(SynInfo synInfo, long timeout, TimeUnit unit, Promise<Stream> handler)
{
// TODO is this right? comment or imple are wrong??
// HTTP does not support pushed streams
handler.completed(new HTTPPushStream(2, getPriority(), getSession(), this));
handler.succeeded(this);
}
@Override
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Callback<Void> handler)
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Callback handler)
{
// TODO
throw new UnsupportedOperationException("Not Yet Implemented");
}
@Override
public void reply(ReplyInfo replyInfo, long timeout, TimeUnit unit, Callback<Void> handler)
public void reply(ReplyInfo replyInfo, long timeout, TimeUnit unit, Callback handler)
{
try
{
@ -263,11 +265,11 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
if (replyInfo.isClose())
completed();
handler.completed(null);
handler.succeeded();
}
catch (IOException x)
{
handler.failed(null, x);
handler.failed(x);
}
}
@ -287,7 +289,7 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
}
@Override
public <C> void data(DataInfo dataInfo, long timeout, TimeUnit unit, C context, Callback<C> handler)
public void data(DataInfo dataInfo, long timeout, TimeUnit unit, Callback handler)
{
try
{
@ -299,11 +301,11 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
if (dataInfo.isClose())
completed();
handler.completed(context);
handler.succeeded();
}
catch (IOException x)
{
handler.failed(context, x);
handler.failed(x);
}
}
}
@ -316,17 +318,17 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
}
@Override
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Callback<Void> handler)
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Callback handler)
{
// Ignore pushed headers
handler.completed(null);
handler.succeeded();
}
@Override
public <C> void data(DataInfo dataInfo, long timeout, TimeUnit unit, C context, Callback<C> handler)
public void data(DataInfo dataInfo, long timeout, TimeUnit unit, Callback handler)
{
// Ignore pushed data
handler.completed(context);
handler.succeeded();
}
}
}

View File

@ -43,6 +43,7 @@ import org.eclipse.jetty.spdy.client.SPDYClient;
import org.eclipse.jetty.spdy.server.http.HTTPSPDYHeader;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise;
/**
* <p>{@link SPDYProxyEngine} implements a SPDY to SPDY proxy, that is, converts SPDY events received by
@ -169,7 +170,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
Session existing = serverSessions.putIfAbsent(host, session);
if (existing != null)
{
session.goAway(getTimeout(), TimeUnit.MILLISECONDS, new Callback.Empty<Void>());
session.goAway(getTimeout(), TimeUnit.MILLISECONDS, new Callback.Adapter());
session = existing;
}
}
@ -202,7 +203,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
private void rst(Stream stream)
{
RstInfo rstInfo = new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM);
stream.getSession().rst(rstInfo, getTimeout(), TimeUnit.MILLISECONDS, new Callback.Empty<Void>());
stream.getSession().rst(rstInfo, getTimeout(), TimeUnit.MILLISECONDS, new Callback.Adapter());
}
private class ProxyStreamFrameListener extends StreamFrameListener.Adapter
@ -258,16 +259,16 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
{
final ReplyInfo replyInfo = this.replyInfo;
this.replyInfo = null;
clientStream.reply(replyInfo, getTimeout(), TimeUnit.MILLISECONDS, new Callback<Void>()
clientStream.reply(replyInfo, getTimeout(), TimeUnit.MILLISECONDS, new Callback()
{
@Override
public void completed(Void context)
public void succeeded()
{
logger.debug("P -> C {} from {} to {}", replyInfo, stream, clientStream);
}
@Override
public void failed(Void context, Throwable x)
public void failed(Throwable x)
{
logger.debug(x);
rst(clientStream);
@ -277,17 +278,17 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
private void data(final Stream stream, final DataInfo dataInfo)
{
clientStream.data(dataInfo, getTimeout(), TimeUnit.MILLISECONDS, null,new Callback<Void>()
clientStream.data(dataInfo, getTimeout(), TimeUnit.MILLISECONDS, new Callback()
{
@Override
public void completed(Void context)
public void succeeded()
{
dataInfo.consume(dataInfo.length());
logger.debug("P -> C {} from {} to {}", dataInfo, stream, clientStream);
}
@Override
public void failed(Void context, Throwable x)
public void failed(Throwable x)
{
logger.debug(x);
rst(clientStream);
@ -304,7 +305,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
* is a fast producer and the server a slow consumer, or if the client is a SPDY v2 client (and hence
* without flow control) while the server is a SPDY v3 server (and hence with flow control).</p>
*/
private class StreamHandler implements Callback<Stream>
private class StreamHandler implements Promise<Stream>
{
private final Queue<DataInfoHandler> queue = new LinkedList<>();
private final Stream clientStream;
@ -318,7 +319,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
}
@Override
public void completed(Stream serverStream)
public void succeeded(Stream serverStream)
{
logger.debug("P -> S {} from {} to {}", serverSynInfo, clientStream, serverStream);
@ -352,7 +353,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
}
@Override
public void failed(Stream serverStream, Throwable x)
public void failed(Throwable x)
{
logger.debug(x);
rst(clientStream);
@ -393,10 +394,10 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
private void flush(Stream serverStream, DataInfoHandler dataInfoHandler)
{
logger.debug("P -> S {} on {}", dataInfoHandler.dataInfo, serverStream);
serverStream.data(dataInfoHandler.dataInfo, getTimeout(), TimeUnit.MILLISECONDS, null,dataInfoHandler);
serverStream.data(dataInfoHandler.dataInfo, getTimeout(), TimeUnit.MILLISECONDS,dataInfoHandler);
}
private class DataInfoHandler implements Callback<Void>
private class DataInfoHandler implements Callback
{
private final DataInfo dataInfo;
private boolean flushing;
@ -407,7 +408,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
}
@Override
public void completed(Void context)
public void succeeded()
{
Stream serverStream;
DataInfoHandler dataInfoHandler;
@ -434,7 +435,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
}
@Override
public void failed(Void context, Throwable x)
public void failed(Throwable x)
{
logger.debug(x);
rst(clientStream);
@ -474,7 +475,7 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
{
Session clientSession = clientStream.getSession();
RstInfo clientRstInfo = new RstInfo(clientStream.getId(), serverRstInfo.getStreamStatus());
clientSession.rst(clientRstInfo, getTimeout(), TimeUnit.MILLISECONDS, new Callback.Empty<Void>());
clientSession.rst(clientRstInfo, getTimeout(), TimeUnit.MILLISECONDS, new Callback.Adapter());
}
}
}

View File

@ -89,11 +89,10 @@ public class HttpTransportOverSPDYTest
{
ByteBuffer content = null;
boolean lastContent = true;
Object context = null;
httpTransportOverSPDY.send(null, content, lastContent, context, callback);
httpTransportOverSPDY.send(null, content, lastContent, callback);
ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), anyObject(), any(Callback.class));
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), any(Callback.class));
assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true));
assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(0));
}
@ -104,11 +103,11 @@ public class HttpTransportOverSPDYTest
ByteBuffer content = createRandomByteBuffer();
boolean lastContent = true;
Object context = null;
httpTransportOverSPDY.send(null, content, lastContent, context, callback);
httpTransportOverSPDY.send(null, content, lastContent, callback);
ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), anyObject(), any(Callback.class));
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), any(Callback.class));
assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true));
assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096));
}
@ -118,11 +117,11 @@ public class HttpTransportOverSPDYTest
{
ByteBuffer content = BufferUtil.EMPTY_BUFFER;
boolean lastContent = true;
Object context = null;
httpTransportOverSPDY.send(null, content, lastContent, context, callback);
httpTransportOverSPDY.send(null, content, lastContent, callback);
ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), anyObject(), any(Callback.class));
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), any(Callback.class));
assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true));
assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(0));
}
@ -132,11 +131,10 @@ public class HttpTransportOverSPDYTest
{
ByteBuffer content = null;
boolean lastContent = false;
Object context = null;
httpTransportOverSPDY.send(null, content, lastContent, context, callback);
verify(stream, times(0)).data(any(ByteBufferDataInfo.class), anyLong(), any(TimeUnit.class), anyObject(),
any(Callback.class));
httpTransportOverSPDY.send(null, content, lastContent, callback);
verify(stream, times(0)).data(any(ByteBufferDataInfo.class), anyLong(), any(TimeUnit.class), any(Callback.class));
}
@Test
@ -144,11 +142,11 @@ public class HttpTransportOverSPDYTest
{
ByteBuffer content = createRandomByteBuffer();
boolean lastContent = false;
Object context = null;
httpTransportOverSPDY.send(null, content, lastContent, context, callback);
httpTransportOverSPDY.send(null, content, lastContent, callback);
ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), anyObject(), any(Callback.class));
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), any(Callback.class));
assertThat("lastContent is false", dataInfoCaptor.getValue().isClose(), is(false));
assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(4096));
}
@ -158,12 +156,11 @@ public class HttpTransportOverSPDYTest
{
ByteBuffer content = BufferUtil.EMPTY_BUFFER;
boolean lastContent = false;
Object context = null;
httpTransportOverSPDY.send(null, content, lastContent, context, callback);
verify(stream, times(0)).data(any(ByteBufferDataInfo.class), anyLong(), any(TimeUnit.class), anyObject(),
any(Callback.class));
verify(callback, times(1)).completed(context);
httpTransportOverSPDY.send(null, content, lastContent, callback);
verify(stream, times(0)).data(any(ByteBufferDataInfo.class), anyLong(), any(TimeUnit.class), any(Callback.class));
verify(callback, times(1)).succeeded();
}
@Test
@ -171,16 +168,16 @@ public class HttpTransportOverSPDYTest
{
ByteBuffer content = null;
boolean lastContent = true;
Object context = null;
// when stream.isClosed() is called a 2nd time, the teply has closed the stream already
when(stream.isClosed()).thenReturn(false).thenReturn(true);
httpTransportOverSPDY.send(responseInfo, content, lastContent, context, callback);
httpTransportOverSPDY.send(responseInfo, content, lastContent, callback);
ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
verify(stream, times(1)).reply(replyInfoCaptor.capture());
assertThat("ReplyInfo close is true", replyInfoCaptor.getValue().isClose(), is(true));
verify(callback, times(1)).completed(context);
verify(callback, times(1)).succeeded();
}
@Test
@ -189,16 +186,16 @@ public class HttpTransportOverSPDYTest
ByteBuffer content = createRandomByteBuffer();
boolean lastContent = true;
Object context = null;
httpTransportOverSPDY.send(responseInfo, content, lastContent, context, callback);
httpTransportOverSPDY.send(responseInfo, content, lastContent, callback);
ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
verify(stream, times(1)).reply(replyInfoCaptor.capture());
assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false));
ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), anyObject(), any(Callback.class));
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), any(Callback.class));
assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true));
assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096));
}
@ -208,15 +205,14 @@ public class HttpTransportOverSPDYTest
{
ByteBuffer content = null;
boolean lastContent = false;
Object context = null;
httpTransportOverSPDY.send(responseInfo, content, lastContent, context, callback);
httpTransportOverSPDY.send(responseInfo, content, lastContent, callback);
ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
verify(stream, times(1)).reply(replyInfoCaptor.capture());
assertThat("ReplyInfo close is true", replyInfoCaptor.getValue().isClose(), is(false));
verify(stream, times(0)).data(any(ByteBufferDataInfo.class), anyLong(), any(TimeUnit.class), anyObject(),
any(Callback.class));
verify(stream, times(0)).data(any(ByteBufferDataInfo.class), anyLong(), any(TimeUnit.class), any(Callback.class));
}
@Test
@ -225,15 +221,15 @@ public class HttpTransportOverSPDYTest
ByteBuffer content = createRandomByteBuffer();
boolean lastContent = false;
Object context = null;
httpTransportOverSPDY.send(responseInfo, content, lastContent, context, callback);
httpTransportOverSPDY.send(responseInfo, content, lastContent, callback);
ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
verify(stream, times(1)).reply(replyInfoCaptor.capture());
assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false));
ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), anyObject(), any(Callback.class));
verify(stream, times(1)).data(dataInfoCaptor.capture(), anyLong(), any(TimeUnit.class), any(Callback.class));
assertThat("lastContent is false", dataInfoCaptor.getValue().isClose(), is(false));
assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096));
}

View File

@ -52,6 +52,7 @@ import org.eclipse.jetty.spdy.server.SPDYServerConnector;
import org.eclipse.jetty.spdy.server.http.HTTPSPDYHeader;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@ -564,10 +565,10 @@ public class ProxyHTTPSPDYTest
Fields pushHeaders = new Fields();
pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/push");
stream.syn(new SynInfo(pushHeaders, false), 5, TimeUnit.SECONDS, new Callback.Empty<Stream>()
stream.syn(new SynInfo(pushHeaders, false), 5, TimeUnit.SECONDS, new Promise.Adapter<Stream>()
{
@Override
public void completed(Stream pushStream)
public void succeeded(Stream pushStream)
{
pushStream.data(new BytesDataInfo(data, true));
}
@ -617,10 +618,10 @@ public class ProxyHTTPSPDYTest
Fields pushHeaders = new Fields();
pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/push");
stream.syn(new SynInfo(pushHeaders, false), 5, TimeUnit.SECONDS, new Callback.Empty<Stream>()
stream.syn(new SynInfo(pushHeaders, false), 5, TimeUnit.SECONDS, new Promise.Adapter<Stream>()
{
@Override
public void completed(Stream pushStream)
public void succeeded(Stream pushStream)
{
pushStream.data(new BytesDataInfo(data, true));
}

View File

@ -28,6 +28,7 @@ import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.SessionFrameListener;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise;
import org.junit.Assert;
import org.junit.Test;
@ -68,10 +69,10 @@ public class PingTest extends AbstractTest
@Override
public void onConnect(Session session)
{
session.ping(0, TimeUnit.MILLISECONDS, new Callback.Empty<PingInfo>()
session.ping(0, TimeUnit.MILLISECONDS, new Promise.Adapter<PingInfo>()
{
@Override
public void completed(PingInfo pingInfo)
public void succeeded(PingInfo pingInfo)
{
pingId = pingInfo.getPingId();
}

View File

@ -61,6 +61,7 @@ import org.eclipse.jetty.spdy.parser.Parser;
import org.eclipse.jetty.spdy.parser.Parser.Listener;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise;
import org.junit.Assert;
import org.junit.Test;
@ -244,10 +245,10 @@ public class PushStreamTest extends AbstractTest
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{
stream.reply(new ReplyInfo(true));
stream.syn(new SynInfo(false),1,TimeUnit.SECONDS,new Callback.Empty<Stream>()
stream.syn(new SynInfo(false),1,TimeUnit.SECONDS,new Promise.Adapter<Stream>()
{
@Override
public void failed(Stream stream, Throwable x)
public void failed(Throwable x)
{
pushStreamFailedLatch.countDown();
}

View File

@ -134,10 +134,10 @@ public class ResetStreamTest extends AbstractTest
});
Stream stream = session.syn(new SynInfo(false),null).get(5,TimeUnit.SECONDS);
stream.data(new StringDataInfo("data",true),5,TimeUnit.SECONDS,null,new Callback.Empty<Void>()
stream.data(new StringDataInfo("data",true),5,TimeUnit.SECONDS,new Callback.Adapter()
{
@Override
public void completed(Void context)
public void succeeded()
{
synLatch.countDown();
}
@ -182,12 +182,12 @@ public class ResetStreamTest extends AbstractTest
Stream stream = session.syn(new SynInfo(false),null).get(5,TimeUnit.SECONDS);
assertThat("syn is received by server", synLatch.await(5,TimeUnit.SECONDS),is(true));
stream.data(new StringDataInfo("data",false),5,TimeUnit.SECONDS,null,null);
stream.data(new StringDataInfo("data",false),5,TimeUnit.SECONDS,null);
assertThat("stream is reset",rstLatch.await(5,TimeUnit.SECONDS),is(true));
stream.data(new StringDataInfo("2nd dataframe",false),5L,TimeUnit.SECONDS,null,new Callback.Empty<Void>()
stream.data(new StringDataInfo("2nd dataframe",false),5L,TimeUnit.SECONDS,new Callback.Adapter()
{
@Override
public void failed(Void context, Throwable x)
public void failed(Throwable x)
{
failLatch.countDown();
}

View File

@ -43,6 +43,7 @@ import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise;
import org.junit.Assert;
import org.junit.Test;
@ -172,12 +173,12 @@ public class SynDataReplyDataLoadTest extends AbstractTest
latch.countDown();
}
}
}, 0, TimeUnit.SECONDS, new Callback.Empty<Stream>()
}, 0, TimeUnit.SECONDS, new Promise.Adapter<Stream>()
{
@Override
public void completed(Stream stream)
public void succeeded(Stream stream)
{
stream.data(new StringDataInfo("data_" + stream.getId(), true), 0, TimeUnit.SECONDS, null,null);
stream.data(new StringDataInfo("data_" + stream.getId(), true), 0, TimeUnit.SECONDS, null);
}
});
}

View File

@ -39,6 +39,7 @@ import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Promise;
import org.junit.Assert;
import org.junit.Test;
@ -199,10 +200,10 @@ public class SynReplyTest extends AbstractTest
Assert.assertTrue(stream.isHalfClosed());
stream.reply(new ReplyInfo(false));
stream.data(new StringDataInfo(data1, false), 5, TimeUnit.SECONDS, null,new Callback.Empty<Void>()
stream.data(new StringDataInfo(data1, false), 5, TimeUnit.SECONDS, new Callback.Adapter()
{
@Override
public void completed(Void context)
public void succeeded()
{
stream.data(new StringDataInfo(data2, true));
}
@ -278,10 +279,10 @@ public class SynReplyTest extends AbstractTest
Assert.assertEquals(clientData, data);
clientDataLatch.countDown();
}
}, 0, TimeUnit.MILLISECONDS, new Callback.Empty<Stream>()
}, 0, TimeUnit.MILLISECONDS, new Promise.Adapter<Stream>()
{
@Override
public void completed(Stream stream)
public void succeeded(Stream stream)
{
stream.data(new StringDataInfo(serverData, true));
}

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
/** Fast B64 Encoder/Decoder as described in RFC 1421.

View File

@ -29,7 +29,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* A Callback for simple reusable conversion of an
* asynchronous API to blocking.
* <p>
* To avoid late redundant calls to {@link #completed(Integer)} or {@link #failed(Integer, Throwable)} from
* To avoid late redundant calls to {@link #succeeded()} or {@link #failed(Throwable)} from
* interfering with later reuses of this class, the callback context is used to hold pass a phase indicated
* and only a single callback per phase is allowed.
* <p>
@ -41,57 +41,45 @@ import java.util.concurrent.atomic.AtomicBoolean;
*
* public void blockingMethod(Object args) throws Exception
* {
* asyncMethod(args,cb.getPhase(),cb);
* asyncMethod(args,cb);
* cb.block();
* }
*
* public <C>void asyncMethod(Object args, C context, Callback<C> callback)
* public <C>void asyncMethod(Object args, Callback callback)
* {
* ...
* }
* }
*/
public class BlockingCallback implements Callback<Integer>
public class BlockingCallback implements Callback
{
private static Throwable COMPLETED=new Throwable();
private final AtomicBoolean _done=new AtomicBoolean(false);
private final Semaphore _semaphone = new Semaphore(0);
private Throwable _cause;
private volatile int _phase;
public BlockingCallback()
{}
@Override
public void completed(Integer phase)
public void succeeded()
{
if (phase==null)
throw new IllegalStateException("Context must be getPhase()");
if (_phase==phase.intValue() && _done.compareAndSet(false,true))
if (_done.compareAndSet(false,true))
{
_phase++;
_cause=COMPLETED;
_semaphone.release();
}
}
@Override
public void failed(Integer phase, Throwable cause)
public void failed(Throwable cause)
{
if (phase==null)
throw new IllegalStateException("Context must be getPhase()");
if (_phase==phase.intValue() && _done.compareAndSet(false,true))
if (_done.compareAndSet(false,true))
{
_phase++;
_cause=cause;
_semaphone.release();
}
}
public Integer getPhase()
{
return new Integer(_phase);
}
/** Block until the FutureCallback is done or cancelled and
* after the return leave in the state as if a {@link #reset()} had been

View File

@ -39,42 +39,42 @@ import org.eclipse.jetty.util.log.Log;
/**
* <p>A callback abstraction that handles completed/failed events of asynchronous operations.</p>
*
* <p>Semantically this is equivalent to an optimise Promise&lt;Void&gt;, but callback is a more meaningful
* name than EmptyPromise</p>
*
* @param <C> the type of the context object
*/
public interface Callback<C>
public interface Callback
{
/**
* <p>Callback invoked when the operation completes.</p>
*
* @param context the context
* @see #failed(Object, Throwable)
* @see #failed(Throwable)
*/
public abstract void completed(C context);
public abstract void succeeded();
/**
* <p>Callback invoked when the operation fails.</p>
*
* @param context the context
* @param x the reason for the operation failure
*/
public void failed(C context, Throwable x);
public void failed(Throwable x);
/**
* <p>Empty implementation of {@link Callback}</p>
*
* @param <C> the type of the context object
*/
public static class Empty<C> implements Callback<C>
public static class Adapter implements Callback
{
@Override
public void completed(C context)
public void succeeded()
{
}
@Override
public void failed(C context, Throwable x)
public void failed(Throwable x)
{
Log.getLogger(this.getClass()).warn(String.valueOf(context),x);
Log.getLogger(this.getClass()).warn(x);
}
}
}

View File

@ -20,16 +20,16 @@ package org.eclipse.jetty.util;
import java.util.concurrent.Executor;
public abstract class ExecutorCallback<C> implements Callback<C>
public abstract class ExecutorCallback implements Callback
{
private final ForkInvoker<C> _invoker;
private final ForkInvoker<Void> _invoker;
private final Executor _executor;
private final Runnable _onComplete=new Runnable()
{
@Override
public void run()
{
onCompleted(null);
onCompleted();
}
};
@ -47,39 +47,27 @@ public abstract class ExecutorCallback<C> implements Callback<C>
}
@Override
public void completed(final C context)
public void succeeded()
{
// Should we execute?
if (_invoker==null)
{
if (context==null)
_executor.execute(_onComplete);
else
{
_executor.execute(new Runnable()
{
@Override
public void run()
{
onCompleted(context);
}
});
}
_executor.execute(_onComplete);
}
else if (alwaysDispatchCompletion())
{
_invoker.fork(context);
_invoker.fork(null);
}
else
{
_invoker.invoke(context);
_invoker.invoke(null);
}
}
protected abstract void onCompleted(C context);
protected abstract void onCompleted();
@Override
public void failed(final C context, final Throwable x)
public void failed(final Throwable x)
{
// Always execute failure
Runnable runnable = new Runnable()
@ -87,13 +75,13 @@ public abstract class ExecutorCallback<C> implements Callback<C>
@Override
public void run()
{
onFailed(context, x);
onFailed(x);
}
@Override
public String toString()
{
return String.format("ExecutorCallback@%x{%s,%s}", hashCode(), context, x);
return String.format("ExecutorCallback@%x{%s}", hashCode(), x);
}
};
@ -103,7 +91,7 @@ public abstract class ExecutorCallback<C> implements Callback<C>
_executor.execute(runnable);
}
protected void onFailed(C context, Throwable x)
protected void onFailed(Throwable x)
{
}
@ -118,7 +106,7 @@ public abstract class ExecutorCallback<C> implements Callback<C>
return String.format("%s@%x", getClass(), hashCode());
}
private class ExecutorCallbackInvoker extends ForkInvoker<C> implements Runnable
private class ExecutorCallbackInvoker extends ForkInvoker<Void> implements Runnable
{
private ExecutorCallbackInvoker(int maxInvocations)
{
@ -126,34 +114,21 @@ public abstract class ExecutorCallback<C> implements Callback<C>
}
@Override
public void fork(final C context)
public void fork(Void arg)
{
_executor.execute(context == null ? this : new Runnable()
{
@Override
public void run()
{
call(context);
}
@Override
public String toString()
{
return String.format("ExecutorCallback@%x{%s}", hashCode(), context);
}
});
_executor.execute(this);
}
@Override
public void call(C context)
public void call(Void arg)
{
onCompleted(context);
onCompleted();
}
@Override
public void run()
{
call(null);
onCompleted();
}
}
}

View File

@ -19,11 +19,11 @@
package org.eclipse.jetty.util;
/**
* Utility class that splits calls to {@link #invoke(T)} into calls to {@link #fork(T)} or {@link #call(T)}
* depending on the max number of reentrant calls to {@link #invoke(T)}.
* Utility class that splits calls to {@link #invoke(Object)} into calls to {@link #fork(Object)} or {@link #call(Object)}
* depending on the max number of reentrant calls to {@link #invoke(Object)}.
* <p/>
* This class prevents {@link StackOverflowError}s in case of methods that end up invoking themselves,
* such is common for {@link Callback#completed(Object)}.
* such is common for {@link Callback#succeeded()}.
* <p/>
* Typical use case is:
* <pre>
@ -48,7 +48,6 @@ package org.eclipse.jetty.util;
* }
* </pre>
*
* @param <T> the generic type of this class
*/
public abstract class ForkInvoker<T>
{
@ -63,12 +62,12 @@ public abstract class ForkInvoker<T>
private final int _maxInvocations;
/**
* Creates an instance with the given max number of reentrant calls to {@link #invoke(T)}
* Creates an instance with the given max number of reentrant calls to {@link #invoke(Object)}
* <p/>
* If {@code maxInvocations} is zero or negative, it is interpreted
* as if the max number of reentrant calls is infinite.
*
* @param maxInvocations the max number of reentrant calls to {@link #invoke(T)}
* @param maxInvocations the max number of reentrant calls to {@link #invoke(Object)}
*/
public ForkInvoker(int maxInvocations)
{
@ -76,22 +75,22 @@ public abstract class ForkInvoker<T>
}
/**
* Invokes either {@link #fork(T)} or {@link #call(T)}.
* If {@link #condition()} returns true, {@link #fork(T)} is invoked.
* Invokes either {@link #fork(Object)} or {@link #call(Object)}.
* If {@link #condition()} returns true, {@link #fork(Object)} is invoked.
* Otherwise, if the max number of reentrant calls is positive and the
* actual number of reentrant invocations exceeds it, {@link #fork(T)} is invoked.
* Otherwise, {@link #call(T)} is invoked.
* actual number of reentrant invocations exceeds it, {@link #fork(Object)} is invoked.
* Otherwise, {@link #call(Object)} is invoked.
* @param arg TODO
*
* @param context the invocation context
* @return true if {@link #fork(T)} has been called, false otherwise
* @return true if {@link #fork(Object)} has been called, false otherwise
*/
public boolean invoke(T context)
public boolean invoke(T arg)
{
boolean countInvocations = _maxInvocations > 0;
int invocations = __invocations.get();
if (condition() || countInvocations && invocations > _maxInvocations)
{
fork(context);
fork(arg);
return true;
}
else
@ -100,7 +99,7 @@ public abstract class ForkInvoker<T>
__invocations.set(invocations + 1);
try
{
call(context);
call(arg);
return false;
}
finally
@ -113,9 +112,9 @@ public abstract class ForkInvoker<T>
/**
* Subclasses should override this method returning true if they want
* {@link #invoke(T)} to call {@link #fork(T)}.
* {@link #invoke(Object)} to call {@link #fork(Object)}.
*
* @return true if {@link #invoke(T)} should call {@link #fork(T)}, false otherwise
* @return true if {@link #invoke(Object)} should call {@link #fork(Object)}, false otherwise
*/
protected boolean condition()
{
@ -124,15 +123,13 @@ public abstract class ForkInvoker<T>
/**
* Executes the forked invocation
*
* @param context the invocation context
* @param arg TODO
*/
public abstract void fork(T context);
public abstract void fork(T arg);
/**
* Executes the direct, non-forked, invocation
*
* @param context the invocation context
* @param arg TODO
*/
public abstract void call(T context);
public abstract void call(T arg);
}

View File

@ -23,57 +23,52 @@ import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.management.RuntimeErrorException;
public class FutureCallback<C> implements Future<C>,Callback<C>
public class FutureCallback implements Future<Void>,Callback
{
private static Throwable COMPLETED=new Throwable();
private final AtomicBoolean _done=new AtomicBoolean(false);
private final CountDownLatch _latch=new CountDownLatch(1);
private Throwable _cause;
private C _context;
public FutureCallback()
{}
public FutureCallback(C ctx)
public FutureCallback(boolean completed)
{
_cause=COMPLETED;
_context=ctx;
_done.set(true);
_latch.countDown();
if (completed)
{
_cause=COMPLETED;
_done.set(true);
_latch.countDown();
}
}
public FutureCallback(C ctx, Throwable failed)
public FutureCallback(Throwable failed)
{
_context=ctx;
_cause=failed;
_done.set(true);
_latch.countDown();
}
@Override
public void completed(C context)
public void succeeded()
{
if (_done.compareAndSet(false,true))
{
_context=context;
_cause=COMPLETED;
_latch.countDown();
}
}
@Override
public void failed(C context, Throwable cause)
public void failed(Throwable cause)
{
if (_done.compareAndSet(false,true))
{
_context=context;
_cause=cause;
_latch.countDown();
}
@ -84,7 +79,6 @@ public class FutureCallback<C> implements Future<C>,Callback<C>
{
if (_done.compareAndSet(false,true))
{
_context=null;
_cause=new CancellationException();
_latch.countDown();
return true;
@ -117,24 +111,24 @@ public class FutureCallback<C> implements Future<C>,Callback<C>
}
@Override
public C get() throws InterruptedException, ExecutionException
public Void get() throws InterruptedException, ExecutionException
{
_latch.await();
if (_cause==COMPLETED)
return _context;
return null;
if (_cause instanceof CancellationException)
throw (CancellationException) new CancellationException().initCause(_cause);
throw new ExecutionException(_cause);
}
@Override
public C get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
public Void get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{
if (!_latch.await(timeout,unit))
throw new TimeoutException();
if (_cause==COMPLETED)
return _context;
return null;
if (_cause instanceof TimeoutException)
throw (TimeoutException)_cause;
if (_cause instanceof CancellationException)
@ -157,7 +151,7 @@ public class FutureCallback<C> implements Future<C>,Callback<C>
@Override
public String toString()
{
return String.format("FutureCallback@%x{%b,%b,%s}",hashCode(),_done,_cause==COMPLETED,_context);
return String.format("FutureCallback@%x{%b,%b}",hashCode(),_done,_cause==COMPLETED);
}
}

View File

@ -0,0 +1,159 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import java.io.IOException;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
public class FuturePromise<C> implements Future<C>,Promise<C>
{
private static Throwable COMPLETED=new Throwable();
private final AtomicBoolean _done=new AtomicBoolean(false);
private final CountDownLatch _latch=new CountDownLatch(1);
private Throwable _cause;
private C _result;
public FuturePromise()
{}
public FuturePromise(C result)
{
_cause=COMPLETED;
_result=result;
_done.set(true);
_latch.countDown();
}
public FuturePromise(C ctx, Throwable failed)
{
_result=ctx;
_cause=failed;
_done.set(true);
_latch.countDown();
}
@Override
public void succeeded(C result)
{
if (_done.compareAndSet(false,true))
{
_result=result;
_cause=COMPLETED;
_latch.countDown();
}
}
@Override
public void failed(Throwable cause)
{
if (_done.compareAndSet(false,true))
{
_cause=cause;
_latch.countDown();
}
}
@Override
public boolean cancel(boolean mayInterruptIfRunning)
{
if (_done.compareAndSet(false,true))
{
_result=null;
_cause=new CancellationException();
_latch.countDown();
return true;
}
return false;
}
@Override
public boolean isCancelled()
{
if (_done.get())
{
try
{
_latch.await();
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
return _cause instanceof CancellationException;
}
return false;
}
@Override
public boolean isDone()
{
return _done.get() && _latch.getCount()==0;
}
@Override
public C get() throws InterruptedException, ExecutionException
{
_latch.await();
if (_cause==COMPLETED)
return _result;
if (_cause instanceof CancellationException)
throw (CancellationException) new CancellationException().initCause(_cause);
throw new ExecutionException(_cause);
}
@Override
public C get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{
if (!_latch.await(timeout,unit))
throw new TimeoutException();
if (_cause==COMPLETED)
return _result;
if (_cause instanceof TimeoutException)
throw (TimeoutException)_cause;
if (_cause instanceof CancellationException)
throw (CancellationException) new CancellationException().initCause(_cause);
throw new ExecutionException(_cause);
}
public static void rethrow(ExecutionException e) throws IOException
{
Throwable cause=e.getCause();
if (cause instanceof IOException)
throw (IOException)cause;
if (cause instanceof Error)
throw (Error)cause;
if (cause instanceof RuntimeException)
throw (RuntimeException)cause;
throw new RuntimeException(cause);
}
@Override
public String toString()
{
return String.format("FutureCallback@%x{%b,%b,%s}",hashCode(),_done,_cause==COMPLETED,_result);
}
}

View File

@ -35,8 +35,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletException;

View File

@ -0,0 +1,65 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import org.eclipse.jetty.util.log.Log;
/**
* <p>A callback abstraction that handles completed/failed events of asynchronous operations.</p>
*
* @param <C> the type of the context object
*/
public interface Promise<C>
{
/**
* <p>Callback invoked when the operation completes.</p>
*
* @param result the context
* @see #failed(Throwable)
*/
public abstract void succeeded(C result);
/**
* <p>Callback invoked when the operation fails.</p>
*
* @param x the reason for the operation failure
*/
public void failed(Throwable x);
/**
* <p>Empty implementation of {@link Promise}</p>
*
* @param <C> the type of the context object
*/
public static class Adapter<C> implements Promise<C>
{
@Override
public void succeeded(C result)
{
}
@Override
public void failed(Throwable x)
{
Log.getLogger(this.getClass()).warn(x);
}
}
}

View File

@ -16,21 +16,29 @@
// ========================================================================
//
package org.eclipse.jetty.websocket.server.callbacks;
package org.eclipse.jetty.util;
import org.eclipse.jetty.util.FutureCallback;
public class WebSocketOpenCallback extends FutureCallback<String>
public class PromisingCallback<R> implements Callback
{
@Override
public void completed(String context)
private final Promise<R> _promise;
private final R _result;
public PromisingCallback(Promise<R> promise, R result)
{
// TODO notify API on connection open
_promise=promise;
_result=result;
}
@Override
public void succeeded()
{
_promise.succeeded(_result);
}
@Override
public void failed(String context, Throwable x)
public void failed(Throwable x)
{
// TODO notify API on open failure
_promise.failed(x);
}
}

View File

@ -25,5 +25,5 @@ import java.util.concurrent.Future;
*/
public interface Graceful
{
public <C> Future<C> shutdown(C c);
public Future<Void> shutdown();
}

View File

@ -82,7 +82,7 @@ public class BlockingCallbackTest
public void testDone() throws Exception
{
BlockingCallback fcb= _factory.newBlockingCallback();
fcb.completed(fcb.getPhase());
fcb.succeeded();
long start=System.currentTimeMillis();
fcb.block();
Assert.assertThat(System.currentTimeMillis()-start,Matchers.lessThan(500L));
@ -101,7 +101,7 @@ public class BlockingCallbackTest
{
latch.countDown();
try{TimeUnit.MILLISECONDS.sleep(100);}catch(Exception e){e.printStackTrace();}
fcb.completed(fcb.getPhase());
fcb.succeeded();
}
}).start();
@ -117,7 +117,7 @@ public class BlockingCallbackTest
{
BlockingCallback fcb= _factory.newBlockingCallback();
Exception ex=new Exception("FAILED");
fcb.failed(fcb.getPhase(),ex);
fcb.failed(ex);
long start=System.currentTimeMillis();
try
@ -146,7 +146,7 @@ public class BlockingCallbackTest
{
latch.countDown();
try{TimeUnit.MILLISECONDS.sleep(100);}catch(Exception e){e.printStackTrace();}
fcb.failed(fcb.getPhase(),ex);
fcb.failed(ex);
}
}).start();

View File

@ -18,9 +18,6 @@
package org.eclipse.jetty.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
@ -30,19 +27,13 @@ import java.util.concurrent.TimeoutException;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
public class FutureCallbackTest
{
@Test
public void testNotDone()
{
FutureCallback<String> fcb= new FutureCallback<>();
FutureCallback fcb= new FutureCallback();
Assert.assertFalse(fcb.isDone());
Assert.assertFalse(fcb.isCancelled());
}
@ -50,7 +41,7 @@ public class FutureCallbackTest
@Test
public void testGetNotDone() throws Exception
{
FutureCallback<String> fcb= new FutureCallback<>();
FutureCallback fcb= new FutureCallback();
long start=System.currentTimeMillis();
try
@ -67,20 +58,20 @@ public class FutureCallbackTest
@Test
public void testDone() throws Exception
{
FutureCallback<String> fcb= new FutureCallback<>();
fcb.completed("Ctx");
FutureCallback fcb= new FutureCallback();
fcb.succeeded();
Assert.assertTrue(fcb.isDone());
Assert.assertFalse(fcb.isCancelled());
long start=System.currentTimeMillis();
Assert.assertEquals("Ctx",fcb.get());
Assert.assertEquals(null,fcb.get());
Assert.assertThat(System.currentTimeMillis()-start,Matchers.lessThan(500L));
}
@Test
public void testGetDone() throws Exception
{
final FutureCallback<String> fcb= new FutureCallback<>();
final FutureCallback fcb= new FutureCallback();
final CountDownLatch latch = new CountDownLatch(1);
new Thread(new Runnable(){
@ -88,13 +79,13 @@ public class FutureCallbackTest
{
latch.countDown();
try{TimeUnit.MILLISECONDS.sleep(100);}catch(Exception e){e.printStackTrace();}
fcb.completed("Ctx");
fcb.succeeded();
}
}).start();
latch.await();
long start=System.currentTimeMillis();
Assert.assertEquals("Ctx",fcb.get(10000,TimeUnit.MILLISECONDS));
Assert.assertEquals(null,fcb.get(10000,TimeUnit.MILLISECONDS));
Assert.assertThat(System.currentTimeMillis()-start,Matchers.greaterThan(10L));
Assert.assertThat(System.currentTimeMillis()-start,Matchers.lessThan(1000L));
@ -107,9 +98,9 @@ public class FutureCallbackTest
@Test
public void testFailed() throws Exception
{
FutureCallback<String> fcb= new FutureCallback<>();
FutureCallback fcb= new FutureCallback();
Exception ex=new Exception("FAILED");
fcb.failed("Ctx",ex);
fcb.failed(ex);
Assert.assertTrue(fcb.isDone());
Assert.assertFalse(fcb.isCancelled());
@ -129,7 +120,7 @@ public class FutureCallbackTest
@Test
public void testGetFailed() throws Exception
{
final FutureCallback<String> fcb= new FutureCallback<>();
final FutureCallback fcb= new FutureCallback();
final Exception ex=new Exception("FAILED");
final CountDownLatch latch = new CountDownLatch(1);
@ -138,7 +129,7 @@ public class FutureCallbackTest
{
latch.countDown();
try{TimeUnit.MILLISECONDS.sleep(100);}catch(Exception e){e.printStackTrace();}
fcb.failed("Ctx",ex);
fcb.failed(ex);
}
}).start();
@ -165,7 +156,7 @@ public class FutureCallbackTest
@Test
public void testCancelled() throws Exception
{
FutureCallback<String> fcb= new FutureCallback<>();
FutureCallback fcb= new FutureCallback();
fcb.cancel(true);
Assert.assertTrue(fcb.isDone());
Assert.assertTrue(fcb.isCancelled());
@ -186,7 +177,7 @@ public class FutureCallbackTest
@Test
public void testGetCancelled() throws Exception
{
final FutureCallback<String> fcb= new FutureCallback<>();
final FutureCallback fcb= new FutureCallback();
final CountDownLatch latch = new CountDownLatch(1);
new Thread(new Runnable(){

View File

@ -20,8 +20,8 @@ package org.eclipse.jetty.websocket.client;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.Future;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.websocket.api.UpgradeRequest;
import org.eclipse.jetty.websocket.api.UpgradeResponse;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
@ -30,7 +30,7 @@ import org.eclipse.jetty.websocket.common.events.EventDriver;
public interface WebSocketClient
{
public FutureCallback<UpgradeResponse> connect(URI websocketUri) throws IOException;
public Future<UpgradeResponse> connect(URI websocketUri) throws IOException;
public WebSocketClientFactory getFactory();

View File

@ -29,6 +29,7 @@ import java.util.Locale;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.FutureCallback;
@ -114,7 +115,7 @@ public class ConnectionManager extends ContainerLifeCycle
}
}
public FutureCallback<UpgradeResponse> connectPhysical(DefaultWebSocketClient client) throws IOException
public Future<UpgradeResponse> connectPhysical(DefaultWebSocketClient client) throws IOException
{
SocketChannel channel = SocketChannel.open();
SocketAddress bindAddress = client.getFactory().getBindAddress();
@ -137,7 +138,7 @@ public class ConnectionManager extends ContainerLifeCycle
return client;
}
public FutureCallback<UpgradeResponse> connectVirtual(WebSocketClient client)
public Future<UpgradeResponse> connectVirtual(WebSocketClient client)
{
// TODO Auto-generated method stub
return null;

View File

@ -21,8 +21,10 @@ package org.eclipse.jetty.websocket.client.internal;
import java.io.IOException;
import java.net.URI;
import java.util.Locale;
import java.util.concurrent.Future;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -41,7 +43,7 @@ import org.eclipse.jetty.websocket.common.events.EventDriver;
/**
* WebSocketClient for working with Upgrade (request and response), and establishing connections to the websocket URI of your choice.
*/
public class DefaultWebSocketClient extends FutureCallback<UpgradeResponse> implements WebSocketClient
public class DefaultWebSocketClient extends FuturePromise<UpgradeResponse> implements WebSocketClient
{
private static final Logger LOG = Log.getLogger(DefaultWebSocketClient.class);
@ -72,10 +74,10 @@ public class DefaultWebSocketClient extends FutureCallback<UpgradeResponse> impl
}
@Override
public void completed(UpgradeResponse context)
public void succeeded(UpgradeResponse response)
{
LOG.debug("completed() - {}",context);
super.completed(context);
LOG.debug("completed() - {}",response);
super.succeeded(response);
}
/*
@ -84,7 +86,7 @@ public class DefaultWebSocketClient extends FutureCallback<UpgradeResponse> impl
* @see org.eclipse.jetty.websocket.client.internal.WebSocketClient#connect(java.net.URI)
*/
@Override
public FutureCallback<UpgradeResponse> connect(URI websocketUri) throws IOException
public Future<UpgradeResponse> connect(URI websocketUri) throws IOException
{
if (!factory.isStarted())
{
@ -111,7 +113,7 @@ public class DefaultWebSocketClient extends FutureCallback<UpgradeResponse> impl
this.websocketUri = websocketUri;
// Validate websocket URI
FutureCallback<UpgradeResponse> result = null;
Future<UpgradeResponse> result = null;
LOG.debug("connect({})",websocketUri);
@ -128,11 +130,11 @@ public class DefaultWebSocketClient extends FutureCallback<UpgradeResponse> impl
}
@Override
public void failed(UpgradeResponse context, Throwable cause)
public void failed(Throwable cause)
{
LOG.debug("failed() - {}, {}",context,cause);
LOG.debug("failed() - {}",cause);
LOG.info(cause);
super.failed(context,cause);
super.failed(cause);
}
protected ClientUpgradeRequest getClientUpgradeRequest()

View File

@ -30,11 +30,13 @@ import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.UpgradeException;
import org.eclipse.jetty.websocket.api.UpgradeResponse;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.api.extensions.Extension;
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
@ -53,13 +55,13 @@ import org.eclipse.jetty.websocket.common.events.EventDriver;
*/
public class UpgradeConnection extends AbstractConnection
{
public class SendUpgradeRequest extends FutureCallback<String> implements Runnable
public class SendUpgradeRequest extends FutureCallback implements Runnable
{
@Override
public void completed(String context)
public void succeeded()
{
// Writing the request header is complete.
super.completed(context);
super.succeeded();
// start the interest in fill
fillInterested();
}
@ -72,7 +74,7 @@ public class UpgradeConnection extends AbstractConnection
String rawRequest = request.generate();
ByteBuffer buf = BufferUtil.toBuffer(rawRequest,StringUtil.__UTF8_CHARSET);
getEndPoint().write("REQ",this,buf);
getEndPoint().write(this,buf);
}
}
@ -95,7 +97,7 @@ public class UpgradeConnection extends AbstractConnection
}
catch (ClassCastException e)
{
client.failed(null,new RuntimeException("Invalid Upgrade Request structure",e));
client.failed(new RuntimeException("Invalid Upgrade Request structure",e));
}
}
@ -113,9 +115,9 @@ public class UpgradeConnection extends AbstractConnection
}
}
private void notifyConnect()
private void notifyConnect(UpgradeResponse response)
{
client.completed(client.getUpgradeResponse());
client.succeeded(response);
}
@Override
@ -183,7 +185,7 @@ public class UpgradeConnection extends AbstractConnection
// Got a response!
client.setUpgradeResponse(resp);
validateResponse(resp);
notifyConnect();
notifyConnect(resp);
upgradeConnection(resp);
return false; // do no more reading
}
@ -193,14 +195,14 @@ public class UpgradeConnection extends AbstractConnection
catch (IOException e)
{
LOG.warn(e);
client.failed(null,e);
client.failed(e);
disconnect(false);
return false;
}
catch (UpgradeException e)
{
LOG.warn(e);
client.failed(null,e);
client.failed(e);
disconnect(false);
return false;
}

View File

@ -94,7 +94,7 @@ public class WebSocketClientSelectorManager extends SelectorManager
catch (IOException e)
{
LOG.debug(e);
client.failed(null,e);
client.failed(e);
// rethrow
throw e;
}

View File

@ -82,7 +82,7 @@ public class ClientConnectTest
WebSocketClient client = factory.newWebSocketClient(wsocket);
URI wsUri = server.getWsUri();
FutureCallback<UpgradeResponse> future = client.connect(wsUri);
Future<UpgradeResponse> future = client.connect(wsUri);
ServerConnection connection = server.accept();
connection.readRequest();
@ -109,7 +109,7 @@ public class ClientConnectTest
WebSocketClient client = factory.newWebSocketClient(wsocket);
URI wsUri = server.getWsUri();
FutureCallback<UpgradeResponse> future = client.connect(wsUri);
Future<UpgradeResponse> future = client.connect(wsUri);
ServerConnection connection = server.accept();
connection.readRequest();

View File

@ -104,7 +104,7 @@ public class SlowClientTest
writer.setMessageCount(messageCount);
writer.setMessage("Hello");
// writer.setExchanger(exchanger);
writer.setSlowness(50);
writer.setSlowness(10);
writer.start();
writer.join();

View File

@ -150,7 +150,7 @@ public class SlowServerTest
writer.setMessageCount(messageCount);
writer.setMessage("Hello");
// writer.setExchanger(exchanger);
writer.setSlowness(50);
writer.setSlowness(10);
writer.start();
writer.join();

View File

@ -544,11 +544,11 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
try
{
endpoint.write(null,frameBytes,buffer);
endpoint.write(frameBytes,buffer);
}
catch (Throwable t)
{
frameBytes.failed(null,t);
frameBytes.failed(t);
}
}
}

View File

@ -38,12 +38,12 @@ public class ControlFrameBytes extends FrameBytes
}
@Override
public void completed(Void context)
public void succeeded()
{
LOG.debug("completed() - frame: {}",frame);
connection.getBufferPool().release(buffer);
super.completed(context);
super.succeeded();
if (frame.getType().getOpCode() == OpCode.CLOSE)
{

View File

@ -35,11 +35,11 @@ public class DataFrameBytes extends FrameBytes
}
@Override
public void completed(Void result)
public void succeeded()
{
if (LOG.isDebugEnabled())
{
LOG.debug("completed({}) - frame.remaining() = {}",result,frame.remaining());
LOG.debug("completed() - frame.remaining() = {}",frame.remaining());
}
connection.getBufferPool().release(buffer);
@ -56,7 +56,7 @@ public class DataFrameBytes extends FrameBytes
else
{
LOG.debug("Send complete");
super.completed(result);
super.succeeded();
}
connection.flush();
}
@ -72,7 +72,7 @@ public class DataFrameBytes extends FrameBytes
}
catch (Throwable x)
{
failed(null,x);
failed(x);
return null;
}
}

View File

@ -28,7 +28,7 @@ import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.Scheduler;
import org.eclipse.jetty.websocket.api.extensions.Frame;
public abstract class FrameBytes extends FutureCallback<Void> implements Runnable
public abstract class FrameBytes extends FutureCallback implements Runnable
{
private final static Logger LOG = Log.getLogger(FrameBytes.class);
protected final AbstractWebSocketConnection connection;
@ -52,12 +52,12 @@ public abstract class FrameBytes extends FutureCallback<Void> implements Runnabl
}
@Override
public void completed(Void v)
public void succeeded()
{
super.completed(v);
super.succeeded();
if (LOG.isDebugEnabled())
{
LOG.debug("completed({}) - {}",v,this.getClass().getName());
LOG.debug("completed() - {}",this.getClass().getName());
}
cancelTask();
connection.complete(this);
@ -65,17 +65,17 @@ public abstract class FrameBytes extends FutureCallback<Void> implements Runnabl
}
@Override
public void failed(Void v, Throwable x)
public void failed(Throwable x)
{
super.failed(v,x);
super.failed(x);
if (x instanceof EofException)
{
// Abbreviate the EofException
LOG.warn("failed(" + v + ") - " + EofException.class);
LOG.warn("failed() - " + EofException.class);
}
else
{
LOG.warn("failed(" + v + ")",x);
LOG.warn("failed()",x);
}
cancelTask();
frame.notifySendFailed(x);
@ -88,7 +88,7 @@ public abstract class FrameBytes extends FutureCallback<Void> implements Runnabl
{
// If this occurs we had a timeout!
connection.close();
failed(null,new InterruptedByTimeoutException());
failed(new InterruptedByTimeoutException());
}
@Override

View File

@ -56,7 +56,7 @@ public class HttpTransportOverMux implements HttpTransport
@Override
public void send(ResponseInfo info, ByteBuffer responseBodyContent, boolean lastContent) throws IOException
{
send(info,responseBodyContent,lastContent,streamBlocker.getPhase(),streamBlocker);
send(info,responseBodyContent,lastContent,streamBlocker);
try
{
streamBlocker.block();
@ -72,7 +72,7 @@ public class HttpTransportOverMux implements HttpTransport
}
@Override
public <C> void send(ResponseInfo info, ByteBuffer responseBodyContent, boolean lastContent, C context, Callback<C> callback)
public void send(ResponseInfo info, ByteBuffer responseBodyContent, boolean lastContent, Callback callback)
{
if (lastContent == false)
{

View File

@ -36,10 +36,9 @@ import org.junit.Assert;
public class OutgoingFramesCapture implements OutgoingFrames
{
public static class Write<C>
public static class Write
{
public C context;
public Callback<C> callback;
public Callback callback;
public Frame frame;
}