001/* Abstract base class for actors that read in data from a URL
002
003 @Copyright (c) 1998-2015 The Regents of the University of California.
004 All rights reserved.
005
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the
009 above copyright notice and the following two paragraphs appear in all
010 copies of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION 2
026 COPYRIGHTENDKEY
027 */
028package ptolemy.actor.lib;
029
030import java.io.BufferedReader;
031import java.io.IOException;
032import java.io.InputStreamReader;
033import java.net.URL;
034
035import ptolemy.data.BooleanToken;
036import ptolemy.data.StringToken;
037import ptolemy.data.expr.Parameter;
038import ptolemy.data.type.BaseType;
039import ptolemy.kernel.CompositeEntity;
040import ptolemy.kernel.util.Attribute;
041import ptolemy.kernel.util.IllegalActionException;
042import ptolemy.kernel.util.NameDuplicationException;
043
044///////////////////////////////////////////////////////////////////
045//// URLReader
046
047/**
048 This actor reads tokens from an URL, and output them. Each entry in
049 the file corresponds to one iteration. If there are multiple fires in
050 the iteration, the same token will be repeated.  This actor has a
051 multiport, where each port corresponds to one column in the data file.
052
053 <p> The file format at the URL is assumed as the following.  A newline
054 character separates the rows, and a tab or a space character separates
055 the columns.
056
057 <p> The <i>sourceURL</i> parameter should be set to the name of the
058 file, specified as a fully qualified URL.  If the <i>sourceURL</i>
059 parameter is an empty string, then the System.in is used for input.
060
061 It is possible to load a file from the local file system by using the
062 prefix "file://" instead of "http://". Relative file paths are
063 allowed. To specify a file relative to the current directory, use
064 "../" or "./". For example, if the current directory contains a file
065 called "test.txt", then <i>sourceURL</i> should be set to
066 "file:./test.txt". If the parent directory contains a file called
067 "test.txt", then <i>sourceURL</i> should be set to
068 "file:../test.txt". To reference the file test.txt, located at
069 "/tmp/test.txt", <i>sourceURL</i> should be set to
070 "file:///tmp/test.txt" The default value is "file:///tmp/test.txt".
071
072 <p>FIXME: The type of the output ports is set to Double for now.
073 It should read a line in the prefire() and refer the type
074 from there.
075 <p>FIXME: URLReader should read in expressions and serialized tokens
076
077 @see ptolemy.actor.lib.javasound.AudioReader
078 @author  Jie Liu
079 @version $Id$
080 @since Ptolemy II 2.0
081 @Pt.ProposedRating Red (liuj)
082 @Pt.AcceptedRating Red (liuj)
083 */
084public abstract class URLReader extends Source {
085    /** Construct an actor with the given container and name.
086     *  @param container The container.
087     *  @param name The name of this actor.
088     *  @exception IllegalActionException If the actor cannot be contained
089     *   by the proposed container.
090     *  @exception NameDuplicationException If the container already has an
091     *   actor with this name.
092     */
093    public URLReader(CompositeEntity container, String name)
094            throws IllegalActionException, NameDuplicationException {
095        super(container, name);
096
097        // Set the type of the output port.
098        output.setMultiport(true);
099        output.setTypeEquals(BaseType.DOUBLE);
100
101        sourceURL = new Parameter(this, "sourceURL", new StringToken(""));
102        sourceURL.setTypeEquals(BaseType.STRING);
103
104        refresh = new Parameter(this, "refresh", new BooleanToken(false));
105        refresh.setTypeEquals(BaseType.BOOLEAN);
106
107        if (_stdIn == null) {
108            _stdIn = new BufferedReader(new InputStreamReader(System.in,
109                    java.nio.charset.Charset.defaultCharset()));
110        }
111
112        _setURLReader(_stdIn);
113    }
114
115    ///////////////////////////////////////////////////////////////////
116    ////                     ports and parameters                  ////
117
118    /** The URL of the file to read from. This parameter contains
119     *  a StringToken.  By default, it contains an empty string, which
120     *  is interpreted to mean that input should be directed to the
121     *  standard input.
122     *  FIXME: Should this bring up a dialog box to type (or select) a URL?
123     */
124    public Parameter sourceURL;
125
126    /** The flag that indicates whether to refresh between each reading.
127     *  This is a boolean, and defaults to false.
128     */
129    public Parameter refresh;
130
131    ///////////////////////////////////////////////////////////////////
132    ////                         public methods                    ////
133
134    /** If the specified attribute is <i>URL</i>, then close
135     *  the current file (if there is one) and open the new one.
136     *  @param attribute The attribute that has changed.
137     *  @exception IllegalActionException If the specified attribute
138     *   is <i>URL</i> and the file cannot be opened.
139     */
140    @Override
141    public void attributeChanged(Attribute attribute)
142            throws IllegalActionException {
143        if (attribute == sourceURL) {
144            StringToken urlToken = null;
145
146            try {
147                urlToken = (StringToken) sourceURL.getToken();
148
149                if (urlToken == null) {
150                    _source = null;
151                    _setURLReader(null);
152                } else {
153                    _source = urlToken.stringValue();
154
155                    if (_source.equals("")) {
156                        _setURLReader(null);
157                    } else {
158                        URL url = new URL(_source);
159                        java.io.BufferedReader reader = new BufferedReader(
160                                new InputStreamReader(url.openStream()));
161                        _setURLReader(reader);
162                    }
163                }
164            } catch (IOException ex) {
165                throw new IllegalActionException(this, ex,
166                        "Failed to evaluate sourceURL '" + urlToken + "'");
167            }
168        } else if (attribute == refresh) {
169            _refreshFlag = ((BooleanToken) refresh.getToken()).booleanValue();
170        }
171
172        super.attributeChanged(attribute);
173    }
174
175    /** Open the file at the URL, and set the width of the output.
176     *  @exception IllegalActionException Not thrown in this base class
177     */
178    @Override
179    public void initialize() throws IllegalActionException {
180        super.initialize();
181        attributeChanged(sourceURL);
182    }
183
184    /** Close the reader if there is one.
185     *  @exception IllegalActionException If an IO error occurs.
186     */
187    @Override
188    public void wrapup() throws IllegalActionException {
189        try {
190            if (_reader != null && _reader != _stdIn) {
191                _reader.close();
192            }
193        } catch (IOException ex) {
194            throw new IllegalActionException(this, ex, "Failed to close");
195        }
196    }
197
198    ///////////////////////////////////////////////////////////////////
199    ////                         protected methods                /////
200
201    /** Set the reader.  If there was a previous reader, close it.
202     *  To set standard input, call this method with argument null.
203     *  @param reader The reader to read to.
204     *  @exception IllegalActionException If an IO error occurs.
205     */
206    protected void _setURLReader(java.io.BufferedReader reader)
207            throws IllegalActionException {
208        try {
209            if (_reader != null && _reader != _stdIn) {
210                _reader.close();
211            }
212        } catch (IOException ex) {
213            throw new IllegalActionException(this, ex, "Failed to close");
214        }
215
216        if (reader != null) {
217            _reader = reader;
218        } else {
219            _reader = _stdIn;
220        }
221    }
222
223    ///////////////////////////////////////////////////////////////////
224    ////                         protected members                 ////
225
226    /** The reader to read from. */
227    protected java.io.BufferedReader _reader = null;
228
229    /** Standard in as a reader. */
230    protected static java.io.BufferedReader _stdIn = null;
231
232    /** String for the URL. */
233    protected String _source;
234
235    /** Flag to indicate whether or not to refresh the data
236     *  between readings.
237     */
238    protected boolean _refreshFlag;
239}