001/* Actor representing one of several refinements. 002 003 Copyright (c) 2002-2015 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.lib.hoc; 028 029import java.util.Iterator; 030 031import ptolemy.actor.IOPort; 032import ptolemy.actor.parameters.ParameterPort; 033import ptolemy.actor.parameters.PortParameter; 034import ptolemy.kernel.ComponentEntity; 035import ptolemy.kernel.CompositeEntity; 036import ptolemy.kernel.util.IllegalActionException; 037import ptolemy.kernel.util.NameDuplicationException; 038import ptolemy.kernel.util.StringAttribute; 039import ptolemy.kernel.util.Workspace; 040 041/////////////////////////////////////////////////////////////////// 042//// Case 043 044/** 045 An actor that executes one of several refinements depending on the 046 value provided by the <i>control</i> port-parameter. To use this, 047 drag the Case icon onto the canvas, right click and select Open Actor. 048 To add a refinement, go to the Case menu in the menu bar and select Add Case, 049 then populate populate the refinement with computations. 050 Each refinement is a composite that is required to have its own director. 051 The name of the refinement is value that the control must have to 052 execute this refinement. 053 This actor always provides one case called "default". This is 054 the refinement that is executed if no other refinement matches 055 the control input. All refinements have the same ports, 056 and adding ports to any one refinement or to the case actor 057 itself results in identical ports being added to all refinements. 058 059 @author Edward A. Lee 060 @version $Id$ 061 @since Ptolemy II 5.2 062 @Pt.ProposedRating Yellow (eal) 063 @Pt.AcceptedRating Red (reviewmoderator) 064 */ 065public class Case extends MultiCompositeActor { 066 067 /** Construct 068 * a modal model with a name and a container. 069 * The container argument must not be null, or a 070 * NullPointerException will be thrown. 071 * @param container The container. 072 * @param name The name of this actor. 073 * @exception IllegalActionException If the container is incompatible 074 * with this actor. 075 * @exception NameDuplicationException If the name coincides with 076 * an actor already in the container. 077 */ 078 public Case(CompositeEntity container, String name) 079 throws IllegalActionException, NameDuplicationException { 080 super(container, name); 081 _init(); 082 } 083 084 /** Construct a Case in the specified workspace with no container and 085 * an empty string as a name. You can then change the name with 086 * setName(). If the workspace argument is null, then use the default 087 * workspace. 088 * @param workspace The workspace that will list the actor. 089 * @exception IllegalActionException If the name has a period in it, or 090 * the director is not compatible with the specified container. 091 * @exception NameDuplicationException If the container already contains 092 * an entity with the specified name. 093 */ 094 public Case(Workspace workspace) 095 throws IllegalActionException, NameDuplicationException { 096 super(workspace); 097 _init(); 098 } 099 100 /////////////////////////////////////////////////////////////////// 101 //// public variables //// 102 103 /** The input port-parameter on which the control token is provided. 104 * This can have any type, and is initialized with a default value 105 * of true. 106 */ 107 public PortParameter control; 108 109 /////////////////////////////////////////////////////////////////// 110 //// public methods //// 111 112 /** Override the base class to ensure that the _default member 113 * points to the default refinement. 114 * @param workspace The workspace for the new object. 115 * @return A new Case. 116 * @exception CloneNotSupportedException If any of the attributes 117 * cannot be cloned. 118 */ 119 @Override 120 public Object clone(Workspace workspace) throws CloneNotSupportedException { 121 Case newObject = (Case) super.clone(workspace); 122 newObject._default = (Refinement) newObject.getEntity("default"); 123 newObject._current = newObject._default; 124 newObject._director = (CaseDirector) newObject 125 .getAttribute("_director"); 126 return newObject; 127 } 128 129 /** Return the current refinement, or null if prefire() has not 130 * yet been invoked. 131 * @return The current refinement. 132 */ 133 public Refinement getCurrentRefinement() { 134 return _current; 135 } 136 137 /** Override the base class to not read inputs, since this has been 138 * done in prefire(). Fire the current refinement, and then 139 * send any output data created by calling the local director's 140 * transferOutputs method. 141 * @exception IllegalActionException If there is no director, or if 142 * the director's fire() method throws it, or if the actor is not 143 * opaque. 144 */ 145 @Override 146 public void fire() throws IllegalActionException { 147 // FIXME: Case.fire() does not invoke the piggyback methods as 148 // is done in CompositeActor.fire(). 149 if (_debugging) { 150 _debug("Calling fire()"); 151 } 152 153 try { 154 _workspace.getReadAccess(); 155 156 _director.fire(); 157 158 if (_stopRequested) { 159 return; 160 } 161 162 // Use the local director to transfer outputs. 163 Iterator outports = outputPortList().iterator(); 164 165 while (outports.hasNext() && !_stopRequested) { 166 IOPort p = (IOPort) outports.next(); 167 _director.transferOutputs(p); 168 } 169 } finally { 170 _workspace.doneReading(); 171 } 172 173 if (_debugging) { 174 _debug("Called fire()"); 175 } 176 } 177 178 /** Create a new refinement with the specified name. 179 * @param name The name of the refinement. 180 * @return The new refinement. 181 * @exception IllegalActionException If the refinement cannot be created. 182 * @exception NameDuplicationException If a refinement already 183 * exists with this name. 184 */ 185 public Refinement newRefinement(String name) 186 throws IllegalActionException, NameDuplicationException { 187 return new Refinement(this, name); 188 } 189 190 /** Return the class name for refinements that this Case actor 191 * expects to contain. 192 * @return The string "ptolemy.actor.lib.hoc.Refinement". 193 */ 194 public String refinementClassName() { 195 return "ptolemy.actor.lib.hoc.Refinement"; 196 } 197 198 /////////////////////////////////////////////////////////////////// 199 //// protected methods //// 200 201 /** Override the base class to ensure that the default refinement remains 202 * last. 203 * @exception IllegalActionException If the entity has no name, or the 204 * action would result in a recursive containment structure. 205 * @exception NameDuplicationException If the name collides with a name 206 * already in the entity. 207 */ 208 @Override 209 protected void _addEntity(ComponentEntity entity) 210 throws IllegalActionException, NameDuplicationException { 211 super._addEntity(entity); 212 if (entity instanceof Refinement) { 213 // Ensure that the default refinement remains the last one. 214 // Note however that this is called on the default itself, 215 // at which time the local member has not been set. 216 if (_default != null) { 217 _default.moveToLast(); 218 } 219 } 220 } 221 222 /** Create a director. This base class creates an instance of CaseDirector. 223 * @return The created director. 224 * @exception IllegalActionException If the director cannot be created. 225 * @exception NameDuplicationException If there is already an 226 * attribute with the name "_director". 227 */ 228 protected CaseDirector _createDirector() 229 throws IllegalActionException, NameDuplicationException { 230 return new CaseDirector(this, "_director"); 231 } 232 233 /////////////////////////////////////////////////////////////////// 234 //// protected variables //// 235 236 /** The current refinement. */ 237 protected Refinement _current; 238 239 /** The default refinement. */ 240 protected Refinement _default; 241 242 /** The director. */ 243 protected CaseDirector _director; 244 245 /////////////////////////////////////////////////////////////////// 246 //// private methods //// 247 248 /** Initialize the class. */ 249 private void _init() 250 throws IllegalActionException, NameDuplicationException { 251 setClassName("ptolemy.actor.lib.hoc.Case"); 252 253 // Create the control port. 254 control = new PortParameter(this, "control"); 255 // FIXME: This is awkward... If I provide some 256 // non-boolean control input, I get obscure type 257 // conflict error messages and have to change this 258 // to match. 259 control.setExpression("true"); 260 ParameterPort port = control.getPort(); 261 // Put the control input on the bottom of the actor. 262 StringAttribute controlCardinal = new StringAttribute(port, 263 "_cardinal"); 264 controlCardinal.setExpression("SOUTH"); 265 266 // Create the default refinement. 267 _default = newRefinement("default"); 268 269 // Create the director. 270 _director = _createDirector(); 271 } 272}