8066678: java.nio.channels.Channels cleanup

Reviewed-by: alanb, chegar
This commit is contained in:
Pavel Rappo 2014-12-05 15:35:15 +00:00
parent 7e7e10eb42
commit 421fc583be

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -38,6 +38,7 @@ import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder; import java.nio.charset.CharsetEncoder;
import java.nio.charset.UnsupportedCharsetException; import java.nio.charset.UnsupportedCharsetException;
import java.nio.channels.spi.AbstractInterruptibleChannel; import java.nio.channels.spi.AbstractInterruptibleChannel;
import java.util.Objects;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import sun.nio.ch.ChannelInputStream; import sun.nio.ch.ChannelInputStream;
import sun.nio.cs.StreamDecoder; import sun.nio.cs.StreamDecoder;
@ -48,8 +49,8 @@ import sun.nio.cs.StreamEncoder;
* Utility methods for channels and streams. * Utility methods for channels and streams.
* *
* <p> This class defines static methods that support the interoperation of the * <p> This class defines static methods that support the interoperation of the
* stream classes of the <tt>{@link java.io}</tt> package with the channel * stream classes of the {@link java.io} package with the channel classes
* classes of this package. </p> * of this package. </p>
* *
* *
* @author Mark Reinhold * @author Mark Reinhold
@ -60,12 +61,7 @@ import sun.nio.cs.StreamEncoder;
public final class Channels { public final class Channels {
private Channels() { } // No instantiation private Channels() { throw new Error("no instances"); }
private static void checkNotNull(Object o, String name) {
if (o == null)
throw new NullPointerException("\"" + name + "\" is null!");
}
/** /**
* Write all remaining bytes in buffer to the given channel. * Write all remaining bytes in buffer to the given channel.
@ -91,7 +87,7 @@ public final class Channels {
throws IOException throws IOException
{ {
if (ch instanceof SelectableChannel) { if (ch instanceof SelectableChannel) {
SelectableChannel sc = (SelectableChannel)ch; SelectableChannel sc = (SelectableChannel) ch;
synchronized (sc.blockingLock()) { synchronized (sc.blockingLock()) {
if (!sc.isBlocking()) if (!sc.isBlocking())
throw new IllegalBlockingModeException(); throw new IllegalBlockingModeException();
@ -107,7 +103,7 @@ public final class Channels {
/** /**
* Constructs a stream that reads bytes from the given channel. * Constructs a stream that reads bytes from the given channel.
* *
* <p> The <tt>read</tt> methods of the resulting stream will throw an * <p> The {@code read} methods of the resulting stream will throw an
* {@link IllegalBlockingModeException} if invoked while the underlying * {@link IllegalBlockingModeException} if invoked while the underlying
* channel is in non-blocking mode. The stream will not be buffered, and * channel is in non-blocking mode. The stream will not be buffered, and
* it will not support the {@link InputStream#mark mark} or {@link * it will not support the {@link InputStream#mark mark} or {@link
@ -121,14 +117,14 @@ public final class Channels {
* @return A new input stream * @return A new input stream
*/ */
public static InputStream newInputStream(ReadableByteChannel ch) { public static InputStream newInputStream(ReadableByteChannel ch) {
checkNotNull(ch, "ch"); Objects.requireNonNull(ch, "ch");
return new sun.nio.ch.ChannelInputStream(ch); return new ChannelInputStream(ch);
} }
/** /**
* Constructs a stream that writes bytes to the given channel. * Constructs a stream that writes bytes to the given channel.
* *
* <p> The <tt>write</tt> methods of the resulting stream will throw an * <p> The {@code write} methods of the resulting stream will throw an
* {@link IllegalBlockingModeException} if invoked while the underlying * {@link IllegalBlockingModeException} if invoked while the underlying
* channel is in non-blocking mode. The stream will not be buffered. The * channel is in non-blocking mode. The stream will not be buffered. The
* stream will be safe for access by multiple concurrent threads. Closing * stream will be safe for access by multiple concurrent threads. Closing
@ -139,22 +135,24 @@ public final class Channels {
* *
* @return A new output stream * @return A new output stream
*/ */
public static OutputStream newOutputStream(final WritableByteChannel ch) { public static OutputStream newOutputStream(WritableByteChannel ch) {
checkNotNull(ch, "ch"); Objects.requireNonNull(ch, "ch");
return new OutputStream() { return new OutputStream() {
private ByteBuffer bb = null; private ByteBuffer bb;
private byte[] bs = null; // Invoker's previous array private byte[] bs; // Invoker's previous array
private byte[] b1 = null; private byte[] b1;
@Override
public synchronized void write(int b) throws IOException { public synchronized void write(int b) throws IOException {
if (b1 == null) if (b1 == null)
b1 = new byte[1]; b1 = new byte[1];
b1[0] = (byte)b; b1[0] = (byte) b;
this.write(b1); this.write(b1);
} }
@Override
public synchronized void write(byte[] bs, int off, int len) public synchronized void write(byte[] bs, int off, int len)
throws IOException throws IOException
{ {
@ -174,6 +172,7 @@ public final class Channels {
Channels.writeFully(ch, bb); Channels.writeFully(ch, bb);
} }
@Override
public void close() throws IOException { public void close() throws IOException {
ch.close(); ch.close();
} }
@ -196,13 +195,13 @@ public final class Channels {
* *
* @since 1.7 * @since 1.7
*/ */
public static InputStream newInputStream(final AsynchronousByteChannel ch) { public static InputStream newInputStream(AsynchronousByteChannel ch) {
checkNotNull(ch, "ch"); Objects.requireNonNull(ch, "ch");
return new InputStream() { return new InputStream() {
private ByteBuffer bb = null; private ByteBuffer bb;
private byte[] bs = null; // Invoker's previous array private byte[] bs; // Invoker's previous array
private byte[] b1 = null; private byte[] b1;
@Override @Override
public synchronized int read() throws IOException { public synchronized int read() throws IOException {
@ -221,8 +220,9 @@ public final class Channels {
if ((off < 0) || (off > bs.length) || (len < 0) || if ((off < 0) || (off > bs.length) || (len < 0) ||
((off + len) > bs.length) || ((off + len) < 0)) { ((off + len) > bs.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} else if (len == 0) } else if (len == 0) {
return 0; return 0;
}
ByteBuffer bb = ((this.bs == bs) ByteBuffer bb = ((this.bs == bs)
? this.bb ? this.bb
@ -270,19 +270,19 @@ public final class Channels {
* *
* @since 1.7 * @since 1.7
*/ */
public static OutputStream newOutputStream(final AsynchronousByteChannel ch) { public static OutputStream newOutputStream(AsynchronousByteChannel ch) {
checkNotNull(ch, "ch"); Objects.requireNonNull(ch, "ch");
return new OutputStream() { return new OutputStream() {
private ByteBuffer bb = null; private ByteBuffer bb;
private byte[] bs = null; // Invoker's previous array private byte[] bs; // Invoker's previous array
private byte[] b1 = null; private byte[] b1;
@Override @Override
public synchronized void write(int b) throws IOException { public synchronized void write(int b) throws IOException {
if (b1 == null) if (b1 == null)
b1 = new byte[1]; b1 = new byte[1];
b1[0] = (byte)b; b1[0] = (byte) b;
this.write(b1); this.write(b1);
} }
@ -343,12 +343,11 @@ public final class Channels {
* *
* @return A new readable byte channel * @return A new readable byte channel
*/ */
public static ReadableByteChannel newChannel(final InputStream in) { public static ReadableByteChannel newChannel(InputStream in) {
checkNotNull(in, "in"); Objects.requireNonNull(in, "in");
if (in instanceof FileInputStream && if (in.getClass() == FileInputStream.class) {
FileInputStream.class.equals(in.getClass())) { return ((FileInputStream) in).getChannel();
return ((FileInputStream)in).getChannel();
} }
return new ReadableByteChannelImpl(in); return new ReadableByteChannelImpl(in);
@ -358,16 +357,16 @@ public final class Channels {
extends AbstractInterruptibleChannel // Not really interruptible extends AbstractInterruptibleChannel // Not really interruptible
implements ReadableByteChannel implements ReadableByteChannel
{ {
InputStream in; private final InputStream in;
private static final int TRANSFER_SIZE = 8192; private static final int TRANSFER_SIZE = 8192;
private byte buf[] = new byte[0]; private byte[] buf = new byte[0];
private boolean open = true; private final Object readLock = new Object();
private Object readLock = new Object();
ReadableByteChannelImpl(InputStream in) { ReadableByteChannelImpl(InputStream in) {
this.in = in; this.in = in;
} }
@Override
public int read(ByteBuffer dst) throws IOException { public int read(ByteBuffer dst) throws IOException {
int len = dst.remaining(); int len = dst.remaining();
int totalRead = 0; int totalRead = 0;
@ -399,9 +398,9 @@ public final class Channels {
} }
} }
@Override
protected void implCloseChannel() throws IOException { protected void implCloseChannel() throws IOException {
in.close(); in.close();
open = false;
} }
} }
@ -418,12 +417,11 @@ public final class Channels {
* *
* @return A new writable byte channel * @return A new writable byte channel
*/ */
public static WritableByteChannel newChannel(final OutputStream out) { public static WritableByteChannel newChannel(OutputStream out) {
checkNotNull(out, "out"); Objects.requireNonNull(out, "out");
if (out instanceof FileOutputStream && if (out.getClass() == FileOutputStream.class) {
FileOutputStream.class.equals(out.getClass())) { return ((FileOutputStream) out).getChannel();
return ((FileOutputStream)out).getChannel();
} }
return new WritableByteChannelImpl(out); return new WritableByteChannelImpl(out);
@ -433,16 +431,16 @@ public final class Channels {
extends AbstractInterruptibleChannel // Not really interruptible extends AbstractInterruptibleChannel // Not really interruptible
implements WritableByteChannel implements WritableByteChannel
{ {
OutputStream out; private final OutputStream out;
private static final int TRANSFER_SIZE = 8192; private static final int TRANSFER_SIZE = 8192;
private byte buf[] = new byte[0]; private byte[] buf = new byte[0];
private boolean open = true; private final Object writeLock = new Object();
private Object writeLock = new Object();
WritableByteChannelImpl(OutputStream out) { WritableByteChannelImpl(OutputStream out) {
this.out = out; this.out = out;
} }
@Override
public int write(ByteBuffer src) throws IOException { public int write(ByteBuffer src) throws IOException {
int len = src.remaining(); int len = src.remaining();
int totalWritten = 0; int totalWritten = 0;
@ -465,9 +463,9 @@ public final class Channels {
} }
} }
@Override
protected void implCloseChannel() throws IOException { protected void implCloseChannel() throws IOException {
out.close(); out.close();
open = false;
} }
} }
@ -479,7 +477,7 @@ public final class Channels {
* given decoder. * given decoder.
* *
* <p> The resulting stream will contain an internal input buffer of at * <p> The resulting stream will contain an internal input buffer of at
* least <tt>minBufferCap</tt> bytes. The stream's <tt>read</tt> methods * least {@code minBufferCap} bytes. The stream's {@code read} methods
* will, as needed, fill the buffer by reading bytes from the underlying * will, as needed, fill the buffer by reading bytes from the underlying
* channel; if the channel is in non-blocking mode when bytes are to be * channel; if the channel is in non-blocking mode when bytes are to be
* read then an {@link IllegalBlockingModeException} will be thrown. The * read then an {@link IllegalBlockingModeException} will be thrown. The
@ -495,7 +493,7 @@ public final class Channels {
* *
* @param minBufferCap * @param minBufferCap
* The minimum capacity of the internal byte buffer, * The minimum capacity of the internal byte buffer,
* or <tt>-1</tt> if an implementation-dependent * or {@code -1} if an implementation-dependent
* default capacity is to be used * default capacity is to be used
* *
* @return A new reader * @return A new reader
@ -504,7 +502,7 @@ public final class Channels {
CharsetDecoder dec, CharsetDecoder dec,
int minBufferCap) int minBufferCap)
{ {
checkNotNull(ch, "ch"); Objects.requireNonNull(ch, "ch");
return StreamDecoder.forDecoder(ch, dec.reset(), minBufferCap); return StreamDecoder.forDecoder(ch, dec.reset(), minBufferCap);
} }
@ -514,16 +512,15 @@ public final class Channels {
* *
* <p> An invocation of this method of the form * <p> An invocation of this method of the form
* *
* <blockquote><pre> * <pre> {@code
* Channels.newReader(ch, csname)</pre></blockquote> * Channels.newReader(ch, csname)
* } </pre>
* *
* behaves in exactly the same way as the expression * behaves in exactly the same way as the expression
* *
* <blockquote><pre> * <pre> {@code
* Channels.newReader(ch, * Channels.newReader(ch, Charset.forName(csName).newDecoder(), -1)
* Charset.forName(csName) * } </pre>
* .newDecoder(),
* -1);</pre></blockquote>
* *
* @param ch * @param ch
* The channel from which bytes will be read * The channel from which bytes will be read
@ -540,7 +537,7 @@ public final class Channels {
public static Reader newReader(ReadableByteChannel ch, public static Reader newReader(ReadableByteChannel ch,
String csName) String csName)
{ {
checkNotNull(csName, "csName"); Objects.requireNonNull(csName, "csName");
return newReader(ch, Charset.forName(csName).newDecoder(), -1); return newReader(ch, Charset.forName(csName).newDecoder(), -1);
} }
@ -549,7 +546,7 @@ public final class Channels {
* writes the resulting bytes to the given channel. * writes the resulting bytes to the given channel.
* *
* <p> The resulting stream will contain an internal output buffer of at * <p> The resulting stream will contain an internal output buffer of at
* least <tt>minBufferCap</tt> bytes. The stream's <tt>write</tt> methods * least {@code minBufferCap} bytes. The stream's {@code write} methods
* will, as needed, flush the buffer by writing bytes to the underlying * will, as needed, flush the buffer by writing bytes to the underlying
* channel; if the channel is in non-blocking mode when bytes are to be * channel; if the channel is in non-blocking mode when bytes are to be
* written then an {@link IllegalBlockingModeException} will be thrown. * written then an {@link IllegalBlockingModeException} will be thrown.
@ -564,16 +561,16 @@ public final class Channels {
* *
* @param minBufferCap * @param minBufferCap
* The minimum capacity of the internal byte buffer, * The minimum capacity of the internal byte buffer,
* or <tt>-1</tt> if an implementation-dependent * or {@code -1} if an implementation-dependent
* default capacity is to be used * default capacity is to be used
* *
* @return A new writer * @return A new writer
*/ */
public static Writer newWriter(final WritableByteChannel ch, public static Writer newWriter(WritableByteChannel ch,
final CharsetEncoder enc, CharsetEncoder enc,
final int minBufferCap) int minBufferCap)
{ {
checkNotNull(ch, "ch"); Objects.requireNonNull(ch, "ch");
return StreamEncoder.forEncoder(ch, enc.reset(), minBufferCap); return StreamEncoder.forEncoder(ch, enc.reset(), minBufferCap);
} }
@ -582,17 +579,15 @@ public final class Channels {
* charset and writes the resulting bytes to the given channel. * charset and writes the resulting bytes to the given channel.
* *
* <p> An invocation of this method of the form * <p> An invocation of this method of the form
* * <p>
* <blockquote><pre> * <pre> {@code
* Channels.newWriter(ch, csname)</pre></blockquote> * Channels.newWriter(ch, csname)
* * } </pre>
* behaves in exactly the same way as the expression * behaves in exactly the same way as the expression
* * <p>
* <blockquote><pre> * <pre> {@code
* Channels.newWriter(ch, * Channels.newWriter(ch, Charset.forName(csName).newEncoder(), -1)
* Charset.forName(csName) * } </pre>
* .newEncoder(),
* -1);</pre></blockquote>
* *
* @param ch * @param ch
* The channel to which bytes will be written * The channel to which bytes will be written
@ -609,7 +604,7 @@ public final class Channels {
public static Writer newWriter(WritableByteChannel ch, public static Writer newWriter(WritableByteChannel ch,
String csName) String csName)
{ {
checkNotNull(csName, "csName"); Objects.requireNonNull(csName, "csName");
return newWriter(ch, Charset.forName(csName).newEncoder(), -1); return newWriter(ch, Charset.forName(csName).newEncoder(), -1);
} }
} }