home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / io / PipedReader.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  9.2 KB  |  313 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)PipedReader.java    1.10 98/07/07
  3.  *
  4.  * Copyright 1996-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.io;
  16.  
  17.  
  18. /**
  19.  * Piped character-input streams.
  20.  *
  21.  * @version     1.10, 98/07/07
  22.  * @author    Mark Reinhold
  23.  * @since    JDK1.1
  24.  */
  25.  
  26. public class PipedReader extends Reader {
  27.     boolean closedByWriter = false;
  28.     boolean closedByReader = false;
  29.     boolean connected = false;
  30.  
  31.     /* REMIND: identification of the read and write sides needs to be
  32.        more sophisticated.  Either using thread groups (but what about
  33.        pipes within a thread?) or using finalization (but it may be a
  34.        long time until the next GC). */
  35.     Thread readSide;
  36.     Thread writeSide;
  37.  
  38.     /**
  39.      * The size of the pipe's circular input buffer.
  40.      */
  41.     static final int PIPE_SIZE = 1024;
  42.  
  43.     /**
  44.      * The circular buffer into which incoming data is placed.
  45.      */
  46.     char buffer[] = new char[PIPE_SIZE];
  47.  
  48.     /**
  49.      * The index of the position in the circular buffer at which the 
  50.      * next character of data will be stored when received from the connected 
  51.      * piped writer. <code>in<0</code> implies the buffer is empty, 
  52.      * <code>in==out</code> implies the buffer is full
  53.      */
  54.     int in = -1;
  55.  
  56.     /**
  57.      * The index of the position in the circular buffer at which the next 
  58.      * character of data will be read by this piped reader.
  59.      */
  60.     int out = 0;
  61.  
  62.     /**
  63.      * Creates a <code>PipedReader</code> so
  64.      * that it is connected to the piped writer
  65.      * <code>src</code>. Data written to <code>src</code> 
  66.      * will then be  available as input from this stream.
  67.      *
  68.      * @param      src   the stream to connect to.
  69.      * @exception  IOException  if an I/O error occurs.
  70.      */
  71.     public PipedReader(PipedWriter src) throws IOException {
  72.     connect(src);
  73.     }
  74.  
  75.     /**
  76.      * Creates a <code>PipedReader</code> so
  77.      * that it is not  yet connected. It must be
  78.      * connected to a <code>PipedWriter</code>
  79.      * before being used.
  80.      *
  81.      * @see     java.io.PipedReader#connect(java.io.PipedWriter)
  82.      * @see     java.io.PipedWriter#connect(java.io.PipedReader)
  83.      */
  84.     public PipedReader() {
  85.     }
  86.  
  87.     /**
  88.      * Causes this piped reader to be connected
  89.      * to the piped  writer <code>src</code>.
  90.      * If this object is already connected to some
  91.      * other piped writer, an <code>IOException</code>
  92.      * is thrown.
  93.      * <p>
  94.      * If <code>src</code> is an
  95.      * unconnected piped writer and <code>snk</code>
  96.      * is an unconnected piped reader, they
  97.      * may be connected by either the call:
  98.      * <p>
  99.      * <pre><code>snk.connect(src)</code> </pre> 
  100.      * <p>
  101.      * or the call:
  102.      * <p>
  103.      * <pre><code>src.connect(snk)</code> </pre> 
  104.      * <p>
  105.      * The two
  106.      * calls have the same effect.
  107.      *
  108.      * @param      src   The piped writer to connect to.
  109.      * @exception  IOException  if an I/O error occurs.
  110.      */
  111.     public void connect(PipedWriter src) throws IOException {
  112.     src.connect(this);
  113.     }
  114.     
  115.     /**
  116.      * Receives a char of data.  This method will block if no input is
  117.      * available.
  118.      */
  119.     synchronized void receive(int c) throws IOException {
  120.         if (!connected) {
  121.             throw new IOException("Pipe not connected");
  122.         } else if (closedByWriter || closedByReader) {
  123.         throw new IOException("Pipe closed");
  124.     } else if (readSide != null && !readSide.isAlive()) {
  125.             throw new IOException("Read end dead");
  126.         }
  127.  
  128.     writeSide = Thread.currentThread();
  129.     while (in == out) {
  130.         if ((readSide != null) && !readSide.isAlive()) {
  131.         throw new IOException("Pipe broken");
  132.         }
  133.         /* full: kick any waiting readers */
  134.         notifyAll();    
  135.         try {
  136.             wait(1000);
  137.         } catch (InterruptedException ex) {
  138.         throw new java.io.InterruptedIOException();
  139.         }
  140.     }
  141.     if (in < 0) {
  142.         in = 0;
  143.         out = 0;
  144.     }
  145.     buffer[in++] = (char) c;
  146.     if (in >= buffer.length) {
  147.         in = 0;
  148.     }
  149.     }
  150.  
  151.     /**
  152.      * Receives data into an array of characters.  This method will
  153.      * block until some input is available. 
  154.      */
  155.     synchronized void receive(char c[], int off, int len)  throws IOException {
  156.     while (--len >= 0) {
  157.         receive(c[off++]);
  158.     }
  159.     }
  160.  
  161.     /**
  162.      * Notifies all waiting threads that the last character of data has been
  163.      * received.
  164.      */
  165.     synchronized void receivedLast() {
  166.     closedByWriter = true;
  167.     notifyAll();
  168.     }
  169.  
  170.     /**
  171.      * Reads the next character of data from this piped stream.
  172.      * If no character is available because the end of the stream 
  173.      * has been reached, the value <code>-1</code> is returned. 
  174.      * This method blocks until input data is available, the end of
  175.      * the stream is detected, or an exception is thrown. 
  176.      *
  177.      * If a thread was providing data characters
  178.      * to the connected piped writer, but
  179.      * the  thread is no longer alive, then an
  180.      * <code>IOException</code> is thrown.
  181.      *
  182.      * @return     the next character of data, or <code>-1</code> if the end of the
  183.      *             stream is reached.
  184.      * @exception  IOException  if the pipe is broken.
  185.      */
  186.     public synchronized int read()  throws IOException {
  187.         if (!connected) {
  188.             throw new IOException("Pipe not connected");
  189.         } else if (closedByReader) {
  190.         throw new IOException("Pipe closed");
  191.     } else if (writeSide != null && !writeSide.isAlive()
  192.                    && !closedByWriter && (in < 0)) {
  193.             throw new IOException("Write end dead");
  194.         }
  195.  
  196.         readSide = Thread.currentThread();
  197.     int trials = 2;
  198.     while (in < 0) {
  199.         if (closedByWriter) { 
  200.         /* closed by writer, return EOF */
  201.         return -1;
  202.         }
  203.         if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {
  204.         throw new IOException("Pipe broken");
  205.         }
  206.             /* might be a writer waiting */
  207.         notifyAll();
  208.         try {
  209.             wait(1000);
  210.         } catch (InterruptedException ex) {
  211.         throw new java.io.InterruptedIOException();
  212.         }
  213.      }
  214.     int ret = buffer[out++];
  215.     if (out >= buffer.length) {
  216.         out = 0;
  217.     }
  218.     if (in == out) {
  219.             /* now empty */
  220.         in = -1;        
  221.     }
  222.     return ret;
  223.     }
  224.  
  225.     /**
  226.      * Reads up to <code>len</code> characters of data from this piped
  227.      * stream into an array of characters. Less than <code>len</code> characters
  228.      * will be read if the end of the data stream is reached. This method 
  229.      * blocks until at least one character of input is available. 
  230.      * If a thread was providing data characters to the connected piped output, 
  231.      * but the thread is no longer alive, then an <code>IOException</code> 
  232.      * is thrown.
  233.      *
  234.      * @param      cbuf     the buffer into which the data is read.
  235.      * @param      off   the start offset of the data.
  236.      * @param      len   the maximum number of characters read.
  237.      * @return     the total number of characters read into the buffer, or
  238.      *             <code>-1</code> if there is no more data because the end of
  239.      *             the stream has been reached.
  240.      * @exception  IOException  if an I/O error occurs.
  241.      */
  242.     public synchronized int read(char cbuf[], int off, int len)  throws IOException {
  243.         if (!connected) {
  244.             throw new IOException("Pipe not connected");
  245.         } else if (closedByReader) {
  246.         throw new IOException("Pipe closed");
  247.     } else if (writeSide != null && !writeSide.isAlive()
  248.                    && !closedByWriter && (in < 0)) {
  249.             throw new IOException("Write end dead");
  250.         }
  251.  
  252.         if ((off < 0) || (off > cbuf.length) || (len < 0) ||
  253.             ((off + len) > cbuf.length) || ((off + len) < 0)) {
  254.         throw new IndexOutOfBoundsException();
  255.     } else if (len == 0) {
  256.         return 0;
  257.     }
  258.  
  259.         /* possibly wait on the first character */
  260.     int c = read();        
  261.     if (c < 0) {
  262.         return -1;
  263.     }
  264.     cbuf[off] =  (char)c;
  265.     int rlen = 1;
  266.     while ((in >= 0) && (--len > 0)) {
  267.         cbuf[off + rlen] = buffer[out++];
  268.         rlen++;
  269.         if (out >= buffer.length) {
  270.         out = 0;
  271.         }
  272.         if (in == out) {
  273.                 /* now empty */
  274.         in = -1;    
  275.         }
  276.     }
  277.     return rlen;
  278.     }
  279.  
  280.     /**
  281.      * Tell whether this stream is ready to be read.  A piped character
  282.      * stream is ready if the circular buffer is not empty.
  283.      *
  284.      * @exception  IOException  If an I/O error occurs
  285.      */
  286.     public synchronized boolean ready() throws IOException {
  287.         if (!connected) {
  288.             throw new IOException("Pipe not connected");
  289.         } else if (closedByReader) {
  290.         throw new IOException("Pipe closed");
  291.     } else if (writeSide != null && !writeSide.isAlive()
  292.                    && !closedByWriter && (in < 0)) {
  293.             throw new IOException("Write end dead");
  294.         }
  295.         if (in < 0) {
  296.             return false;
  297.         } else {
  298.             return true;
  299.         }
  300.     }
  301.  
  302.     /**
  303.      * Closes this piped stream and releases any system resources 
  304.      * associated with the stream. 
  305.      *
  306.      * @exception  IOException  if an I/O error occurs.
  307.      */
  308.     public void close()  throws IOException {
  309.     in = -1;
  310.     closedByReader = true;
  311.     }
  312. }
  313.