001/* An actor that finds a destination to send data to. 002 003 Copyright (c) 2003-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 028 */ 029package ptolemy.domains.de.demo.SmartSender; 030 031import java.util.Iterator; 032import java.util.List; 033 034import ptolemy.actor.Director; 035import ptolemy.actor.IOPort; 036import ptolemy.actor.TypedAtomicActor; 037import ptolemy.actor.TypedIOPort; 038import ptolemy.data.DoubleToken; 039import ptolemy.data.IntToken; 040import ptolemy.data.expr.Parameter; 041import ptolemy.data.type.BaseType; 042import ptolemy.kernel.CompositeEntity; 043import ptolemy.kernel.Entity; 044import ptolemy.kernel.Port; 045import ptolemy.kernel.util.ChangeRequest; 046import ptolemy.kernel.util.IllegalActionException; 047import ptolemy.kernel.util.NameDuplicationException; 048 049/////////////////////////////////////////////////////////////////// 050//// SmartSender 051 052/** 053 This actor adaptively establishes connections by searching for an 054 unused input port in the model and connecting to it. If the output 055 is connected to something (the width of the output port is greater 056 than zero), then the actor sends an integer on the output port and 057 requests a refiring at a time in the future determined by the 058 <i>firingPeriod</i> parameter. The value of the output is simply 059 the count of the firing, starting at 1. 060 <p> 061 If the output is not connected to anything, then the actor will 062 attempt to connect it. It does this by issuing a change request 063 that, when executed, will search for an unused input port (any 064 unused input port) in and actor in the same container as this actor, 065 and then will connect to it. 066 <p> 067 Note that getWidth() is used rather than numberOfSinks() to determine 068 whether the output is connected. This way, this actors search for an 069 input port can be silenced by just connecting it to a relation. 070 <p> 071 This actor is an illustration of the capability actors can have to affect 072 their environment, to detect faults (in this case, missing connections), 073 and to repair the model. It is designed to be used in the DE domain, 074 or any domain that respects fireAt() calls. 075 076 @author Edward A. Lee 077 @see IOPort#getWidth() 078 @version $Id$ 079 @since Ptolemy II 4.0 080 @Pt.ProposedRating Yellow (eal) 081 @Pt.AcceptedRating Red (eal) 082 */ 083public class SmartSender extends TypedAtomicActor { 084 /** Create a new actor in the specified container with the specified 085 * name. The name must be unique within the container or an exception 086 * is thrown. The container argument must not be null, or a 087 * NullPointerException will be thrown. 088 * @param container The container. 089 * @param name The name of this actor within the container. 090 * @exception IllegalActionException If this actor cannot be contained 091 * by the proposed container (see the setContainer() method). 092 * @exception NameDuplicationException If the name coincides with 093 * an entity already in the container. 094 */ 095 public SmartSender(CompositeEntity container, String name) 096 throws NameDuplicationException, IllegalActionException { 097 super(container, name); 098 099 output = new TypedIOPort(this, "output"); 100 output.setOutput(true); 101 output.setTypeEquals(BaseType.INT); 102 103 firingPeriod = new Parameter(this, "firingPeriod"); 104 firingPeriod.setExpression("0.1"); 105 firingPeriod.setTypeEquals(BaseType.DOUBLE); 106 } 107 108 /////////////////////////////////////////////////////////////////// 109 //// ports and parameters //// 110 111 /** The output port, which has type int. */ 112 public TypedIOPort output; 113 114 /** The period at which this actor will execute. This is a double 115 * with a default value of 0.1. 116 */ 117 public Parameter firingPeriod; 118 119 /////////////////////////////////////////////////////////////////// 120 //// public methods //// 121 122 /** If the output port is connected, then send a count of the firing 123 * to the output; otherwise, issue a change request that will search 124 * for an input port to connect to. 125 * @exception IllegalActionException If there is no director or if 126 * producing the output causes an exception. 127 */ 128 @Override 129 public void fire() throws IllegalActionException { 130 super.fire(); 131 132 double firingPeriodValue = ((DoubleToken) firingPeriod.getToken()) 133 .doubleValue(); 134 Director director = getDirector(); 135 _fireAt(director.getModelTime().add(firingPeriodValue)); 136 137 if (output.isOutsideConnected()) { 138 output.send(0, new IntToken(_count++)); 139 } else { 140 ChangeRequest request = new ChangeRequest(this, 141 "Find a destination") { 142 @Override 143 protected void _execute() throws IllegalActionException { 144 CompositeEntity container = (CompositeEntity) getContainer(); 145 List entityList = container.entityList(); 146 Iterator entities = entityList.iterator(); 147 148 while (entities.hasNext()) { 149 Entity entity = (Entity) entities.next(); 150 Iterator ports = entity.portList().iterator(); 151 152 while (ports.hasNext()) { 153 Port port = (Port) ports.next(); 154 155 if (port instanceof IOPort 156 && ((IOPort) port).isInput() 157 && !((IOPort) port).isOutsideConnected()) { 158 container.connect(output, (IOPort) port); 159 return; 160 } 161 } 162 } 163 } 164 }; 165 166 requestChange(request); 167 } 168 } 169 170 /** Initialize this actor, which in this case requests a firing at 171 * the current time. 172 * @exception IllegalActionException If a derived class throws it. 173 */ 174 @Override 175 public void initialize() throws IllegalActionException { 176 super.initialize(); 177 178 Director director = getDirector(); 179 director.fireAtCurrentTime(this); 180 181 _count = 1; 182 } 183 184 /////////////////////////////////////////////////////////////////// 185 //// private members //// 186 187 /** Count of the number of firings. */ 188 private int _count = 1; 189}