001/* An output port that publishes its data on a named channel. 002 003 Copyright (c) 1997-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; 028 029import ptolemy.data.IntToken; 030import ptolemy.data.Token; 031import ptolemy.data.expr.Parameter; 032import ptolemy.data.type.BaseType; 033import ptolemy.kernel.ComponentEntity; 034import ptolemy.kernel.util.IllegalActionException; 035import ptolemy.kernel.util.NameDuplicationException; 036import ptolemy.kernel.util.Settable; 037 038/////////////////////////////////////////////////////////////////// 039//// ConstantPublisherPort 040 041/** 042 This is a specialized output port that publishes constant data sent on 043 the specified named channel. The tokens are 044 "tunneled" to any instance of {@link SubscriberPort} that names the same channel. 045 If {@link #global} is false (the default), then this publisher 046 will only send to instances of SubscriberPort that are under the 047 control of the same director. That is, it can 048 be at a different level of the hierarchy, or in an entirely different 049 composite actor, as long as the relevant composite actors are 050 transparent (have no director). If {@link #global} is true, 051 then the subscriber may be anywhere in the model, as long as its 052 <i>global</i> parameter is also true. 053 <p> 054 Note that this port should be used just like a {@link PublisherPort}. 055 If you put it in an opaque composite actor, then it requires a 056 token on the inside in order to produce its output. It will replace 057 each token with the constant value. Similarly, if it is put into 058 a transparent composite actor, then tokens must be sent through 059 it. Those tokens will be replaced with the constant value. If it 060 is put into an atomic actor, then the actor should call one of 061 its broadcast or send methods, providing a token that will be 062 replaced with the constant token. This pattern ensures that data 063 dependencies work with this port just as with any other port. 064<p> 065 It is an error to have two instances of PublisherPort 066 or ConstantPublisherPort using the same 067 channel under the control of the same director. When you create a 068 new PublisherPort or 069 ConstantPublisherPort, by default, it has no channel name. You have to 070 specify a channel name to use it. 071 <p> 072 <b>How it works:</b> 073 When the channel name 074 is specified, typically during model construction, this actor 075 causes a relation to be created in the least opaque composite 076 actor above it in the hierarchy and links to that relation. 077 In addition, if {@link #global} is set to true, it causes 078 a port to be created in that composite, and also links that 079 port to the relation on the inside. The relation is recorded by the opaque 080 composite. When a SubscriberPort is preinitialized that refers 081 to the same channel, that SubscriberPort finds the relation (by 082 finding the least opaque composite actor above it) and links 083 to the relation. Some of these links are "liberal links" in that 084 they cross levels of the hierarchy. 085 <p> 086 Since publishers are linked to subscribers, 087 any data dependencies that the director might assume on a regular 088 "wired" connection will also be assumed across publisher-subscriber 089 pairs. Similarly, type constraints will propagate across 090 publisher-subscriber pairs. That is, the type of the subscriber 091 output will match the type of the publisher input. 092 093 @author Edward A. Lee 094 @version $Id$ 095 @since Ptolemy II 10.0 096 @Pt.ProposedRating Yellow (eal) 097 @Pt.AcceptedRating Red (eal) 098 */ 099public class ConstantPublisherPort extends PublisherPort { 100 101 /** Construct a constant publisher port with the specified name and container. 102 * @param container The container actor. 103 * @param name The name of the port. 104 * @exception IllegalActionException If the port is not of an acceptable 105 * class for the container, or if the container does not implement the 106 * Actor interface. 107 * @exception NameDuplicationException If the name coincides with 108 * a port already in the container. 109 */ 110 public ConstantPublisherPort(ComponentEntity container, String name) 111 throws IllegalActionException, NameDuplicationException { 112 super(container, name); 113 114 constantValue = new Parameter(this, "constantValue"); 115 constantValue.setExpression("0"); 116 117 Parameter UNBOUNDED = new Parameter(this, "UNBOUNDED"); 118 UNBOUNDED.setTypeEquals(BaseType.INT); 119 UNBOUNDED.setExpression("-1"); 120 UNBOUNDED.setPersistent(false); 121 UNBOUNDED.setVisibility(Settable.NONE); 122 123 numberOfTokens = new Parameter(this, "numberOfTokens"); 124 numberOfTokens.setExpression("UNBOUNDED"); 125 numberOfTokens.setTypeEquals(BaseType.INT); 126 127 numberOfTokens.moveToFirst(); 128 constantValue.moveToFirst(); 129 130 // Hide the initial tokens, as they make no sense for this port. 131 initialTokens.setVisibility(Settable.NONE); 132 133 setTypeSameAs(constantValue); 134 } 135 136 /////////////////////////////////////////////////////////////////// 137 //// parameters //// 138 139 /** The constant value to publish. This can have any type. 140 * It defaults to the integer 0. 141 */ 142 public Parameter constantValue; 143 144 /** The number of constant tokens to publish. By default, 145 * this is UNBOUNDED, which means that there is no limit. 146 */ 147 public Parameter numberOfTokens; 148 149 /////////////////////////////////////////////////////////////////// 150 //// public methods //// 151 152 /** Override the base class to replace the specified token with 153 * the value of <i>constantValue</i>. 154 * @param token A token, which will be replaced. 155 * @exception IllegalActionException Not thrown in this base class. 156 * @exception NoRoomException If a send to one of the channels throws 157 * it. 158 */ 159 @Override 160 public void broadcast(Token token) 161 throws IllegalActionException, NoRoomException { 162 if (token == null) { 163 super.broadcast(null); 164 } else { 165 int limit = ((IntToken) numberOfTokens.getToken()).intValue(); 166 if (limit >= 0) { 167 if (_numberOfTokensSent >= limit) { 168 return; 169 } 170 _numberOfTokensSent++; 171 } 172 super.broadcast(constantValue.getToken()); 173 } 174 } 175 176 /** Override the base class to replace the specified tokens with 177 * the value of <i>constantValue</i>. 178 * @param tokenArray The token array to replace. 179 * @param vectorLength The number of elements of the token 180 * array to send. 181 * @exception NoRoomException If there is no room in the receiver. 182 * @exception IllegalActionException Not thrown in this base class. 183 */ 184 @Override 185 public void broadcast(Token[] tokenArray, int vectorLength) 186 throws IllegalActionException, NoRoomException { 187 Token[] replacement = new Token[tokenArray.length]; 188 for (int i = 0; i < tokenArray.length; i++) { 189 replacement[i] = tokenArray[i]; 190 } 191 int limit = ((IntToken) numberOfTokens.getToken()).intValue(); 192 if (limit >= 0) { 193 if (_numberOfTokensSent >= limit) { 194 return; 195 } 196 _numberOfTokensSent += vectorLength; 197 } 198 super.broadcast(replacement, vectorLength); 199 } 200 201 /** Override the base class to initialize the token count. 202 * @exception IllegalActionException If initialTokens is invalid. 203 */ 204 @Override 205 public void initialize() throws IllegalActionException { 206 super.initialize(); 207 _numberOfTokensSent = 0; 208 } 209 210 /** Override the base class to replace the specified token with 211 * the value of <i>constantValue</i>. 212 * @param channelIndex The index of the channel, from 0 to width-1 213 * @param token The token to replace, or null to send no token. 214 * @exception NoRoomException If there is no room in the receiver. 215 * @exception IllegalActionException Not thrown in this base class. 216 */ 217 @Override 218 public void send(int channelIndex, Token token) 219 throws IllegalActionException, NoRoomException { 220 if (token == null) { 221 super.send(channelIndex, null); 222 } else { 223 int limit = ((IntToken) numberOfTokens.getToken()).intValue(); 224 if (limit >= 0) { 225 if (_numberOfTokensSent >= limit) { 226 return; 227 } 228 _numberOfTokensSent++; 229 } 230 super.send(channelIndex, constantValue.getToken()); 231 } 232 } 233 234 /** Override the base class to replace the specified tokens with 235 * the value of <i>constantValue</i>. 236 * @param channelIndex The index of the channel, from 0 to width-1 237 * @param tokenArray The token array to replace. 238 * @param vectorLength The number of elements of of the token 239 * array to send. 240 * @exception NoRoomException If there is no room in the receiver. 241 * @exception IllegalActionException Not thrown in this base class. 242 */ 243 @Override 244 public void send(int channelIndex, Token[] tokenArray, int vectorLength) 245 throws IllegalActionException, NoRoomException { 246 Token[] replacement = new Token[tokenArray.length]; 247 for (int i = 0; i < tokenArray.length; i++) { 248 replacement[i] = tokenArray[i]; 249 } 250 int limit = ((IntToken) numberOfTokens.getToken()).intValue(); 251 if (limit >= 0) { 252 if (_numberOfTokensSent >= limit) { 253 return; 254 } 255 _numberOfTokensSent += vectorLength; 256 } 257 super.send(channelIndex, replacement, vectorLength); 258 } 259 260 /////////////////////////////////////////////////////////////////// 261 //// private variables //// 262 263 /** Number of tokens sent since initialize(). */ 264 private int _numberOfTokensSent = 0; 265}