001/* A representative of a file that contains one or more tokens. 002 003 Copyright (c) 1998-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 */ 027package ptolemy.actor.gui; 028 029import java.io.File; 030import java.io.FileWriter; 031import java.io.IOException; 032import java.io.InputStreamReader; 033import java.io.LineNumberReader; 034import java.io.OutputStreamWriter; 035import java.io.PrintWriter; 036import java.io.Writer; 037import java.net.URL; 038import java.util.ArrayList; 039import java.util.Iterator; 040import java.util.List; 041 042import ptolemy.data.Token; 043import ptolemy.data.expr.Variable; 044import ptolemy.kernel.CompositeEntity; 045import ptolemy.kernel.util.Attribute; 046import ptolemy.kernel.util.IllegalActionException; 047import ptolemy.kernel.util.KernelException; 048import ptolemy.kernel.util.NameDuplicationException; 049import ptolemy.kernel.util.Workspace; 050 051/////////////////////////////////////////////////////////////////// 052//// TokenEffigy 053 054/** 055 An effigy for a file that contains one or more tokens, one per line, 056 represented as text in the expression language. 057 058 @author Edward A. Lee 059 @version $Id$ 060 @since Ptolemy II 2.1 061 @Pt.ProposedRating Red (neuendor) 062 @Pt.AcceptedRating Red (neuendor) 063 */ 064public class TokenEffigy extends Effigy { 065 /** Create a new effigy in the specified workspace with an empty string 066 * for its name. 067 * @param workspace The workspace for this effigy. 068 */ 069 public TokenEffigy(Workspace workspace) { 070 super(workspace); 071 } 072 073 /** Create a new effigy in the given directory with the given name. 074 * @param container The directory that contains this effigy. 075 * @param name The name of this effigy. 076 * @exception IllegalActionException If the entity cannot be contained 077 * by the proposed container. 078 * @exception NameDuplicationException If the name coincides with 079 * an entity already in the container. 080 */ 081 public TokenEffigy(CompositeEntity container, String name) 082 throws IllegalActionException, NameDuplicationException { 083 super(container, name); 084 } 085 086 /////////////////////////////////////////////////////////////////// 087 //// public methods //// 088 089 /** Append the specified token to the token array associated with this 090 * effigy. 091 * @param token The token to append. 092 * @exception IllegalActionException If the token is not acceptable. 093 */ 094 public void append(Token token) throws IllegalActionException { 095 _tokens.add(token); 096 097 // Notify the contained tableaux. 098 Iterator tableaux = entityList(TokenTableau.class).iterator(); 099 100 while (tableaux.hasNext()) { 101 TokenTableau tableau = (TokenTableau) tableaux.next(); 102 tableau.append(token); 103 } 104 } 105 106 /** If the argument is the <i>uri</i> parameter, then read the 107 * specified URL and parse the data contained in it. 108 * @param attribute The attribute that changed. 109 * @exception IllegalActionException If the URL cannot be read or 110 * if the data is malformed. 111 */ 112 @Override 113 public void attributeChanged(Attribute attribute) 114 throws IllegalActionException { 115 // The superclass does some handling of the url attribute. 116 super.attributeChanged(attribute); 117 118 if (attribute == uri) { 119 try { 120 URL urlToRead = uri.getURL(); 121 122 if (urlToRead != null) { 123 read(urlToRead); 124 } 125 } catch (IOException ex) { 126 throw new IllegalActionException(this, null, ex, 127 "Failed to read data: " + ex.getMessage()); 128 } 129 } 130 } 131 132 /** Clear the token array associated with this effigy. 133 */ 134 public void clear() { 135 _tokens.clear(); 136 137 // Notify the contained tableaux. 138 Iterator tableaux = entityList(TokenTableau.class).iterator(); 139 140 while (tableaux.hasNext()) { 141 TokenTableau tableau = (TokenTableau) tableaux.next(); 142 tableau.clear(); 143 } 144 } 145 146 /** Return an array of the tokens in the file. 147 * @return An array of tokens in the file. 148 * @see #setTokens(List) 149 */ 150 public ArrayList getTokens() { 151 return _tokens; 152 } 153 154 /** Read the specified URL and parse the data. 155 * @param input The URL to read. 156 * @exception IOException If an error occurs while reading the URL 157 * or parsing the data. 158 */ 159 public void read(URL input) throws IOException { 160 if (input == null) { 161 throw new IOException("Attempt to read from null input."); 162 } 163 164 LineNumberReader reader = null; 165 166 try { 167 reader = new LineNumberReader( 168 new InputStreamReader(input.openStream())); 169 170 while (true) { 171 // NOTE: The following tolerates all major line terminators. 172 String line = reader.readLine(); 173 174 if (line == null) { 175 break; 176 } 177 178 try { 179 // Parse the line. 180 if (_variable == null) { 181 _variable = new Variable(workspace()); 182 _variable.setName("Expression evaluator"); 183 } 184 185 _variable.setExpression(line); 186 187 Token token = _variable.getToken(); 188 189 if (token != null) { 190 _tokens.add(token); 191 192 // Notify the contained tableaux. 193 Iterator tableaux = entityList(TokenTableau.class) 194 .iterator(); 195 196 while (tableaux.hasNext()) { 197 ((TokenTableau) tableaux.next()).append(token); 198 } 199 } 200 } catch (KernelException ex) { 201 throw new IOException("Error evaluating data expression: " 202 + ex.getMessage()); 203 } 204 } 205 } finally { 206 if (reader != null) { 207 reader.close(); 208 } 209 } 210 } 211 212 /** Set the token array associated with this effigy. 213 * @param tokens An array of tokens. 214 * @exception IllegalActionException If the tokens are not acceptable. 215 * @see #getTokens() 216 */ 217 public void setTokens(List tokens) throws IllegalActionException { 218 _tokens.clear(); 219 _tokens.addAll(tokens); 220 221 // Notify the contained tableaux. 222 Iterator tableaux = entityList(TokenTableau.class).iterator(); 223 224 while (tableaux.hasNext()) { 225 TokenTableau tableau = (TokenTableau) tableaux.next(); 226 tableau.clear(); 227 tableau.append(tokens); 228 } 229 } 230 231 /** Write the current data of this effigy to the specified file. 232 * This is done by producing one line per token using its toString() 233 * method. 234 * @param file The file to write to, or null to write to standard out. 235 * @exception IOException If the write fails. 236 */ 237 @Override 238 public void writeFile(File file) throws IOException { 239 Writer writer = null; 240 241 if (file == null) { 242 writer = new OutputStreamWriter(System.out); 243 } else { 244 writer = new FileWriter(file); 245 } 246 247 // Use a PrintWriter so that the local platform's notion 248 // of line termination is used, making a more user-friendly output. 249 // Note that the corresponding reader is platform-tolerant. 250 PrintWriter print = new PrintWriter(writer); 251 Iterator tokens = _tokens.iterator(); 252 253 while (tokens.hasNext()) { 254 Token token = (Token) tokens.next(); 255 print.println(token.toString()); 256 } 257 258 print.close(); 259 } 260 261 /////////////////////////////////////////////////////////////////// 262 //// private members //// 263 // The list of tokens read from the file. 264 private ArrayList _tokens = new ArrayList(); 265 266 // The variable used to evaluate the expression. 267 private Variable _variable; 268 269 /////////////////////////////////////////////////////////////////// 270 //// inner classes //// 271 272 /** A factory for creating new effigies. 273 */ 274 public static class Factory extends EffigyFactory { 275 /** Create a factory with the given name and container. 276 * @param container The container. 277 * @param name The name. 278 * @exception IllegalActionException If the container is incompatible 279 * with this entity. 280 * @exception NameDuplicationException If the name coincides with 281 * an entity already in the container. 282 */ 283 public Factory(CompositeEntity container, String name) 284 throws IllegalActionException, NameDuplicationException { 285 super(container, name); 286 } 287 288 /////////////////////////////////////////////////////////////// 289 //// public methods //// 290 291 /** Return false, indicating that this effigy factory is not 292 * capable of creating an effigy without a URL being specified. 293 * @return False. 294 */ 295 @Override 296 public boolean canCreateBlankEffigy() { 297 return false; 298 } 299 300 /** Create a new effigy in the given container by reading the 301 * specified URL. If the specified URL is null, or 302 * if the URL does not end with extension ".ptd" 303 * (for Ptolemy data), then return null. 304 * @param container The container for the effigy. 305 * @param base The base for relative file references, which are 306 * ignored here, and therefore can be null. 307 * @param input The input URL. 308 * @return A new instance of TokenEffigy, or null if the URL 309 * does not have a recognized extension. 310 * @exception Exception If the URL cannot be read. 311 */ 312 @Override 313 public Effigy createEffigy(CompositeEntity container, URL base, 314 URL input) throws Exception { 315 if (input != null) { 316 String extension = getExtension(input); 317 318 if (extension.equals("ptd")) { 319 TokenEffigy effigy = new TokenEffigy(container, 320 container.uniqueName("effigy")); 321 effigy.uri.setURL(input); 322 return effigy; 323 } 324 } 325 326 return null; 327 } 328 } 329}