Save This Page
Home » openjdk-7 » java » nio » channels » [javadoc | source]
    1   /*
    2    * Copyright 2000-2005 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package java.nio.channels;
   27   
   28   import java.io.FileInputStream;
   29   import java.io.FileOutputStream;
   30   import java.io.InputStream;
   31   import java.io.OutputStream;
   32   import java.io.Reader;
   33   import java.io.Writer;
   34   import java.io.IOException;
   35   import java.nio.ByteBuffer;
   36   import java.nio.CharBuffer;
   37   import java.nio.BufferOverflowException;
   38   import java.nio.BufferUnderflowException;
   39   import java.nio.charset.Charset;
   40   import java.nio.charset.CharsetDecoder;
   41   import java.nio.charset.CharsetEncoder;
   42   import java.nio.charset.CoderResult;
   43   import java.nio.charset.UnsupportedCharsetException;
   44   import java.nio.channels.spi.AbstractInterruptibleChannel;
   45   import sun.nio.ch.ChannelInputStream;
   46   import sun.nio.cs.StreamDecoder;
   47   import sun.nio.cs.StreamEncoder;
   48   
   49   
   50   /**
   51    * Utility methods for channels and streams.
   52    *
   53    * <p> This class defines static methods that support the interoperation of the
   54    * stream classes of the <tt>{@link java.io}</tt> package with the channel
   55    * classes of this package.  </p>
   56    *
   57    *
   58    * @author Mark Reinhold
   59    * @author Mike McCloskey
   60    * @author JSR-51 Expert Group
   61    * @since 1.4
   62    */
   63   
   64   public final class Channels {
   65   
   66       private Channels() { }              // No instantiation
   67   
   68   
   69       /**
   70        * Write all remaining bytes in buffer to the given channel.
   71        * If the channel is selectable then it must be configured blocking.
   72        */
   73       private static void writeFullyImpl(WritableByteChannel ch, ByteBuffer bb)
   74           throws IOException
   75       {
   76           while (bb.remaining() > 0) {
   77               int n = ch.write(bb);
   78               if (n <= 0)
   79                   throw new RuntimeException("no bytes written");
   80           }
   81       }
   82   
   83       /**
   84        * Write all remaining bytes in buffer to the given channel.
   85        *
   86        * @throws  IllegalBlockingException
   87        *          If the channel is selectable and configured non-blocking.
   88        */
   89       private static void writeFully(WritableByteChannel ch, ByteBuffer bb)
   90           throws IOException
   91       {
   92           if (ch instanceof SelectableChannel) {
   93               SelectableChannel sc = (SelectableChannel)ch;
   94               synchronized (sc.blockingLock()) {
   95                   if (!sc.isBlocking())
   96                       throw new IllegalBlockingModeException();
   97                   writeFullyImpl(ch, bb);
   98               }
   99           } else {
  100               writeFullyImpl(ch, bb);
  101           }
  102       }
  103   
  104       // -- Byte streams from channels --
  105   
  106       /**
  107        * Constructs a stream that reads bytes from the given channel.
  108        *
  109        * <p> The <tt>read</tt> methods of the resulting stream will throw an
  110        * {@link IllegalBlockingModeException} if invoked while the underlying
  111        * channel is in non-blocking mode.  The stream will not be buffered, and
  112        * it will not support the {@link InputStream#mark mark} or {@link
  113        * InputStream#reset reset} methods.  The stream will be safe for access by
  114        * multiple concurrent threads.  Closing the stream will in turn cause the
  115        * channel to be closed.  </p>
  116        *
  117        * @param  ch
  118        *         The channel from which bytes will be read
  119        *
  120        * @return  A new input stream
  121        */
  122       public static InputStream newInputStream(ReadableByteChannel ch) {
  123           return new sun.nio.ch.ChannelInputStream(ch);
  124       }
  125   
  126       /**
  127        * Constructs a stream that writes bytes to the given channel.
  128        *
  129        * <p> The <tt>write</tt> methods of the resulting stream will throw an
  130        * {@link IllegalBlockingModeException} if invoked while the underlying
  131        * channel is in non-blocking mode.  The stream will not be buffered.  The
  132        * stream will be safe for access by multiple concurrent threads.  Closing
  133        * the stream will in turn cause the channel to be closed.  </p>
  134        *
  135        * @param  ch
  136        *         The channel to which bytes will be written
  137        *
  138        * @return  A new output stream
  139        */
  140       public static OutputStream newOutputStream(final WritableByteChannel ch) {
  141           return new OutputStream() {
  142   
  143                   private ByteBuffer bb = null;
  144                   private byte[] bs = null;       // Invoker's previous array
  145                   private byte[] b1 = null;
  146   
  147                   public synchronized void write(int b) throws IOException {
  148                      if (b1 == null)
  149                           b1 = new byte[1];
  150                       b1[0] = (byte)b;
  151                       this.write(b1);
  152                   }
  153   
  154                   public synchronized void write(byte[] bs, int off, int len)
  155                       throws IOException
  156                   {
  157                       if ((off < 0) || (off > bs.length) || (len < 0) ||
  158                           ((off + len) > bs.length) || ((off + len) < 0)) {
  159                           throw new IndexOutOfBoundsException();
  160                       } else if (len == 0) {
  161                           return;
  162                       }
  163                       ByteBuffer bb = ((this.bs == bs)
  164                                        ? this.bb
  165                                        : ByteBuffer.wrap(bs));
  166                       bb.limit(Math.min(off + len, bb.capacity()));
  167                       bb.position(off);
  168                       this.bb = bb;
  169                       this.bs = bs;
  170                       Channels.writeFully(ch, bb);
  171                   }
  172   
  173                   public void close() throws IOException {
  174                       ch.close();
  175                   }
  176   
  177               };
  178       }
  179   
  180   
  181       // -- Channels from streams --
  182   
  183       /**
  184        * Constructs a channel that reads bytes from the given stream.
  185        *
  186        * <p> The resulting channel will not be buffered; it will simply redirect
  187        * its I/O operations to the given stream.  Closing the channel will in
  188        * turn cause the stream to be closed.  </p>
  189        *
  190        * @param  in
  191        *         The stream from which bytes are to be read
  192        *
  193        * @return  A new readable byte channel
  194        */
  195       public static ReadableByteChannel newChannel(final InputStream in) {
  196           if (in == null) {
  197               throw new NullPointerException();
  198           }
  199   
  200           if (in instanceof FileInputStream &&
  201               FileInputStream.class.equals(in.getClass())) {
  202               return ((FileInputStream)in).getChannel();
  203           }
  204   
  205           return new ReadableByteChannelImpl(in);
  206       }
  207   
  208       private static class ReadableByteChannelImpl
  209           extends AbstractInterruptibleChannel    // Not really interruptible
  210           implements ReadableByteChannel
  211       {
  212           InputStream in;
  213           private static final int TRANSFER_SIZE = 8192;
  214           private byte buf[] = new byte[0];
  215           private boolean open = true;
  216           private Object readLock = new Object();
  217   
  218           ReadableByteChannelImpl(InputStream in) {
  219               this.in = in;
  220           }
  221   
  222           public int read(ByteBuffer dst) throws IOException {
  223               int len = dst.remaining();
  224               int totalRead = 0;
  225               int bytesRead = 0;
  226               synchronized (readLock) {
  227                   while (totalRead < len) {
  228                       int bytesToRead = Math.min((len - totalRead),
  229                                                  TRANSFER_SIZE);
  230                       if (buf.length < bytesToRead)
  231                           buf = new byte[bytesToRead];
  232                       if ((totalRead > 0) && !(in.available() > 0))
  233                           break; // block at most once
  234                       try {
  235                           begin();
  236                           bytesRead = in.read(buf, 0, bytesToRead);
  237                       } finally {
  238                           end(bytesRead > 0);
  239                       }
  240                       if (bytesRead < 0)
  241                           break;
  242                       else
  243                           totalRead += bytesRead;
  244                       dst.put(buf, 0, bytesRead);
  245                   }
  246                   if ((bytesRead < 0) && (totalRead == 0))
  247                       return -1;
  248   
  249                   return totalRead;
  250               }
  251           }
  252   
  253           protected void implCloseChannel() throws IOException {
  254               in.close();
  255               open = false;
  256           }
  257       }
  258   
  259   
  260       /**
  261        * Constructs a channel that writes bytes to the given stream.
  262        *
  263        * <p> The resulting channel will not be buffered; it will simply redirect
  264        * its I/O operations to the given stream.  Closing the channel will in
  265        * turn cause the stream to be closed.  </p>
  266        *
  267        * @param  out
  268        *         The stream to which bytes are to be written
  269        *
  270        * @return  A new writable byte channel
  271        */
  272       public static WritableByteChannel newChannel(final OutputStream out) {
  273           if (out == null) {
  274               throw new NullPointerException();
  275           }
  276   
  277           if (out instanceof FileOutputStream &&
  278               FileOutputStream.class.equals(out.getClass())) {
  279                   return ((FileOutputStream)out).getChannel();
  280           }
  281   
  282           return new WritableByteChannelImpl(out);
  283       }
  284   
  285       private static class WritableByteChannelImpl
  286           extends AbstractInterruptibleChannel    // Not really interruptible
  287           implements WritableByteChannel
  288       {
  289           OutputStream out;
  290           private static final int TRANSFER_SIZE = 8192;
  291           private byte buf[] = new byte[0];
  292           private boolean open = true;
  293           private Object writeLock = new Object();
  294   
  295           WritableByteChannelImpl(OutputStream out) {
  296               this.out = out;
  297           }
  298   
  299           public int write(ByteBuffer src) throws IOException {
  300               int len = src.remaining();
  301               int totalWritten = 0;
  302               synchronized (writeLock) {
  303                   while (totalWritten < len) {
  304                       int bytesToWrite = Math.min((len - totalWritten),
  305                                                   TRANSFER_SIZE);
  306                       if (buf.length < bytesToWrite)
  307                           buf = new byte[bytesToWrite];
  308                       src.get(buf, 0, bytesToWrite);
  309                       try {
  310                           begin();
  311                           out.write(buf, 0, bytesToWrite);
  312                       } finally {
  313                           end(bytesToWrite > 0);
  314                       }
  315                       totalWritten += bytesToWrite;
  316                   }
  317                   return totalWritten;
  318               }
  319           }
  320   
  321           protected void implCloseChannel() throws IOException {
  322               out.close();
  323               open = false;
  324           }
  325       }
  326   
  327   
  328       // -- Character streams from channels --
  329   
  330       /**
  331        * Constructs a reader that decodes bytes from the given channel using the
  332        * given decoder.
  333        *
  334        * <p> The resulting stream will contain an internal input buffer of at
  335        * least <tt>minBufferCap</tt> bytes.  The stream's <tt>read</tt> methods
  336        * will, as needed, fill the buffer by reading bytes from the underlying
  337        * channel; if the channel is in non-blocking mode when bytes are to be
  338        * read then an {@link IllegalBlockingModeException} will be thrown.  The
  339        * resulting stream will not otherwise be buffered, and it will not support
  340        * the {@link Reader#mark mark} or {@link Reader#reset reset} methods.
  341        * Closing the stream will in turn cause the channel to be closed.  </p>
  342        *
  343        * @param  ch
  344        *         The channel from which bytes will be read
  345        *
  346        * @param  dec
  347        *         The charset decoder to be used
  348        *
  349        * @param  minBufferCap
  350        *         The minimum capacity of the internal byte buffer,
  351        *         or <tt>-1</tt> if an implementation-dependent
  352        *         default capacity is to be used
  353        *
  354        * @return  A new reader
  355        */
  356       public static Reader newReader(ReadableByteChannel ch,
  357                                      CharsetDecoder dec,
  358                                      int minBufferCap)
  359       {
  360           dec.reset();
  361           return StreamDecoder.forDecoder(ch, dec, minBufferCap);
  362       }
  363   
  364       /**
  365        * Constructs a reader that decodes bytes from the given channel according
  366        * to the named charset.
  367        *
  368        * <p> An invocation of this method of the form
  369        *
  370        * <blockquote><pre>
  371        * Channels.newReader(ch, csname)</pre></blockquote>
  372        *
  373        * behaves in exactly the same way as the expression
  374        *
  375        * <blockquote><pre>
  376        * Channels.newReader(ch,
  377        *                    Charset.forName(csName)
  378        *                        .newDecoder(),
  379        *                    -1);</pre></blockquote>
  380        *
  381        * @param  ch
  382        *         The channel from which bytes will be read
  383        *
  384        * @param  csName
  385        *         The name of the charset to be used
  386        *
  387        * @return  A new reader
  388        *
  389        * @throws  UnsupportedCharsetException
  390        *          If no support for the named charset is available
  391        *          in this instance of the Java virtual machine
  392        */
  393       public static Reader newReader(ReadableByteChannel ch,
  394                                      String csName)
  395       {
  396           return newReader(ch, Charset.forName(csName).newDecoder(), -1);
  397       }
  398   
  399       /**
  400        * Constructs a writer that encodes characters using the given encoder and
  401        * writes the resulting bytes to the given channel.
  402        *
  403        * <p> The resulting stream will contain an internal output buffer of at
  404        * least <tt>minBufferCap</tt> bytes.  The stream's <tt>write</tt> methods
  405        * will, as needed, flush the buffer by writing bytes to the underlying
  406        * channel; if the channel is in non-blocking mode when bytes are to be
  407        * written then an {@link IllegalBlockingModeException} will be thrown.
  408        * The resulting stream will not otherwise be buffered.  Closing the stream
  409        * will in turn cause the channel to be closed.  </p>
  410        *
  411        * @param  ch
  412        *         The channel to which bytes will be written
  413        *
  414        * @param  enc
  415        *         The charset encoder to be used
  416        *
  417        * @param  minBufferCap
  418        *         The minimum capacity of the internal byte buffer,
  419        *         or <tt>-1</tt> if an implementation-dependent
  420        *         default capacity is to be used
  421        *
  422        * @return  A new writer
  423        */
  424       public static Writer newWriter(final WritableByteChannel ch,
  425                                      final CharsetEncoder enc,
  426                                      final int minBufferCap)
  427       {
  428           enc.reset();
  429           return StreamEncoder.forEncoder(ch, enc, minBufferCap);
  430       }
  431   
  432       /**
  433        * Constructs a writer that encodes characters according to the named
  434        * charset and writes the resulting bytes to the given channel.
  435        *
  436        * <p> An invocation of this method of the form
  437        *
  438        * <blockquote><pre>
  439        * Channels.newWriter(ch, csname)</pre></blockquote>
  440        *
  441        * behaves in exactly the same way as the expression
  442        *
  443        * <blockquote><pre>
  444        * Channels.newWriter(ch,
  445        *                    Charset.forName(csName)
  446        *                        .newEncoder(),
  447        *                    -1);</pre></blockquote>
  448        *
  449        * @param  ch
  450        *         The channel to which bytes will be written
  451        *
  452        * @param  csName
  453        *         The name of the charset to be used
  454        *
  455        * @return  A new writer
  456        *
  457        * @throws  UnsupportedCharsetException
  458        *          If no support for the named charset is available
  459        *          in this instance of the Java virtual machine
  460        */
  461       public static Writer newWriter(WritableByteChannel ch,
  462                                      String csName)
  463       {
  464           return newWriter(ch, Charset.forName(csName).newEncoder(), -1);
  465       }
  466   
  467   }

Save This Page
Home » openjdk-7 » java » nio » channels » [javadoc | source]