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