/** * Examines the channel buffer and attempts to match the protocol of the request and invoke the * matching {@link ProtocolInitiator}. * * @param ctx The channel handler context * @param channel The channel * @param bufferx The message buffer * @param e The channel event * @return The channel buffer to send upstream, or null if we need more bytes */ protected ChannelBuffer protocolSwitch( ChannelHandlerContext ctx, Channel channel, ChannelBuffer bufferx, ChannelEvent e) { ChannelBuffer cb = preSwitchedBuffer.get(channel); if (cb != null) { cb.writeBytes(bufferx); cb.resetReaderIndex(); } else { cb = bufferx; } // this guy will be set with a matching initiator ProtocolInitiator selectedInitiator = null; // this guy will be set to false if at least 1 initiator had insufficient bytes to match boolean sufficientBytes = true; // ths guy has the total bytes available in the buffer final int bytesAvailable = cb.readableBytes(); for (ProtocolInitiator pi : initiators.values()) { if (pi.requiredBytes() > bytesAvailable) { sufficientBytes = false; } else { if (pi.match(cb)) { selectedInitiator = pi; break; } } } if (selectedInitiator == null) { // we did not get a match if (!sufficientBytes) { // ok, we did not have enough bytes DynamicChannelBuffer dcb = preSwitchedBuffer.get(channel); if (dcb == null) { dcb = new DynamicChannelBuffer(cb.order(), 1024, chanelBufferFactory); preSwitchedBuffer.set(channel, dcb); } dcb.writeBytes(cb); dcb.resetReaderIndex(); return null; } // darn, we have enough bytes for any of the inits, // but none matched throw new RuntimeException("Failed to match any protocol initiator"); } preSwitchedBuffer.remove(channel); // we matched on an initiator, so have it modify the pipeline selectedInitiator.modifyPipeline(ctx, channel, cb); return cb; // if we get here, it means we did not find a protocol match // so pass to the default protocol initiator. }
// TODO this is all a bit of a pain - if we can just throw exceptions if people set stuff outside // of the buffer // like Netty that would be preferable private void ensureWritable(int pos, int len) { int ni = pos + len; int cap = buffer.capacity(); int over = ni - cap; if (over > 0) { buffer.writerIndex(cap); buffer.ensureWritableBytes(over); } // We have to make sure that the writerindex is always positioned on the last bit of data set in // the buffer if (ni > buffer.writerIndex()) { buffer.writerIndex(ni); } }
/** * Appends the specified {@code Buffer} to the end of the Buffer. The buffer will expand as * necessary to accomodate any bytes written. * * <p>Returns a reference to {@code this} so multiple operations can be appended together. */ public Buffer appendBuffer(Buffer buff) { ChannelBuffer cb = buff.getChannelBuffer(); buffer.writeBytes(buff.getChannelBuffer()); cb.readerIndex( 0); // Need to reset readerindex since Netty write modifies readerIndex of source! return this; }
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Buffer buffer1 = (Buffer) o; return buffer.equals(buffer1.buffer); }
/** * Sets the {@code double} at position {@code pos} in the Buffer to the value {@code i}. * * <p>The buffer will expand as necessary to accomodate any value written. */ public Buffer setDouble(int pos, double d) { ensureWritable(pos, 8); buffer.setDouble(pos, d); return this; }
/** * Sets the {@code long} at position {@code pos} in the Buffer to the value {@code i}. * * <p>The buffer will expand as necessary to accomodate any value written. */ public Buffer setLong(int pos, long l) { ensureWritable(pos, 8); buffer.setLong(pos, l); return this; }
/** * Returns the {@code short} at position {@code pos} in the Buffer. * * @throws IndexOutOfBoundsException if the specified {@code pos} is less than {@code 0} or {@code * pos + 2} is greater than the length {@code } of the Buffer. */ public short getShort(int pos) { return buffer.getShort(pos); }
private Buffer setBytes(int pos, String str, Charset charset) { byte[] bytes = str.getBytes(charset); ensureWritable(pos, bytes.length); buffer.setBytes(pos, bytes); return this; }
/** Returns a copy of the entire Buffer. */ public Buffer copy() { return new Buffer(buffer.copy()); }
/** * Sets the bytes at position {@code pos} in the Buffer to the value {@code b}. * * <p>The buffer will expand as necessary to accomodate any value written. */ public Buffer setBytes(int pos, byte[] b) { ensureWritable(pos, b.length); buffer.setBytes(pos, b); return this; }
/** * Sets the bytes at position {@code pos} in the Buffer to the value {@code b}. * * <p>The buffer will expand as necessary to accomodate any value written. */ public Buffer setBuffer(int pos, Buffer b) { ensureWritable(pos, b.length()); buffer.setBytes(pos, b.getChannelBuffer()); return this; }
/** * Appends the specified {@code long} to the end of the Buffer. The buffer will expand as * necessary to accomodate any bytes written. * * <p>Returns a reference to {@code this} so multiple operations can be appended together. */ public Buffer appendLong(long l) { buffer.writeLong(l); return this; }
/** * Appends the specified {@code int} to the end of the Buffer. The buffer will expand as necessary * to accomodate any bytes written. * * <p>Returns a reference to {@code this} so multiple operations can be appended together. */ public Buffer appendInt(int i) { buffer.writeInt(i); return this; }
/** * Appends the specified {@code byte} to the end of the Buffer. The buffer will expand as * necessary to accomodate any bytes written. * * <p>Returns a reference to {@code this} so multiple operations can be appended together. */ public Buffer appendByte(byte b) { buffer.writeByte(b); return this; }
/** * Appends the specified {@code byte[]} to the end of the Buffer. The buffer will expand as * necessary to accomodate any bytes written. * * <p>Returns a reference to {@code this} so multiple operations can be appended together. */ public Buffer appendBytes(byte[] bytes) { buffer.writeBytes(bytes); return this; }
/** * Returns a copy of a sub-sequence the Buffer as a {@code byte[]} starting at position {@code * start} and ending at position {@code end - 1} */ public byte[] getBytes(int start, int end) { byte[] arr = new byte[end - start]; buffer.getBytes(start, arr, 0, end - start); return arr; }
/** Returns a copy of the entire Buffer as a {@code byte[]} */ public byte[] getBytes() { byte[] arr = new byte[buffer.writerIndex()]; buffer.getBytes(0, arr); return arr; }
/** * Sets the {@code float} at position {@code pos} in the Buffer to the value {@code i}. * * <p>The buffer will expand as necessary to accomodate any value written. */ public Buffer setFloat(int pos, float f) { ensureWritable(pos, 4); buffer.setFloat(pos, f); return this; }
/** * Sets the {@code short} at position {@code pos} in the Buffer to the value {@code i}. * * <p>The buffer will expand as necessary to accomodate any value written. */ public Buffer setShort(int pos, short s) { ensureWritable(pos, 2); buffer.setShort(pos, s); return this; }
/** * Appends the specified {@code short} to the end of the Buffer.The buffer will expand as * necessary to accomodate any bytes written. * * <p>Returns a reference to {@code this} so multiple operations can be appended together. */ public Buffer appendShort(short s) { buffer.writeShort(s); return this; }
/** * Sets the bytes at position {@code pos} in the Buffer to the value {@code b}. * * <p>The buffer will expand as necessary to accomodate any value written. */ public Buffer setBytes(int pos, ByteBuffer b) { ensureWritable(pos, b.limit()); buffer.setBytes(pos, b); return this; }
/** * Appends the specified {@code float} to the end of the Buffer. The buffer will expand as * necessary to accomodate any bytes written. * * <p>Returns a reference to {@code this} so multiple operations can be appended together. */ public Buffer appendFloat(float f) { buffer.writeFloat(f); return this; }
/** * Returns the length of the buffer, measured in bytes. The length is defined as the largest * position of any byte in the buffer + 1. All positions are indexed from zero. */ public int length() { return buffer.writerIndex(); }
/** * Appends the specified {@code double} to the end of the Buffer. The buffer will expand as * necessary to accomodate any bytes written. * * <p>Returns a reference to {@code this} so multiple operations can be appended together. */ public Buffer appendDouble(double d) { buffer.writeDouble(d); return this; }
private Buffer append(String str, Charset charset) { byte[] bytes = str.getBytes(charset); buffer.writeBytes(bytes); return this; }
/** * Returns the {@code double} at position {@code pos} in the Buffer. * * @throws IndexOutOfBoundsException if the specified {@code pos} is less than {@code 0} or {@code * pos + 8} is greater than the length {@code } of the Buffer. */ public double getDouble(int pos) { return buffer.getDouble(pos); }
/** * Sets the {@code byte} at position {@code pos} in the Buffer to the value {@code b}. * * <p>The buffer will expand as necessary to accomodate any value written. */ public Buffer setByte(int pos, byte b) { ensureWritable(pos, 1); buffer.setByte(pos, b); return this; }
/** * Returns the {@code float} at position {@code pos} in the Buffer. * * @throws IndexOutOfBoundsException if the specified {@code pos} is less than {@code 0} or {@code * pos + 4} is greater than the length {@code } of the Buffer. */ public float getFloat(int pos) { return buffer.getFloat(pos); }
/** * Sets the {@code int} at position {@code pos} in the Buffer to the value {@code i}. * * <p>The buffer will expand as necessary to accomodate any value written. */ public Buffer setInt(int pos, int i) { ensureWritable(pos, 4); buffer.setInt(pos, i); return this; }
/** * Returns the {@code long} at position {@code pos} in the Buffer. * * @throws IndexOutOfBoundsException if the specified {@code pos} is less than {@code 0} or {@code * pos + 8} is greater than the length {@code } of the Buffer. */ public long getLong(int pos) { return buffer.getLong(pos); }