Cleaning up the initialization of Http2ConnectionHandler

Motivation:

It currently takes a builder for the encoder and decoder, which makes it difficult to decorate them.

Modifications:

Removed the builders from the interfaces entirely. Left the builder for the decoder impl but removed it from the encoder since it's constructor only takes 2 parameters. Also added decorator base classes for the encoder and decoder and made the CompressorHttp2ConnectionEncoder extend the decorator.

Result:

Fixes #3530
This commit is contained in:
nmittler 2015-03-27 15:37:20 -07:00
parent cb63e34bda
commit 6fbca14f8a
15 changed files with 353 additions and 302 deletions

View File

@ -34,10 +34,10 @@ import io.netty.handler.codec.compression.ZlibCodecFactory;
import io.netty.handler.codec.compression.ZlibWrapper; import io.netty.handler.codec.compression.ZlibWrapper;
/** /**
* A HTTP2 encoder that will compress data frames according to the {@code content-encoding} header for each stream. * A decorating HTTP2 encoder that will compress data frames according to the {@code content-encoding} header for each
* The compression provided by this class will be applied to the data for the entire stream. * stream. The compression provided by this class will be applied to the data for the entire stream.
*/ */
public class CompressorHttp2ConnectionEncoder extends DefaultHttp2ConnectionEncoder { public class CompressorHttp2ConnectionEncoder extends DecoratingHttp2ConnectionEncoder {
private static final Http2ConnectionAdapter CLEAN_UP_LISTENER = new Http2ConnectionAdapter() { private static final Http2ConnectionAdapter CLEAN_UP_LISTENER = new Http2ConnectionAdapter() {
@Override @Override
public void streamRemoved(Http2Stream stream) { public void streamRemoved(Http2Stream stream) {
@ -48,53 +48,33 @@ public class CompressorHttp2ConnectionEncoder extends DefaultHttp2ConnectionEnco
} }
}; };
public static final int DEFAULT_COMPRESSION_LEVEL = 6;
public static final int DEFAULT_WINDOW_BITS = 15;
public static final int DEFAULT_MEM_LEVEL = 8;
private final int compressionLevel; private final int compressionLevel;
private final int windowBits; private final int windowBits;
private final int memLevel; private final int memLevel;
/** public CompressorHttp2ConnectionEncoder(Http2ConnectionEncoder delegate) {
* Builder for new instances of {@link CompressorHttp2ConnectionEncoder} this(delegate, DEFAULT_COMPRESSION_LEVEL, DEFAULT_WINDOW_BITS, DEFAULT_MEM_LEVEL);
*/
public static class Builder extends DefaultHttp2ConnectionEncoder.Builder {
protected int compressionLevel = 6;
protected int windowBits = 15;
protected int memLevel = 8;
public Builder compressionLevel(int compressionLevel) {
this.compressionLevel = compressionLevel;
return this;
}
public Builder windowBits(int windowBits) {
this.windowBits = windowBits;
return this;
}
public Builder memLevel(int memLevel) {
this.memLevel = memLevel;
return this;
}
@Override
public CompressorHttp2ConnectionEncoder build() {
return new CompressorHttp2ConnectionEncoder(this);
}
} }
protected CompressorHttp2ConnectionEncoder(Builder builder) { public CompressorHttp2ConnectionEncoder(Http2ConnectionEncoder delegate, int compressionLevel, int windowBits,
super(builder); int memLevel) {
if (builder.compressionLevel < 0 || builder.compressionLevel > 9) { super(delegate);
throw new IllegalArgumentException("compressionLevel: " + builder.compressionLevel + " (expected: 0-9)"); if (compressionLevel < 0 || compressionLevel > 9) {
throw new IllegalArgumentException("compressionLevel: " + compressionLevel + " (expected: 0-9)");
} }
if (builder.windowBits < 9 || builder.windowBits > 15) { if (windowBits < 9 || windowBits > 15) {
throw new IllegalArgumentException("windowBits: " + builder.windowBits + " (expected: 9-15)"); throw new IllegalArgumentException("windowBits: " + windowBits + " (expected: 9-15)");
} }
if (builder.memLevel < 1 || builder.memLevel > 9) { if (memLevel < 1 || memLevel > 9) {
throw new IllegalArgumentException("memLevel: " + builder.memLevel + " (expected: 1-9)"); throw new IllegalArgumentException("memLevel: " + memLevel + " (expected: 1-9)");
} }
compressionLevel = builder.compressionLevel; this.compressionLevel = compressionLevel;
windowBits = builder.windowBits; this.windowBits = windowBits;
memLevel = builder.memLevel; this.memLevel = memLevel;
connection().addListener(CLEAN_UP_LISTENER); connection().addListener(CLEAN_UP_LISTENER);
} }

View File

@ -0,0 +1,78 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License, version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package io.netty.handler.codec.http2;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import java.util.List;
/**
* Decorator around another {@link Http2ConnectionDecoder} instance.
*/
public class DecoratingHttp2ConnectionDecoder implements Http2ConnectionDecoder {
private final Http2ConnectionDecoder delegate;
public DecoratingHttp2ConnectionDecoder(Http2ConnectionDecoder delegate) {
this.delegate = checkNotNull(delegate, "delegate");
}
@Override
public void lifecycleManager(Http2LifecycleManager lifecycleManager) {
delegate.lifecycleManager(lifecycleManager);
}
@Override
public Http2Connection connection() {
return delegate.connection();
}
@Override
public Http2LocalFlowController flowController() {
return delegate.flowController();
}
@Override
public Http2FrameListener listener() {
return delegate.listener();
}
@Override
public void decodeFrame(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Http2Exception {
delegate.decodeFrame(ctx, in, out);
}
@Override
public Http2Settings localSettings() {
return delegate.localSettings();
}
@Override
public void localSettings(Http2Settings settings) throws Http2Exception {
delegate.localSettings(settings);
}
@Override
public boolean prefaceReceived() {
return delegate.prefaceReceived();
}
@Override
public void close() {
delegate.close();
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License, version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package io.netty.handler.codec.http2;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
/**
* A decorator around another {@link Http2ConnectionEncoder} instance.
*/
public class DecoratingHttp2ConnectionEncoder extends DecoratingHttp2FrameWriter implements Http2ConnectionEncoder {
private final Http2ConnectionEncoder delegate;
public DecoratingHttp2ConnectionEncoder(Http2ConnectionEncoder delegate) {
super(delegate);
this.delegate = checkNotNull(delegate, "delegate");
}
@Override
public void lifecycleManager(Http2LifecycleManager lifecycleManager) {
delegate.lifecycleManager(lifecycleManager);
}
@Override
public Http2Connection connection() {
return delegate.connection();
}
@Override
public Http2RemoteFlowController flowController() {
return delegate.flowController();
}
@Override
public Http2FrameWriter frameWriter() {
return delegate.frameWriter();
}
@Override
public Http2Settings pollSentSettings() {
return delegate.pollSentSettings();
}
@Override
public void remoteSettings(Http2Settings settings) throws Http2Exception {
delegate.remoteSettings(settings);
}
}

View File

@ -0,0 +1,114 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License, version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package io.netty.handler.codec.http2;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
/**
* Decorator around another {@link Http2FrameWriter} instance.
*/
public class DecoratingHttp2FrameWriter implements Http2FrameWriter {
private final Http2FrameWriter delegate;
public DecoratingHttp2FrameWriter(Http2FrameWriter delegate) {
this.delegate = checkNotNull(delegate, "delegate");
}
@Override
public ChannelFuture writeData(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,
boolean endStream, ChannelPromise promise) {
return delegate.writeData(ctx, streamId, data, padding, endStream, promise);
}
@Override
public ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding,
boolean endStream, ChannelPromise promise) {
return delegate.writeHeaders(ctx, streamId, headers, padding, endStream, promise);
}
@Override
public ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
int streamDependency, short weight, boolean exclusive, int padding,
boolean endStream, ChannelPromise promise) {
return delegate
.writeHeaders(ctx, streamId, headers, streamDependency, weight, exclusive, padding, endStream, promise);
}
@Override
public ChannelFuture writePriority(ChannelHandlerContext ctx, int streamId, int streamDependency, short weight,
boolean exclusive, ChannelPromise promise) {
return delegate.writePriority(ctx, streamId, streamDependency, weight, exclusive, promise);
}
@Override
public ChannelFuture writeRstStream(ChannelHandlerContext ctx, int streamId, long errorCode,
ChannelPromise promise) {
return delegate.writeRstStream(ctx, streamId, errorCode, promise);
}
@Override
public ChannelFuture writeSettings(ChannelHandlerContext ctx, Http2Settings settings, ChannelPromise promise) {
return delegate.writeSettings(ctx, settings, promise);
}
@Override
public ChannelFuture writeSettingsAck(ChannelHandlerContext ctx, ChannelPromise promise) {
return delegate.writeSettingsAck(ctx, promise);
}
@Override
public ChannelFuture writePing(ChannelHandlerContext ctx, boolean ack, ByteBuf data, ChannelPromise promise) {
return delegate.writePing(ctx, ack, data, promise);
}
@Override
public ChannelFuture writePushPromise(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
Http2Headers headers, int padding, ChannelPromise promise) {
return delegate.writePushPromise(ctx, streamId, promisedStreamId, headers, padding, promise);
}
@Override
public ChannelFuture writeGoAway(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData,
ChannelPromise promise) {
return delegate.writeGoAway(ctx, lastStreamId, errorCode, debugData, promise);
}
@Override
public ChannelFuture writeWindowUpdate(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement,
ChannelPromise promise) {
return delegate.writeWindowUpdate(ctx, streamId, windowSizeIncrement, promise);
}
@Override
public ChannelFuture writeFrame(ChannelHandlerContext ctx, byte frameType, int streamId, Http2Flags flags,
ByteBuf payload, ChannelPromise promise) {
return delegate.writeFrame(ctx, frameType, streamId, flags, payload, promise);
}
@Override
public Configuration configuration() {
return delegate.configuration();
}
@Override
public void close() {
delegate.close();
}
}

View File

@ -40,87 +40,40 @@ import java.util.List;
public class DefaultHttp2ConnectionDecoder implements Http2ConnectionDecoder { public class DefaultHttp2ConnectionDecoder implements Http2ConnectionDecoder {
private Http2FrameListener internalFrameListener = new PrefaceFrameListener(); private Http2FrameListener internalFrameListener = new PrefaceFrameListener();
private final Http2Connection connection; private final Http2Connection connection;
private final Http2LifecycleManager lifecycleManager; private Http2LifecycleManager lifecycleManager;
private final Http2ConnectionEncoder encoder; private final Http2ConnectionEncoder encoder;
private final Http2FrameReader frameReader; private final Http2FrameReader frameReader;
private final Http2FrameListener listener; private final Http2FrameListener listener;
private final Http2PromisedRequestVerifier requestVerifier; private final Http2PromisedRequestVerifier requestVerifier;
/** public DefaultHttp2ConnectionDecoder(Http2Connection connection,
* Builder for instances of {@link DefaultHttp2ConnectionDecoder}. Http2ConnectionEncoder encoder,
*/ Http2FrameReader frameReader,
public static class Builder implements Http2ConnectionDecoder.Builder { Http2FrameListener listener) {
private Http2Connection connection; this(connection, encoder, frameReader, listener, ALWAYS_VERIFY);
private Http2LifecycleManager lifecycleManager;
private Http2ConnectionEncoder encoder;
private Http2FrameReader frameReader;
private Http2FrameListener listener;
private Http2PromisedRequestVerifier requestVerifier = ALWAYS_VERIFY;
@Override
public Builder connection(Http2Connection connection) {
this.connection = connection;
return this;
}
@Override
public Builder lifecycleManager(Http2LifecycleManager lifecycleManager) {
this.lifecycleManager = lifecycleManager;
return this;
}
@Override
public Http2LifecycleManager lifecycleManager() {
return lifecycleManager;
}
@Override
public Builder frameReader(Http2FrameReader frameReader) {
this.frameReader = frameReader;
return this;
}
@Override
public Builder listener(Http2FrameListener listener) {
this.listener = listener;
return this;
}
@Override
public Builder encoder(Http2ConnectionEncoder encoder) {
this.encoder = encoder;
return this;
}
@Override
public Http2ConnectionDecoder.Builder requestVerifier(Http2PromisedRequestVerifier requestVerifier) {
this.requestVerifier = requestVerifier;
return this;
}
@Override
public Http2ConnectionDecoder build() {
return new DefaultHttp2ConnectionDecoder(this);
}
} }
public static Builder newBuilder() { public DefaultHttp2ConnectionDecoder(Http2Connection connection,
return new Builder(); Http2ConnectionEncoder encoder,
} Http2FrameReader frameReader,
Http2FrameListener listener,
protected DefaultHttp2ConnectionDecoder(Builder builder) { Http2PromisedRequestVerifier requestVerifier) {
connection = checkNotNull(builder.connection, "connection"); this.connection = checkNotNull(connection, "connection");
frameReader = checkNotNull(builder.frameReader, "frameReader"); this.frameReader = checkNotNull(frameReader, "frameReader");
lifecycleManager = checkNotNull(builder.lifecycleManager, "lifecycleManager"); this.encoder = checkNotNull(encoder, "encoder");
encoder = checkNotNull(builder.encoder, "encoder"); this.listener = checkNotNull(listener, "listener");
listener = checkNotNull(builder.listener, "listener"); this.requestVerifier = checkNotNull(requestVerifier, "requestVerifier");
requestVerifier = checkNotNull(builder.requestVerifier, "requestVerifier");
if (connection.local().flowController() == null) { if (connection.local().flowController() == null) {
connection.local().flowController( connection.local().flowController(
new DefaultHttp2LocalFlowController(connection, encoder.frameWriter())); new DefaultHttp2LocalFlowController(connection, encoder.frameWriter()));
} }
} }
@Override
public void lifecycleManager(Http2LifecycleManager lifecycleManager) {
this.lifecycleManager = checkNotNull(lifecycleManager, "lifecycleManager");
}
@Override @Override
public Http2Connection connection() { public Http2Connection connection() {
return connection; return connection;

View File

@ -35,63 +35,24 @@ import java.util.ArrayDeque;
public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder { public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder {
private final Http2FrameWriter frameWriter; private final Http2FrameWriter frameWriter;
private final Http2Connection connection; private final Http2Connection connection;
private final Http2LifecycleManager lifecycleManager; private Http2LifecycleManager lifecycleManager;
// We prefer ArrayDeque to LinkedList because later will produce more GC. // We prefer ArrayDeque to LinkedList because later will produce more GC.
// This initial capacity is plenty for SETTINGS traffic. // This initial capacity is plenty for SETTINGS traffic.
private final ArrayDeque<Http2Settings> outstandingLocalSettingsQueue = new ArrayDeque<Http2Settings>(4); private final ArrayDeque<Http2Settings> outstandingLocalSettingsQueue = new ArrayDeque<Http2Settings>(4);
/** public DefaultHttp2ConnectionEncoder(Http2Connection connection, Http2FrameWriter frameWriter) {
* Builder for new instances of {@link DefaultHttp2ConnectionEncoder}. this.connection = checkNotNull(connection, "connection");
*/ this.frameWriter = checkNotNull(frameWriter, "frameWriter");
public static class Builder implements Http2ConnectionEncoder.Builder {
protected Http2FrameWriter frameWriter;
protected Http2Connection connection;
protected Http2LifecycleManager lifecycleManager;
@Override
public Builder connection(
Http2Connection connection) {
this.connection = connection;
return this;
}
@Override
public Builder lifecycleManager(
Http2LifecycleManager lifecycleManager) {
this.lifecycleManager = lifecycleManager;
return this;
}
@Override
public Http2LifecycleManager lifecycleManager() {
return lifecycleManager;
}
@Override
public Builder frameWriter(Http2FrameWriter frameWriter) {
this.frameWriter = frameWriter;
return this;
}
@Override
public Http2ConnectionEncoder build() {
return new DefaultHttp2ConnectionEncoder(this);
}
}
public static Builder newBuilder() {
return new Builder();
}
protected DefaultHttp2ConnectionEncoder(Builder builder) {
connection = checkNotNull(builder.connection, "connection");
frameWriter = checkNotNull(builder.frameWriter, "frameWriter");
lifecycleManager = checkNotNull(builder.lifecycleManager, "lifecycleManager");
if (connection.remote().flowController() == null) { if (connection.remote().flowController() == null) {
connection.remote().flowController(new DefaultHttp2RemoteFlowController(connection)); connection.remote().flowController(new DefaultHttp2RemoteFlowController(connection));
} }
} }
@Override
public void lifecycleManager(Http2LifecycleManager lifecycleManager) {
this.lifecycleManager = checkNotNull(lifecycleManager, "lifecycleManager");
}
@Override @Override
public Http2FrameWriter frameWriter() { public Http2FrameWriter frameWriter() {
return frameWriter; return frameWriter;

View File

@ -29,49 +29,9 @@ import java.util.List;
public interface Http2ConnectionDecoder extends Closeable { public interface Http2ConnectionDecoder extends Closeable {
/** /**
* Builder for new instances of {@link Http2ConnectionDecoder}. * Sets the lifecycle manager. Must be called as part of initialization before the decoder is used.
*/ */
interface Builder { void lifecycleManager(Http2LifecycleManager lifecycleManager);
/**
* Sets the {@link Http2Connection} to be used when building the decoder.
*/
Builder connection(Http2Connection connection);
/**
* Sets the {@link Http2LifecycleManager} to be used when building the decoder.
*/
Builder lifecycleManager(Http2LifecycleManager lifecycleManager);
/**
* Gets the {@link Http2LifecycleManager} to be used when building the decoder.
*/
Http2LifecycleManager lifecycleManager();
/**
* Sets the {@link Http2FrameReader} to be used when building the decoder.
*/
Builder frameReader(Http2FrameReader frameReader);
/**
* Sets the {@link Http2FrameListener} to be used when building the decoder.
*/
Builder listener(Http2FrameListener listener);
/**
* Sets the {@link Http2ConnectionEncoder} used when building the decoder.
*/
Builder encoder(Http2ConnectionEncoder encoder);
/**
* Sets the {@link Http2PromisedRequestVerifier} used when building the decoder.
*/
Builder requestVerifier(Http2PromisedRequestVerifier requestVerifier);
/**
* Creates a new decoder instance.
*/
Http2ConnectionDecoder build();
}
/** /**
* Provides direct access to the underlying connection. * Provides direct access to the underlying connection.

View File

@ -26,35 +26,9 @@ import io.netty.channel.ChannelPromise;
public interface Http2ConnectionEncoder extends Http2FrameWriter { public interface Http2ConnectionEncoder extends Http2FrameWriter {
/** /**
* Builder for new instances of {@link Http2ConnectionEncoder}. * Sets the lifecycle manager. Must be called as part of initialization before the encoder is used.
*/ */
interface Builder { void lifecycleManager(Http2LifecycleManager lifecycleManager);
/**
* Sets the {@link Http2Connection} to be used when building the encoder.
*/
Builder connection(Http2Connection connection);
/**
* Sets the {@link Http2LifecycleManager} to be used when building the encoder.
*/
Builder lifecycleManager(Http2LifecycleManager lifecycleManager);
/**
* Gets the {@link Http2LifecycleManager} to be used when building the encoder.
*/
Http2LifecycleManager lifecycleManager();
/**
* Sets the {@link Http2FrameWriter} to be used when building the encoder.
*/
Builder frameWriter(Http2FrameWriter frameWriter);
/**
* Creates a new encoder instance.
*/
Http2ConnectionEncoder build();
}
/** /**
* Provides direct access to the underlying connection. * Provides direct access to the underlying connection.

View File

@ -63,38 +63,19 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
} }
public Http2ConnectionHandler(Http2Connection connection, Http2FrameReader frameReader, public Http2ConnectionHandler(Http2Connection connection, Http2FrameReader frameReader,
Http2FrameWriter frameWriter, Http2FrameListener listener) { Http2FrameWriter frameWriter, Http2FrameListener listener) {
this(DefaultHttp2ConnectionDecoder.newBuilder().connection(connection) encoder = new DefaultHttp2ConnectionEncoder(connection, frameWriter);
.frameReader(frameReader).listener(listener), decoder = new DefaultHttp2ConnectionDecoder(connection, encoder, frameReader, listener);
DefaultHttp2ConnectionEncoder.newBuilder().connection(connection)
.frameWriter(frameWriter));
} }
/** /**
* Constructor for pre-configured encoder and decoder builders. Just sets the {@code this} as the * Constructor for pre-configured encoder and decoder. Just sets the {@code this} as the
* {@link Http2LifecycleManager} and builds them. * {@link Http2LifecycleManager} and builds them.
*/ */
public Http2ConnectionHandler(Http2ConnectionDecoder.Builder decoderBuilder, public Http2ConnectionHandler(Http2ConnectionDecoder decoder,
Http2ConnectionEncoder.Builder encoderBuilder) { Http2ConnectionEncoder encoder) {
checkNotNull(decoderBuilder, "decoderBuilder"); this.decoder = checkNotNull(decoder, "decoder");
checkNotNull(encoderBuilder, "encoderBuilder"); this.encoder = checkNotNull(encoder, "encoder");
if (encoderBuilder.lifecycleManager() != decoderBuilder.lifecycleManager()) {
throw new IllegalArgumentException("Encoder and Decoder must share a lifecycle manager");
} else if (encoderBuilder.lifecycleManager() == null) {
encoderBuilder.lifecycleManager(this);
decoderBuilder.lifecycleManager(this);
}
// Build the encoder.
encoder = checkNotNull(encoderBuilder.build(), "encoder");
// Build the decoder.
decoderBuilder.encoder(encoder);
decoder = checkNotNull(decoderBuilder.build(), "decoder");
// Verify that the encoder and decoder use the same connection.
checkNotNull(encoder.connection(), "encoder.connection");
if (encoder.connection() != decoder.connection()) { if (encoder.connection() != decoder.connection()) {
throw new IllegalArgumentException("Encoder and Decoder do not share the same connection object"); throw new IllegalArgumentException("Encoder and Decoder do not share the same connection object");
} }
@ -304,6 +285,9 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
@Override @Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception { public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
// Initialize the encoder and decoder.
encoder.lifecycleManager(this);
decoder.lifecycleManager(this);
byteDecoder = new PrefaceDecoder(ctx); byteDecoder = new PrefaceDecoder(ctx);
} }

View File

@ -40,9 +40,9 @@ public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler {
super(connection, frameReader, frameWriter, listener); super(connection, frameReader, frameWriter, listener);
} }
public HttpToHttp2ConnectionHandler(Http2ConnectionDecoder.Builder decoderBuilder, public HttpToHttp2ConnectionHandler(Http2ConnectionDecoder decoder,
Http2ConnectionEncoder.Builder encoderBuilder) { Http2ConnectionEncoder encoder) {
super(decoderBuilder, encoderBuilder); super(decoder, encoder);
} }
/** /**

View File

@ -216,7 +216,7 @@ public class DataCompressionHttp2Test {
}); });
awaitServer(); awaitServer();
assertEquals(0, serverConnection.local().flowController().unconsumedBytes(stream)); assertEquals(0, serverConnection.local().flowController().unconsumedBytes(stream));
assertEquals(new StringBuilder(text1).append(text2).toString(), assertEquals(text1 + text2,
serverOut.toString(CharsetUtil.UTF_8.name())); serverOut.toString(CharsetUtil.UTF_8.name()));
} finally { } finally {
data1.release(); data1.release();
@ -296,16 +296,13 @@ public class DataCompressionHttp2Test {
@Override @Override
protected void initChannel(Channel ch) throws Exception { protected void initChannel(Channel ch) throws Exception {
ChannelPipeline p = ch.pipeline(); ChannelPipeline p = ch.pipeline();
Http2FrameWriter writer = new DefaultHttp2FrameWriter(); Http2ConnectionEncoder encoder = new CompressorHttp2ConnectionEncoder(
Http2ConnectionHandler connectionHandler = new DefaultHttp2ConnectionEncoder(serverConnection, new DefaultHttp2FrameWriter()));
new Http2ConnectionHandler(new DefaultHttp2ConnectionDecoder.Builder() Http2ConnectionDecoder decoder =
.connection(serverConnection) new DefaultHttp2ConnectionDecoder(serverConnection, encoder, new DefaultHttp2FrameReader(),
.frameReader(new DefaultHttp2FrameReader()) new DelegatingDecompressorFrameListener(serverConnection,
.listener( serverListener));
new DelegatingDecompressorFrameListener(serverConnection, Http2ConnectionHandler connectionHandler = new Http2ConnectionHandler(decoder, encoder);
serverListener)),
new CompressorHttp2ConnectionEncoder.Builder().connection(
serverConnection).frameWriter(writer));
p.addLast(connectionHandler); p.addLast(connectionHandler);
serverChannelLatch.countDown(); serverChannelLatch.countDown();
} }
@ -319,17 +316,14 @@ public class DataCompressionHttp2Test {
ChannelPipeline p = ch.pipeline(); ChannelPipeline p = ch.pipeline();
FrameCountDown clientFrameCountDown = new FrameCountDown(clientListener, FrameCountDown clientFrameCountDown = new FrameCountDown(clientListener,
clientSettingsAckLatch, clientLatch); clientSettingsAckLatch, clientLatch);
Http2FrameWriter writer = new DefaultHttp2FrameWriter(); clientEncoder = new CompressorHttp2ConnectionEncoder(
Http2ConnectionHandler connectionHandler = new DefaultHttp2ConnectionEncoder(clientConnection, new DefaultHttp2FrameWriter()));
new Http2ConnectionHandler(new DefaultHttp2ConnectionDecoder.Builder() Http2ConnectionDecoder decoder =
.connection(clientConnection) new DefaultHttp2ConnectionDecoder(clientConnection, clientEncoder,
.frameReader(new DefaultHttp2FrameReader()) new DefaultHttp2FrameReader(),
.listener( new DelegatingDecompressorFrameListener(clientConnection,
new DelegatingDecompressorFrameListener(clientConnection, clientFrameCountDown));
clientFrameCountDown)), Http2ConnectionHandler connectionHandler = new Http2ConnectionHandler(decoder, clientEncoder);
new CompressorHttp2ConnectionEncoder.Builder().connection(
clientConnection).frameWriter(writer));
clientEncoder = connectionHandler.encoder();
p.addLast(connectionHandler); p.addLast(connectionHandler);
} }
}); });

View File

@ -139,9 +139,8 @@ public class DefaultHttp2ConnectionDecoderTest {
when(ctx.newPromise()).thenReturn(promise); when(ctx.newPromise()).thenReturn(promise);
when(ctx.write(any())).thenReturn(future); when(ctx.write(any())).thenReturn(future);
decoder = DefaultHttp2ConnectionDecoder.newBuilder().connection(connection) decoder = new DefaultHttp2ConnectionDecoder(connection, encoder, reader, listener);
.frameReader(reader).encoder(encoder) decoder.lifecycleManager(lifecycleManager);
.listener(listener).lifecycleManager(lifecycleManager).build();
// Simulate receiving the initial settings from the remote endpoint. // Simulate receiving the initial settings from the remote endpoint.
decode().onSettingsRead(ctx, new Http2Settings()); decode().onSettingsRead(ctx, new Http2Settings());

View File

@ -195,8 +195,8 @@ public class DefaultHttp2ConnectionEncoderTest {
when(ctx.newPromise()).thenReturn(promise); when(ctx.newPromise()).thenReturn(promise);
when(ctx.write(any())).thenReturn(future); when(ctx.write(any())).thenReturn(future);
encoder = DefaultHttp2ConnectionEncoder.newBuilder().connection(connection) encoder = new DefaultHttp2ConnectionEncoder(connection, writer);
.frameWriter(writer).lifecycleManager(lifecycleManager).build(); encoder.lifecycleManager(lifecycleManager);
} }
@Test @Test

View File

@ -89,12 +89,6 @@ public class Http2ConnectionHandlerTest {
@Mock @Mock
private Http2Stream stream; private Http2Stream stream;
@Mock
private Http2ConnectionDecoder.Builder decoderBuilder;
@Mock
private Http2ConnectionEncoder.Builder encoderBuilder;
@Mock @Mock
private Http2ConnectionDecoder decoder; private Http2ConnectionDecoder decoder;
@ -110,8 +104,6 @@ public class Http2ConnectionHandlerTest {
promise = new DefaultChannelPromise(channel); promise = new DefaultChannelPromise(channel);
when(encoderBuilder.build()).thenReturn(encoder);
when(decoderBuilder.build()).thenReturn(decoder);
when(encoder.connection()).thenReturn(connection); when(encoder.connection()).thenReturn(connection);
when(decoder.connection()).thenReturn(connection); when(decoder.connection()).thenReturn(connection);
when(encoder.frameWriter()).thenReturn(frameWriter); when(encoder.frameWriter()).thenReturn(frameWriter);
@ -132,7 +124,7 @@ public class Http2ConnectionHandlerTest {
} }
private Http2ConnectionHandler newHandler() throws Exception { private Http2ConnectionHandler newHandler() throws Exception {
Http2ConnectionHandler handler = new Http2ConnectionHandler(decoderBuilder, encoderBuilder); Http2ConnectionHandler handler = new Http2ConnectionHandler(decoder, encoder);
handler.handlerAdded(ctx); handler.handlerAdded(ctx);
return handler; return handler;
} }

View File

@ -52,6 +52,8 @@ import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
import io.netty.handler.codec.http2.DefaultHttp2FrameWriter; import io.netty.handler.codec.http2.DefaultHttp2FrameWriter;
import io.netty.handler.codec.http2.DefaultHttp2Headers; import io.netty.handler.codec.http2.DefaultHttp2Headers;
import io.netty.handler.codec.http2.Http2Connection; import io.netty.handler.codec.http2.Http2Connection;
import io.netty.handler.codec.http2.Http2ConnectionDecoder;
import io.netty.handler.codec.http2.Http2ConnectionEncoder;
import io.netty.handler.codec.http2.Http2ConnectionHandler; import io.netty.handler.codec.http2.Http2ConnectionHandler;
import io.netty.handler.codec.http2.Http2FrameAdapter; import io.netty.handler.codec.http2.Http2FrameAdapter;
import io.netty.handler.codec.http2.Http2FrameWriter; import io.netty.handler.codec.http2.Http2FrameWriter;
@ -264,11 +266,11 @@ public class Http2FrameWriterBenchmark extends AbstractSharedExecutorMicrobenchm
connection.local().flowController(localFlowController); connection.local().flowController(localFlowController);
} }
environment.writer(new DefaultHttp2FrameWriter()); environment.writer(new DefaultHttp2FrameWriter());
Http2ConnectionHandler connectionHandler = new Http2ConnectionHandler( Http2ConnectionEncoder encoder = new DefaultHttp2ConnectionEncoder(connection, environment.writer());
new DefaultHttp2ConnectionDecoder.Builder().connection(connection) Http2ConnectionDecoder decoder =
.frameReader(new DefaultHttp2FrameReader()).listener(new Http2FrameAdapter()), new DefaultHttp2ConnectionDecoder(connection, encoder, new DefaultHttp2FrameReader(),
new DefaultHttp2ConnectionEncoder.Builder().connection(connection).frameWriter( new Http2FrameAdapter());
environment.writer())); Http2ConnectionHandler connectionHandler = new Http2ConnectionHandler(decoder, encoder);
p.addLast(connectionHandler); p.addLast(connectionHandler);
environment.context(p.lastContext()); environment.context(p.lastContext());
} }
@ -283,10 +285,11 @@ public class Http2FrameWriterBenchmark extends AbstractSharedExecutorMicrobenchm
private static Environment boostrapEmbeddedEnv(final ByteBufAllocator alloc) { private static Environment boostrapEmbeddedEnv(final ByteBufAllocator alloc) {
final EmbeddedEnvironment env = new EmbeddedEnvironment(new DefaultHttp2FrameWriter()); final EmbeddedEnvironment env = new EmbeddedEnvironment(new DefaultHttp2FrameWriter());
final Http2Connection connection = new DefaultHttp2Connection(false); final Http2Connection connection = new DefaultHttp2Connection(false);
final Http2ConnectionHandler connectionHandler = new Http2ConnectionHandler( Http2ConnectionEncoder encoder = new DefaultHttp2ConnectionEncoder(connection, env.writer());
new DefaultHttp2ConnectionDecoder.Builder().connection(connection) Http2ConnectionDecoder decoder =
.frameReader(new DefaultHttp2FrameReader()).listener(new Http2FrameAdapter()), new DefaultHttp2ConnectionDecoder(connection, encoder, new DefaultHttp2FrameReader(),
new DefaultHttp2ConnectionEncoder.Builder().connection(connection).frameWriter(env.writer())); new Http2FrameAdapter());
Http2ConnectionHandler connectionHandler = new Http2ConnectionHandler(decoder, encoder);
env.context(new EmbeddedChannelWriteReleaseHandlerContext(alloc, connectionHandler) { env.context(new EmbeddedChannelWriteReleaseHandlerContext(alloc, connectionHandler) {
@Override @Override
protected void handleException(Throwable t) { protected void handleException(Throwable t) {