001/* 002 * Copyright (c) 1998-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.ROADnet; 031 032import java.io.BufferedReader; 033import java.io.File; 034import java.util.StringTokenizer; 035import java.util.Vector; 036 037import org.ROADnet.qaqc.DataQAQC.Range; 038import org.ROADnet.qaqc.DataQAQC.RangeList; 039import org.ROADnet.qaqc.DataQAQC.ReadConfig; 040import org.ROADnet.qaqc.DataQAQC.RecordDef; 041 042import ptolemy.actor.TypedAtomicActor; 043import ptolemy.actor.TypedIOPort; 044import ptolemy.data.DoubleToken; 045import ptolemy.data.StringToken; 046import ptolemy.data.expr.FileParameter; 047import ptolemy.data.expr.StringParameter; 048import ptolemy.data.type.BaseType; 049import ptolemy.gui.GraphicalMessageHandler; 050import ptolemy.kernel.CompositeEntity; 051import ptolemy.kernel.util.Attribute; 052import ptolemy.kernel.util.IllegalActionException; 053import ptolemy.kernel.util.NameDuplicationException; 054 055////////////////////////////////////////////////////////////////////////// 056////QAQC 057/** 058 * Produce an output token on each firing with a value that is equal to a QAQC 059 * checked version of the input. 060 * 061 * @author Brandon Smith and Efrat Jaeger 062 * @version $Id: QAQC.java 24234 2010-05-06 05:21:26Z welker $ 063 * @since Ptolemy II 4.0.1 064 */ 065 066public class QAQC extends TypedAtomicActor { 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 QAQC(CompositeEntity container, String name) 082 throws NameDuplicationException, IllegalActionException { 083 super(container, name); 084 085 input = new TypedIOPort(this, "input", true, false); 086 new Attribute(input, "_showName"); 087 088 originalValue = new TypedIOPort(this, "originalValue", false, true); 089 originalValue.setTypeEquals(BaseType.DOUBLE); 090 new Attribute(originalValue, "_showName"); 091 modifiedValue = new TypedIOPort(this, "modifiedValue", false, true); 092 modifiedValue.setTypeEquals(BaseType.DOUBLE); 093 new Attribute(modifiedValue, "_showName"); 094 config = new FileParameter(this, "configuration file"); 095 checks = new StringParameter(this, "attribute"); 096 checks.setTypeEquals(BaseType.STRING); 097 098 _attachText("_iconDescription", "<svg>\n" 099 + "<polygon points=\"-30,-10 -30,10 -10,10 -10,30 10,30 10,10" 100 + " 30,10 30,-10 10,-10 10,-30 -10,-30 -10,-10\" " 101 + "style=\"fill:red\"/>\n" + "</svg>\n"); 102 } 103 104 // ///////////////////////////////////////////////////////////////// 105 // // ports and parameters //// 106 107 /** 108 * The input port. This base class imposes no type constraints except that 109 * the type of the input cannot be greater than the type of the output. 110 */ 111 public TypedIOPort input; 112 113 /** 114 * The output port. By default, the type of this output is constrained to be 115 * at least that of the input. 116 */ 117 public TypedIOPort modifiedValue; 118 119 // TODO: make it configurable.. 120 /** 121 * The output port. By default, the type of this output is constrained to be 122 * at least that of the input. 123 */ 124 public TypedIOPort originalValue; 125 126 /** 127 * The config file. This parameter is the location of the config file as a 128 * String 129 */ 130 public FileParameter config; 131 132 /** 133 * The checks String. This parameter contains the columns to check as a 134 * String 135 */ 136 public StringParameter checks; 137 138 // ///////////////////////////////////////////////////////////////// 139 // // public methods //// 140 141 /** 142 * Callback for changes in attribute values Get the attributes from the 143 * config file. 144 * 145 * @param a 146 * The attribute that changed. 147 * @exception IllegalActionException 148 */ 149 public void attributeChanged(Attribute at) throws IllegalActionException { 150 if (at == config) { 151 if (!config.getExpression().equals(_prevConfig)) { // If the value 152 // has really 153 // changed. 154 155 _prevConfig = config.getExpression(); 156 checks.removeAllChoices(); 157 try { 158 BufferedReader reader = config.openForReading(); 159 reader.readLine(); 160 String line = ""; 161 while ((line = reader.readLine()) != null) { 162 if (!line.equals("")) { 163 int space = line.indexOf(" "); 164 if (space != -1) { 165 checks.addChoice(line.substring(0, space)); 166 } else 167 checks.addChoice(line); 168 } 169 } 170 boolean inChoices = false; 171 String[] choices = checks.getChoices(); 172 for (int i = 0; i < choices.length; i++) { 173 if (checks.getExpression().equals(choices[i])) { 174 inChoices = true; 175 break; 176 } 177 } 178 if (!inChoices) 179 checks.setExpression(""); 180 reader.close(); 181 } catch (Exception ex) { 182 _debug("<EXCEPTION> There was an error while parsing the config file. " 183 + ex + ". </EXCEPTION>"); 184 GraphicalMessageHandler 185 .message(ex.getMessage() 186 + "There was an error while parsing the config file" 187 + config.getExpression() + "in the actor: " 188 + this.getName()); 189 } 190 191 } else { 192 _debug("The config file" + _prevConfig + " hasn't changed."); 193 } 194 } else { 195 super.attributeChanged(at); 196 } 197 } 198 199 /** 200 * Compute the product of the input and the <i>factor</i>. If there is no 201 * input, then produce no output. 202 * 203 * @exception IllegalActionException 204 * If there is no director. 205 */ 206 public void fire() throws IllegalActionException { 207 if (input.hasToken(0)) { 208 209 // TODO: remote files.. 210 File config_file = config.asFile(); 211 String line = ((StringToken) input.get(0)).stringValue(); 212 String current_col = ((StringToken) checks.getToken()) 213 .stringValue(); 214 if (current_col.equals("")) { 215 throw new IllegalActionException(this, 216 "Please select an attribute for actor " 217 + this.getName() + "."); 218 } 219 220 // parse the CSV line into Vector data_list 221 Vector data_list = new Vector(); 222 StringTokenizer st = new StringTokenizer(line); 223 // don't need if 1 rec type: st.nextToken(","); // skip the first 224 // token = record id 225 while (st.hasMoreTokens()) 226 data_list.add(st.nextToken(",")); 227 228 // make call to read config info from file 229 ReadConfig rc = new ReadConfig(config_file.getAbsolutePath()); 230 231 // only one type of record, so set the config as the single 232 // RecordDef 233 RecordDef config = (RecordDef) rc.getConfig().firstElement(); 234 235 // check the value equal to the current_col 236 int index = ((Vector) config.getTypes()).indexOf(current_col); 237 238 // get the value to check (as a double) 239 double value = Double.parseDouble((String) data_list 240 .elementAt(index)); 241 originalValue.broadcast(new DoubleToken(value)); 242 243 // get the range values, can have a set/list of ranges, but only 1 244 // now 245 RangeList list = (RangeList) ((Vector) config.getRanges()) 246 .elementAt(index); 247 double high = ((Range) list.getRangeAt(0)).getHigh(); 248 double low = ((Range) list.getRangeAt(0)).getLow(); 249 250 // do checks, replace value by min if too low or max if too high 251 // System.err.println(low + "<" + value + "<" + high); 252 // check if too low 253 if (value < low) { 254 Double l = new Double(low); 255 data_list.setElementAt(l.toString(), index); 256 } 257 // check if too high 258 if (value > high) { 259 Double h = new Double(high); 260 data_list.setElementAt(h.toString(), index); 261 } 262 double modValue = Double.parseDouble((String) data_list 263 .elementAt(index)); 264 265 modifiedValue.broadcast(new DoubleToken(modValue)); 266 } 267 268 } 269 270 /** 271 * Post fire the actor. Return false to indicate that the process has 272 * finished. If it returns true, the process will continue indefinitely. 273 */ 274 public boolean postfire() throws IllegalActionException { 275 return super.postfire(); 276 } 277 278 // ///////////////////////////////////////////////////////////////// 279 // // private members //// 280 281 /** Previous value of configuration file. */ 282 String _prevConfig = ""; 283}