001/* A publisher that transparently tunnels messages to subscribers and saves its output for testing 002 003 Copyright (c) 2007-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 027 */ 028package ptolemy.actor.lib; 029 030import java.util.ArrayList; 031 032import ptolemy.data.ArrayToken; 033import ptolemy.data.BooleanToken; 034import ptolemy.data.RecordToken; 035import ptolemy.data.Token; 036import ptolemy.kernel.CompositeEntity; 037import ptolemy.kernel.util.IllegalActionException; 038import ptolemy.kernel.util.NameDuplicationException; 039 040////////////////////////////////////////////////////////////////////////// 041//// PublisherTest 042 043/** 044 This actor publishes input tokens on a named channel and compares 045 the inputs against the value specified by the <i>correctValues</i> parameter. 046 047 <p>This actor combines the {@link ptolemy.actor.lib.Publisher} actor 048 and the {@link ptolemy.actor.lib.Test} actor. Thus, it has quite 049 a bit of duplicated code from the Test actor. 050 051 @author Christopher Brooks, based on Test, which has Edward A. Lee and Jim Armstrong as authors 052 @version $Id$ 053 @since Ptolemy II 6.1 054 @Pt.ProposedRating Red (cxh) 055 @Pt.AcceptedRating Red (cxh) 056 */ 057public class PublisherTest extends PublisherNonStrictTest { 058 059 /** Construct a publisher with the specified container and name. 060 * @param container The container actor. 061 * @param name The name of the actor. 062 * @exception IllegalActionException If the actor is not of an acceptable 063 * class for the container. 064 * @exception NameDuplicationException If the name coincides with 065 * an actor already in the container. 066 */ 067 public PublisherTest(CompositeEntity container, String name) 068 throws IllegalActionException, NameDuplicationException { 069 super(container, name); 070 071 // Note that the parent class (PublisherNonStrictTest) does 072 // not have a multiport input port. 073 input.setMultiport(true); 074 } 075 076 /** Read at most one input token from each 077 * input channel and send it to the subscribers, 078 * if any. 079 * Read one token from each input channel and compare against 080 * the value specified in <i>correctValues</i>. If the value 081 * matches, then output false (to indicate that the test is not 082 * complete yet) and return. Otherwise, throw an exception. 083 * If the iteration count is larger than the length of 084 * <i>correctValues</i>, then output <i>true</i> and return, 085 * indicating that the test is complete, i.e. that all 086 * values in <i>correctValues</i> have been matched. 087 * @exception IllegalActionException If there is no director. 088 */ 089 @Override 090 public void fire() throws IllegalActionException { 091 super.fire(); 092 int width = input.getWidth(); 093 094 // If we are in training mode, read the inputs and add to the 095 // training data. 096 boolean training = ((BooleanToken) trainingMode.getToken()) 097 .booleanValue(); 098 099 if (training) { 100 if (_trainingTokens == null) { 101 _trainingTokens = new ArrayList(); 102 } 103 104 if (_debugging) { 105 _debug("PublisherTest: width: " + width + " " 106 + input.hasToken(0)); 107 } 108 if (width == 1) { 109 if (input.hasToken(0)) { 110 Token token = input.get(0); 111 output.send(0, token); 112 if (token instanceof ArrayToken) { 113 Token[] innerArrayToken = new Token[1]; 114 innerArrayToken[0] = token; 115 _trainingTokens.add(innerArrayToken); 116 } else { 117 _trainingTokens.add(token); 118 } 119 } 120 } else { 121 ArrayList arrayList = new ArrayList(); 122 123 for (int i = 0; i < width; i++) { 124 if (input.hasToken(i)) { 125 Token token = input.get(i); 126 arrayList.add(token); 127 output.send(i, token); 128 } 129 } 130 131 _trainingTokens.add(arrayList); 132 } 133 134 return; 135 } 136 137 if (_numberOfInputTokensSeen >= ((ArrayToken) correctValues.getToken()) 138 .length()) { 139 // Consume and discard input values. We are beyond the end 140 // of the correctValues array. 141 for (int i = 0; i < width; i++) { 142 if (input.hasToken(i)) { 143 Token token = input.get(i); 144 output.send(i, token); 145 } 146 } 147 148 // Indicate that the test has passed. 149 output.send(0, new BooleanToken(true)); 150 return; 151 } 152 153 Token referenceToken = ((ArrayToken) correctValues.getToken()) 154 .getElement(_numberOfInputTokensSeen); 155 Token[] reference; 156 157 if (width == 1 && !(referenceToken instanceof ArrayToken)) { 158 reference = new Token[1]; 159 reference[0] = referenceToken; 160 } else { 161 try { 162 reference = ((ArrayToken) referenceToken).arrayValue(); 163 } catch (ClassCastException ex) { 164 throw new IllegalActionException(this, 165 "Test fails in iteration " + _numberOfInputTokensSeen 166 + ".\n" + "Width of input is " + width 167 + ", but correctValues parameter " 168 + "is not an array " + "of arrays."); 169 } 170 171 if (width != reference.length) { 172 throw new IllegalActionException(this, 173 "Test fails in iteration " + _numberOfInputTokensSeen 174 + ".\n" + "Width of input is " + width 175 + ", which does not match " 176 + "the width of the " 177 + _numberOfInputTokensSeen + "-th element of" 178 + " correctValues, " + reference.length); 179 } 180 } 181 182 for (int i = 0; i < width; i++) { 183 if (!input.hasToken(i)) { 184 throw new IllegalActionException(this, 185 "Test fails in iteration " + _numberOfInputTokensSeen 186 + ".\n" + "Empty input on channel " + i); 187 } 188 189 Token token = input.get(i); 190 191 boolean isClose; 192 193 try { 194 isClose = token.isCloseTo(reference[i], _tolerance) 195 .booleanValue() 196 || token.isNil() && reference[i].isNil(); 197 // Additional guards makes things slightly easier for 198 // Copernicus. 199 if (token instanceof ArrayToken 200 && reference[i] instanceof ArrayToken) { 201 isClose |= NonStrictTest._isCloseToIfNilArrayElement(token, 202 reference[i], _tolerance); 203 } 204 if (token instanceof RecordToken 205 && reference[i] instanceof RecordToken) { 206 isClose |= NonStrictTest._isCloseToIfNilRecordElement(token, 207 reference[i], _tolerance); 208 } 209 210 } catch (IllegalActionException ex) { 211 // Chain the exceptions together so we know which test 212 // actor failed if there was more than one... 213 throw new IllegalActionException(this, ex, 214 "Test fails in iteration " + _numberOfInputTokensSeen 215 + ".\n" + "Value was: " + token 216 + ". Should have been: " + reference[i]); 217 } 218 219 if (!isClose) { 220 throw new IllegalActionException(this, 221 "Test fails in iteration " + _numberOfInputTokensSeen 222 + ".\n" + "Value was: " + token 223 + ". Should have been: " + reference[i]); 224 } 225 output.send(i, token); 226 } 227 228 _numberOfInputTokensSeen++; 229 } 230 231 /** Override the base class to do nothing and return true. 232 * @return True. 233 */ 234 @Override 235 public boolean postfire() { 236 return true; 237 } 238}