001/* A director to control the execution of ExecutionChoice actors. 002 * 003 * Copyright (c) 2012 The Regents of the University of California. 004 * All rights reserved. 005 * 006 * '$Author: crawl $' 007 * '$Date: 2014-02-19 18:21:33 +0000 (Wed, 19 Feb 2014) $' 008 * '$Revision: 32608 $' 009 * 010 * Permission is hereby granted, without written agreement and without 011 * license or royalty fees, to use, copy, modify, and distribute this 012 * software and its documentation for any purpose, provided that the above 013 * copyright notice and the following two paragraphs appear in all copies 014 * of this software. 015 * 016 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 017 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 018 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 019 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 020 * SUCH DAMAGE. 021 * 022 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 023 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 025 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 026 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 027 * ENHANCEMENTS, OR MODIFICATIONS. 028 * 029 */ 030package org.kepler.ddp.actor; 031 032import java.util.Iterator; 033import java.util.LinkedList; 034import java.util.List; 035 036import ptolemy.actor.Director; 037import ptolemy.actor.FiringEvent; 038import ptolemy.actor.IOPort; 039import ptolemy.actor.IOPortEvent; 040import ptolemy.actor.Receiver; 041import ptolemy.actor.lib.hoc.Case; 042import ptolemy.actor.lib.hoc.CaseDirector; 043import ptolemy.actor.lib.hoc.Refinement; 044import ptolemy.actor.parameters.ParameterPort; 045import ptolemy.actor.parameters.PortParameter; 046import ptolemy.data.BooleanToken; 047import ptolemy.data.StringToken; 048import ptolemy.data.Token; 049import ptolemy.data.expr.Parameter; 050import ptolemy.data.expr.StringParameter; 051import ptolemy.domains.ddf.kernel.DDFDirector; 052import ptolemy.kernel.CompositeEntity; 053import ptolemy.kernel.util.IllegalActionException; 054import ptolemy.kernel.util.NameDuplicationException; 055import ptolemy.kernel.util.NamedObj; 056import ptolemy.kernel.util.Workspace; 057 058/** 059 * A director to control the execution of execution choice actors. 060 * 061 * @author Daniel Crawl 062 * @version $Id: ExecutionChoiceDirector.java 32608 2014-02-19 18:21:33Z crawl $ 063 */ 064public class ExecutionChoiceDirector extends CaseDirector { 065 066 /** Create a new ExecutionChoiceDirector in a container 067 * with a specific name. 068 */ 069 public ExecutionChoiceDirector(CompositeEntity container, String name) 070 throws IllegalActionException, NameDuplicationException { 071 super(container, name); 072 073 // make sure the container in ExecutionChoice 074 // XXX do not do this check since container may be CompositeClassEntity 075 /* 076 NamedObj namedObj = getContainer(); 077 if (!(namedObj instanceof ExecutionChoice)) { 078 throw new IllegalActionException( 079 "ExecutionChoiceDirector may only be used with the ExecutionChoice actor."); 080 } 081 */ 082 } 083 084 /** Clone this director into the specified workspace. */ 085 @Override 086 public Object clone(Workspace workspace) throws CloneNotSupportedException { 087 ExecutionChoiceDirector newObject = (ExecutionChoiceDirector) super.clone(workspace); 088 newObject._addedDirectors = new LinkedList<Director>(); 089 return newObject; 090 } 091 092 /** Read the control token input, transfer input tokens, 093 * and invoke prefire() of the selected refinement. 094 * 095 * @exception IllegalActionException If there is no director, 096 * or if the director's prefire() method throws it, or if this actor 097 * is not opaque. 098 */ 099 @Override 100 public boolean prefire() throws IllegalActionException { 101 if (_debugging) { 102 _debug("Calling prefire()"); 103 } 104 105 try { 106 _workspace.getReadAccess(); 107 //super.prefire(); 108 109 Case container = (Case) getContainer(); 110 // Read from port parameters, including the control port. 111 Iterator<PortParameter> portParameters = container.attributeList( 112 PortParameter.class).iterator(); 113 while (portParameters.hasNext()) { 114 PortParameter portParameter = (PortParameter) portParameters 115 .next(); 116 portParameter.update(); 117 } 118 119 String controlValue; 120 Token controlToken = container.control.getToken(); 121 // If it's a string, use stringValue() otherwise there 122 // are quotes around the string. 123 if (controlToken instanceof StringToken) { 124 controlValue = ((StringToken) controlToken).stringValue(); 125 } else { 126 controlValue = controlToken.toString(); 127 } 128 129 ExecutionChoice choice = (ExecutionChoice)container; 130 131 Refinement refinement = (Refinement) container.getEntity(controlValue); 132 133 // make sure we found the refinement. 134 if(refinement == null) { 135 throw new IllegalActionException(choice, "Could not find execution choice called \"" + 136 controlValue + "\""); 137 } 138 139 // NOTE: the control value in ExecutionChoice is prevented from being 140 // set to something other than a refinement, so this check is not necessary. 141 /* 142 if (!(refinement instanceof Refinement)) { 143 refinement = choice._getDefaultRefinement(); 144 } 145 */ 146 choice._setCurrentRefinement(refinement); 147 148 // Transfer input tokens. 149 for (IOPort port : (List<IOPort>)choice.inputPortList()) { 150 151 if(_stopRequested) { 152 break; 153 } 154 155 if (!(port instanceof ParameterPort)) { 156 Receiver[][] insideReceivers = port.deepGetReceivers(); 157 for (int i = 0; i < insideReceivers.length; i++) { 158 Token token = null; 159 if(port.numberOfSources() > 0) { 160 if (i < port.getWidth() && port.hasToken(i)) { 161 token = port.get(i); 162 } 163 } else if(choice.getPortIOType(port) == ExecutionChoice.IOType.File){ 164 token = ((Parameter)container.getAttribute(port.getName())).getToken(); 165 } 166 if(token != null) { 167 if (insideReceivers[i] != null) { 168 for (int j = 0; j < insideReceivers[i].length; j++) { 169 if (insideReceivers[i][j].getContainer() 170 .getContainer() == refinement) { 171 172 if (_debugging) { 173 _debug(new IOPortEvent(port, 174 insideReceivers[i][j] 175 .getContainer(), 176 true, i, false, token)); 177 } 178 179 insideReceivers[i][j].put(token); 180 181 if (_debugging) { 182 _debug(new IOPortEvent(port, 183 insideReceivers[i][j] 184 .getContainer(), 185 false, i, false, token)); 186 _debug(getFullName(), 187 "transferring input from " 188 + port.getFullName() 189 + " to " 190 + (insideReceivers[i][j]) 191 .getContainer() 192 .getFullName()); 193 } 194 } 195 } 196 } 197 } 198 } 199 } 200 } 201 202 if (_stopRequested) { 203 return false; 204 } 205 if (_debugging) { 206 _debug(new FiringEvent(this, refinement, 207 FiringEvent.BEFORE_PREFIRE)); 208 } 209 boolean result = refinement.prefire(); 210 if (_debugging) { 211 _debug(new FiringEvent(this, refinement, 212 FiringEvent.AFTER_PREFIRE)); 213 } 214 return result; 215 } finally { 216 _workspace.doneReading(); 217 } 218 } 219 220 /** Add DDF director to any refinements that have no directors. */ 221 @Override 222 public void preinitialize() throws IllegalActionException { 223 224 Case container = (Case) getContainer(); 225 final List<Refinement> refinements = container.entityList(Refinement.class); 226 for(Refinement refinement : refinements) { 227 if(!refinement.isOpaque()) { 228 //System.out.println("adding ddf to " + refinement.getName()); 229 DDFDirector director; 230 try { 231 director = new DDFDirector(refinement, "DDF Director"); 232 } catch (NameDuplicationException e) { 233 throw new IllegalActionException(refinement, e, 234 "Error adding DDF director in choice " + refinement.getName()); 235 } 236 director.setPersistent(false); 237 director.runUntilDeadlockInOneIteration.setToken(BooleanToken.TRUE); 238 _addedDirectors.add(director); 239 } 240 } 241 242 super.preinitialize(); 243 } 244 245 /** Remove all DDF directors that were added to refinements in preinitialize(). */ 246 @Override 247 public void wrapup() throws IllegalActionException { 248 249 super.wrapup(); 250 251 for(Director director : _addedDirectors) { 252 try { 253 //System.out.println("removing ddf from " + director.getContainer().getName()); 254 director.setContainer(null); 255 } catch (NameDuplicationException e) { 256 throw new IllegalActionException(director.getContainer(), e, 257 "Error removing DDF director in choice " + 258 director.getContainer().getName()); 259 } 260 } 261 _addedDirectors.clear(); 262 263 } 264 265 /** Transfer data from output ports in an ExecutionChoice actor. The port 266 * is a MultiComposite port that is connected (mirrored) to output ports 267 * inside each of the refinements in the ExecutionChoice actor. If the 268 * inside port has inputs, then transfer the tokens as usual. Otherwise, 269 * if the IOType of the port is File, transfer the value of the parameter 270 * with the same name as the port. 271 * 272 * @exception IllegalActionException If the port is not an opaque output port. 273 * @param port The port to transfer tokens from. 274 * @return True if the port has an inside token that was successfully 275 * transferred. Otherwise return false (or throw an exception). 276 */ 277 @Override 278 protected boolean _transferOutputs(IOPort port) throws IllegalActionException { 279 280 // see if the mirrored port in the refinement has inputs 281 282 // TODO check only current refinement? 283 boolean isConnected = false; 284 List<IOPort> insidePorts = port.insideSourcePortList(); 285 for(IOPort insidePort : insidePorts) { 286 // see if the RefinementPort is connected to something in the 287 // refinement 288 if(!insidePort.insideSourcePortList().isEmpty()) { 289 isConnected = true; 290 break; 291 } 292 } 293 294 // if there are inputs, transfer as usual 295 if (isConnected) { 296 return super._transferOutputs(port); 297 } else if(((ExecutionChoice) port.getContainer()).getPortIOType(port) == ExecutionChoice.IOType.File) { 298 299 // true once we write a token to the port 300 boolean result = false; 301 302 // get the container's parameter with the same name 303 // as the port's display name. 304 final NamedObj namedObj = getContainer(); 305 final String portName = port.getDisplayName(); 306 final StringParameter parameter = (StringParameter) namedObj 307 .getAttribute(portName); 308 // make sure we found it 309 if (parameter == null) { 310 throw new IllegalActionException("Missing parameter for output " 311 + portName); 312 } 313 314 // write the token in the parameter to the port 315 final Token token = parameter.getToken(); 316 for (int i = 0; i < port.getWidth(); i++) { 317 port.send(i, token); 318 result = true; 319 } 320 321 return result; 322 } 323 324 return false; 325 } 326 327 /** A list of directors that were added to refinements in preinitialize(). */ 328 private List<Director> _addedDirectors = new LinkedList<Director>(); 329 330}