private <T> Response<T> sendRequest( RequestType type, SlaveContext slaveContext, Serializer serializer, Deserializer<T> deserializer) { // TODO Refactor, break into smaller methods Triplet<Channel, ChannelBuffer, ByteBuffer> channelContext = null; try { // Send 'em over the wire channelContext = getChannel(); Channel channel = channelContext.first(); ChannelBuffer buffer = channelContext.second(); buffer.clear(); buffer = new ChunkingChannelBuffer(buffer, channel, MAX_FRAME_LENGTH); buffer.writeByte(type.ordinal()); if (type.includesSlaveContext()) { writeSlaveContext(buffer, slaveContext); } serializer.write(buffer, channelContext.third()); if (buffer.writerIndex() > 0) { channel.write(buffer); } // Read the response @SuppressWarnings("unchecked") BlockingReadHandler<ChannelBuffer> reader = (BlockingReadHandler<ChannelBuffer>) channel.getPipeline().get("blockingHandler"); final Triplet<Channel, ChannelBuffer, ByteBuffer> finalChannelContext = channelContext; DechunkingChannelBuffer dechunkingBuffer = new DechunkingChannelBuffer(reader) { @Override protected ChannelBuffer readNext() { ChannelBuffer result = super.readNext(); if (result == null) { channelPool.dispose(finalChannelContext); throw new HaCommunicationException("Channel has been closed"); } return result; } }; T response = deserializer.read(dechunkingBuffer); TransactionStream txStreams = type.includesSlaveContext() ? readTransactionStreams(dechunkingBuffer) : TransactionStream.EMPTY; return new Response<T>(response, txStreams); } catch (ClosedChannelException e) { channelPool.dispose(channelContext); throw new HaCommunicationException(e); } catch (IOException e) { throw new HaCommunicationException(e); } catch (InterruptedException e) { throw new HaCommunicationException(e); } catch (Exception e) { throw new HaCommunicationException(e); } }