001: /*
002: * ReaderSource.java: java.io.Reader-backed data source for the Tokenizer.
003: *
004: * Copyright (C) 2002 Heiko Blau
005: *
006: * This file belongs to the JTopas Library.
007: * JTopas is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as published by the
009: * Free Software Foundation; either version 2.1 of the License, or (at your
010: * option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE.
015: * See the GNU Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public License along
018: * with JTopas. If not, write to the
019: *
020: * Free Software Foundation, Inc.
021: * 59 Temple Place, Suite 330,
022: * Boston, MA 02111-1307
023: * USA
024: *
025: * or check the Internet: http://www.fsf.org
026: *
027: * Contact:
028: * email: heiko@susebox.de
029: */
030:
031: package de.susebox.jtopas;
032:
033: //-----------------------------------------------------------------------------
034: // Imports
035: //
036: import java.io.InputStream;
037: import java.io.FileInputStream;
038: import java.io.Reader;
039: import java.io.InputStreamReader;
040: import java.io.File;
041: import java.io.IOException;
042:
043: //-----------------------------------------------------------------------------
044: // Class ReaderSource
045: //
046:
047: /**<p>
048: * This implementation of the {@link TokenizerSource} interface uses the JDK
049: * {@link java.io.Reader} class to realize the requested functionality. Note that
050: * the backing <code>Reader</code> can be changed during the parse operations of
051: * the {@link Tokenizer} instance that accesses this <code>ReaderSource</code>.
052: *</p>
053: *
054: * @see de.susebox.java.util.Tokenizer
055: * @see de.susebox.java.util.AbstractTokenizer
056: * @author Heiko Blau
057: * @see java.io.Reader
058: */
059: public class ReaderSource implements TokenizerSource {
060:
061: //---------------------------------------------------------------------------
062: // Constructors
063: //
064:
065: /**
066: * The default constructor constructs a <code>ReaderSource</code> instance
067: * that reads from nowhere. A call to the {@link #read} method will immediately
068: * return the end-of-file condition.
069: *
070: * @see #read
071: */
072: public ReaderSource() {
073: this ((Reader) null);
074: }
075:
076: /**
077: * Constructing an <code>ReaderSource</code> object with the given {@link java.io.Reader}
078: * instance to get input data from. <code>null</code> is a valid value. The
079: * {@link #read} method will return an end-of-file condition in that case.
080: *<br>
081: * The given {@link java.io.Reader} instance can be closed manually or by
082: * calling the {@link #close} method of this <code>ReaderSource</code> object.
083: *
084: * @param reader the backing {@link java.io.Reader} or <code>null</code>
085: */
086: public ReaderSource(Reader reader) {
087: setReader(reader);
088: }
089:
090: /**
091: * This Constructor takes an {@link java.io.InputStream}. It is comfortable
092: * when You dont have a {@link java.io.Reader} in the first place. However,
093: * when using this constructor, the method {@link #close} should be called
094: * after tokenizing has been finished. It will also close the given
095: * <code>InputStream</code>.
096: *<br>
097: * The method accepts <code>null</code> leading to an end-of-file condition
098: * in the first call to {@link #read}.
099: *
100: * @param is the input stream or <code>null</code>
101: */
102: public ReaderSource(InputStream is) {
103: if ((_inputStream = is) != null) {
104: setReader(new InputStreamReader(is));
105: }
106: }
107:
108: /**
109: * This Constructor takes an {@link java.io.File} to create a {@link java.io.Reader}
110: * from. When using this constructor, the method {@link #close} should be
111: * called after tokenizing has been finished.
112: *<br>
113: * The method accepts <code>null</code> leading to an end-of-file condition
114: * in the first call to {@link #read}.
115: *
116: * @param file the {@link java.io.File} object that should be read or <code>null</code>
117: */
118: public ReaderSource(File file) throws IOException {
119: if (file != null) {
120: _inputStream = new FileInputStream(file);
121: setReader(new InputStreamReader(_inputStream));
122: }
123: }
124:
125: /**
126: * This Constructor takes an {@link java.lang.String} as a file path to create
127: * a {@link java.io.Reader} from. When using this constructor, the method
128: * {@link #close} should be called after tokenizing has been finished.
129: *<br>
130: * The method accepts <code>null</code> leading to an end-of-file condition
131: * in the first call to {@link #read}.
132: *
133: * @param path a file path or <code>null</code>
134: */
135: public ReaderSource(String path) throws IOException {
136: if (path != null) {
137: _inputStream = new FileInputStream(path);
138: setReader(new InputStreamReader(_inputStream));
139: }
140: }
141:
142: //---------------------------------------------------------------------------
143: // Methods of the TokenizerSource interface
144: //
145:
146: /**
147: * The method calls the {@link java.io.Reader#read(char[], int, int)} method of
148: * the currently backing {@link java.io.Reader}. If no <code>Reader is set so far,
149: * -1 (end-of-file) is returned.
150: *
151: * @param cbuf buffer to receive data
152: * @param offset position from where the data should be inserted in <CODE>cbuf</CODE>
153: * @param maxChars maximum number of characters to be read into <CODE>cbuf</CODE>
154: * @return actually read characters or -1 on an end-of-file condition
155: * @throws Exception anything that could happen during read, most likely {@link java.io.IOException}
156: */
157: public int read(char[] cbuf, int offset, int maxChars)
158: throws Exception {
159: if (_reader != null) {
160: return _reader.read(cbuf, offset, maxChars);
161: } else {
162: return -1;
163: }
164: }
165:
166: //---------------------------------------------------------------------------
167: // Implementation
168: //
169:
170: /**
171: * This method can be called to close streams (either {@link java.io.Reader}
172: * or {@link java.io.InputStream} passed to the constructors or implicitely
173: * created when this <code>ReaderSource</code> is setup.
174: *<br>
175: * It is a shortcut for otherwise nessecary operations that will usually consist
176: * of calling {@link java.io.Reader#close} and {@link java.io.InputStream#close}
177: * probably combined with an exception handling to catch {@link java.io.IOException}.
178: */
179: public void close() {
180: if (_reader != null) {
181: try {
182: _reader.close();
183: } catch (IOException ex) {
184: }
185: }
186: if (_inputStream != null) {
187: try {
188: _inputStream.close();
189: } catch (IOException ex) {
190: }
191: }
192: }
193:
194: /**
195: * Setting the backing {@link java.io.Reader} instance. <code>null</code> is a
196: * valid value. The {@link #read} method will return no data (end-of-file) in
197: * that case.
198: *
199: * @param reader the backing {@link java.io.Reader}
200: * @see #read
201: * @see #getReader
202: */
203: public void setReader(Reader reader) {
204: _reader = reader;
205: }
206:
207: /**
208: * Retrieving the current {@link java.io.Reader}. The method may return <code>null</code>
209: * if a {@link #setReader} with null has occured before.
210: *
211: * @return the current {@link java.io.Reader} or <code>null</code>
212: * @see #setReader
213: */
214: public Reader getReader() {
215: return _reader;
216: }
217:
218: /**
219: * Release ressources
220: */
221: protected void finalize() {
222: close();
223: }
224:
225: //---------------------------------------------------------------------------
226: // Members
227: //
228: private Reader _reader = null;
229: private InputStream _inputStream = null;
230: }
|