0N/A/*
2362N/A * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.nio.channels;
0N/A
0N/Aimport java.io.FileInputStream;
0N/Aimport java.io.FileOutputStream;
0N/Aimport java.io.InputStream;
0N/Aimport java.io.OutputStream;
0N/Aimport java.io.Reader;
0N/Aimport java.io.Writer;
0N/Aimport java.io.IOException;
0N/Aimport java.nio.ByteBuffer;
0N/Aimport java.nio.charset.Charset;
0N/Aimport java.nio.charset.CharsetDecoder;
0N/Aimport java.nio.charset.CharsetEncoder;
0N/Aimport java.nio.charset.UnsupportedCharsetException;
0N/Aimport java.nio.channels.spi.AbstractInterruptibleChannel;
893N/Aimport java.util.concurrent.ExecutionException;
0N/Aimport sun.nio.ch.ChannelInputStream;
0N/Aimport sun.nio.cs.StreamDecoder;
0N/Aimport sun.nio.cs.StreamEncoder;
0N/A
0N/A
0N/A/**
0N/A * Utility methods for channels and streams.
0N/A *
0N/A * <p> This class defines static methods that support the interoperation of the
0N/A * stream classes of the <tt>{@link java.io}</tt> package with the channel
0N/A * classes of this package. </p>
0N/A *
0N/A *
0N/A * @author Mark Reinhold
0N/A * @author Mike McCloskey
0N/A * @author JSR-51 Expert Group
0N/A * @since 1.4
0N/A */
0N/A
0N/Apublic final class Channels {
0N/A
0N/A private Channels() { } // No instantiation
0N/A
724N/A private static void checkNotNull(Object o, String name) {
724N/A if (o == null)
724N/A throw new NullPointerException("\"" + name + "\" is null!");
724N/A }
0N/A
43N/A /**
43N/A * Write all remaining bytes in buffer to the given channel.
43N/A * If the channel is selectable then it must be configured blocking.
43N/A */
43N/A private static void writeFullyImpl(WritableByteChannel ch, ByteBuffer bb)
43N/A throws IOException
43N/A {
43N/A while (bb.remaining() > 0) {
43N/A int n = ch.write(bb);
43N/A if (n <= 0)
43N/A throw new RuntimeException("no bytes written");
43N/A }
43N/A }
43N/A
43N/A /**
43N/A * Write all remaining bytes in buffer to the given channel.
43N/A *
43N/A * @throws IllegalBlockingException
43N/A * If the channel is selectable and configured non-blocking.
43N/A */
43N/A private static void writeFully(WritableByteChannel ch, ByteBuffer bb)
0N/A throws IOException
0N/A {
0N/A if (ch instanceof SelectableChannel) {
0N/A SelectableChannel sc = (SelectableChannel)ch;
0N/A synchronized (sc.blockingLock()) {
0N/A if (!sc.isBlocking())
0N/A throw new IllegalBlockingModeException();
43N/A writeFullyImpl(ch, bb);
0N/A }
0N/A } else {
43N/A writeFullyImpl(ch, bb);
0N/A }
0N/A }
0N/A
0N/A // -- Byte streams from channels --
0N/A
0N/A /**
0N/A * Constructs a stream that reads bytes from the given channel.
0N/A *
0N/A * <p> The <tt>read</tt> methods of the resulting stream will throw an
0N/A * {@link IllegalBlockingModeException} if invoked while the underlying
0N/A * channel is in non-blocking mode. The stream will not be buffered, and
0N/A * it will not support the {@link InputStream#mark mark} or {@link
0N/A * InputStream#reset reset} methods. The stream will be safe for access by
0N/A * multiple concurrent threads. Closing the stream will in turn cause the
0N/A * channel to be closed. </p>
0N/A *
0N/A * @param ch
0N/A * The channel from which bytes will be read
0N/A *
0N/A * @return A new input stream
0N/A */
0N/A public static InputStream newInputStream(ReadableByteChannel ch) {
724N/A checkNotNull(ch, "ch");
0N/A return new sun.nio.ch.ChannelInputStream(ch);
0N/A }
0N/A
0N/A /**
0N/A * Constructs a stream that writes bytes to the given channel.
0N/A *
0N/A * <p> The <tt>write</tt> methods of the resulting stream will throw an
0N/A * {@link IllegalBlockingModeException} if invoked while the underlying
0N/A * channel is in non-blocking mode. The stream will not be buffered. The
0N/A * stream will be safe for access by multiple concurrent threads. Closing
0N/A * the stream will in turn cause the channel to be closed. </p>
0N/A *
0N/A * @param ch
0N/A * The channel to which bytes will be written
0N/A *
0N/A * @return A new output stream
0N/A */
0N/A public static OutputStream newOutputStream(final WritableByteChannel ch) {
724N/A checkNotNull(ch, "ch");
724N/A
0N/A return new OutputStream() {
0N/A
0N/A private ByteBuffer bb = null;
0N/A private byte[] bs = null; // Invoker's previous array
0N/A private byte[] b1 = null;
0N/A
0N/A public synchronized void write(int b) throws IOException {
0N/A if (b1 == null)
0N/A b1 = new byte[1];
0N/A b1[0] = (byte)b;
0N/A this.write(b1);
0N/A }
0N/A
0N/A public synchronized void write(byte[] bs, int off, int len)
0N/A throws IOException
0N/A {
0N/A if ((off < 0) || (off > bs.length) || (len < 0) ||
0N/A ((off + len) > bs.length) || ((off + len) < 0)) {
0N/A throw new IndexOutOfBoundsException();
0N/A } else if (len == 0) {
0N/A return;
0N/A }
0N/A ByteBuffer bb = ((this.bs == bs)
0N/A ? this.bb
0N/A : ByteBuffer.wrap(bs));
0N/A bb.limit(Math.min(off + len, bb.capacity()));
0N/A bb.position(off);
0N/A this.bb = bb;
0N/A this.bs = bs;
43N/A Channels.writeFully(ch, bb);
0N/A }
0N/A
0N/A public void close() throws IOException {
0N/A ch.close();
0N/A }
0N/A
0N/A };
0N/A }
0N/A
893N/A /**
893N/A * Constructs a stream that reads bytes from the given channel.
893N/A *
893N/A * <p> The stream will not be buffered, and it will not support the {@link
893N/A * InputStream#mark mark} or {@link InputStream#reset reset} methods. The
893N/A * stream will be safe for access by multiple concurrent threads. Closing
893N/A * the stream will in turn cause the channel to be closed. </p>
893N/A *
893N/A * @param ch
893N/A * The channel from which bytes will be read
893N/A *
893N/A * @return A new input stream
893N/A *
893N/A * @since 1.7
893N/A */
893N/A public static InputStream newInputStream(final AsynchronousByteChannel ch) {
893N/A checkNotNull(ch, "ch");
893N/A return new InputStream() {
893N/A
893N/A private ByteBuffer bb = null;
893N/A private byte[] bs = null; // Invoker's previous array
893N/A private byte[] b1 = null;
893N/A
893N/A @Override
893N/A public synchronized int read() throws IOException {
893N/A if (b1 == null)
893N/A b1 = new byte[1];
893N/A int n = this.read(b1);
893N/A if (n == 1)
893N/A return b1[0] & 0xff;
893N/A return -1;
893N/A }
893N/A
893N/A @Override
893N/A public synchronized int read(byte[] bs, int off, int len)
893N/A throws IOException
893N/A {
893N/A if ((off < 0) || (off > bs.length) || (len < 0) ||
893N/A ((off + len) > bs.length) || ((off + len) < 0)) {
893N/A throw new IndexOutOfBoundsException();
893N/A } else if (len == 0)
893N/A return 0;
893N/A
893N/A ByteBuffer bb = ((this.bs == bs)
893N/A ? this.bb
893N/A : ByteBuffer.wrap(bs));
893N/A bb.position(off);
893N/A bb.limit(Math.min(off + len, bb.capacity()));
893N/A this.bb = bb;
893N/A this.bs = bs;
893N/A
893N/A boolean interrupted = false;
893N/A try {
893N/A for (;;) {
893N/A try {
893N/A return ch.read(bb).get();
893N/A } catch (ExecutionException ee) {
893N/A throw new IOException(ee.getCause());
893N/A } catch (InterruptedException ie) {
893N/A interrupted = true;
893N/A }
893N/A }
893N/A } finally {
893N/A if (interrupted)
893N/A Thread.currentThread().interrupt();
893N/A }
893N/A }
893N/A
893N/A @Override
893N/A public void close() throws IOException {
893N/A ch.close();
893N/A }
893N/A };
893N/A }
893N/A
893N/A /**
893N/A * Constructs a stream that writes bytes to the given channel.
893N/A *
893N/A * <p> The stream will not be buffered. The stream will be safe for access
893N/A * by multiple concurrent threads. Closing the stream will in turn cause
893N/A * the channel to be closed. </p>
893N/A *
893N/A * @param ch
893N/A * The channel to which bytes will be written
893N/A *
893N/A * @return A new output stream
893N/A *
893N/A * @since 1.7
893N/A */
893N/A public static OutputStream newOutputStream(final AsynchronousByteChannel ch) {
893N/A checkNotNull(ch, "ch");
893N/A return new OutputStream() {
893N/A
893N/A private ByteBuffer bb = null;
893N/A private byte[] bs = null; // Invoker's previous array
893N/A private byte[] b1 = null;
893N/A
893N/A @Override
893N/A public synchronized void write(int b) throws IOException {
893N/A if (b1 == null)
893N/A b1 = new byte[1];
893N/A b1[0] = (byte)b;
893N/A this.write(b1);
893N/A }
893N/A
893N/A @Override
893N/A public synchronized void write(byte[] bs, int off, int len)
893N/A throws IOException
893N/A {
893N/A if ((off < 0) || (off > bs.length) || (len < 0) ||
893N/A ((off + len) > bs.length) || ((off + len) < 0)) {
893N/A throw new IndexOutOfBoundsException();
893N/A } else if (len == 0) {
893N/A return;
893N/A }
893N/A ByteBuffer bb = ((this.bs == bs)
893N/A ? this.bb
893N/A : ByteBuffer.wrap(bs));
893N/A bb.limit(Math.min(off + len, bb.capacity()));
893N/A bb.position(off);
893N/A this.bb = bb;
893N/A this.bs = bs;
893N/A
893N/A boolean interrupted = false;
893N/A try {
893N/A while (bb.remaining() > 0) {
893N/A try {
893N/A ch.write(bb).get();
893N/A } catch (ExecutionException ee) {
893N/A throw new IOException(ee.getCause());
893N/A } catch (InterruptedException ie) {
893N/A interrupted = true;
893N/A }
893N/A }
893N/A } finally {
893N/A if (interrupted)
893N/A Thread.currentThread().interrupt();
893N/A }
893N/A }
893N/A
893N/A @Override
893N/A public void close() throws IOException {
893N/A ch.close();
893N/A }
893N/A };
893N/A }
893N/A
0N/A
0N/A // -- Channels from streams --
0N/A
0N/A /**
0N/A * Constructs a channel that reads bytes from the given stream.
0N/A *
0N/A * <p> The resulting channel will not be buffered; it will simply redirect
0N/A * its I/O operations to the given stream. Closing the channel will in
0N/A * turn cause the stream to be closed. </p>
0N/A *
0N/A * @param in
0N/A * The stream from which bytes are to be read
0N/A *
0N/A * @return A new readable byte channel
0N/A */
0N/A public static ReadableByteChannel newChannel(final InputStream in) {
724N/A checkNotNull(in, "in");
0N/A
0N/A if (in instanceof FileInputStream &&
0N/A FileInputStream.class.equals(in.getClass())) {
0N/A return ((FileInputStream)in).getChannel();
0N/A }
0N/A
0N/A return new ReadableByteChannelImpl(in);
0N/A }
0N/A
0N/A private static class ReadableByteChannelImpl
0N/A extends AbstractInterruptibleChannel // Not really interruptible
0N/A implements ReadableByteChannel
0N/A {
0N/A InputStream in;
0N/A private static final int TRANSFER_SIZE = 8192;
0N/A private byte buf[] = new byte[0];
0N/A private boolean open = true;
0N/A private Object readLock = new Object();
0N/A
0N/A ReadableByteChannelImpl(InputStream in) {
0N/A this.in = in;
0N/A }
0N/A
0N/A public int read(ByteBuffer dst) throws IOException {
0N/A int len = dst.remaining();
0N/A int totalRead = 0;
0N/A int bytesRead = 0;
0N/A synchronized (readLock) {
0N/A while (totalRead < len) {
0N/A int bytesToRead = Math.min((len - totalRead),
0N/A TRANSFER_SIZE);
0N/A if (buf.length < bytesToRead)
0N/A buf = new byte[bytesToRead];
0N/A if ((totalRead > 0) && !(in.available() > 0))
0N/A break; // block at most once
0N/A try {
0N/A begin();
0N/A bytesRead = in.read(buf, 0, bytesToRead);
0N/A } finally {
0N/A end(bytesRead > 0);
0N/A }
0N/A if (bytesRead < 0)
0N/A break;
0N/A else
0N/A totalRead += bytesRead;
0N/A dst.put(buf, 0, bytesRead);
0N/A }
0N/A if ((bytesRead < 0) && (totalRead == 0))
0N/A return -1;
0N/A
0N/A return totalRead;
0N/A }
0N/A }
0N/A
0N/A protected void implCloseChannel() throws IOException {
0N/A in.close();
0N/A open = false;
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Constructs a channel that writes bytes to the given stream.
0N/A *
0N/A * <p> The resulting channel will not be buffered; it will simply redirect
0N/A * its I/O operations to the given stream. Closing the channel will in
0N/A * turn cause the stream to be closed. </p>
0N/A *
0N/A * @param out
0N/A * The stream to which bytes are to be written
0N/A *
0N/A * @return A new writable byte channel
0N/A */
0N/A public static WritableByteChannel newChannel(final OutputStream out) {
724N/A checkNotNull(out, "out");
0N/A
0N/A if (out instanceof FileOutputStream &&
0N/A FileOutputStream.class.equals(out.getClass())) {
0N/A return ((FileOutputStream)out).getChannel();
0N/A }
0N/A
0N/A return new WritableByteChannelImpl(out);
0N/A }
0N/A
0N/A private static class WritableByteChannelImpl
0N/A extends AbstractInterruptibleChannel // Not really interruptible
0N/A implements WritableByteChannel
0N/A {
0N/A OutputStream out;
0N/A private static final int TRANSFER_SIZE = 8192;
0N/A private byte buf[] = new byte[0];
0N/A private boolean open = true;
0N/A private Object writeLock = new Object();
0N/A
0N/A WritableByteChannelImpl(OutputStream out) {
0N/A this.out = out;
0N/A }
0N/A
0N/A public int write(ByteBuffer src) throws IOException {
0N/A int len = src.remaining();
0N/A int totalWritten = 0;
0N/A synchronized (writeLock) {
0N/A while (totalWritten < len) {
0N/A int bytesToWrite = Math.min((len - totalWritten),
0N/A TRANSFER_SIZE);
0N/A if (buf.length < bytesToWrite)
0N/A buf = new byte[bytesToWrite];
0N/A src.get(buf, 0, bytesToWrite);
0N/A try {
0N/A begin();
0N/A out.write(buf, 0, bytesToWrite);
0N/A } finally {
0N/A end(bytesToWrite > 0);
0N/A }
0N/A totalWritten += bytesToWrite;
0N/A }
0N/A return totalWritten;
0N/A }
0N/A }
0N/A
0N/A protected void implCloseChannel() throws IOException {
0N/A out.close();
0N/A open = false;
0N/A }
0N/A }
0N/A
0N/A
0N/A // -- Character streams from channels --
0N/A
0N/A /**
0N/A * Constructs a reader that decodes bytes from the given channel using the
0N/A * given decoder.
0N/A *
0N/A * <p> The resulting stream will contain an internal input buffer of at
0N/A * least <tt>minBufferCap</tt> bytes. The stream's <tt>read</tt> methods
0N/A * will, as needed, fill the buffer by reading bytes from the underlying
0N/A * channel; if the channel is in non-blocking mode when bytes are to be
0N/A * read then an {@link IllegalBlockingModeException} will be thrown. The
0N/A * resulting stream will not otherwise be buffered, and it will not support
0N/A * the {@link Reader#mark mark} or {@link Reader#reset reset} methods.
0N/A * Closing the stream will in turn cause the channel to be closed. </p>
0N/A *
0N/A * @param ch
0N/A * The channel from which bytes will be read
0N/A *
0N/A * @param dec
0N/A * The charset decoder to be used
0N/A *
0N/A * @param minBufferCap
0N/A * The minimum capacity of the internal byte buffer,
0N/A * or <tt>-1</tt> if an implementation-dependent
0N/A * default capacity is to be used
0N/A *
0N/A * @return A new reader
0N/A */
0N/A public static Reader newReader(ReadableByteChannel ch,
0N/A CharsetDecoder dec,
0N/A int minBufferCap)
0N/A {
724N/A checkNotNull(ch, "ch");
724N/A return StreamDecoder.forDecoder(ch, dec.reset(), minBufferCap);
0N/A }
0N/A
0N/A /**
0N/A * Constructs a reader that decodes bytes from the given channel according
0N/A * to the named charset.
0N/A *
0N/A * <p> An invocation of this method of the form
0N/A *
0N/A * <blockquote><pre>
0N/A * Channels.newReader(ch, csname)</pre></blockquote>
0N/A *
0N/A * behaves in exactly the same way as the expression
0N/A *
0N/A * <blockquote><pre>
0N/A * Channels.newReader(ch,
0N/A * Charset.forName(csName)
0N/A * .newDecoder(),
0N/A * -1);</pre></blockquote>
0N/A *
0N/A * @param ch
0N/A * The channel from which bytes will be read
0N/A *
0N/A * @param csName
0N/A * The name of the charset to be used
0N/A *
0N/A * @return A new reader
0N/A *
0N/A * @throws UnsupportedCharsetException
0N/A * If no support for the named charset is available
0N/A * in this instance of the Java virtual machine
0N/A */
0N/A public static Reader newReader(ReadableByteChannel ch,
0N/A String csName)
0N/A {
724N/A checkNotNull(csName, "csName");
0N/A return newReader(ch, Charset.forName(csName).newDecoder(), -1);
0N/A }
0N/A
0N/A /**
0N/A * Constructs a writer that encodes characters using the given encoder and
0N/A * writes the resulting bytes to the given channel.
0N/A *
0N/A * <p> The resulting stream will contain an internal output buffer of at
0N/A * least <tt>minBufferCap</tt> bytes. The stream's <tt>write</tt> methods
0N/A * will, as needed, flush the buffer by writing bytes to the underlying
0N/A * channel; if the channel is in non-blocking mode when bytes are to be
0N/A * written then an {@link IllegalBlockingModeException} will be thrown.
0N/A * The resulting stream will not otherwise be buffered. Closing the stream
0N/A * will in turn cause the channel to be closed. </p>
0N/A *
0N/A * @param ch
0N/A * The channel to which bytes will be written
0N/A *
0N/A * @param enc
0N/A * The charset encoder to be used
0N/A *
0N/A * @param minBufferCap
0N/A * The minimum capacity of the internal byte buffer,
0N/A * or <tt>-1</tt> if an implementation-dependent
0N/A * default capacity is to be used
0N/A *
0N/A * @return A new writer
0N/A */
0N/A public static Writer newWriter(final WritableByteChannel ch,
0N/A final CharsetEncoder enc,
0N/A final int minBufferCap)
0N/A {
724N/A checkNotNull(ch, "ch");
724N/A return StreamEncoder.forEncoder(ch, enc.reset(), minBufferCap);
0N/A }
0N/A
0N/A /**
0N/A * Constructs a writer that encodes characters according to the named
0N/A * charset and writes the resulting bytes to the given channel.
0N/A *
0N/A * <p> An invocation of this method of the form
0N/A *
0N/A * <blockquote><pre>
0N/A * Channels.newWriter(ch, csname)</pre></blockquote>
0N/A *
0N/A * behaves in exactly the same way as the expression
0N/A *
0N/A * <blockquote><pre>
0N/A * Channels.newWriter(ch,
0N/A * Charset.forName(csName)
0N/A * .newEncoder(),
0N/A * -1);</pre></blockquote>
0N/A *
0N/A * @param ch
0N/A * The channel to which bytes will be written
0N/A *
0N/A * @param csName
0N/A * The name of the charset to be used
0N/A *
0N/A * @return A new writer
0N/A *
0N/A * @throws UnsupportedCharsetException
0N/A * If no support for the named charset is available
0N/A * in this instance of the Java virtual machine
0N/A */
0N/A public static Writer newWriter(WritableByteChannel ch,
0N/A String csName)
0N/A {
724N/A checkNotNull(csName, "csName");
0N/A return newWriter(ch, Charset.forName(csName).newEncoder(), -1);
0N/A }
0N/A}