001/* 002 * Copyright (c) 2002-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: welker $' 006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 007 * '$Revision: 24234 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.geon; 031 032import java.io.File; 033import java.io.FileOutputStream; 034 035import ptolemy.actor.TypedIOPort; 036import ptolemy.actor.lib.Sink; 037import ptolemy.data.ArrayToken; 038import ptolemy.data.BooleanToken; 039import ptolemy.data.StringToken; 040import ptolemy.data.Token; 041import ptolemy.data.UnsignedByteToken; 042import ptolemy.data.expr.FileParameter; 043import ptolemy.data.expr.Parameter; 044import ptolemy.data.type.ArrayType; 045import ptolemy.data.type.BaseType; 046import ptolemy.kernel.CompositeEntity; 047import ptolemy.kernel.util.Attribute; 048import ptolemy.kernel.util.IllegalActionException; 049import ptolemy.kernel.util.NameDuplicationException; 050import ptolemy.kernel.util.Workspace; 051import ptolemy.util.MessageHandler; 052 053////////////////////////////////////////////////////////////////////////// 054//// BinaryFileWriter 055/** 056 * This actor receives an array of bytes as an input and writes it to a file. At 057 * each iteration a bytes array is read from the input port and written to a 058 * specified file. 059 * 060 * @UserLevelDocumentation This actor writes streams of bytes array to a file 061 * specified by filename and outputs the filePath. 062 * @author Efrat Jaeger 063 * @version $Id: BinaryFileWriter.java 24234 2010-05-06 05:21:26Z welker $ 064 * @since Ptolemy II 3.0.2 065 */ 066public class BinaryFileWriter extends Sink { 067 068 /** 069 * Construct an actor with the given container and name. 070 * 071 * @param container 072 * The container. 073 * @param name 074 * The name of this actor. 075 * @exception IllegalActionException 076 * If the actor cannot be contained by the proposed 077 * container. 078 * @exception NameDuplicationException 079 * If the container already has an actor with this name. 080 */ 081 public BinaryFileWriter(CompositeEntity container, String name) 082 throws IllegalActionException, NameDuplicationException { 083 super(container, name); 084 085 input.setTypeEquals(new ArrayType(BaseType.UNSIGNED_BYTE)); 086 087 filePath = new TypedIOPort(this, "filePath", false, true); 088 filePath.setTypeEquals(BaseType.STRING); 089 090 fileName = new FileParameter(this, "fileName"); 091 fileName.setExpression("System.out"); 092 093 append = new Parameter(this, "append"); 094 append.setTypeEquals(BaseType.BOOLEAN); 095 append.setToken(BooleanToken.FALSE); 096 097 confirmOverwrite = new Parameter(this, "confirmOverwrite"); 098 confirmOverwrite.setTypeEquals(BaseType.BOOLEAN); 099 confirmOverwrite.setToken(BooleanToken.TRUE); 100 101 _attachText("_iconDescription", "<svg>\n" 102 + "<rect x=\"-25\" y=\"-20\" " + "width=\"50\" height=\"40\" " 103 + "style=\"fill:white\"/>\n" 104 + "<polygon points=\"-15,-10 -12,-10 -8,-14 -1,-14 3,-10" 105 + " 15,-10 15,10, -15,10\" " + "style=\"fill:red\"/>\n" 106 + "</svg>\n"); 107 } 108 109 // ///////////////////////////////////////////////////////////////// 110 // // ports and parameters //// 111 112 /** 113 * output the file URL for display purposes. 114 * 115 * @UserLevelDocumentation Outputs the path to the written file. 116 */ 117 public TypedIOPort filePath; 118 119 /** 120 * If true, then append to the specified file. If false (the default), then 121 * overwrite any preexisting file after asking the user for permission. 122 * 123 * @UserLevelDocumentation If true, then append to the specified file. If 124 * false (the default), then overwrite any 125 * preexisting file after asking the user for 126 * permission. 127 */ 128 public Parameter append; 129 130 /** 131 * The file name to which to write. This is a string with any form accepted 132 * by FileParameter. The default value is "System.out". 133 * 134 * @see FileParameter 135 * @UserLevelDocumentation Path to the file to be written. 136 */ 137 public FileParameter fileName; 138 139 /** 140 * If false, then overwrite the specified file if it exists without asking. 141 * If true (the default), then if the file exists, ask for confirmation 142 * before overwriting. 143 * 144 * @UserLevelDocumentation If false, then overwrite the specified file if it 145 * exists without asking. If true (the default), 146 * then if the file exists, ask for confirmation 147 * before overwriting. 148 */ 149 public Parameter confirmOverwrite; 150 151 // ///////////////////////////////////////////////////////////////// 152 // // public methods //// 153 154 /** 155 * If the specified attribute is <i>fileName</i> and there is an open file 156 * being written, then close that file. The new file will be opened or 157 * created when it is next written to. 158 * 159 * @param attribute 160 * The attribute that has changed. 161 * @exception IllegalActionException 162 * If the specified attribute is <i>fileName</i> and the 163 * previously opened file cannot be closed. 164 */ 165 public void attributeChanged(Attribute attribute) 166 throws IllegalActionException { 167 if (attribute == fileName) { 168 // Do not close the file if it is the same file. 169 String newFileName = ((StringToken) fileName.getToken()) 170 .stringValue(); 171 // calling getToken forces an evaluation of the expression 172 // System.out.println("newFileName:"+newFileName); 173 if (_previousFileName != null 174 && !newFileName.equals(_previousFileName)) { 175 _previousFileName = newFileName; 176 fileName.close(); 177 _writer = null; 178 } 179 } else { 180 super.attributeChanged(attribute); 181 } 182 } 183 184 /** 185 * Clone the actor into the specified workspace. 186 * 187 * @return A new actor. 188 * @exception CloneNotSupportedException 189 * If a derived class contains an attribute that cannot be 190 * cloned. 191 */ 192 public Object clone(Workspace workspace) throws CloneNotSupportedException { 193 BinaryFileWriter newObject = (BinaryFileWriter) super.clone(workspace); 194 newObject._writer = null; 195 return newObject; 196 } 197 198 /** 199 * Writes the input content to the file. At the first iteration opens the 200 * file for writing. 201 * 202 */ 203 public boolean postfire() throws IllegalActionException { 204 if (input.hasToken(0)) { 205 Token token = input.get(0); 206 if (_writer == null) { 207 // Open the file. 208 File file = fileName.asFile(); 209 boolean appendValue = ((BooleanToken) append.getToken()) 210 .booleanValue(); 211 boolean confirmOverwriteValue = ((BooleanToken) confirmOverwrite 212 .getToken()).booleanValue(); 213 // Don't ask for confirmation in append mode, since there 214 // will be no loss of data. 215 if (file.exists() && !appendValue && confirmOverwriteValue) { 216 // Query for overwrite. 217 if (!MessageHandler.yesNoQuestion("OK to overwrite " + file 218 + "?")) { 219 throw new IllegalActionException(this, 220 "Please select another file name."); 221 } 222 } 223 try { 224 _writer = new FileOutputStream(file); 225 } catch (Exception ex) { 226 System.out.println("Error opening stream"); 227 } 228 } 229 _writeToken(token); 230 // String _fileName = 231 // java.net.URLDecoder.decode(fileName.getExpression()); 232 // above line replaced so that expressions used in fileName will be 233 // evaluated 234 filePath.broadcast(new StringToken(((StringToken) fileName 235 .getToken()).stringValue())); 236 } 237 return super.postfire(); 238 } 239 240 /** 241 * Close the writer if there is one. 242 * 243 * @exception IllegalActionException 244 * If an IO error occurs. 245 */ 246 public void wrapup() throws IllegalActionException { 247 try { 248 _writer.close(); 249 } catch (Exception ex) { 250 System.out.println("Error closing stream"); 251 } 252 253 _writer = null; 254 } 255 256 // ///////////////////////////////////////////////////////////////// 257 // // protected methods //// 258 259 private void _writeToken(Token token) { 260 ArrayToken dataArrayToken = (ArrayToken) token; 261 byte[] dataBytes = new byte[dataArrayToken.length()]; 262 for (int j = 0; j < dataArrayToken.length(); j++) { 263 UnsignedByteToken dataToken = (UnsignedByteToken) dataArrayToken 264 .getElement(j); 265 dataBytes[j] = (byte) dataToken.byteValue(); 266 } 267 try { 268 _writer.write(dataBytes); 269 } catch (Exception ex) { 270 System.out.println("Error writing to stream"); 271 } 272 273 } 274 275 // ///////////////////////////////////////////////////////////////// 276 // // protected members //// 277 278 /** The current writer. */ 279 private FileOutputStream _writer; 280 281 // ///////////////////////////////////////////////////////////////// 282 // // private members //// 283 284 /** Previous value of fileName parameter. */ 285 private String _previousFileName; 286 287}