Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Various cleanups and fixes

  • Loading branch information...
commit e4947153f25eb9d7f5a13bb012b2a2f85ef63563 1 parent 4846d69
@dmlloyd dmlloyd authored
View
2  api/src/main/java/org/xnio/BufferAllocator.java
@@ -28,6 +28,8 @@
/**
* A simple allocator for buffers.
*
+ * @param <B> the buffer type
+ *
* @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
*/
public interface BufferAllocator<B extends Buffer> {
View
59 api/src/main/java/org/xnio/ByteBufferSlicePool.java
@@ -42,71 +42,56 @@
public final class ByteBufferSlicePool implements Pool<ByteBuffer> {
private final Set<Ref> refSet = Collections.synchronizedSet(new HashSet<Ref>());
-
private final Queue<Slice> sliceQueue = new ConcurrentLinkedQueue<Slice>();
+ private final BufferAllocator<ByteBuffer> allocator;
+ private final int bufferSize;
+ private final int buffersPerRegion;
/**
* Construct a new instance.
*
* @param allocator the buffer allocator to use
* @param bufferSize the size of each buffer
- * @param bufferCount the number of buffers to allocate
* @param maxRegionSize the maximum region size for each backing buffer
*/
- public ByteBufferSlicePool(final BufferAllocator<ByteBuffer> allocator, final int bufferSize, final int bufferCount, final int maxRegionSize) {
+ public ByteBufferSlicePool(final BufferAllocator<ByteBuffer> allocator, final int bufferSize, final int maxRegionSize) {
if (bufferSize <= 0) {
throw new IllegalArgumentException("Buffer size must be greater than zero");
}
- if (bufferCount <= 0) {
- throw new IllegalArgumentException("Buffer count must be greater than zero");
- }
if (maxRegionSize < bufferSize) {
throw new IllegalArgumentException("Maximum region size must be greater than or equal to the buffer size");
}
- final long finalSize = (long) bufferSize * (long) bufferCount;
- final int buffersPerRegion = maxRegionSize / bufferSize;
- final int wholeRegionCount = (int) (finalSize / (long)maxRegionSize);
- final int lastRegionBufferCount = (int) (finalSize % (long)maxRegionSize);
- for (int i = 0; i < wholeRegionCount; i ++) {
- // this buffer may only ever be updated via a duplicate
- final ByteBuffer buffer = allocator.allocate(buffersPerRegion * bufferSize);
- for (int j = 0; j < buffersPerRegion; j ++) {
- sliceQueue.add(new Slice(buffer, j * bufferSize, bufferSize));
- }
- }
- if (lastRegionBufferCount > 0) {
- // this buffer may only ever be updated via a duplicate
- final ByteBuffer buffer = allocator.allocate(bufferSize * lastRegionBufferCount);
- for (int j = 0; j < lastRegionBufferCount; j ++) {
- sliceQueue.add(new Slice(buffer, j * bufferSize, bufferSize));
- }
- }
+ buffersPerRegion = maxRegionSize / bufferSize;
+ this.bufferSize = bufferSize;
+ this.allocator = allocator;
}
/**
* Construct a new instance, using a direct buffer allocator.
*
* @param bufferSize the size of each buffer
- * @param bufferCount the number of buffers to allocate
* @param maxRegionSize the maximum region size for each backing buffer
*/
- public ByteBufferSlicePool(final int bufferSize, final int bufferCount, final int maxRegionSize) {
- this(BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR, bufferSize, bufferCount, maxRegionSize);
- }
-
- /**
- * Construct a new instance, using a direct buffer allocator and a maximum region size of {@code Integer.MAX_VALUE}.
- *
- * @param bufferSize the size of each buffer
- * @param bufferCount the number of buffers to allocate
- */
- public ByteBufferSlicePool(final int bufferSize, final int bufferCount) {
- this(bufferSize, bufferCount, Integer.MAX_VALUE);
+ public ByteBufferSlicePool(final int bufferSize, final int maxRegionSize) {
+ this(BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR, bufferSize, maxRegionSize);
}
/** {@inheritDoc} */
public Pooled<ByteBuffer> allocate() {
+ final Queue<Slice> sliceQueue = this.sliceQueue;
final Slice slice = sliceQueue.poll();
+ if (slice == null) {
+ final int bufferSize = this.bufferSize;
+ final int buffersPerRegion = this.buffersPerRegion;
+ final ByteBuffer region = allocator.allocate(buffersPerRegion * bufferSize);
+ int idx = bufferSize;
+ for (int i = 1; i <= buffersPerRegion; i ++) {
+ sliceQueue.add(new Slice(region, idx, bufferSize));
+ idx += bufferSize;
+ }
+ final Slice newSlice = new Slice(region, 0, bufferSize);
+ return new PooledByteBuffer(newSlice, newSlice.slice());
+ }
return slice == null ? null : new PooledByteBuffer(slice, slice.slice());
}
View
4 api/src/main/java/org/xnio/ByteString.java
@@ -83,7 +83,7 @@ public static ByteString copyOf(byte[] b, int offs, int len) {
}
/**
- * Get a byte string from the bytes of a charater string.
+ * Get a byte string from the bytes of a character string.
*
* @param str the character string
* @param charset the character set to use
@@ -95,7 +95,7 @@ public static ByteString getBytes(String str, String charset) throws Unsupported
}
/**
- * Get a byte string from the bytes of a charater string.
+ * Get a byte string from the bytes of a character string.
*
* @param str the character string
* @param charset the character set to use
View
3  api/src/main/java/org/xnio/Options.java
@@ -22,6 +22,9 @@
package org.xnio;
+import org.xnio.sasl.SaslQop;
+import org.xnio.sasl.SaslStrength;
+
import javax.security.sasl.Sasl;
/**
View
2  api/src/main/java/org/xnio/SaslQop.java → api/src/main/java/org/xnio/sasl/SaslQop.java
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
-package org.xnio;
+package org.xnio.sasl;
/**
* The SASL quality-of-protection value.
View
2  api/src/main/java/org/xnio/SaslStrength.java → ...main/java/org/xnio/sasl/SaslStrength.java
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
-package org.xnio;
+package org.xnio.sasl;
/**
* The SASL cipher strength value.
View
217 api/src/main/java/org/xnio/streams/ReaderInputStream.java
@@ -0,0 +1,217 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.xnio.streams;
+
+import java.io.CharConversionException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import org.xnio.Buffers;
+
+/**
+ * An input stream which encodes characters into bytes.
+ */
+public final class ReaderInputStream extends InputStream {
+
+ private final Reader reader;
+ private final CharsetEncoder encoder;
+ private final CharBuffer charBuffer;
+ private final ByteBuffer byteBuffer;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param reader the reader to encode from
+ */
+ public ReaderInputStream(final Reader reader) {
+ this(reader, Charset.defaultCharset());
+ }
+
+ /**
+ * Construct a new instance.
+ *
+ * @param reader the reader to encode from
+ * @param charsetName the character set name
+ * @throws UnsupportedEncodingException if the character set is not supported
+ */
+ public ReaderInputStream(final Reader reader, final String charsetName) throws UnsupportedEncodingException {
+ this(reader, Streams.getCharset(charsetName));
+ }
+
+ /**
+ * Construct a new instance.
+ *
+ * @param reader the reader to encode from
+ * @param charset the character set
+ */
+ public ReaderInputStream(final Reader reader, final Charset charset) {
+ this(reader, getEncoder(charset));
+ }
+
+ /**
+ * Construct a new instance.
+ *
+ * @param reader the reader to encode from
+ * @param encoder the character set encoder
+ */
+ public ReaderInputStream(final Reader reader, final CharsetEncoder encoder) {
+ this(reader, encoder, 1024);
+ }
+
+ /**
+ * Construct a new instance.
+ *
+ * @param reader the reader to encode from
+ * @param encoder the character set encoder
+ * @param bufferSize the buffer size to use
+ */
+ public ReaderInputStream(final Reader reader, final CharsetEncoder encoder, final int bufferSize) {
+ this.reader = reader;
+ this.encoder = encoder;
+ charBuffer = CharBuffer.wrap(new char[bufferSize]);
+ byteBuffer = ByteBuffer.wrap(new byte[(int) ((float)bufferSize * encoder.averageBytesPerChar() + 0.5f)]);
+ }
+
+ private static CharsetEncoder getEncoder(final Charset charset) {
+ final CharsetEncoder encoder = charset.newEncoder();
+ encoder.onMalformedInput(CodingErrorAction.REPLACE);
+ encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ return encoder;
+ }
+
+ /** {@inheritDoc} */
+ public int read() throws IOException {
+ final ByteBuffer byteBuffer = this.byteBuffer;
+ if (! byteBuffer.hasRemaining()) {
+ if (! fill()) {
+ return -1;
+ }
+ }
+ return byteBuffer.get() & 0xff;
+ }
+
+ /** {@inheritDoc} */
+ public int read(final byte[] b, int off, int len) throws IOException {
+ final ByteBuffer byteBuffer = this.byteBuffer;
+ int cnt = 0;
+ while (len > 0) {
+ final int r = byteBuffer.remaining();
+ if (r == 0) {
+ if (! fill()) return cnt == 0 ? -1 : cnt;
+ continue;
+ }
+ final int c = Math.min(r, len);
+ byteBuffer.get(b, off, c);
+ cnt += c;
+ off += c;
+ len -= c;
+ }
+ return cnt;
+ }
+
+ private boolean fill() throws IOException {
+ final CharBuffer charBuffer = this.charBuffer;
+ final ByteBuffer byteBuffer = this.byteBuffer;
+ byteBuffer.compact();
+ try {
+ while (byteBuffer.hasRemaining()) {
+ while (charBuffer.hasRemaining()) {
+ final CoderResult result = encoder.encode(charBuffer, byteBuffer, false);
+ if (result.isOverflow()) {
+ return true;
+ }
+ if (result.isUnderflow()) {
+ break;
+ }
+ if (result.isError()) {
+ if (result.isMalformed()) {
+ throw new CharConversionException("Malformed input");
+ }
+ if (result.isUnmappable()) {
+ throw new CharConversionException("Unmappable character");
+ }
+ throw new CharConversionException("Character decoding problem");
+ }
+ }
+ charBuffer.compact();
+ try {
+ final int cnt = reader.read(charBuffer);
+ if (cnt == -1) {
+ return false;
+ }
+ } finally {
+ charBuffer.flip();
+ }
+ }
+ return true;
+ } finally {
+ byteBuffer.flip();
+ }
+ }
+
+ /** {@inheritDoc} */
+ public long skip(long n) throws IOException {
+ final ByteBuffer byteBuffer = this.byteBuffer;
+ int cnt = 0;
+ while (n > 0) {
+ final int r = byteBuffer.remaining();
+ if (r == 0) {
+ if (! fill()) return cnt;
+ continue;
+ }
+ final int c = Math.min(r, n > (long) Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) n);
+ Buffers.skip(byteBuffer, c);
+ cnt += c;
+ n -= c;
+ }
+ return cnt;
+ }
+
+ /** {@inheritDoc} */
+ public int available() throws IOException {
+ return byteBuffer.remaining();
+ }
+
+ /** {@inheritDoc} */
+ public void close() throws IOException {
+ byteBuffer.clear();
+ charBuffer.clear();
+ reader.close();
+ }
+
+ /**
+ * Get a string representation of this object.
+ *
+ * @return the string
+ */
+ public String toString() {
+ return "ReaderInputStream over " + reader;
+ }
+}
View
100 api/src/main/java/org/xnio/streams/Streams.java
@@ -0,0 +1,100 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2011, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.xnio.streams;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.UnsupportedCharsetException;
+import org.xnio.IoUtils;
+
+/**
+ * @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
+ */
+public final class Streams {
+
+ /**
+ * Copy from one stream to another.
+ *
+ * @param input the source stream
+ * @param output the destination stream
+ * @param close {@code true} if the input and output streams should be closed
+ * @param bufferSize the buffer size
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copyStream(InputStream input, OutputStream output, boolean close, int bufferSize) throws IOException {
+ final byte[] buffer = new byte[bufferSize];
+ int res;
+ try {
+ for (;;) {
+ res = input.read(buffer);
+ if (res == -1) {
+ if (close) {
+ input.close();
+ output.close();
+ }
+ return;
+ }
+ output.write(buffer, 0, res);
+ }
+ } finally {
+ if (close) {
+ IoUtils.safeClose(input);
+ IoUtils.safeClose(output);
+ }
+ }
+ }
+
+ /**
+ * Copy from one stream to another. A default buffer size is assumed.
+ *
+ * @param input the source stream
+ * @param output the destination stream
+ * @param close {@code true} if the input and output streams should be closed
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copyStream(InputStream input, OutputStream output, boolean close) throws IOException {
+ copyStream(input, output, close, 8192);
+ }
+
+ /**
+ * Copy from one stream to another. A default buffer size is assumed, and both streams are closed on completion.
+ *
+ * @param input the source stream
+ * @param output the destination stream
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copyStream(InputStream input, OutputStream output) throws IOException {
+ copyStream(input, output, true, 8192);
+ }
+
+ static Charset getCharset(final String charsetName) throws UnsupportedEncodingException {
+ try {
+ return Charset.forName(charsetName);
+ } catch (UnsupportedCharsetException e) {
+ throw new UnsupportedEncodingException(e.getMessage());
+ }
+ }
+}
View
195 api/src/main/java/org/xnio/streams/WriterOutputStream.java
@@ -0,0 +1,195 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.xnio.streams;
+
+import java.io.CharConversionException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * An output stream which decodes bytes into a character writer.
+ */
+public final class WriterOutputStream extends OutputStream {
+
+ private final Writer writer;
+ private final CharsetDecoder decoder;
+ private final ByteBuffer byteBuffer;
+ private final char[] chars;
+ private volatile boolean closed;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param writer the writer to decode into
+ */
+ public WriterOutputStream(final Writer writer) {
+ this(writer, Charset.defaultCharset());
+ }
+
+ /**
+ * Construct a new instance.
+ *
+ * @param writer the writer to decode into
+ * @param decoder the charset decoder to use
+ */
+ public WriterOutputStream(final Writer writer, final CharsetDecoder decoder) {
+ this(writer, decoder, 1024);
+ }
+
+ /**
+ * Construct a new instance.
+ *
+ * @param writer the writer to decode into
+ * @param decoder the charset decoder to use
+ * @param bufferSize the buffer size to use
+ */
+ public WriterOutputStream(final Writer writer, final CharsetDecoder decoder, int bufferSize) {
+ this.writer = writer;
+ this.decoder = decoder;
+ byteBuffer = ByteBuffer.allocate(bufferSize);
+ chars = new char[(int) ((float)bufferSize * decoder.maxCharsPerByte() + 0.5f)];
+ }
+
+ /**
+ * Construct a new instance.
+ *
+ * @param writer the writer to decode into
+ * @param charset the character set to use
+ */
+ public WriterOutputStream(final Writer writer, final Charset charset) {
+ this(writer, getDecoder(charset));
+ }
+
+ /**
+ * Construct a new instance.
+ *
+ * @param writer the writer to decode into
+ * @param charsetName the character set name to use
+ * @throws UnsupportedEncodingException if the character set name is unknown
+ */
+ public WriterOutputStream(final Writer writer, final String charsetName) throws UnsupportedEncodingException {
+ this(writer, Streams.getCharset(charsetName));
+ }
+
+ private static CharsetDecoder getDecoder(final Charset charset) {
+ final CharsetDecoder decoder = charset.newDecoder();
+ decoder.onMalformedInput(CodingErrorAction.REPLACE);
+ decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ decoder.replaceWith("?");
+ return decoder;
+ }
+
+ /** {@inheritDoc} */
+ public void write(final int b) throws IOException {
+ if (closed) throw new IOException("Stream closed");
+ final ByteBuffer byteBuffer = this.byteBuffer;
+ if (! byteBuffer.hasRemaining()) {
+ doFlush(false);
+ }
+ byteBuffer.put((byte) b);
+ }
+
+ /** {@inheritDoc} */
+ public void write(final byte[] b, int off, int len) throws IOException {
+ if (closed) throw new IOException("Stream closed");
+ final ByteBuffer byteBuffer = this.byteBuffer;
+ // todo Correct first, fast later
+ while (len > 0) {
+ final int r = byteBuffer.remaining();
+ if (r == 0) {
+ doFlush(false);
+ continue;
+ }
+ final int c = Math.min(len, r);
+ byteBuffer.put(b, off, c);
+ len -= c;
+ off += c;
+ }
+ }
+
+ private void doFlush(final boolean eof) throws IOException {
+ final CharBuffer charBuffer = CharBuffer.wrap(chars);
+ final ByteBuffer byteBuffer = this.byteBuffer;
+ final CharsetDecoder decoder = this.decoder;
+ byteBuffer.flip();
+ try {
+ while (byteBuffer.hasRemaining()) {
+ final CoderResult result = decoder.decode(byteBuffer, charBuffer, eof);
+ if (result.isOverflow()) {
+ writer.write(chars, 0, charBuffer.position());
+ charBuffer.clear();
+ continue;
+ }
+ if (result.isUnderflow()) {
+ final int p = charBuffer.position();
+ if (p > 0) {
+ writer.write(chars, 0, p);
+ }
+ return;
+ }
+ if (result.isError()) {
+ if (result.isMalformed()) {
+ throw new CharConversionException("Malformed input");
+ }
+ if (result.isUnmappable()) {
+ throw new CharConversionException("Unmappable character");
+ }
+ throw new CharConversionException("Character decoding problem");
+ }
+ }
+ } finally {
+ byteBuffer.compact();
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void flush() throws IOException {
+ if (closed) throw new IOException("Stream closed");
+ writer.flush();
+ }
+
+ /** {@inheritDoc} */
+ public void close() throws IOException {
+ closed = true;
+ doFlush(true);
+ byteBuffer.clear();
+ writer.close();
+ }
+
+ /**
+ * Get the string representation of this object.
+ *
+ * @return the string
+ */
+ public String toString() {
+ return "Output stream writing to " + writer;
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.