Home | History | Annotate | Download | only in support
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package tests.support;
     19 
     20 import java.io.IOException;
     21 import java.io.Reader;
     22 
     23 public class Support_StringReader extends Reader {
     24     private String str;
     25 
     26     private int markpos = -1;
     27 
     28     private int pos = 0;
     29 
     30     private int count;
     31 
     32     /**
     33      * Construct a StringReader on the String <code>str</code>. The size of
     34      * the reader is set to the <code>length()</code> of the String and the
     35      * Object to synchronize access through is set to <code>str</code>.
     36      *
     37      * @param str
     38      *            the String to filter reads on.
     39      */
     40     public Support_StringReader(String str) {
     41         super(str);
     42         this.str = str;
     43         this.count = str.length();
     44     }
     45 
     46     /**
     47      * This method closes this StringReader. Once it is closed, you can no
     48      * longer read from it. Only the first invocation of this method has any
     49      * effect.
     50      *
     51      */
     52     @Override
     53     public void close() {
     54         synchronized (lock) {
     55             if (isOpen()) {
     56                 str = null;
     57             }
     58         }
     59     }
     60 
     61     /**
     62      * Answer a boolean indicating whether or not this StringReader is open.
     63      */
     64     private boolean isOpen() {
     65         return str != null;
     66     }
     67 
     68     /**
     69      * Set a Mark position in this Reader. The parameter <code>readLimit</code>
     70      * is ignored for StringReaders. Sending reset() will reposition the reader
     71      * back to the marked position provided the mark has not been invalidated.
     72      *
     73      * @param readlimit
     74      *            ignored for StringReaders.
     75      *
     76      * @exception java.io.IOException
     77      *                If an error occurs attempting mark this StringReader.
     78      */
     79     @Override
     80     public void mark(int readLimit) throws IOException {
     81         if (readLimit >= 0) {
     82             synchronized (lock) {
     83                 if (isOpen()) {
     84                     markpos = pos;
     85                 } else {
     86                     throw new IOException("StringReader is closed");
     87                 }
     88             }
     89         } else {
     90             throw new IllegalArgumentException();
     91         }
     92     }
     93 
     94     /**
     95      * Answers a boolean indicating whether or not this StringReader supports
     96      * mark() and reset(). This method always returns true.
     97      *
     98      * @return <code>true</code> if mark() and reset() are supported,
     99      *         <code>false</code> otherwise. This implementation always
    100      *         returns <code>true</code>.
    101      */
    102     @Override
    103     public boolean markSupported() {
    104         return true;
    105     }
    106 
    107     /**
    108      * Reads a single character from this StringReader and returns the result as
    109      * an int. The 2 higher-order bytes are set to 0. If the end of reader was
    110      * encountered then return -1.
    111      *
    112      * @return the character read or -1 if end of reader.
    113      *
    114      * @exception java.io.IOException
    115      *                If the StringReader is already closed.
    116      */
    117     @Override
    118     public int read() throws IOException {
    119         synchronized (lock) {
    120             if (isOpen()) {
    121                 if (pos != count) {
    122                     return str.charAt(pos++);
    123                 }
    124                 return -1;
    125             }
    126             throw new IOException("StringReader is closed");
    127         }
    128     }
    129 
    130     /**
    131      * Reads at most <code>count</code> characters from this StringReader and
    132      * stores them at <code>offset</code> in the character array
    133      * <code>buf</code>. Returns the number of characters actually read or -1
    134      * if the end of reader was encountered.
    135      *
    136      * @param buf
    137      *            character array to store the read characters
    138      * @param offset
    139      *            offset in buf to store the read characters
    140      * @param count
    141      *            maximum number of characters to read
    142      * @return the number of characters read or -1 if end of reader.
    143      *
    144      * @exception java.io.IOException
    145      *                If the StringReader is closed.
    146      */
    147     @Override
    148     public int read(char buf[], int offset, int count) throws IOException {
    149         // avoid int overflow
    150         if (0 <= offset && offset <= buf.length && 0 <= count
    151                 && count <= buf.length - offset) {
    152             synchronized (lock) {
    153                 if (isOpen()) {
    154                     if (pos == this.count) {
    155                         return -1;
    156                     }
    157                     int end = pos + count > this.count ? this.count : pos
    158                             + count;
    159                     str.getChars(pos, end, buf, offset);
    160                     int read = end - pos;
    161                     pos = end;
    162                     return read;
    163                 }
    164                 throw new IOException("StringReader is closed");
    165             }
    166         }
    167         throw new ArrayIndexOutOfBoundsException();
    168     }
    169 
    170     /**
    171      * Answers a <code>boolean</code> indicating whether or not this
    172      * StringReader is ready to be read without blocking. If the result is
    173      * <code>true</code>, the next <code>read()</code> will not block. If
    174      * the result is <code>false</code> this Reader may or may not block when
    175      * <code>read()</code> is sent. The implementation in StringReader always
    176      * returns <code>true</code> even when it has been closed.
    177      *
    178      * @return <code>true</code> if the receiver will not block when
    179      *         <code>read()</code> is called, <code>false</code> if unknown
    180      *         or blocking will occur.
    181      *
    182      * @exception java.io.IOException
    183      *                If an IO error occurs.
    184      */
    185     @Override
    186     public boolean ready() throws IOException {
    187         synchronized (lock) {
    188             if (isOpen()) {
    189                 return true;
    190             }
    191             throw new IOException("StringReader is closed");
    192         }
    193     }
    194 
    195     /**
    196      * Reset this StringReader's position to the last <code>mark()</code>
    197      * location. Invocations of <code>read()/skip()</code> will occur from
    198      * this new location. If this Reader was not marked, the StringReader is
    199      * reset to the beginning of the String.
    200      *
    201      * @exception java.io.IOException
    202      *                If this StringReader has already been closed.
    203      */
    204     @Override
    205     public void reset() throws IOException {
    206         synchronized (lock) {
    207             if (isOpen()) {
    208                 pos = markpos != -1 ? markpos : 0;
    209             } else {
    210                 throw new IOException("StringReader is closed");
    211             }
    212         }
    213     }
    214 
    215     /**
    216      * Skips <code>count</code> number of characters in this StringReader.
    217      * Subsequent <code>read()</code>'s will not return these characters
    218      * unless <code>reset()</code> is used.
    219      *
    220      * @param count
    221      *            The number of characters to skip.
    222      * @return the number of characters actually skipped.
    223      *
    224      * @exception java.io.IOException
    225      *                If this StringReader has already been closed.
    226      */
    227     @Override
    228     public long skip(long count) throws IOException {
    229         synchronized (lock) {
    230             if (isOpen()) {
    231                 if (count <= 0) {
    232                     return 0;
    233                 }
    234                 long skipped = 0;
    235                 if (count < this.count - pos) {
    236                     pos = pos + (int) count;
    237                     skipped = count;
    238                 } else {
    239                     skipped = this.count - pos;
    240                     pos = this.count;
    241                 }
    242                 return skipped;
    243             }
    244             throw new IOException("StringReader is closed");
    245         }
    246     }
    247 }
    248