Save This Page
Home » openjdk-7 » java » io » [javadoc | source]
    1   /*
    2    * Copyright 2005-2006 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.io;
   27   
   28   import java.util;
   29   import java.nio.charset.Charset;
   30   import sun.nio.cs.StreamDecoder;
   31   import sun.nio.cs.StreamEncoder;
   32   
   33   /**
   34    * Methods to access the character-based console device, if any, associated
   35    * with the current Java virtual machine.
   36    *
   37    * <p> Whether a virtual machine has a console is dependent upon the
   38    * underlying platform and also upon the manner in which the virtual
   39    * machine is invoked.  If the virtual machine is started from an
   40    * interactive command line without redirecting the standard input and
   41    * output streams then its console will exist and will typically be
   42    * connected to the keyboard and display from which the virtual machine
   43    * was launched.  If the virtual machine is started automatically, for
   44    * example by a background job scheduler, then it will typically not
   45    * have a console.
   46    * <p>
   47    * If this virtual machine has a console then it is represented by a
   48    * unique instance of this class which can be obtained by invoking the
   49    * {@link java.lang.System#console()} method.  If no console device is
   50    * available then an invocation of that method will return <tt>null</tt>.
   51    * <p>
   52    * Read and write operations are synchronized to guarantee the atomic
   53    * completion of critical operations; therefore invoking methods
   54    * {@link #readLine()}, {@link #readPassword()}, {@link #format format()},
   55    * {@link #printf printf()} as well as the read, format and write operations
   56    * on the objects returned by {@link #reader()} and {@link #writer()} may
   57    * block in multithreaded scenarios.
   58    * <p>
   59    * Invoking <tt>close()</tt> on the objects returned by the {@link #reader()}
   60    * and the {@link #writer()} will not close the underlying stream of those
   61    * objects.
   62    * <p>
   63    * The console-read methods return <tt>null</tt> when the end of the
   64    * console input stream is reached, for example by typing control-D on
   65    * Unix or control-Z on Windows.  Subsequent read operations will succeed
   66    * if additional characters are later entered on the console's input
   67    * device.
   68    * <p>
   69    * Unless otherwise specified, passing a <tt>null</tt> argument to any method
   70    * in this class will cause a {@link NullPointerException} to be thrown.
   71    * <p>
   72    * <b>Security note:</b>
   73    * If an application needs to read a password or other secure data, it should
   74    * use {@link #readPassword()} or {@link #readPassword(String, Object...)} and
   75    * manually zero the returned character array after processing to minimize the
   76    * lifetime of sensitive data in memory.
   77    *
   78    * <blockquote><pre>
   79    * Console cons;
   80    * char[] passwd;
   81    * if ((cons = System.console()) != null &&
   82    *     (passwd = cons.readPassword("[%s]", "Password:")) != null) {
   83    *     ...
   84    *     java.util.Arrays.fill(passwd, ' ');
   85    * }
   86    * </pre></blockquote>
   87    *
   88    * @author  Xueming Shen
   89    * @since   1.6
   90    */
   91   
   92   public final class Console implements Flushable
   93   {
   94      /**
   95       * Retrieves the unique {@link java.io.PrintWriter PrintWriter} object
   96       * associated with this console.
   97       *
   98       * @return  The printwriter associated with this console
   99       */
  100       public PrintWriter writer() {
  101           return pw;
  102       }
  103   
  104      /**
  105       * Retrieves the unique {@link java.io.Reader Reader} object associated
  106       * with this console.
  107       * <p>
  108       * This method is intended to be used by sophisticated applications, for
  109       * example, a {@link java.util.Scanner} object which utilizes the rich
  110       * parsing/scanning functionality provided by the <tt>Scanner</tt>:
  111       * <blockquote><pre>
  112       * Console con = System.console();
  113       * if (con != null) {
  114       *     Scanner sc = new Scanner(con.reader());
  115       *     ...
  116       * }
  117       * </pre></blockquote>
  118       * <p>
  119       * For simple applications requiring only line-oriented reading, use
  120       * <tt>{@link #readLine}</tt>.
  121       * <p>
  122       * The bulk read operations {@link java.io.Reader#read(char[]) read(char[]) },
  123       * {@link java.io.Reader#read(char[], int, int) read(char[], int, int) } and
  124       * {@link java.io.Reader#read(java.nio.CharBuffer) read(java.nio.CharBuffer)}
  125       * on the returned object will not read in characters beyond the line
  126       * bound for each invocation, even if the destination buffer has space for
  127       * more characters. A line bound is considered to be any one of a line feed
  128       * (<tt>'\n'</tt>), a carriage return (<tt>'\r'</tt>), a carriage return
  129       * followed immediately by a linefeed, or an end of stream.
  130       *
  131       * @return  The reader associated with this console
  132       */
  133       public Reader reader() {
  134           return reader;
  135       }
  136   
  137      /**
  138       * Writes a formatted string to this console's output stream using
  139       * the specified format string and arguments.
  140       *
  141       * @param  fmt
  142       *         A format string as described in <a
  143       *         href="../util/Formatter.html#syntax">Format string syntax</a>
  144       *
  145       * @param  args
  146       *         Arguments referenced by the format specifiers in the format
  147       *         string.  If there are more arguments than format specifiers, the
  148       *         extra arguments are ignored.  The number of arguments is
  149       *         variable and may be zero.  The maximum number of arguments is
  150       *         limited by the maximum dimension of a Java array as defined by
  151       *         the <a href="http://java.sun.com/docs/books/vmspec/">Java
  152       *         Virtual Machine Specification</a>.  The behaviour on a
  153       *         <tt>null</tt> argument depends on the <a
  154       *         href="../util/Formatter.html#syntax">conversion</a>.
  155       *
  156       * @throws  IllegalFormatException
  157       *          If a format string contains an illegal syntax, a format
  158       *          specifier that is incompatible with the given arguments,
  159       *          insufficient arguments given the format string, or other
  160       *          illegal conditions.  For specification of all possible
  161       *          formatting errors, see the <a
  162       *          href="../util/Formatter.html#detail">Details</a> section
  163       *          of the formatter class specification.
  164       *
  165       * @return  This console
  166       */
  167       public Console format(String fmt, Object ...args) {
  168           formatter.format(fmt, args).flush();
  169           return this;
  170       }
  171   
  172      /**
  173       * A convenience method to write a formatted string to this console's
  174       * output stream using the specified format string and arguments.
  175       *
  176       * <p> An invocation of this method of the form <tt>con.printf(format,
  177       * args)</tt> behaves in exactly the same way as the invocation of
  178       * <pre>con.format(format, args)</pre>.
  179       *
  180       * @param  format
  181       *         A format string as described in <a
  182       *         href="../util/Formatter.html#syntax">Format string syntax</a>.
  183       *
  184       * @param  args
  185       *         Arguments referenced by the format specifiers in the format
  186       *         string.  If there are more arguments than format specifiers, the
  187       *         extra arguments are ignored.  The number of arguments is
  188       *         variable and may be zero.  The maximum number of arguments is
  189       *         limited by the maximum dimension of a Java array as defined by
  190       *         the <a href="http://java.sun.com/docs/books/vmspec/">Java
  191       *         Virtual Machine Specification</a>.  The behaviour on a
  192       *         <tt>null</tt> argument depends on the <a
  193       *         href="../util/Formatter.html#syntax">conversion</a>.
  194       *
  195       * @throws  IllegalFormatException
  196       *          If a format string contains an illegal syntax, a format
  197       *          specifier that is incompatible with the given arguments,
  198       *          insufficient arguments given the format string, or other
  199       *          illegal conditions.  For specification of all possible
  200       *          formatting errors, see the <a
  201       *          href="../util/Formatter.html#detail">Details</a> section of the
  202       *          formatter class specification.
  203       *
  204       * @return  This console
  205       */
  206       public Console printf(String format, Object ... args) {
  207           return format(format, args);
  208       }
  209   
  210      /**
  211       * Provides a formatted prompt, then reads a single line of text from the
  212       * console.
  213       *
  214       * @param  fmt
  215       *         A format string as described in <a
  216       *         href="../util/Formatter.html#syntax">Format string syntax</a>.
  217       *
  218       * @param  args
  219       *         Arguments referenced by the format specifiers in the format
  220       *         string.  If there are more arguments than format specifiers, the
  221       *         extra arguments are ignored.  The maximum number of arguments is
  222       *         limited by the maximum dimension of a Java array as defined by
  223       *         the <a href="http://java.sun.com/docs/books/vmspec/">Java
  224       *         Virtual Machine Specification</a>.
  225       *
  226       * @throws  IllegalFormatException
  227       *          If a format string contains an illegal syntax, a format
  228       *          specifier that is incompatible with the given arguments,
  229       *          insufficient arguments given the format string, or other
  230       *          illegal conditions.  For specification of all possible
  231       *          formatting errors, see the <a
  232       *          href="../util/Formatter.html#detail">Details</a> section
  233       *          of the formatter class specification.
  234       *
  235       * @throws IOError
  236       *         If an I/O error occurs.
  237       *
  238       * @return  A string containing the line read from the console, not
  239       *          including any line-termination characters, or <tt>null</tt>
  240       *          if an end of stream has been reached.
  241       */
  242       public String readLine(String fmt, Object ... args) {
  243           String line = null;
  244           synchronized (writeLock) {
  245               synchronized(readLock) {
  246                   if (fmt.length() != 0)
  247                       pw.format(fmt, args);
  248                   try {
  249                       char[] ca = readline(false);
  250                       if (ca != null)
  251                           line = new String(ca);
  252                   } catch (IOException x) {
  253                       throw new IOError(x);
  254                   }
  255               }
  256           }
  257           return line;
  258       }
  259   
  260      /**
  261       * Reads a single line of text from the console.
  262       *
  263       * @throws IOError
  264       *         If an I/O error occurs.
  265       *
  266       * @return  A string containing the line read from the console, not
  267       *          including any line-termination characters, or <tt>null</tt>
  268       *          if an end of stream has been reached.
  269       */
  270       public String readLine() {
  271           return readLine("");
  272       }
  273   
  274      /**
  275       * Provides a formatted prompt, then reads a password or passphrase from
  276       * the console with echoing disabled.
  277       *
  278       * @param  fmt
  279       *         A format string as described in <a
  280       *         href="../util/Formatter.html#syntax">Format string syntax</a>
  281       *         for the prompt text.
  282       *
  283       * @param  args
  284       *         Arguments referenced by the format specifiers in the format
  285       *         string.  If there are more arguments than format specifiers, the
  286       *         extra arguments are ignored.  The maximum number of arguments is
  287       *         limited by the maximum dimension of a Java array as defined by
  288       *         the <a href="http://java.sun.com/docs/books/vmspec/">Java
  289       *         Virtual Machine Specification</a>.
  290       *
  291       * @throws  IllegalFormatException
  292       *          If a format string contains an illegal syntax, a format
  293       *          specifier that is incompatible with the given arguments,
  294       *          insufficient arguments given the format string, or other
  295       *          illegal conditions.  For specification of all possible
  296       *          formatting errors, see the <a
  297       *          href="../util/Formatter.html#detail">Details</a>
  298       *          section of the formatter class specification.
  299       *
  300       * @throws IOError
  301       *         If an I/O error occurs.
  302       *
  303       * @return  A character array containing the password or passphrase read
  304       *          from the console, not including any line-termination characters,
  305       *          or <tt>null</tt> if an end of stream has been reached.
  306       */
  307       public char[] readPassword(String fmt, Object ... args) {
  308           char[] passwd = null;
  309           synchronized (writeLock) {
  310               synchronized(readLock) {
  311                   if (fmt.length() != 0)
  312                       pw.format(fmt, args);
  313                   try {
  314                       echoOff = echo(false);
  315                       passwd = readline(true);
  316                   } catch (IOException x) {
  317                       throw new IOError(x);
  318                   } finally {
  319                       try {
  320                           echoOff = echo(true);
  321                       } catch (IOException xx) {}
  322                   }
  323                   pw.println();
  324               }
  325           }
  326           return passwd;
  327       }
  328   
  329      /**
  330       * Reads a password or passphrase from the console with echoing disabled
  331       *
  332       * @throws IOError
  333       *         If an I/O error occurs.
  334       *
  335       * @return  A character array containing the password or passphrase read
  336       *          from the console, not including any line-termination characters,
  337       *          or <tt>null</tt> if an end of stream has been reached.
  338       */
  339       public char[] readPassword() {
  340           return readPassword("");
  341       }
  342   
  343       /**
  344        * Flushes the console and forces any buffered output to be written
  345        * immediately .
  346        */
  347       public void flush() {
  348           pw.flush();
  349       }
  350   
  351       private Object readLock;
  352       private Object writeLock;
  353       private Reader reader;
  354       private Writer out;
  355       private PrintWriter pw;
  356       private Formatter formatter;
  357       private Charset cs;
  358       private char[] rcb;
  359       private static native String encoding();
  360       private static native boolean echo(boolean on) throws IOException;
  361       private static boolean echoOff;
  362   
  363       private char[] readline(boolean zeroOut) throws IOException {
  364           int len = reader.read(rcb, 0, rcb.length);
  365           if (len < 0)
  366               return null;  //EOL
  367           if (rcb[len-1] == '\r')
  368               len--;        //remove CR at end;
  369           else if (rcb[len-1] == '\n') {
  370               len--;        //remove LF at end;
  371               if (len > 0 && rcb[len-1] == '\r')
  372                   len--;    //remove the CR, if there is one
  373           }
  374           char[] b = new char[len];
  375           if (len > 0) {
  376               System.arraycopy(rcb, 0, b, 0, len);
  377               if (zeroOut) {
  378                   Arrays.fill(rcb, 0, len, ' ');
  379               }
  380           }
  381           return b;
  382       }
  383   
  384       private char[] grow() {
  385           assert Thread.holdsLock(readLock);
  386           char[] t = new char[rcb.length * 2];
  387           System.arraycopy(rcb, 0, t, 0, rcb.length);
  388           rcb = t;
  389           return rcb;
  390       }
  391   
  392       class LineReader extends Reader {
  393           private Reader in;
  394           private char[] cb;
  395           private int nChars, nextChar;
  396           boolean leftoverLF;
  397           LineReader(Reader in) {
  398               this.in = in;
  399               cb = new char[1024];
  400               nextChar = nChars = 0;
  401               leftoverLF = false;
  402           }
  403           public void close () {}
  404           public boolean ready() throws IOException {
  405               //in.ready synchronizes on readLock already
  406               return in.ready();
  407           }
  408   
  409           public int read(char cbuf[], int offset, int length)
  410               throws IOException
  411           {
  412               int off = offset;
  413               int end = offset + length;
  414               if (offset < 0 || offset > cbuf.length || length < 0 ||
  415                   end < 0 || end > cbuf.length) {
  416                   throw new IndexOutOfBoundsException();
  417               }
  418               synchronized(readLock) {
  419                   boolean eof = false;
  420                   char c = 0;
  421                   for (;;) {
  422                       if (nextChar >= nChars) {   //fill
  423                           int n = 0;
  424                           do {
  425                               n = in.read(cb, 0, cb.length);
  426                           } while (n == 0);
  427                           if (n > 0) {
  428                               nChars = n;
  429                               nextChar = 0;
  430                               if (n < cb.length &&
  431                                   cb[n-1] != '\n' && cb[n-1] != '\r') {
  432                                   /*
  433                                    * we're in canonical mode so each "fill" should
  434                                    * come back with an eol. if there no lf or nl at
  435                                    * the end of returned bytes we reached an eof.
  436                                    */
  437                                   eof = true;
  438                               }
  439                           } else { /*EOF*/
  440                               if (off - offset == 0)
  441                                   return -1;
  442                               return off - offset;
  443                           }
  444                       }
  445                       if (leftoverLF && cbuf == rcb && cb[nextChar] == '\n') {
  446                           /*
  447                            * if invoked by our readline, skip the leftover, otherwise
  448                            * return the LF.
  449                            */
  450                           nextChar++;
  451                       }
  452                       leftoverLF = false;
  453                       while (nextChar < nChars) {
  454                           c = cbuf[off++] = cb[nextChar];
  455                           cb[nextChar++] = 0;
  456                           if (c == '\n') {
  457                               return off - offset;
  458                           } else if (c == '\r') {
  459                               if (off == end) {
  460                                   /* no space left even the next is LF, so return
  461                                    * whatever we have if the invoker is not our
  462                                    * readLine()
  463                                    */
  464                                   if (cbuf == rcb) {
  465                                       cbuf = grow();
  466                                       end = cbuf.length;
  467                                   } else {
  468                                       leftoverLF = true;
  469                                       return off - offset;
  470                                   }
  471                               }
  472                               if (nextChar == nChars && in.ready()) {
  473                                   /*
  474                                    * we have a CR and we reached the end of
  475                                    * the read in buffer, fill to make sure we
  476                                    * don't miss a LF, if there is one, it's possible
  477                                    * that it got cut off during last round reading
  478                                    * simply because the read in buffer was full.
  479                                    */
  480                                   nChars = in.read(cb, 0, cb.length);
  481                                   nextChar = 0;
  482                               }
  483                               if (nextChar < nChars && cb[nextChar] == '\n') {
  484                                   cbuf[off++] = '\n';
  485                                   nextChar++;
  486                               }
  487                               return off - offset;
  488                           } else if (off == end) {
  489                              if (cbuf == rcb) {
  490                                   cbuf = grow();
  491                                   end = cbuf.length;
  492                              } else {
  493                                  return off - offset;
  494                              }
  495                           }
  496                       }
  497                       if (eof)
  498                           return off - offset;
  499                   }
  500               }
  501           }
  502       }
  503   
  504       // Set up JavaIOAccess in SharedSecrets
  505       static {
  506           sun.misc.SharedSecrets.setJavaIOAccess(new sun.misc.JavaIOAccess() {
  507               public Console console() {
  508                   if (istty()) {
  509                       if (cons == null)
  510                           cons = new Console();
  511                       return cons;
  512                   }
  513                   return null;
  514               }
  515   
  516               // Add a shutdown hook to restore console's echo state should
  517               // it be necessary.
  518               public Runnable consoleRestoreHook() {
  519                   return new Runnable() {
  520                       public void run() {
  521                           try {
  522                               if (echoOff) {
  523                                   echo(true);
  524                               }
  525                           } catch (IOException x) {}
  526                       }
  527                   };
  528               }
  529   
  530               public Charset charset() {
  531                   // This method is called in sun.security.util.Password,
  532                   // cons already exists when this method is called
  533                   return cons.cs;
  534               }
  535           });
  536       }
  537       private static Console cons;
  538       private native static boolean istty();
  539       private Console() {
  540           readLock = new Object();
  541           writeLock = new Object();
  542           String csname = encoding();
  543           if (csname != null) {
  544               try {
  545                   cs = Charset.forName(csname);
  546               } catch (Exception x) {}
  547           }
  548           if (cs == null)
  549               cs = Charset.defaultCharset();
  550           out = StreamEncoder.forOutputStreamWriter(
  551                     new FileOutputStream(FileDescriptor.out),
  552                     writeLock,
  553                     cs);
  554           pw = new PrintWriter(out, true) { public void close() {} };
  555           formatter = new Formatter(out);
  556           reader = new LineReader(StreamDecoder.forInputStreamReader(
  557                        new FileInputStream(FileDescriptor.in),
  558                        readLock,
  559                        cs));
  560           rcb = new char[1024];
  561       }
  562   }

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